diff --git a/src/code-stubs.h b/src/code-stubs.h index fc7000bb03..23544bc457 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -71,7 +71,8 @@ namespace internal { V(KeyedStoreElement) \ V(DebuggerStatement) \ V(StringDictionaryLookup) \ - V(ElementsTransitionAndStore) + V(ElementsTransitionAndStore) \ + V(StoreArrayLiteralElement) // List of code stubs only used on ARM platforms. #ifdef V8_TARGET_ARCH_ARM @@ -1064,6 +1065,20 @@ class ElementsTransitionAndStoreStub : public CodeStub { DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub); }; + +class StoreArrayLiteralElementStub : public CodeStub { + public: + explicit StoreArrayLiteralElementStub() {} + + private: + Major MajorKey() { return StoreArrayLiteralElement; } + int MinorKey() { return 0; } + + void Generate(MacroAssembler* masm); + + DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub); +}; + } } // namespace v8::internal #endif // V8_CODE_STUBS_H_ diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 1e622023e6..50cddcaae5 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -6787,6 +6787,8 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { // ElementsTransitionGenerator::GenerateDoubleToObject { eax, edx, esi, EMIT_REMEMBERED_SET}, { edx, eax, edi, EMIT_REMEMBERED_SET}, + // StoreArrayLiteralElementStub::Generate + { ebx, eax, ecx, EMIT_REMEMBERED_SET}, // Null termination. { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} }; @@ -7029,6 +7031,93 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( // Fall through when we need to inform the incremental marker. } + +void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : element value to store + // -- ebx : array literal + // -- edi : map of array literal + // -- ecx : element index as smi + // -- edx : array literal index in function + // -- esp[0] : return address + // ----------------------------------- + + Label element_done; + Label double_elements; + Label smi_element; + Label slow_elements; + Label slow_elements_from_double; + Label fast_elements; + + if (!FLAG_trace_elements_transitions) { + __ CheckFastElements(edi, &double_elements); + + // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS + __ JumpIfSmi(eax, &smi_element); + __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear); + + // Store into the array literal requires a elements transition. Call into + // the runtime. + } + + __ bind(&slow_elements); + __ pop(edi); // Pop return address and remember to put back later for tail + // call. + __ push(ebx); + __ push(ecx); + __ push(eax); + __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); + __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); + __ push(edx); + __ push(edi); // Return return address so that tail call returns to right + // place. + __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); + + if (!FLAG_trace_elements_transitions) { + // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. + __ bind(&double_elements); + + __ push(edx); + __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset)); + __ StoreNumberToDoubleElements(eax, + edx, + ecx, + edi, + xmm0, + &slow_elements_from_double, + false); + __ pop(edx); + __ jmp(&element_done); + + __ bind(&slow_elements_from_double); + __ pop(edx); + __ jmp(&slow_elements); + + // 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, + FixedArrayBase::kHeaderSize)); + __ mov(Operand(ecx, 0), eax); + // Update the write barrier for the array store. + __ RecordWrite(ebx, ecx, eax, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ jmp(&element_done); + + // Array literal has ElementsKind of FAST_SMI_ONLY_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); + // Fall through + __ bind(&element_done); + __ ret(0); + } +} + #undef __ } } // namespace v8::internal diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 23cc5aba30..2a99eba5a1 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1539,60 +1539,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { // Store the subexpression value in the array's elements. __ mov(ebx, Operand(esp, 0)); // Copy of array literal. __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset)); - __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); - int offset = FixedArray::kHeaderSize + (i * kPointerSize); - - Label element_done; - Label double_elements; - Label smi_element; - Label slow_elements; - Label fast_elements; - __ CheckFastElements(edi, &double_elements); - - // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS - __ JumpIfSmi(result_register(), &smi_element); - __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear); - - // Store into the array literal requires a elements transition. Call into - // the runtime. - __ bind(&slow_elements); - __ push(Operand(esp, 0)); // Copy of array literal. - __ push(Immediate(Smi::FromInt(i))); - __ push(result_register()); - __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes - __ push(Immediate(Smi::FromInt(strict_mode_flag()))); // Strict mode. - __ CallRuntime(Runtime::kSetProperty, 5); - __ jmp(&element_done); - - // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. - __ bind(&double_elements); __ mov(ecx, Immediate(Smi::FromInt(i))); - __ StoreNumberToDoubleElements(result_register(), - ebx, - ecx, - edx, - xmm0, - &slow_elements, - false); - __ jmp(&element_done); - - // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. - __ bind(&fast_elements); - __ mov(FieldOperand(ebx, offset), result_register()); - // Update the write barrier for the array store. - __ RecordWriteField(ebx, offset, result_register(), ecx, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - __ jmp(&element_done); - - // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or - // FAST_ELEMENTS, and value is Smi. - __ bind(&smi_element); - __ mov(FieldOperand(ebx, offset), result_register()); - // Fall through - - __ bind(&element_done); + __ mov(edx, Immediate(Smi::FromInt(expr->literal_index()))); + StoreArrayLiteralElementStub stub; + __ CallStub(&stub); PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); } diff --git a/src/runtime.cc b/src/runtime.cc index 712509882a..08b944a8a1 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4689,6 +4689,44 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { + RUNTIME_ASSERT(args.length() == 5); + CONVERT_ARG_CHECKED(JSObject, object, 0); + CONVERT_SMI_ARG_CHECKED(store_index, 1); + Handle value = args.at(2); + CONVERT_ARG_CHECKED(FixedArray, literals, 3); + CONVERT_SMI_ARG_CHECKED(literal_index, 4); + HandleScope scope; + + Object* raw_boilerplate_object = literals->get(literal_index); + Handle boilerplate_object(JSArray::cast(raw_boilerplate_object)); +#if DEBUG + ElementsKind elements_kind = object->GetElementsKind(); +#endif + ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS); + // Smis should never trigger transitions. + ASSERT(!value->IsSmi()); + + if (value->IsNumber()) { + ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS); + TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS); + ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS); + 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); + TransitionElementsKind(object, FAST_ELEMENTS); + FixedArray* object_array = + FixedArray::cast(object->elements()); + object_array->set(store_index, *value); + } + return *object; +} + + // Set a local property, even if it is READ_ONLY. If the property does not // exist, it will be added with attributes NONE. RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { diff --git a/src/runtime.h b/src/runtime.h index 3dd03692a7..c411b306b1 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -98,6 +98,7 @@ namespace internal { F(SetNewFunctionAttributes, 1, 1) \ F(AllocateInNewSpace, 1, 1) \ F(SetNativeFlag, 1, 1) \ + F(StoreArrayLiteralElement, 5, 1) \ \ /* Array join support */ \ F(PushIfAbsent, 2, 1) \