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