Merge AddFastElement and AddFastDoubleElement

BUG=v8:4137
LOG=n

Review URL: https://codereview.chromium.org/1198343004

Cr-Commit-Position: refs/heads/master@{#29227}
This commit is contained in:
verwaest 2015-06-23 04:35:43 -07:00 committed by Commit bot
parent 47421760f4
commit 359142c330
8 changed files with 127 additions and 274 deletions

View File

@ -11,6 +11,7 @@
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/builtins.h" #include "src/builtins.h"
#include "src/cpu-profiler.h" #include "src/cpu-profiler.h"
#include "src/elements.h"
#include "src/gdb-jit.h" #include "src/gdb-jit.h"
#include "src/heap/mark-compact.h" #include "src/heap/mark-compact.h"
#include "src/heap-profiler.h" #include "src/heap-profiler.h"

View File

@ -138,6 +138,9 @@ class ElementsAccessor {
static void InitializeOncePerProcess(); static void InitializeOncePerProcess();
static void TearDown(); static void TearDown();
virtual void Set(FixedArrayBase* backing_store, uint32_t key,
Object* value) = 0;
protected: protected:
friend class SloppyArgumentsElementsAccessor; friend class SloppyArgumentsElementsAccessor;
friend class LookupIterator; friend class LookupIterator;
@ -164,9 +167,6 @@ class ElementsAccessor {
uint32_t index) = 0; uint32_t index) = 0;
virtual bool HasIndex(FixedArrayBase* backing_store, uint32_t key) = 0; virtual bool HasIndex(FixedArrayBase* backing_store, uint32_t key) = 0;
virtual void Set(FixedArrayBase* backing_store, uint32_t key,
Object* value) = 0;
private: private:
static ElementsAccessor** elements_accessors_; static ElementsAccessor** elements_accessors_;
const char* name_; const char* name_;

View File

@ -6,6 +6,7 @@
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/double.h" #include "src/double.h"
#include "src/elements.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/hydrogen-infer-representation.h" #include "src/hydrogen-infer-representation.h"

View File

@ -7,6 +7,8 @@
#include "src/lookup.h" #include "src/lookup.h"
#include "src/elements.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {

View File

@ -16,7 +16,6 @@
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/contexts.h" #include "src/contexts.h"
#include "src/conversions-inl.h" #include "src/conversions-inl.h"
#include "src/elements.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/field-index-inl.h" #include "src/field-index-inl.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
@ -1605,16 +1604,6 @@ FixedArrayBase* JSObject::elements() const {
} }
void JSObject::ValidateElements(Handle<JSObject> object) {
#ifdef ENABLE_SLOW_DCHECKS
if (FLAG_enable_slow_asserts) {
ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->Validate(object);
}
#endif
}
void AllocationSite::Initialize() { void AllocationSite::Initialize() {
set_transition_info(Smi::FromInt(0)); set_transition_info(Smi::FromInt(0));
SetElementsKind(GetInitialFastElementsKind()); SetElementsKind(GetInitialFastElementsKind());
@ -6227,11 +6216,6 @@ ElementsKind JSObject::GetElementsKind() {
} }
ElementsAccessor* JSObject::GetElementsAccessor() {
return ElementsAccessor::ForKind(GetElementsKind());
}
bool JSObject::HasFastObjectElements() { bool JSObject::HasFastObjectElements() {
return IsFastObjectElementsKind(GetElementsKind()); return IsFastObjectElementsKind(GetElementsKind());
} }

View File

@ -12351,98 +12351,18 @@ bool JSObject::HasDictionaryArgumentsElements() {
} }
void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, ElementsAccessor* JSObject::GetElementsAccessor() {
Handle<Object> value) { return ElementsAccessor::ForKind(GetElementsKind());
DCHECK(object->HasFastSmiOrObjectElements() || }
object->HasFastArgumentsElements());
Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
if (object->HasSloppyArgumentsElements()) { void JSObject::ValidateElements(Handle<JSObject> object) {
backing_store = handle(FixedArray::cast(backing_store->get(1))); #ifdef ENABLE_SLOW_DCHECKS
} else { if (FLAG_enable_slow_asserts) {
backing_store = EnsureWritableFastElements(object); ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->Validate(object);
} }
uint32_t capacity = static_cast<uint32_t>(backing_store->length()); #endif
// Check if the length property of this object needs to be updated.
uint32_t array_length = 0;
bool must_update_array_length = false;
bool introduces_holes = true;
if (object->IsJSArray()) {
CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
introduces_holes = index > array_length;
if (index >= array_length) {
must_update_array_length = true;
array_length = index + 1;
}
} else {
introduces_holes = index >= capacity;
}
uint32_t new_capacity = capacity;
// Check if the capacity of the backing store needs to be increased, or if
// a transition to slow elements is necessary.
if (index >= capacity) {
bool convert_to_slow = true;
if ((index - capacity) < kMaxGap) {
new_capacity = NewElementsCapacity(index + 1);
DCHECK_LT(index, new_capacity);
convert_to_slow = object->ShouldConvertToSlowElements(new_capacity);
}
if (convert_to_slow) {
NormalizeElements(object);
AddDictionaryElement(object, index, value, NONE);
return;
}
}
if (object->HasFastSmiElements() && !value->IsSmi()) {
// Convert to fast double elements if appropriate.
if (value->IsNumber()) {
ElementsKind to_kind =
introduces_holes ? FAST_HOLEY_DOUBLE_ELEMENTS : FAST_DOUBLE_ELEMENTS;
ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
accessor->GrowCapacityAndConvert(object, new_capacity);
AddFastDoubleElement(object, index, value);
return;
}
// Change elements kind from Smi-only to generic FAST if necessary.
ElementsKind kind = introduces_holes || object->HasFastHoleyElements()
? FAST_HOLEY_ELEMENTS
: FAST_ELEMENTS;
UpdateAllocationSite(object, kind);
Handle<Map> new_map = GetElementsTransitionMap(object, kind);
JSObject::MigrateToMap(object, new_map);
DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
} else if (introduces_holes && !object->HasFastHoleyElements()) {
// If the array is growing, and it's not growth by a single element at the
// end, make sure that the ElementsKind is HOLEY.
ElementsKind transitioned_kind =
GetHoleyElementsKind(object->GetElementsKind());
TransitionElementsKind(object, transitioned_kind);
}
// Increase backing store capacity if that's been decided previously.
if (capacity != new_capacity) {
DCHECK(!object->HasFastDoubleElements());
ElementsAccessor* accessor =
value->IsSmi() || object->HasSloppyArgumentsElements()
? object->GetElementsAccessor()
: ElementsAccessor::ForKind(FAST_ELEMENTS);
accessor->GrowCapacityAndConvert(object, new_capacity);
}
if (must_update_array_length) {
Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
}
FixedArray* elements = FixedArray::cast(object->elements());
if (object->HasSloppyArgumentsElements()) {
elements = FixedArray::cast(elements->get(1));
}
elements->set(index, *value);
} }
@ -12482,30 +12402,6 @@ void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object,
} }
void JSObject::AddSloppyArgumentsElement(Handle<JSObject> object,
uint32_t index, Handle<Object> value,
PropertyAttributes attributes) {
DCHECK(object->HasSloppyArgumentsElements());
// TODO(verwaest): Handle with the elements accessor.
FixedArray* parameter_map = FixedArray::cast(object->elements());
#ifdef DEBUG
uint32_t length = parameter_map->length();
if (index < length - 2) {
Object* probe = parameter_map->get(index + 2);
DCHECK(probe->IsTheHole());
}
#endif
if (parameter_map->get(1)->IsDictionary()) {
AddDictionaryElement(object, index, value, attributes);
} else {
AddFastElement(object, index, value);
}
}
void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index, void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes) { PropertyAttributes attributes) {
@ -12597,8 +12493,7 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
if (object->ShouldConvertToFastElements()) { if (object->ShouldConvertToFastElements()) {
uint32_t new_length = 0; uint32_t new_length = 0;
if (object->IsJSArray()) { if (object->IsJSArray()) {
CHECK( CHECK(JSArray::cast(*object)->length()->ToArrayLength(&new_length));
Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length));
} else { } else {
new_length = dictionary->max_number_key() + 1; new_length = dictionary->max_number_key() + 1;
} }
@ -12616,78 +12511,6 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
} }
void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value) {
DCHECK(object->HasFastDoubleElements());
Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
uint32_t capacity = static_cast<uint32_t>(base_elms->length());
// Check if the length property of this object needs to be updated.
uint32_t array_length = 0;
bool must_update_array_length = false;
bool introduces_holes = true;
if (object->IsJSArray()) {
// In case of JSArray, the length does not equal the capacity.
CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
introduces_holes = index > array_length;
if (index >= array_length) {
must_update_array_length = true;
array_length = index + 1;
}
} else {
introduces_holes = index >= capacity;
}
uint32_t new_capacity = capacity;
// Check if the capacity of the backing store needs to be increased, or if
// a transition to slow elements is necessary.
if (index >= capacity) {
bool convert_to_slow = true;
if ((index - capacity) < kMaxGap) {
new_capacity = NewElementsCapacity(index + 1);
DCHECK_LT(index, new_capacity);
convert_to_slow = object->ShouldConvertToSlowElements(new_capacity);
}
if (convert_to_slow) {
NormalizeElements(object);
AddDictionaryElement(object, index, value, NONE);
return;
}
}
// If the value object is not a heap number, switch to fast elements and try
// again.
if (!value->IsNumber()) {
ElementsKind to_kind =
introduces_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
accessor->GrowCapacityAndConvert(object, new_capacity);
return AddFastElement(object, index, value);
}
// If the array is growing, and it's not growth by a single element at the
// end, make sure that the ElementsKind is HOLEY.
if (introduces_holes && !object->HasFastHoleyElements()) {
ElementsKind transitioned_kind =
GetHoleyElementsKind(object->GetElementsKind());
TransitionElementsKind(object, transitioned_kind);
}
// Increase backing store capacity if that's been decided previously.
if (capacity != new_capacity) {
ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->GrowCapacityAndConvert(object, new_capacity);
}
if (must_update_array_length) {
Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
}
FixedDoubleArray::cast(object->elements())->set(index, value->Number());
}
// static // static
MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
uint32_t index, Handle<Object> value, uint32_t index, Handle<Object> value,
@ -12698,66 +12521,109 @@ MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
} }
static void AddFastElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value, ElementsKind from_kind,
uint32_t capacity, uint32_t new_capacity) {
// Check if the length property of this object needs to be updated.
uint32_t array_length = 0;
bool introduces_holes = true;
if (object->IsJSArray()) {
CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
introduces_holes = index > array_length;
} else {
introduces_holes = index >= capacity;
}
ElementsKind to_kind = value->OptimalElementsKind();
if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
to_kind = IsMoreGeneralElementsKindTransition(from_kind, to_kind) ? to_kind
: from_kind;
if (introduces_holes) to_kind = GetHoleyElementsKind(to_kind);
ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
// Increase backing store capacity if that's been decided previously.
if (capacity != new_capacity || IsDictionaryElementsKind(from_kind) ||
IsFastDoubleElementsKind(from_kind) !=
IsFastDoubleElementsKind(to_kind)) {
accessor->GrowCapacityAndConvert(object, new_capacity);
} else if (from_kind != to_kind) {
JSObject::TransitionElementsKind(object, to_kind);
}
if (object->IsJSArray() && index >= array_length) {
Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
}
accessor->Set(object->elements(), index, *value);
}
// static // static
MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver, MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
uint32_t index, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes) { PropertyAttributes attributes) {
DCHECK(receiver->map()->is_extensible()); DCHECK(object->map()->is_extensible());
Isolate* isolate = receiver->GetIsolate(); Isolate* isolate = object->GetIsolate();
// TODO(verwaest): Use ElementAccessor. // TODO(verwaest): Use ElementAccessor.
Handle<Object> old_length_handle; Handle<Object> old_length_handle;
if (receiver->IsJSArray() && receiver->map()->is_observed()) { if (object->IsJSArray() && object->map()->is_observed()) {
old_length_handle = handle(JSArray::cast(*receiver)->length(), isolate); old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
} }
if (attributes != NONE) { ElementsKind kind = object->GetElementsKind();
Handle<SeededNumberDictionary> d = JSObject::NormalizeElements(receiver); bool handle_slow = false;
// TODO(verwaest): Move this into NormalizeElements. uint32_t capacity = 0;
d->set_requires_slow_elements(); uint32_t new_capacity = 0;
if (IsFastElementsKind(kind) || object->HasFastArgumentsElements()) {
if (attributes != NONE) {
// TODO(verwaest): Move set_requires_slow_elements into NormalizeElements.
NormalizeElements(object)->set_requires_slow_elements();
handle_slow = true;
} else {
if (IsSloppyArgumentsElements(kind)) {
FixedArray* parameter_map = FixedArray::cast(object->elements());
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
capacity = static_cast<uint32_t>(arguments->length());
} else {
if (IsFastSmiOrObjectElementsKind(kind)) {
EnsureWritableFastElements(object);
}
capacity = static_cast<uint32_t>(object->elements()->length());
}
new_capacity = capacity;
// Check if the capacity of the backing store needs to be increased, or if
// a transition to slow elements is necessary.
if (index >= capacity) {
handle_slow = true;
if ((index - capacity) < kMaxGap) {
new_capacity = NewElementsCapacity(index + 1);
DCHECK_LT(index, new_capacity);
handle_slow = object->ShouldConvertToSlowElements(new_capacity);
}
if (handle_slow) NormalizeElements(object);
}
}
} else {
handle_slow = true;
} }
Handle<Object> result = value; if (handle_slow) {
DCHECK(object->HasDictionaryElements() ||
switch (receiver->GetElementsKind()) { object->HasDictionaryArgumentsElements());
case FAST_SMI_ELEMENTS: AddDictionaryElement(object, index, value, attributes);
case FAST_ELEMENTS: } else {
case FAST_HOLEY_SMI_ELEMENTS: AddFastElement(object, index, value, kind, capacity, new_capacity);
case FAST_HOLEY_ELEMENTS:
AddFastElement(receiver, index, value);
break;
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
AddFastDoubleElement(receiver, index, value);
break;
case DICTIONARY_ELEMENTS:
AddDictionaryElement(receiver, index, value, attributes);
break;
case SLOPPY_ARGUMENTS_ELEMENTS:
AddSloppyArgumentsElement(receiver, index, value, attributes);
break;
// Elements cannot be added to typed arrays.
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
UNREACHABLE();
break;
} }
if (!old_length_handle.is_null() && if (!old_length_handle.is_null() &&
!old_length_handle->SameValue( !old_length_handle->SameValue(Handle<JSArray>::cast(object)->length())) {
Handle<JSArray>::cast(receiver)->length())) { // |old_length_handle| is kept null above unless the object is observed.
// |old_length_handle| is kept null above unless the receiver is observed. DCHECK(object->map()->is_observed());
DCHECK(receiver->map()->is_observed()); Handle<JSArray> array = Handle<JSArray>::cast(object);
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
Handle<String> name = isolate->factory()->Uint32ToString(index); Handle<String> name = isolate->factory()->Uint32ToString(index);
Handle<Object> new_length_handle(array->length(), isolate); Handle<Object> new_length_handle(array->length(), isolate);
uint32_t old_length = 0; uint32_t old_length = 0;
@ -12767,28 +12633,28 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver,
RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
RETURN_ON_EXCEPTION( RETURN_ON_EXCEPTION(
isolate, JSObject::EnqueueChangeRecord( isolate, EnqueueChangeRecord(array, "add", name,
array, "add", name, isolate->factory()->the_hole_value()), isolate->factory()->the_hole_value()),
Object);
RETURN_ON_EXCEPTION(
isolate, JSObject::EnqueueChangeRecord(
array, "update", isolate->factory()->length_string(),
old_length_handle),
Object); Object);
RETURN_ON_EXCEPTION(isolate,
EnqueueChangeRecord(array, "update",
isolate->factory()->length_string(),
old_length_handle),
Object);
RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object); RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
RETURN_ON_EXCEPTION(isolate, EnqueueSpliceRecord(array, old_length, deleted, RETURN_ON_EXCEPTION(isolate, EnqueueSpliceRecord(array, old_length, deleted,
new_length - old_length), new_length - old_length),
Object); Object);
} else if (receiver->map()->is_observed()) { } else if (object->map()->is_observed()) {
Handle<String> name = isolate->factory()->Uint32ToString(index); Handle<String> name = isolate->factory()->Uint32ToString(index);
RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord( RETURN_ON_EXCEPTION(
receiver, "add", name, isolate, EnqueueChangeRecord(object, "add", name,
isolate->factory()->the_hole_value()), isolate->factory()->the_hole_value()),
Object); Object);
} }
return result; return value;
} }

View File

@ -1114,6 +1114,12 @@ class Object {
} }
} }
inline ElementsKind OptimalElementsKind() {
if (IsSmi()) return FAST_SMI_ELEMENTS;
if (IsNumber()) return FAST_DOUBLE_ELEMENTS;
return FAST_ELEMENTS;
}
inline bool FitsRepresentation(Representation representation) { inline bool FitsRepresentation(Representation representation) {
if (FLAG_track_fields && representation.IsNone()) { if (FLAG_track_fields && representation.IsNone()) {
return false; return false;
@ -1777,7 +1783,7 @@ class JSObject: public JSReceiver {
Handle<Map> map, Handle<Map> map,
Handle<FixedArrayBase> elements); Handle<FixedArrayBase> elements);
inline ElementsKind GetElementsKind(); inline ElementsKind GetElementsKind();
inline ElementsAccessor* GetElementsAccessor(); ElementsAccessor* GetElementsAccessor();
// Returns true if an object has elements of FAST_SMI_ELEMENTS ElementsKind. // Returns true if an object has elements of FAST_SMI_ELEMENTS ElementsKind.
inline bool HasFastSmiElements(); inline bool HasFastSmiElements();
// Returns true if an object has elements of FAST_ELEMENTS ElementsKind. // Returns true if an object has elements of FAST_ELEMENTS ElementsKind.
@ -1900,9 +1906,6 @@ class JSObject: public JSReceiver {
static void AddDictionaryElement(Handle<JSObject> object, uint32_t index, static void AddDictionaryElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
static void AddSloppyArgumentsElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value,
PropertyAttributes attributes);
static void SetDictionaryElement(Handle<JSObject> object, uint32_t index, static void SetDictionaryElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
@ -1911,11 +1914,6 @@ class JSObject: public JSReceiver {
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
static void AddFastElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value);
static void AddFastDoubleElement(Handle<JSObject> object, uint32_t index,
Handle<Object> value);
static void OptimizeAsPrototype(Handle<JSObject> object, static void OptimizeAsPrototype(Handle<JSObject> object,
PrototypeOptimizationMode mode); PrototypeOptimizationMode mode);
static void ReoptimizeIfPrototype(Handle<JSObject> object); static void ReoptimizeIfPrototype(Handle<JSObject> object);
@ -1990,7 +1988,7 @@ class JSObject: public JSReceiver {
static void SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash); static void SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash);
static inline void ValidateElements(Handle<JSObject> object); static void ValidateElements(Handle<JSObject> object);
// Makes sure that this object can contain HeapObject as elements. // Makes sure that this object can contain HeapObject as elements.
static inline void EnsureCanContainHeapObjectElements(Handle<JSObject> obj); static inline void EnsureCanContainHeapObjectElements(Handle<JSObject> obj);

View File

@ -5,6 +5,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/arguments.h" #include "src/arguments.h"
#include "src/elements.h"
#include "src/messages.h" #include "src/messages.h"
#include "src/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"