• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/heap/factory-inl.h"
12 #include "src/interpreter/bytecodes.h"
13 #include "src/interpreter/interpreter-assembler.h"
14 #include "src/interpreter/interpreter-intrinsics.h"
15 #include "src/objects-inl.h"
16 #include "src/objects/js-generator.h"
17 #include "src/objects/module.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace interpreter {
22 
23 using compiler::Node;
24 template <typename T>
25 using TNode = compiler::TNode<T>;
26 
27 class IntrinsicsGenerator {
28  public:
IntrinsicsGenerator(InterpreterAssembler * assembler)29   explicit IntrinsicsGenerator(InterpreterAssembler* assembler)
30       : isolate_(assembler->isolate()),
31         zone_(assembler->zone()),
32         assembler_(assembler) {}
33 
34   Node* InvokeIntrinsic(Node* function_id, Node* context,
35                         const InterpreterAssembler::RegListNodePair& args);
36 
37  private:
38   enum InstanceTypeCompareMode {
39     kInstanceTypeEqual,
40     kInstanceTypeGreaterThanOrEqual
41   };
42 
43   Node* IsInstanceType(Node* input, int type);
44   Node* CompareInstanceType(Node* map, int type, InstanceTypeCompareMode mode);
45   Node* IntrinsicAsStubCall(const InterpreterAssembler::RegListNodePair& args,
46                             Node* context, Callable const& callable);
47   Node* IntrinsicAsBuiltinCall(
48       const InterpreterAssembler::RegListNodePair& args, Node* context,
49       Builtins::Name name);
50   void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
51 
52 #define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
53   Node* name(const InterpreterAssembler::RegListNodePair& args, Node* context);
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)54   INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
55 #undef DECLARE_INTRINSIC_HELPER
56 
57   Isolate* isolate() { return isolate_; }
zone()58   Zone* zone() { return zone_; }
factory()59   Factory* factory() { return isolate()->factory(); }
60 
61   Isolate* isolate_;
62   Zone* zone_;
63   InterpreterAssembler* assembler_;
64 
65   DISALLOW_COPY_AND_ASSIGN(IntrinsicsGenerator);
66 };
67 
GenerateInvokeIntrinsic(InterpreterAssembler * assembler,Node * function_id,Node * context,const InterpreterAssembler::RegListNodePair & args)68 Node* GenerateInvokeIntrinsic(
69     InterpreterAssembler* assembler, Node* function_id, Node* context,
70     const InterpreterAssembler::RegListNodePair& args) {
71   IntrinsicsGenerator generator(assembler);
72   return generator.InvokeIntrinsic(function_id, context, args);
73 }
74 
75 #define __ assembler_->
76 
InvokeIntrinsic(Node * function_id,Node * context,const InterpreterAssembler::RegListNodePair & args)77 Node* IntrinsicsGenerator::InvokeIntrinsic(
78     Node* function_id, Node* context,
79     const InterpreterAssembler::RegListNodePair& args) {
80   InterpreterAssembler::Label abort(assembler_), end(assembler_);
81   InterpreterAssembler::Variable result(assembler_,
82                                         MachineRepresentation::kTagged);
83 
84 #define MAKE_LABEL(name, lower_case, count) \
85   InterpreterAssembler::Label lower_case(assembler_);
86   INTRINSICS_LIST(MAKE_LABEL)
87 #undef MAKE_LABEL
88 
89 #define LABEL_POINTER(name, lower_case, count) &lower_case,
90   InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)};
91 #undef LABEL_POINTER
92 
93 #define CASE(name, lower_case, count) \
94   static_cast<int32_t>(IntrinsicsHelper::IntrinsicId::k##name),
95   int32_t cases[] = {INTRINSICS_LIST(CASE)};
96 #undef CASE
97 
98   __ Switch(function_id, &abort, cases, labels, arraysize(cases));
99 #define HANDLE_CASE(name, lower_case, expected_arg_count)            \
100   __ BIND(&lower_case);                                              \
101   {                                                                  \
102     if (FLAG_debug_code && expected_arg_count >= 0) {                \
103       AbortIfArgCountMismatch(expected_arg_count, args.reg_count()); \
104     }                                                                \
105     Node* value = name(args, context);                               \
106     if (value) {                                                     \
107       result.Bind(value);                                            \
108       __ Goto(&end);                                                 \
109     }                                                                \
110   }
111   INTRINSICS_LIST(HANDLE_CASE)
112 #undef HANDLE_CASE
113 
114   __ BIND(&abort);
115   {
116     __ Abort(AbortReason::kUnexpectedFunctionIDForInvokeIntrinsic);
117     result.Bind(__ UndefinedConstant());
118     __ Goto(&end);
119   }
120 
121   __ BIND(&end);
122   return result.value();
123 }
124 
CompareInstanceType(Node * object,int type,InstanceTypeCompareMode mode)125 Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
126                                                InstanceTypeCompareMode mode) {
127   Node* instance_type = __ LoadInstanceType(object);
128 
129   if (mode == kInstanceTypeEqual) {
130     return __ Word32Equal(instance_type, __ Int32Constant(type));
131   } else {
132     DCHECK_EQ(mode, kInstanceTypeGreaterThanOrEqual);
133     return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
134   }
135 }
136 
IsInstanceType(Node * input,int type)137 Node* IntrinsicsGenerator::IsInstanceType(Node* input, int type) {
138   TNode<Oddball> result = __ Select<Oddball>(
139       __ TaggedIsSmi(input), [=] { return __ FalseConstant(); },
140       [=] {
141         return __ SelectBooleanConstant(
142             CompareInstanceType(input, type, kInstanceTypeEqual));
143       });
144   return result;
145 }
146 
IsJSReceiver(const InterpreterAssembler::RegListNodePair & args,Node * context)147 Node* IntrinsicsGenerator::IsJSReceiver(
148     const InterpreterAssembler::RegListNodePair& args, Node* context) {
149   Node* input = __ LoadRegisterFromRegisterList(args, 0);
150   TNode<Oddball> result = __ Select<Oddball>(
151       __ TaggedIsSmi(input), [=] { return __ FalseConstant(); },
152       [=] { return __ SelectBooleanConstant(__ IsJSReceiver(input)); });
153   return result;
154 }
155 
IsArray(const InterpreterAssembler::RegListNodePair & args,Node * context)156 Node* IntrinsicsGenerator::IsArray(
157     const InterpreterAssembler::RegListNodePair& args, Node* context) {
158   Node* input = __ LoadRegisterFromRegisterList(args, 0);
159   return IsInstanceType(input, JS_ARRAY_TYPE);
160 }
161 
IsJSProxy(const InterpreterAssembler::RegListNodePair & args,Node * context)162 Node* IntrinsicsGenerator::IsJSProxy(
163     const InterpreterAssembler::RegListNodePair& args, Node* context) {
164   Node* input = __ LoadRegisterFromRegisterList(args, 0);
165   return IsInstanceType(input, JS_PROXY_TYPE);
166 }
167 
IsTypedArray(const InterpreterAssembler::RegListNodePair & args,Node * context)168 Node* IntrinsicsGenerator::IsTypedArray(
169     const InterpreterAssembler::RegListNodePair& args, Node* context) {
170   Node* input = __ LoadRegisterFromRegisterList(args, 0);
171   return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
172 }
173 
IsSmi(const InterpreterAssembler::RegListNodePair & args,Node * context)174 Node* IntrinsicsGenerator::IsSmi(
175     const InterpreterAssembler::RegListNodePair& args, Node* context) {
176   Node* input = __ LoadRegisterFromRegisterList(args, 0);
177   return __ SelectBooleanConstant(__ TaggedIsSmi(input));
178 }
179 
IntrinsicAsStubCall(const InterpreterAssembler::RegListNodePair & args,Node * context,Callable const & callable)180 Node* IntrinsicsGenerator::IntrinsicAsStubCall(
181     const InterpreterAssembler::RegListNodePair& args, Node* context,
182     Callable const& callable) {
183   int param_count = callable.descriptor().GetParameterCount();
184   int input_count = param_count + 2;  // +2 for target and context
185   Node** stub_args = zone()->NewArray<Node*>(input_count);
186   int index = 0;
187   stub_args[index++] = __ HeapConstant(callable.code());
188   for (int i = 0; i < param_count; i++) {
189     stub_args[index++] = __ LoadRegisterFromRegisterList(args, i);
190   }
191   stub_args[index++] = context;
192   return __ CallStubN(callable.descriptor(), 1, input_count, stub_args);
193 }
194 
IntrinsicAsBuiltinCall(const InterpreterAssembler::RegListNodePair & args,Node * context,Builtins::Name name)195 Node* IntrinsicsGenerator::IntrinsicAsBuiltinCall(
196     const InterpreterAssembler::RegListNodePair& args, Node* context,
197     Builtins::Name name) {
198   Callable callable = Builtins::CallableFor(isolate_, name);
199   return IntrinsicAsStubCall(args, context, callable);
200 }
201 
CreateIterResultObject(const InterpreterAssembler::RegListNodePair & args,Node * context)202 Node* IntrinsicsGenerator::CreateIterResultObject(
203     const InterpreterAssembler::RegListNodePair& args, Node* context) {
204   return IntrinsicAsStubCall(
205       args, context,
206       Builtins::CallableFor(isolate(), Builtins::kCreateIterResultObject));
207 }
208 
HasProperty(const InterpreterAssembler::RegListNodePair & args,Node * context)209 Node* IntrinsicsGenerator::HasProperty(
210     const InterpreterAssembler::RegListNodePair& args, Node* context) {
211   return IntrinsicAsStubCall(
212       args, context, Builtins::CallableFor(isolate(), Builtins::kHasProperty));
213 }
214 
GetProperty(const InterpreterAssembler::RegListNodePair & args,Node * context)215 Node* IntrinsicsGenerator::GetProperty(
216     const InterpreterAssembler::RegListNodePair& args, Node* context) {
217   return IntrinsicAsStubCall(
218       args, context, Builtins::CallableFor(isolate(), Builtins::kGetProperty));
219 }
220 
RejectPromise(const InterpreterAssembler::RegListNodePair & args,Node * context)221 Node* IntrinsicsGenerator::RejectPromise(
222     const InterpreterAssembler::RegListNodePair& args, Node* context) {
223   return IntrinsicAsStubCall(
224       args, context,
225       Builtins::CallableFor(isolate(), Builtins::kRejectPromise));
226 }
227 
ResolvePromise(const InterpreterAssembler::RegListNodePair & args,Node * context)228 Node* IntrinsicsGenerator::ResolvePromise(
229     const InterpreterAssembler::RegListNodePair& args, Node* context) {
230   return IntrinsicAsStubCall(
231       args, context,
232       Builtins::CallableFor(isolate(), Builtins::kResolvePromise));
233 }
234 
ToString(const InterpreterAssembler::RegListNodePair & args,Node * context)235 Node* IntrinsicsGenerator::ToString(
236     const InterpreterAssembler::RegListNodePair& args, Node* context) {
237   return IntrinsicAsStubCall(
238       args, context, Builtins::CallableFor(isolate(), Builtins::kToString));
239 }
240 
ToLength(const InterpreterAssembler::RegListNodePair & args,Node * context)241 Node* IntrinsicsGenerator::ToLength(
242     const InterpreterAssembler::RegListNodePair& args, Node* context) {
243   return IntrinsicAsStubCall(
244       args, context, Builtins::CallableFor(isolate(), Builtins::kToLength));
245 }
246 
ToInteger(const InterpreterAssembler::RegListNodePair & args,Node * context)247 Node* IntrinsicsGenerator::ToInteger(
248     const InterpreterAssembler::RegListNodePair& args, Node* context) {
249   return IntrinsicAsStubCall(
250       args, context, Builtins::CallableFor(isolate(), Builtins::kToInteger));
251 }
252 
ToNumber(const InterpreterAssembler::RegListNodePair & args,Node * context)253 Node* IntrinsicsGenerator::ToNumber(
254     const InterpreterAssembler::RegListNodePair& args, Node* context) {
255   return IntrinsicAsStubCall(
256       args, context, Builtins::CallableFor(isolate(), Builtins::kToNumber));
257 }
258 
ToObject(const InterpreterAssembler::RegListNodePair & args,Node * context)259 Node* IntrinsicsGenerator::ToObject(
260     const InterpreterAssembler::RegListNodePair& args, Node* context) {
261   return IntrinsicAsStubCall(
262       args, context, Builtins::CallableFor(isolate(), Builtins::kToObject));
263 }
264 
Call(const InterpreterAssembler::RegListNodePair & args,Node * context)265 Node* IntrinsicsGenerator::Call(
266     const InterpreterAssembler::RegListNodePair& args, Node* context) {
267   // First argument register contains the function target.
268   Node* function = __ LoadRegisterFromRegisterList(args, 0);
269 
270   // The arguments for the target function are from the second runtime call
271   // argument.
272   InterpreterAssembler::RegListNodePair target_args(
273       __ RegisterLocationInRegisterList(args, 1),
274       __ Int32Sub(args.reg_count(), __ Int32Constant(1)));
275 
276   if (FLAG_debug_code) {
277     InterpreterAssembler::Label arg_count_positive(assembler_);
278     Node* comparison =
279         __ Int32LessThan(target_args.reg_count(), __ Int32Constant(0));
280     __ GotoIfNot(comparison, &arg_count_positive);
281     __ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
282     __ Goto(&arg_count_positive);
283     __ BIND(&arg_count_positive);
284   }
285 
286   __ CallJSAndDispatch(function, context, target_args,
287                        ConvertReceiverMode::kAny);
288   return nullptr;  // We never return from the CallJSAndDispatch above.
289 }
290 
CreateAsyncFromSyncIterator(const InterpreterAssembler::RegListNodePair & args,Node * context)291 Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(
292     const InterpreterAssembler::RegListNodePair& args, Node* context) {
293   InterpreterAssembler::Label not_receiver(
294       assembler_, InterpreterAssembler::Label::kDeferred);
295   InterpreterAssembler::Label done(assembler_);
296   InterpreterAssembler::Variable return_value(assembler_,
297                                               MachineRepresentation::kTagged);
298 
299   Node* sync_iterator = __ LoadRegisterFromRegisterList(args, 0);
300 
301   __ GotoIf(__ TaggedIsSmi(sync_iterator), &not_receiver);
302   __ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_receiver);
303 
304   Node* const next =
305       __ GetProperty(context, sync_iterator, factory()->next_string());
306 
307   Node* const native_context = __ LoadNativeContext(context);
308   Node* const map = __ LoadContextElement(
309       native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
310   Node* const iterator = __ AllocateJSObjectFromMap(map);
311 
312   __ StoreObjectFieldNoWriteBarrier(
313       iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
314   __ StoreObjectFieldNoWriteBarrier(iterator,
315                                     JSAsyncFromSyncIterator::kNextOffset, next);
316 
317   return_value.Bind(iterator);
318   __ Goto(&done);
319 
320   __ BIND(&not_receiver);
321   {
322     return_value.Bind(
323         __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
324 
325     // Unreachable due to the Throw in runtime call.
326     __ Goto(&done);
327   }
328 
329   __ BIND(&done);
330   return return_value.value();
331 }
332 
CreateJSGeneratorObject(const InterpreterAssembler::RegListNodePair & args,Node * context)333 Node* IntrinsicsGenerator::CreateJSGeneratorObject(
334     const InterpreterAssembler::RegListNodePair& args, Node* context) {
335   return IntrinsicAsBuiltinCall(args, context,
336                                 Builtins::kCreateGeneratorObject);
337 }
338 
GeneratorGetInputOrDebugPos(const InterpreterAssembler::RegListNodePair & args,Node * context)339 Node* IntrinsicsGenerator::GeneratorGetInputOrDebugPos(
340     const InterpreterAssembler::RegListNodePair& args, Node* context) {
341   Node* generator = __ LoadRegisterFromRegisterList(args, 0);
342   Node* const value =
343       __ LoadObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset);
344 
345   return value;
346 }
347 
GeneratorGetResumeMode(const InterpreterAssembler::RegListNodePair & args,Node * context)348 Node* IntrinsicsGenerator::GeneratorGetResumeMode(
349     const InterpreterAssembler::RegListNodePair& args, Node* context) {
350   Node* generator = __ LoadRegisterFromRegisterList(args, 0);
351   Node* const value =
352       __ LoadObjectField(generator, JSGeneratorObject::kResumeModeOffset);
353 
354   return value;
355 }
356 
GeneratorClose(const InterpreterAssembler::RegListNodePair & args,Node * context)357 Node* IntrinsicsGenerator::GeneratorClose(
358     const InterpreterAssembler::RegListNodePair& args, Node* context) {
359   Node* generator = __ LoadRegisterFromRegisterList(args, 0);
360   __ StoreObjectFieldNoWriteBarrier(
361       generator, JSGeneratorObject::kContinuationOffset,
362       __ SmiConstant(JSGeneratorObject::kGeneratorClosed));
363   return __ UndefinedConstant();
364 }
365 
GetImportMetaObject(const InterpreterAssembler::RegListNodePair & args,Node * context)366 Node* IntrinsicsGenerator::GetImportMetaObject(
367     const InterpreterAssembler::RegListNodePair& args, Node* context) {
368   Node* const module_context = __ LoadModuleContext(context);
369   Node* const module =
370       __ LoadContextElement(module_context, Context::EXTENSION_INDEX);
371   Node* const import_meta =
372       __ LoadObjectField(module, Module::kImportMetaOffset);
373 
374   InterpreterAssembler::Variable return_value(assembler_,
375                                               MachineRepresentation::kTagged);
376   return_value.Bind(import_meta);
377 
378   InterpreterAssembler::Label end(assembler_);
379   __ GotoIfNot(__ IsTheHole(import_meta), &end);
380 
381   return_value.Bind(__ CallRuntime(Runtime::kGetImportMetaObject, context));
382   __ Goto(&end);
383 
384   __ BIND(&end);
385   return return_value.value();
386 }
387 
AsyncGeneratorReject(const InterpreterAssembler::RegListNodePair & args,Node * context)388 Node* IntrinsicsGenerator::AsyncGeneratorReject(
389     const InterpreterAssembler::RegListNodePair& args, Node* context) {
390   return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorReject);
391 }
392 
AsyncGeneratorResolve(const InterpreterAssembler::RegListNodePair & args,Node * context)393 Node* IntrinsicsGenerator::AsyncGeneratorResolve(
394     const InterpreterAssembler::RegListNodePair& args, Node* context) {
395   return IntrinsicAsBuiltinCall(args, context,
396                                 Builtins::kAsyncGeneratorResolve);
397 }
398 
AsyncGeneratorYield(const InterpreterAssembler::RegListNodePair & args,Node * context)399 Node* IntrinsicsGenerator::AsyncGeneratorYield(
400     const InterpreterAssembler::RegListNodePair& args, Node* context) {
401   return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorYield);
402 }
403 
AbortIfArgCountMismatch(int expected,Node * actual)404 void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
405   InterpreterAssembler::Label match(assembler_);
406   Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
407   __ GotoIf(comparison, &match);
408   __ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
409   __ Goto(&match);
410   __ BIND(&match);
411 }
412 
413 #undef __
414 
415 }  // namespace interpreter
416 }  // namespace internal
417 }  // namespace v8
418