LCOV - code coverage report
Current view: top level - src/interpreter - interpreter-intrinsics-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 147 167 88.0 %
Date: 2017-04-26 Functions: 20 27 74.1 %

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

Generated by: LCOV version 1.10