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