Version 3.11.7
Get better function names in stack traces.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@11674 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index b0c0a58..f64809d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-05-29: Version 3.11.7
+
+ Get better function names in stack traces.
+
+ Performance and stability improvements on all platforms.
+
+
2012-05-24: Version 3.11.6
Fixed RegExp.prototype.toString for incompatible receivers
diff --git a/build/common.gypi b/build/common.gypi
index 01ee426..7f084b8 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -238,6 +238,11 @@
'defines': [
'WIN32',
],
+ 'msvs_configuration_attributes': {
+ 'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)',
+ 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
+ 'CharacterSet': '1',
+ },
}],
['OS=="win" and v8_enable_prof==1', {
'msvs_settings': {
@@ -359,11 +364,6 @@
},
}], # OS=="mac"
['OS=="win"', {
- 'msvs_configuration_attributes': {
- 'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)',
- 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
- 'CharacterSet': '1',
- },
'msvs_settings': {
'VCCLCompilerTool': {
'Optimization': '2',
diff --git a/src/SConscript b/src/SConscript
index 0d0b535..2482b37 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -68,6 +68,7 @@
diy-fp.cc
dtoa.cc
elements.cc
+ elements-kind.cc
execution.cc
factory.cc
flags.cc
diff --git a/src/api.cc b/src/api.cc
index b43aaf3..74886f0 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -5040,7 +5040,7 @@
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Array::CloneElementAt()", return Local<Object>());
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- if (!self->HasFastElements()) {
+ if (!self->HasFastObjectElements()) {
return Local<Object>();
}
i::FixedArray* elms = i::FixedArray::cast(self->elements());
diff --git a/src/api.h b/src/api.h
index 3ad57f4..05e5e72 100644
--- a/src/api.h
+++ b/src/api.h
@@ -105,13 +105,13 @@
v8::internal::Object* NeanderObject::get(int offset) {
- ASSERT(value()->HasFastElements());
+ ASSERT(value()->HasFastObjectElements());
return v8::internal::FixedArray::cast(value()->elements())->get(offset);
}
void NeanderObject::set(int offset, v8::internal::Object* value) {
- ASSERT(value_->HasFastElements());
+ ASSERT(value_->HasFastObjectElements());
v8::internal::FixedArray::cast(value_->elements())->set(offset, value);
}
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index c99e778..578bd81 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -114,7 +114,7 @@
Label* gc_required) {
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadInitialArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -208,7 +208,8 @@
bool fill_with_hole,
Label* gc_required) {
// Load the initial map from the array function.
- __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage);
+ __ LoadInitialArrayMap(array_function, scratch2,
+ elements_array_storage, fill_with_hole);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ tst(array_size, array_size);
@@ -440,10 +441,10 @@
__ b(call_generic_code);
__ bind(¬_double);
- // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS.
+ // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
// r3: JSArray
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
r2,
r9,
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 218c355..2296490 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -7102,8 +7102,8 @@
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET },
{ REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET },
- // ElementsTransitionGenerator::GenerateSmiOnlyToObject
- // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // ElementsTransitionGenerator::GenerateMapChangeElementTransition
+ // and ElementsTransitionGenerator::GenerateSmiToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
{ REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET },
{ REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET },
@@ -7366,9 +7366,9 @@
Label fast_elements;
__ CheckFastElements(r2, r5, &double_elements);
- // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
__ JumpIfSmi(r0, &smi_element);
- __ CheckFastSmiOnlyElements(r2, r5, &fast_elements);
+ __ CheckFastSmiElements(r2, r5, &fast_elements);
// Store into the array literal requires a elements transition. Call into
// the runtime.
@@ -7380,7 +7380,7 @@
__ Push(r5, r4);
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
- // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
__ bind(&fast_elements);
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
__ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
@@ -7391,8 +7391,8 @@
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ Ret();
- // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
- // FAST_ELEMENTS, and value is Smi.
+ // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
+ // and value is Smi.
__ bind(&smi_element);
__ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
__ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index befd8f2..e00afb9 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -73,7 +73,7 @@
// -------------------------------------------------------------------------
// Code generators
-void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : value
@@ -96,7 +96,7 @@
}
-void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+void ElementsTransitionGenerator::GenerateSmiToDouble(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- r0 : value
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 3c8df29..2a5887a 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1701,7 +1701,7 @@
ASSERT_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
- bool has_fast_elements = constant_elements_kind == FAST_ELEMENTS;
+ bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
@@ -1722,8 +1722,7 @@
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
- ASSERT(constant_elements_kind == FAST_ELEMENTS ||
- constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
FastCloneShallowArrayStub::Mode mode = has_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
@@ -1751,7 +1750,7 @@
}
VisitForAccumulatorValue(subexpr);
- if (constant_elements_kind == FAST_ELEMENTS) {
+ if (IsFastObjectElementsKind(constant_elements_kind)) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ ldr(r6, MemOperand(sp)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index c12c167..fd93480 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1249,7 +1249,7 @@
// Must return the modified receiver in r0.
if (!FLAG_trace_elements_transitions) {
Label fail;
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
__ mov(r0, r2);
__ Ret();
__ bind(&fail);
@@ -1462,27 +1462,27 @@
__ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
__ b(ne, &non_double_value);
- // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+ // Value is a double. Transition FAST_SMI_ELEMENTS ->
// FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS,
receiver_map,
r4,
&slow);
ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
receiver_map,
r4,
&slow);
ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 5c60f53..c97831a 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -2082,8 +2082,9 @@
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
- if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
+ ElementsKind from_kind = instr->original_map()->elements_kind();
+ ElementsKind to_kind = instr->transitioned_map()->elements_kind();
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index d224d24..fd4b3e8 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2696,8 +2696,10 @@
__ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
__ ubfx(scratch, scratch, Map::kElementsKindShift,
Map::kElementsKindBitCount);
- __ cmp(scratch, Operand(FAST_ELEMENTS));
- __ b(eq, &done);
+ __ cmp(scratch, Operand(GetInitialFastElementsKind()));
+ __ b(lt, &fail);
+ __ cmp(scratch, Operand(TERMINAL_FAST_ELEMENTS_KIND));
+ __ b(le, &done);
__ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(lt, &fail);
__ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
@@ -2788,9 +2790,11 @@
(instr->additional_index() << shift_size)));
}
- __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
- __ cmp(scratch, Operand(kHoleNanUpper32));
- DeoptimizeIf(eq, instr->environment());
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ __ cmp(scratch, Operand(kHoleNanUpper32));
+ DeoptimizeIf(eq, instr->environment());
+ }
__ vldr(result, elements, 0);
}
@@ -2866,9 +2870,12 @@
break;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3871,7 +3878,10 @@
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3908,20 +3918,22 @@
__ cmp(scratch, Operand(from_map));
__ b(ne, ¬_applicable);
__ mov(new_map_reg, Operand(to_map));
- if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
__ str(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
// Write barrier.
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
scratch, kLRHasBeenSaved, kDontSaveFPRegs);
- } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- to_kind == FAST_DOUBLE_ELEMENTS) {
+ } else if (IsFastSmiElementsKind(from_kind) &&
+ IsFastDoubleElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(r2));
ASSERT(new_map_reg.is(r3));
__ mov(fixed_object_reg, object_reg);
CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
RelocInfo::CODE_TARGET, instr);
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ } else if (IsFastDoubleElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(r2));
ASSERT(new_map_reg.is(r3));
@@ -4695,8 +4707,9 @@
// Deopt if the array literal boilerplate ElementsKind is of a type different
// than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(r1, instr->hydrogen()->boilerplate_object());
// Load map into r2.
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
@@ -4847,10 +4860,11 @@
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate()->GetElementsKind();
- // Deopt if the literal boilerplate ElementsKind is of a type different than
- // the expected one. The check isn't necessary if the boilerplate has already
- // been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // Deopt if the array literal boilerplate ElementsKind is of a type different
+ // than the expected one. The check isn't necessary if the boilerplate has
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
// Load map into r2.
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 4da2fec..b4aec54 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -1868,10 +1868,12 @@
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
- cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
+ cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
b(hi, fail);
}
@@ -1879,22 +1881,25 @@
void MacroAssembler::CheckFastObjectElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
- cmp(scratch, Operand(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
b(ls, fail);
- cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
+ cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
b(hi, fail);
}
-void MacroAssembler::CheckFastSmiOnlyElements(Register map,
- Register scratch,
- Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+void MacroAssembler::CheckFastSmiElements(Register map,
+ Register scratch,
+ Label* fail) {
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
- cmp(scratch, Operand(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
b(hi, fail);
}
@@ -1997,22 +2002,17 @@
ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
cmp(scratch, Operand(map));
if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) {
- Map* transitioned_fast_element_map(
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL));
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- b(eq, early_success);
- cmp(scratch, Operand(Handle<Map>(transitioned_fast_element_map)));
- }
-
- Map* transitioned_double_map(
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL));
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- b(eq, early_success);
- cmp(scratch, Operand(Handle<Map>(transitioned_double_map)));
+ ElementsKind kind = map->elements_kind();
+ if (IsFastElementsKind(kind)) {
+ bool packed = IsFastPackedElementsKind(kind);
+ Map* current_map = *map;
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
+ if (!current_map) break;
+ b(eq, early_success);
+ cmp(scratch, Operand(Handle<Map>(current_map)));
+ }
}
}
}
@@ -2865,28 +2865,38 @@
ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check that the function's map is the same as the expected cached map.
- int expected_index =
- Context::GetContextMapIndexFromElementsKind(expected_kind);
- ldr(ip, MemOperand(scratch, Context::SlotOffset(expected_index)));
- cmp(map_in_out, ip);
+ ldr(scratch,
+ MemOperand(scratch,
+ Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
+ size_t offset = expected_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ cmp(map_in_out, scratch);
b(ne, no_map_match);
// Use the transitioned cached map.
- int trans_index =
- Context::GetContextMapIndexFromElementsKind(transitioned_kind);
- ldr(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index)));
+ offset = transitioned_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ ldr(map_in_out, FieldMemOperand(scratch, offset));
}
void MacroAssembler::LoadInitialArrayMap(
- Register function_in, Register scratch, Register map_out) {
+ Register function_in, Register scratch,
+ Register map_out, bool can_have_holes) {
ASSERT(!function_in.is(map_out));
Label done;
ldr(map_out, FieldMemOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
- FAST_ELEMENTS,
+ ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ kind,
+ map_out,
+ scratch,
+ &done);
+ } else if (can_have_holes) {
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_HOLEY_SMI_ELEMENTS,
map_out,
scratch,
&done);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 360f4c1..b93aba1 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -512,7 +512,8 @@
// Load the initial map for new Arrays from a JSFunction.
void LoadInitialArrayMap(Register function_in,
Register scratch,
- Register map_out);
+ Register map_out,
+ bool can_have_holes);
void LoadGlobalFunction(int index, Register function);
@@ -802,9 +803,9 @@
// Check if a map for a JSObject indicates that the object has fast smi only
// elements. Jump to the specified label if it does not.
- void CheckFastSmiOnlyElements(Register map,
- Register scratch,
- Label* fail);
+ void CheckFastSmiElements(Register map,
+ Register scratch,
+ Label* fail);
// Check to see if maybe_number can be stored as a double in
// FastDoubleElements. If it can, store it at the index specified by key in
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 49c0982..a024d79 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1581,16 +1581,29 @@
__ jmp(&fast_object);
// In case of fast smi-only, convert to fast object, otherwise bail out.
__ bind(¬_fast_object);
- __ CheckFastSmiOnlyElements(r3, r7, &call_builtin);
+ __ CheckFastSmiElements(r3, r7, &call_builtin);
// edx: receiver
// r3: map
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ Label try_holey_map;
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
r3,
r7,
+ &try_holey_map);
+ __ mov(r2, receiver);
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
+ __ jmp(&fast_object);
+
+ __ bind(&try_holey_map);
+ __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
+ FAST_HOLEY_ELEMENTS,
+ r3,
+ r7,
&call_builtin);
__ mov(r2, receiver);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
__ bind(&fast_object);
} else {
__ CheckFastObjectElements(r3, r3, &call_builtin);
@@ -3372,8 +3385,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3497,8 +3513,11 @@
}
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3838,8 +3857,11 @@
}
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3902,8 +3924,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -4042,8 +4067,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -4225,7 +4253,7 @@
// Check that the key is a smi or a heap number convertible to a smi.
GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
}
@@ -4253,7 +4281,7 @@
DONT_DO_SMI_CHECK);
__ bind(&finish_store);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ add(scratch,
elements_reg,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -4263,7 +4291,7 @@
Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
__ str(value_reg, MemOperand(scratch));
} else {
- ASSERT(elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastObjectElementsKind(elements_kind));
__ add(scratch,
elements_reg,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 048a027..a20f87b 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1092,7 +1092,7 @@
// Check the state of the object.
ASSERT(result->HasFastProperties());
- ASSERT(result->HasFastElements());
+ ASSERT(result->HasFastObjectElements());
#endif
}
@@ -1185,7 +1185,7 @@
// Check the state of the object.
ASSERT(result->HasFastProperties());
- ASSERT(result->HasFastElements());
+ ASSERT(result->HasFastObjectElements());
#endif
}
@@ -1635,7 +1635,7 @@
array_function->initial_map()->CopyDropTransitions();
Map* new_map;
if (!maybe_map->To<Map>(&new_map)) return false;
- new_map->set_elements_kind(FAST_ELEMENTS);
+ new_map->set_elements_kind(FAST_HOLEY_ELEMENTS);
array_function->set_initial_map(new_map);
// Make "length" magic on instances.
diff --git a/src/builtins.cc b/src/builtins.cc
index 84a0c3d..64ec3d9 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -200,9 +200,12 @@
array->set_elements(heap->empty_fixed_array());
if (!FLAG_smi_only_arrays) {
Context* global_context = isolate->context()->global_context();
- if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
- !global_context->object_js_array_map()->IsUndefined()) {
- array->set_map(Map::cast(global_context->object_js_array_map()));
+ if (array->GetElementsKind() == GetInitialFastElementsKind() &&
+ !global_context->js_array_maps()->IsUndefined()) {
+ FixedArray* map_array =
+ FixedArray::cast(global_context->js_array_maps());
+ array->set_map(Map::cast(map_array->
+ get(TERMINAL_FAST_ELEMENTS_KIND)));
}
}
} else {
@@ -222,6 +225,13 @@
{ MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
}
+ ElementsKind elements_kind = array->GetElementsKind();
+ if (!IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ MaybeObject* maybe_array =
+ array->TransitionElementsKind(elements_kind);
+ if (maybe_array->IsFailure()) return maybe_array;
+ }
// We do not use SetContent to skip the unnecessary elements type check.
array->set_elements(FixedArray::cast(fixed_array));
array->set_length(Smi::cast(obj));
@@ -250,7 +260,7 @@
// Allocate an appropriately typed elements array.
MaybeObject* maybe_elms;
ElementsKind elements_kind = array->GetElementsKind();
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastDoubleElementsKind(elements_kind)) {
maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
number_of_elements);
} else {
@@ -261,13 +271,15 @@
// Fill in the content
switch (array->GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS: {
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_SMI_ELEMENTS: {
FixedArray* smi_elms = FixedArray::cast(elms);
for (int index = 0; index < number_of_elements; index++) {
smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
}
break;
}
+ case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
@@ -277,6 +289,7 @@
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
for (int index = 0; index < number_of_elements; index++) {
@@ -412,7 +425,7 @@
HeapObject* elms = array->elements();
Map* map = elms->map();
if (map == heap->fixed_array_map()) {
- if (args == NULL || array->HasFastElements()) return elms;
+ if (args == NULL || array->HasFastObjectElements()) return elms;
if (array->HasFastDoubleElements()) {
ASSERT(elms == heap->empty_fixed_array());
MaybeObject* maybe_transition =
@@ -422,7 +435,7 @@
}
} else if (map == heap->fixed_cow_array_map()) {
MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
- if (args == NULL || array->HasFastElements() ||
+ if (args == NULL || array->HasFastObjectElements() ||
maybe_writable_result->IsFailure()) {
return maybe_writable_result;
}
@@ -516,8 +529,8 @@
}
FixedArray* new_elms = FixedArray::cast(obj);
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
- new_elms, FAST_ELEMENTS, 0, len);
+ ElementsKind kind = array->GetElementsKind();
+ CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len);
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
@@ -588,7 +601,7 @@
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastTypeElements());
+ ASSERT(array->HasFastSmiOrObjectElements());
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
@@ -630,7 +643,7 @@
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastTypeElements());
+ ASSERT(array->HasFastSmiOrObjectElements());
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
@@ -652,8 +665,8 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
- new_elms, FAST_ELEMENTS, to_add, len);
+ ElementsKind kind = array->GetElementsKind();
+ CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len);
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
@@ -682,7 +695,7 @@
int len = -1;
if (receiver->IsJSArray()) {
JSArray* array = JSArray::cast(receiver);
- if (!array->HasFastTypeElements() ||
+ if (!array->HasFastSmiOrObjectElements() ||
!IsJSArrayFastElementMovingAllowed(heap, array)) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -698,7 +711,7 @@
bool is_arguments_object_with_fast_elements =
receiver->IsJSObject()
&& JSObject::cast(receiver)->map() == arguments_map
- && JSObject::cast(receiver)->HasFastTypeElements();
+ && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
if (!is_arguments_object_with_fast_elements) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -763,9 +776,9 @@
JSArray* result_array;
if (!maybe_array->To(&result_array)) return maybe_array;
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, k,
+ CopyObjectToObjectElements(elms, elements_kind, k,
FixedArray::cast(result_array->elements()),
- FAST_ELEMENTS, 0, result_len);
+ elements_kind, 0, result_len);
return result_array;
}
@@ -786,7 +799,7 @@
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastTypeElements());
+ ASSERT(array->HasFastSmiOrObjectElements());
int len = Smi::cast(array->length())->value();
@@ -837,9 +850,9 @@
{
// Fill newly created array.
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start,
+ CopyObjectToObjectElements(elms, elements_kind, actual_start,
FixedArray::cast(result_array->elements()),
- FAST_ELEMENTS, 0, actual_delete_count);
+ elements_kind, 0, actual_delete_count);
}
int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
@@ -888,12 +901,13 @@
{
// Copy the part before actual_start as is.
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
- new_elms, FAST_ELEMENTS, 0, actual_start);
+ ElementsKind kind = array->GetElementsKind();
+ CopyObjectToObjectElements(elms, kind, 0,
+ new_elms, kind, 0, actual_start);
const int to_copy = len - actual_delete_count - actual_start;
- CopyObjectToObjectElements(elms, FAST_ELEMENTS,
+ CopyObjectToObjectElements(elms, kind,
actual_start + actual_delete_count,
- new_elms, FAST_ELEMENTS,
+ new_elms, kind,
actual_start + item_count, to_copy);
}
@@ -940,11 +954,12 @@
// and calculating total length.
int n_arguments = args.length();
int result_len = 0;
- ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
+ ElementsKind elements_kind = GetInitialFastElementsKind();
for (int i = 0; i < n_arguments; i++) {
Object* arg = args[i];
- if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
- || JSArray::cast(arg)->GetPrototype() != array_proto) {
+ if (!arg->IsJSArray() ||
+ !JSArray::cast(arg)->HasFastSmiOrObjectElements() ||
+ JSArray::cast(arg)->GetPrototype() != array_proto) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
@@ -961,8 +976,18 @@
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
- if (!JSArray::cast(arg)->HasFastSmiOnlyElements()) {
- elements_kind = FAST_ELEMENTS;
+ if (!JSArray::cast(arg)->HasFastSmiElements()) {
+ if (IsFastSmiElementsKind(elements_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = FAST_HOLEY_ELEMENTS;
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
+ }
+ }
+
+ if (JSArray::cast(arg)->HasFastHoleyElements()) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
}
}
@@ -982,8 +1007,8 @@
JSArray* array = JSArray::cast(args[i]);
int len = Smi::cast(array->length())->value();
FixedArray* elms = FixedArray::cast(array->elements());
- CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
- result_elms, FAST_ELEMENTS,
+ CopyObjectToObjectElements(elms, elements_kind, 0,
+ result_elms, elements_kind,
start_pos, len);
start_pos += len;
}
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 814e358..8f31660 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -262,10 +262,13 @@
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break;
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
break;
case EXTERNAL_BYTE_ELEMENTS:
@@ -292,7 +295,9 @@
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS: {
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS: {
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
is_js_array_,
elements_kind_,
@@ -300,6 +305,7 @@
}
break;
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_js_array_,
grow_mode_);
@@ -430,24 +436,32 @@
void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
Label fail;
+ ASSERT(!IsFastHoleyElementsKind(from_) || IsFastHoleyElementsKind(to_));
if (!FLAG_trace_elements_transitions) {
- if (to_ == FAST_ELEMENTS) {
- if (from_ == FAST_SMI_ONLY_ELEMENTS) {
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
- } else if (from_ == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastSmiOrObjectElementsKind(to_)) {
+ if (IsFastSmiOrObjectElementsKind(from_)) {
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm);
+ } else if (IsFastDoubleElementsKind(from_)) {
+ ASSERT(!IsFastSmiElementsKind(to_));
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
} else {
UNREACHABLE();
}
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
is_jsarray_,
- FAST_ELEMENTS,
+ to_,
grow_mode_);
- } else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) {
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ } else if (IsFastSmiElementsKind(from_) &&
+ IsFastDoubleElementsKind(to_)) {
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_jsarray_,
grow_mode_);
+ } else if (IsFastDoubleElementsKind(from_)) {
+ ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm);
} else {
UNREACHABLE();
}
diff --git a/src/codegen.h b/src/codegen.h
index 50d70f2..08a777f 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -95,8 +95,8 @@
class ElementsTransitionGenerator : public AllStatic {
public:
- static void GenerateSmiOnlyToObject(MacroAssembler* masm);
- static void GenerateSmiOnlyToDouble(MacroAssembler* masm, Label* fail);
+ static void GenerateMapChangeElementsTransition(MacroAssembler* masm);
+ static void GenerateSmiToDouble(MacroAssembler* masm, Label* fail);
static void GenerateDoubleToObject(MacroAssembler* masm, Label* fail);
private:
diff --git a/src/contexts.h b/src/contexts.h
index 647c15c..d154b82 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -106,9 +106,7 @@
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
- V(SMI_JS_ARRAY_MAP_INDEX, Object, smi_js_array_map) \
- V(DOUBLE_JS_ARRAY_MAP_INDEX, Object, double_js_array_map) \
- V(OBJECT_JS_ARRAY_MAP_INDEX, Object, object_js_array_map) \
+ V(JS_ARRAY_MAPS_INDEX, Object, js_array_maps) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
V(JSON_OBJECT_INDEX, JSObject, json_object) \
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
@@ -248,9 +246,7 @@
OBJECT_FUNCTION_INDEX,
INTERNAL_ARRAY_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
- SMI_JS_ARRAY_MAP_INDEX,
- DOUBLE_JS_ARRAY_MAP_INDEX,
- OBJECT_JS_ARRAY_MAP_INDEX,
+ JS_ARRAY_MAPS_INDEX,
DATE_FUNCTION_INDEX,
JSON_OBJECT_INDEX,
REGEXP_FUNCTION_INDEX,
@@ -373,18 +369,6 @@
Object* OptimizedFunctionsListHead();
void ClearOptimizedFunctions();
- static int GetContextMapIndexFromElementsKind(
- ElementsKind elements_kind) {
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- return Context::DOUBLE_JS_ARRAY_MAP_INDEX;
- } else if (elements_kind == FAST_ELEMENTS) {
- return Context::OBJECT_JS_ARRAY_MAP_INDEX;
- } else {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
- return Context::SMI_JS_ARRAY_MAP_INDEX;
- }
- }
-
#define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void set_##name(type* value) { \
ASSERT(IsGlobalContext()); \
diff --git a/src/elements-kind.cc b/src/elements-kind.cc
new file mode 100644
index 0000000..655a23b
--- /dev/null
+++ b/src/elements-kind.cc
@@ -0,0 +1,134 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "elements-kind.h"
+
+#include "api.h"
+#include "elements.h"
+#include "objects.h"
+
+namespace v8 {
+namespace internal {
+
+
+void PrintElementsKind(FILE* out, ElementsKind kind) {
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
+ PrintF(out, "%s", accessor->name());
+}
+
+
+ElementsKind GetInitialFastElementsKind() {
+ if (FLAG_packed_arrays) {
+ return FAST_SMI_ELEMENTS;
+ } else {
+ return FAST_HOLEY_SMI_ELEMENTS;
+ }
+}
+
+
+struct InitializeFastElementsKindSequence {
+ static void Construct(
+ ElementsKind** fast_elements_kind_sequence_ptr) {
+ ElementsKind* fast_elements_kind_sequence =
+ new ElementsKind[kFastElementsKindCount];
+ *fast_elements_kind_sequence_ptr = fast_elements_kind_sequence;
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == FIRST_FAST_ELEMENTS_KIND);
+ fast_elements_kind_sequence[0] = FAST_SMI_ELEMENTS;
+ fast_elements_kind_sequence[1] = FAST_HOLEY_SMI_ELEMENTS;
+ fast_elements_kind_sequence[2] = FAST_DOUBLE_ELEMENTS;
+ fast_elements_kind_sequence[3] = FAST_HOLEY_DOUBLE_ELEMENTS;
+ fast_elements_kind_sequence[4] = FAST_ELEMENTS;
+ fast_elements_kind_sequence[5] = FAST_HOLEY_ELEMENTS;
+ }
+};
+
+
+static LazyInstance<ElementsKind*,
+ InitializeFastElementsKindSequence>::type
+ fast_elements_kind_sequence = LAZY_INSTANCE_INITIALIZER;
+
+
+ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number) {
+ ASSERT(sequence_number >= 0 &&
+ sequence_number < kFastElementsKindCount);
+ return fast_elements_kind_sequence.Get()[sequence_number];
+}
+
+int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) {
+ for (int i = 0; i < kFastElementsKindCount; ++i) {
+ if (fast_elements_kind_sequence.Get()[i] == elements_kind) {
+ return i;
+ }
+ }
+ UNREACHABLE();
+ return 0;
+}
+
+
+ElementsKind GetNextMoreGeneralFastElementsKind(ElementsKind elements_kind,
+ bool allow_only_packed) {
+ ASSERT(IsFastElementsKind(elements_kind));
+ ASSERT(elements_kind != TERMINAL_FAST_ELEMENTS_KIND);
+ while (true) {
+ int index =
+ GetSequenceIndexFromFastElementsKind(elements_kind) + 1;
+ elements_kind = GetFastElementsKindFromSequenceIndex(index);
+ if (!IsFastHoleyElementsKind(elements_kind) || !allow_only_packed) {
+ return elements_kind;
+ }
+ }
+ UNREACHABLE();
+ return TERMINAL_FAST_ELEMENTS_KIND;
+}
+
+
+bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
+ ElementsKind to_kind) {
+ switch (from_kind) {
+ case FAST_SMI_ELEMENTS:
+ return to_kind != FAST_SMI_ELEMENTS;
+ case FAST_HOLEY_SMI_ELEMENTS:
+ return to_kind != FAST_SMI_ELEMENTS &&
+ to_kind != FAST_HOLEY_SMI_ELEMENTS;
+ case FAST_DOUBLE_ELEMENTS:
+ return to_kind != FAST_SMI_ELEMENTS &&
+ to_kind != FAST_HOLEY_SMI_ELEMENTS &&
+ to_kind != FAST_DOUBLE_ELEMENTS;
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ return to_kind == FAST_ELEMENTS ||
+ to_kind == FAST_HOLEY_ELEMENTS;
+ case FAST_ELEMENTS:
+ return to_kind == FAST_HOLEY_ELEMENTS;
+ case FAST_HOLEY_ELEMENTS:
+ return false;
+ default:
+ return false;
+ }
+}
+
+
+} } // namespace v8::internal
diff --git a/src/elements-kind.h b/src/elements-kind.h
new file mode 100644
index 0000000..ab31a33
--- /dev/null
+++ b/src/elements-kind.h
@@ -0,0 +1,210 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ELEMENTS_KIND_H_
+#define V8_ELEMENTS_KIND_H_
+
+#include "v8checks.h"
+
+namespace v8 {
+namespace internal {
+
+enum ElementsKind {
+ // The "fast" kind for elements that only contain SMI values. Must be first
+ // to make it possible to efficiently check maps for this kind.
+ FAST_SMI_ELEMENTS,
+ FAST_HOLEY_SMI_ELEMENTS,
+
+ // The "fast" kind for tagged values. Must be second to make it possible to
+ // efficiently check maps for this and the FAST_SMI_ONLY_ELEMENTS kind
+ // together at once.
+ FAST_ELEMENTS,
+ FAST_HOLEY_ELEMENTS,
+
+ // The "fast" kind for unwrapped, non-tagged double values.
+ FAST_DOUBLE_ELEMENTS,
+ FAST_HOLEY_DOUBLE_ELEMENTS,
+
+ // The "slow" kind.
+ DICTIONARY_ELEMENTS,
+ NON_STRICT_ARGUMENTS_ELEMENTS,
+ // The "fast" kind for external arrays
+ EXTERNAL_BYTE_ELEMENTS,
+ EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
+ EXTERNAL_SHORT_ELEMENTS,
+ EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
+ EXTERNAL_INT_ELEMENTS,
+ EXTERNAL_UNSIGNED_INT_ELEMENTS,
+ EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_DOUBLE_ELEMENTS,
+ EXTERNAL_PIXEL_ELEMENTS,
+
+ // Derived constants from ElementsKind
+ FIRST_ELEMENTS_KIND = FAST_SMI_ELEMENTS,
+ LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
+ FIRST_FAST_ELEMENTS_KIND = FAST_SMI_ELEMENTS,
+ LAST_FAST_ELEMENTS_KIND = FAST_HOLEY_DOUBLE_ELEMENTS,
+ FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
+ LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
+ TERMINAL_FAST_ELEMENTS_KIND = FAST_HOLEY_ELEMENTS
+};
+
+const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
+const int kFastElementsKindCount = LAST_FAST_ELEMENTS_KIND -
+ FIRST_FAST_ELEMENTS_KIND + 1;
+
+void PrintElementsKind(FILE* out, ElementsKind kind);
+
+ElementsKind GetInitialFastElementsKind();
+
+ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_index);
+
+int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind);
+
+
+inline bool IsFastElementsKind(ElementsKind kind) {
+ ASSERT(FIRST_FAST_ELEMENTS_KIND == 0);
+ return kind <= FAST_HOLEY_DOUBLE_ELEMENTS;
+}
+
+
+inline bool IsFastDoubleElementsKind(ElementsKind kind) {
+ return kind == FAST_DOUBLE_ELEMENTS ||
+ kind == FAST_HOLEY_DOUBLE_ELEMENTS;
+}
+
+
+inline bool IsFastSmiOrObjectElementsKind(ElementsKind kind) {
+ return kind == FAST_SMI_ELEMENTS ||
+ kind == FAST_HOLEY_SMI_ELEMENTS ||
+ kind == FAST_ELEMENTS ||
+ kind == FAST_HOLEY_ELEMENTS;
+}
+
+
+inline bool IsFastSmiElementsKind(ElementsKind kind) {
+ return kind == FAST_SMI_ELEMENTS ||
+ kind == FAST_HOLEY_SMI_ELEMENTS;
+}
+
+
+inline bool IsFastObjectElementsKind(ElementsKind kind) {
+ return kind == FAST_ELEMENTS ||
+ kind == FAST_HOLEY_ELEMENTS;
+}
+
+
+inline bool IsFastHoleyElementsKind(ElementsKind kind) {
+ return kind == FAST_HOLEY_SMI_ELEMENTS ||
+ kind == FAST_HOLEY_DOUBLE_ELEMENTS ||
+ kind == FAST_HOLEY_ELEMENTS;
+}
+
+
+inline bool IsHoleyElementsKind(ElementsKind kind) {
+ return IsFastHoleyElementsKind(kind) ||
+ kind == DICTIONARY_ELEMENTS;
+}
+
+
+inline bool IsFastPackedElementsKind(ElementsKind kind) {
+ return kind == FAST_SMI_ELEMENTS ||
+ kind == FAST_DOUBLE_ELEMENTS ||
+ kind == FAST_ELEMENTS;
+}
+
+
+inline ElementsKind GetPackedElementsKind(ElementsKind holey_kind) {
+ if (holey_kind == FAST_HOLEY_SMI_ELEMENTS) {
+ return FAST_SMI_ELEMENTS;
+ }
+ if (holey_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
+ return FAST_DOUBLE_ELEMENTS;
+ }
+ if (holey_kind == FAST_HOLEY_ELEMENTS) {
+ return FAST_ELEMENTS;
+ }
+ return holey_kind;
+}
+
+
+inline ElementsKind GetHoleyElementsKind(ElementsKind packed_kind) {
+ if (packed_kind == FAST_SMI_ELEMENTS) {
+ return FAST_HOLEY_SMI_ELEMENTS;
+ }
+ if (packed_kind == FAST_DOUBLE_ELEMENTS) {
+ return FAST_HOLEY_DOUBLE_ELEMENTS;
+ }
+ if (packed_kind == FAST_ELEMENTS) {
+ return FAST_HOLEY_ELEMENTS;
+ }
+ return packed_kind;
+}
+
+
+inline ElementsKind FastSmiToObjectElementsKind(ElementsKind from_kind) {
+ ASSERT(IsFastSmiElementsKind(from_kind));
+ return (from_kind == FAST_SMI_ELEMENTS)
+ ? FAST_ELEMENTS
+ : FAST_HOLEY_ELEMENTS;
+}
+
+
+inline bool IsSimpleMapChangeTransition(ElementsKind from_kind,
+ ElementsKind to_kind) {
+ return (GetHoleyElementsKind(from_kind) == to_kind) ||
+ (IsFastSmiElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind));
+}
+
+
+bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
+ ElementsKind to_kind);
+
+
+inline bool IsTransitionableFastElementsKind(ElementsKind from_kind) {
+ return IsFastElementsKind(from_kind) &&
+ from_kind != TERMINAL_FAST_ELEMENTS_KIND;
+}
+
+
+ElementsKind GetNextMoreGeneralFastElementsKind(ElementsKind elements_kind,
+ bool allow_only_packed);
+
+
+inline bool CanTransitionToMoreGeneralFastElementsKind(
+ ElementsKind elements_kind,
+ bool allow_only_packed) {
+ return IsFastElementsKind(elements_kind) &&
+ (elements_kind != TERMINAL_FAST_ELEMENTS_KIND &&
+ (!allow_only_packed || elements_kind != FAST_ELEMENTS));
+}
+
+
+} } // namespace v8::internal
+
+#endif // V8_ELEMENTS_KIND_H_
diff --git a/src/elements.cc b/src/elements.cc
index d367af8..2692cb5 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -39,8 +39,14 @@
// Inheritance hierarchy:
// - ElementsAccessorBase (abstract)
// - FastElementsAccessor (abstract)
-// - FastObjectElementsAccessor
+// - FastSmiOrObjectElementsAccessor
+// - FastPackedSmiElementsAccessor
+// - FastHoleySmiElementsAccessor
+// - FastPackedObjectElementsAccessor
+// - FastHoleyObjectElementsAccessor
// - FastDoubleElementsAccessor
+// - FastPackedDoubleElementsAccessor
+// - FastHoleyDoubleElementsAccessor
// - ExternalElementsAccessor (abstract)
// - ExternalByteElementsAccessor
// - ExternalUnsignedByteElementsAccessor
@@ -65,9 +71,15 @@
// identical. Note that the order must match that of the ElementsKind enum for
// the |accessor_array[]| below to work.
#define ELEMENTS_LIST(V) \
- V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS, FixedArray) \
- V(FastObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
- V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
+ V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
+ V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \
+ FixedArray) \
+ V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
+ V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
+ V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \
+ FixedDoubleArray) \
+ V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
+ FixedDoubleArray) \
V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \
SeededNumberDictionary) \
V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \
@@ -139,8 +151,6 @@
uint32_t to_start,
int raw_copy_size) {
ASSERT(to->map() != HEAP->fixed_cow_array_map());
- ASSERT(from_kind == FAST_ELEMENTS || from_kind == FAST_SMI_ONLY_ELEMENTS);
- ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
@@ -148,7 +158,7 @@
copy_size = Min(from->length() - from_start,
to->length() - to_start);
#ifdef DEBUG
- // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
+ // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
// marked with the hole.
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
for (int i = to_start + copy_size; i < to->length(); ++i) {
@@ -160,12 +170,15 @@
ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
(copy_size + static_cast<int>(from_start)) <= from->length());
if (copy_size == 0) return;
+ ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
+ ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
Address to_address = to->address() + FixedArray::kHeaderSize;
Address from_address = from->address() + FixedArray::kHeaderSize;
CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
reinterpret_cast<Object**>(from_address) + from_start,
copy_size);
- if (from_kind == FAST_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ if (IsFastObjectElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind)) {
Heap* heap = from->GetHeap();
if (!heap->InNewSpace(to)) {
heap->RecordWrites(to->address(),
@@ -190,7 +203,7 @@
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
copy_size = from->max_number_key() + 1 - from_start;
#ifdef DEBUG
- // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
+ // Fast object arrays cannot be uninitialized. Ensure they are already
// marked with the hole.
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
for (int i = to_start + copy_size; i < to->length(); ++i) {
@@ -200,7 +213,7 @@
#endif
}
ASSERT(to != from);
- ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
+ ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
if (copy_size == 0) return;
uint32_t to_length = to->length();
if (to_start + copy_size > to_length) {
@@ -216,7 +229,7 @@
to->set_the_hole(i + to_start);
}
}
- if (to_kind == FAST_ELEMENTS) {
+ if (IsFastObjectElementsKind(to_kind)) {
if (!heap->InNewSpace(to)) {
heap->RecordWrites(to->address(),
to->OffsetOfElementAt(to_start),
@@ -234,7 +247,7 @@
ElementsKind to_kind,
uint32_t to_start,
int raw_copy_size) {
- ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
+ ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
@@ -242,7 +255,7 @@
copy_size = Min(from->length() - from_start,
to->length() - to_start);
#ifdef DEBUG
- // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
+ // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
// marked with the hole.
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
for (int i = to_start + copy_size; i < to->length(); ++i) {
@@ -255,14 +268,14 @@
(copy_size + static_cast<int>(from_start)) <= from->length());
if (copy_size == 0) return from;
for (int i = 0; i < copy_size; ++i) {
- if (to_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(to_kind)) {
UNIMPLEMENTED();
return Failure::Exception();
} else {
MaybeObject* maybe_value = from->get(i + from_start);
Object* value;
- ASSERT(to_kind == FAST_ELEMENTS);
- // Because FAST_DOUBLE_ELEMENTS -> FAST_ELEMENT allocate HeapObjects
+ ASSERT(IsFastObjectElementsKind(to_kind));
+ // Because Double -> Object elements transitions allocate HeapObjects
// iteratively, the allocate must succeed within a single GC cycle,
// otherwise the retry after the GC will also fail. In order to ensure
// that no GC is triggered, allocate HeapNumbers from old space if they
@@ -404,6 +417,38 @@
virtual ElementsKind kind() const { return ElementsTraits::Kind; }
+ static void ValidateContents(JSObject* holder, int length) {
+ }
+
+ static void ValidateImpl(JSObject* holder) {
+ FixedArrayBase* fixed_array_base = holder->elements();
+ // When objects are first allocated, its elements are Failures.
+ if (fixed_array_base->IsFailure()) return;
+ if (!fixed_array_base->IsHeapObject()) return;
+ Map* map = fixed_array_base->map();
+ // Arrays that have been shifted in place can't be verified.
+ Heap* heap = holder->GetHeap();
+ if (map == heap->raw_unchecked_one_pointer_filler_map() ||
+ map == heap->raw_unchecked_two_pointer_filler_map() ||
+ map == heap->free_space_map()) {
+ return;
+ }
+ int length = 0;
+ if (holder->IsJSArray()) {
+ Object* length_obj = JSArray::cast(holder)->length();
+ if (length_obj->IsSmi()) {
+ length = Smi::cast(length_obj)->value();
+ }
+ } else {
+ length = fixed_array_base->length();
+ }
+ ElementsAccessorSubclass::ValidateContents(holder, length);
+ }
+
+ virtual void Validate(JSObject* holder) {
+ ElementsAccessorSubclass::ValidateImpl(holder);
+ }
+
static bool HasElementImpl(Object* receiver,
JSObject* holder,
uint32_t key,
@@ -455,9 +500,10 @@
Object* length,
BackingStore* backing_store);
- MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array,
- int capacity,
- int length) {
+ MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
+ JSArray* array,
+ int capacity,
+ int length) {
return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
array,
capacity,
@@ -623,6 +669,7 @@
KindTraits>(name) {}
protected:
friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
+ friend class NonStrictArgumentsElementsAccessor;
typedef typename KindTraits::BackingStore BackingStore;
@@ -633,10 +680,21 @@
Object* length_object,
uint32_t length) {
uint32_t old_capacity = backing_store->length();
+ Object* old_length = array->length();
+ bool same_size = old_length->IsSmi() &&
+ static_cast<uint32_t>(Smi::cast(old_length)->value()) == length;
+ ElementsKind kind = array->GetElementsKind();
+
+ if (!same_size && IsFastElementsKind(kind) &&
+ !IsFastHoleyElementsKind(kind)) {
+ kind = GetHoleyElementsKind(kind);
+ MaybeObject* maybe_obj = array->TransitionElementsKind(kind);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+ }
// Check whether the backing store should be shrunk.
if (length <= old_capacity) {
- if (array->HasFastTypeElements()) {
+ if (array->HasFastSmiOrObjectElements()) {
MaybeObject* maybe_obj = array->EnsureWritableFastElements();
if (!maybe_obj->To(&backing_store)) return maybe_obj;
}
@@ -668,39 +726,40 @@
MaybeObject* result = FastElementsAccessorSubclass::
SetFastElementsCapacityAndLength(array, new_capacity, length);
if (result->IsFailure()) return result;
+ array->ValidateElements();
return length_object;
}
// Request conversion to slow elements.
return array->GetHeap()->undefined_value();
}
-};
-
-
-class FastObjectElementsAccessor
- : public FastElementsAccessor<FastObjectElementsAccessor,
- ElementsKindTraits<FAST_ELEMENTS>,
- kPointerSize> {
- public:
- explicit FastObjectElementsAccessor(const char* name)
- : FastElementsAccessor<FastObjectElementsAccessor,
- ElementsKindTraits<FAST_ELEMENTS>,
- kPointerSize>(name) {}
static MaybeObject* DeleteCommon(JSObject* obj,
- uint32_t key) {
- ASSERT(obj->HasFastElements() ||
- obj->HasFastSmiOnlyElements() ||
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
+ ASSERT(obj->HasFastSmiOrObjectElements() ||
+ obj->HasFastDoubleElements() ||
obj->HasFastArgumentsElements());
+ typename KindTraits::BackingStore* backing_store =
+ KindTraits::BackingStore::cast(obj->elements());
Heap* heap = obj->GetHeap();
- FixedArray* backing_store = FixedArray::cast(obj->elements());
if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
- backing_store = FixedArray::cast(backing_store->get(1));
+ backing_store =
+ KindTraits::BackingStore::cast(
+ FixedArray::cast(backing_store)->get(1));
} else {
- Object* writable;
- MaybeObject* maybe = obj->EnsureWritableFastElements();
- if (!maybe->ToObject(&writable)) return maybe;
- backing_store = FixedArray::cast(writable);
+ ElementsKind kind = KindTraits::Kind;
+ if (IsFastPackedElementsKind(kind)) {
+ MaybeObject* transitioned =
+ obj->TransitionElementsKind(GetHoleyElementsKind(kind));
+ if (transitioned->IsFailure()) return transitioned;
+ }
+ if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
+ Object* writable;
+ MaybeObject* maybe = obj->EnsureWritableFastElements();
+ if (!maybe->ToObject(&writable)) return maybe;
+ backing_store = KindTraits::BackingStore::cast(writable);
+ }
}
uint32_t length = static_cast<uint32_t>(
obj->IsJSArray()
@@ -712,15 +771,14 @@
// has too few used values, normalize it.
// To avoid doing the check on every delete we require at least
// one adjacent hole to the value being deleted.
- Object* hole = heap->the_hole_value();
const int kMinLengthForSparsenessCheck = 64;
if (backing_store->length() >= kMinLengthForSparsenessCheck &&
!heap->InNewSpace(backing_store) &&
- ((key > 0 && backing_store->get(key - 1) == hole) ||
- (key + 1 < length && backing_store->get(key + 1) == hole))) {
+ ((key > 0 && backing_store->is_the_hole(key - 1)) ||
+ (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
int num_used = 0;
for (int i = 0; i < backing_store->length(); ++i) {
- if (backing_store->get(i) != hole) ++num_used;
+ if (!backing_store->is_the_hole(i)) ++num_used;
// Bail out early if more than 1/4 is used.
if (4 * num_used > backing_store->length()) break;
}
@@ -733,27 +791,75 @@
return heap->true_value();
}
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t key,
+ JSReceiver::DeleteMode mode) {
+ return DeleteCommon(obj, key, mode);
+ }
+
+ static bool HasElementImpl(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ typename KindTraits::BackingStore* backing_store) {
+ if (key >= static_cast<uint32_t>(backing_store->length())) {
+ return false;
+ }
+ return !backing_store->is_the_hole(key);
+ }
+
+ static void ValidateContents(JSObject* holder, int length) {
+#if DEBUG
+ FixedArrayBase* elements = holder->elements();
+ Heap* heap = elements->GetHeap();
+ Map* map = elements->map();
+ ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
+ (map == heap->fixed_array_map() ||
+ map == heap->fixed_cow_array_map())) ||
+ (IsFastDoubleElementsKind(KindTraits::Kind) ==
+ ((map == heap->fixed_array_map() && length == 0) ||
+ map == heap->fixed_double_array_map())));
+ for (int i = 0; i < length; i++) {
+ typename KindTraits::BackingStore* backing_store =
+ KindTraits::BackingStore::cast(elements);
+ ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) ||
+ static_cast<Object*>(backing_store->get(i))->IsSmi()) ||
+ (IsFastHoleyElementsKind(KindTraits::Kind) ==
+ backing_store->is_the_hole(i)));
+ }
+#endif
+ }
+};
+
+
+template<typename FastElementsAccessorSubclass,
+ typename KindTraits>
+class FastSmiOrObjectElementsAccessor
+ : public FastElementsAccessor<FastElementsAccessorSubclass,
+ KindTraits,
+ kPointerSize> {
+ public:
+ explicit FastSmiOrObjectElementsAccessor(const char* name)
+ : FastElementsAccessor<FastElementsAccessorSubclass,
+ KindTraits,
+ kPointerSize>(name) {}
+
static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
uint32_t from_start,
FixedArrayBase* to,
ElementsKind to_kind,
uint32_t to_start,
int copy_size) {
- switch (to_kind) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
- CopyObjectToObjectElements(
- FixedArray::cast(from), ElementsTraits::Kind, from_start,
- FixedArray::cast(to), to_kind, to_start, copy_size);
- return from;
- }
- case FAST_DOUBLE_ELEMENTS:
- CopyObjectToDoubleElements(
- FixedArray::cast(from), from_start,
- FixedDoubleArray::cast(to), to_start, copy_size);
- return from;
- default:
- UNREACHABLE();
+ if (IsFastSmiOrObjectElementsKind(to_kind)) {
+ CopyObjectToObjectElements(
+ FixedArray::cast(from), KindTraits::Kind, from_start,
+ FixedArray::cast(to), to_kind, to_start, copy_size);
+ } else if (IsFastDoubleElementsKind(to_kind)) {
+ CopyObjectToDoubleElements(
+ FixedArray::cast(from), from_start,
+ FixedDoubleArray::cast(to), to_start, copy_size);
+ } else {
+ UNREACHABLE();
}
return to->GetHeap()->undefined_value();
}
@@ -762,51 +868,85 @@
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
- JSObject::SetFastElementsCapacityMode set_capacity_mode =
- obj->HasFastSmiOnlyElements()
- ? JSObject::kAllowSmiOnlyElements
- : JSObject::kDontAllowSmiOnlyElements;
+ JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
+ obj->HasFastSmiElements()
+ ? JSObject::kAllowSmiElements
+ : JSObject::kDontAllowSmiElements;
return obj->SetFastElementsCapacityAndLength(capacity,
length,
set_capacity_mode);
}
-
- protected:
- friend class FastElementsAccessor<FastObjectElementsAccessor,
- ElementsKindTraits<FAST_ELEMENTS>,
- kPointerSize>;
-
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
- return DeleteCommon(obj, key);
- }
};
+class FastPackedSmiElementsAccessor
+ : public FastSmiOrObjectElementsAccessor<
+ FastPackedSmiElementsAccessor,
+ ElementsKindTraits<FAST_SMI_ELEMENTS> > {
+ public:
+ explicit FastPackedSmiElementsAccessor(const char* name)
+ : FastSmiOrObjectElementsAccessor<
+ FastPackedSmiElementsAccessor,
+ ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
+};
+
+
+class FastHoleySmiElementsAccessor
+ : public FastSmiOrObjectElementsAccessor<
+ FastHoleySmiElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
+ public:
+ explicit FastHoleySmiElementsAccessor(const char* name)
+ : FastSmiOrObjectElementsAccessor<
+ FastHoleySmiElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
+};
+
+
+class FastPackedObjectElementsAccessor
+ : public FastSmiOrObjectElementsAccessor<
+ FastPackedObjectElementsAccessor,
+ ElementsKindTraits<FAST_ELEMENTS> > {
+ public:
+ explicit FastPackedObjectElementsAccessor(const char* name)
+ : FastSmiOrObjectElementsAccessor<
+ FastPackedObjectElementsAccessor,
+ ElementsKindTraits<FAST_ELEMENTS> >(name) {}
+};
+
+
+class FastHoleyObjectElementsAccessor
+ : public FastSmiOrObjectElementsAccessor<
+ FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
+ public:
+ explicit FastHoleyObjectElementsAccessor(const char* name)
+ : FastSmiOrObjectElementsAccessor<
+ FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
+};
+
+
+template<typename FastElementsAccessorSubclass,
+ typename KindTraits>
class FastDoubleElementsAccessor
- : public FastElementsAccessor<FastDoubleElementsAccessor,
- ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
+ : public FastElementsAccessor<FastElementsAccessorSubclass,
+ KindTraits,
kDoubleSize> {
public:
explicit FastDoubleElementsAccessor(const char* name)
- : FastElementsAccessor<FastDoubleElementsAccessor,
- ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
+ : FastElementsAccessor<FastElementsAccessorSubclass,
+ KindTraits,
kDoubleSize>(name) {}
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
- return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
+ return obj->SetFastDoubleElementsCapacityAndLength(capacity,
+ length);
}
protected:
- friend class ElementsAccessorBase<FastDoubleElementsAccessor,
- ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
- friend class FastElementsAccessor<FastDoubleElementsAccessor,
- ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
- kDoubleSize>;
-
static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
uint32_t from_start,
FixedArrayBase* to,
@@ -814,12 +954,15 @@
uint32_t to_start,
int copy_size) {
switch (to_kind) {
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
return CopyDoubleToObjectElements(
FixedDoubleArray::cast(from), from_start, FixedArray::cast(to),
to_kind, to_start, copy_size);
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start,
FixedDoubleArray::cast(to),
to_start, copy_size);
@@ -829,26 +972,35 @@
}
return to->GetHeap()->undefined_value();
}
+};
- virtual MaybeObject* Delete(JSObject* obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
- int length = obj->IsJSArray()
- ? Smi::cast(JSArray::cast(obj)->length())->value()
- : FixedDoubleArray::cast(obj->elements())->length();
- if (key < static_cast<uint32_t>(length)) {
- FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
- }
- return obj->GetHeap()->true_value();
- }
- static bool HasElementImpl(Object* receiver,
- JSObject* holder,
- uint32_t key,
- FixedDoubleArray* backing_store) {
- return key < static_cast<uint32_t>(backing_store->length()) &&
- !backing_store->is_the_hole(key);
- }
+class FastPackedDoubleElementsAccessor
+ : public FastDoubleElementsAccessor<
+ FastPackedDoubleElementsAccessor,
+ ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
+ public:
+ friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
+ ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
+ explicit FastPackedDoubleElementsAccessor(const char* name)
+ : FastDoubleElementsAccessor<
+ FastPackedDoubleElementsAccessor,
+ ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
+};
+
+
+class FastHoleyDoubleElementsAccessor
+ : public FastDoubleElementsAccessor<
+ FastHoleyDoubleElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
+ public:
+ friend class ElementsAccessorBase<
+ FastHoleyDoubleElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
+ explicit FastHoleyDoubleElementsAccessor(const char* name)
+ : FastDoubleElementsAccessor<
+ FastHoleyDoubleElementsAccessor,
+ ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
};
@@ -1115,13 +1267,16 @@
uint32_t to_start,
int copy_size) {
switch (to_kind) {
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
CopyDictionaryToObjectElements(
SeededNumberDictionary::cast(from), from_start,
FixedArray::cast(to), to_kind, to_start, copy_size);
return from;
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
CopyDictionaryToDoubleElements(
SeededNumberDictionary::cast(from), from_start,
FixedDoubleArray::cast(to), to_start, copy_size);
@@ -1248,7 +1403,10 @@
if (arguments->IsDictionary()) {
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
} else {
- return FastObjectElementsAccessor::DeleteCommon(obj, key);
+ // It's difficult to access the version of DeleteCommon that is declared
+ // in the templatized super class, call the concrete implementation in
+ // the class for the most generalized ElementsKind subclass.
+ return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
}
}
return obj->GetHeap()->true_value();
@@ -1312,7 +1470,7 @@
if (array->IsDictionary()) {
return elements_accessors_[DICTIONARY_ELEMENTS];
} else {
- return elements_accessors_[FAST_ELEMENTS];
+ return elements_accessors_[FAST_HOLEY_ELEMENTS];
}
case EXTERNAL_BYTE_ARRAY_TYPE:
return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
diff --git a/src/elements.h b/src/elements.h
index 55d6fa5..822fca5 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -28,6 +28,7 @@
#ifndef V8_ELEMENTS_H_
#define V8_ELEMENTS_H_
+#include "elements-kind.h"
#include "objects.h"
#include "heap.h"
#include "isolate.h"
@@ -45,6 +46,10 @@
virtual ElementsKind kind() const = 0;
const char* name() const { return name_; }
+ // Checks the elements of an object for consistency, asserting when a problem
+ // is found.
+ virtual void Validate(JSObject* obj) = 0;
+
// Returns true if a holder contains an element with the specified key
// without iterating up the prototype chain. The caller can optionally pass
// in the backing store to use for the check, which must be compatible with
diff --git a/src/factory.cc b/src/factory.cc
index 6bb7893..1c29ea1 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -775,7 +775,7 @@
instance_size != JSObject::kHeaderSize) {
Handle<Map> initial_map = NewMap(type,
instance_size,
- FAST_SMI_ONLY_ELEMENTS);
+ GetInitialFastElementsKind());
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
}
@@ -1013,10 +1013,11 @@
void Factory::EnsureCanContainElements(Handle<JSArray> array,
Handle<FixedArrayBase> elements,
+ uint32_t length,
EnsureElementsMode mode) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
- array->EnsureCanContainElements(*elements, mode));
+ array->EnsureCanContainElements(*elements, length, mode));
}
diff --git a/src/factory.h b/src/factory.h
index 06aad1b..a999b15 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -216,9 +216,10 @@
Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
Handle<Object> value);
- Handle<Map> NewMap(InstanceType type,
- int instance_size,
- ElementsKind elements_kind = FAST_ELEMENTS);
+ Handle<Map> NewMap(
+ InstanceType type,
+ int instance_size,
+ ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND);
Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
@@ -269,13 +270,14 @@
Handle<JSModule> NewJSModule();
// JS arrays are pretenured when allocated by the parser.
- Handle<JSArray> NewJSArray(int capacity,
- ElementsKind elements_kind = FAST_ELEMENTS,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<JSArray> NewJSArray(
+ int capacity,
+ ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND,
+ PretenureFlag pretenure = NOT_TENURED);
Handle<JSArray> NewJSArrayWithElements(
Handle<FixedArrayBase> elements,
- ElementsKind elements_kind = FAST_ELEMENTS,
+ ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND,
PretenureFlag pretenure = NOT_TENURED);
void SetElementsCapacityAndLength(Handle<JSArray> array,
@@ -287,6 +289,7 @@
void EnsureCanContainHeapObjectElements(Handle<JSArray> array);
void EnsureCanContainElements(Handle<JSArray> array,
Handle<FixedArrayBase> elements,
+ uint32_t length,
EnsureElementsMode mode);
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index ccba511..fc9a1db 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -150,6 +150,7 @@
DEFINE_implication(harmony_modules, harmony_scoping)
// Flags for experimental implementation features.
+DEFINE_bool(packed_arrays, false, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
DEFINE_bool(clever_optimizations,
true,
diff --git a/src/func-name-inferrer.h b/src/func-name-inferrer.h
index 1a57268..ccd962a 100644
--- a/src/func-name-inferrer.h
+++ b/src/func-name-inferrer.h
@@ -88,6 +88,8 @@
void Leave() {
ASSERT(IsOpen());
names_stack_.Rewind(entries_stack_.RemoveLast());
+ if (entries_stack_.is_empty())
+ funcs_to_infer_.Clear();
}
private:
diff --git a/src/heap.cc b/src/heap.cc
index 47b259e..a224e2b 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2469,7 +2469,7 @@
// bottleneck to trap the Smi-only -> fast elements transition, and there
// appears to be no benefit for optimize this case.
Map* new_neander_map = Map::cast(obj);
- new_neander_map->set_elements_kind(FAST_ELEMENTS);
+ new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
set_neander_map(new_neander_map);
{ MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
@@ -3050,6 +3050,7 @@
}
JSMessageObject* message = JSMessageObject::cast(result);
message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
+ message->initialize_elements();
message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
message->set_type(type);
message->set_arguments(arguments);
@@ -3753,7 +3754,7 @@
// Check the state of the object
ASSERT(JSObject::cast(result)->HasFastProperties());
- ASSERT(JSObject::cast(result)->HasFastElements());
+ ASSERT(JSObject::cast(result)->HasFastObjectElements());
return result;
}
@@ -3798,7 +3799,7 @@
map->set_inobject_properties(in_object_properties);
map->set_unused_property_fields(in_object_properties);
map->set_prototype(prototype);
- ASSERT(map->has_fast_elements());
+ ASSERT(map->has_fast_object_elements());
// If the function has only simple this property assignments add
// field descriptors for these to the initial map as the object
@@ -3915,8 +3916,7 @@
InitializeJSObjectFromMap(JSObject::cast(obj),
FixedArray::cast(properties),
map);
- ASSERT(JSObject::cast(obj)->HasFastSmiOnlyElements() ||
- JSObject::cast(obj)->HasFastElements());
+ ASSERT(JSObject::cast(obj)->HasFastSmiOrObjectElements());
return obj;
}
@@ -3961,6 +3961,9 @@
ArrayStorageAllocationMode mode,
PretenureFlag pretenure) {
ASSERT(capacity >= length);
+ if (length != 0 && mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ }
MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
JSArray* array;
if (!maybe_array->To(&array)) return maybe_array;
@@ -3981,8 +3984,7 @@
maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
}
} else {
- ASSERT(elements_kind == FAST_ELEMENTS ||
- elements_kind == FAST_SMI_ONLY_ELEMENTS);
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
maybe_elms = AllocateUninitializedFixedArray(capacity);
} else {
@@ -4008,6 +4010,7 @@
array->set_elements(elements);
array->set_length(Smi::FromInt(elements->length()));
+ array->ValidateElements();
return array;
}
@@ -4548,13 +4551,13 @@
Context* global_context = isolate()->context()->global_context();
JSFunction* array_function = global_context->array_function();
Map* map = array_function->initial_map();
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- map = Map::cast(global_context->double_js_array_map());
- } else if (elements_kind == FAST_ELEMENTS || !FLAG_smi_only_arrays) {
- map = Map::cast(global_context->object_js_array_map());
- } else {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
- ASSERT(map == global_context->smi_js_array_map());
+ Object* maybe_map_array = global_context->js_array_maps();
+ if (!maybe_map_array->IsUndefined()) {
+ Object* maybe_transitioned_map =
+ FixedArray::cast(maybe_map_array)->get(elements_kind);
+ if (!maybe_transitioned_map->IsUndefined()) {
+ map = Map::cast(maybe_transitioned_map);
+ }
}
return AllocateJSObjectFromMap(map, pretenure);
@@ -4839,9 +4842,7 @@
}
Context* context = reinterpret_cast<Context*>(result);
context->set_map_no_write_barrier(global_context_map());
- context->set_smi_js_array_map(undefined_value());
- context->set_double_js_array_map(undefined_value());
- context->set_object_js_array_map(undefined_value());
+ context->set_js_array_maps(undefined_value());
ASSERT(context->IsGlobalContext());
ASSERT(result->IsContext());
return result;
diff --git a/src/heap.h b/src/heap.h
index beb1bc5..55e7135 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -621,7 +621,7 @@
MUST_USE_RESULT MaybeObject* AllocateMap(
InstanceType instance_type,
int instance_size,
- ElementsKind elements_kind = FAST_ELEMENTS);
+ ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND);
// Allocates a partial map for bootstrapping.
MUST_USE_RESULT MaybeObject* AllocatePartialMap(InstanceType instance_type,
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index c66a7a1..57a1862 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1685,6 +1685,9 @@
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("]");
+ if (hole_check_mode_ == PERFORM_HOLE_CHECK) {
+ stream->Add(" check_hole");
+ }
}
@@ -1736,7 +1739,7 @@
HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
index_cache,
key_load->key(),
- HLoadKeyedFastElement::OMIT_HOLE_CHECK);
+ OMIT_HOLE_CHECK);
HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
object(), index);
map_check->InsertBefore(this);
@@ -1784,8 +1787,11 @@
stream->Add("pixel");
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -1882,9 +1888,12 @@
case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
- 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:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -1899,7 +1908,13 @@
void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
- stream->Add(" %p -> %p", *original_map(), *transitioned_map());
+ ElementsKind from_kind = original_map()->elements_kind();
+ ElementsKind to_kind = transitioned_map()->elements_kind();
+ stream->Add(" %p [%s] -> %p [%s]",
+ *original_map(),
+ ElementsAccessor::ForKind(from_kind)->name(),
+ *transitioned_map(),
+ ElementsAccessor::ForKind(to_kind)->name());
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 4f21db7..c68befd 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -2083,28 +2083,21 @@
HCheckMaps* check_map = new HCheckMaps(object, map);
SmallMapList* map_set = check_map->map_set();
- // If the map to check has the untransitioned elements, it can be hoisted
- // above TransitionElements instructions.
- if (map->has_fast_smi_only_elements()) {
- check_map->ClearGVNFlag(kDependsOnElementsKind);
- }
+ // Since transitioned elements maps of the initial map don't fail the map
+ // check, the CheckMaps instruction doesn't need to depend on ElementsKinds.
+ check_map->ClearGVNFlag(kDependsOnElementsKind);
- Map* transitioned_fast_element_map =
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL);
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- map_set->Add(Handle<Map>(transitioned_fast_element_map));
- }
- Map* transitioned_double_map =
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL);
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- map_set->Add(Handle<Map>(transitioned_double_map));
- }
+ ElementsKind kind = map->elements_kind();
+ bool packed = IsFastPackedElementsKind(kind);
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ Map* transitioned_map =
+ map->LookupElementsTransitionMap(kind, NULL);
+ if (transitioned_map) {
+ map_set->Add(Handle<Map>(transitioned_map));
+ }
+ };
map_set->Sort();
-
return check_map;
}
@@ -3956,11 +3949,12 @@
virtual ~ArrayInstructionInterface() { };
};
+
+enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
+
class HLoadKeyedFastElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
- enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
-
HLoadKeyedFastElement(HValue* obj,
HValue* key,
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
@@ -4015,14 +4009,19 @@
class HLoadKeyedFastDoubleElement
: public HTemplateInstruction<2>, public ArrayInstructionInterface {
public:
- HLoadKeyedFastDoubleElement(HValue* elements, HValue* key)
- : index_offset_(0), is_dehoisted_(false) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- set_representation(Representation::Double());
+ HLoadKeyedFastDoubleElement(
+ HValue* elements,
+ HValue* key,
+ HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
+ : index_offset_(0),
+ is_dehoisted_(false),
+ hole_check_mode_(hole_check_mode) {
+ SetOperandAt(0, elements);
+ SetOperandAt(1, key);
+ set_representation(Representation::Double());
SetGVNFlag(kDependsOnDoubleArrayElements);
SetFlag(kUseGVN);
- }
+ }
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
@@ -4040,16 +4039,26 @@
: Representation::Integer32();
}
+ bool RequiresHoleCheck() {
+ return hole_check_mode_ == PERFORM_HOLE_CHECK;
+ }
+
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
protected:
- virtual bool DataEquals(HValue* other) { return true; }
+ virtual bool DataEquals(HValue* other) {
+ if (!other->IsLoadKeyedFastDoubleElement()) return false;
+ HLoadKeyedFastDoubleElement* other_load =
+ HLoadKeyedFastDoubleElement::cast(other);
+ return hole_check_mode_ == other_load->hole_check_mode_;
+ }
private:
uint32_t index_offset_;
bool is_dehoisted_;
+ HoleCheckMode hole_check_mode_;
};
@@ -4256,7 +4265,7 @@
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
bool value_is_smi() {
- return elements_kind_ == FAST_SMI_ONLY_ELEMENTS;
+ return IsFastSmiElementsKind(elements_kind_);
}
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
@@ -4427,9 +4436,19 @@
transitioned_map_(transitioned_map) {
SetOperandAt(0, object);
SetFlag(kUseGVN);
+ // Don't set GVN DependOn flags here. That would defeat GVN's detection of
+ // congruent HTransitionElementsKind instructions. Instruction hoisting
+ // handles HTransitionElementsKind instruction specially, explicitly adding
+ // DependsOn flags during its dependency calculations.
SetGVNFlag(kChangesElementsKind);
- SetGVNFlag(kChangesElementsPointer);
- SetGVNFlag(kChangesNewSpacePromotion);
+ if (original_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+ if (transitioned_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
set_representation(Representation::Tagged());
}
@@ -4667,7 +4686,7 @@
HValue* context() { return OperandAt(0); }
ElementsKind boilerplate_elements_kind() const {
if (!boilerplate_object_->IsJSObject()) {
- return FAST_ELEMENTS;
+ return TERMINAL_FAST_ELEMENTS_KIND;
}
return Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind();
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 99beda0..b9ad8af 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1709,23 +1709,23 @@
bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
if (instr->IsTransitionElementsKind()) {
// It's possible to hoist transitions out of a loop as long as the
- // hoisting wouldn't move the transition past a DependsOn of one of it's
- // changes or any instructions that might change an objects map or
- // elements contents.
- GVNFlagSet changes = instr->ChangesFlags();
+ // hoisting wouldn't move the transition past an instruction that has a
+ // DependsOn flag for anything it changes.
GVNFlagSet hoist_depends_blockers =
- HValue::ConvertChangesToDependsFlags(changes);
- // In addition to not hoisting transitions above other instructions that
- // change dependencies that the transition changes, it must not be
- // hoisted above map changes and stores to an elements backing store
- // that the transition might change.
- GVNFlagSet hoist_change_blockers = changes;
- hoist_change_blockers.Add(kChangesMaps);
+ HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
+
+ // In addition, the transition must not be hoisted above elements kind
+ // changes, or if the transition is destructive to the elements buffer,
+ // changes to array pointer or array contents.
+ GVNFlagSet hoist_change_blockers;
+ hoist_change_blockers.Add(kChangesElementsKind);
HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
if (trans->original_map()->has_fast_double_elements()) {
+ hoist_change_blockers.Add(kChangesElementsPointer);
hoist_change_blockers.Add(kChangesDoubleArrayElements);
}
if (trans->transitioned_map()->has_fast_double_elements()) {
+ hoist_change_blockers.Add(kChangesElementsPointer);
hoist_change_blockers.Add(kChangesArrayElements);
}
if (FLAG_trace_gvn) {
@@ -3966,7 +3966,7 @@
new(zone()) HLoadKeyedFastElement(
environment()->ExpressionStackAt(2), // Enum cache.
environment()->ExpressionStackAt(0), // Iteration index.
- HLoadKeyedFastElement::OMIT_HOLE_CHECK));
+ OMIT_HOLE_CHECK));
// Check if the expected map still matches that of the enumerable.
// If not just deoptimize.
@@ -4257,7 +4257,7 @@
elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
if (boilerplate->HasFastDoubleElements()) {
*total_size += FixedDoubleArray::SizeFor(elements->length());
- } else if (boilerplate->HasFastElements()) {
+ } else if (boilerplate->HasFastObjectElements()) {
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
int length = elements->length();
for (int i = 0; i < length; i++) {
@@ -4464,11 +4464,13 @@
Representation::Integer32()));
switch (boilerplate_elements_kind) {
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
// Smi-only arrays need a smi check.
AddInstruction(new(zone()) HCheckSmi(value));
// Fall through.
case FAST_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
AddInstruction(new(zone()) HStoreKeyedFastElement(
elements,
key,
@@ -4476,6 +4478,7 @@
boilerplate_elements_kind));
break;
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements,
key,
value));
@@ -5233,9 +5236,12 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
break;
- 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:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -5260,13 +5266,16 @@
ASSERT(val != NULL);
switch (elements_kind) {
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
return new(zone()) HStoreKeyedFastDoubleElement(
elements, checked_key, val);
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
// Smi-only arrays need a smi check.
AddInstruction(new(zone()) HCheckSmi(val));
// Fall through.
case FAST_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
return new(zone()) HStoreKeyedFastElement(
elements, checked_key, val, elements_kind);
default:
@@ -5275,10 +5284,13 @@
}
}
// It's an element load (!is_store).
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
- } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS.
- return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ?
+ OMIT_HOLE_CHECK :
+ PERFORM_HOLE_CHECK;
+ if (IsFastDoubleElementsKind(elements_kind)) {
+ return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode);
+ } else { // Smi or Object elements.
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode);
}
}
@@ -5286,15 +5298,30 @@
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
+ HValue* dependency,
Handle<Map> map,
bool is_store) {
- HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map));
- bool fast_smi_only_elements = map->has_fast_smi_only_elements();
- bool fast_elements = map->has_fast_elements();
+ HInstruction* mapcheck =
+ AddInstruction(new(zone()) HCheckMaps(object, map, dependency));
+ // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
+ // on a HElementsTransition instruction. The flag can also be removed if the
+ // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
+ // ElementsKind transitions. Finally, the dependency can be removed for stores
+ // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
+ // generated store code.
+ if (dependency ||
+ (map->elements_kind() == FAST_HOLEY_ELEMENTS) ||
+ (map->elements_kind() == FAST_ELEMENTS && is_store)) {
+ mapcheck->ClearGVNFlag(kDependsOnElementsKind);
+ }
+ bool fast_smi_only_elements = map->has_fast_smi_elements();
+ bool fast_elements = map->has_fast_object_elements();
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
if (is_store && (fast_elements || fast_smi_only_elements)) {
- AddInstruction(new(zone()) HCheckMaps(
- elements, isolate()->factory()->fixed_array_map()));
+ HCheckMaps* check_cow_map = new(zone()) HCheckMaps(
+ elements, isolate()->factory()->fixed_array_map());
+ check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
+ AddInstruction(check_cow_map);
}
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
@@ -5347,8 +5374,8 @@
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
ElementsKind elements_kind = map->elements_kind();
- if (elements_kind == FAST_DOUBLE_ELEMENTS ||
- elements_kind == FAST_ELEMENTS) {
+ if (IsFastElementsKind(elements_kind) &&
+ elements_kind != GetInitialFastElementsKind()) {
possible_transitioned_maps.Add(map);
}
}
@@ -5362,12 +5389,17 @@
int num_untransitionable_maps = 0;
Handle<Map> untransitionable_map;
+ HTransitionElementsKind* transition = NULL;
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
ASSERT(map->IsMap());
if (!transition_target.at(i).is_null()) {
- AddInstruction(new(zone()) HTransitionElementsKind(
- object, map, transition_target.at(i)));
+ ASSERT(Map::IsValidElementsTransition(
+ map->elements_kind(),
+ transition_target.at(i)->elements_kind()));
+ transition = new(zone()) HTransitionElementsKind(
+ object, map, transition_target.at(i));
+ AddInstruction(transition);
} else {
type_todo[map->elements_kind()] = true;
if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
@@ -5387,7 +5419,7 @@
: BuildLoadKeyedGeneric(object, key));
} else {
instr = AddInstruction(BuildMonomorphicElementAccess(
- object, key, val, untransitionable_map, is_store));
+ object, key, val, transition, untransitionable_map, is_store));
}
*has_side_effects |= instr->HasObservableSideEffects();
instr->set_position(position);
@@ -5404,20 +5436,18 @@
HLoadExternalArrayPointer* external_elements = NULL;
HInstruction* checked_key = NULL;
- // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS,
- // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external
- // arrays.
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
- STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds
+ // are handled before external arrays.
+ STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND;
elements_kind <= LAST_ELEMENTS_KIND;
elements_kind = ElementsKind(elements_kind + 1)) {
- // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS,
- // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code
- // that's executed for all external array cases.
+ // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some
+ // code that's executed for all external array cases.
STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
LAST_ELEMENTS_KIND);
if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
@@ -5439,10 +5469,8 @@
set_current_block(if_true);
HInstruction* access;
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_ELEMENTS ||
- elements_kind == FAST_DOUBLE_ELEMENTS) {
- if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) {
+ if (IsFastElementsKind(elements_kind)) {
+ if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
AddInstruction(new(zone()) HCheckMaps(
elements, isolate()->factory()->fixed_array_map(),
elements_kind_branch));
@@ -5529,7 +5557,7 @@
: BuildLoadKeyedGeneric(obj, key);
} else {
AddInstruction(new(zone()) HCheckNonSmi(obj));
- instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store);
+ instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store);
}
} else if (expr->GetReceiverTypes() != NULL &&
!expr->GetReceiverTypes()->is_empty()) {
diff --git a/src/hydrogen.h b/src/hydrogen.h
index b56a5af..5c8ddbf 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1093,6 +1093,7 @@
HInstruction* BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
+ HValue* dependency,
Handle<Map> map,
bool is_store);
HValue* HandlePolymorphicElementAccess(HValue* object,
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index a36763d..be46ff2 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -900,7 +900,7 @@
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadInitialArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -1003,7 +1003,8 @@
ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax
- __ LoadInitialArrayMap(array_function, scratch, elements_array);
+ __ LoadInitialArrayMap(array_function, scratch,
+ elements_array, fill_with_hole);
// Allocate the JSArray object together with space for a FixedArray with the
// requested elements.
@@ -1274,11 +1275,11 @@
__ jmp(&prepare_generic_code_call);
__ bind(¬_double);
- // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS.
+ // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
__ mov(ebx, Operand(esp, 0));
__ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
__ LoadTransitionedArrayMapConditional(
- FAST_SMI_ONLY_ELEMENTS,
+ FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
edi,
eax,
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index a701d1b..df04b28 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -7063,8 +7063,8 @@
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET},
{ REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET},
- // ElementsTransitionGenerator::GenerateSmiOnlyToObject
- // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // ElementsTransitionGenerator::GenerateMapChangeElementTransition
+ // and ElementsTransitionGenerator::GenerateSmiToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
{ REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET},
{ REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET},
@@ -7336,9 +7336,9 @@
__ CheckFastElements(edi, &double_elements);
- // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
__ JumpIfSmi(eax, &smi_element);
- __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
+ __ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
// Store into the array literal requires a elements transition. Call into
// the runtime.
@@ -7360,7 +7360,7 @@
__ pop(edx);
__ jmp(&slow_elements);
- // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
__ bind(&fast_elements);
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
__ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
@@ -7373,15 +7373,15 @@
OMIT_SMI_CHECK);
__ ret(0);
- // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
- // FAST_ELEMENTS, and value is Smi.
+ // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
+ // and value is Smi.
__ bind(&smi_element);
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
__ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
FixedArrayBase::kHeaderSize), eax);
__ ret(0);
- // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+ // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
__ bind(&double_elements);
__ push(edx);
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index cff6454..eb68687 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -351,7 +351,7 @@
#define __ ACCESS_MASM(masm)
-void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
@@ -372,7 +372,7 @@
}
-void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+void ElementsTransitionGenerator::GenerateSmiToDouble(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- eax : value
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 266afce..9727ea0 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1649,7 +1649,8 @@
ASSERT_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
- bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
+ bool has_constant_fast_elements =
+ IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
@@ -1660,7 +1661,7 @@
Heap* heap = isolate()->heap();
if (has_constant_fast_elements &&
constant_elements_values->map() == heap->fixed_cow_array_map()) {
- // If the elements are already FAST_ELEMENTS, the boilerplate cannot
+ // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
FastCloneShallowArrayStub stub(
@@ -1672,10 +1673,9 @@
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
- ASSERT(constant_elements_kind == FAST_ELEMENTS ||
- constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
- // If the elements are already FAST_ELEMENTS, the boilerplate cannot
+ // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
@@ -1703,9 +1703,9 @@
}
VisitForAccumulatorValue(subexpr);
- if (constant_elements_kind == FAST_ELEMENTS) {
- // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
- // transition and don't need to call the runtime stub.
+ if (IsFastObjectElementsKind(constant_elements_kind)) {
+ // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
+ // cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ mov(ebx, Operand(esp, 0)); // Copy of array literal.
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index dc64a09..a091ff1 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -889,25 +889,25 @@
&non_double_value,
DONT_DO_SMI_CHECK);
- // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
+ // and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS,
ebx,
edi,
&slow);
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
ebx,
edi,
&slow);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
@@ -1622,7 +1622,7 @@
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
__ mov(eax, edx);
__ Ret();
__ bind(&fail);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index fa58146..18f2a39 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2377,8 +2377,10 @@
__ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Map::kElementsKindMask);
__ shr(temp, Map::kElementsKindShift);
- __ cmp(temp, FAST_ELEMENTS);
- __ j(equal, &ok, Label::kNear);
+ __ cmp(temp, GetInitialFastElementsKind());
+ __ j(less, &fail, Label::kNear);
+ __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
+ __ j(less_equal, &ok, Label::kNear);
__ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less, &fail, Label::kNear);
__ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
@@ -2439,15 +2441,17 @@
LLoadKeyedFastDoubleElement* instr) {
XMMRegister result = ToDoubleRegister(instr->result());
- int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
- sizeof(kHoleNanLower32);
- Operand hole_check_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(),
- FAST_DOUBLE_ELEMENTS,
- offset,
- instr->additional_index());
- __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
- DeoptimizeIf(equal, instr->environment());
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
+ sizeof(kHoleNanLower32);
+ Operand hole_check_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ offset,
+ instr->additional_index());
+ __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
+ DeoptimizeIf(equal, instr->environment());
+ }
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(),
@@ -2528,9 +2532,12 @@
break;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
- 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:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3456,9 +3463,12 @@
break;
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
- 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:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3550,22 +3560,23 @@
__ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
__ j(not_equal, ¬_applicable);
__ mov(new_map_reg, to_map);
- if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
Register object_reg = ToRegister(instr->object());
__ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
// Write barrier.
ASSERT_NE(instr->temp_reg(), NULL);
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ToRegister(instr->temp_reg()), kDontSaveFPRegs);
- } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- to_kind == FAST_DOUBLE_ELEMENTS) {
+ } else if (IsFastSmiElementsKind(from_kind) &&
+ IsFastDoubleElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(edx));
ASSERT(new_map_reg.is(ebx));
__ mov(fixed_object_reg, object_reg);
CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
RelocInfo::CODE_TARGET, instr);
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ } else if (IsFastDoubleElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(edx));
ASSERT(new_map_reg.is(ebx));
@@ -4425,8 +4436,9 @@
// Deopt if the array literal boilerplate ElementsKind is of a type different
// than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
// Load the map's "bit field 2". We only need the first byte,
@@ -4588,8 +4600,9 @@
// Deopt if the literal boilerplate ElementsKind is of a type different than
// the expected one. The check isn't necessary if the boilerplate has already
- // been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
// Load the map's "bit field 2". We only need the first byte,
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index d0cb230..fbc75d0 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2092,8 +2092,9 @@
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
- if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
+ ElementsKind from_kind = instr->original_map()->elements_kind();
+ ElementsKind to_kind = instr->transitioned_map()->elements_kind();
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LOperand* temp_reg = TempRegister();
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index c31b0c2..1b61486 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -382,10 +382,12 @@
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Map::kMaximumBitField2FastElementValue);
+ Map::kMaximumBitField2FastHoleyElementValue);
j(above, fail, distance);
}
@@ -393,23 +395,26 @@
void MacroAssembler::CheckFastObjectElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Map::kMaximumBitField2FastSmiOnlyElementValue);
+ Map::kMaximumBitField2FastHoleySmiElementValue);
j(below_equal, fail, distance);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Map::kMaximumBitField2FastElementValue);
+ Map::kMaximumBitField2FastHoleyElementValue);
j(above, fail, distance);
}
-void MacroAssembler::CheckFastSmiOnlyElements(Register map,
- Label* fail,
- Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+void MacroAssembler::CheckFastSmiElements(Register map,
+ Label* fail,
+ Label::Distance distance) {
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Map::kMaximumBitField2FastSmiOnlyElementValue);
+ Map::kMaximumBitField2FastHoleySmiElementValue);
j(above, fail, distance);
}
@@ -493,24 +498,18 @@
CompareMapMode mode) {
cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) {
- Map* transitioned_fast_element_map(
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL));
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- j(equal, early_success, Label::kNear);
- cmp(FieldOperand(obj, HeapObject::kMapOffset),
- Handle<Map>(transitioned_fast_element_map));
- }
-
- Map* transitioned_double_map(
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL));
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- j(equal, early_success, Label::kNear);
- cmp(FieldOperand(obj, HeapObject::kMapOffset),
- Handle<Map>(transitioned_double_map));
+ ElementsKind kind = map->elements_kind();
+ if (IsFastElementsKind(kind)) {
+ bool packed = IsFastPackedElementsKind(kind);
+ Map* current_map = *map;
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
+ if (!current_map) break;
+ j(equal, early_success, Label::kNear);
+ cmp(FieldOperand(obj, HeapObject::kMapOffset),
+ Handle<Map>(current_map));
+ }
}
}
}
@@ -2161,27 +2160,38 @@
mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check that the function's map is the same as the expected cached map.
- int expected_index =
- Context::GetContextMapIndexFromElementsKind(expected_kind);
- cmp(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+ mov(scratch, Operand(scratch,
+ Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
+
+ size_t offset = expected_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ cmp(map_in_out, FieldOperand(scratch, offset));
j(not_equal, no_map_match);
// Use the transitioned cached map.
- int trans_index =
- Context::GetContextMapIndexFromElementsKind(transitioned_kind);
- mov(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+ offset = transitioned_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ mov(map_in_out, FieldOperand(scratch, offset));
}
void MacroAssembler::LoadInitialArrayMap(
- Register function_in, Register scratch, Register map_out) {
+ Register function_in, Register scratch,
+ Register map_out, bool can_have_holes) {
ASSERT(!function_in.is(map_out));
Label done;
mov(map_out, FieldOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
- FAST_ELEMENTS,
+ ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ kind,
+ map_out,
+ scratch,
+ &done);
+ } else if (can_have_holes) {
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_HOLEY_SMI_ELEMENTS,
map_out,
scratch,
&done);
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 66d1ce7..c71cad8 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -235,7 +235,8 @@
// Load the initial map for new Arrays from a JSFunction.
void LoadInitialArrayMap(Register function_in,
Register scratch,
- Register map_out);
+ Register map_out,
+ bool can_have_holes);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
@@ -357,9 +358,9 @@
// Check if a map for a JSObject indicates that the object has fast smi only
// elements. Jump to the specified label if it does not.
- void CheckFastSmiOnlyElements(Register map,
- Label* fail,
- Label::Distance distance = Label::kFar);
+ void CheckFastSmiElements(Register map,
+ Label* fail,
+ Label::Distance distance = Label::kFar);
// Check to see if maybe_number can be stored as a double in
// FastDoubleElements. If it can, store it at the index specified by key in
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index e148e2f..71740ac 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -1462,16 +1462,31 @@
__ jmp(&fast_object);
// In case of fast smi-only, convert to fast object, otherwise bail out.
__ bind(¬_fast_object);
- __ CheckFastSmiOnlyElements(ebx, &call_builtin);
+ __ CheckFastSmiElements(ebx, &call_builtin);
// edi: elements array
// edx: receiver
// ebx: map
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ Label try_holey_map;
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
ebx,
edi,
+ &try_holey_map);
+
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
+ // Restore edi.
+ __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
+ __ jmp(&fast_object);
+
+ __ bind(&try_holey_map);
+ __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
+ FAST_HOLEY_ELEMENTS,
+ ebx,
+ edi,
&call_builtin);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
// Restore edi.
__ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
__ bind(&fast_object);
@@ -3818,7 +3833,7 @@
// Check that the key is a smi or a heap number convertible to a smi.
GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(eax, &transition_elements_kind);
}
@@ -3843,7 +3858,7 @@
__ j(not_equal, &miss_force_generic);
__ bind(&finish_store);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
// ecx is a smi, use times_half_pointer_size instead of
// times_pointer_size
__ mov(FieldOperand(edi,
@@ -3851,7 +3866,7 @@
times_half_pointer_size,
FixedArray::kHeaderSize), eax);
} else {
- ASSERT(elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastObjectElementsKind(elements_kind));
// Do the store and update the write barrier.
// ecx is a smi, use times_half_pointer_size instead of
// times_pointer_size
diff --git a/src/ic.cc b/src/ic.cc
index 9772b94..134ef8b 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1644,8 +1644,7 @@
return string_stub();
} else {
ASSERT(receiver_map->has_dictionary_elements() ||
- receiver_map->has_fast_elements() ||
- receiver_map->has_fast_smi_only_elements() ||
+ receiver_map->has_fast_smi_or_object_elements() ||
receiver_map->has_fast_double_elements() ||
receiver_map->has_external_array_elements());
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
@@ -1660,8 +1659,7 @@
StubKind stub_kind,
StrictModeFlag strict_mode,
Handle<Code> generic_stub) {
- if (receiver->HasFastElements() ||
- receiver->HasFastSmiOnlyElements() ||
+ if (receiver->HasFastSmiOrObjectElements() ||
receiver->HasExternalArrayElements() ||
receiver->HasFastDoubleElements() ||
receiver->HasDictionaryElements()) {
@@ -1681,15 +1679,26 @@
case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
case KeyedIC::STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
- break;
case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
- break;
- default:
+ case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
+ case KeyedIC::STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+ case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
+ case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+ return JSObject::GetElementsTransitionMap(receiver,
+ FAST_HOLEY_ELEMENTS);
+ case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+ case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+ return JSObject::GetElementsTransitionMap(receiver,
+ FAST_HOLEY_DOUBLE_ELEMENTS);
+ case KeyedIC::LOAD:
+ case KeyedIC::STORE_NO_TRANSITION:
+ case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
UNREACHABLE();
- return Handle<Map>::null();
+ break;
}
+ return Handle<Map>::null();
}
@@ -1749,30 +1758,54 @@
if (allow_growth) {
// Handle growing array in stub if necessary.
- if (receiver->HasFastSmiOnlyElements()) {
+ if (receiver->HasFastSmiElements()) {
if (value->IsHeapNumber()) {
- return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
+ } else {
+ return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
+ }
}
if (value->IsHeapObject()) {
- return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
+ } else {
+ return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
+ }
}
} else if (receiver->HasFastDoubleElements()) {
if (!value->IsSmi() && !value->IsHeapNumber()) {
- return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
+ } else {
+ return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
+ }
}
}
return STORE_AND_GROW_NO_TRANSITION;
} else {
// Handle only in-bounds elements accesses.
- if (receiver->HasFastSmiOnlyElements()) {
+ if (receiver->HasFastSmiElements()) {
if (value->IsHeapNumber()) {
- return STORE_TRANSITION_SMI_TO_DOUBLE;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
+ } else {
+ return STORE_TRANSITION_SMI_TO_DOUBLE;
+ }
} else if (value->IsHeapObject()) {
- return STORE_TRANSITION_SMI_TO_OBJECT;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
+ } else {
+ return STORE_TRANSITION_SMI_TO_OBJECT;
+ }
}
} else if (receiver->HasFastDoubleElements()) {
if (!value->IsSmi() && !value->IsHeapNumber()) {
- return STORE_TRANSITION_DOUBLE_TO_OBJECT;
+ if (receiver->HasFastHoleyElements()) {
+ return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
+ } else {
+ return STORE_TRANSITION_DOUBLE_TO_OBJECT;
+ }
}
}
return STORE_NO_TRANSITION;
diff --git a/src/ic.h b/src/ic.h
index 3b44abf..c1b9549 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -378,10 +378,16 @@
STORE_TRANSITION_SMI_TO_OBJECT,
STORE_TRANSITION_SMI_TO_DOUBLE,
STORE_TRANSITION_DOUBLE_TO_OBJECT,
+ STORE_TRANSITION_HOLEY_SMI_TO_OBJECT,
+ STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+ STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT,
STORE_AND_GROW_NO_TRANSITION,
STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
- STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT
+ STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT,
+ STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT,
+ STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+ STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT
};
static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index cbd0b26..c5e73ed 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -324,7 +324,7 @@
index)));
if (index == -1) return isolate->factory()->null_value();
}
- ASSERT(last_match_info->HasFastElements());
+ ASSERT(last_match_info->HasFastObjectElements());
{
NoHandleAllocation no_handles;
diff --git a/src/lithium.cc b/src/lithium.cc
index c41cce8..4ee2a7a 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -225,9 +225,12 @@
return 2;
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
return 3;
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
return kPointerSizeLog2;
diff --git a/src/messages.js b/src/messages.js
index ab71936..2a00ba8 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -788,15 +788,7 @@
}
function CallSiteGetTypeName() {
- var constructor = this.receiver.constructor;
- if (!constructor) {
- return %_CallFunction(this.receiver, ObjectToString);
- }
- var constructorName = constructor.name;
- if (!constructorName) {
- return %_CallFunction(this.receiver, ObjectToString);
- }
- return constructorName;
+ return GetTypeName(this, false);
}
function CallSiteIsToplevel() {
@@ -830,8 +822,10 @@
var name = this.fun.name;
if (name) {
return name;
- } else {
- return %FunctionGetInferredName(this.fun);
+ }
+ name = %FunctionGetInferredName(this.fun);
+ if (name) {
+ return name;
}
// Maybe this is an evaluation?
var script = %FunctionGetScript(this.fun);
@@ -952,20 +946,24 @@
fileLocation = "unknown source";
}
var line = "";
- var functionName = this.getFunction().name;
- var addPrefix = true;
+ var functionName = this.getFunctionName();
+ var addSuffix = true;
var isConstructor = this.isConstructor();
var isMethodCall = !(this.isToplevel() || isConstructor);
if (isMethodCall) {
+ var typeName = GetTypeName(this, true);
var methodName = this.getMethodName();
- line += this.getTypeName() + ".";
if (functionName) {
+ if (typeName && functionName.indexOf(typeName) != 0) {
+ line += typeName + ".";
+ }
line += functionName;
- if (methodName && (methodName != functionName)) {
+ if (methodName && functionName.lastIndexOf("." + methodName) !=
+ functionName.length - methodName.length - 1) {
line += " [as " + methodName + "]";
}
} else {
- line += methodName || "<anonymous>";
+ line += typeName + "." + (methodName || "<anonymous>");
}
} else if (isConstructor) {
line += "new " + (functionName || "<anonymous>");
@@ -973,9 +971,9 @@
line += functionName;
} else {
line += fileLocation;
- addPrefix = false;
+ addSuffix = false;
}
- if (addPrefix) {
+ if (addSuffix) {
line += " (" + fileLocation + ")";
}
return line;
@@ -1085,6 +1083,19 @@
}
}
+function GetTypeName(obj, requireConstructor) {
+ var constructor = obj.receiver.constructor;
+ if (!constructor) {
+ return requireConstructor ? null :
+ %_CallFunction(obj.receiver, ObjectToString);
+ }
+ var constructorName = constructor.name;
+ if (!constructorName) {
+ return requireConstructor ? null :
+ %_CallFunction(obj.receiver, ObjectToString);
+ }
+ return constructorName;
+}
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index eeb84c3..5a2074e 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -118,7 +118,7 @@
Label* gc_required) {
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadInitialArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -214,7 +214,8 @@
bool fill_with_hole,
Label* gc_required) {
// Load the initial map from the array function.
- __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage);
+ __ LoadInitialArrayMap(array_function, scratch2,
+ elements_array_storage, fill_with_hole);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ Assert(
@@ -449,10 +450,10 @@
__ Branch(call_generic_code);
__ bind(¬_double);
- // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS.
+ // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
// a3: JSArray
__ lw(a2, FieldMemOperand(a3, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
a2,
t5,
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a83468c..a464348 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -7370,8 +7370,8 @@
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ REG(a3), REG(a2), REG(t0), EMIT_REMEMBERED_SET },
{ REG(a2), REG(a3), REG(t0), EMIT_REMEMBERED_SET },
- // ElementsTransitionGenerator::GenerateSmiOnlyToObject
- // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // ElementsTransitionGenerator::GenerateMapChangeElementTransition
+ // and ElementsTransitionGenerator::GenerateSmiToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
{ REG(a2), REG(a3), REG(t5), EMIT_REMEMBERED_SET },
{ REG(a2), REG(a3), REG(t5), OMIT_REMEMBERED_SET },
@@ -7637,9 +7637,9 @@
Label fast_elements;
__ CheckFastElements(a2, t1, &double_elements);
- // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
__ JumpIfSmi(a0, &smi_element);
- __ CheckFastSmiOnlyElements(a2, t1, &fast_elements);
+ __ CheckFastSmiElements(a2, t1, &fast_elements);
// Store into the array literal requires a elements transition. Call into
// the runtime.
@@ -7651,7 +7651,7 @@
__ Push(t1, t0);
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
- // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
__ bind(&fast_elements);
__ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
__ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
@@ -7664,8 +7664,8 @@
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
- // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
- // FAST_ELEMENTS, and value is Smi.
+ // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
+ // and value is Smi.
__ bind(&smi_element);
__ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
__ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
@@ -7674,7 +7674,7 @@
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
- // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+ // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
__ bind(&double_elements);
__ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
__ StoreNumberToDoubleElements(a0, a3, a1, t1, t2, t3, t5, a2,
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 9acccdc..44e0359 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -72,7 +72,7 @@
// -------------------------------------------------------------------------
// Code generators
-void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : value
@@ -95,7 +95,7 @@
}
-void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+void ElementsTransitionGenerator::GenerateSmiToDouble(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- a0 : value
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 7be5056..3ed794a 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1711,7 +1711,8 @@
ASSERT_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
- bool has_fast_elements = constant_elements_kind == FAST_ELEMENTS;
+ bool has_fast_elements =
+ IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
@@ -1733,8 +1734,7 @@
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
- ASSERT(constant_elements_kind == FAST_ELEMENTS ||
- constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
FastCloneShallowArrayStub::Mode mode = has_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
@@ -1763,7 +1763,7 @@
VisitForAccumulatorValue(subexpr);
- if (constant_elements_kind == FAST_ELEMENTS) {
+ if (IsFastObjectElementsKind(constant_elements_kind)) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ lw(t2, MemOperand(sp)); // Copy of array literal.
__ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset));
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 964a7e2..5d530d0 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1347,34 +1347,35 @@
__ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
__ Branch(&non_double_value, ne, t0, Operand(at));
- // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+
+ // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
+ // and complete the store.
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS,
receiver_map,
t0,
&slow);
ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
receiver_map,
t0,
&slow);
ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
__ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
__ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+ // Elements are double, but value is an Object that's not a HeapNumber. Make
+ // sure that the receiver is a Array with Object elements and transition array
+ // from double elements to Object elements.
__ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
FAST_ELEMENTS,
receiver_map,
@@ -1471,7 +1472,7 @@
// Must return the modified receiver in v0.
if (!FLAG_trace_elements_transitions) {
Label fail;
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a2);
__ bind(&fail);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 0d11118..5c5c842 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -2448,8 +2448,10 @@
__ lbu(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
__ Ext(scratch, scratch, Map::kElementsKindShift,
Map::kElementsKindBitCount);
- __ Branch(&done, eq, scratch,
- Operand(FAST_ELEMENTS));
+ __ Branch(&fail, lt, scratch,
+ Operand(GetInitialFastElementsKind()));
+ __ Branch(&done, le, scratch,
+ Operand(TERMINAL_FAST_ELEMENTS_KIND));
__ Branch(&fail, lt, scratch,
Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ Branch(&done, le, scratch,
@@ -2546,8 +2548,10 @@
(instr->additional_index() << shift_size)));
}
- __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
- DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
+ }
__ ldc1(result, MemOperand(elements));
}
@@ -2636,7 +2640,10 @@
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3669,7 +3676,10 @@
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3707,20 +3717,21 @@
__ Branch(¬_applicable, ne, scratch, Operand(from_map));
__ li(new_map_reg, Operand(to_map));
- if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ if (IsFastSmiElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) {
__ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
// Write barrier.
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
scratch, kRAHasBeenSaved, kDontSaveFPRegs);
- } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- to_kind == FAST_DOUBLE_ELEMENTS) {
+ } else if (IsFastSmiElementsKind(from_kind) &&
+ IsFastDoubleElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(a2));
ASSERT(new_map_reg.is(a3));
__ mov(fixed_object_reg, object_reg);
CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
RelocInfo::CODE_TARGET, instr);
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ } else if (IsFastDoubleElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(a2));
ASSERT(new_map_reg.is(a3));
@@ -4475,8 +4486,9 @@
// Deopt if the array literal boilerplate ElementsKind is of a type different
// than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(a1, instr->hydrogen()->boilerplate_object());
// Load map into a2.
__ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
@@ -4629,10 +4641,11 @@
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate()->GetElementsKind();
- // Deopt if the literal boilerplate ElementsKind is of a type different than
- // the expected one. The check isn't necessary if the boilerplate has already
- // been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // Deopt if the array literal boilerplate ElementsKind is of a type different
+ // than the expected one. The check isn't necessary if the boilerplate has
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
// Load map into a2.
__ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 1eb3ab7..49a462a 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -2023,8 +2023,9 @@
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
- if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
+ ElementsKind from_kind = instr->original_map()->elements_kind();
+ ElementsKind to_kind = instr->transitioned_map()->elements_kind();
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index c7dc7b7..f68e6ca 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -1224,7 +1224,8 @@
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 2c2445b..6cd5e97 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -3341,33 +3341,39 @@
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
- Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue));
+ Branch(fail, hi, scratch,
+ Operand(Map::kMaximumBitField2FastHoleyElementValue));
}
void MacroAssembler::CheckFastObjectElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
Branch(fail, ls, scratch,
- Operand(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
Branch(fail, hi, scratch,
- Operand(Map::kMaximumBitField2FastElementValue));
+ Operand(Map::kMaximumBitField2FastHoleyElementValue));
}
-void MacroAssembler::CheckFastSmiOnlyElements(Register map,
- Register scratch,
- Label* fail) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+void MacroAssembler::CheckFastSmiElements(Register map,
+ Register scratch,
+ Label* fail) {
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
Branch(fail, hi, scratch,
- Operand(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
}
@@ -3469,22 +3475,17 @@
lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
Operand right = Operand(map);
if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) {
- Map* transitioned_fast_element_map(
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL));
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- Branch(early_success, eq, scratch, right);
- right = Operand(Handle<Map>(transitioned_fast_element_map));
- }
-
- Map* transitioned_double_map(
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL));
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- Branch(early_success, eq, scratch, right);
- right = Operand(Handle<Map>(transitioned_double_map));
+ ElementsKind kind = map->elements_kind();
+ if (IsFastElementsKind(kind)) {
+ bool packed = IsFastPackedElementsKind(kind);
+ Map* current_map = *map;
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
+ if (!current_map) break;
+ Branch(early_success, eq, scratch, right);
+ right = Operand(Handle<Map>(current_map));
+ }
}
}
@@ -4443,27 +4444,37 @@
lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check that the function's map is the same as the expected cached map.
- int expected_index =
- Context::GetContextMapIndexFromElementsKind(expected_kind);
- lw(at, MemOperand(scratch, Context::SlotOffset(expected_index)));
- Branch(no_map_match, ne, map_in_out, Operand(at));
+ lw(scratch,
+ MemOperand(scratch,
+ Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
+ size_t offset = expected_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ Branch(no_map_match, ne, map_in_out, Operand(scratch));
// Use the transitioned cached map.
- int trans_index =
- Context::GetContextMapIndexFromElementsKind(transitioned_kind);
- lw(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index)));
+ offset = transitioned_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ lw(map_in_out, FieldMemOperand(scratch, offset));
}
void MacroAssembler::LoadInitialArrayMap(
- Register function_in, Register scratch, Register map_out) {
+ Register function_in, Register scratch,
+ Register map_out, bool can_have_holes) {
ASSERT(!function_in.is(map_out));
Label done;
lw(map_out, FieldMemOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
- FAST_ELEMENTS,
+ ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ kind,
+ map_out,
+ scratch,
+ &done);
+ } else if (can_have_holes) {
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_HOLEY_SMI_ELEMENTS,
map_out,
scratch,
&done);
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index f57418f..1766866 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -819,7 +819,8 @@
// Load the initial map for new Arrays from a JSFunction.
void LoadInitialArrayMap(Register function_in,
Register scratch,
- Register map_out);
+ Register map_out,
+ bool can_have_holes);
void LoadGlobalFunction(int index, Register function);
@@ -961,9 +962,9 @@
// Check if a map for a JSObject indicates that the object has fast smi only
// elements. Jump to the specified label if it does not.
- void CheckFastSmiOnlyElements(Register map,
- Register scratch,
- Label* fail);
+ void CheckFastSmiElements(Register map,
+ Register scratch,
+ Label* fail);
// Check to see if maybe_number can be stored as a double in
// FastDoubleElements. If it can, store it at the index specified by key in
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 18a5f5f..f8cf970 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1585,16 +1585,29 @@
__ jmp(&fast_object);
// In case of fast smi-only, convert to fast object, otherwise bail out.
__ bind(¬_fast_object);
- __ CheckFastSmiOnlyElements(a3, t3, &call_builtin);
+ __ CheckFastSmiElements(a3, t3, &call_builtin);
// edx: receiver
// r3: map
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ Label try_holey_map;
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
a3,
t3,
+ &try_holey_map);
+ __ mov(a2, receiver);
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
+ __ jmp(&fast_object);
+
+ __ bind(&try_holey_map);
+ __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
+ FAST_HOLEY_ELEMENTS,
+ a3,
+ t3,
&call_builtin);
__ mov(a2, receiver);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
__ bind(&fast_object);
} else {
__ CheckFastObjectElements(a3, a3, &call_builtin);
@@ -3372,9 +3385,12 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
- 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:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3508,8 +3524,11 @@
}
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3869,8 +3888,11 @@
}
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3934,8 +3956,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -4106,8 +4131,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -4286,7 +4314,7 @@
// Check that the key is a smi or a heap number convertible to a smi.
GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
}
@@ -4314,7 +4342,7 @@
__ bind(&finish_store);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ Addu(scratch,
elements_reg,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -4323,7 +4351,7 @@
__ Addu(scratch, scratch, scratch2);
__ sw(value_reg, MemOperand(scratch));
} else {
- ASSERT(elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastObjectElementsKind(elements_kind));
__ Addu(scratch,
elements_reg,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -4332,7 +4360,6 @@
__ Addu(scratch, scratch, scratch2);
__ sw(value_reg, MemOperand(scratch));
__ mov(receiver_reg, value_reg);
- ASSERT(elements_kind == FAST_ELEMENTS);
__ RecordWrite(elements_reg, // Object.
scratch, // Address.
receiver_reg, // Value.
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 89b25bd..11a3df9 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -286,12 +286,11 @@
(map()->inobject_properties() + properties()->length() -
map()->NextFreePropertyIndex()));
}
- ASSERT_EQ((map()->has_fast_elements() ||
- map()->has_fast_smi_only_elements() ||
+ ASSERT_EQ((map()->has_fast_smi_or_object_elements() ||
(elements() == GetHeap()->empty_fixed_array())),
(elements()->map() == GetHeap()->fixed_array_map() ||
elements()->map() == GetHeap()->fixed_cow_array_map()));
- ASSERT(map()->has_fast_elements() == HasFastElements());
+ ASSERT(map()->has_fast_object_elements() == HasFastObjectElements());
}
@@ -517,7 +516,7 @@
VerifyObjectField(JSGlobalProxy::kContextOffset);
// Make sure that this object has no properties, elements.
CHECK_EQ(0, properties()->length());
- CHECK(HasFastElements());
+ CHECK(HasFastObjectElements());
CHECK_EQ(0, FixedArray::cast(elements())->length());
}
@@ -812,6 +811,11 @@
}
// Indexed properties
switch (GetElementsKind()) {
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS: {
info->number_of_objects_with_fast_elements_++;
int holes = 0;
@@ -825,6 +829,14 @@
info->number_of_fast_unused_elements_ += holes;
break;
}
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS: {
info->number_of_objects_with_fast_elements_++;
ExternalPixelArray* e = ExternalPixelArray::cast(elements());
@@ -838,8 +850,7 @@
dict->Capacity() - dict->NumberOfElements();
break;
}
- default:
- UNREACHABLE();
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
break;
}
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 5444438..4afbe3e 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -128,18 +128,6 @@
}
-bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
- ElementsKind to_kind) {
- if (to_kind == FAST_ELEMENTS) {
- return from_kind == FAST_SMI_ONLY_ELEMENTS ||
- from_kind == FAST_DOUBLE_ELEMENTS;
- } else {
- return to_kind == FAST_DOUBLE_ELEMENTS &&
- from_kind == FAST_SMI_ONLY_ELEMENTS;
- }
-}
-
-
bool Object::IsFixedArrayBase() {
return IsFixedArray() || IsFixedDoubleArray();
}
@@ -1244,35 +1232,26 @@
return static_cast<FixedArrayBase*>(array);
}
-void JSObject::ValidateSmiOnlyElements() {
+
+void JSObject::ValidateElements() {
#if DEBUG
- if (map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) {
- Heap* heap = GetHeap();
- // Don't use elements, since integrity checks will fail if there
- // are filler pointers in the array.
- FixedArray* fixed_array =
- reinterpret_cast<FixedArray*>(READ_FIELD(this, kElementsOffset));
- Map* map = fixed_array->map();
- // Arrays that have been shifted in place can't be verified.
- if (map != heap->raw_unchecked_one_pointer_filler_map() &&
- map != heap->raw_unchecked_two_pointer_filler_map() &&
- map != heap->free_space_map()) {
- for (int i = 0; i < fixed_array->length(); i++) {
- Object* current = fixed_array->get(i);
- ASSERT(current->IsSmi() || current->IsTheHole());
- }
- }
+ if (FLAG_enable_slow_asserts) {
+ ElementsAccessor* accessor = GetElementsAccessor();
+ accessor->Validate(this);
}
#endif
}
MaybeObject* JSObject::EnsureCanContainHeapObjectElements() {
-#if DEBUG
- ValidateSmiOnlyElements();
-#endif
- if ((map()->elements_kind() != FAST_ELEMENTS)) {
- return TransitionElementsKind(FAST_ELEMENTS);
+ ValidateElements();
+ ElementsKind elements_kind = map()->elements_kind();
+ if (!IsFastObjectElementsKind(elements_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ return TransitionElementsKind(FAST_HOLEY_ELEMENTS);
+ } else {
+ return TransitionElementsKind(FAST_ELEMENTS);
+ }
}
return this;
}
@@ -1284,20 +1263,34 @@
ElementsKind current_kind = map()->elements_kind();
ElementsKind target_kind = current_kind;
ASSERT(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
- if (current_kind == FAST_ELEMENTS) return this;
-
+ bool is_holey = IsFastHoleyElementsKind(current_kind);
+ if (current_kind == FAST_HOLEY_ELEMENTS) return this;
Heap* heap = GetHeap();
Object* the_hole = heap->the_hole_value();
Object* heap_number_map = heap->heap_number_map();
for (uint32_t i = 0; i < count; ++i) {
Object* current = *objects++;
- if (!current->IsSmi() && current != the_hole) {
+ if (current == the_hole) {
+ is_holey = true;
+ target_kind = GetHoleyElementsKind(target_kind);
+ } else if (!current->IsSmi()) {
if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS &&
- HeapObject::cast(current)->map() == heap_number_map) {
- target_kind = FAST_DOUBLE_ELEMENTS;
+ HeapObject::cast(current)->map() == heap_number_map &&
+ IsFastSmiElementsKind(target_kind)) {
+ if (is_holey) {
+ target_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
+ } else {
+ target_kind = FAST_DOUBLE_ELEMENTS;
+ }
} else {
- target_kind = FAST_ELEMENTS;
- break;
+ if (!current->IsNumber()) {
+ if (is_holey) {
+ target_kind = FAST_HOLEY_ELEMENTS;
+ break;
+ } else {
+ target_kind = FAST_ELEMENTS;
+ }
+ }
}
}
}
@@ -1310,6 +1303,7 @@
MaybeObject* JSObject::EnsureCanContainElements(FixedArrayBase* elements,
+ uint32_t length,
EnsureElementsMode mode) {
if (elements->map() != GetHeap()->fixed_double_array_map()) {
ASSERT(elements->map() == GetHeap()->fixed_array_map() ||
@@ -1318,11 +1312,19 @@
mode = DONT_ALLOW_DOUBLE_ELEMENTS;
}
Object** objects = FixedArray::cast(elements)->GetFirstElementAddress();
- return EnsureCanContainElements(objects, elements->length(), mode);
+ return EnsureCanContainElements(objects, length, mode);
}
ASSERT(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
- if (GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) {
+ if (GetElementsKind() == FAST_HOLEY_SMI_ELEMENTS) {
+ return TransitionElementsKind(FAST_HOLEY_DOUBLE_ELEMENTS);
+ } else if (GetElementsKind() == FAST_SMI_ELEMENTS) {
+ FixedDoubleArray* double_array = FixedDoubleArray::cast(elements);
+ for (uint32_t i = 0; i < length; ++i) {
+ if (double_array->is_the_hole(i)) {
+ return TransitionElementsKind(FAST_HOLEY_DOUBLE_ELEMENTS);
+ }
+ }
return TransitionElementsKind(FAST_DOUBLE_ELEMENTS);
}
@@ -1334,21 +1336,20 @@
ElementsKind to_kind) {
Map* current_map = map();
ElementsKind from_kind = current_map->elements_kind();
-
if (from_kind == to_kind) return current_map;
Context* global_context = isolate->context()->global_context();
- if (current_map == global_context->smi_js_array_map()) {
- if (to_kind == FAST_ELEMENTS) {
- return global_context->object_js_array_map();
- } else {
- if (to_kind == FAST_DOUBLE_ELEMENTS) {
- return global_context->double_js_array_map();
- } else {
- ASSERT(to_kind == DICTIONARY_ELEMENTS);
+ Object* maybe_array_maps = global_context->js_array_maps();
+ if (maybe_array_maps->IsFixedArray()) {
+ FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
+ if (array_maps->get(from_kind) == current_map) {
+ Object* maybe_transitioned_map = array_maps->get(to_kind);
+ if (maybe_transitioned_map->IsMap()) {
+ return Map::cast(maybe_transitioned_map);
}
}
}
+
return GetElementsTransitionMapSlow(to_kind);
}
@@ -1357,9 +1358,6 @@
FixedArrayBase* value,
WriteBarrierMode mode) {
ASSERT(value->HasValidElements());
-#ifdef DEBUG
- ValidateSmiOnlyElements();
-#endif
if (new_map != NULL) {
if (mode == UPDATE_WRITE_BARRIER) {
set_map(new_map);
@@ -1368,8 +1366,7 @@
set_map_no_write_barrier(new_map);
}
}
- ASSERT((map()->has_fast_elements() ||
- map()->has_fast_smi_only_elements() ||
+ ASSERT((map()->has_fast_smi_or_object_elements() ||
(value == GetHeap()->empty_fixed_array())) ==
(value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map()));
@@ -1392,8 +1389,7 @@
void JSObject::initialize_elements() {
- ASSERT(map()->has_fast_elements() ||
- map()->has_fast_smi_only_elements() ||
+ ASSERT(map()->has_fast_smi_or_object_elements() ||
map()->has_fast_double_elements());
ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
@@ -1402,9 +1398,10 @@
MaybeObject* JSObject::ResetElements() {
Object* obj;
- ElementsKind elements_kind = FLAG_smi_only_arrays
- ? FAST_SMI_ONLY_ELEMENTS
- : FAST_ELEMENTS;
+ ElementsKind elements_kind = GetInitialFastElementsKind();
+ if (!FLAG_smi_only_arrays) {
+ elements_kind = FastSmiToObjectElementsKind(elements_kind);
+ }
MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
elements_kind);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -1676,6 +1673,11 @@
}
+bool FixedArray::is_the_hole(int index) {
+ return get(index) == GetHeap()->the_hole_value();
+}
+
+
void FixedArray::set(int index, Smi* value) {
ASSERT(map() != HEAP->fixed_cow_array_map());
ASSERT(index >= 0 && index < this->length());
@@ -2857,15 +2859,15 @@
void Map::set_function_with_prototype(bool value) {
if (value) {
- set_bit_field2(bit_field2() | (1 << kFunctionWithPrototype));
+ set_bit_field3(bit_field3() | (1 << kFunctionWithPrototype));
} else {
- set_bit_field2(bit_field2() & ~(1 << kFunctionWithPrototype));
+ set_bit_field3(bit_field3() & ~(1 << kFunctionWithPrototype));
}
}
bool Map::function_with_prototype() {
- return ((1 << kFunctionWithPrototype) & bit_field2()) != 0;
+ return ((1 << kFunctionWithPrototype) & bit_field3()) != 0;
}
@@ -4008,27 +4010,32 @@
global_context->get(Context::ARRAY_FUNCTION_INDEX);
if (array_function->IsJSFunction() &&
this == JSFunction::cast(array_function)) {
- ASSERT(initial_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
+ // Replace all of the cached initial array maps in the global context with
+ // the appropriate transitioned elements kind maps.
+ Heap* heap = GetHeap();
+ MaybeObject* maybe_maps =
+ heap->AllocateFixedArrayWithHoles(kElementsKindCount);
+ FixedArray* maps;
+ if (!maybe_maps->To(&maps)) return maybe_maps;
- MaybeObject* maybe_map = initial_map->CopyDropTransitions();
- Map* new_double_map = NULL;
- if (!maybe_map->To<Map>(&new_double_map)) return maybe_map;
- new_double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
- maybe_map = initial_map->AddElementsTransition(FAST_DOUBLE_ELEMENTS,
- new_double_map);
- if (maybe_map->IsFailure()) return maybe_map;
-
- maybe_map = new_double_map->CopyDropTransitions();
- Map* new_object_map = NULL;
- if (!maybe_map->To<Map>(&new_object_map)) return maybe_map;
- new_object_map->set_elements_kind(FAST_ELEMENTS);
- maybe_map = new_double_map->AddElementsTransition(FAST_ELEMENTS,
- new_object_map);
- if (maybe_map->IsFailure()) return maybe_map;
-
- global_context->set_smi_js_array_map(initial_map);
- global_context->set_double_js_array_map(new_double_map);
- global_context->set_object_js_array_map(new_object_map);
+ Map* current_map = initial_map;
+ ElementsKind kind = current_map->elements_kind();
+ ASSERT(kind == GetInitialFastElementsKind());
+ maps->set(kind, current_map);
+ for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
+ i < kFastElementsKindCount; ++i) {
+ ElementsKind transitioned_kind = GetFastElementsKindFromSequenceIndex(i);
+ MaybeObject* maybe_new_map = current_map->CopyDropTransitions();
+ Map* new_map = NULL;
+ if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
+ new_map->set_elements_kind(transitioned_kind);
+ maybe_new_map = current_map->AddElementsTransition(transitioned_kind,
+ new_map);
+ if (maybe_new_map->IsFailure()) return maybe_new_map;
+ maps->set(transitioned_kind, new_map);
+ current_map = new_map;
+ }
+ global_context->set_js_array_maps(maps);
}
set_initial_map(initial_map);
return this;
@@ -4364,18 +4371,18 @@
FixedArrayBase* fixed_array =
reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
Map* map = fixed_array->map();
- ASSERT(((kind == FAST_ELEMENTS || kind == FAST_SMI_ONLY_ELEMENTS) &&
- (map == GetHeap()->fixed_array_map() ||
- map == GetHeap()->fixed_cow_array_map())) ||
- (kind == FAST_DOUBLE_ELEMENTS &&
- (fixed_array->IsFixedDoubleArray() ||
- fixed_array == GetHeap()->empty_fixed_array())) ||
- (kind == DICTIONARY_ELEMENTS &&
+ ASSERT((IsFastSmiOrObjectElementsKind(kind) &&
+ (map == GetHeap()->fixed_array_map() ||
+ map == GetHeap()->fixed_cow_array_map())) ||
+ (IsFastDoubleElementsKind(kind) &&
+ (fixed_array->IsFixedDoubleArray() ||
+ fixed_array == GetHeap()->empty_fixed_array())) ||
+ (kind == DICTIONARY_ELEMENTS &&
fixed_array->IsFixedArray() &&
- fixed_array->IsDictionary()) ||
- (kind > DICTIONARY_ELEMENTS));
- ASSERT((kind != NON_STRICT_ARGUMENTS_ELEMENTS) ||
- (elements()->IsFixedArray() && elements()->length() >= 2));
+ fixed_array->IsDictionary()) ||
+ (kind > DICTIONARY_ELEMENTS));
+ ASSERT((kind != NON_STRICT_ARGUMENTS_ELEMENTS) ||
+ (elements()->IsFixedArray() && elements()->length() >= 2));
#endif
return kind;
}
@@ -4386,25 +4393,28 @@
}
-bool JSObject::HasFastElements() {
- return GetElementsKind() == FAST_ELEMENTS;
+bool JSObject::HasFastObjectElements() {
+ return IsFastObjectElementsKind(GetElementsKind());
}
-bool JSObject::HasFastSmiOnlyElements() {
- return GetElementsKind() == FAST_SMI_ONLY_ELEMENTS;
+bool JSObject::HasFastSmiElements() {
+ return IsFastSmiElementsKind(GetElementsKind());
}
-bool JSObject::HasFastTypeElements() {
- ElementsKind elements_kind = GetElementsKind();
- return elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_ELEMENTS;
+bool JSObject::HasFastSmiOrObjectElements() {
+ return IsFastSmiOrObjectElementsKind(GetElementsKind());
}
bool JSObject::HasFastDoubleElements() {
- return GetElementsKind() == FAST_DOUBLE_ELEMENTS;
+ return IsFastDoubleElementsKind(GetElementsKind());
+}
+
+
+bool JSObject::HasFastHoleyElements() {
+ return IsFastHoleyElementsKind(GetElementsKind());
}
@@ -4461,7 +4471,7 @@
MaybeObject* JSObject::EnsureWritableFastElements() {
- ASSERT(HasFastTypeElements());
+ ASSERT(HasFastSmiOrObjectElements());
FixedArray* elems = FixedArray::cast(elements());
Isolate* isolate = GetIsolate();
if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
@@ -4819,7 +4829,7 @@
void JSArray::EnsureSize(int required_size) {
- ASSERT(HasFastTypeElements());
+ ASSERT(HasFastSmiOrObjectElements());
FixedArray* elts = FixedArray::cast(elements());
const int kArraySizeThatFitsComfortablyInNewSpace = 128;
if (elts->length() < required_size) {
@@ -4851,13 +4861,13 @@
MaybeObject* JSArray::SetContent(FixedArrayBase* storage) {
MaybeObject* maybe_result = EnsureCanContainElements(
- storage, ALLOW_COPIED_DOUBLE_ELEMENTS);
+ storage, storage->length(), ALLOW_COPIED_DOUBLE_ELEMENTS);
if (maybe_result->IsFailure()) return maybe_result;
ASSERT((storage->map() == GetHeap()->fixed_double_array_map() &&
- GetElementsKind() == FAST_DOUBLE_ELEMENTS) ||
+ IsFastDoubleElementsKind(GetElementsKind())) ||
((storage->map() != GetHeap()->fixed_double_array_map()) &&
- ((GetElementsKind() == FAST_ELEMENTS) ||
- (GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
+ (IsFastObjectElementsKind(GetElementsKind()) ||
+ (IsFastSmiElementsKind(GetElementsKind()) &&
FixedArray::cast(storage)->ContainsOnlySmisOrHoles()))));
set_elements(storage);
set_length(Smi::FromInt(storage->length()));
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index febdaab..3aea5f0 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -318,7 +318,9 @@
// Don't call GetElementsKind, its validation code can cause the printer to
// fail when debugging.
switch (map()->elements_kind()) {
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS: {
// Print in array notation for non-sparse arrays.
FixedArray* p = FixedArray::cast(elements());
@@ -329,6 +331,7 @@
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// Print in array notation for non-sparse arrays.
if (elements()->length() > 0) {
diff --git a/src/objects.cc b/src/objects.cc
index cb87c71..ba460cf 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -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 @@
// 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 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 @@
Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
- ElementsKind elms_kind = elements_kind();
- if (elms_kind == FAST_DOUBLE_ELEMENTS) {
- bool dummy = true;
- Handle<Map> fast_map =
- MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
- if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
- return fast_map;
+ 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> 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;
+ }
+ current_map = maybe_transitioned_map;
}
- return Handle<Map>::null();
}
- 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;
- }
- 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 @@
}
-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,
- safe_to_add_transition);
- if (double_map == NULL) return double_map;
- return double_map->LookupElementsTransitionMap(FAST_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 (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 @@
}
-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) {
- 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.
- ASSERT(safe_to_add);
+ 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* 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 @@
!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 @@
// 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 @@
}
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
}
-// 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 @@
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:
@@ -4417,7 +4439,12 @@
LookupResult result(GetHeap()->isolate());
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty() && result.type() == CALLBACKS) {
- ASSERT(!result.IsDontDelete());
+ // Note that the result can actually have IsDontDelete() == true when we
+ // e.g. have to fall back to the slow case while adding a setter after
+ // successfully reusing a map transition for a getter. Nevertheless, this is
+ // OK, because the assertion only holds for the whole addition of both
+ // accessors, not for the addition of each part. See first comment in
+ // DefinePropertyAccessor below.
Object* obj = result.GetCallbackObject();
if (obj->IsAccessorPair()) {
return AccessorPair::cast(obj)->CopyWithoutTransitions();
@@ -4431,6 +4458,28 @@
Object* getter,
Object* setter,
PropertyAttributes attributes) {
+ // We could assert that the property is configurable here, but we would need
+ // to do a lookup, which seems to be a bit of overkill.
+ Heap* heap = GetHeap();
+ bool only_attribute_changes = getter->IsNull() && setter->IsNull();
+ if (HasFastProperties() && !only_attribute_changes) {
+ MaybeObject* getterOk = heap->undefined_value();
+ if (!getter->IsNull()) {
+ getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
+ if (getterOk->IsFailure()) return getterOk;
+ }
+
+ MaybeObject* setterOk = heap->undefined_value();
+ if (getterOk != heap->null_value() && !setter->IsNull()) {
+ setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
+ if (setterOk->IsFailure()) return setterOk;
+ }
+
+ if (getterOk != heap->null_value() && setterOk != heap->null_value()) {
+ return heap->undefined_value();
+ }
+ }
+
AccessorPair* accessors;
{ MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
if (!maybe_accessors->To(&accessors)) return maybe_accessors;
@@ -4445,7 +4494,7 @@
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
@@ -4580,6 +4629,159 @@
}
+static MaybeObject* CreateFreshAccessor(JSObject* obj,
+ String* name,
+ AccessorComponent component,
+ Object* accessor,
+ PropertyAttributes attributes) {
+ // step 1: create a new getter/setter pair with only the accessor in it
+ Heap* heap = obj->GetHeap();
+ AccessorPair* accessors2;
+ { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair();
+ if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2;
+ }
+ accessors2->set(component, accessor);
+
+ // step 2: create a copy of the descriptors, incl. the new getter/setter pair
+ Map* map1 = obj->map();
+ CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
+ DescriptorArray* descriptors2;
+ { MaybeObject* maybe_descriptors2 =
+ map1->instance_descriptors()->CopyInsert(&callbacks_descr2,
+ REMOVE_TRANSITIONS);
+ if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2;
+ }
+
+ // step 3: create a new map with the new descriptors
+ Map* map2;
+ { MaybeObject* maybe_map2 = map1->CopyDropDescriptors();
+ if (!maybe_map2->To(&map2)) return maybe_map2;
+ }
+ map2->set_instance_descriptors(descriptors2);
+
+ // step 4: create a new getter/setter pair with a transition to the new map
+ AccessorPair* accessors1;
+ { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair();
+ if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1;
+ }
+ accessors1->set(component, map2);
+
+ // step 5: create a copy of the descriptors, incl. the new getter/setter pair
+ // with the transition
+ CallbacksDescriptor callbacks_descr1(name, accessors1, attributes);
+ DescriptorArray* descriptors1;
+ { MaybeObject* maybe_descriptors1 =
+ map1->instance_descriptors()->CopyInsert(&callbacks_descr1,
+ KEEP_TRANSITIONS);
+ if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1;
+ }
+
+ // step 6: everything went well so far, so we make our changes visible
+ obj->set_map(map2);
+ map1->set_instance_descriptors(descriptors1);
+ map2->SetBackPointer(map1);
+ return obj;
+}
+
+
+static bool TransitionToSameAccessor(Object* map,
+ String* name,
+ AccessorComponent component,
+ Object* accessor,
+ PropertyAttributes attributes ) {
+ DescriptorArray* descs = Map::cast(map)->instance_descriptors();
+ int number = descs->SearchWithCache(name);
+ ASSERT(number != DescriptorArray::kNotFound);
+ Object* target_accessor =
+ AccessorPair::cast(descs->GetCallbacksObject(number))->get(component);
+ PropertyAttributes target_attributes = descs->GetDetails(number).attributes();
+ return target_accessor == accessor && target_attributes == attributes;
+}
+
+
+static MaybeObject* NewCallbackTransition(JSObject* obj,
+ String* name,
+ AccessorComponent component,
+ Object* accessor,
+ PropertyAttributes attributes,
+ AccessorPair* accessors2) {
+ // step 1: copy the old getter/setter pair and set the new accessor
+ AccessorPair* accessors3;
+ { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions();
+ if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3;
+ }
+ accessors3->set(component, accessor);
+
+ // step 2: create a copy of the descriptors, incl. the new getter/setter pair
+ Map* map2 = obj->map();
+ CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
+ DescriptorArray* descriptors3;
+ { MaybeObject* maybe_descriptors3 =
+ map2->instance_descriptors()->CopyInsert(&callbacks_descr3,
+ REMOVE_TRANSITIONS);
+ if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3;
+ }
+
+ // step 3: create a new map with the new descriptors
+ Map* map3;
+ { MaybeObject* maybe_map3 = map2->CopyDropDescriptors();
+ if (!maybe_map3->To(&map3)) return maybe_map3;
+ }
+ map3->set_instance_descriptors(descriptors3);
+
+ // step 4: everything went well so far, so we make our changes visible
+ obj->set_map(map3);
+ accessors2->set(component, map3);
+ map3->SetBackPointer(map2);
+ return obj;
+}
+
+
+MaybeObject* JSObject::DefineFastAccessor(String* name,
+ AccessorComponent component,
+ Object* accessor,
+ PropertyAttributes attributes) {
+ ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
+ LookupResult result(GetIsolate());
+ LocalLookup(name, &result);
+
+ // If we have a new property, create a fresh accessor plus a transition to it.
+ if (!result.IsFound()) {
+ return CreateFreshAccessor(this, name, component, accessor, attributes);
+ }
+
+ // 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.GetCallbackObject();
+ if (!callback_value->IsAccessorPair()) return GetHeap()->null_value();
+ AccessorPair* accessors = AccessorPair::cast(callback_value);
+
+ // Follow a callback transition, if there is a fitting one.
+ Object* entry = accessors->get(component);
+ if (entry->IsMap() &&
+ TransitionToSameAccessor(entry, name, component, accessor, attributes)) {
+ set_map(Map::cast(entry));
+ return this;
+ }
+
+ // When we re-add the same accessor again, there is nothing to do.
+ if (entry == accessor && result.GetAttributes() == attributes) return this;
+
+ // Only the other accessor has been set so far, create a new transition.
+ if (entry->IsTheHole()) {
+ return NewCallbackTransition(this,
+ name,
+ component,
+ accessor,
+ attributes,
+ accessors);
+ }
+
+ // Nothing from the above worked, so we have to fall back to the slow case.
+ return GetHeap()->null_value();
+}
+
+
MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Isolate* isolate = GetIsolate();
String* name = String::cast(info->name());
@@ -4616,9 +4818,12 @@
// 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:
@@ -5735,21 +5940,15 @@
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) {
- 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 {
+ 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;
}
@@ -5947,8 +6146,8 @@
Object* AccessorPair::GetComponent(AccessorComponent component) {
- Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
- return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
+ Object* accessor = get(component);
+ return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
}
@@ -8407,7 +8606,7 @@
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());
@@ -8418,34 +8617,40 @@
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;
- }
-
- FixedArrayBase* old_elements = elements();
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();
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);
@@ -8457,11 +8662,9 @@
GetElementsKind(), new_elements);
}
- // Update the length if necessary.
if (IsJSArray()) {
JSArray::cast(this)->set_length(Smi::FromInt(length));
}
-
return new_elements;
}
@@ -8479,20 +8682,28 @@
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);
@@ -8501,7 +8712,7 @@
if (FLAG_trace_elements_transitions) {
PrintElementsTransition(stdout, elements_kind, old_elements,
- FAST_DOUBLE_ELEMENTS, elems);
+ GetElementsKind(), elems);
}
if (IsJSArray()) {
@@ -8781,8 +8992,10 @@
}
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()) :
@@ -8793,7 +9006,8 @@
}
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()) :
@@ -9077,7 +9291,7 @@
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
- ASSERT(HasFastTypeElements() ||
+ ASSERT(HasFastSmiOrObjectElements() ||
HasFastArgumentsElements());
FixedArray* backing_store = FixedArray::cast(elements());
@@ -9103,13 +9317,29 @@
// 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) {
@@ -9129,42 +9359,44 @@
}
}
// 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);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- }
+ 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);
@@ -9288,20 +9520,21 @@
} 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) {
@@ -9340,27 +9573,40 @@
// If the value object is not a heap number, switch to fast elements and try
// again.
bool value_is_smi = value->IsSmi();
+ 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()) {
- Object* obj;
- uint32_t length = elms_length;
- if (IsJSArray()) {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&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);
+ 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());
@@ -9382,13 +9628,11 @@
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;
}
}
@@ -9532,10 +9776,13 @@
(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());
@@ -9626,11 +9873,19 @@
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;
@@ -9657,18 +9912,21 @@
}
}
- 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;
}
@@ -9682,10 +9940,14 @@
// 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);
}
@@ -9776,8 +10038,10 @@
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) {
@@ -9791,7 +10055,8 @@
*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++) {
@@ -10061,16 +10326,19 @@
if (this->IsStringObjectWithCharacterAt(index)) return true;
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
- uint32_t length = IsJSArray() ?
+ 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()) :
static_cast<uint32_t>(FixedArray::cast(elements())->length());
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()) :
@@ -10270,7 +10538,7 @@
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()) :
@@ -10286,8 +10554,10 @@
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();
@@ -10302,7 +10572,8 @@
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();
@@ -11235,10 +11506,9 @@
// Convert to fast elements.
Object* obj;
- { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
- FAST_ELEMENTS);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ 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;
@@ -11249,9 +11519,9 @@
}
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());
@@ -11261,7 +11531,7 @@
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.
diff --git a/src/objects.h b/src/objects.h
index 421a531..e9dfe6c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -30,6 +30,7 @@
#include "allocation.h"
#include "builtins.h"
+#include "elements-kind.h"
#include "list.h"
#include "property-details.h"
#include "smart-array-pointer.h"
@@ -131,40 +132,6 @@
namespace v8 {
namespace internal {
-enum ElementsKind {
- // The "fast" kind for elements that only contain SMI values. Must be first
- // to make it possible to efficiently check maps for this kind.
- FAST_SMI_ONLY_ELEMENTS,
-
- // The "fast" kind for tagged values. Must be second to make it possible to
- // efficiently check maps for this and the FAST_SMI_ONLY_ELEMENTS kind
- // together at once.
- FAST_ELEMENTS,
-
- // The "fast" kind for unwrapped, non-tagged double values.
- FAST_DOUBLE_ELEMENTS,
-
- // The "slow" kind.
- DICTIONARY_ELEMENTS,
- NON_STRICT_ARGUMENTS_ELEMENTS,
- // The "fast" kind for external arrays
- EXTERNAL_BYTE_ELEMENTS,
- EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
- EXTERNAL_SHORT_ELEMENTS,
- EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
- EXTERNAL_INT_ELEMENTS,
- EXTERNAL_UNSIGNED_INT_ELEMENTS,
- EXTERNAL_FLOAT_ELEMENTS,
- EXTERNAL_DOUBLE_ELEMENTS,
- EXTERNAL_PIXEL_ELEMENTS,
-
- // Derived constants from ElementsKind
- FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
- LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
- FIRST_ELEMENTS_KIND = FAST_SMI_ONLY_ELEMENTS,
- LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
-};
-
enum CompareMapMode {
REQUIRE_EXACT_MAP,
ALLOW_ELEMENT_TRANSITION_MAPS
@@ -175,13 +142,6 @@
ALLOW_JSARRAY_GROWTH
};
-const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
-
-void PrintElementsKind(FILE* out, ElementsKind kind);
-
-inline bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
- ElementsKind to_kind);
-
// Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
@@ -704,12 +664,13 @@
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
+class AccessorPair;
class DictionaryElementsAccessor;
class ElementsAccessor;
+class Failure;
class FixedArrayBase;
class ObjectVisitor;
class StringStream;
-class Failure;
struct ValueInfo : public Malloced {
ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
@@ -1509,13 +1470,19 @@
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
inline ElementsAccessor* GetElementsAccessor();
- inline bool HasFastSmiOnlyElements();
- inline bool HasFastElements();
- // Returns if an object has either FAST_ELEMENT or FAST_SMI_ONLY_ELEMENT
- // elements. TODO(danno): Rename HasFastTypeElements to HasFastElements() and
- // HasFastElements to HasFastObjectElements.
- inline bool HasFastTypeElements();
+ // Returns true if an object has elements of FAST_SMI_ELEMENTS ElementsKind.
+ inline bool HasFastSmiElements();
+ // Returns true if an object has elements of FAST_ELEMENTS ElementsKind.
+ inline bool HasFastObjectElements();
+ // Returns true if an object has elements of FAST_ELEMENTS or
+ // FAST_SMI_ONLY_ELEMENTS.
+ inline bool HasFastSmiOrObjectElements();
+ // Returns true if an object has elements of FAST_DOUBLE_ELEMENTS
+ // ElementsKind.
inline bool HasFastDoubleElements();
+ // Returns true if an object has elements of FAST_HOLEY_*_ELEMENTS
+ // ElementsKind.
+ inline bool HasFastHoleyElements();
inline bool HasNonStrictArgumentsElements();
inline bool HasDictionaryElements();
inline bool HasExternalPixelElements();
@@ -1642,6 +1609,14 @@
Object* getter,
Object* setter,
PropertyAttributes attributes);
+ // Try to define a single accessor paying attention to map transitions.
+ // Returns a JavaScript null if this was not possible and we have to use the
+ // slow case. Note that we can fail due to allocations, too.
+ MUST_USE_RESULT MaybeObject* DefineFastAccessor(
+ String* name,
+ AccessorComponent component,
+ Object* accessor,
+ PropertyAttributes attributes);
Object* LookupAccessor(String* name, AccessorComponent component);
MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info);
@@ -1710,7 +1685,7 @@
static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
- inline void ValidateSmiOnlyElements();
+ inline void ValidateElements();
// Makes sure that this object can contain HeapObject as elements.
MUST_USE_RESULT inline MaybeObject* EnsureCanContainHeapObjectElements();
@@ -1722,6 +1697,7 @@
EnsureElementsMode mode);
MUST_USE_RESULT inline MaybeObject* EnsureCanContainElements(
FixedArrayBase* elements,
+ uint32_t length,
EnsureElementsMode mode);
MUST_USE_RESULT MaybeObject* EnsureCanContainElements(
Arguments* arguments,
@@ -1820,10 +1796,10 @@
MUST_USE_RESULT MaybeObject* GetElementWithInterceptor(Object* receiver,
uint32_t index);
- enum SetFastElementsCapacityMode {
- kAllowSmiOnlyElements,
- kForceSmiOnlyElements,
- kDontAllowSmiOnlyElements
+ enum SetFastElementsCapacitySmiMode {
+ kAllowSmiElements,
+ kForceSmiElements,
+ kDontAllowSmiElements
};
// Replace the elements' backing store with fast elements of the given
@@ -1832,7 +1808,7 @@
MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(
int capacity,
int length,
- SetFastElementsCapacityMode set_capacity_mode);
+ SetFastElementsCapacitySmiMode smi_mode);
MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
int capacity,
int length);
@@ -4638,17 +4614,21 @@
}
// Tells whether the instance has fast elements that are only Smis.
- inline bool has_fast_smi_only_elements() {
- return elements_kind() == FAST_SMI_ONLY_ELEMENTS;
+ inline bool has_fast_smi_elements() {
+ return IsFastSmiElementsKind(elements_kind());
}
// Tells whether the instance has fast elements.
- inline bool has_fast_elements() {
- return elements_kind() == FAST_ELEMENTS;
+ inline bool has_fast_object_elements() {
+ return IsFastObjectElementsKind(elements_kind());
+ }
+
+ inline bool has_fast_smi_or_object_elements() {
+ return IsFastSmiOrObjectElementsKind(elements_kind());
}
inline bool has_fast_double_elements() {
- return elements_kind() == FAST_DOUBLE_ELEMENTS;
+ return IsFastDoubleElementsKind(elements_kind());
}
inline bool has_non_strict_arguments_elements() {
@@ -4944,25 +4924,31 @@
// Bit positions for bit field 2
static const int kIsExtensible = 0;
- static const int kFunctionWithPrototype = 1;
- static const int kStringWrapperSafeForDefaultValueOf = 2;
- static const int kAttachedToSharedFunctionInfo = 3;
+ static const int kStringWrapperSafeForDefaultValueOf = 1;
+ static const int kAttachedToSharedFunctionInfo = 2;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
// storing ElementKind.
- static const int kElementsKindShift = 4;
- static const int kElementsKindBitCount = 4;
+ static const int kElementsKindShift = 3;
+ static const int kElementsKindBitCount = 5;
// Derived values from bit field 2
static const int kElementsKindMask = (-1 << kElementsKindShift) &
((1 << (kElementsKindShift + kElementsKindBitCount)) - 1);
static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>(
(FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
- static const int8_t kMaximumBitField2FastSmiOnlyElementValue =
- static_cast<int8_t>((FAST_SMI_ONLY_ELEMENTS + 1) <<
+ static const int8_t kMaximumBitField2FastSmiElementValue =
+ static_cast<int8_t>((FAST_SMI_ELEMENTS + 1) <<
+ Map::kElementsKindShift) - 1;
+ static const int8_t kMaximumBitField2FastHoleyElementValue =
+ static_cast<int8_t>((FAST_HOLEY_ELEMENTS + 1) <<
+ Map::kElementsKindShift) - 1;
+ static const int8_t kMaximumBitField2FastHoleySmiElementValue =
+ static_cast<int8_t>((FAST_HOLEY_SMI_ELEMENTS + 1) <<
Map::kElementsKindShift) - 1;
// Bit positions for bit field 3
static const int kIsShared = 0;
+ static const int kFunctionWithPrototype = 1;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -8123,6 +8109,18 @@
MUST_USE_RESULT MaybeObject* CopyWithoutTransitions();
+ Object* get(AccessorComponent component) {
+ return component == ACCESSOR_GETTER ? getter() : setter();
+ }
+
+ void set(AccessorComponent component, Object* value) {
+ if (component == ACCESSOR_GETTER) {
+ set_getter(value);
+ } else {
+ set_setter(value);
+ }
+ }
+
// Note: Returns undefined instead in case of a hole.
Object* GetComponent(AccessorComponent component);
diff --git a/src/parser.cc b/src/parser.cc
index 8620519..3a7a973 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3767,10 +3767,12 @@
Handle<FixedArray> object_literals =
isolate()->factory()->NewFixedArray(values->length(), TENURED);
Handle<FixedDoubleArray> double_literals;
- ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
+ ElementsKind elements_kind = FAST_SMI_ELEMENTS;
bool has_only_undefined_values = true;
+ bool has_hole_values = false;
// Fill in the literals.
+ Heap* heap = isolate()->heap();
bool is_simple = true;
int depth = 1;
for (int i = 0, n = values->length(); i < n; i++) {
@@ -3779,12 +3781,18 @@
depth = m_literal->depth() + 1;
}
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
- if (boilerplate_value->IsUndefined()) {
+ if (boilerplate_value->IsTheHole()) {
+ has_hole_values = true;
object_literals->set_the_hole(i);
if (elements_kind == FAST_DOUBLE_ELEMENTS) {
double_literals->set_the_hole(i);
}
+ } else if (boilerplate_value->IsUndefined()) {
is_simple = false;
+ object_literals->set(i, Smi::FromInt(0));
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ double_literals->set(i, 0);
+ }
} else {
// Examine each literal element, and adjust the ElementsKind if the
// literal element is not of a type that can be stored in the current
@@ -3794,7 +3802,7 @@
// ultimately end up in FAST_ELEMENTS.
has_only_undefined_values = false;
object_literals->set(i, *boilerplate_value);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (elements_kind == FAST_SMI_ELEMENTS) {
// Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
// FAST_ELEMENTS is required.
if (!boilerplate_value->IsSmi()) {
@@ -3842,7 +3850,7 @@
// elements array to a copy-on-write array.
if (is_simple && depth == 1 && values->length() > 0 &&
elements_kind != FAST_DOUBLE_ELEMENTS) {
- object_literals->set_map(isolate()->heap()->fixed_cow_array_map());
+ object_literals->set_map(heap->fixed_cow_array_map());
}
Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
@@ -3854,6 +3862,10 @@
Handle<FixedArray> literals =
isolate()->factory()->NewFixedArray(2, TENURED);
+ if (has_hole_values || !FLAG_packed_arrays) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ }
+
literals->set(0, Smi::FromInt(elements_kind));
literals->set(1, *element_values);
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index b670d4e..0fe7499 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -2207,7 +2207,7 @@
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
- if (js_obj->HasFastElements()) {
+ if (js_obj->HasFastObjectElements()) {
FixedArray* elements = FixedArray::cast(js_obj->elements());
int length = js_obj->IsJSArray() ?
Smi::cast(JSArray::cast(js_obj)->length())->value() :
diff --git a/src/regexp.js b/src/regexp.js
index 44f8dd1..3809039 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -427,6 +427,7 @@
LAST_INPUT(lastMatchInfo) = ToString(string);
};
+ %OptimizeObjectForAddingMultipleProperties($RegExp, 22);
%DefineOrRedefineAccessorProperty($RegExp, 'input', RegExpGetInput,
RegExpSetInput, DONT_DELETE);
%DefineOrRedefineAccessorProperty($RegExp, '$_', RegExpGetInput,
@@ -481,6 +482,7 @@
RegExpMakeCaptureGetter(i), NoOpSetter,
DONT_DELETE);
}
+ %ToFastProperties($RegExp);
}
SetUpRegExp();
diff --git a/src/runtime.cc b/src/runtime.cc
index 4deaaba..d18a158 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -208,8 +208,10 @@
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->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: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
@@ -223,7 +225,7 @@
Object* value = elements->get(i);
ASSERT(value->IsSmi() ||
value->IsTheHole() ||
- (copy->GetElementsKind() == FAST_ELEMENTS));
+ (IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
{ MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
@@ -268,6 +270,7 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
// No contained objects, nothing to do.
break;
}
@@ -452,7 +455,7 @@
}
-static const int kSmiOnlyLiteralMinimumLength = 1024;
+static const int kSmiLiteralMinimumLength = 1024;
Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
@@ -470,23 +473,22 @@
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(elements->get(1)));
+ ASSERT(IsFastElementsKind(constant_elements_kind));
Context* global_context = isolate->context()->global_context();
- if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
- object->set_map(Map::cast(global_context->smi_js_array_map()));
- } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
- object->set_map(Map::cast(global_context->double_js_array_map()));
- } else {
- object->set_map(Map::cast(global_context->object_js_array_map()));
- }
+ Object* maybe_maps_array = global_context->js_array_maps();
+ ASSERT(!maybe_maps_array->IsUndefined());
+ Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
+ constant_elements_kind);
+ ASSERT(maybe_map->IsMap());
+ object->set_map(Map::cast(maybe_map));
Handle<FixedArrayBase> copied_elements_values;
- if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastDoubleElementsKind(constant_elements_kind)) {
ASSERT(FLAG_smi_only_arrays);
copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
Handle<FixedDoubleArray>::cast(constant_elements_values));
} else {
- ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- constant_elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
const bool is_cow =
(constant_elements_values->map() ==
isolate->heap()->fixed_cow_array_map());
@@ -522,15 +524,22 @@
object->set_elements(*copied_elements_values);
object->set_length(Smi::FromInt(copied_elements_values->length()));
- // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
+ // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
// on or the object is larger than the threshold.
if (!FLAG_smi_only_arrays &&
- constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
- if (object->GetElementsKind() != FAST_ELEMENTS) {
- CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
+ constant_elements_values->length() < kSmiLiteralMinimumLength) {
+ ElementsKind elements_kind = object->GetElementsKind();
+ if (!IsFastObjectElementsKind(elements_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
+ isolate)->IsFailure());
+ } else {
+ CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
+ }
}
}
+ object->ValidateElements();
return object;
}
@@ -1730,7 +1739,7 @@
// length of a string, i.e. it is always a Smi. We check anyway for security.
CONVERT_SMI_ARG_CHECKED(index, 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
- RUNTIME_ASSERT(last_match_info->HasFastElements());
+ RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
RUNTIME_ASSERT(index >= 0);
RUNTIME_ASSERT(index <= subject->length());
isolate->counters()->regexp_entry_runtime()->Increment();
@@ -3104,7 +3113,7 @@
const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
bool matched = true;
do {
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
// Increase the capacity of the builder before entering local handle-scope,
// so its internal buffer can safely allocate a new handle if it grows.
builder.EnsureCapacity(parts_added_per_loop);
@@ -3201,7 +3210,7 @@
if (match.is_null()) return Failure::Exception();
if (match->IsNull()) return *subject_handle;
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
int start, end;
{
@@ -3275,7 +3284,7 @@
if (match.is_null()) return Failure::Exception();
if (match->IsNull()) break;
- ASSERT(last_match_info_handle->HasFastElements());
+ ASSERT(last_match_info_handle->HasFastObjectElements());
HandleScope loop_scope(isolate);
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
@@ -3345,7 +3354,7 @@
CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
- ASSERT(last_match_info->HasFastElements());
+ ASSERT(last_match_info->HasFastObjectElements());
if (replacement->length() == 0) {
if (subject->HasOnlyAsciiChars()) {
@@ -4034,10 +4043,10 @@
CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
- ASSERT(last_match_info->HasFastElements());
+ ASSERT(last_match_info->HasFastObjectElements());
ASSERT(regexp->GetFlags().is_global());
Handle<FixedArray> result_elements;
- if (result_array->HasFastElements()) {
+ if (result_array->HasFastObjectElements()) {
result_elements =
Handle<FixedArray>(FixedArray::cast(result_array->elements()));
}
@@ -4339,17 +4348,22 @@
// JSObject without a string key. If the key is a Smi, check for a
// definite out-of-bounds access to elements, which is a strong indicator
// that subsequent accesses will also call the runtime. Proactively
- // transition elements to FAST_ELEMENTS to avoid excessive boxing of
+ // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
// doubles for those future calls in the case that the elements would
// become FAST_DOUBLE_ELEMENTS.
Handle<JSObject> js_object(args.at<JSObject>(0));
ElementsKind elements_kind = js_object->GetElementsKind();
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastElementsKind(elements_kind) &&
+ !IsFastObjectElementsKind(elements_kind)) {
FixedArrayBase* elements = js_object->elements();
if (args.at<Smi>(1)->value() >= elements->length()) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = FAST_HOLEY_ELEMENTS;
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
MaybeObject* maybe_object = TransitionElements(js_object,
- FAST_ELEMENTS,
+ elements_kind,
isolate);
if (maybe_object->IsFailure()) return maybe_object;
}
@@ -4519,8 +4533,10 @@
return *value;
}
+ js_object->ValidateElements();
Handle<Object> result = JSObject::SetElement(
js_object, index, value, attr, strict_mode, set_mode);
+ js_object->ValidateElements();
if (result.is_null()) return Failure::Exception();
return *value;
}
@@ -4678,7 +4694,15 @@
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
- return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
+ if (object->IsJSObject()) {
+ Handle<JSObject> js_object(Handle<JSObject>::cast(object));
+ ElementsKind new_kind = js_object->HasFastHoleyElements()
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+ return TransitionElements(object, new_kind, isolate);
+ } else {
+ return *object;
+ }
}
@@ -4686,7 +4710,15 @@
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
- return TransitionElements(object, FAST_ELEMENTS, isolate);
+ if (object->IsJSObject()) {
+ Handle<JSObject> js_object(Handle<JSObject>::cast(object));
+ ElementsKind new_kind = js_object->HasFastHoleyElements()
+ ? FAST_HOLEY_ELEMENTS
+ : FAST_ELEMENTS;
+ return TransitionElements(object, new_kind, isolate);
+ } else {
+ return *object;
+ }
}
@@ -4717,32 +4749,38 @@
HandleScope scope;
Object* raw_boilerplate_object = literals->get(literal_index);
- Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
-#if DEBUG
+ Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
ElementsKind elements_kind = object->GetElementsKind();
-#endif
- ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
+ ASSERT(IsFastElementsKind(elements_kind));
// Smis should never trigger transitions.
ASSERT(!value->IsSmi());
if (value->IsNumber()) {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
- JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
- if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
- FAST_DOUBLE_ELEMENTS)) {
- JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
+ ASSERT(IsFastSmiElementsKind(elements_kind));
+ ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_DOUBLE_ELEMENTS
+ : FAST_DOUBLE_ELEMENTS;
+ if (IsMoreGeneralElementsKindTransition(
+ boilerplate_object->GetElementsKind(),
+ transitioned_kind)) {
+ JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
}
- ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ JSObject::TransitionElementsKind(object, transitioned_kind);
+ ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
HeapNumber* number = HeapNumber::cast(*value);
double_array->set(store_index, number->Number());
} else {
- ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
- elements_kind == FAST_DOUBLE_ELEMENTS);
- JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
- if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
- FAST_ELEMENTS)) {
- JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
+ ASSERT(IsFastSmiElementsKind(elements_kind) ||
+ IsFastDoubleElementsKind(elements_kind));
+ ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+ ? FAST_HOLEY_ELEMENTS
+ : FAST_ELEMENTS;
+ JSObject::TransitionElementsKind(object, transitioned_kind);
+ if (IsMoreGeneralElementsKindTransition(
+ boilerplate_object->GetElementsKind(),
+ transitioned_kind)) {
+ JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
}
FixedArray* object_array = FixedArray::cast(object->elements());
object_array->set(store_index, *value);
@@ -5955,7 +5993,9 @@
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSArray, array, 0);
- if (!array->HasFastElements()) return isolate->heap()->undefined_value();
+ if (!array->HasFastObjectElements()) {
+ return isolate->heap()->undefined_value();
+ }
FixedArray* elements = FixedArray::cast(array->elements());
int n = elements->length();
bool ascii = true;
@@ -6398,7 +6438,7 @@
if (maybe_result->IsFailure()) return maybe_result;
result->set_length(Smi::FromInt(part_count));
- ASSERT(result->HasFastElements());
+ ASSERT(result->HasFastObjectElements());
if (part_count == 1 && indices.at(0) == subject_length) {
FixedArray::cast(result->elements())->set(0, *subject);
@@ -6417,7 +6457,7 @@
}
if (limit == 0xffffffffu) {
- if (result->HasFastElements()) {
+ if (result->HasFastObjectElements()) {
StringSplitCache::Enter(isolate->heap(),
isolate->heap()->string_split_cache(),
*subject,
@@ -6774,7 +6814,7 @@
if (maybe_result->IsFailure()) return maybe_result;
int special_length = special->length();
- if (!array->HasFastElements()) {
+ if (!array->HasFastObjectElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
@@ -6884,7 +6924,7 @@
int array_length = args.smi_at(1);
CONVERT_ARG_CHECKED(String, separator, 2);
- if (!array->HasFastElements()) {
+ if (!array->HasFastObjectElements()) {
return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
@@ -7001,8 +7041,7 @@
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
- RUNTIME_ASSERT(elements_array->HasFastElements() ||
- elements_array->HasFastSmiOnlyElements());
+ RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
CONVERT_ARG_CHECKED(String, separator, 2);
// elements_array is fast-mode JSarray of alternating positions
@@ -9163,7 +9202,7 @@
MaybeObject* maybe_result_array =
output->EnsureCanContainHeapObjectElements();
if (maybe_result_array->IsFailure()) return maybe_result_array;
- RUNTIME_ASSERT(output->HasFastElements());
+ RUNTIME_ASSERT(output->HasFastObjectElements());
AssertNoAllocation no_allocation;
@@ -9395,7 +9434,7 @@
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSArray, array, 0);
CONVERT_ARG_CHECKED(JSObject, element, 1);
- RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
+ RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
for (int i = 0; i < length; i++) {
@@ -9480,7 +9519,7 @@
Handle<Map> map;
if (fast_elements_) {
map = isolate_->factory()->GetElementsTransitionMap(array,
- FAST_ELEMENTS);
+ FAST_HOLEY_ELEMENTS);
} else {
map = isolate_->factory()->GetElementsTransitionMap(array,
DICTIONARY_ELEMENTS);
@@ -9539,8 +9578,10 @@
uint32_t length = static_cast<uint32_t>(array->length()->Number());
int element_count = 0;
switch (array->GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
// Fast elements can't have lengths that are not representable by
// a 32-bit signed integer.
ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
@@ -9552,6 +9593,7 @@
break;
}
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
break;
@@ -9642,8 +9684,10 @@
List<uint32_t>* indices) {
ElementsKind kind = object->GetElementsKind();
switch (kind) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
if (range < length) length = range;
@@ -9654,6 +9698,7 @@
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
@@ -9768,8 +9813,10 @@
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->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: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
@@ -9790,6 +9837,7 @@
}
break;
}
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// TODO(1810): Decide if it's worthwhile to implement this.
UNREACHABLE();
@@ -9887,7 +9935,7 @@
CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
int argument_count = static_cast<int>(arguments->length()->Number());
- RUNTIME_ASSERT(arguments->HasFastElements());
+ RUNTIME_ASSERT(arguments->HasFastObjectElements());
Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
// Pass 1: estimate the length and number of elements of the result.
@@ -9907,10 +9955,14 @@
Handle<JSArray> array(Handle<JSArray>::cast(obj));
// TODO(1810): Find out if it's worthwhile to properly support
// arbitrary ElementsKinds. For now, pessimistically transition to
- // FAST_ELEMENTS.
+ // FAST_*_ELEMENTS.
if (array->HasFastDoubleElements()) {
+ ElementsKind to_kind = FAST_ELEMENTS;
+ if (array->HasFastHoleyElements()) {
+ to_kind = FAST_HOLEY_ELEMENTS;
+ }
array = Handle<JSArray>::cast(
- JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
+ JSObject::TransitionElementsKind(array, to_kind));
}
length_estimate =
static_cast<uint32_t>(array->length()->Number());
@@ -10007,29 +10059,22 @@
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSArray, from, 0);
CONVERT_ARG_CHECKED(JSArray, to, 1);
+ from->ValidateElements();
+ to->ValidateElements();
FixedArrayBase* new_elements = from->elements();
+ ElementsKind from_kind = from->GetElementsKind();
MaybeObject* maybe_new_map;
- ElementsKind elements_kind;
- if (new_elements->map() == isolate->heap()->fixed_array_map() ||
- new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
- elements_kind = FAST_ELEMENTS;
- } else if (new_elements->map() ==
- isolate->heap()->fixed_double_array_map()) {
- elements_kind = FAST_DOUBLE_ELEMENTS;
- } else {
- elements_kind = DICTIONARY_ELEMENTS;
- }
- maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
+ maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
Object* new_map;
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
- to->set_map(Map::cast(new_map));
- to->set_elements(new_elements);
+ to->set_map_and_elements(Map::cast(new_map), new_elements);
to->set_length(from->length());
Object* obj;
{ MaybeObject* maybe_obj = from->ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
from->set_length(Smi::FromInt(0));
+ to->ValidateElements();
return to;
}
@@ -10079,8 +10124,7 @@
}
return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
- ASSERT(array->HasFastElements() ||
- array->HasFastSmiOnlyElements() ||
+ ASSERT(array->HasFastSmiOrObjectElements() ||
array->HasFastDoubleElements());
Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
// -1 means start of array.
@@ -13395,9 +13439,11 @@
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
diff --git a/src/runtime.h b/src/runtime.h
index 83991bb..fc0a472 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -364,9 +364,11 @@
F(IS_VAR, 1, 1) \
\
/* expose boolean functions from objects-inl.h */ \
- F(HasFastSmiOnlyElements, 1, 1) \
- F(HasFastElements, 1, 1) \
+ F(HasFastSmiElements, 1, 1) \
+ F(HasFastSmiOrObjectElements, 1, 1) \
+ F(HasFastObjectElements, 1, 1) \
F(HasFastDoubleElements, 1, 1) \
+ F(HasFastHoleyElements, 1, 1) \
F(HasDictionaryElements, 1, 1) \
F(HasExternalPixelElements, 1, 1) \
F(HasExternalArrayElements, 1, 1) \
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 35f7be5..bf711ba 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -427,7 +427,7 @@
PrintUsingMap(JSObject::cast(printee));
if (printee->IsJSArray()) {
JSArray* array = JSArray::cast(printee);
- if (array->HasFastElements()) {
+ if (array->HasFastObjectElements()) {
unsigned int limit = FixedArray::cast(array->elements())->length();
unsigned int length =
static_cast<uint32_t>(JSArray::cast(array)->length()->Number());
diff --git a/src/version.cc b/src/version.cc
index ec62870..534622e 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 11
-#define BUILD_NUMBER 6
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 7
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 4e037ff..0af0a43 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -977,7 +977,7 @@
const int initial_capacity = JSArray::kPreallocatedArrayElements;
STATIC_ASSERT(initial_capacity >= 0);
- __ LoadInitialArrayMap(array_function, scratch2, scratch1);
+ __ LoadInitialArrayMap(array_function, scratch2, scratch1, false);
// Allocate the JSArray object together with space for a fixed array with the
// requested elements.
@@ -1076,7 +1076,8 @@
Register scratch,
bool fill_with_hole,
Label* gc_required) {
- __ LoadInitialArrayMap(array_function, scratch, elements_array);
+ __ LoadInitialArrayMap(array_function, scratch,
+ elements_array, fill_with_hole);
if (FLAG_debug_code) { // Assert that array size is not zero.
__ testq(array_size, array_size);
@@ -1303,10 +1304,10 @@
__ jmp(call_generic_code);
__ bind(¬_double);
- // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS.
+ // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS.
// rbx: JSArray
__ movq(r11, FieldOperand(rbx, HeapObject::kMapOffset));
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
r11,
kScratchRegister,
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 13838ac..61d6c87 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -6002,12 +6002,12 @@
// KeyedStoreStubCompiler::GenerateStoreFastElement.
{ REG(rdi), REG(rbx), REG(rcx), EMIT_REMEMBERED_SET},
{ REG(rdx), REG(rdi), REG(rbx), EMIT_REMEMBERED_SET},
- // ElementsTransitionGenerator::GenerateSmiOnlyToObject
- // and ElementsTransitionGenerator::GenerateSmiOnlyToObject
+ // ElementsTransitionGenerator::GenerateMapChangeElementTransition
+ // and ElementsTransitionGenerator::GenerateSmiToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
{ REG(rdx), REG(rbx), REG(rdi), EMIT_REMEMBERED_SET},
{ REG(rdx), REG(rbx), REG(rdi), OMIT_REMEMBERED_SET},
- // ElementsTransitionGenerator::GenerateSmiOnlyToDouble
+ // ElementsTransitionGenerator::GenerateSmiToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
{ REG(rdx), REG(r11), REG(r15), EMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateDoubleToObject
@@ -6281,9 +6281,9 @@
__ CheckFastElements(rdi, &double_elements);
- // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
+ // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
__ JumpIfSmi(rax, &smi_element);
- __ CheckFastSmiOnlyElements(rdi, &fast_elements);
+ __ CheckFastSmiElements(rdi, &fast_elements);
// Store into the array literal requires a elements transition. Call into
// the runtime.
@@ -6301,7 +6301,7 @@
// place.
__ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
- // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
+ // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
__ bind(&fast_elements);
__ SmiToInteger32(kScratchRegister, rcx);
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
@@ -6315,8 +6315,8 @@
OMIT_SMI_CHECK);
__ ret(0);
- // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
- // FAST_ELEMENTS, and value is Smi.
+ // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or
+ // FAST_*_ELEMENTS, and value is Smi.
__ bind(&smi_element);
__ SmiToInteger32(kScratchRegister, rcx);
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index a8d39b2..2924810 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -220,7 +220,7 @@
#define __ ACCESS_MASM(masm)
-void ElementsTransitionGenerator::GenerateSmiOnlyToObject(
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
@@ -241,7 +241,7 @@
}
-void ElementsTransitionGenerator::GenerateSmiOnlyToDouble(
+void ElementsTransitionGenerator::GenerateSmiToDouble(
MacroAssembler* masm, Label* fail) {
// ----------- S t a t e -------------
// -- rax : value
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 81dad6b..0db7424 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -1659,7 +1659,8 @@
ASSERT_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
- bool has_constant_fast_elements = constant_elements_kind == FAST_ELEMENTS;
+ bool has_constant_fast_elements =
+ IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
@@ -1670,7 +1671,7 @@
Heap* heap = isolate()->heap();
if (has_constant_fast_elements &&
constant_elements_values->map() == heap->fixed_cow_array_map()) {
- // If the elements are already FAST_ELEMENTS, the boilerplate cannot
+ // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
FastCloneShallowArrayStub stub(
@@ -1682,10 +1683,9 @@
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
- ASSERT(constant_elements_kind == FAST_ELEMENTS ||
- constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
+ ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
- // If the elements are already FAST_ELEMENTS, the boilerplate cannot
+ // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
// change, so it's possible to specialize the stub in advance.
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
? FastCloneShallowArrayStub::CLONE_ELEMENTS
@@ -1713,9 +1713,9 @@
}
VisitForAccumulatorValue(subexpr);
- if (constant_elements_kind == FAST_ELEMENTS) {
- // Fast-case array literal with ElementsKind of FAST_ELEMENTS, they cannot
- // transition and don't need to call the runtime stub.
+ if (IsFastObjectElementsKind(constant_elements_kind)) {
+ // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
+ // cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 6ba5fb6..82fdb3c 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -769,25 +769,25 @@
__ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &non_double_value);
- // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+ // Value is a double. Transition FAST_SMI_ELEMENTS ->
// FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_DOUBLE_ELEMENTS,
rbx,
rdi,
&slow);
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ jmp(&fast_double_without_map_check);
__ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+ // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
rbx,
rdi,
&slow);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+ ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ jmp(&finish_object_store);
@@ -1642,7 +1642,7 @@
// Must return the modified receiver in eax.
if (!FLAG_trace_elements_transitions) {
Label fail;
- ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
+ ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
__ movq(rax, rdx);
__ Ret();
__ bind(&fail);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index d1cf338..f1c631b 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2324,8 +2324,10 @@
__ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Immediate(Map::kElementsKindMask));
__ shr(temp, Immediate(Map::kElementsKindShift));
- __ cmpl(temp, Immediate(FAST_ELEMENTS));
- __ j(equal, &ok, Label::kNear);
+ __ cmpl(temp, Immediate(GetInitialFastElementsKind()));
+ __ j(less, &fail, Label::kNear);
+ __ cmpl(temp, Immediate(TERMINAL_FAST_ELEMENTS_KIND));
+ __ j(less_equal, &ok, Label::kNear);
__ cmpl(temp, Immediate(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less, &fail, Label::kNear);
__ cmpl(temp, Immediate(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
@@ -2403,16 +2405,18 @@
__ movsxlq(key_reg, key_reg);
}
- int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
- sizeof(kHoleNanLower32);
- Operand hole_check_operand = BuildFastArrayOperand(
- instr->elements(),
- instr->key(),
- FAST_DOUBLE_ELEMENTS,
- offset,
- instr->additional_index());
- __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
- DeoptimizeIf(equal, instr->environment());
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
+ sizeof(kHoleNanLower32);
+ Operand hole_check_operand = BuildFastArrayOperand(
+ instr->elements(),
+ instr->key(),
+ FAST_DOUBLE_ELEMENTS,
+ offset,
+ instr->additional_index());
+ __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
+ DeoptimizeIf(equal, instr->environment());
+ }
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(),
@@ -2501,8 +2505,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3403,8 +3410,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3539,21 +3549,22 @@
__ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
__ j(not_equal, ¬_applicable);
__ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
- if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
__ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
// Write barrier.
ASSERT_NE(instr->temp_reg(), NULL);
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ToRegister(instr->temp_reg()), kDontSaveFPRegs);
- } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- to_kind == FAST_DOUBLE_ELEMENTS) {
+ } else if (IsFastSmiElementsKind(from_kind) &&
+ IsFastDoubleElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(rdx));
ASSERT(new_map_reg.is(rbx));
__ movq(fixed_object_reg, object_reg);
CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
RelocInfo::CODE_TARGET, instr);
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ } else if (IsFastDoubleElementsKind(from_kind) &&
+ IsFastObjectElementsKind(to_kind)) {
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(rdx));
ASSERT(new_map_reg.is(rbx));
@@ -4227,8 +4238,9 @@
// Deopt if the array literal boilerplate ElementsKind is of a type different
// than the expected one. The check isn't necessary if the boilerplate has
- // already been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(rax, instr->hydrogen()->boilerplate_object());
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
// Load the map's "bit field 2".
@@ -4374,10 +4386,11 @@
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate()->GetElementsKind();
- // Deopt if the literal boilerplate ElementsKind is of a type different than
- // the expected one. The check isn't necessary if the boilerplate has already
- // been converted to FAST_ELEMENTS.
- if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ // Deopt if the array literal boilerplate ElementsKind is of a type different
+ // than the expected one. The check isn't necessary if the boilerplate has
+ // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
+ if (CanTransitionToMoreGeneralFastElementsKind(
+ boilerplate_elements_kind, true)) {
__ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
__ movq(rcx, FieldOperand(rbx, HeapObject::kMapOffset));
// Load the map's "bit field 2".
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 3ba0cae..6094dbb 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -2012,8 +2012,9 @@
LInstruction* LChunkBuilder::DoTransitionElementsKind(
HTransitionElementsKind* instr) {
- if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
+ ElementsKind from_kind = instr->original_map()->elements_kind();
+ ElementsKind to_kind = instr->transitioned_map()->elements_kind();
+ if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
LOperand* object = UseRegister(instr->object());
LOperand* new_map_reg = TempRegister();
LOperand* temp_reg = TempRegister();
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 3d380a2..95b43f4 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2658,10 +2658,12 @@
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastElementValue));
+ Immediate(Map::kMaximumBitField2FastHoleyElementValue));
j(above, fail, distance);
}
@@ -2669,23 +2671,26 @@
void MacroAssembler::CheckFastObjectElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
- STATIC_ASSERT(FAST_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ STATIC_ASSERT(FAST_ELEMENTS == 2);
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
j(below_equal, fail, distance);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastElementValue));
+ Immediate(Map::kMaximumBitField2FastHoleyElementValue));
j(above, fail, distance);
}
-void MacroAssembler::CheckFastSmiOnlyElements(Register map,
- Label* fail,
- Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+void MacroAssembler::CheckFastSmiElements(Register map,
+ Label* fail,
+ Label::Distance distance) {
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+ Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
j(above, fail, distance);
}
@@ -2749,24 +2754,18 @@
CompareMapMode mode) {
Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) {
- Map* transitioned_fast_element_map(
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL));
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- j(equal, early_success, Label::kNear);
- Cmp(FieldOperand(obj, HeapObject::kMapOffset),
- Handle<Map>(transitioned_fast_element_map));
- }
-
- Map* transitioned_double_map(
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL));
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- j(equal, early_success, Label::kNear);
- Cmp(FieldOperand(obj, HeapObject::kMapOffset),
- Handle<Map>(transitioned_double_map));
+ ElementsKind kind = map->elements_kind();
+ if (IsFastElementsKind(kind)) {
+ bool packed = IsFastPackedElementsKind(kind);
+ Map* current_map = *map;
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
+ if (!current_map) break;
+ j(equal, early_success, Label::kNear);
+ Cmp(FieldOperand(obj, HeapObject::kMapOffset),
+ Handle<Map>(current_map));
+ }
}
}
}
@@ -4057,27 +4056,38 @@
movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check that the function's map is the same as the expected cached map.
- int expected_index =
- Context::GetContextMapIndexFromElementsKind(expected_kind);
- cmpq(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+ movq(scratch, Operand(scratch,
+ Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
+
+ int offset = expected_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ cmpq(map_in_out, FieldOperand(scratch, offset));
j(not_equal, no_map_match);
// Use the transitioned cached map.
- int trans_index =
- Context::GetContextMapIndexFromElementsKind(transitioned_kind);
- movq(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+ offset = transitioned_kind * kPointerSize +
+ FixedArrayBase::kHeaderSize;
+ movq(map_in_out, FieldOperand(scratch, offset));
}
void MacroAssembler::LoadInitialArrayMap(
- Register function_in, Register scratch, Register map_out) {
+ Register function_in, Register scratch,
+ Register map_out, bool can_have_holes) {
ASSERT(!function_in.is(map_out));
Label done;
movq(map_out, FieldOperand(function_in,
JSFunction::kPrototypeOrInitialMapOffset));
if (!FLAG_smi_only_arrays) {
- LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
- FAST_ELEMENTS,
+ ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ kind,
+ map_out,
+ scratch,
+ &done);
+ } else if (can_have_holes) {
+ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
+ FAST_HOLEY_SMI_ELEMENTS,
map_out,
scratch,
&done);
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 66587d5..1c1cd95 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -877,9 +877,9 @@
// Check if a map for a JSObject indicates that the object has fast smi only
// elements. Jump to the specified label if it does not.
- void CheckFastSmiOnlyElements(Register map,
- Label* fail,
- Label::Distance distance = Label::kFar);
+ void CheckFastSmiElements(Register map,
+ Label* fail,
+ Label::Distance distance = Label::kFar);
// Check to see if maybe_number can be stored as a double in
// FastDoubleElements. If it can, store it at the index specified by index in
@@ -1141,7 +1141,8 @@
// Load the initial map for new Arrays from a JSFunction.
void LoadInitialArrayMap(Register function_in,
Register scratch,
- Register map_out);
+ Register map_out,
+ bool can_have_holes);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 5721e9b..1b8ed38 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -1434,17 +1434,32 @@
__ jmp(&fast_object);
// In case of fast smi-only, convert to fast object, otherwise bail out.
__ bind(¬_fast_object);
- __ CheckFastSmiOnlyElements(rbx, &call_builtin);
+ __ CheckFastSmiElements(rbx, &call_builtin);
// rdx: receiver
// rbx: map
- __ movq(r9, rdi); // Backup rdi as it is going to be trashed.
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+
+ Label try_holey_map;
+ __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
FAST_ELEMENTS,
rbx,
rdi,
+ &try_holey_map);
+
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
+ // Restore edi.
+ __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
+ __ jmp(&fast_object);
+
+ __ bind(&try_holey_map);
+ __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
+ FAST_HOLEY_ELEMENTS,
+ rbx,
+ rdi,
&call_builtin);
- ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
- __ movq(rdi, r9);
+ ElementsTransitionGenerator::
+ GenerateMapChangeElementsTransition(masm());
+ __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset));
__ bind(&fast_object);
} else {
__ CheckFastObjectElements(rbx, &call_builtin);
@@ -3369,8 +3384,11 @@
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
break;
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3435,8 +3453,11 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_SMI_ONLY_ELEMENTS:
+ case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
@@ -3587,7 +3608,7 @@
// Check that the key is a smi or a heap number convertible to a smi.
GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(rax, &transition_elements_kind);
}
@@ -3611,13 +3632,13 @@
__ j(not_equal, &miss_force_generic);
__ bind(&finish_store);
- if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ if (IsFastSmiElementsKind(elements_kind)) {
__ SmiToInteger32(rcx, rcx);
__ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
rax);
} else {
// Do the store and update the write barrier.
- ASSERT(elements_kind == FAST_ELEMENTS);
+ ASSERT(IsFastObjectElementsKind(elements_kind));
__ SmiToInteger32(rcx, rcx);
__ lea(rcx,
FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index af28be1..3cbc3bc 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -27,6 +27,7 @@
prefix cctest
+# All tests prefixed with 'Bug' are expected to fail.
test-api/Bug*: FAIL
##############################################################################
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index 8f405b7..762cc9f 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -400,3 +400,41 @@
// See MultipleAssignments test.
CheckFunctionName(script, "return 2", "Enclosing.Bar");
}
+
+
+TEST(MethodAssignmentInAnonymousFunctionCall) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "(function () {\n"
+ " var EventSource = function () { };\n"
+ " EventSource.prototype.addListener = function () {\n"
+ " return 2012;\n"
+ " };\n"
+ " this.PublicEventSource = EventSource;\n"
+ "})();");
+ CheckFunctionName(script, "return 2012", "EventSource.addListener");
+}
+
+
+TEST(ReturnAnonymousFunction) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Script> script = Compile(
+ "(function() {\n"
+ " function wrapCode() {\n"
+ " return function () {\n"
+ " return 2012;\n"
+ " };\n"
+ " };\n"
+ " var foo = 10;\n"
+ " function f() {\n"
+ " return wrapCode();\n"
+ " }\n"
+ " this.ref = f;\n"
+ "})()");
+ script->Run();
+ CheckFunctionName(script, "return 2012", "");
+}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index d4a40bf..33aaed3 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -673,7 +673,7 @@
array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
CHECK_EQ(Smi::FromInt(0), array->length());
// Must be in fast mode.
- CHECK(array->HasFastTypeElements());
+ CHECK(array->HasFastSmiOrObjectElements());
// array[length] = name.
array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
@@ -811,7 +811,9 @@
// Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
objs[next_objs_index++] = FACTORY->NewJSArray(10);
- objs[next_objs_index++] = FACTORY->NewJSArray(10, FAST_ELEMENTS, TENURED);
+ objs[next_objs_index++] = FACTORY->NewJSArray(10,
+ FAST_HOLEY_ELEMENTS,
+ TENURED);
// Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
objs[next_objs_index++] =
@@ -1595,7 +1597,7 @@
Handle<JSObject> prototype;
PagedSpace* space = HEAP->old_pointer_space();
do {
- prototype = FACTORY->NewJSArray(32 * KB, FAST_ELEMENTS, TENURED);
+ prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
} while (space->FirstPage() == space->LastPage() ||
!space->LastPage()->Contains(prototype->address()));
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 700f322..2712370 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -531,18 +531,18 @@
// there we just skip the test.
if (initial_memory >= 0) {
InitializeVM();
- intptr_t booted_memory = MemoryInUse();
+ intptr_t delta = MemoryInUse() - initial_memory;
if (sizeof(initial_memory) == 8) {
if (v8::internal::Snapshot::IsEnabled()) {
- CHECK_LE(booted_memory - initial_memory, 3600 * 1024); // 3396.
+ CHECK_LE(delta, 3600 * 1024); // 3396.
} else {
- CHECK_LE(booted_memory - initial_memory, 3600 * 1024); // 3432.
+ CHECK_LE(delta, 4000 * 1024); // 3948.
}
} else {
if (v8::internal::Snapshot::IsEnabled()) {
- CHECK_LE(booted_memory - initial_memory, 2800 * 1024); // 2484.
+ CHECK_LE(delta, 2600 * 1024); // 2484.
} else {
- CHECK_LE(booted_memory - initial_memory, 2950 * 1024); // 2844
+ CHECK_LE(delta, 2950 * 1024); // 2844
}
}
}
diff --git a/test/mjsunit/accessor-map-sharing.js b/test/mjsunit/accessor-map-sharing.js
new file mode 100644
index 0000000..8bbcb4f
--- /dev/null
+++ b/test/mjsunit/accessor-map-sharing.js
@@ -0,0 +1,176 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --fast-accessor-properties
+
+// Handy abbreviations.
+var dp = Object.defineProperty;
+var gop = Object.getOwnPropertyDescriptor;
+
+function getter() { return 111; }
+function setter(x) { print(222); }
+function anotherGetter() { return 333; }
+function anotherSetter(x) { print(444); }
+var obj1, obj2;
+
+// Two objects with the same getter.
+obj1 = {};
+dp(obj1, "alpha", { get: getter });
+obj2 = {};
+dp(obj2, "alpha", { get: getter });
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same getter, oldskool.
+obj1 = {};
+obj1.__defineGetter__("bravo", getter);
+assertEquals(getter, obj1.__lookupGetter__("bravo"));
+obj2 = {};
+obj2.__defineGetter__("bravo", getter);
+assertEquals(getter, obj2.__lookupGetter__("bravo"));
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same setter.
+obj1 = {};
+dp(obj1, "charlie", { set: setter });
+obj2 = {};
+dp(obj2, "charlie", { set: setter });
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same setter, oldskool.
+obj1 = {};
+obj1.__defineSetter__("delta", setter);
+assertEquals(setter, obj1.__lookupSetter__("delta"));
+obj2 = {};
+obj2.__defineSetter__("delta", setter);
+assertEquals(setter, obj2.__lookupSetter__("delta"));
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same getter and setter.
+obj1 = {};
+dp(obj1, "foxtrot", { get: getter, set: setter });
+obj2 = {};
+dp(obj2, "foxtrot", { get: getter, set: setter });
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same getter and setter, set separately.
+obj1 = {};
+dp(obj1, "golf", { get: getter, configurable: true });
+dp(obj1, "golf", { set: setter, configurable: true });
+obj2 = {};
+dp(obj2, "golf", { get: getter, configurable: true });
+dp(obj2, "golf", { set: setter, configurable: true });
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same getter and setter, set separately, oldskool.
+obj1 = {};
+obj1.__defineGetter__("hotel", getter);
+obj1.__defineSetter__("hotel", setter);
+obj2 = {};
+obj2.__defineGetter__("hotel", getter);
+obj2.__defineSetter__("hotel", setter);
+assertTrue(%HaveSameMap(obj1, obj2));
+
+// Attribute-only change, shouldn't affect previous descriptor properties.
+obj1 = {};
+dp(obj1, "india", { get: getter, configurable: true, enumerable: true });
+assertEquals(getter, gop(obj1, "india").get);
+assertTrue(gop(obj1, "india").configurable);
+assertTrue(gop(obj1, "india").enumerable);
+dp(obj1, "india", { enumerable: false });
+assertEquals(getter, gop(obj1, "india").get);
+assertTrue(gop(obj1, "india").configurable);
+assertFalse(gop(obj1, "india").enumerable);
+
+// Attribute-only change, shouldn't affect objects with previously shared maps.
+obj1 = {};
+dp(obj1, "juliet", { set: setter, configurable: true, enumerable: false });
+assertEquals(setter, gop(obj1, "juliet").set);
+assertTrue(gop(obj1, "juliet").configurable);
+assertFalse(gop(obj1, "juliet").enumerable);
+obj2 = {};
+dp(obj2, "juliet", { set: setter, configurable: true, enumerable: false });
+assertEquals(setter, gop(obj2, "juliet").set);
+assertTrue(gop(obj2, "juliet").configurable);
+assertFalse(gop(obj2, "juliet").enumerable);
+dp(obj1, "juliet", { set: setter, configurable: false, enumerable: true });
+assertEquals(setter, gop(obj1, "juliet").set);
+assertFalse(gop(obj1, "juliet").configurable);
+assertTrue(gop(obj1, "juliet").enumerable);
+assertEquals(setter, gop(obj2, "juliet").set);
+assertTrue(gop(obj2, "juliet").configurable);
+assertFalse(gop(obj2, "juliet").enumerable);
+
+// Two objects with the different getters.
+obj1 = {};
+dp(obj1, "kilo", { get: getter });
+obj2 = {};
+dp(obj2, "kilo", { get: anotherGetter });
+assertEquals(getter, gop(obj1, "kilo").get);
+assertEquals(anotherGetter, gop(obj2, "kilo").get);
+assertFalse(%HaveSameMap(obj1, obj2));
+
+// Two objects with the same getters and different setters.
+obj1 = {};
+dp(obj1, "lima", { get: getter, set: setter });
+obj2 = {};
+dp(obj2, "lima", { get: getter, set: anotherSetter });
+assertEquals(setter, gop(obj1, "lima").set);
+assertEquals(anotherSetter, gop(obj2, "lima").set);
+assertFalse(%HaveSameMap(obj1, obj2));
+
+// Even 'undefined' is a kind of getter.
+obj1 = {};
+dp(obj1, "mike", { get: undefined });
+assertTrue("mike" in obj1);
+assertEquals(undefined, gop(obj1, "mike").get);
+assertEquals(undefined, obj1.__lookupGetter__("mike"));
+assertEquals(undefined, gop(obj1, "mike").set);
+assertEquals(undefined, obj1.__lookupSetter__("mike"));
+
+// Even 'undefined' is a kind of setter.
+obj1 = {};
+dp(obj1, "november", { set: undefined });
+assertTrue("november" in obj1);
+assertEquals(undefined, gop(obj1, "november").get);
+assertEquals(undefined, obj1.__lookupGetter__("november"));
+assertEquals(undefined, gop(obj1, "november").set);
+assertEquals(undefined, obj1.__lookupSetter__("november"));
+
+// Redefining a data property.
+obj1 = {};
+obj1.oscar = 12345;
+dp(obj1, "oscar", { set: setter });
+assertEquals(setter, gop(obj1, "oscar").set);
+
+// Re-adding the same getter/attributes pair.
+obj1 = {};
+dp(obj1, "papa", { get: getter, configurable: true });
+dp(obj1, "papa", { get: getter, set: setter, configurable: true });
+assertEquals(getter, gop(obj1, "papa").get);
+assertEquals(setter, gop(obj1, "papa").set);
+assertTrue(gop(obj1, "papa").configurable);
+assertFalse(gop(obj1, "papa").enumerable);
diff --git a/test/mjsunit/array-construct-transition.js b/test/mjsunit/array-construct-transition.js
index 577e321..f8d7c83 100644
--- a/test/mjsunit/array-construct-transition.js
+++ b/test/mjsunit/array-construct-transition.js
@@ -27,13 +27,13 @@
// Flags: --allow-natives-syntax --smi-only-arrays
-support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8));
+support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6));
if (support_smi_only_arrays) {
var a = new Array(0, 1, 2);
- assertTrue(%HasFastSmiOnlyElements(a));
+ assertTrue(%HasFastSmiElements(a));
var b = new Array(0.5, 1.2, 2.3);
assertTrue(%HasFastDoubleElements(b));
var c = new Array(0.5, 1.2, new Object());
- assertTrue(%HasFastElements(c));
+ assertTrue(%HasFastObjectElements(c));
}
diff --git a/test/mjsunit/array-literal-transitions.js b/test/mjsunit/array-literal-transitions.js
index f657525..a96719d 100644
--- a/test/mjsunit/array-literal-transitions.js
+++ b/test/mjsunit/array-literal-transitions.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -33,7 +33,7 @@
// in this test case. Depending on whether smi-only arrays are actually
// enabled, this test takes the appropriate code path to check smi-only arrays.
-support_smi_only_arrays = %HasFastSmiOnlyElements([1,2,3,4,5,6,7,8,9,10]);
+support_smi_only_arrays = %HasFastSmiElements([1,2,3,4,5,6,7,8,9,10]);
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
@@ -46,14 +46,14 @@
function array_literal_test() {
var a0 = [1, 2, 3];
- assertTrue(%HasFastSmiOnlyElements(a0));
+ assertTrue(%HasFastSmiElements(a0));
var a1 = [get(1), get(2), get(3)];
- assertTrue(%HasFastSmiOnlyElements(a1));
+ assertTrue(%HasFastSmiElements(a1));
var b0 = [1, 2, get("three")];
- assertTrue(%HasFastElements(b0));
+ assertTrue(%HasFastObjectElements(b0));
var b1 = [get(1), get(2), get("three")];
- assertTrue(%HasFastElements(b1));
+ assertTrue(%HasFastObjectElements(b1));
var c0 = [1, 2, get(3.5)];
assertTrue(%HasFastDoubleElements(c0));
@@ -75,7 +75,7 @@
var object = new Object();
var d0 = [1, 2, object];
- assertTrue(%HasFastElements(d0));
+ assertTrue(%HasFastObjectElements(d0));
assertEquals(object, d0[2]);
assertEquals(2, d0[1]);
assertEquals(1, d0[0]);
@@ -87,7 +87,7 @@
assertEquals(1, e0[0]);
var f0 = [1, 2, [1, 2]];
- assertTrue(%HasFastElements(f0));
+ assertTrue(%HasFastObjectElements(f0));
assertEquals([1,2], f0[2]);
assertEquals(2, f0[1]);
assertEquals(1, f0[0]);
@@ -115,9 +115,9 @@
large =
[ 0, 1, 2, 3, 4, 5, d(), d(), d(), d(), d(), d(), o(), o(), o(), o() ];
assertFalse(%HasDictionaryElements(large));
- assertFalse(%HasFastSmiOnlyElements(large));
+ assertFalse(%HasFastSmiElements(large));
assertFalse(%HasFastDoubleElements(large));
- assertTrue(%HasFastElements(large));
+ assertTrue(%HasFastObjectElements(large));
assertEquals(large,
[0, 1, 2, 3, 4, 5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5,
new Object(), new Object(), new Object(), new Object()]);
diff --git a/test/mjsunit/elements-kind.js b/test/mjsunit/elements-kind.js
index 4aa79de..26b3c78 100644
--- a/test/mjsunit/elements-kind.js
+++ b/test/mjsunit/elements-kind.js
@@ -34,7 +34,7 @@
// in this test case. Depending on whether smi-only arrays are actually
// enabled, this test takes the appropriate code path to check smi-only arrays.
-support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8));
+support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
@@ -59,8 +59,8 @@
}
function getKind(obj) {
- if (%HasFastSmiOnlyElements(obj)) return elements_kind.fast_smi_only;
- if (%HasFastElements(obj)) return elements_kind.fast;
+ if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
+ if (%HasFastObjectElements(obj)) return elements_kind.fast;
if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
// Every external kind is also an external array.
@@ -116,7 +116,7 @@
assertKind(elements_kind.fast_smi_only, too);
}
-// Make sure the element kind transitions from smionly when a non-smi is stored.
+// Make sure the element kind transitions from smi when a non-smi is stored.
var you = new Array();
assertKind(elements_kind.fast_smi_only, you);
for (var i = 0; i < 1337; i++) {
diff --git a/test/mjsunit/elements-transition-hoisting.js b/test/mjsunit/elements-transition-hoisting.js
index 5e78f10..50ca2a1 100644
--- a/test/mjsunit/elements-transition-hoisting.js
+++ b/test/mjsunit/elements-transition-hoisting.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -31,7 +31,7 @@
// not hoisted) correctly, don't change the semantics programs and don't trigger
// deopt through hoisting in important situations.
-support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6));
+support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6));
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
diff --git a/test/mjsunit/elements-transition.js b/test/mjsunit/elements-transition.js
index 60e051b..0dffd37 100644
--- a/test/mjsunit/elements-transition.js
+++ b/test/mjsunit/elements-transition.js
@@ -27,7 +27,7 @@
// Flags: --allow-natives-syntax --smi-only-arrays
-support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8));
+support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
@@ -44,8 +44,8 @@
var array_1 = new Array(length);
var array_2 = new Array(length);
- assertTrue(%HasFastSmiOnlyElements(array_1));
- assertTrue(%HasFastSmiOnlyElements(array_2));
+ assertTrue(%HasFastSmiElements(array_1));
+ assertTrue(%HasFastSmiElements(array_2));
for (var i = 0; i < length; i++) {
if (i == length - 5 && test_double) {
// Trigger conversion to fast double elements at length-5.
@@ -57,8 +57,8 @@
// Trigger conversion to fast object elements at length-3.
set(array_1, i, 'object');
set(array_2, i, 'object');
- assertTrue(%HasFastElements(array_1));
- assertTrue(%HasFastElements(array_2));
+ assertTrue(%HasFastObjectElements(array_1));
+ assertTrue(%HasFastObjectElements(array_2));
} else if (i != length - 7) {
// Set the element to an integer but leave a hole at length-7.
set(array_1, i, 2*i+1);
diff --git a/test/mjsunit/packed-elements.js b/test/mjsunit/packed-elements.js
new file mode 100644
index 0000000..7f333e5
--- /dev/null
+++ b/test/mjsunit/packed-elements.js
@@ -0,0 +1,112 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays --packed-arrays
+
+var has_packed_elements = !%HasFastHoleyElements(Array());
+
+function test1() {
+ var a = Array(8);
+ assertTrue(%HasFastSmiOrObjectElements(a));
+ assertTrue(%HasFastHoleyElements(a));
+}
+
+function test2() {
+ var a = Array();
+ assertTrue(%HasFastSmiOrObjectElements(a));
+ assertFalse(%HasFastHoleyElements(a));
+}
+
+function test3() {
+ var a = Array(1,2,3,4,5,6,7);
+ assertTrue(%HasFastSmiOrObjectElements(a));
+ assertFalse(%HasFastHoleyElements(a));
+}
+
+function test4() {
+ var a = [1, 2, 3, 4];
+ assertTrue(%HasFastSmiElements(a));
+ assertFalse(%HasFastHoleyElements(a));
+ var b = [1, 2,, 4];
+ assertTrue(%HasFastSmiElements(b));
+ assertTrue(%HasFastHoleyElements(b));
+}
+
+function test5() {
+ var a = [1, 2, 3, 4.5];
+ assertTrue(%HasFastDoubleElements(a));
+ assertFalse(%HasFastHoleyElements(a));
+ var b = [1,, 3.5, 4];
+ assertTrue(%HasFastDoubleElements(b));
+ assertTrue(%HasFastHoleyElements(b));
+ var c = [1, 3.5,, 4];
+ assertTrue(%HasFastDoubleElements(c));
+ assertTrue(%HasFastHoleyElements(c));
+}
+
+function test6() {
+ var x = new Object();
+ var a = [1, 2, 3.5, x];
+ assertTrue(%HasFastObjectElements(a));
+ assertFalse(%HasFastHoleyElements(a));
+ assertEquals(1, a[0]);
+ assertEquals(2, a[1]);
+ assertEquals(3.5, a[2]);
+ assertEquals(x, a[3]);
+ var b = [1,, 3.5, x];
+ assertTrue(%HasFastObjectElements(b));
+ assertTrue(%HasFastHoleyElements(b));
+ assertEquals(1, b[0]);
+ assertEquals(undefined, b[1]);
+ assertEquals(3.5, b[2]);
+ assertEquals(x, b[3]);
+ var c = [1, 3.5, x,,];
+ assertTrue(%HasFastObjectElements(c));
+ assertTrue(%HasFastHoleyElements(c));
+ assertEquals(1, c[0]);
+ assertEquals(3.5, c[1]);
+ assertEquals(x, c[2]);
+ assertEquals(undefined, c[3]);
+}
+
+function test_with_optimization(f) {
+ // Run tests in a loop to make sure that inlined Array() constructor runs out
+ // of new space memory and must fall back on runtime impl.
+ for (i = 0; i < 250000; ++i) f();
+ %OptimizeFunctionOnNextCall(f);
+ for (i = 0; i < 250000; ++i) f(); // Make sure GC happens
+}
+
+if (has_packed_elements) {
+ test_with_optimization(test1);
+ test_with_optimization(test2);
+ test_with_optimization(test3);
+ test_with_optimization(test4);
+ test_with_optimization(test5);
+ test_with_optimization(test6);
+}
+
diff --git a/test/mjsunit/regress/regress-117409.js b/test/mjsunit/regress/regress-117409.js
index 9222191..98aab5a 100644
--- a/test/mjsunit/regress/regress-117409.js
+++ b/test/mjsunit/regress/regress-117409.js
@@ -36,7 +36,7 @@
KeyedStoreIC(literal);
KeyedStoreIC(literal);
-// Trruncate array to 0 elements, at which point backing store will be replaced
+// Truncate array to 0 elements, at which point backing store will be replaced
// with empty fixed array.
literal.length = 0;
diff --git a/test/mjsunit/regress/regress-128146.js b/test/mjsunit/regress/regress-128146.js
index 5c22b4e..730dd91 100644
--- a/test/mjsunit/regress/regress-128146.js
+++ b/test/mjsunit/regress/regress-128146.js
@@ -25,14 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Define accessor properties, resulting in an AccessorPair with 2 transitions.
Object.defineProperty({},"foo",{set:function(){},configurable:false});
Object.defineProperty({},"foo",{get:function(){},configurable:false});
+
+// Define a data property under the same name.
Object.defineProperty({},"foo",{});
-
-// From WebKit layout tests (fast/js/prototypes.html)
-var wasSet = false;
-var o = { };
-o.__defineGetter__("__proto__", function() { wasSet = true });
-o.__proto__;
-assertFalse(wasSet);
-
diff --git a/test/mjsunit/regress/regress-1849.js b/test/mjsunit/regress/regress-1849.js
index 176f918..5b8fc50 100644
--- a/test/mjsunit/regress/regress-1849.js
+++ b/test/mjsunit/regress/regress-1849.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// See: http://code.google.com/p/v8/issues/detail?id=1878
+// See: http://code.google.com/p/v8/issues/detail?id=1849
// Flags: --allow-natives-syntax
@@ -36,4 +36,4 @@
arr[i] = 0;
}
assertFalse(%HasFastDoubleElements(arr));
-assertTrue(%HasFastSmiOnlyElements(arr));
+assertTrue(%HasFastSmiElements(arr));
diff --git a/test/mjsunit/regress/regress-1878.js b/test/mjsunit/regress/regress-1878.js
index a1648b1..fbc47bd 100644
--- a/test/mjsunit/regress/regress-1878.js
+++ b/test/mjsunit/regress/regress-1878.js
@@ -34,11 +34,11 @@
for (var i = 0; i < 1000; i++) {
var ai = natives.InternalArray(10000);
assertFalse(%HaveSameMap(ai, a));
- assertTrue(%HasFastElements(ai));
+ assertTrue(%HasFastObjectElements(ai));
}
for (var i = 0; i < 1000; i++) {
var ai = new natives.InternalArray(10000);
assertFalse(%HaveSameMap(ai, a));
- assertTrue(%HasFastElements(ai));
+ assertTrue(%HasFastObjectElements(ai));
}
diff --git a/test/mjsunit/regress/regress-2153.js b/test/mjsunit/regress/regress-2153.js
new file mode 100644
index 0000000..3170042
--- /dev/null
+++ b/test/mjsunit/regress/regress-2153.js
@@ -0,0 +1,32 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var o = {};
+o.__defineGetter__('foo', function () { return null; });
+var o = {};
+o.foo = 42;
+assertEquals(42, o.foo);
diff --git a/test/mjsunit/regress/regress-crbug-122271.js b/test/mjsunit/regress/regress-crbug-122271.js
index 3a99a7f..8ae91e8 100644
--- a/test/mjsunit/regress/regress-crbug-122271.js
+++ b/test/mjsunit/regress/regress-crbug-122271.js
@@ -39,11 +39,11 @@
array.foo = "bar";
}
-assertTrue(%HasFastSmiOnlyElements(a));
-assertTrue(%HasFastElements(b));
+assertTrue(%HasFastSmiElements(a));
+assertTrue(%HasFastObjectElements(b));
foo(a);
foo(b);
-assertTrue(%HasFastSmiOnlyElements(a));
-assertTrue(%HasFastElements(b));
+assertTrue(%HasFastSmiElements(a));
+assertTrue(%HasFastObjectElements(b));
diff --git a/test/mjsunit/regress/regress-smi-only-concat.js b/test/mjsunit/regress/regress-smi-only-concat.js
index a9a6d89..55ca299 100644
--- a/test/mjsunit/regress/regress-smi-only-concat.js
+++ b/test/mjsunit/regress/regress-smi-only-concat.js
@@ -33,5 +33,5 @@
var fast_array = ['a', 'b'];
var array = fast_array.concat(fast_array);
-assertTrue(%HasFastElements(fast_array));
-assertTrue(%HasFastElements(array));
\ No newline at end of file
+assertTrue(%HasFastObjectElements(fast_array));
+assertTrue(%HasFastObjectElements(array));
diff --git a/test/mjsunit/stack-traces.js b/test/mjsunit/stack-traces.js
index 536e71b..438eec9 100644
--- a/test/mjsunit/stack-traces.js
+++ b/test/mjsunit/stack-traces.js
@@ -111,6 +111,18 @@
throw new CustomError("hep-hey", CustomError);
}
+MyObj = function() { FAIL; }
+
+MyObjCreator = function() {}
+
+MyObjCreator.prototype.Create = function() {
+ return new MyObj();
+}
+
+function testClassNames() {
+ (new MyObjCreator).Create();
+}
+
// Utility function for testing that the expected strings occur
// in the stack trace produced when running the given function.
function testTrace(name, fun, expected, unexpected) {
@@ -254,6 +266,8 @@
["collectStackTrace"]);
testTrace("testStrippedCustomError", testStrippedCustomError, ["hep-hey"],
["new CustomError", "collectStackTrace"]);
+testTrace("testClassNames", testClassNames,
+ ["new MyObj", "MyObjCreator.Create"], ["as Create"]);
testCallerCensorship();
testUnintendedCallerCensorship();
testErrorsDuringFormatting();
diff --git a/test/mjsunit/unbox-double-arrays.js b/test/mjsunit/unbox-double-arrays.js
index fd7db28..ac03993 100644
--- a/test/mjsunit/unbox-double-arrays.js
+++ b/test/mjsunit/unbox-double-arrays.js
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -278,7 +278,8 @@
expected_array_value(7));
%DeoptimizeFunction(test_various_loads6);
- gc();
+ %ClearFunctionTypeFeedback(test_various_stores);
+ %ClearFunctionTypeFeedback(test_various_loads7);
// Test stores for non-NaN.
var large_array = new allocator(large_array_size);
@@ -376,7 +377,7 @@
// Convert back to fast elements and make sure the contents of the array are
// unchanged.
large_array2[25] = new Object();
-assertTrue(%HasFastElements(large_array2));
+assertTrue(%HasFastObjectElements(large_array2));
for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
if (i != 25 && i != 5) {
assertEquals(expected_array_value(i), large_array2[i]);
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index aa91139..ea82d31 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -295,6 +295,8 @@
'../../src/dtoa.h',
'../../src/elements.cc',
'../../src/elements.h',
+ '../../src/elements-kind.cc',
+ '../../src/elements-kind.h',
'../../src/execution.cc',
'../../src/execution.h',
'../../src/factory.cc',
diff --git a/tools/test-wrapper-gypbuild.py b/tools/test-wrapper-gypbuild.py
index eda2459..27b5a35 100755
--- a/tools/test-wrapper-gypbuild.py
+++ b/tools/test-wrapper-gypbuild.py
@@ -224,7 +224,8 @@
print ">>> running presubmit tests"
returncodes += subprocess.call([workspace + '/tools/presubmit.py'])
- args_for_children = [workspace + '/tools/test.py'] + PassOnOptions(options)
+ args_for_children = ['python']
+ args_for_children += [workspace + '/tools/test.py'] + PassOnOptions(options)
args_for_children += ['--no-build', '--build-system=gyp']
for arg in args:
args_for_children += [arg]
@@ -240,10 +241,14 @@
shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode
env['LD_LIBRARY_PATH'] = shellpath + '/lib.target'
shell = shellpath + "/d8"
- child = subprocess.Popen(' '.join(args_for_children +
- ['--arch=' + arch] +
- ['--mode=' + mode] +
- ['--shell=' + shell]),
+ cmdline = ' '.join(args_for_children +
+ ['--arch=' + arch] +
+ ['--mode=' + mode] +
+ ['--shell=' + shell])
+ # TODO(jkummerow): This print is temporary.
+ print "Executing: %s" % cmdline
+
+ child = subprocess.Popen(cmdline,
shell=True,
cwd=workspace,
env=env)