|
|
@ -56,11 +56,6 @@ |
|
|
|
namespace v8 { |
|
|
|
namespace internal { |
|
|
|
|
|
|
|
void PrintElementsKind(FILE* out, ElementsKind kind) { |
|
|
|
ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); |
|
|
|
PrintF(out, "%s", accessor->name()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, |
|
|
|
Object* value) { |
|
|
@ -543,7 +538,7 @@ bool JSObject::IsDirty() { |
|
|
|
// If the object is fully fast case and has the same map it was
|
|
|
|
// created with then no changes can have been made to it.
|
|
|
|
return map() != fun->initial_map() |
|
|
|
|| !HasFastElements() |
|
|
|
|| !HasFastObjectElements() |
|
|
|
|| !HasFastProperties(); |
|
|
|
} |
|
|
|
|
|
|
@ -1067,7 +1062,9 @@ void String::StringShortPrint(StringStream* accumulator) { |
|
|
|
void JSObject::JSObjectShortPrint(StringStream* accumulator) { |
|
|
|
switch (map()->instance_type()) { |
|
|
|
case JS_ARRAY_TYPE: { |
|
|
|
double length = JSArray::cast(this)->length()->Number(); |
|
|
|
double length = JSArray::cast(this)->length()->IsUndefined() |
|
|
|
? 0 |
|
|
|
: JSArray::cast(this)->length()->Number(); |
|
|
|
accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length)); |
|
|
|
break; |
|
|
|
} |
|
|
@ -2202,34 +2199,29 @@ static Handle<T> MaybeNull(T* p) { |
|
|
|
|
|
|
|
|
|
|
|
Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { |
|
|
|
ElementsKind elms_kind = elements_kind(); |
|
|
|
if (elms_kind == FAST_DOUBLE_ELEMENTS) { |
|
|
|
ElementsKind kind = elements_kind(); |
|
|
|
Handle<Map> transitioned_map = Handle<Map>::null(); |
|
|
|
Handle<Map> current_map(this); |
|
|
|
bool packed = IsFastPackedElementsKind(kind); |
|
|
|
if (IsTransitionableFastElementsKind(kind)) { |
|
|
|
while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { |
|
|
|
kind = GetNextMoreGeneralFastElementsKind(kind, false); |
|
|
|
bool dummy = true; |
|
|
|
Handle<Map> fast_map = |
|
|
|
MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy)); |
|
|
|
if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) { |
|
|
|
return fast_map; |
|
|
|
} |
|
|
|
return Handle<Map>::null(); |
|
|
|
Handle<Map> maybe_transitioned_map = |
|
|
|
MaybeNull(current_map->LookupElementsTransitionMap(kind, &dummy)); |
|
|
|
if (maybe_transitioned_map.is_null()) break; |
|
|
|
if (ContainsMap(candidates, maybe_transitioned_map) && |
|
|
|
(packed || !IsFastPackedElementsKind(kind))) { |
|
|
|
transitioned_map = maybe_transitioned_map; |
|
|
|
if (!IsFastPackedElementsKind(kind)) packed = false; |
|
|
|
} |
|
|
|
if (elms_kind == FAST_SMI_ONLY_ELEMENTS) { |
|
|
|
bool dummy = true; |
|
|
|
Handle<Map> double_map = |
|
|
|
MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy)); |
|
|
|
// In the current implementation, if the DOUBLE map doesn't exist, the
|
|
|
|
// FAST map can't exist either.
|
|
|
|
if (double_map.is_null()) return Handle<Map>::null(); |
|
|
|
Handle<Map> fast_map = |
|
|
|
MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS, |
|
|
|
&dummy)); |
|
|
|
if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) { |
|
|
|
return fast_map; |
|
|
|
current_map = maybe_transitioned_map; |
|
|
|
} |
|
|
|
if (ContainsMap(candidates, double_map)) return double_map; |
|
|
|
} |
|
|
|
return Handle<Map>::null(); |
|
|
|
return transitioned_map; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents, |
|
|
|
ElementsKind elements_kind) { |
|
|
|
if (descriptor_contents->IsMap()) { |
|
|
@ -2338,24 +2330,36 @@ Object* Map::GetDescriptorContents(String* sentinel_name, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind, |
|
|
|
Map* Map::LookupElementsTransitionMap(ElementsKind to_kind, |
|
|
|
bool* safe_to_add_transition) { |
|
|
|
// Special case: indirect SMI->FAST transition (cf. comment in
|
|
|
|
// AddElementsTransition()).
|
|
|
|
if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS && |
|
|
|
elements_kind == FAST_ELEMENTS) { |
|
|
|
Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, |
|
|
|
ElementsKind from_kind = elements_kind(); |
|
|
|
if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { |
|
|
|
if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { |
|
|
|
if (safe_to_add_transition) *safe_to_add_transition = false; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
ElementsKind transitioned_from_kind = |
|
|
|
GetNextMoreGeneralFastElementsKind(from_kind, false); |
|
|
|
|
|
|
|
|
|
|
|
// If the transition is a single step in the transition sequence, fall
|
|
|
|
// through to looking it up and returning it. If it requires several steps,
|
|
|
|
// divide and conquer.
|
|
|
|
if (transitioned_from_kind != to_kind) { |
|
|
|
// If the transition is several steps in the lattice, divide and conquer.
|
|
|
|
Map* from_map = LookupElementsTransitionMap(transitioned_from_kind, |
|
|
|
safe_to_add_transition); |
|
|
|
if (double_map == NULL) return double_map; |
|
|
|
return double_map->LookupElementsTransitionMap(FAST_ELEMENTS, |
|
|
|
if (from_map == NULL) return NULL; |
|
|
|
return from_map->LookupElementsTransitionMap(to_kind, |
|
|
|
safe_to_add_transition); |
|
|
|
} |
|
|
|
} |
|
|
|
Object* descriptor_contents = GetDescriptorContents( |
|
|
|
elements_transition_sentinel_name(), safe_to_add_transition); |
|
|
|
if (descriptor_contents != NULL) { |
|
|
|
Map* maybe_transition_map = |
|
|
|
GetElementsTransitionMapFromDescriptor(descriptor_contents, |
|
|
|
elements_kind); |
|
|
|
to_kind); |
|
|
|
ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap()); |
|
|
|
return maybe_transition_map; |
|
|
|
} |
|
|
@ -2363,29 +2367,35 @@ Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind, |
|
|
|
MaybeObject* Map::AddElementsTransition(ElementsKind to_kind, |
|
|
|
Map* transitioned_map) { |
|
|
|
// The map transition graph should be a tree, therefore the transition
|
|
|
|
// from SMI to FAST elements is not done directly, but by going through
|
|
|
|
// DOUBLE elements first.
|
|
|
|
if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS && |
|
|
|
elements_kind == FAST_ELEMENTS) { |
|
|
|
ElementsKind from_kind = elements_kind(); |
|
|
|
if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { |
|
|
|
ASSERT(IsMoreGeneralElementsKindTransition(from_kind, to_kind)); |
|
|
|
ElementsKind transitioned_from_kind = |
|
|
|
GetNextMoreGeneralFastElementsKind(from_kind, false); |
|
|
|
// The map transitions graph should be a tree, therefore transitions to
|
|
|
|
// ElementsKind that are not adjacent in the ElementsKind sequence are not
|
|
|
|
// done directly, but instead by going through intermediate ElementsKinds
|
|
|
|
// first.
|
|
|
|
if (to_kind != transitioned_from_kind) { |
|
|
|
bool safe_to_add = true; |
|
|
|
Map* double_map = this->LookupElementsTransitionMap( |
|
|
|
FAST_DOUBLE_ELEMENTS, &safe_to_add); |
|
|
|
// This method is only called when safe_to_add_transition has been found
|
|
|
|
// to be true earlier.
|
|
|
|
Map* intermediate_map = LookupElementsTransitionMap( |
|
|
|
transitioned_from_kind, &safe_to_add); |
|
|
|
// This method is only called when safe_to_add has been found to be true
|
|
|
|
// earlier.
|
|
|
|
ASSERT(safe_to_add); |
|
|
|
|
|
|
|
if (double_map == NULL) { |
|
|
|
MaybeObject* maybe_map = this->CopyDropTransitions(); |
|
|
|
if (!maybe_map->To(&double_map)) return maybe_map; |
|
|
|
double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS); |
|
|
|
MaybeObject* maybe_double_transition = this->AddElementsTransition( |
|
|
|
FAST_DOUBLE_ELEMENTS, double_map); |
|
|
|
if (maybe_double_transition->IsFailure()) return maybe_double_transition; |
|
|
|
if (intermediate_map == NULL) { |
|
|
|
MaybeObject* maybe_map = CopyDropTransitions(); |
|
|
|
if (!maybe_map->To(&intermediate_map)) return maybe_map; |
|
|
|
intermediate_map->set_elements_kind(transitioned_from_kind); |
|
|
|
MaybeObject* maybe_transition = AddElementsTransition( |
|
|
|
transitioned_from_kind, intermediate_map); |
|
|
|
if (maybe_transition->IsFailure()) return maybe_transition; |
|
|
|
} |
|
|
|
return intermediate_map->AddElementsTransition(to_kind, transitioned_map); |
|
|
|
} |
|
|
|
return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map); |
|
|
|
} |
|
|
|
|
|
|
|
bool safe_to_add_transition = true; |
|
|
@ -2437,10 +2447,11 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { |
|
|
|
!current_map->IsUndefined() && |
|
|
|
!current_map->is_shared(); |
|
|
|
|
|
|
|
// Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
|
|
|
|
// Prevent long chains of DICTIONARY -> FAST_*_ELEMENTS maps caused by objects
|
|
|
|
// with elements that switch back and forth between dictionary and fast
|
|
|
|
// element mode.
|
|
|
|
if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) { |
|
|
|
// element modes.
|
|
|
|
if (from_kind == DICTIONARY_ELEMENTS && |
|
|
|
IsFastElementsKind(to_kind)) { |
|
|
|
safe_to_add_transition = false; |
|
|
|
} |
|
|
|
|
|
|
@ -2967,12 +2978,18 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, |
|
|
|
// Preserve the attributes of this existing property.
|
|
|
|
attributes = result->GetAttributes(); |
|
|
|
return ConvertDescriptorToField(name, value, attributes); |
|
|
|
case CALLBACKS: |
|
|
|
return SetPropertyWithCallback(result->GetCallbackObject(), |
|
|
|
case CALLBACKS: { |
|
|
|
Object* callback_object = result->GetCallbackObject(); |
|
|
|
if (callback_object->IsAccessorPair() && |
|
|
|
!AccessorPair::cast(callback_object)->ContainsAccessor()) { |
|
|
|
return ConvertDescriptorToField(name, value, attributes); |
|
|
|
} |
|
|
|
return SetPropertyWithCallback(callback_object, |
|
|
|
name, |
|
|
|
value, |
|
|
|
result->holder(), |
|
|
|
strict_mode); |
|
|
|
} |
|
|
|
case INTERCEPTOR: |
|
|
|
return SetPropertyWithInterceptor(name, value, attributes, strict_mode); |
|
|
|
case CONSTANT_TRANSITION: { |
|
|
@ -3476,8 +3493,7 @@ MaybeObject* JSObject::NormalizeElements() { |
|
|
|
} |
|
|
|
if (array->IsDictionary()) return array; |
|
|
|
|
|
|
|
ASSERT(HasFastElements() || |
|
|
|
HasFastSmiOnlyElements() || |
|
|
|
ASSERT(HasFastSmiOrObjectElements() || |
|
|
|
HasFastDoubleElements() || |
|
|
|
HasFastArgumentsElements()); |
|
|
|
// Compute the effective length and allocate a new backing store.
|
|
|
@ -3512,8 +3528,7 @@ MaybeObject* JSObject::NormalizeElements() { |
|
|
|
if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
|
|
|
} |
|
|
|
} else { |
|
|
|
ASSERT(old_map->has_fast_elements() || |
|
|
|
old_map->has_fast_smi_only_elements()); |
|
|
|
ASSERT(old_map->has_fast_smi_or_object_elements()); |
|
|
|
value = FixedArray::cast(array)->get(i); |
|
|
|
} |
|
|
|
PropertyDetails details = PropertyDetails(NONE, NORMAL); |
|
|
@ -4000,9 +4015,9 @@ MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { |
|
|
|
bool JSObject::ReferencesObjectFromElements(FixedArray* elements, |
|
|
|
ElementsKind kind, |
|
|
|
Object* object) { |
|
|
|
ASSERT(kind == FAST_ELEMENTS || |
|
|
|
ASSERT(IsFastObjectElementsKind(kind) || |
|
|
|
kind == DICTIONARY_ELEMENTS); |
|
|
|
if (kind == FAST_ELEMENTS) { |
|
|
|
if (IsFastObjectElementsKind(kind)) { |
|
|
|
int length = IsJSArray() |
|
|
|
? Smi::cast(JSArray::cast(this)->length())->value() |
|
|
|
: elements->length(); |
|
|
@ -4054,12 +4069,15 @@ bool JSObject::ReferencesObject(Object* obj) { |
|
|
|
case EXTERNAL_FLOAT_ELEMENTS: |
|
|
|
case EXTERNAL_DOUBLE_ELEMENTS: |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: |
|
|
|
// Raw pixels and external arrays do not reference other
|
|
|
|
// objects.
|
|
|
|
break; |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
break; |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: |
|
|
|
case DICTIONARY_ELEMENTS: { |
|
|
|
FixedArray* elements = FixedArray::cast(this->elements()); |
|
|
|
if (ReferencesObjectFromElements(elements, kind, obj)) return true; |
|
|
@ -4075,7 +4093,8 @@ bool JSObject::ReferencesObject(Object* obj) { |
|
|
|
} |
|
|
|
// Check the arguments.
|
|
|
|
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|
|
|
kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS; |
|
|
|
kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : |
|
|
|
FAST_HOLEY_ELEMENTS; |
|
|
|
if (ReferencesObjectFromElements(arguments, kind, obj)) return true; |
|
|
|
break; |
|
|
|
} |
|
|
@ -4309,7 +4328,7 @@ void JSReceiver::Lookup(String* name, LookupResult* result) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Search object and it's prototype chain for callback properties.
|
|
|
|
// Search object and its prototype chain for callback properties.
|
|
|
|
void JSObject::LookupCallback(String* name, LookupResult* result) { |
|
|
|
Heap* heap = GetHeap(); |
|
|
|
for (Object* current = this; |
|
|
@ -4353,9 +4372,12 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index, |
|
|
|
Object* setter, |
|
|
|
PropertyAttributes attributes) { |
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: |
|
|
|
break; |
|
|
|
case EXTERNAL_PIXEL_ELEMENTS: |
|
|
|
case EXTERNAL_BYTE_ELEMENTS: |
|
|
@ -4472,7 +4494,7 @@ bool JSObject::CanSetCallback(String* name) { |
|
|
|
GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET)); |
|
|
|
|
|
|
|
// Check if there is an API defined callback object which prohibits
|
|
|
|
// callback overwriting in this object or it's prototype chain.
|
|
|
|
// callback overwriting in this object or its prototype chain.
|
|
|
|
// This mechanism is needed for instance in a browser setting, where
|
|
|
|
// certain accessors such as window.location should not be allowed
|
|
|
|
// to be overwritten because allowing overwriting could potentially
|
|
|
@ -4730,7 +4752,7 @@ MaybeObject* JSObject::DefineFastAccessor(String* name, |
|
|
|
|
|
|
|
// If the property is not a JavaScript accessor, fall back to the slow case.
|
|
|
|
if (result.type() != CALLBACKS) return GetHeap()->null_value(); |
|
|
|
Object* callback_value = result.GetValue(); |
|
|
|
Object* callback_value = result.GetCallbackObject(); |
|
|
|
if (!callback_value->IsAccessorPair()) return GetHeap()->null_value(); |
|
|
|
AccessorPair* accessors = AccessorPair::cast(callback_value); |
|
|
|
|
|
|
@ -4796,9 +4818,12 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
|
|
|
|
|
|
|
// Accessors overwrite previous callbacks (cf. with getters/setters).
|
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: |
|
|
|
break; |
|
|
|
case EXTERNAL_PIXEL_ELEMENTS: |
|
|
|
case EXTERNAL_BYTE_ELEMENTS: |
|
|
@ -5915,21 +5940,15 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, |
|
|
|
int index = Search(descriptor->GetKey()); |
|
|
|
const bool replacing = (index != kNotFound); |
|
|
|
bool keep_enumeration_index = false; |
|
|
|
if (replacing) { |
|
|
|
// We are replacing an existing descriptor. We keep the enumeration
|
|
|
|
// index of a visible property.
|
|
|
|
PropertyType t = GetDetails(index).type(); |
|
|
|
if (t == CONSTANT_FUNCTION || |
|
|
|
t == FIELD || |
|
|
|
t == CALLBACKS || |
|
|
|
t == INTERCEPTOR) { |
|
|
|
if (!replacing) { |
|
|
|
++new_size; |
|
|
|
} else if (!IsTransitionOnly(index)) { |
|
|
|
// We are replacing an existing descriptor. We keep the enumeration index
|
|
|
|
// of a visible property.
|
|
|
|
keep_enumeration_index = true; |
|
|
|
} else if (remove_transitions) { |
|
|
|
// Replaced descriptor has been counted as removed if it is
|
|
|
|
// a transition that will be replaced. Adjust count in this case.
|
|
|
|
++new_size; |
|
|
|
} |
|
|
|
} else { |
|
|
|
// Replaced descriptor has been counted as removed if it is a transition
|
|
|
|
// that will be replaced. Adjust count in this case.
|
|
|
|
++new_size; |
|
|
|
} |
|
|
|
|
|
|
@ -8587,7 +8606,7 @@ void Code::Disassemble(const char* name, FILE* out) { |
|
|
|
MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
|
|
|
int capacity, |
|
|
|
int length, |
|
|
|
SetFastElementsCapacityMode set_capacity_mode) { |
|
|
|
SetFastElementsCapacitySmiMode smi_mode) { |
|
|
|
Heap* heap = GetHeap(); |
|
|
|
// We should never end in here with a pixel or external array.
|
|
|
|
ASSERT(!HasExternalArrayElements()); |
|
|
@ -8598,34 +8617,40 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
|
|
|
if (!maybe->To(&new_elements)) return maybe; |
|
|
|
} |
|
|
|
|
|
|
|
// Find the new map to use for this object if there is a map change.
|
|
|
|
Map* new_map = NULL; |
|
|
|
if (elements()->map() != heap->non_strict_arguments_elements_map()) { |
|
|
|
// The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
|
|
|
|
// it, or if it's allowed and the old elements array contained only SMIs.
|
|
|
|
bool has_fast_smi_only_elements = |
|
|
|
(set_capacity_mode == kForceSmiOnlyElements) || |
|
|
|
((set_capacity_mode == kAllowSmiOnlyElements) && |
|
|
|
(elements()->map()->has_fast_smi_only_elements() || |
|
|
|
elements() == heap->empty_fixed_array())); |
|
|
|
ElementsKind elements_kind = has_fast_smi_only_elements |
|
|
|
? FAST_SMI_ONLY_ELEMENTS |
|
|
|
: FAST_ELEMENTS; |
|
|
|
MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind); |
|
|
|
if (!maybe->To(&new_map)) return maybe; |
|
|
|
ElementsKind elements_kind = GetElementsKind(); |
|
|
|
ElementsKind new_elements_kind; |
|
|
|
// The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
|
|
|
|
// or if it's allowed and the old elements array contained only SMIs.
|
|
|
|
bool has_fast_smi_elements = |
|
|
|
(smi_mode == kForceSmiElements) || |
|
|
|
((smi_mode == kAllowSmiElements) && HasFastSmiElements()); |
|
|
|
if (has_fast_smi_elements) { |
|
|
|
if (IsHoleyElementsKind(elements_kind)) { |
|
|
|
new_elements_kind = FAST_HOLEY_SMI_ELEMENTS; |
|
|
|
} else { |
|
|
|
new_elements_kind = FAST_SMI_ELEMENTS; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (IsHoleyElementsKind(elements_kind)) { |
|
|
|
new_elements_kind = FAST_HOLEY_ELEMENTS; |
|
|
|
} else { |
|
|
|
new_elements_kind = FAST_ELEMENTS; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FixedArrayBase* old_elements = elements(); |
|
|
|
ElementsKind elements_kind = GetElementsKind(); |
|
|
|
ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); |
|
|
|
ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS) |
|
|
|
? FAST_SMI_ONLY_ELEMENTS |
|
|
|
: FAST_ELEMENTS; |
|
|
|
{ MaybeObject* maybe_obj = |
|
|
|
accessor->CopyElements(this, new_elements, to_kind); |
|
|
|
accessor->CopyElements(this, new_elements, new_elements_kind); |
|
|
|
if (maybe_obj->IsFailure()) return maybe_obj; |
|
|
|
} |
|
|
|
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) { |
|
|
|
Map* new_map = map(); |
|
|
|
if (new_elements_kind != elements_kind) { |
|
|
|
MaybeObject* maybe = |
|
|
|
GetElementsTransitionMap(GetIsolate(), new_elements_kind); |
|
|
|
if (!maybe->To(&new_map)) return maybe; |
|
|
|
} |
|
|
|
ValidateElements(); |
|
|
|
set_map_and_elements(new_map, new_elements); |
|
|
|
} else { |
|
|
|
FixedArray* parameter_map = FixedArray::cast(old_elements); |
|
|
@ -8637,11 +8662,9 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
|
|
|
GetElementsKind(), new_elements); |
|
|
|
} |
|
|
|
|
|
|
|
// Update the length if necessary.
|
|
|
|
if (IsJSArray()) { |
|
|
|
JSArray::cast(this)->set_length(Smi::FromInt(length)); |
|
|
|
} |
|
|
|
|
|
|
|
return new_elements; |
|
|
|
} |
|
|
|
|
|
|
@ -8659,20 +8682,28 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
|
|
|
if (!maybe_obj->To(&elems)) return maybe_obj; |
|
|
|
} |
|
|
|
|
|
|
|
ElementsKind elements_kind = GetElementsKind(); |
|
|
|
ElementsKind new_elements_kind = elements_kind; |
|
|
|
if (IsHoleyElementsKind(elements_kind)) { |
|
|
|
new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS; |
|
|
|
} else { |
|
|
|
new_elements_kind = FAST_DOUBLE_ELEMENTS; |
|
|
|
} |
|
|
|
|
|
|
|
Map* new_map; |
|
|
|
{ MaybeObject* maybe_obj = |
|
|
|
GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS); |
|
|
|
GetElementsTransitionMap(heap->isolate(), new_elements_kind); |
|
|
|
if (!maybe_obj->To(&new_map)) return maybe_obj; |
|
|
|
} |
|
|
|
|
|
|
|
FixedArrayBase* old_elements = elements(); |
|
|
|
ElementsKind elements_kind = GetElementsKind(); |
|
|
|
ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); |
|
|
|
{ MaybeObject* maybe_obj = |
|
|
|
accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS); |
|
|
|
if (maybe_obj->IsFailure()) return maybe_obj; |
|
|
|
} |
|
|
|
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) { |
|
|
|
ValidateElements(); |
|
|
|
set_map_and_elements(new_map, elems); |
|
|
|
} else { |
|
|
|
FixedArray* parameter_map = FixedArray::cast(old_elements); |
|
|
@ -8681,7 +8712,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
|
|
|
|
|
|
|
if (FLAG_trace_elements_transitions) { |
|
|
|
PrintElementsTransition(stdout, elements_kind, old_elements, |
|
|
|
FAST_DOUBLE_ELEMENTS, elems); |
|
|
|
GetElementsKind(), elems); |
|
|
|
} |
|
|
|
|
|
|
|
if (IsJSArray()) { |
|
|
@ -8961,8 +8992,10 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { |
|
|
|
} |
|
|
|
|
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: { |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: { |
|
|
|
uint32_t length = IsJSArray() ? |
|
|
|
static_cast<uint32_t> |
|
|
|
(Smi::cast(JSArray::cast(this)->length())->value()) : |
|
|
@ -8973,7 +9006,8 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case FAST_DOUBLE_ELEMENTS: { |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: { |
|
|
|
uint32_t length = IsJSArray() ? |
|
|
|
static_cast<uint32_t> |
|
|
|
(Smi::cast(JSArray::cast(this)->length())->value()) : |
|
|
@ -9257,7 +9291,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
|
|
|
Object* value, |
|
|
|
StrictModeFlag strict_mode, |
|
|
|
bool check_prototype) { |
|
|
|
ASSERT(HasFastTypeElements() || |
|
|
|
ASSERT(HasFastSmiOrObjectElements() || |
|
|
|
HasFastArgumentsElements()); |
|
|
|
|
|
|
|
FixedArray* backing_store = FixedArray::cast(elements()); |
|
|
@ -9283,13 +9317,29 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
|
|
|
// 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 (IsJSArray()) { |
|
|
|
CHECK(JSArray::cast(this)->length()->ToArrayIndex(&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; |
|
|
|
} |
|
|
|
|
|
|
|
// 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 elements_kind = GetElementsKind(); |
|
|
|
if (introduces_holes && |
|
|
|
IsFastElementsKind(elements_kind) && |
|
|
|
!IsFastHoleyElementsKind(elements_kind)) { |
|
|
|
ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); |
|
|
|
MaybeObject* maybe = TransitionElementsKind(transitioned_kind); |
|
|
|
if (maybe->IsFailure()) return maybe; |
|
|
|
} |
|
|
|
|
|
|
|
// Check if the capacity of the backing store needs to be increased, or if
|
|
|
|
// a transition to slow elements is necessary.
|
|
|
|
if (index >= capacity) { |
|
|
@ -9309,42 +9359,44 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
|
|
|
} |
|
|
|
} |
|
|
|
// Convert to fast double elements if appropriate.
|
|
|
|
if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) { |
|
|
|
if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) { |
|
|
|
MaybeObject* maybe = |
|
|
|
SetFastDoubleElementsCapacityAndLength(new_capacity, array_length); |
|
|
|
if (maybe->IsFailure()) return maybe; |
|
|
|
FixedDoubleArray::cast(elements())->set(index, value->Number()); |
|
|
|
ValidateElements(); |
|
|
|
return value; |
|
|
|
} |
|
|
|
// Change elements kind from SMI_ONLY to generic FAST if necessary.
|
|
|
|
if (HasFastSmiOnlyElements() && !value->IsSmi()) { |
|
|
|
// Change elements kind from Smi-only to generic FAST if necessary.
|
|
|
|
if (HasFastSmiElements() && !value->IsSmi()) { |
|
|
|
Map* new_map; |
|
|
|
{ MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(), |
|
|
|
FAST_ELEMENTS); |
|
|
|
ElementsKind kind = HasFastHoleyElements() |
|
|
|
? FAST_HOLEY_ELEMENTS |
|
|
|
: FAST_ELEMENTS; |
|
|
|
MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(), |
|
|
|
kind); |
|
|
|
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
|
|
|
} |
|
|
|
|
|
|
|
set_map(new_map); |
|
|
|
if (FLAG_trace_elements_transitions) { |
|
|
|
PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(), |
|
|
|
FAST_ELEMENTS, elements()); |
|
|
|
} |
|
|
|
} |
|
|
|
// Increase backing store capacity if that's been decided previously.
|
|
|
|
if (new_capacity != capacity) { |
|
|
|
FixedArray* new_elements; |
|
|
|
SetFastElementsCapacityMode set_capacity_mode = |
|
|
|
value->IsSmi() && HasFastSmiOnlyElements() |
|
|
|
? kAllowSmiOnlyElements |
|
|
|
: kDontAllowSmiOnlyElements; |
|
|
|
SetFastElementsCapacitySmiMode smi_mode = |
|
|
|
value->IsSmi() && HasFastSmiElements() |
|
|
|
? kAllowSmiElements |
|
|
|
: kDontAllowSmiElements; |
|
|
|
{ MaybeObject* maybe = |
|
|
|
SetFastElementsCapacityAndLength(new_capacity, |
|
|
|
array_length, |
|
|
|
set_capacity_mode); |
|
|
|
smi_mode); |
|
|
|
if (!maybe->To(&new_elements)) return maybe; |
|
|
|
} |
|
|
|
new_elements->set(index, value); |
|
|
|
ValidateElements(); |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
// Finally, set the new element and length.
|
|
|
|
ASSERT(elements()->IsFixedArray()); |
|
|
|
backing_store->set(index, value); |
|
|
@ -9468,20 +9520,21 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, |
|
|
|
} else { |
|
|
|
new_length = dictionary->max_number_key() + 1; |
|
|
|
} |
|
|
|
SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays |
|
|
|
? kAllowSmiOnlyElements |
|
|
|
: kDontAllowSmiOnlyElements; |
|
|
|
SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays |
|
|
|
? kAllowSmiElements |
|
|
|
: kDontAllowSmiElements; |
|
|
|
bool has_smi_only_elements = false; |
|
|
|
bool should_convert_to_fast_double_elements = |
|
|
|
ShouldConvertToFastDoubleElements(&has_smi_only_elements); |
|
|
|
if (has_smi_only_elements) { |
|
|
|
set_capacity_mode = kForceSmiOnlyElements; |
|
|
|
smi_mode = kForceSmiElements; |
|
|
|
} |
|
|
|
MaybeObject* result = should_convert_to_fast_double_elements |
|
|
|
? SetFastDoubleElementsCapacityAndLength(new_length, new_length) |
|
|
|
: SetFastElementsCapacityAndLength(new_length, |
|
|
|
new_length, |
|
|
|
set_capacity_mode); |
|
|
|
smi_mode); |
|
|
|
ValidateElements(); |
|
|
|
if (result->IsFailure()) return result; |
|
|
|
#ifdef DEBUG |
|
|
|
if (FLAG_trace_normalization) { |
|
|
@ -9520,27 +9573,40 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
|
|
|
// If the value object is not a heap number, switch to fast elements and try
|
|
|
|
// again.
|
|
|
|
bool value_is_smi = value->IsSmi(); |
|
|
|
if (!value->IsNumber()) { |
|
|
|
Object* obj; |
|
|
|
bool introduces_holes = true; |
|
|
|
uint32_t length = elms_length; |
|
|
|
if (IsJSArray()) { |
|
|
|
CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
|
|
|
introduces_holes = index > length; |
|
|
|
} else { |
|
|
|
introduces_holes = index >= elms_length; |
|
|
|
} |
|
|
|
|
|
|
|
if (!value->IsNumber()) { |
|
|
|
MaybeObject* maybe_obj = SetFastElementsCapacityAndLength( |
|
|
|
elms_length, |
|
|
|
length, |
|
|
|
kDontAllowSmiOnlyElements); |
|
|
|
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
|
|
|
return SetFastElement(index, |
|
|
|
value, |
|
|
|
strict_mode, |
|
|
|
check_prototype); |
|
|
|
kDontAllowSmiElements); |
|
|
|
if (maybe_obj->IsFailure()) return maybe_obj; |
|
|
|
maybe_obj = SetFastElement(index, value, strict_mode, check_prototype); |
|
|
|
if (maybe_obj->IsFailure()) return maybe_obj; |
|
|
|
ValidateElements(); |
|
|
|
return maybe_obj; |
|
|
|
} |
|
|
|
|
|
|
|
double double_value = value_is_smi |
|
|
|
? static_cast<double>(Smi::cast(value)->value()) |
|
|
|
: HeapNumber::cast(value)->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.
|
|
|
|
ElementsKind elements_kind = GetElementsKind(); |
|
|
|
if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) { |
|
|
|
ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); |
|
|
|
MaybeObject* maybe = TransitionElementsKind(transitioned_kind); |
|
|
|
if (maybe->IsFailure()) return maybe; |
|
|
|
} |
|
|
|
|
|
|
|
// Check whether there is extra space in the fixed array.
|
|
|
|
if (index < elms_length) { |
|
|
|
FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
|
|
@ -9562,13 +9628,11 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
|
|
|
int new_capacity = NewElementsCapacity(index+1); |
|
|
|
if (!ShouldConvertToSlowElements(new_capacity)) { |
|
|
|
ASSERT(static_cast<uint32_t>(new_capacity) > index); |
|
|
|
Object* obj; |
|
|
|
{ MaybeObject* maybe_obj = |
|
|
|
SetFastDoubleElementsCapacityAndLength(new_capacity, |
|
|
|
index + 1); |
|
|
|
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
|
|
|
} |
|
|
|
MaybeObject* maybe_obj = |
|
|
|
SetFastDoubleElementsCapacityAndLength(new_capacity, index + 1); |
|
|
|
if (maybe_obj->IsFailure()) return maybe_obj; |
|
|
|
FixedDoubleArray::cast(elements())->set(index, double_value); |
|
|
|
ValidateElements(); |
|
|
|
return value; |
|
|
|
} |
|
|
|
} |
|
|
@ -9712,10 +9776,13 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
|
|
|
(attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0); |
|
|
|
Isolate* isolate = GetIsolate(); |
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: |
|
|
|
return SetFastElement(index, value, strict_mode, check_prototype); |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: |
|
|
|
return SetFastDoubleElement(index, value, strict_mode, check_prototype); |
|
|
|
case EXTERNAL_PIXEL_ELEMENTS: { |
|
|
|
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
|
|
@ -9806,11 +9873,19 @@ Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object, |
|
|
|
MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { |
|
|
|
ElementsKind from_kind = map()->elements_kind(); |
|
|
|
|
|
|
|
if (IsFastHoleyElementsKind(from_kind)) { |
|
|
|
to_kind = GetHoleyElementsKind(to_kind); |
|
|
|
} |
|
|
|
|
|
|
|
Isolate* isolate = GetIsolate(); |
|
|
|
if ((from_kind == FAST_SMI_ONLY_ELEMENTS || |
|
|
|
elements() == isolate->heap()->empty_fixed_array()) && |
|
|
|
to_kind == FAST_ELEMENTS) { |
|
|
|
ASSERT(from_kind != FAST_ELEMENTS); |
|
|
|
if (elements() == isolate->heap()->empty_fixed_array() || |
|
|
|
(IsFastSmiOrObjectElementsKind(from_kind) && |
|
|
|
IsFastSmiOrObjectElementsKind(to_kind)) || |
|
|
|
(from_kind == FAST_DOUBLE_ELEMENTS && |
|
|
|
to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { |
|
|
|
ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); |
|
|
|
// No change is needed to the elements() buffer, the transition
|
|
|
|
// only requires a map change.
|
|
|
|
MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind); |
|
|
|
Map* new_map; |
|
|
|
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
|
|
@ -9837,18 +9912,21 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (from_kind == FAST_SMI_ONLY_ELEMENTS && |
|
|
|
to_kind == FAST_DOUBLE_ELEMENTS) { |
|
|
|
if (IsFastSmiElementsKind(from_kind) && |
|
|
|
IsFastDoubleElementsKind(to_kind)) { |
|
|
|
MaybeObject* maybe_result = |
|
|
|
SetFastDoubleElementsCapacityAndLength(capacity, length); |
|
|
|
if (maybe_result->IsFailure()) return maybe_result; |
|
|
|
ValidateElements(); |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
|
if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { |
|
|
|
if (IsFastDoubleElementsKind(from_kind) && |
|
|
|
IsFastObjectElementsKind(to_kind)) { |
|
|
|
MaybeObject* maybe_result = SetFastElementsCapacityAndLength( |
|
|
|
capacity, length, kDontAllowSmiOnlyElements); |
|
|
|
capacity, length, kDontAllowSmiElements); |
|
|
|
if (maybe_result->IsFailure()) return maybe_result; |
|
|
|
ValidateElements(); |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
@ -9862,10 +9940,14 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { |
|
|
|
// static
|
|
|
|
bool Map::IsValidElementsTransition(ElementsKind from_kind, |
|
|
|
ElementsKind to_kind) { |
|
|
|
return |
|
|
|
(from_kind == FAST_SMI_ONLY_ELEMENTS && |
|
|
|
(to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) || |
|
|
|
(from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS); |
|
|
|
// Transitions can't go backwards.
|
|
|
|
if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Transitions from HOLEY -> PACKED are not allowed.
|
|
|
|
return !IsFastHoleyElementsKind(from_kind) || |
|
|
|
IsFastHoleyElementsKind(to_kind); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -9956,8 +10038,10 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
|
|
|
break; |
|
|
|
} |
|
|
|
// Fall through.
|
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: |
|
|
|
backing_store = FixedArray::cast(backing_store_base); |
|
|
|
*capacity = backing_store->length(); |
|
|
|
for (int i = 0; i < *capacity; ++i) { |
|
|
@ -9971,7 +10055,8 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
|
|
|
*used = dictionary->NumberOfElements(); |
|
|
|
break; |
|
|
|
} |
|
|
|
case FAST_DOUBLE_ELEMENTS: { |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: { |
|
|
|
FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
|
|
|
*capacity = elms->length(); |
|
|
|
for (int i = 0; i < *capacity; i++) { |
|
|
@ -10241,8 +10326,10 @@ bool JSObject::HasRealElementProperty(uint32_t index) { |
|
|
|
if (this->IsStringObjectWithCharacterAt(index)) return true; |
|
|
|
|
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: { |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: { |
|
|
|
uint32_t length = IsJSArray() ? |
|
|
|
static_cast<uint32_t>( |
|
|
|
Smi::cast(JSArray::cast(this)->length())->value()) : |
|
|
@ -10250,7 +10337,8 @@ bool JSObject::HasRealElementProperty(uint32_t index) { |
|
|
|
return (index < length) && |
|
|
|
!FixedArray::cast(elements())->get(index)->IsTheHole(); |
|
|
|
} |
|
|
|
case FAST_DOUBLE_ELEMENTS: { |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: { |
|
|
|
uint32_t length = IsJSArray() ? |
|
|
|
static_cast<uint32_t>( |
|
|
|
Smi::cast(JSArray::cast(this)->length())->value()) : |
|
|
@ -10450,7 +10538,7 @@ int JSObject::NumberOfLocalElements(PropertyAttributes filter) { |
|
|
|
|
|
|
|
int JSObject::NumberOfEnumElements() { |
|
|
|
// Fast case for objects with no elements.
|
|
|
|
if (!IsJSValue() && HasFastElements()) { |
|
|
|
if (!IsJSValue() && HasFastObjectElements()) { |
|
|
|
uint32_t length = IsJSArray() ? |
|
|
|
static_cast<uint32_t>( |
|
|
|
Smi::cast(JSArray::cast(this)->length())->value()) : |
|
|
@ -10466,8 +10554,10 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, |
|
|
|
PropertyAttributes filter) { |
|
|
|
int counter = 0; |
|
|
|
switch (GetElementsKind()) { |
|
|
|
case FAST_SMI_ONLY_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: { |
|
|
|
case FAST_SMI_ELEMENTS: |
|
|
|
case FAST_ELEMENTS: |
|
|
|
case FAST_HOLEY_SMI_ELEMENTS: |
|
|
|
case FAST_HOLEY_ELEMENTS: { |
|
|
|
int length = IsJSArray() ? |
|
|
|
Smi::cast(JSArray::cast(this)->length())->value() : |
|
|
|
FixedArray::cast(elements())->length(); |
|
|
@ -10482,7 +10572,8 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, |
|
|
|
ASSERT(!storage || storage->length() >= counter); |
|
|
|
break; |
|
|
|
} |
|
|
|
case FAST_DOUBLE_ELEMENTS: { |
|
|
|
case FAST_DOUBLE_ELEMENTS: |
|
|
|
case FAST_HOLEY_DOUBLE_ELEMENTS: { |
|
|
|
int length = IsJSArray() ? |
|
|
|
Smi::cast(JSArray::cast(this)->length())->value() : |
|
|
|
FixedDoubleArray::cast(elements())->length(); |
|
|
@ -11415,10 +11506,9 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { |
|
|
|
// Convert to fast elements.
|
|
|
|
|
|
|
|
Object* obj; |
|
|
|
{ MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(), |
|
|
|
FAST_ELEMENTS); |
|
|
|
MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(), |
|
|
|
FAST_HOLEY_ELEMENTS); |
|
|
|
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
|
|
|
} |
|
|
|
Map* new_map = Map::cast(obj); |
|
|
|
|
|
|
|
PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; |
|
|
@ -11429,9 +11519,9 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { |
|
|
|
} |
|
|
|
FixedArray* fast_elements = FixedArray::cast(new_array); |
|
|
|
dict->CopyValuesTo(fast_elements); |
|
|
|
ValidateElements(); |
|
|
|
|
|
|
|
set_map(new_map); |
|
|
|
set_elements(fast_elements); |
|
|
|
set_map_and_elements(new_map, fast_elements); |
|
|
|
} else if (HasExternalArrayElements()) { |
|
|
|
// External arrays cannot have holes or undefined elements.
|
|
|
|
return Smi::FromInt(ExternalArray::cast(elements())->length()); |
|
|
@ -11441,7 +11531,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { |
|
|
|
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
|
|
|
} |
|
|
|
} |
|
|
|
ASSERT(HasFastTypeElements() || HasFastDoubleElements()); |
|
|
|
ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements()); |
|
|
|
|
|
|
|
// Collect holes at the end, undefined before that and the rest at the
|
|
|
|
// start, and return the number of non-hole, non-undefined values.
|
|
|
|