Home | History | Annotate | Download | only in src
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/code-factory.h"
      6 
      7 #include "src/bootstrapper.h"
      8 #include "src/builtins/builtins-descriptors.h"
      9 #include "src/ic/ic.h"
     10 #include "src/objects-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 namespace {
     16 
     17 // TODO(ishell): make it (const Stub& stub) once CodeStub::GetCode() is const.
     18 template <typename Stub>
     19 Callable make_callable(Stub& stub) {
     20   typedef typename Stub::Descriptor Descriptor;
     21   return Callable(stub.GetCode(), Descriptor{});
     22 }
     23 
     24 }  // namespace
     25 
     26 // static
     27 Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) {
     28   return CodeFactory::CEntry(isolate, result_size);
     29 }
     30 
     31 #define CENTRY_CODE(RS, SD, AM, BE) \
     32   BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE)
     33 
     34 // static
     35 Handle<Code> CodeFactory::CEntry(Isolate* isolate, int result_size,
     36                                  SaveFPRegsMode save_doubles,
     37                                  ArgvMode argv_mode, bool builtin_exit_frame) {
     38   // Aliases for readability below.
     39   const int rs = result_size;
     40   const SaveFPRegsMode sd = save_doubles;
     41   const ArgvMode am = argv_mode;
     42   const bool be = builtin_exit_frame;
     43 
     44   if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
     45     return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
     46   } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
     47     return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
     48   } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
     49     return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
     50   } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
     51     return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
     52   } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && be) {
     53     return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit);
     54   } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
     55     return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
     56   } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
     57     return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
     58   } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
     59     return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
     60   } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
     61     return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
     62   } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && be) {
     63     return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit);
     64   }
     65 
     66   UNREACHABLE();
     67 }
     68 
     69 #undef CENTRY_CODE
     70 
     71 // static
     72 Callable CodeFactory::ApiGetter(Isolate* isolate) {
     73   return Callable(BUILTIN_CODE(isolate, CallApiGetter), ApiGetterDescriptor{});
     74 }
     75 
     76 // static
     77 Callable CodeFactory::CallApiCallback(Isolate* isolate, int argc) {
     78   switch (argc) {
     79     case 0:
     80       return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc0),
     81                       ApiCallbackDescriptor{});
     82     case 1:
     83       return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc1),
     84                       ApiCallbackDescriptor{});
     85     default: {
     86       CallApiCallbackStub stub(isolate, argc);
     87       return make_callable(stub);
     88     }
     89   }
     90   UNREACHABLE();
     91 }
     92 
     93 // static
     94 Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
     95   return Callable(
     96       typeof_mode == NOT_INSIDE_TYPEOF
     97           ? BUILTIN_CODE(isolate, LoadGlobalICTrampoline)
     98           : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeofTrampoline),
     99       LoadGlobalDescriptor{});
    100 }
    101 
    102 // static
    103 Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
    104                                                   TypeofMode typeof_mode) {
    105   return Callable(typeof_mode == NOT_INSIDE_TYPEOF
    106                       ? BUILTIN_CODE(isolate, LoadGlobalIC)
    107                       : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeof),
    108                   LoadGlobalWithVectorDescriptor{});
    109 }
    110 
    111 Callable CodeFactory::StoreOwnIC(Isolate* isolate) {
    112   // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
    113   // already exist in the boilerplate therefore we can use StoreIC.
    114   return Callable(BUILTIN_CODE(isolate, StoreICTrampoline), StoreDescriptor{});
    115 }
    116 
    117 Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) {
    118   // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
    119   // already exist in the boilerplate therefore we can use StoreIC.
    120   return Callable(BUILTIN_CODE(isolate, StoreIC), StoreWithVectorDescriptor{});
    121 }
    122 
    123 // static
    124 Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
    125   switch (op) {
    126     case Operation::kShiftRight:
    127       return Builtins::CallableFor(isolate, Builtins::kShiftRight);
    128     case Operation::kShiftLeft:
    129       return Builtins::CallableFor(isolate, Builtins::kShiftLeft);
    130     case Operation::kShiftRightLogical:
    131       return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical);
    132     case Operation::kAdd:
    133       return Builtins::CallableFor(isolate, Builtins::kAdd);
    134     case Operation::kSubtract:
    135       return Builtins::CallableFor(isolate, Builtins::kSubtract);
    136     case Operation::kMultiply:
    137       return Builtins::CallableFor(isolate, Builtins::kMultiply);
    138     case Operation::kDivide:
    139       return Builtins::CallableFor(isolate, Builtins::kDivide);
    140     case Operation::kModulus:
    141       return Builtins::CallableFor(isolate, Builtins::kModulus);
    142     case Operation::kBitwiseOr:
    143       return Builtins::CallableFor(isolate, Builtins::kBitwiseOr);
    144     case Operation::kBitwiseAnd:
    145       return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd);
    146     case Operation::kBitwiseXor:
    147       return Builtins::CallableFor(isolate, Builtins::kBitwiseXor);
    148     default:
    149       break;
    150   }
    151   UNREACHABLE();
    152 }
    153 
    154 // static
    155 Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
    156                                               ToPrimitiveHint hint) {
    157   return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
    158                   TypeConversionDescriptor{});
    159 }
    160 
    161 // static
    162 Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
    163                                           OrdinaryToPrimitiveHint hint) {
    164   return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
    165                   TypeConversionDescriptor{});
    166 }
    167 
    168 // static
    169 Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags,
    170                                 PretenureFlag pretenure_flag) {
    171   if (pretenure_flag == NOT_TENURED) {
    172     switch (flags) {
    173       case STRING_ADD_CHECK_NONE:
    174         return Builtins::CallableFor(isolate,
    175                                      Builtins::kStringAdd_CheckNone_NotTenured);
    176       case STRING_ADD_CONVERT_LEFT:
    177         return Builtins::CallableFor(
    178             isolate, Builtins::kStringAdd_ConvertLeft_NotTenured);
    179       case STRING_ADD_CONVERT_RIGHT:
    180         return Builtins::CallableFor(
    181             isolate, Builtins::kStringAdd_ConvertRight_NotTenured);
    182     }
    183   } else {
    184     CHECK_EQ(TENURED, pretenure_flag);
    185     CHECK_EQ(STRING_ADD_CHECK_NONE, flags);
    186     return Builtins::CallableFor(isolate,
    187                                  Builtins::kStringAdd_CheckNone_Tenured);
    188   }
    189 
    190   UNREACHABLE();
    191 }
    192 
    193 // static
    194 Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
    195   return Callable(BUILTIN_CODE(isolate, ResumeGeneratorTrampoline),
    196                   ResumeGeneratorDescriptor{});
    197 }
    198 
    199 // static
    200 Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) {
    201   return Callable(BUILTIN_CODE(isolate, FrameDropperTrampoline),
    202                   FrameDropperTrampolineDescriptor{});
    203 }
    204 
    205 // static
    206 Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) {
    207   return Callable(BUILTIN_CODE(isolate, HandleDebuggerStatement),
    208                   ContextOnlyDescriptor{});
    209 }
    210 
    211 // static
    212 Callable CodeFactory::FastNewFunctionContext(Isolate* isolate,
    213                                              ScopeType scope_type) {
    214   return Callable(isolate->builtins()->NewFunctionContext(scope_type),
    215                   FastNewFunctionContextDescriptor{});
    216 }
    217 
    218 // static
    219 Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) {
    220   return Callable(BUILTIN_CODE(isolate, ArgumentsAdaptorTrampoline),
    221                   ArgumentAdaptorDescriptor{});
    222 }
    223 
    224 // static
    225 Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
    226   return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
    227 }
    228 
    229 // static
    230 Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
    231   return Callable(BUILTIN_CODE(isolate, CallWithArrayLike),
    232                   CallWithArrayLikeDescriptor{});
    233 }
    234 
    235 // static
    236 Callable CodeFactory::CallWithSpread(Isolate* isolate) {
    237   return Callable(BUILTIN_CODE(isolate, CallWithSpread),
    238                   CallWithSpreadDescriptor{});
    239 }
    240 
    241 // static
    242 Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
    243   return Callable(isolate->builtins()->CallFunction(mode),
    244                   CallTrampolineDescriptor{});
    245 }
    246 
    247 // static
    248 Callable CodeFactory::CallVarargs(Isolate* isolate) {
    249   return Callable(BUILTIN_CODE(isolate, CallVarargs), CallVarargsDescriptor{});
    250 }
    251 
    252 // static
    253 Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
    254   return Callable(BUILTIN_CODE(isolate, CallForwardVarargs),
    255                   CallForwardVarargsDescriptor{});
    256 }
    257 
    258 // static
    259 Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
    260   return Callable(BUILTIN_CODE(isolate, CallFunctionForwardVarargs),
    261                   CallForwardVarargsDescriptor{});
    262 }
    263 
    264 // static
    265 Callable CodeFactory::Construct(Isolate* isolate) {
    266   return Callable(BUILTIN_CODE(isolate, Construct), JSTrampolineDescriptor{});
    267 }
    268 
    269 // static
    270 Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
    271   return Callable(BUILTIN_CODE(isolate, ConstructWithSpread),
    272                   ConstructWithSpreadDescriptor{});
    273 }
    274 
    275 // static
    276 Callable CodeFactory::ConstructFunction(Isolate* isolate) {
    277   return Callable(BUILTIN_CODE(isolate, ConstructFunction),
    278                   JSTrampolineDescriptor{});
    279 }
    280 
    281 // static
    282 Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
    283   return Callable(BUILTIN_CODE(isolate, ConstructVarargs),
    284                   ConstructVarargsDescriptor{});
    285 }
    286 
    287 // static
    288 Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
    289   return Callable(BUILTIN_CODE(isolate, ConstructForwardVarargs),
    290                   ConstructForwardVarargsDescriptor{});
    291 }
    292 
    293 // static
    294 Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
    295   return Callable(BUILTIN_CODE(isolate, ConstructFunctionForwardVarargs),
    296                   ConstructForwardVarargsDescriptor{});
    297 }
    298 
    299 // static
    300 Callable CodeFactory::InterpreterPushArgsThenCall(
    301     Isolate* isolate, ConvertReceiverMode receiver_mode,
    302     InterpreterPushArgsMode mode) {
    303   return Callable(
    304       isolate->builtins()->InterpreterPushArgsThenCall(receiver_mode, mode),
    305       InterpreterPushArgsThenCallDescriptor{});
    306 }
    307 
    308 // static
    309 Callable CodeFactory::InterpreterPushArgsThenConstruct(
    310     Isolate* isolate, InterpreterPushArgsMode mode) {
    311   return Callable(isolate->builtins()->InterpreterPushArgsThenConstruct(mode),
    312                   InterpreterPushArgsThenConstructDescriptor{});
    313 }
    314 
    315 // static
    316 Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
    317   // Note: If we ever use fpregs in the interpreter then we will need to
    318   // save fpregs too.
    319   Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs,
    320                                           kArgvInRegister);
    321   if (result_size == 1) {
    322     return Callable(code, InterpreterCEntry1Descriptor{});
    323   } else {
    324     DCHECK_EQ(result_size, 2);
    325     return Callable(code, InterpreterCEntry2Descriptor{});
    326   }
    327 }
    328 
    329 // static
    330 Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
    331   return Callable(BUILTIN_CODE(isolate, InterpreterOnStackReplacement),
    332                   ContextOnlyDescriptor{});
    333 }
    334 
    335 // static
    336 Callable CodeFactory::ArrayNoArgumentConstructor(
    337     Isolate* isolate, ElementsKind kind,
    338     AllocationSiteOverrideMode override_mode) {
    339 #define CASE(kind_caps, kind_camel, mode_camel)                               \
    340   case kind_caps:                                                             \
    341     return Callable(                                                          \
    342         BUILTIN_CODE(isolate,                                                 \
    343                      ArrayNoArgumentConstructor_##kind_camel##_##mode_camel), \
    344         ArrayNoArgumentConstructorDescriptor{})
    345   if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
    346     DCHECK(IsSmiElementsKind(kind));
    347     switch (kind) {
    348       CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
    349       CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
    350       default:
    351         UNREACHABLE();
    352     }
    353   } else {
    354     DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
    355            !AllocationSite::ShouldTrack(kind));
    356     switch (kind) {
    357       CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
    358       CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
    359       CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
    360       CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
    361       CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
    362       CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
    363       default:
    364         UNREACHABLE();
    365     }
    366   }
    367 #undef CASE
    368 }
    369 
    370 // static
    371 Callable CodeFactory::ArraySingleArgumentConstructor(
    372     Isolate* isolate, ElementsKind kind,
    373     AllocationSiteOverrideMode override_mode) {
    374 #define CASE(kind_caps, kind_camel, mode_camel)                          \
    375   case kind_caps:                                                        \
    376     return Callable(                                                     \
    377         BUILTIN_CODE(                                                    \
    378             isolate,                                                     \
    379             ArraySingleArgumentConstructor_##kind_camel##_##mode_camel), \
    380         ArraySingleArgumentConstructorDescriptor{})
    381   if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
    382     DCHECK(IsSmiElementsKind(kind));
    383     switch (kind) {
    384       CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
    385       CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
    386       default:
    387         UNREACHABLE();
    388     }
    389   } else {
    390     DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
    391            !AllocationSite::ShouldTrack(kind));
    392     switch (kind) {
    393       CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
    394       CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
    395       CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
    396       CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
    397       CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
    398       CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
    399       default:
    400         UNREACHABLE();
    401     }
    402   }
    403 #undef CASE
    404 }
    405 
    406 // static
    407 Callable CodeFactory::InternalArrayNoArgumentConstructor(Isolate* isolate,
    408                                                          ElementsKind kind) {
    409   switch (kind) {
    410     case PACKED_ELEMENTS:
    411       return Callable(
    412           BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Packed),
    413           ArrayNoArgumentConstructorDescriptor{});
    414     case HOLEY_ELEMENTS:
    415       return Callable(
    416           BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Holey),
    417           ArrayNoArgumentConstructorDescriptor{});
    418     default:
    419       UNREACHABLE();
    420   }
    421 }
    422 
    423 // static
    424 Callable CodeFactory::InternalArraySingleArgumentConstructor(
    425     Isolate* isolate, ElementsKind kind) {
    426   switch (kind) {
    427     case PACKED_ELEMENTS:
    428       return Callable(
    429           BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Packed),
    430           ArraySingleArgumentConstructorDescriptor{});
    431     case HOLEY_ELEMENTS:
    432       return Callable(
    433           BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Holey),
    434           ArraySingleArgumentConstructorDescriptor{});
    435     default:
    436       UNREACHABLE();
    437   }
    438 }
    439 
    440 }  // namespace internal
    441 }  // namespace v8
    442