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/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:
29 168 : explicit IntrinsicsGenerator(InterpreterAssembler* assembler)
30 168 : : isolate_(assembler->isolate()),
31 168 : zone_(assembler->zone()),
32 336 : 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);
54 : INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
55 : #undef DECLARE_INTRINSIC_HELPER
56 :
57 : Isolate* isolate() { return isolate_; }
58 : Zone* zone() { return zone_; }
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 :
68 168 : Node* GenerateInvokeIntrinsic(
69 : InterpreterAssembler* assembler, Node* function_id, Node* context,
70 : const InterpreterAssembler::RegListNodePair& args) {
71 168 : IntrinsicsGenerator generator(assembler);
72 168 : return generator.InvokeIntrinsic(function_id, context, args);
73 : }
74 :
75 : #define __ assembler_->
76 :
77 168 : Node* IntrinsicsGenerator::InvokeIntrinsic(
78 : Node* function_id, Node* context,
79 : const InterpreterAssembler::RegListNodePair& args) {
80 504 : InterpreterAssembler::Label abort(assembler_), end(assembler_);
81 168 : InterpreterAssembler::Variable result(assembler_,
82 336 : MachineRepresentation::kTagged);
83 :
84 : #define MAKE_LABEL(name, lower_case, count) \
85 : InterpreterAssembler::Label lower_case(assembler_);
86 4368 : INTRINSICS_LIST(MAKE_LABEL)
87 : #undef MAKE_LABEL
88 :
89 : #define LABEL_POINTER(name, lower_case, count) &lower_case,
90 168 : 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 168 : int32_t cases[] = {INTRINSICS_LIST(CASE)};
96 : #undef CASE
97 :
98 168 : __ 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 2016 : INTRINSICS_LIST(HANDLE_CASE)
112 : #undef HANDLE_CASE
113 :
114 168 : __ BIND(&abort);
115 : {
116 168 : __ Abort(AbortReason::kUnexpectedFunctionIDForInvokeIntrinsic);
117 336 : result.Bind(__ UndefinedConstant());
118 168 : __ Goto(&end);
119 : }
120 :
121 168 : __ BIND(&end);
122 336 : return result.value();
123 : }
124 :
125 336 : Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
126 : InstanceTypeCompareMode mode) {
127 672 : Node* instance_type = __ LoadInstanceType(object);
128 :
129 336 : if (mode == kInstanceTypeEqual) {
130 1008 : return __ Word32Equal(instance_type, __ Int32Constant(type));
131 : } else {
132 : DCHECK_EQ(mode, kInstanceTypeGreaterThanOrEqual);
133 0 : return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
134 : }
135 : }
136 :
137 336 : Node* IntrinsicsGenerator::IsInstanceType(Node* input, int type) {
138 336 : TNode<Oddball> result = __ Select<Oddball>(
139 1008 : __ TaggedIsSmi(input), [=] { return __ FalseConstant(); },
140 336 : [=] {
141 672 : return __ SelectBooleanConstant(
142 1344 : CompareInstanceType(input, type, kInstanceTypeEqual));
143 1680 : });
144 336 : return result;
145 : }
146 :
147 168 : Node* IntrinsicsGenerator::IsJSReceiver(
148 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
149 168 : Node* input = __ LoadRegisterFromRegisterList(args, 0);
150 168 : TNode<Oddball> result = __ Select<Oddball>(
151 504 : __ TaggedIsSmi(input), [=] { return __ FalseConstant(); },
152 1008 : [=] { return __ SelectBooleanConstant(__ IsJSReceiver(input)); });
153 168 : return result;
154 : }
155 :
156 168 : Node* IntrinsicsGenerator::IsArray(
157 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
158 168 : Node* input = __ LoadRegisterFromRegisterList(args, 0);
159 168 : return IsInstanceType(input, JS_ARRAY_TYPE);
160 : }
161 :
162 168 : Node* IntrinsicsGenerator::IsTypedArray(
163 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
164 168 : Node* input = __ LoadRegisterFromRegisterList(args, 0);
165 168 : return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
166 : }
167 :
168 168 : Node* IntrinsicsGenerator::IsSmi(
169 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
170 168 : Node* input = __ LoadRegisterFromRegisterList(args, 0);
171 504 : return __ SelectBooleanConstant(__ TaggedIsSmi(input));
172 : }
173 :
174 2688 : Node* IntrinsicsGenerator::IntrinsicAsStubCall(
175 : const InterpreterAssembler::RegListNodePair& args, Node* context,
176 : Callable const& callable) {
177 : int param_count = callable.descriptor().GetParameterCount();
178 2688 : int input_count = param_count + 2; // +2 for target and context
179 2688 : Node** stub_args = zone()->NewArray<Node*>(input_count);
180 : int index = 0;
181 5376 : stub_args[index++] = __ HeapConstant(callable.code());
182 13776 : for (int i = 0; i < param_count; i++) {
183 5544 : stub_args[index++] = __ LoadRegisterFromRegisterList(args, i);
184 : }
185 2688 : stub_args[index++] = context;
186 5376 : return __ CallStubN(StubCallMode::kCallCodeObject, callable.descriptor(), 1,
187 5376 : input_count, stub_args);
188 : }
189 :
190 1848 : Node* IntrinsicsGenerator::IntrinsicAsBuiltinCall(
191 : const InterpreterAssembler::RegListNodePair& args, Node* context,
192 : Builtins::Name name) {
193 1848 : Callable callable = Builtins::CallableFor(isolate_, name);
194 3696 : return IntrinsicAsStubCall(args, context, callable);
195 : }
196 :
197 168 : Node* IntrinsicsGenerator::CreateIterResultObject(
198 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
199 : return IntrinsicAsStubCall(
200 : args, context,
201 336 : Builtins::CallableFor(isolate(), Builtins::kCreateIterResultObject));
202 : }
203 :
204 168 : Node* IntrinsicsGenerator::HasProperty(
205 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
206 : return IntrinsicAsStubCall(
207 336 : args, context, Builtins::CallableFor(isolate(), Builtins::kHasProperty));
208 : }
209 :
210 168 : Node* IntrinsicsGenerator::ToString(
211 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
212 : return IntrinsicAsStubCall(
213 336 : args, context, Builtins::CallableFor(isolate(), Builtins::kToString));
214 : }
215 :
216 168 : Node* IntrinsicsGenerator::ToLength(
217 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
218 : return IntrinsicAsStubCall(
219 336 : args, context, Builtins::CallableFor(isolate(), Builtins::kToLength));
220 : }
221 :
222 168 : Node* IntrinsicsGenerator::ToObject(
223 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
224 : return IntrinsicAsStubCall(
225 336 : args, context, Builtins::CallableFor(isolate(), Builtins::kToObject));
226 : }
227 :
228 168 : Node* IntrinsicsGenerator::Call(
229 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
230 : // First argument register contains the function target.
231 168 : Node* function = __ LoadRegisterFromRegisterList(args, 0);
232 :
233 : // The arguments for the target function are from the second runtime call
234 : // argument.
235 : InterpreterAssembler::RegListNodePair target_args(
236 168 : __ RegisterLocationInRegisterList(args, 1),
237 672 : __ Int32Sub(args.reg_count(), __ Int32Constant(1)));
238 :
239 168 : if (FLAG_debug_code) {
240 0 : InterpreterAssembler::Label arg_count_positive(assembler_);
241 : Node* comparison =
242 0 : __ Int32LessThan(target_args.reg_count(), __ Int32Constant(0));
243 0 : __ GotoIfNot(comparison, &arg_count_positive);
244 0 : __ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
245 0 : __ Goto(&arg_count_positive);
246 0 : __ BIND(&arg_count_positive);
247 : }
248 :
249 168 : __ CallJSAndDispatch(function, context, target_args,
250 168 : ConvertReceiverMode::kAny);
251 168 : return nullptr; // We never return from the CallJSAndDispatch above.
252 : }
253 :
254 168 : Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(
255 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
256 : InterpreterAssembler::Label not_receiver(
257 336 : assembler_, InterpreterAssembler::Label::kDeferred);
258 336 : InterpreterAssembler::Label done(assembler_);
259 168 : InterpreterAssembler::Variable return_value(assembler_,
260 336 : MachineRepresentation::kTagged);
261 :
262 168 : Node* sync_iterator = __ LoadRegisterFromRegisterList(args, 0);
263 :
264 336 : __ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver);
265 336 : __ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver);
266 :
267 : Node* const next =
268 336 : __ GetProperty(context, sync_iterator, factory()->next_string());
269 :
270 336 : Node* const native_context = __ LoadNativeContext(context);
271 504 : Node* const map = __ LoadContextElement(
272 336 : native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
273 168 : Node* const iterator = __ AllocateJSObjectFromMap(map);
274 :
275 168 : __ StoreObjectFieldNoWriteBarrier(
276 168 : iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
277 168 : __ StoreObjectFieldNoWriteBarrier(iterator,
278 168 : JSAsyncFromSyncIterator::kNextOffset, next);
279 :
280 168 : return_value.Bind(iterator);
281 168 : __ Goto(&done);
282 :
283 168 : __ BIND(¬_receiver);
284 : {
285 : return_value.Bind(
286 336 : __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
287 :
288 : // Unreachable due to the Throw in runtime call.
289 168 : __ Goto(&done);
290 : }
291 :
292 168 : __ BIND(&done);
293 336 : return return_value.value();
294 : }
295 :
296 0 : Node* IntrinsicsGenerator::CreateJSGeneratorObject(
297 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
298 : return IntrinsicAsBuiltinCall(args, context,
299 168 : Builtins::kCreateGeneratorObject);
300 : }
301 :
302 168 : Node* IntrinsicsGenerator::GeneratorGetResumeMode(
303 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
304 168 : Node* generator = __ LoadRegisterFromRegisterList(args, 0);
305 : Node* const value =
306 168 : __ LoadObjectField(generator, JSGeneratorObject::kResumeModeOffset);
307 :
308 168 : return value;
309 : }
310 :
311 168 : Node* IntrinsicsGenerator::GeneratorClose(
312 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
313 168 : Node* generator = __ LoadRegisterFromRegisterList(args, 0);
314 168 : __ StoreObjectFieldNoWriteBarrier(
315 : generator, JSGeneratorObject::kContinuationOffset,
316 336 : __ SmiConstant(JSGeneratorObject::kGeneratorClosed));
317 336 : return __ UndefinedConstant();
318 : }
319 :
320 168 : Node* IntrinsicsGenerator::GetImportMetaObject(
321 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
322 336 : Node* const module_context = __ LoadModuleContext(context);
323 : Node* const module =
324 336 : __ LoadContextElement(module_context, Context::EXTENSION_INDEX);
325 : Node* const import_meta =
326 168 : __ LoadObjectField(module, Module::kImportMetaOffset);
327 :
328 168 : InterpreterAssembler::Variable return_value(assembler_,
329 336 : MachineRepresentation::kTagged);
330 168 : return_value.Bind(import_meta);
331 :
332 336 : InterpreterAssembler::Label end(assembler_);
333 336 : __ GotoIfNot(__ IsTheHole(import_meta), &end);
334 :
335 336 : return_value.Bind(__ CallRuntime(Runtime::kGetImportMetaObject, context));
336 168 : __ Goto(&end);
337 :
338 168 : __ BIND(&end);
339 336 : return return_value.value();
340 : }
341 :
342 0 : Node* IntrinsicsGenerator::AsyncFunctionAwaitCaught(
343 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
344 : return IntrinsicAsBuiltinCall(args, context,
345 168 : Builtins::kAsyncFunctionAwaitCaught);
346 : }
347 :
348 0 : Node* IntrinsicsGenerator::AsyncFunctionAwaitUncaught(
349 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
350 : return IntrinsicAsBuiltinCall(args, context,
351 168 : Builtins::kAsyncFunctionAwaitUncaught);
352 : }
353 :
354 0 : Node* IntrinsicsGenerator::AsyncFunctionEnter(
355 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
356 168 : return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncFunctionEnter);
357 : }
358 :
359 0 : Node* IntrinsicsGenerator::AsyncFunctionReject(
360 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
361 168 : return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncFunctionReject);
362 : }
363 :
364 0 : Node* IntrinsicsGenerator::AsyncFunctionResolve(
365 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
366 168 : return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncFunctionResolve);
367 : }
368 :
369 0 : Node* IntrinsicsGenerator::AsyncGeneratorAwaitCaught(
370 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
371 : return IntrinsicAsBuiltinCall(args, context,
372 168 : Builtins::kAsyncGeneratorAwaitCaught);
373 : }
374 :
375 0 : Node* IntrinsicsGenerator::AsyncGeneratorAwaitUncaught(
376 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
377 : return IntrinsicAsBuiltinCall(args, context,
378 168 : Builtins::kAsyncGeneratorAwaitUncaught);
379 : }
380 :
381 0 : Node* IntrinsicsGenerator::AsyncGeneratorReject(
382 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
383 168 : return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorReject);
384 : }
385 :
386 0 : Node* IntrinsicsGenerator::AsyncGeneratorResolve(
387 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
388 : return IntrinsicAsBuiltinCall(args, context,
389 168 : Builtins::kAsyncGeneratorResolve);
390 : }
391 :
392 0 : Node* IntrinsicsGenerator::AsyncGeneratorYield(
393 : const InterpreterAssembler::RegListNodePair& args, Node* context) {
394 168 : return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorYield);
395 : }
396 :
397 0 : void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
398 0 : InterpreterAssembler::Label match(assembler_);
399 0 : Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
400 0 : __ GotoIf(comparison, &match);
401 0 : __ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
402 0 : __ Goto(&match);
403 0 : __ BIND(&match);
404 0 : }
405 :
406 : #undef __
407 :
408 : } // namespace interpreter
409 : } // namespace internal
410 59480 : } // namespace v8
|