From 56f3337ebc4bb95c76c5785306980f3fc3b11dc3 Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Wed, 5 Jun 2013 10:43:18 +0000 Subject: [PATCH] Adapt hydrogen-based Array constructor to also support InternalArray and function call versions. BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/14576005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14948 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/builtins-arm.cc | 50 +++++++---- src/arm/code-stubs-arm.cc | 163 +++++++++++++++++++++++++++++++++++- src/bootstrapper.cc | 10 ++- src/builtins-decls.h | 2 + src/builtins.cc | 65 +++++++++++---- src/code-stubs-hydrogen.cc | 199 +++++++++++++++++++++++++++++++------------- src/code-stubs.cc | 15 ++++ src/code-stubs.h | 99 ++++++++++++++++++++++ src/hydrogen-instructions.h | 4 + src/hydrogen.cc | 31 ++++++- src/hydrogen.h | 6 ++ src/ia32/builtins-ia32.cc | 48 +++++++---- src/ia32/code-stubs-ia32.cc | 165 +++++++++++++++++++++++++++++++++++- src/isolate.cc | 1 + src/mips/code-stubs-mips.cc | 6 +- src/type-info.cc | 16 ++-- src/x64/builtins-x64.cc | 48 +++++++---- src/x64/code-stubs-x64.cc | 165 +++++++++++++++++++++++++++++++++++- 18 files changed, 952 insertions(+), 141 deletions(-) diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 6333924..4d7bc8e 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -480,15 +480,20 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Run the native code for the InternalArray function called as a normal // function. - ArrayNativeCode(masm, &generic_array_code); - - // Jump to the generic array code if the specialized code cannot handle the - // construction. - __ bind(&generic_array_code); - - Handle array_code = - masm->isolate()->builtins()->InternalArrayCodeGeneric(); - __ Jump(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + InternalArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, &generic_array_code); + + // Jump to the generic array code if the specialized code cannot handle the + // construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->InternalArrayCodeGeneric(); + __ Jump(array_code, RelocInfo::CODE_TARGET); + } } @@ -513,15 +518,24 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } // Run the native code for the Array function called as a normal function. - ArrayNativeCode(masm, &generic_array_code); - - // Jump to the generic array code if the specialized code cannot handle - // the construction. - __ bind(&generic_array_code); - - Handle array_code = - masm->isolate()->builtins()->ArrayCodeGeneric(); - __ Jump(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + Handle undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + __ mov(r2, Operand(undefined_sentinel)); + ArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, &generic_array_code); + + // Jump to the generic array code if the specialized code cannot handle + // the construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->ArrayCodeGeneric(); + __ Jump(array_code, RelocInfo::CODE_TARGET); + } } diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 0227b25..d5b4816 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -150,6 +150,28 @@ static void InitializeArrayConstructorDescriptor( } +static void InitializeInternalArrayConstructorDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor, + int constant_stack_parameter_count) { + // register state + // r0 -- number of arguments + // r1 -- constructor function + static Register registers[] = { r1 }; + descriptor->register_param_count_ = 1; + + if (constant_stack_parameter_count != 0) { + // stack param count needs (constructor pointer, and single argument) + descriptor->stack_parameter_count_ = &r0; + } + descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; + descriptor->register_params_ = registers; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(InternalArrayConstructor_StubFailure); +} + + void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -184,6 +206,27 @@ void ToBooleanStub::InitializeInterfaceDescriptor( } +void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0); +} + + +void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1); +} + + +void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); +} + + #define __ ACCESS_MASM(masm) static void EmitIdenticalObjectComparison(MacroAssembler* masm, @@ -4745,7 +4788,11 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ b(ne, &slow); if (RecordCallTarget()) { - GenerateRecordCallTargetNoArray(masm); + if (FLAG_optimize_constructed_arrays) { + GenerateRecordCallTarget(masm); + } else { + GenerateRecordCallTargetNoArray(masm); + } } // Fast-case: Invoke the function now. @@ -7262,6 +7309,21 @@ void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { } +void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( + Isolate* isolate) { + ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS }; + for (int i = 0; i < 2; i++) { + // For internal arrays we only need a few things + InternalArrayNoArgumentConstructorStub stubh1(kinds[i]); + stubh1.GetCode(isolate)->set_is_pregenerated(true); + InternalArraySingleArgumentConstructorStub stubh2(kinds[i]); + stubh2.GetCode(isolate)->set_is_pregenerated(true); + InternalArrayNArgumentsConstructorStub stubh3(kinds[i]); + stubh3.GetCode(isolate)->set_is_pregenerated(true); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : argc (only if argument_count_ == ANY) @@ -7348,6 +7410,105 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { } +void InternalArrayConstructorStub::GenerateCase( + MacroAssembler* masm, ElementsKind kind) { + Label not_zero_case, not_one_case; + Label normal_sequence; + + __ tst(r0, r0); + __ b(ne, ¬_zero_case); + InternalArrayNoArgumentConstructorStub stub0(kind); + __ TailCallStub(&stub0); + + __ bind(¬_zero_case); + __ cmp(r0, Operand(1)); + __ b(gt, ¬_one_case); + + if (IsFastPackedElementsKind(kind)) { + // We might need to create a holey array + // look at the first argument + __ ldr(r3, MemOperand(sp, 0)); + __ cmp(r3, Operand::Zero()); + __ b(eq, &normal_sequence); + + InternalArraySingleArgumentConstructorStub + stub1_holey(GetHoleyElementsKind(kind)); + __ TailCallStub(&stub1_holey); + } + + __ bind(&normal_sequence); + InternalArraySingleArgumentConstructorStub stub1(kind); + __ TailCallStub(&stub1); + + __ bind(¬_one_case); + InternalArrayNArgumentsConstructorStub stubN(kind); + __ TailCallStub(&stubN); +} + + +void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : argc + // -- r1 : constructor + // -- sp[0] : return address + // -- sp[4] : last argument + // ----------------------------------- + + if (FLAG_debug_code) { + // The array construct code is only set for the global and natives + // builtin Array functions which always have maps. + + // Initial map for the builtin Array function should be a map. + __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); + // Will both indicate a NULL and a Smi. + __ tst(r3, Operand(kSmiTagMask)); + __ Assert(ne, "Unexpected initial map for Array function"); + __ CompareObjectType(r3, r3, r4, MAP_TYPE); + __ Assert(eq, "Unexpected initial map for Array function"); + } + + if (FLAG_optimize_constructed_arrays) { + // Figure out the right elements kind + __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); + + // Load the map's "bit field 2" into |result|. We only need the first byte, + // but the following bit field extraction takes care of that anyway. + __ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount); + + if (FLAG_debug_code) { + Label done; + __ cmp(r3, Operand(FAST_ELEMENTS)); + __ b(eq, &done); + __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS)); + __ Assert(eq, + "Invalid ElementsKind for InternalArray or InternalPackedArray"); + __ bind(&done); + } + + Label fast_elements_case; + __ cmp(r3, Operand(FAST_ELEMENTS)); + __ b(eq, &fast_elements_case); + GenerateCase(masm, FAST_HOLEY_ELEMENTS); + + __ bind(&fast_elements_case); + GenerateCase(masm, FAST_ELEMENTS); + } else { + Label generic_constructor; + // Run the native code for the Array function called as constructor. + ArrayNativeCode(masm, &generic_constructor); + + // Jump to the generic construct code in case the specialized code cannot + // handle the construction. + __ bind(&generic_constructor); + Handle generic_construct_stub = + masm->isolate()->builtins()->JSConstructStubGeneric(); + __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); + } +} + + #undef __ } } // namespace v8::internal diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 7077241..5ef8d30 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1611,8 +1611,14 @@ Handle Genesis::InstallInternalArray( factory()->NewJSObject(isolate()->object_function(), TENURED); SetPrototype(array_function, prototype); - array_function->shared()->set_construct_stub( - isolate()->builtins()->builtin(Builtins::kCommonArrayConstructCode)); + if (FLAG_optimize_constructed_arrays) { + InternalArrayConstructorStub internal_array_constructor_stub(isolate()); + Handle code = internal_array_constructor_stub.GetCode(isolate()); + array_function->shared()->set_construct_stub(*code); + } else { + array_function->shared()->set_construct_stub( + isolate()->builtins()->builtin(Builtins::kCommonArrayConstructCode)); + } array_function->shared()->DontAdaptArguments(); diff --git a/src/builtins-decls.h b/src/builtins-decls.h index beb5dd1..8c038dc 100644 --- a/src/builtins-decls.h +++ b/src/builtins-decls.h @@ -33,7 +33,9 @@ namespace v8 { namespace internal { +// TODO(mvstanton): move these to runtime.h/.cc DECLARE_RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure); +DECLARE_RUNTIME_FUNCTION(MaybeObject*, InternalArrayConstructor_StubFailure); } } // namespace v8::internal diff --git a/src/builtins.cc b/src/builtins.cc index 37ba1e5..5b2d9af 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -194,20 +194,11 @@ BUILTIN(EmptyFunction) { } -RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) { - // If we get 2 arguments then they are the stub parameters (constructor, type - // info). If we get 3, then the first one is a pointer to the arguments - // passed by the caller. - Arguments empty_args(0, NULL); - bool no_caller_args = args.length() == 2; - ASSERT(no_caller_args || args.length() == 3); - int parameters_start = no_caller_args ? 0 : 1; - Arguments* caller_args = no_caller_args - ? &empty_args - : reinterpret_cast(args[0]); - Handle constructor = args.at(parameters_start); - Handle type_info = args.at(parameters_start + 1); - +static MaybeObject* ArrayConstructorStubFailureCommon( + Isolate* isolate, + Handle constructor, + Handle type_info, + Arguments* caller_args) { bool holey = false; if (caller_args->length() == 1 && (*caller_args)[0]->IsSmi()) { int value = Smi::cast((*caller_args)[0])->value(); @@ -216,7 +207,8 @@ RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) { JSArray* array; MaybeObject* maybe_array; - if (*type_info != isolate->heap()->undefined_value() && + if (!type_info.is_null() && + *type_info != isolate->heap()->undefined_value() && JSGlobalPropertyCell::cast(*type_info)->value()->IsSmi()) { JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(*type_info); Smi* smi = Smi::cast(cell->value()); @@ -231,12 +223,11 @@ RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) { *constructor, type_info); if (!maybe_array->To(&array)) return maybe_array; } else { - ElementsKind kind = constructor->initial_map()->elements_kind(); - ASSERT(kind == GetInitialFastElementsKind()); maybe_array = isolate->heap()->AllocateJSObject(*constructor); if (!maybe_array->To(&array)) return maybe_array; // We might need to transition to holey - if (holey) { + ElementsKind kind = constructor->initial_map()->elements_kind(); + if (holey && !IsFastHoleyElementsKind(kind)) { kind = GetHoleyElementsKind(kind); maybe_array = array->TransitionElementsKind(kind); if (maybe_array->IsFailure()) return maybe_array; @@ -252,6 +243,44 @@ RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) { } +RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) { + // If we get 2 arguments then they are the stub parameters (constructor, type + // info). If we get 3, then the first one is a pointer to the arguments + // passed by the caller. + Arguments empty_args(0, NULL); + bool no_caller_args = args.length() == 2; + ASSERT(no_caller_args || args.length() == 3); + int parameters_start = no_caller_args ? 0 : 1; + Arguments* caller_args = no_caller_args + ? &empty_args + : reinterpret_cast(args[0]); + Handle constructor = args.at(parameters_start); + Handle type_info = args.at(parameters_start + 1); + + return ArrayConstructorStubFailureCommon(isolate, + constructor, + type_info, + caller_args); +} + + +RUNTIME_FUNCTION(MaybeObject*, InternalArrayConstructor_StubFailure) { + Arguments empty_args(0, NULL); + bool no_caller_args = args.length() == 1; + ASSERT(no_caller_args || args.length() == 2); + int parameters_start = no_caller_args ? 0 : 1; + Arguments* caller_args = no_caller_args + ? &empty_args + : reinterpret_cast(args[0]); + Handle constructor = args.at(parameters_start); + + return ArrayConstructorStubFailureCommon(isolate, + constructor, + Handle::null(), + caller_args); +} + + static MaybeObject* ArrayCodeGenericCommon(Arguments* args, Isolate* isolate, JSFunction* constructor) { diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 77657c0..4be21c3 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -99,7 +99,23 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { IfBuilder checker_; }; + enum ArgumentClass { + NONE, + SINGLE, + MULTIPLE + }; + + HValue* BuildArrayConstructor(ElementsKind kind, + bool disable_allocation_sites, + ArgumentClass argument_class); + HValue* BuildInternalArrayConstructor(ElementsKind kind, + ArgumentClass argument_class); + private: + HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); + HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, + ElementsKind kind); + SmartArrayPointer parameters_; HValue* arguments_length_; CompilationInfoWithZone info_; @@ -520,40 +536,56 @@ Handle TransitionElementsKindStub::GenerateCode() { return DoGenerateCode(this); } - -template <> -HValue* CodeStubGraphBuilder::BuildCodeStub() { - // ----------- S t a t e ------------- - // -- Parameter 1 : type info cell - // -- Parameter 0 : constructor - // ----------------------------------- +HValue* CodeStubGraphBuilderBase::BuildArrayConstructor( + ElementsKind kind, bool disable_allocation_sites, + ArgumentClass argument_class) { + HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor); + HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell); HInstruction* array_function = BuildGetArrayFunction(context()); - ArrayContextChecker(this, - GetParameter(ArrayConstructorStubBase::kConstructor), - array_function); - // Get the right map - // Should be a constant - JSArrayBuilder array_builder( - this, - casted_stub()->elements_kind(), - GetParameter(ArrayConstructorStubBase::kPropertyCell), - casted_stub()->disable_allocation_sites()); - return array_builder.AllocateEmptyArray(); + + ArrayContextChecker(this, constructor, array_function); + JSArrayBuilder array_builder(this, kind, property_cell, + disable_allocation_sites); + HValue* result = NULL; + switch (argument_class) { + case NONE: + result = array_builder.AllocateEmptyArray(); + break; + case SINGLE: + result = BuildArraySingleArgumentConstructor(&array_builder); + break; + case MULTIPLE: + result = BuildArrayNArgumentsConstructor(&array_builder, kind); + break; + } + return result; } -Handle ArrayNoArgumentConstructorStub::GenerateCode() { - return DoGenerateCode(this); +HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor( + ElementsKind kind, ArgumentClass argument_class) { + HValue* constructor = GetParameter( + InternalArrayConstructorStubBase::kConstructor); + JSArrayBuilder array_builder(this, kind, constructor); + + HValue* result = NULL; + switch (argument_class) { + case NONE: + result = array_builder.AllocateEmptyArray(); + break; + case SINGLE: + result = BuildArraySingleArgumentConstructor(&array_builder); + break; + case MULTIPLE: + result = BuildArrayNArgumentsConstructor(&array_builder, kind); + break; + } + return result; } -template <> -HValue* CodeStubGraphBuilder:: - BuildCodeStub() { - HInstruction* array_function = BuildGetArrayFunction(context()); - ArrayContextChecker(this, - GetParameter(ArrayConstructorStubBase::kConstructor), - array_function); +HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor( + JSArrayBuilder* array_builder) { // Smi check and range check on the input arg. HValue* constant_one = graph()->GetConstant1(); HValue* constant_zero = graph()->GetConstant0(); @@ -584,46 +616,23 @@ HValue* CodeStubGraphBuilder:: // Figure out total size HValue* length = Pop(); HValue* capacity = Pop(); - - JSArrayBuilder array_builder( - this, - casted_stub()->elements_kind(), - GetParameter(ArrayConstructorStubBase::kPropertyCell), - casted_stub()->disable_allocation_sites()); - return array_builder.AllocateArray(capacity, length, true); -} - - -Handle ArraySingleArgumentConstructorStub::GenerateCode() { - return DoGenerateCode(this); + return array_builder->AllocateArray(capacity, length, true); } -template <> -HValue* CodeStubGraphBuilder::BuildCodeStub() { - HInstruction* array_function = BuildGetArrayFunction(context()); - ArrayContextChecker(this, - GetParameter(ArrayConstructorStubBase::kConstructor), - array_function); - ElementsKind kind = casted_stub()->elements_kind(); - HValue* length = GetArgumentsLength(); - - JSArrayBuilder array_builder( - this, - kind, - GetParameter(ArrayConstructorStubBase::kPropertyCell), - casted_stub()->disable_allocation_sites()); - +HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor( + JSArrayBuilder* array_builder, ElementsKind kind) { // We need to fill with the hole if it's a smi array in the multi-argument // case because we might have to bail out while copying arguments into // the array because they aren't compatible with a smi array. // If it's a double array, no problem, and if it's fast then no // problem either because doubles are boxed. + HValue* length = GetArgumentsLength(); bool fill_with_hole = IsFastSmiElementsKind(kind); - HValue* new_object = array_builder.AllocateArray(length, - length, - fill_with_hole); - HValue* elements = array_builder.GetElementsLocation(); + HValue* new_object = array_builder->AllocateArray(length, + length, + fill_with_hole); + HValue* elements = array_builder->GetElementsLocation(); ASSERT(elements != NULL); // Now populate the elements correctly. @@ -643,12 +652,86 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { } +template <> +HValue* CodeStubGraphBuilder::BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + bool disable_allocation_sites = casted_stub()->disable_allocation_sites(); + return BuildArrayConstructor(kind, disable_allocation_sites, NONE); +} + + +Handle ArrayNoArgumentConstructorStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> +HValue* CodeStubGraphBuilder:: + BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + bool disable_allocation_sites = casted_stub()->disable_allocation_sites(); + return BuildArrayConstructor(kind, disable_allocation_sites, SINGLE); +} + + +Handle ArraySingleArgumentConstructorStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> +HValue* CodeStubGraphBuilder::BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + bool disable_allocation_sites = casted_stub()->disable_allocation_sites(); + return BuildArrayConstructor(kind, disable_allocation_sites, MULTIPLE); +} + + Handle ArrayNArgumentsConstructorStub::GenerateCode() { return DoGenerateCode(this); } template <> +HValue* CodeStubGraphBuilder:: + BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + return BuildInternalArrayConstructor(kind, NONE); +} + + +Handle InternalArrayNoArgumentConstructorStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> +HValue* CodeStubGraphBuilder:: + BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + return BuildInternalArrayConstructor(kind, SINGLE); +} + + +Handle InternalArraySingleArgumentConstructorStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> +HValue* CodeStubGraphBuilder:: + BuildCodeStub() { + ElementsKind kind = casted_stub()->elements_kind(); + return BuildInternalArrayConstructor(kind, MULTIPLE); +} + + +Handle InternalArrayNArgumentsConstructorStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> HValue* CodeStubGraphBuilder::BuildCodeInitializedStub() { CompareNilICStub* stub = casted_stub(); HIfContinuation continuation; diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 882d743..4c6ee86 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -777,4 +777,19 @@ ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate, } +void InternalArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) { + InternalArrayNoArgumentConstructorStub stub1(FAST_ELEMENTS); + InstallDescriptor(isolate, &stub1); + InternalArraySingleArgumentConstructorStub stub2(FAST_ELEMENTS); + InstallDescriptor(isolate, &stub2); + InternalArrayNArgumentsConstructorStub stub3(FAST_ELEMENTS); + InstallDescriptor(isolate, &stub3); +} + +InternalArrayConstructorStub::InternalArrayConstructorStub( + Isolate* isolate) { + InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); +} + + } } // namespace v8::internal diff --git a/src/code-stubs.h b/src/code-stubs.h index 5a5abcb..ad1f09b 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -77,6 +77,9 @@ namespace internal { V(ArrayNoArgumentConstructor) \ V(ArraySingleArgumentConstructor) \ V(ArrayNArgumentsConstructor) \ + V(InternalArrayNoArgumentConstructor) \ + V(InternalArraySingleArgumentConstructor) \ + V(InternalArrayNArgumentsConstructor) \ V(KeyedStoreElement) \ V(DebuggerStatement) \ V(NameDictionaryLookup) \ @@ -85,6 +88,7 @@ namespace internal { V(StoreArrayLiteralElement) \ V(StubFailureTrampoline) \ V(ArrayConstructor) \ + V(InternalArrayConstructor) \ V(ProfileEntryHook) \ /* IC Handler stubs */ \ V(LoadField) \ @@ -670,6 +674,20 @@ class ArrayConstructorStub: public PlatformCodeStub { }; +class InternalArrayConstructorStub: public PlatformCodeStub { + public: + explicit InternalArrayConstructorStub(Isolate* isolate); + + void Generate(MacroAssembler* masm); + + private: + virtual CodeStub::Major MajorKey() { return InternalArrayConstructor; } + virtual int MinorKey() { return 0; } + + void GenerateCase(MacroAssembler* masm, ElementsKind kind); +}; + + class MathPowStub: public PlatformCodeStub { public: enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK }; @@ -1826,6 +1844,87 @@ class ArrayNArgumentsConstructorStub : public ArrayConstructorStubBase { }; +class InternalArrayConstructorStubBase : public HydrogenCodeStub { + public: + explicit InternalArrayConstructorStubBase(ElementsKind kind) { + kind_ = kind; + } + + virtual bool IsPregenerated() { return true; } + static void GenerateStubsAheadOfTime(Isolate* isolate); + static void InstallDescriptors(Isolate* isolate); + + // Parameters accessed via CodeStubGraphBuilder::GetParameter() + static const int kConstructor = 0; + + ElementsKind elements_kind() const { return kind_; } + + private: + int NotMissMinorKey() { return kind_; } + + ElementsKind kind_; + + DISALLOW_COPY_AND_ASSIGN(InternalArrayConstructorStubBase); +}; + + +class InternalArrayNoArgumentConstructorStub : public + InternalArrayConstructorStubBase { + public: + explicit InternalArrayNoArgumentConstructorStub(ElementsKind kind) + : InternalArrayConstructorStubBase(kind) { } + + virtual Handle GenerateCode(); + + virtual void InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor); + + private: + Major MajorKey() { return InternalArrayNoArgumentConstructor; } + + DISALLOW_COPY_AND_ASSIGN(InternalArrayNoArgumentConstructorStub); +}; + + +class InternalArraySingleArgumentConstructorStub : public + InternalArrayConstructorStubBase { + public: + explicit InternalArraySingleArgumentConstructorStub(ElementsKind kind) + : InternalArrayConstructorStubBase(kind) { } + + virtual Handle GenerateCode(); + + virtual void InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor); + + private: + Major MajorKey() { return InternalArraySingleArgumentConstructor; } + + DISALLOW_COPY_AND_ASSIGN(InternalArraySingleArgumentConstructorStub); +}; + + +class InternalArrayNArgumentsConstructorStub : public + InternalArrayConstructorStubBase { + public: + explicit InternalArrayNArgumentsConstructorStub(ElementsKind kind) + : InternalArrayConstructorStubBase(kind) { } + + virtual Handle GenerateCode(); + + virtual void InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor); + + private: + Major MajorKey() { return InternalArrayNArgumentsConstructor; } + + DISALLOW_COPY_AND_ASSIGN(InternalArrayNArgumentsConstructorStub); +}; + + class KeyedStoreElementStub : public PlatformCodeStub { public: KeyedStoreElementStub(bool is_js_array, diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index aa8b2c0..4a8a406 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -5246,6 +5246,10 @@ class HObjectAccess { return HObjectAccess(kInobject, JSObject::kPropertiesOffset); } + static HObjectAccess ForPrototypeOrInitialMap() { + return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); + } + static HObjectAccess ForMap() { return HObjectAccess(kMaps, JSObject::kMapOffset); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 2093db4..85a7534 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -1789,13 +1789,25 @@ HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, bool disable_allocation_sites) : builder_(builder), kind_(kind), - allocation_site_payload_(allocation_site_payload) { + allocation_site_payload_(allocation_site_payload), + constructor_function_(NULL) { mode_ = disable_allocation_sites ? DONT_TRACK_ALLOCATION_SITE : AllocationSiteInfo::GetMode(kind); } +HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, + ElementsKind kind, + HValue* constructor_function) : + builder_(builder), + kind_(kind), + mode_(DONT_TRACK_ALLOCATION_SITE), + allocation_site_payload_(NULL), + constructor_function_(constructor_function) { +} + + HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) { HInstruction* native_context = builder()->BuildGetNativeContext(context); @@ -1813,6 +1825,16 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) { } +HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { + // Find the map near the constructor function + HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); + return AddInstruction( + builder()->BuildLoadNamedField(constructor_function_, + access, + Representation::Tagged())); +} + + HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( HValue* length_node) { HValue* context = builder()->environment()->LookupContext(); @@ -1899,7 +1921,12 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, AddInstruction(new_object); // Fill in the fields: map, properties, length - HValue* map = EmitMapCode(context); + HValue* map; + if (constructor_function_ != NULL) { + map = EmitInternalMapCode(); + } else { + map = EmitMapCode(context); + } elements_location_ = builder()->BuildJSArrayHeader(new_object, map, mode_, diff --git a/src/hydrogen.h b/src/hydrogen.h index 78f9ac1..db607d5 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -1262,6 +1262,10 @@ class HGraphBuilder { HValue* allocation_site_payload, bool disable_allocation_sites); + JSArrayBuilder(HGraphBuilder* builder, + ElementsKind kind, + HValue* constructor_function); + HValue* AllocateEmptyArray(); HValue* AllocateArray(HValue* capacity, HValue* length_field, bool fill_with_hole); @@ -1283,6 +1287,7 @@ class HGraphBuilder { } HValue* EmitMapCode(HValue* context); + HValue* EmitInternalMapCode(); HValue* EstablishEmptyArrayAllocationSize(); HValue* EstablishAllocationSize(HValue* length_node); HValue* AllocateArray(HValue* size_in_bytes, HValue* capacity, @@ -1292,6 +1297,7 @@ class HGraphBuilder { ElementsKind kind_; AllocationSiteMode mode_; HValue* allocation_site_payload_; + HValue* constructor_function_; HInnerAllocatedObject* elements_location_; }; diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 4420102..bf4ee94 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -1459,14 +1459,20 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Run the native code for the InternalArray function called as a normal // function. - ArrayNativeCode(masm, false, &generic_array_code); - - // Jump to the generic internal array code in case the specialized code cannot - // handle the construction. - __ bind(&generic_array_code); - Handle array_code = - masm->isolate()->builtins()->InternalArrayCodeGeneric(); - __ jmp(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + InternalArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, false, &generic_array_code); + + // Jump to the generic internal array code in case the specialized code + // cannot handle the construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->InternalArrayCodeGeneric(); + __ jmp(array_code, RelocInfo::CODE_TARGET); + } } @@ -1492,14 +1498,24 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } // Run the native code for the Array function called as a normal function. - ArrayNativeCode(masm, false, &generic_array_code); - - // Jump to the generic array code in case the specialized code cannot handle - // the construction. - __ bind(&generic_array_code); - Handle array_code = - masm->isolate()->builtins()->ArrayCodeGeneric(); - __ jmp(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + Handle undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + __ mov(ebx, Immediate(undefined_sentinel)); + ArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, false, &generic_array_code); + + // Jump to the generic internal array code in case the specialized code + // cannot handle the construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->ArrayCodeGeneric(); + __ jmp(array_code, RelocInfo::CODE_TARGET); + } } diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 40af087..8cb4725 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -142,6 +142,28 @@ static void InitializeArrayConstructorDescriptor( } +static void InitializeInternalArrayConstructorDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor, + int constant_stack_parameter_count) { + // register state + // eax -- number of arguments + // edi -- constructor function + static Register registers[] = { edi }; + descriptor->register_param_count_ = 1; + + if (constant_stack_parameter_count != 0) { + // stack param count needs (constructor pointer, and single argument) + descriptor->stack_parameter_count_ = &eax; + } + descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; + descriptor->register_params_ = registers; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(InternalArrayConstructor_StubFailure); +} + + void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -163,6 +185,27 @@ void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( } +void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0); +} + + +void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1); +} + + +void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); +} + + void CompareNilICStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -4782,7 +4825,11 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ j(not_equal, &slow); if (RecordCallTarget()) { - GenerateRecordCallTargetNoArray(masm); + if (FLAG_optimize_constructed_arrays) { + GenerateRecordCallTarget(masm); + } else { + GenerateRecordCallTargetNoArray(masm); + } } // Fast-case: Just invoke the function. @@ -7843,6 +7890,21 @@ void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { } +void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( + Isolate* isolate) { + ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS }; + for (int i = 0; i < 2; i++) { + // For internal arrays we only need a few things + InternalArrayNoArgumentConstructorStub stubh1(kinds[i]); + stubh1.GetCode(isolate)->set_is_pregenerated(true); + InternalArraySingleArgumentConstructorStub stubh2(kinds[i]); + stubh2.GetCode(isolate)->set_is_pregenerated(true); + InternalArrayNArgumentsConstructorStub stubh3(kinds[i]); + stubh3.GetCode(isolate)->set_is_pregenerated(true); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : argc (only if argument_count_ == ANY) @@ -7928,6 +7990,107 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { } +void InternalArrayConstructorStub::GenerateCase( + MacroAssembler* masm, ElementsKind kind) { + Label not_zero_case, not_one_case; + Label normal_sequence; + + __ test(eax, eax); + __ j(not_zero, ¬_zero_case); + InternalArrayNoArgumentConstructorStub stub0(kind); + __ TailCallStub(&stub0); + + __ bind(¬_zero_case); + __ cmp(eax, 1); + __ j(greater, ¬_one_case); + + if (IsFastPackedElementsKind(kind)) { + // We might need to create a holey array + // look at the first argument + __ mov(ecx, Operand(esp, kPointerSize)); + __ test(ecx, ecx); + __ j(zero, &normal_sequence); + + InternalArraySingleArgumentConstructorStub + stub1_holey(GetHoleyElementsKind(kind)); + __ TailCallStub(&stub1_holey); + } + + __ bind(&normal_sequence); + InternalArraySingleArgumentConstructorStub stub1(kind); + __ TailCallStub(&stub1); + + __ bind(¬_one_case); + InternalArrayNArgumentsConstructorStub stubN(kind); + __ TailCallStub(&stubN); +} + + +void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : argc + // -- ebx : type info cell + // -- edi : constructor + // -- esp[0] : return address + // -- esp[4] : last argument + // ----------------------------------- + + if (FLAG_debug_code) { + // The array construct code is only set for the global and natives + // builtin Array functions which always have maps. + + // Initial map for the builtin Array function should be a map. + __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); + // Will both indicate a NULL and a Smi. + __ test(ecx, Immediate(kSmiTagMask)); + __ Assert(not_zero, "Unexpected initial map for Array function"); + __ CmpObjectType(ecx, MAP_TYPE, ecx); + __ Assert(equal, "Unexpected initial map for Array function"); + } + + if (FLAG_optimize_constructed_arrays) { + // Figure out the right elements kind + __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); + + // Load the map's "bit field 2" into |result|. We only need the first byte, + // but the following masking takes care of that anyway. + __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ and_(ecx, Map::kElementsKindMask); + __ shr(ecx, Map::kElementsKindShift); + + if (FLAG_debug_code) { + Label done; + __ cmp(ecx, Immediate(FAST_ELEMENTS)); + __ j(equal, &done); + __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS)); + __ Assert(equal, + "Invalid ElementsKind for InternalArray or InternalPackedArray"); + __ bind(&done); + } + + Label fast_elements_case; + __ cmp(ecx, Immediate(FAST_ELEMENTS)); + __ j(equal, &fast_elements_case); + GenerateCase(masm, FAST_HOLEY_ELEMENTS); + + __ bind(&fast_elements_case); + GenerateCase(masm, FAST_ELEMENTS); + } else { + Label generic_constructor; + // Run the native code for the Array function called as constructor. + ArrayNativeCode(masm, true, &generic_constructor); + + // Jump to the generic construct code in case the specialized code cannot + // handle the construction. + __ bind(&generic_constructor); + Handle generic_construct_stub = + masm->isolate()->builtins()->JSConstructStubGeneric(); + __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); + } +} + + #undef __ } } // namespace v8::internal diff --git a/src/isolate.cc b/src/isolate.cc index 1ae4bce..7cce14a 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -2251,6 +2251,7 @@ bool Isolate::Init(Deserializer* des) { CompareNilICStub::InitializeForIsolate(this); ToBooleanStub::InitializeForIsolate(this); ArrayConstructorStubBase::InstallDescriptors(this); + InternalArrayConstructorStubBase::InstallDescriptors(this); } if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Start(); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 08f6f71..89017f1 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -5128,7 +5128,11 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE)); if (RecordCallTarget()) { - GenerateRecordCallTargetNoArray(masm); + if (FLAG_optimize_constructed_arrays) { + GenerateRecordCallTarget(masm); + } else { + GenerateRecordCallTargetNoArray(masm); + } } // Fast-case: Invoke the function now. diff --git a/src/type-info.cc b/src/type-info.cc index 6c04eac..b284062 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -168,12 +168,7 @@ bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) { Handle info = GetInfo(expr->CallNewFeedbackId()); - if (info->IsSmi()) { - ASSERT(static_cast(Smi::cast(*info)->value()) <= - LAST_FAST_ELEMENTS_KIND); - return isolate_->global_context()->array_function(); - } - return info->IsJSFunction(); + return info->IsSmi() || info->IsJSFunction(); } @@ -298,7 +293,14 @@ CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { Handle TypeFeedbackOracle::GetCallTarget(Call* expr) { - return Handle::cast(GetInfo(expr->CallFeedbackId())); + Handle info = GetInfo(expr->CallFeedbackId()); + if (info->IsSmi()) { + ASSERT(static_cast(Smi::cast(*info)->value()) <= + LAST_FAST_ELEMENTS_KIND); + return Handle(isolate_->global_context()->array_function()); + } else { + return Handle::cast(info); + } } diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index b1b99b4..2a01b0b 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -1477,14 +1477,20 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Run the native code for the InternalArray function called as a normal // function. - ArrayNativeCode(masm, &generic_array_code); - - // Jump to the generic array code in case the specialized code cannot handle - // the construction. - __ bind(&generic_array_code); - Handle array_code = - masm->isolate()->builtins()->InternalArrayCodeGeneric(); - __ Jump(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + InternalArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, &generic_array_code); + + // Jump to the generic array code in case the specialized code cannot handle + // the construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->InternalArrayCodeGeneric(); + __ Jump(array_code, RelocInfo::CODE_TARGET); + } } @@ -1511,14 +1517,24 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { } // Run the native code for the Array function called as a normal function. - ArrayNativeCode(masm, &generic_array_code); - - // Jump to the generic array code in case the specialized code cannot handle - // the construction. - __ bind(&generic_array_code); - Handle array_code = - masm->isolate()->builtins()->ArrayCodeGeneric(); - __ Jump(array_code, RelocInfo::CODE_TARGET); + if (FLAG_optimize_constructed_arrays) { + // tail call a stub + Handle undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + __ Move(rbx, undefined_sentinel); + ArrayConstructorStub stub(masm->isolate()); + __ TailCallStub(&stub); + } else { + ArrayNativeCode(masm, &generic_array_code); + + // Jump to the generic array code in case the specialized code cannot handle + // the construction. + __ bind(&generic_array_code); + Handle array_code = + masm->isolate()->builtins()->ArrayCodeGeneric(); + __ Jump(array_code, RelocInfo::CODE_TARGET); + } } diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 0efd8c8..f5d38f3 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -137,6 +137,28 @@ static void InitializeArrayConstructorDescriptor( } +static void InitializeInternalArrayConstructorDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor, + int constant_stack_parameter_count) { + // register state + // rax -- number of arguments + // rdi -- constructor function + static Register registers[] = { rdi }; + descriptor->register_param_count_ = 1; + + if (constant_stack_parameter_count != 0) { + // stack param count needs (constructor pointer, and single argument) + descriptor->stack_parameter_count_ = &rax; + } + descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; + descriptor->register_params_ = registers; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(InternalArrayConstructor_StubFailure); +} + + void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -158,6 +180,27 @@ void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( } +void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0); +} + + +void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1); +} + + +void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); +} + + void CompareNilICStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -3818,7 +3861,11 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ j(not_equal, &slow); if (RecordCallTarget()) { - GenerateRecordCallTargetNoArray(masm); + if (FLAG_optimize_constructed_arrays) { + GenerateRecordCallTarget(masm); + } else { + GenerateRecordCallTargetNoArray(masm); + } } // Fast-case: Just invoke the function. @@ -6848,6 +6895,20 @@ void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { } +void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( + Isolate* isolate) { + ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS }; + for (int i = 0; i < 2; i++) { + // For internal arrays we only need a few things + InternalArrayNoArgumentConstructorStub stubh1(kinds[i]); + stubh1.GetCode(isolate)->set_is_pregenerated(true); + InternalArraySingleArgumentConstructorStub stubh2(kinds[i]); + stubh2.GetCode(isolate)->set_is_pregenerated(true); + InternalArrayNArgumentsConstructorStub stubh3(kinds[i]); + stubh3.GetCode(isolate)->set_is_pregenerated(true); + } +} + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- @@ -6935,6 +6996,108 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { } +void InternalArrayConstructorStub::GenerateCase( + MacroAssembler* masm, ElementsKind kind) { + Label not_zero_case, not_one_case; + Label normal_sequence; + + __ testq(rax, rax); + __ j(not_zero, ¬_zero_case); + InternalArrayNoArgumentConstructorStub stub0(kind); + __ TailCallStub(&stub0); + + __ bind(¬_zero_case); + __ cmpl(rax, Immediate(1)); + __ j(greater, ¬_one_case); + + if (IsFastPackedElementsKind(kind)) { + // We might need to create a holey array + // look at the first argument + __ movq(rcx, Operand(rsp, kPointerSize)); + __ testq(rcx, rcx); + __ j(zero, &normal_sequence); + + InternalArraySingleArgumentConstructorStub + stub1_holey(GetHoleyElementsKind(kind)); + __ TailCallStub(&stub1_holey); + } + + __ bind(&normal_sequence); + InternalArraySingleArgumentConstructorStub stub1(kind); + __ TailCallStub(&stub1); + + __ bind(¬_one_case); + InternalArrayNArgumentsConstructorStub stubN(kind); + __ TailCallStub(&stubN); +} + + +void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : argc + // -- ebx : type info cell + // -- edi : constructor + // -- esp[0] : return address + // -- esp[4] : last argument + // ----------------------------------- + + if (FLAG_debug_code) { + // The array construct code is only set for the global and natives + // builtin Array functions which always have maps. + + // Initial map for the builtin Array function should be a map. + __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); + // Will both indicate a NULL and a Smi. + STATIC_ASSERT(kSmiTag == 0); + Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); + __ Check(not_smi, "Unexpected initial map for Array function"); + __ CmpObjectType(rcx, MAP_TYPE, rcx); + __ Check(equal, "Unexpected initial map for Array function"); + } + + if (FLAG_optimize_constructed_arrays) { + // Figure out the right elements kind + __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); + + // Load the map's "bit field 2" into |result|. We only need the first byte, + // but the following masking takes care of that anyway. + __ movzxbq(rcx, FieldOperand(rcx, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ and_(rcx, Immediate(Map::kElementsKindMask)); + __ shr(rcx, Immediate(Map::kElementsKindShift)); + + if (FLAG_debug_code) { + Label done; + __ cmpl(rcx, Immediate(FAST_ELEMENTS)); + __ j(equal, &done); + __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS)); + __ Assert(equal, + "Invalid ElementsKind for InternalArray or InternalPackedArray"); + __ bind(&done); + } + + Label fast_elements_case; + __ cmpl(rcx, Immediate(FAST_ELEMENTS)); + __ j(equal, &fast_elements_case); + GenerateCase(masm, FAST_HOLEY_ELEMENTS); + + __ bind(&fast_elements_case); + GenerateCase(masm, FAST_ELEMENTS); + } else { + Label generic_constructor; + // Run the native code for the Array function called as constructor. + ArrayNativeCode(masm, &generic_constructor); + + // Jump to the generic construct code in case the specialized code cannot + // handle the construction. + __ bind(&generic_constructor); + Handle generic_construct_stub = + masm->isolate()->builtins()->JSConstructStubGeneric(); + __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); + } +} + + #undef __ } } // namespace v8::internal -- 2.7.4