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), ¬_receiver);
272 __ GotoIfNot(__ IsJSReceiver(__ CAST(sync_iterator)), ¬_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(¬_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