| // Copyright 2014 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/code-factory.h" | |
| #include "src/bootstrapper.h" | |
| #include "src/builtins/builtins-descriptors.h" | |
| #include "src/ic/ic.h" | |
| #include "src/objects-inl.h" | |
| namespace v8 { | |
| namespace internal { | |
| namespace { | |
| // TODO(ishell): make it (const Stub& stub) once CodeStub::GetCode() is const. | |
| template <typename Stub> | |
| Callable make_callable(Stub& stub) { | |
| typedef typename Stub::Descriptor Descriptor; | |
| return Callable(stub.GetCode(), Descriptor{}); | |
| } | |
| } // namespace | |
| // static | |
| Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) { | |
| return CodeFactory::CEntry(isolate, result_size); | |
| } | |
| #define CENTRY_CODE(RS, SD, AM, BE) \ | |
| BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE) | |
| // static | |
| Handle<Code> CodeFactory::CEntry(Isolate* isolate, int result_size, | |
| SaveFPRegsMode save_doubles, | |
| ArgvMode argv_mode, bool builtin_exit_frame) { | |
| // Aliases for readability below. | |
| const int rs = result_size; | |
| const SaveFPRegsMode sd = save_doubles; | |
| const ArgvMode am = argv_mode; | |
| const bool be = builtin_exit_frame; | |
| if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) { | |
| return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); | |
| } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) { | |
| return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit); | |
| } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) { | |
| return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); | |
| } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && !be) { | |
| return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit); | |
| } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && be) { | |
| return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit); | |
| } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) { | |
| return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); | |
| } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) { | |
| return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit); | |
| } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) { | |
| return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); | |
| } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && !be) { | |
| return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit); | |
| } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && be) { | |
| return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit); | |
| } | |
| UNREACHABLE(); | |
| } | |
| #undef CENTRY_CODE | |
| // static | |
| Callable CodeFactory::ApiGetter(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallApiGetter), ApiGetterDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallApiCallback(Isolate* isolate, int argc) { | |
| switch (argc) { | |
| case 0: | |
| return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc0), | |
| ApiCallbackDescriptor{}); | |
| case 1: | |
| return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc1), | |
| ApiCallbackDescriptor{}); | |
| default: { | |
| CallApiCallbackStub stub(isolate, argc); | |
| return make_callable(stub); | |
| } | |
| } | |
| UNREACHABLE(); | |
| } | |
| // static | |
| Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) { | |
| return Callable( | |
| typeof_mode == NOT_INSIDE_TYPEOF | |
| ? BUILTIN_CODE(isolate, LoadGlobalICTrampoline) | |
| : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeofTrampoline), | |
| LoadGlobalDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate, | |
| TypeofMode typeof_mode) { | |
| return Callable(typeof_mode == NOT_INSIDE_TYPEOF | |
| ? BUILTIN_CODE(isolate, LoadGlobalIC) | |
| : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeof), | |
| LoadGlobalWithVectorDescriptor{}); | |
| } | |
| Callable CodeFactory::StoreOwnIC(Isolate* isolate) { | |
| // TODO(ishell): Currently we use StoreOwnIC only for storing properties that | |
| // already exist in the boilerplate therefore we can use StoreIC. | |
| return Callable(BUILTIN_CODE(isolate, StoreICTrampoline), StoreDescriptor{}); | |
| } | |
| Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) { | |
| // TODO(ishell): Currently we use StoreOwnIC only for storing properties that | |
| // already exist in the boilerplate therefore we can use StoreIC. | |
| return Callable(BUILTIN_CODE(isolate, StoreIC), StoreWithVectorDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) { | |
| switch (op) { | |
| case Operation::kShiftRight: | |
| return Builtins::CallableFor(isolate, Builtins::kShiftRight); | |
| case Operation::kShiftLeft: | |
| return Builtins::CallableFor(isolate, Builtins::kShiftLeft); | |
| case Operation::kShiftRightLogical: | |
| return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical); | |
| case Operation::kAdd: | |
| return Builtins::CallableFor(isolate, Builtins::kAdd); | |
| case Operation::kSubtract: | |
| return Builtins::CallableFor(isolate, Builtins::kSubtract); | |
| case Operation::kMultiply: | |
| return Builtins::CallableFor(isolate, Builtins::kMultiply); | |
| case Operation::kDivide: | |
| return Builtins::CallableFor(isolate, Builtins::kDivide); | |
| case Operation::kModulus: | |
| return Builtins::CallableFor(isolate, Builtins::kModulus); | |
| case Operation::kBitwiseOr: | |
| return Builtins::CallableFor(isolate, Builtins::kBitwiseOr); | |
| case Operation::kBitwiseAnd: | |
| return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd); | |
| case Operation::kBitwiseXor: | |
| return Builtins::CallableFor(isolate, Builtins::kBitwiseXor); | |
| default: | |
| break; | |
| } | |
| UNREACHABLE(); | |
| } | |
| // static | |
| Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate, | |
| ToPrimitiveHint hint) { | |
| return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint), | |
| TypeConversionDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate, | |
| OrdinaryToPrimitiveHint hint) { | |
| return Callable(isolate->builtins()->OrdinaryToPrimitive(hint), | |
| TypeConversionDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags, | |
| PretenureFlag pretenure_flag) { | |
| if (pretenure_flag == NOT_TENURED) { | |
| switch (flags) { | |
| case STRING_ADD_CHECK_NONE: | |
| return Builtins::CallableFor(isolate, | |
| Builtins::kStringAdd_CheckNone_NotTenured); | |
| case STRING_ADD_CONVERT_LEFT: | |
| return Builtins::CallableFor( | |
| isolate, Builtins::kStringAdd_ConvertLeft_NotTenured); | |
| case STRING_ADD_CONVERT_RIGHT: | |
| return Builtins::CallableFor( | |
| isolate, Builtins::kStringAdd_ConvertRight_NotTenured); | |
| } | |
| } else { | |
| CHECK_EQ(TENURED, pretenure_flag); | |
| CHECK_EQ(STRING_ADD_CHECK_NONE, flags); | |
| return Builtins::CallableFor(isolate, | |
| Builtins::kStringAdd_CheckNone_Tenured); | |
| } | |
| UNREACHABLE(); | |
| } | |
| // static | |
| Callable CodeFactory::ResumeGenerator(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ResumeGeneratorTrampoline), | |
| ResumeGeneratorDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, FrameDropperTrampoline), | |
| FrameDropperTrampolineDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, HandleDebuggerStatement), | |
| ContextOnlyDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::FastNewFunctionContext(Isolate* isolate, | |
| ScopeType scope_type) { | |
| return Callable(isolate->builtins()->NewFunctionContext(scope_type), | |
| FastNewFunctionContextDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ArgumentsAdaptorTrampoline), | |
| ArgumentAdaptorDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) { | |
| return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallWithArrayLike(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallWithArrayLike), | |
| CallWithArrayLikeDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallWithSpread(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallWithSpread), | |
| CallWithSpreadDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) { | |
| return Callable(isolate->builtins()->CallFunction(mode), | |
| CallTrampolineDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallVarargs), CallVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallForwardVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallForwardVarargs), | |
| CallForwardVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, CallFunctionForwardVarargs), | |
| CallForwardVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::Construct(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, Construct), JSTrampolineDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ConstructWithSpread(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ConstructWithSpread), | |
| ConstructWithSpreadDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ConstructFunction(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ConstructFunction), | |
| JSTrampolineDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ConstructVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ConstructVarargs), | |
| ConstructVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ConstructForwardVarargs), | |
| ConstructForwardVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, ConstructFunctionForwardVarargs), | |
| ConstructForwardVarargsDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::InterpreterPushArgsThenCall( | |
| Isolate* isolate, ConvertReceiverMode receiver_mode, | |
| InterpreterPushArgsMode mode) { | |
| return Callable( | |
| isolate->builtins()->InterpreterPushArgsThenCall(receiver_mode, mode), | |
| InterpreterPushArgsThenCallDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::InterpreterPushArgsThenConstruct( | |
| Isolate* isolate, InterpreterPushArgsMode mode) { | |
| return Callable(isolate->builtins()->InterpreterPushArgsThenConstruct(mode), | |
| InterpreterPushArgsThenConstructDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) { | |
| // Note: If we ever use fpregs in the interpreter then we will need to | |
| // save fpregs too. | |
| Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs, | |
| kArgvInRegister); | |
| if (result_size == 1) { | |
| return Callable(code, InterpreterCEntry1Descriptor{}); | |
| } else { | |
| DCHECK_EQ(result_size, 2); | |
| return Callable(code, InterpreterCEntry2Descriptor{}); | |
| } | |
| } | |
| // static | |
| Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) { | |
| return Callable(BUILTIN_CODE(isolate, InterpreterOnStackReplacement), | |
| ContextOnlyDescriptor{}); | |
| } | |
| // static | |
| Callable CodeFactory::ArrayNoArgumentConstructor( | |
| Isolate* isolate, ElementsKind kind, | |
| AllocationSiteOverrideMode override_mode) { | |
| #define CASE(kind_caps, kind_camel, mode_camel) \ | |
| case kind_caps: \ | |
| return Callable( \ | |
| BUILTIN_CODE(isolate, \ | |
| ArrayNoArgumentConstructor_##kind_camel##_##mode_camel), \ | |
| ArrayNoArgumentConstructorDescriptor{}) | |
| if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { | |
| DCHECK(IsSmiElementsKind(kind)); | |
| switch (kind) { | |
| CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); | |
| CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } else { | |
| DCHECK(override_mode == DISABLE_ALLOCATION_SITES || | |
| !AllocationSite::ShouldTrack(kind)); | |
| switch (kind) { | |
| CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); | |
| CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); | |
| CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); | |
| CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); | |
| CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); | |
| CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| #undef CASE | |
| } | |
| // static | |
| Callable CodeFactory::ArraySingleArgumentConstructor( | |
| Isolate* isolate, ElementsKind kind, | |
| AllocationSiteOverrideMode override_mode) { | |
| #define CASE(kind_caps, kind_camel, mode_camel) \ | |
| case kind_caps: \ | |
| return Callable( \ | |
| BUILTIN_CODE( \ | |
| isolate, \ | |
| ArraySingleArgumentConstructor_##kind_camel##_##mode_camel), \ | |
| ArraySingleArgumentConstructorDescriptor{}) | |
| if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { | |
| DCHECK(IsSmiElementsKind(kind)); | |
| switch (kind) { | |
| CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); | |
| CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } else { | |
| DCHECK(override_mode == DISABLE_ALLOCATION_SITES || | |
| !AllocationSite::ShouldTrack(kind)); | |
| switch (kind) { | |
| CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); | |
| CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); | |
| CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); | |
| CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); | |
| CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); | |
| CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| #undef CASE | |
| } | |
| // static | |
| Callable CodeFactory::InternalArrayNoArgumentConstructor(Isolate* isolate, | |
| ElementsKind kind) { | |
| switch (kind) { | |
| case PACKED_ELEMENTS: | |
| return Callable( | |
| BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Packed), | |
| ArrayNoArgumentConstructorDescriptor{}); | |
| case HOLEY_ELEMENTS: | |
| return Callable( | |
| BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Holey), | |
| ArrayNoArgumentConstructorDescriptor{}); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| // static | |
| Callable CodeFactory::InternalArraySingleArgumentConstructor( | |
| Isolate* isolate, ElementsKind kind) { | |
| switch (kind) { | |
| case PACKED_ELEMENTS: | |
| return Callable( | |
| BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Packed), | |
| ArraySingleArgumentConstructorDescriptor{}); | |
| case HOLEY_ELEMENTS: | |
| return Callable( | |
| BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Holey), | |
| ArraySingleArgumentConstructorDescriptor{}); | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| } // namespace internal | |
| } // namespace v8 |