| // 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 |