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