Home | History | Annotate | Download | only in interpreter
      1 // Copyright 2015 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/interpreter/interpreter-intrinsics.h"
      6 
      7 #include "src/code-factory.h"
      8 #include "src/objects-inl.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace interpreter {
     13 
     14 using compiler::Node;
     15 
     16 #define __ assembler_->
     17 
     18 IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
     19     : isolate_(assembler->isolate()),
     20       zone_(assembler->zone()),
     21       assembler_(assembler) {}
     22 
     23 // static
     24 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
     25   switch (function_id) {
     26 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name:
     27     INTRINSICS_LIST(SUPPORTED)
     28     return true;
     29 #undef SUPPORTED
     30     default:
     31       return false;
     32   }
     33 }
     34 
     35 // static
     36 IntrinsicsHelper::IntrinsicId IntrinsicsHelper::FromRuntimeId(
     37     Runtime::FunctionId function_id) {
     38   switch (function_id) {
     39 #define TO_RUNTIME_ID(name, lower_case, count) \
     40   case Runtime::kInline##name:                 \
     41     return IntrinsicId::k##name;
     42     INTRINSICS_LIST(TO_RUNTIME_ID)
     43 #undef TO_RUNTIME_ID
     44     default:
     45       UNREACHABLE();
     46       return static_cast<IntrinsicsHelper::IntrinsicId>(-1);
     47   }
     48 }
     49 
     50 // static
     51 Runtime::FunctionId IntrinsicsHelper::ToRuntimeId(
     52     IntrinsicsHelper::IntrinsicId intrinsic_id) {
     53   switch (intrinsic_id) {
     54 #define TO_INTRINSIC_ID(name, lower_case, count) \
     55   case IntrinsicId::k##name:                     \
     56     return Runtime::kInline##name;
     57     INTRINSICS_LIST(TO_INTRINSIC_ID)
     58 #undef TO_INTRINSIC_ID
     59     default:
     60       UNREACHABLE();
     61       return static_cast<Runtime::FunctionId>(-1);
     62   }
     63 }
     64 
     65 Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
     66                                         Node* first_arg_reg, Node* arg_count) {
     67   InterpreterAssembler::Label abort(assembler_), end(assembler_);
     68   InterpreterAssembler::Variable result(assembler_,
     69                                         MachineRepresentation::kTagged);
     70 
     71 #define MAKE_LABEL(name, lower_case, count) \
     72   InterpreterAssembler::Label lower_case(assembler_);
     73   INTRINSICS_LIST(MAKE_LABEL)
     74 #undef MAKE_LABEL
     75 
     76 #define LABEL_POINTER(name, lower_case, count) &lower_case,
     77   InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)};
     78 #undef LABEL_POINTER
     79 
     80 #define CASE(name, lower_case, count) \
     81   static_cast<int32_t>(IntrinsicId::k##name),
     82   int32_t cases[] = {INTRINSICS_LIST(CASE)};
     83 #undef CASE
     84 
     85   __ Switch(function_id, &abort, cases, labels, arraysize(cases));
     86 #define HANDLE_CASE(name, lower_case, expected_arg_count)   \
     87   __ Bind(&lower_case);                                     \
     88   if (FLAG_debug_code && expected_arg_count >= 0) {         \
     89     AbortIfArgCountMismatch(expected_arg_count, arg_count); \
     90   }                                                         \
     91   result.Bind(name(first_arg_reg, arg_count, context));     \
     92   __ Goto(&end);
     93   INTRINSICS_LIST(HANDLE_CASE)
     94 #undef HANDLE_CASE
     95 
     96   __ Bind(&abort);
     97   {
     98     __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
     99     result.Bind(__ UndefinedConstant());
    100     __ Goto(&end);
    101   }
    102 
    103   __ Bind(&end);
    104   return result.value();
    105 }
    106 
    107 Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type,
    108                                             InstanceTypeCompareMode mode) {
    109   Node* instance_type = __ LoadInstanceType(object);
    110 
    111   if (mode == kInstanceTypeEqual) {
    112     return __ Word32Equal(instance_type, __ Int32Constant(type));
    113   } else {
    114     DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
    115     return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
    116   }
    117 }
    118 
    119 Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) {
    120   InterpreterAssembler::Variable return_value(assembler_,
    121                                               MachineRepresentation::kTagged);
    122   // TODO(ishell): Use Select here.
    123   InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
    124       return_false(assembler_), end(assembler_);
    125   Node* arg = __ LoadRegister(input);
    126   __ GotoIf(__ TaggedIsSmi(arg), &return_false);
    127 
    128   Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
    129   __ Branch(condition, &return_true, &return_false);
    130 
    131   __ Bind(&return_true);
    132   {
    133     return_value.Bind(__ BooleanConstant(true));
    134     __ Goto(&end);
    135   }
    136 
    137   __ Bind(&return_false);
    138   {
    139     return_value.Bind(__ BooleanConstant(false));
    140     __ Goto(&end);
    141   }
    142 
    143   __ Bind(&end);
    144   return return_value.value();
    145 }
    146 
    147 Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count,
    148                                      Node* context) {
    149   // TODO(ishell): Use Select here.
    150   // TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
    151   InterpreterAssembler::Variable return_value(assembler_,
    152                                               MachineRepresentation::kTagged);
    153   InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
    154       end(assembler_);
    155 
    156   Node* arg = __ LoadRegister(input);
    157   __ GotoIf(__ TaggedIsSmi(arg), &return_false);
    158 
    159   STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
    160   Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
    161                                         kInstanceTypeGreaterThanOrEqual);
    162   __ Branch(condition, &return_true, &return_false);
    163 
    164   __ Bind(&return_true);
    165   {
    166     return_value.Bind(__ BooleanConstant(true));
    167     __ Goto(&end);
    168   }
    169 
    170   __ Bind(&return_false);
    171   {
    172     return_value.Bind(__ BooleanConstant(false));
    173     __ Goto(&end);
    174   }
    175 
    176   __ Bind(&end);
    177   return return_value.value();
    178 }
    179 
    180 Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
    181   return IsInstanceType(input, JS_ARRAY_TYPE);
    182 }
    183 
    184 Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) {
    185   return IsInstanceType(input, JS_PROXY_TYPE);
    186 }
    187 
    188 Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count,
    189                                      Node* context) {
    190   return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
    191 }
    192 
    193 Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) {
    194   // TODO(ishell): Use SelectBooleanConstant here.
    195   InterpreterAssembler::Variable return_value(assembler_,
    196                                               MachineRepresentation::kTagged);
    197   InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
    198       end(assembler_);
    199 
    200   Node* arg = __ LoadRegister(input);
    201 
    202   __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
    203   __ Bind(&if_smi);
    204   {
    205     return_value.Bind(__ BooleanConstant(true));
    206     __ Goto(&end);
    207   }
    208 
    209   __ Bind(&if_not_smi);
    210   {
    211     return_value.Bind(__ BooleanConstant(false));
    212     __ Goto(&end);
    213   }
    214 
    215   __ Bind(&end);
    216   return return_value.value();
    217 }
    218 
    219 Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context,
    220                                             Callable const& callable) {
    221   int param_count = callable.descriptor().GetParameterCount();
    222   int input_count = param_count + 2;  // +2 for target and context
    223   Node** args = zone()->NewArray<Node*>(input_count);
    224   int index = 0;
    225   args[index++] = __ HeapConstant(callable.code());
    226   for (int i = 0; i < param_count; i++) {
    227     args[index++] = __ LoadRegister(args_reg);
    228     args_reg = __ NextRegister(args_reg);
    229   }
    230   args[index++] = context;
    231   return __ CallStubN(callable.descriptor(), 1, input_count, args);
    232 }
    233 
    234 Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count,
    235                                                Node* context) {
    236   return IntrinsicAsStubCall(input, context,
    237                              CodeFactory::CreateIterResultObject(isolate()));
    238 }
    239 
    240 Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
    241                                     Node* context) {
    242   return IntrinsicAsStubCall(input, context,
    243                              CodeFactory::HasProperty(isolate()));
    244 }
    245 
    246 Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) {
    247   return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
    248 }
    249 
    250 Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) {
    251   return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
    252 }
    253 
    254 Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) {
    255   return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
    256 }
    257 
    258 Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) {
    259   return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
    260 }
    261 
    262 Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) {
    263   return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
    264 }
    265 
    266 Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) {
    267   return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
    268 }
    269 
    270 Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) {
    271   // First argument register contains the function target.
    272   Node* function = __ LoadRegister(args_reg);
    273 
    274   // Receiver is the second runtime call argument.
    275   Node* receiver_reg = __ NextRegister(args_reg);
    276   Node* receiver_arg = __ RegisterLocation(receiver_reg);
    277 
    278   // Subtract function and receiver from arg count.
    279   Node* function_and_receiver_count = __ Int32Constant(2);
    280   Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);
    281 
    282   if (FLAG_debug_code) {
    283     InterpreterAssembler::Label arg_count_positive(assembler_);
    284     Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
    285     __ GotoIfNot(comparison, &arg_count_positive);
    286     __ Abort(kWrongArgumentCountForInvokeIntrinsic);
    287     __ Goto(&arg_count_positive);
    288     __ Bind(&arg_count_positive);
    289   }
    290 
    291   Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
    292                            TailCallMode::kDisallow);
    293   return result;
    294 }
    295 
    296 Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count,
    297                                 Node* context) {
    298   Node* value = __ LoadRegister(args_reg);
    299   return __ ClassOf(value);
    300 }
    301 
    302 Node* IntrinsicsHelper::CreateAsyncFromSyncIterator(Node* args_reg,
    303                                                     Node* arg_count,
    304                                                     Node* context) {
    305   InterpreterAssembler::Label not_receiver(
    306       assembler_, InterpreterAssembler::Label::kDeferred);
    307   InterpreterAssembler::Label done(assembler_);
    308   InterpreterAssembler::Variable return_value(assembler_,
    309                                               MachineRepresentation::kTagged);
    310 
    311   Node* sync_iterator = __ LoadRegister(args_reg);
    312 
    313   __ GotoIf(__ TaggedIsSmi(sync_iterator), &not_receiver);
    314   __ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_receiver);
    315 
    316   Node* const native_context = __ LoadNativeContext(context);
    317   Node* const map = __ LoadContextElement(
    318       native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
    319   Node* const iterator = __ AllocateJSObjectFromMap(map);
    320 
    321   __ StoreObjectFieldNoWriteBarrier(
    322       iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
    323 
    324   return_value.Bind(iterator);
    325   __ Goto(&done);
    326 
    327   __ Bind(&not_receiver);
    328   {
    329     return_value.Bind(
    330         __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
    331 
    332     // Unreachable due to the Throw in runtime call.
    333     __ Goto(&done);
    334   }
    335 
    336   __ Bind(&done);
    337   return return_value.value();
    338 }
    339 
    340 void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
    341   InterpreterAssembler::Label match(assembler_);
    342   Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
    343   __ GotoIf(comparison, &match);
    344   __ Abort(kWrongArgumentCountForInvokeIntrinsic);
    345   __ Goto(&match);
    346   __ Bind(&match);
    347 }
    348 
    349 }  // namespace interpreter
    350 }  // namespace internal
    351 }  // namespace v8
    352