LCOV - code coverage report
Current view: top level - src/interpreter - interpreter-intrinsics-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 162 188 86.2 %
Date: 2017-10-20 Functions: 22 35 62.9 %

          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          93 :   explicit IntrinsicsGenerator(InterpreterAssembler* assembler)
      24          93 :       : isolate_(assembler->isolate()),
      25          93 :         zone_(assembler->zone()),
      26         186 :         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          93 : Node* GenerateInvokeIntrinsic(InterpreterAssembler* assembler,
      60             :                               Node* function_id, Node* context,
      61             :                               Node* first_arg_reg, Node* arg_count) {
      62          93 :   IntrinsicsGenerator generator(assembler);
      63             :   return generator.InvokeIntrinsic(function_id, context, first_arg_reg,
      64          93 :                                    arg_count);
      65             : }
      66             : 
      67             : #define __ assembler_->
      68             : 
      69          93 : Node* IntrinsicsGenerator::InvokeIntrinsic(Node* function_id, Node* context,
      70             :                                            Node* first_arg_reg,
      71             :                                            Node* arg_count) {
      72         279 :   InterpreterAssembler::Label abort(assembler_), end(assembler_);
      73             :   InterpreterAssembler::Variable result(assembler_,
      74         186 :                                         MachineRepresentation::kTagged);
      75             : 
      76             : #define MAKE_LABEL(name, lower_case, count) \
      77             :   InterpreterAssembler::Label lower_case(assembler_);
      78        2604 :   INTRINSICS_LIST(MAKE_LABEL)
      79             : #undef MAKE_LABEL
      80             : 
      81             : #define LABEL_POINTER(name, lower_case, count) &lower_case,
      82          93 :   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          93 :   int32_t cases[] = {INTRINSICS_LIST(CASE)};
      88             : #undef CASE
      89             : 
      90          93 :   __ Switch(function_id, &abort, cases, labels, arraysize(cases));
      91             : #define HANDLE_CASE(name, lower_case, expected_arg_count)     \
      92             :   __ BIND(&lower_case);                                       \
      93             :   {                                                           \
      94             :     if (FLAG_debug_code && expected_arg_count >= 0) {         \
      95             :       AbortIfArgCountMismatch(expected_arg_count, arg_count); \
      96             :     }                                                         \
      97             :     Node* value = name(first_arg_reg, arg_count, context);    \
      98             :     if (value) {                                              \
      99             :       result.Bind(value);                                     \
     100             :       __ Goto(&end);                                          \
     101             :     }                                                         \
     102             :   }
     103        1209 :   INTRINSICS_LIST(HANDLE_CASE)
     104             : #undef HANDLE_CASE
     105             : 
     106          93 :   __ BIND(&abort);
     107             :   {
     108          93 :     __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
     109         186 :     result.Bind(__ UndefinedConstant());
     110          93 :     __ Goto(&end);
     111             :   }
     112             : 
     113          93 :   __ BIND(&end);
     114         186 :   return result.value();
     115             : }
     116             : 
     117         744 : Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
     118             :                                                InstanceTypeCompareMode mode) {
     119        1488 :   Node* instance_type = __ LoadInstanceType(object);
     120             : 
     121         744 :   if (mode == kInstanceTypeEqual) {
     122        1953 :     return __ Word32Equal(instance_type, __ Int32Constant(type));
     123             :   } else {
     124             :     DCHECK_EQ(mode, kInstanceTypeGreaterThanOrEqual);
     125         279 :     return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
     126             :   }
     127             : }
     128             : 
     129         651 : Node* IntrinsicsGenerator::IsInstanceType(Node* input, int type) {
     130             :   InterpreterAssembler::Variable return_value(assembler_,
     131         651 :                                               MachineRepresentation::kTagged);
     132             :   // TODO(ishell): Use Select here.
     133        1953 :   InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
     134        1953 :       return_false(assembler_), end(assembler_);
     135         651 :   Node* arg = __ LoadRegister(input);
     136        1302 :   __ GotoIf(__ TaggedIsSmi(arg), &return_false);
     137             : 
     138         651 :   Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
     139         651 :   __ Branch(condition, &return_true, &return_false);
     140             : 
     141         651 :   __ BIND(&return_true);
     142             :   {
     143        1302 :     return_value.Bind(__ BooleanConstant(true));
     144         651 :     __ Goto(&end);
     145             :   }
     146             : 
     147         651 :   __ BIND(&return_false);
     148             :   {
     149        1302 :     return_value.Bind(__ BooleanConstant(false));
     150         651 :     __ Goto(&end);
     151             :   }
     152             : 
     153         651 :   __ BIND(&end);
     154        1302 :   return return_value.value();
     155             : }
     156             : 
     157          93 : Node* IntrinsicsGenerator::IsJSReceiver(Node* input, Node* arg_count,
     158             :                                         Node* context) {
     159             :   // TODO(ishell): Use Select here.
     160             :   // TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
     161             :   InterpreterAssembler::Variable return_value(assembler_,
     162          93 :                                               MachineRepresentation::kTagged);
     163         279 :   InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
     164         186 :       end(assembler_);
     165             : 
     166          93 :   Node* arg = __ LoadRegister(input);
     167         186 :   __ GotoIf(__ TaggedIsSmi(arg), &return_false);
     168             : 
     169             :   STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
     170             :   Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
     171          93 :                                         kInstanceTypeGreaterThanOrEqual);
     172          93 :   __ Branch(condition, &return_true, &return_false);
     173             : 
     174          93 :   __ BIND(&return_true);
     175             :   {
     176         186 :     return_value.Bind(__ BooleanConstant(true));
     177          93 :     __ Goto(&end);
     178             :   }
     179             : 
     180          93 :   __ BIND(&return_false);
     181             :   {
     182         186 :     return_value.Bind(__ BooleanConstant(false));
     183          93 :     __ Goto(&end);
     184             :   }
     185             : 
     186          93 :   __ BIND(&end);
     187         186 :   return return_value.value();
     188             : }
     189             : 
     190           0 : Node* IntrinsicsGenerator::IsArray(Node* input, Node* arg_count,
     191             :                                    Node* context) {
     192          93 :   return IsInstanceType(input, JS_ARRAY_TYPE);
     193             : }
     194             : 
     195           0 : Node* IntrinsicsGenerator::IsJSProxy(Node* input, Node* arg_count,
     196             :                                      Node* context) {
     197          93 :   return IsInstanceType(input, JS_PROXY_TYPE);
     198             : }
     199             : 
     200           0 : Node* IntrinsicsGenerator::IsTypedArray(Node* input, Node* arg_count,
     201             :                                         Node* context) {
     202          93 :   return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
     203             : }
     204             : 
     205           0 : Node* IntrinsicsGenerator::IsJSMap(Node* input, Node* arg_count,
     206             :                                    Node* context) {
     207          93 :   return IsInstanceType(input, JS_MAP_TYPE);
     208             : }
     209             : 
     210           0 : Node* IntrinsicsGenerator::IsJSSet(Node* input, Node* arg_count,
     211             :                                    Node* context) {
     212          93 :   return IsInstanceType(input, JS_SET_TYPE);
     213             : }
     214             : 
     215           0 : Node* IntrinsicsGenerator::IsJSWeakMap(Node* input, Node* arg_count,
     216             :                                        Node* context) {
     217          93 :   return IsInstanceType(input, JS_WEAK_MAP_TYPE);
     218             : }
     219             : 
     220           0 : Node* IntrinsicsGenerator::IsJSWeakSet(Node* input, Node* arg_count,
     221             :                                        Node* context) {
     222          93 :   return IsInstanceType(input, JS_WEAK_SET_TYPE);
     223             : }
     224             : 
     225          93 : Node* IntrinsicsGenerator::IsSmi(Node* input, Node* arg_count, Node* context) {
     226             :   // TODO(ishell): Use SelectBooleanConstant here.
     227             :   InterpreterAssembler::Variable return_value(assembler_,
     228          93 :                                               MachineRepresentation::kTagged);
     229         279 :   InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
     230         186 :       end(assembler_);
     231             : 
     232          93 :   Node* arg = __ LoadRegister(input);
     233             : 
     234         186 :   __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
     235          93 :   __ BIND(&if_smi);
     236             :   {
     237         186 :     return_value.Bind(__ BooleanConstant(true));
     238          93 :     __ Goto(&end);
     239             :   }
     240             : 
     241          93 :   __ BIND(&if_not_smi);
     242             :   {
     243         186 :     return_value.Bind(__ BooleanConstant(false));
     244          93 :     __ Goto(&end);
     245             :   }
     246             : 
     247          93 :   __ BIND(&end);
     248         186 :   return return_value.value();
     249             : }
     250             : 
     251        1023 : Node* IntrinsicsGenerator::IntrinsicAsStubCall(Node* args_reg, Node* context,
     252        1023 :                                                Callable const& callable) {
     253             :   int param_count = callable.descriptor().GetParameterCount();
     254        1023 :   int input_count = param_count + 2;  // +2 for target and context
     255        1023 :   Node** args = zone()->NewArray<Node*>(input_count);
     256             :   int index = 0;
     257        2046 :   args[index++] = __ HeapConstant(callable.code());
     258        2790 :   for (int i = 0; i < param_count; i++) {
     259        1767 :     args[index++] = __ LoadRegister(args_reg);
     260        1767 :     args_reg = __ NextRegister(args_reg);
     261             :   }
     262        1023 :   args[index++] = context;
     263        1023 :   return __ CallStubN(callable.descriptor(), 1, input_count, args);
     264             : }
     265             : 
     266         372 : Node* IntrinsicsGenerator::IntrinsicAsBuiltinCall(Node* input, Node* context,
     267             :                                                   Builtins::Name name) {
     268         372 :   Callable callable = Builtins::CallableFor(isolate_, name);
     269         372 :   return IntrinsicAsStubCall(input, context, callable);
     270             : }
     271             : 
     272          93 : Node* IntrinsicsGenerator::CreateIterResultObject(Node* input, Node* arg_count,
     273          93 :                                                   Node* context) {
     274             :   return IntrinsicAsStubCall(
     275             :       input, context,
     276          93 :       Builtins::CallableFor(isolate(), Builtins::kCreateIterResultObject));
     277             : }
     278             : 
     279          93 : Node* IntrinsicsGenerator::HasProperty(Node* input, Node* arg_count,
     280          93 :                                        Node* context) {
     281             :   return IntrinsicAsStubCall(
     282          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kHasProperty));
     283             : }
     284             : 
     285          93 : Node* IntrinsicsGenerator::ToString(Node* input, Node* arg_count,
     286          93 :                                     Node* context) {
     287             :   return IntrinsicAsStubCall(
     288          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kToString));
     289             : }
     290             : 
     291          93 : Node* IntrinsicsGenerator::ToLength(Node* input, Node* arg_count,
     292          93 :                                     Node* context) {
     293             :   return IntrinsicAsStubCall(
     294          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kToLength));
     295             : }
     296             : 
     297          93 : Node* IntrinsicsGenerator::ToInteger(Node* input, Node* arg_count,
     298          93 :                                      Node* context) {
     299             :   return IntrinsicAsStubCall(
     300          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kToInteger));
     301             : }
     302             : 
     303          93 : Node* IntrinsicsGenerator::ToNumber(Node* input, Node* arg_count,
     304          93 :                                     Node* context) {
     305             :   return IntrinsicAsStubCall(
     306          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kToNumber));
     307             : }
     308             : 
     309          93 : Node* IntrinsicsGenerator::ToObject(Node* input, Node* arg_count,
     310          93 :                                     Node* context) {
     311             :   return IntrinsicAsStubCall(
     312          93 :       input, context, Builtins::CallableFor(isolate(), Builtins::kToObject));
     313             : }
     314             : 
     315          93 : Node* IntrinsicsGenerator::Call(Node* args_reg, Node* arg_count,
     316             :                                 Node* context) {
     317             :   // First argument register contains the function target.
     318          93 :   Node* function = __ LoadRegister(args_reg);
     319             : 
     320             :   // Receiver is the second runtime call argument.
     321          93 :   Node* receiver_reg = __ NextRegister(args_reg);
     322          93 :   Node* receiver_arg = __ RegisterLocation(receiver_reg);
     323             : 
     324             :   // Subtract function and receiver from arg count.
     325         186 :   Node* function_and_receiver_count = __ Int32Constant(2);
     326         186 :   Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);
     327             : 
     328          93 :   if (FLAG_debug_code) {
     329           0 :     InterpreterAssembler::Label arg_count_positive(assembler_);
     330           0 :     Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
     331           0 :     __ GotoIfNot(comparison, &arg_count_positive);
     332           0 :     __ Abort(kWrongArgumentCountForInvokeIntrinsic);
     333           0 :     __ Goto(&arg_count_positive);
     334           0 :     __ BIND(&arg_count_positive);
     335             :   }
     336             : 
     337             :   __ CallJSAndDispatch(function, context, receiver_arg, target_args_count,
     338          93 :                        ConvertReceiverMode::kAny);
     339          93 :   return nullptr;  // We never return from the CallJSAndDispatch above.
     340             : }
     341             : 
     342           0 : Node* IntrinsicsGenerator::ClassOf(Node* args_reg, Node* arg_count,
     343             :                                    Node* context) {
     344          93 :   Node* value = __ LoadRegister(args_reg);
     345          93 :   return __ ClassOf(value);
     346             : }
     347             : 
     348          93 : Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(Node* args_reg,
     349             :                                                        Node* arg_count,
     350             :                                                        Node* context) {
     351             :   InterpreterAssembler::Label not_receiver(
     352          93 :       assembler_, InterpreterAssembler::Label::kDeferred);
     353         186 :   InterpreterAssembler::Label done(assembler_);
     354             :   InterpreterAssembler::Variable return_value(assembler_,
     355         186 :                                               MachineRepresentation::kTagged);
     356             : 
     357          93 :   Node* sync_iterator = __ LoadRegister(args_reg);
     358             : 
     359         186 :   __ GotoIf(__ TaggedIsSmi(sync_iterator), &not_receiver);
     360         186 :   __ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_receiver);
     361             : 
     362         186 :   Node* const native_context = __ LoadNativeContext(context);
     363             :   Node* const map = __ LoadContextElement(
     364         186 :       native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
     365          93 :   Node* const iterator = __ AllocateJSObjectFromMap(map);
     366             : 
     367             :   __ StoreObjectFieldNoWriteBarrier(
     368          93 :       iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
     369             : 
     370          93 :   return_value.Bind(iterator);
     371          93 :   __ Goto(&done);
     372             : 
     373          93 :   __ BIND(&not_receiver);
     374             :   {
     375             :     return_value.Bind(
     376         186 :         __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
     377             : 
     378             :     // Unreachable due to the Throw in runtime call.
     379          93 :     __ Goto(&done);
     380             :   }
     381             : 
     382          93 :   __ BIND(&done);
     383         186 :   return return_value.value();
     384             : }
     385             : 
     386           0 : Node* IntrinsicsGenerator::CreateJSGeneratorObject(Node* input, Node* arg_count,
     387             :                                                    Node* context) {
     388             :   return IntrinsicAsBuiltinCall(input, context,
     389          93 :                                 Builtins::kCreateGeneratorObject);
     390             : }
     391             : 
     392          93 : Node* IntrinsicsGenerator::GeneratorGetContext(Node* args_reg, Node* arg_count,
     393             :                                                Node* context) {
     394          93 :   Node* generator = __ LoadRegister(args_reg);
     395             :   Node* const value =
     396          93 :       __ LoadObjectField(generator, JSGeneratorObject::kContextOffset);
     397             : 
     398          93 :   return value;
     399             : }
     400             : 
     401          93 : Node* IntrinsicsGenerator::GeneratorGetInputOrDebugPos(Node* args_reg,
     402             :                                                        Node* arg_count,
     403             :                                                        Node* context) {
     404          93 :   Node* generator = __ LoadRegister(args_reg);
     405             :   Node* const value =
     406          93 :       __ LoadObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset);
     407             : 
     408          93 :   return value;
     409             : }
     410             : 
     411          93 : Node* IntrinsicsGenerator::GeneratorGetResumeMode(Node* args_reg,
     412             :                                                   Node* arg_count,
     413             :                                                   Node* context) {
     414          93 :   Node* generator = __ LoadRegister(args_reg);
     415             :   Node* const value =
     416          93 :       __ LoadObjectField(generator, JSGeneratorObject::kResumeModeOffset);
     417             : 
     418          93 :   return value;
     419             : }
     420             : 
     421          93 : Node* IntrinsicsGenerator::GeneratorClose(Node* args_reg, Node* arg_count,
     422             :                                           Node* context) {
     423          93 :   Node* generator = __ LoadRegister(args_reg);
     424             :   __ StoreObjectFieldNoWriteBarrier(
     425             :       generator, JSGeneratorObject::kContinuationOffset,
     426         186 :       __ SmiConstant(JSGeneratorObject::kGeneratorClosed));
     427         186 :   return __ UndefinedConstant();
     428             : }
     429             : 
     430           0 : Node* IntrinsicsGenerator::AsyncGeneratorReject(Node* input, Node* arg_count,
     431             :                                                 Node* context) {
     432             :   return IntrinsicAsBuiltinCall(input, context,
     433          93 :                                 Builtins::kAsyncGeneratorReject);
     434             : }
     435             : 
     436           0 : Node* IntrinsicsGenerator::AsyncGeneratorResolve(Node* input, Node* arg_count,
     437             :                                                  Node* context) {
     438             :   return IntrinsicAsBuiltinCall(input, context,
     439          93 :                                 Builtins::kAsyncGeneratorResolve);
     440             : }
     441             : 
     442           0 : Node* IntrinsicsGenerator::AsyncGeneratorYield(Node* input, Node* arg_count,
     443             :                                                Node* context) {
     444          93 :   return IntrinsicAsBuiltinCall(input, context, Builtins::kAsyncGeneratorYield);
     445             : }
     446             : 
     447           0 : void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
     448           0 :   InterpreterAssembler::Label match(assembler_);
     449           0 :   Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
     450           0 :   __ GotoIf(comparison, &match);
     451           0 :   __ Abort(kWrongArgumentCountForInvokeIntrinsic);
     452           0 :   __ Goto(&match);
     453           0 :   __ BIND(&match);
     454           0 : }
     455             : 
     456             : #undef __
     457             : 
     458             : }  // namespace interpreter
     459             : }  // namespace internal
     460             : }  // namespace v8

Generated by: LCOV version 1.10