Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 94671d094e772e37096ea6309bb12b872f06d545..f894bc52b9e81e066f37470c1e444e6a399a3b9f 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -3063,6 +3063,7 @@ MaybeObject* JSObject::NormalizeElements() { |
if (array->IsDictionary()) return array; |
ASSERT(HasFastElements() || |
+ HasFastSmiOnlyElements() || |
HasFastDoubleElements() || |
HasFastArgumentsElements()); |
// Compute the effective length and allocate a new backing store. |
@@ -3097,7 +3098,8 @@ MaybeObject* JSObject::NormalizeElements() { |
if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
} |
} else { |
- ASSERT(old_map->has_fast_elements()); |
+ ASSERT(old_map->has_fast_elements() || |
+ old_map->has_fast_smi_only_elements()); |
value = FixedArray::cast(array)->get(i); |
} |
PropertyDetails details = PropertyDetails(NONE, NORMAL); |
@@ -3412,7 +3414,8 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
bool JSObject::ReferencesObjectFromElements(FixedArray* elements, |
ElementsKind kind, |
Object* object) { |
- ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); |
+ ASSERT(kind == FAST_ELEMENTS || |
+ kind == DICTIONARY_ELEMENTS); |
if (kind == FAST_ELEMENTS) { |
int length = IsJSArray() |
? Smi::cast(JSArray::cast(this)->length())->value() |
@@ -3467,6 +3470,8 @@ bool JSObject::ReferencesObject(Object* obj) { |
// Raw pixels and external arrays do not reference other |
// objects. |
break; |
+ case FAST_SMI_ONLY_ELEMENTS: |
+ break; |
case FAST_ELEMENTS: |
case DICTIONARY_ELEMENTS: { |
FixedArray* elements = FixedArray::cast(this->elements()); |
@@ -3758,6 +3763,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name, |
if (is_element) { |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
break; |
@@ -4007,6 +4013,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
// Accessors overwrite previous callbacks (cf. with getters/setters). |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
break; |
@@ -7416,8 +7423,10 @@ static void CopySlowElementsToFast(NumberDictionary* source, |
} |
-MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
- int length) { |
+MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
+ int capacity, |
+ int length, |
+ SetFastElementsCapacityMode set_capacity_mode) { |
Heap* heap = GetHeap(); |
// We should never end in here with a pixel or external array. |
ASSERT(!HasExternalArrayElements()); |
@@ -7434,15 +7443,25 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
Map* new_map = NULL; |
if (elements()->map() != heap->non_strict_arguments_elements_map()) { |
Object* object; |
- MaybeObject* maybe = GetElementsTransitionMap(FAST_ELEMENTS); |
+ bool has_fast_smi_only_elements = |
+ FLAG_smi_only_arrays && |
+ (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(elements_kind); |
if (!maybe->ToObject(&object)) return maybe; |
new_map = Map::cast(object); |
} |
- switch (GetElementsKind()) { |
+ ElementsKind elements_kind = GetElementsKind(); |
+ switch (elements_kind) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
AssertNoAllocation no_gc; |
- WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); |
+ WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc)); |
CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); |
set_map(new_map); |
set_elements(new_elements); |
@@ -7545,6 +7564,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
AssertNoAllocation no_gc; |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
elems->Initialize(FixedArray::cast(elements())); |
break; |
@@ -7582,8 +7602,9 @@ MaybeObject* JSObject::SetSlowElements(Object* len) { |
uint32_t new_length = static_cast<uint32_t>(len->Number()); |
switch (GetElementsKind()) { |
- case FAST_ELEMENTS: { |
- case FAST_DOUBLE_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
+ case FAST_ELEMENTS: |
+ case FAST_DOUBLE_ELEMENTS: { |
// Make sure we never try to shrink dense arrays into sparse arrays. |
ASSERT(static_cast<uint32_t>( |
FixedArrayBase::cast(elements())->length()) <= new_length); |
@@ -7649,7 +7670,7 @@ void JSArray::Expand(int required_size) { |
Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); |
// Can't use this any more now because we may have had a GC! |
for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); |
- self->SetContent(*new_backing); |
+ GetIsolate()->factory()->SetContent(self, new_backing); |
} |
@@ -7672,13 +7693,15 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
if (value < 0) return ArrayLengthRangeError(GetHeap()); |
ElementsKind elements_kind = GetElementsKind(); |
switch (elements_kind) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: { |
int old_capacity = FixedArrayBase::cast(elements())->length(); |
if (value <= old_capacity) { |
if (IsJSArray()) { |
Object* obj; |
- if (elements_kind == FAST_ELEMENTS) { |
+ if (elements_kind == FAST_ELEMENTS || |
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
MaybeObject* maybe_obj = EnsureWritableFastElements(); |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
} |
@@ -7689,7 +7712,8 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
} else { |
Address filler_start; |
int filler_size; |
- if (GetElementsKind() == FAST_ELEMENTS) { |
+ if (elements_kind == FAST_ELEMENTS || |
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
FixedArray* fast_elements = FixedArray::cast(elements()); |
fast_elements->set_length(value); |
filler_start = fast_elements->address() + |
@@ -7709,13 +7733,14 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
} else { |
// Otherwise, fill the unused tail with holes. |
int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
- if (GetElementsKind() == FAST_ELEMENTS) { |
+ if (elements_kind == FAST_ELEMENTS || |
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
FixedArray* fast_elements = FixedArray::cast(elements()); |
for (int i = value; i < old_length; i++) { |
fast_elements->set_the_hole(i); |
} |
} else { |
- ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); |
+ ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS); |
FixedDoubleArray* fast_double_elements = |
FixedDoubleArray::cast(elements()); |
for (int i = value; i < old_length; i++) { |
@@ -7731,10 +7756,17 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
int new_capacity = value > min ? value : min; |
if (!ShouldConvertToSlowElements(new_capacity)) { |
MaybeObject* result; |
- if (GetElementsKind() == FAST_ELEMENTS) { |
- result = SetFastElementsCapacityAndLength(new_capacity, value); |
+ if (elements_kind == FAST_ELEMENTS || |
+ elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ SetFastElementsCapacityMode set_capacity_mode = |
+ elements_kind == FAST_SMI_ONLY_ELEMENTS |
+ ? kAllowSmiOnlyElements |
+ : kDontAllowSmiOnlyElements; |
+ result = SetFastElementsCapacityAndLength(new_capacity, |
+ value, |
+ set_capacity_mode); |
} else { |
- ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); |
+ ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS); |
result = SetFastDoubleElementsCapacityAndLength(new_capacity, |
value); |
} |
@@ -7791,10 +7823,13 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
// len is not a number so make the array size one and |
// set only element to len. |
Object* obj; |
- { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); |
- if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
- } |
+ MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); |
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
FixedArray::cast(obj)->set(0, len); |
+ |
+ maybe_obj = EnsureCanContainElements(&len, 1); |
+ if (maybe_obj->IsFailure()) return maybe_obj; |
+ |
if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); |
set_elements(FixedArray::cast(obj)); |
return this; |
@@ -7942,8 +7977,16 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, |
} |
+MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, |
+ uint32_t first_arg, |
+ uint32_t arg_count) { |
+ return EnsureCanContainElements(args->arguments() - first_arg, arg_count); |
+} |
+ |
+ |
bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
uint32_t length = IsJSArray() ? |
static_cast<uint32_t> |
@@ -8085,6 +8128,7 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { |
} |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
uint32_t length = IsJSArray() ? |
static_cast<uint32_t> |
@@ -8199,6 +8243,7 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { |
ElementsKind kind = GetElementsKind(); |
switch (kind) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
uint32_t length = IsJSArray() ? |
static_cast<uint32_t> |
@@ -8453,7 +8498,8 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
Object* value, |
StrictModeFlag strict_mode, |
bool check_prototype) { |
- ASSERT(HasFastElements() || HasFastArgumentsElements()); |
+ ASSERT(HasFastTypeElements() || |
+ HasFastArgumentsElements()); |
FixedArray* backing_store = FixedArray::cast(elements()); |
if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) { |
@@ -8478,6 +8524,24 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
// Check whether there is extra space in fixed array. |
if (index < length) { |
+ if (HasFastSmiOnlyElements()) { |
+ if (!value->IsSmi()) { |
+ // If the value is a number, transition from smi-only to |
+ // FastDoubleElements. |
+ if (value->IsNumber()) { |
+ MaybeObject* maybe = |
+ SetFastDoubleElementsCapacityAndLength(length, length); |
+ if (maybe->IsFailure()) return maybe; |
+ FixedDoubleArray::cast(elements())->set(index, value->Number()); |
+ return value; |
+ } |
+ // Value is not a number, transition to generic fast elements. |
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS); |
+ Map* new_map; |
+ if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map; |
+ set_map(new_map); |
+ } |
+ } |
backing_store->set(index, value); |
if (IsJSArray()) { |
// Update the length of the array if needed. |
@@ -8497,8 +8561,14 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
if (!ShouldConvertToSlowElements(new_capacity)) { |
ASSERT(static_cast<uint32_t>(new_capacity) > index); |
Object* new_elements; |
+ SetFastElementsCapacityMode set_capacity_mode = |
+ value->IsSmi() && HasFastSmiOnlyElements() |
+ ? kAllowSmiOnlyElements |
+ : kDontAllowSmiOnlyElements; |
MaybeObject* maybe = |
- SetFastElementsCapacityAndLength(new_capacity, index + 1); |
+ SetFastElementsCapacityAndLength(new_capacity, |
+ index + 1, |
+ set_capacity_mode); |
if (!maybe->ToObject(&new_elements)) return maybe; |
FixedArray::cast(new_elements)->set(index, value); |
return value; |
@@ -8604,7 +8674,9 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, |
} |
MaybeObject* result = CanConvertToFastDoubleElements() |
? SetFastDoubleElementsCapacityAndLength(new_length, new_length) |
- : SetFastElementsCapacityAndLength(new_length, new_length); |
+ : SetFastElementsCapacityAndLength(new_length, |
+ new_length, |
+ kDontAllowSmiOnlyElements); |
if (result->IsFailure()) return result; |
#ifdef DEBUG |
if (FLAG_trace_normalization) { |
@@ -8648,10 +8720,15 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
if (IsJSArray()) { |
CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
} |
- MaybeObject* maybe_obj = |
- SetFastElementsCapacityAndLength(elms_length, length); |
+ MaybeObject* maybe_obj = SetFastElementsCapacityAndLength( |
+ elms_length, |
+ length, |
+ kDontAllowSmiOnlyElements); |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
- return SetFastElement(index, value, strict_mode, check_prototype); |
+ return SetFastElement(index, |
+ value, |
+ strict_mode, |
+ check_prototype); |
} |
double double_value = value_is_smi |
@@ -8759,6 +8836,7 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
bool check_prototype) { |
Isolate* isolate = GetIsolate(); |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: |
return SetFastElement(index, value, strict_mode, check_prototype); |
case FAST_DOUBLE_ELEMENTS: |
@@ -8921,6 +8999,7 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
break; |
} |
// Fall through. |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: |
backing_store = FixedArray::cast(backing_store_base); |
*capacity = backing_store->length(); |
@@ -9196,6 +9275,7 @@ bool JSObject::HasRealElementProperty(uint32_t index) { |
if (this->IsStringObjectWithCharacterAt(index)) return true; |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
uint32_t length = IsJSArray() ? |
static_cast<uint32_t>( |
@@ -9435,6 +9515,7 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, |
PropertyAttributes filter) { |
int counter = 0; |
switch (GetElementsKind()) { |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_ELEMENTS: { |
int length = IsJSArray() ? |
Smi::cast(JSArray::cast(this)->length())->value() : |
@@ -10337,7 +10418,8 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
} |
} |
- ASSERT(HasFastElements() || HasFastDoubleElements()); |
+ ASSERT(HasFastTypeElements() || |
+ 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. |