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 129 : explicit IntrinsicsGenerator(InterpreterAssembler* assembler)
24 129 : : isolate_(assembler->isolate()),
25 129 : zone_(assembler->zone()),
26 258 : 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 129 : Node* GenerateInvokeIntrinsic(InterpreterAssembler* assembler,
60 : Node* function_id, Node* context,
61 : Node* first_arg_reg, Node* arg_count) {
62 129 : IntrinsicsGenerator generator(assembler);
63 : return generator.InvokeIntrinsic(function_id, context, first_arg_reg,
64 129 : arg_count);
65 : }
66 :
67 : #define __ assembler_->
68 :
69 129 : Node* IntrinsicsGenerator::InvokeIntrinsic(Node* function_id, Node* context,
70 : Node* first_arg_reg,
71 : Node* arg_count) {
72 387 : InterpreterAssembler::Label abort(assembler_), end(assembler_);
73 : InterpreterAssembler::Variable result(assembler_,
74 258 : MachineRepresentation::kTagged);
75 :
76 : #define MAKE_LABEL(name, lower_case, count) \
77 : InterpreterAssembler::Label lower_case(assembler_);
78 2580 : INTRINSICS_LIST(MAKE_LABEL)
79 : #undef MAKE_LABEL
80 :
81 : #define LABEL_POINTER(name, lower_case, count) &lower_case,
82 129 : 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 129 : int32_t cases[] = {INTRINSICS_LIST(CASE)};
88 : #undef CASE
89 :
90 129 : __ Switch(function_id, &abort, cases, labels, arraysize(cases));
91 : #define HANDLE_CASE(name, lower_case, expected_arg_count) \
92 : __ Bind(&lower_case); \
93 : if (FLAG_debug_code && expected_arg_count >= 0) { \
94 : AbortIfArgCountMismatch(expected_arg_count, arg_count); \
95 : } \
96 : result.Bind(name(first_arg_reg, arg_count, context)); \
97 : __ Goto(&end);
98 903 : INTRINSICS_LIST(HANDLE_CASE)
99 : #undef HANDLE_CASE
100 :
101 129 : __ Bind(&abort);
102 : {
103 129 : __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
104 129 : result.Bind(__ UndefinedConstant());
105 129 : __ Goto(&end);
106 : }
107 :
108 129 : __ Bind(&end);
109 258 : return result.value();
110 : }
111 :
112 516 : Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
113 : InstanceTypeCompareMode mode) {
114 516 : Node* instance_type = __ LoadInstanceType(object);
115 :
116 516 : if (mode == kInstanceTypeEqual) {
117 387 : return __ Word32Equal(instance_type, __ Int32Constant(type));
118 : } else {
119 : DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
120 129 : return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
121 : }
122 : }
123 :
124 387 : Node* IntrinsicsGenerator::IsInstanceType(Node* input, int type) {
125 : InterpreterAssembler::Variable return_value(assembler_,
126 387 : MachineRepresentation::kTagged);
127 : // TODO(ishell): Use Select here.
128 1161 : InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
129 1161 : return_false(assembler_), end(assembler_);
130 387 : Node* arg = __ LoadRegister(input);
131 387 : __ GotoIf(__ TaggedIsSmi(arg), &return_false);
132 :
133 387 : Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
134 387 : __ Branch(condition, &return_true, &return_false);
135 :
136 387 : __ Bind(&return_true);
137 : {
138 387 : return_value.Bind(__ BooleanConstant(true));
139 387 : __ Goto(&end);
140 : }
141 :
142 387 : __ Bind(&return_false);
143 : {
144 387 : return_value.Bind(__ BooleanConstant(false));
145 387 : __ Goto(&end);
146 : }
147 :
148 387 : __ Bind(&end);
149 774 : return return_value.value();
150 : }
151 :
152 129 : Node* IntrinsicsGenerator::IsJSReceiver(Node* input, Node* arg_count,
153 : Node* context) {
154 : // TODO(ishell): Use Select here.
155 : // TODO(ishell): Use CSA::IsJSReceiverInstanceType here.
156 : InterpreterAssembler::Variable return_value(assembler_,
157 129 : MachineRepresentation::kTagged);
158 387 : InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
159 258 : end(assembler_);
160 :
161 129 : Node* arg = __ LoadRegister(input);
162 129 : __ GotoIf(__ TaggedIsSmi(arg), &return_false);
163 :
164 : STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
165 : Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
166 129 : kInstanceTypeGreaterThanOrEqual);
167 129 : __ Branch(condition, &return_true, &return_false);
168 :
169 129 : __ Bind(&return_true);
170 : {
171 129 : return_value.Bind(__ BooleanConstant(true));
172 129 : __ Goto(&end);
173 : }
174 :
175 129 : __ Bind(&return_false);
176 : {
177 129 : return_value.Bind(__ BooleanConstant(false));
178 129 : __ Goto(&end);
179 : }
180 :
181 129 : __ Bind(&end);
182 258 : return return_value.value();
183 : }
184 :
185 0 : Node* IntrinsicsGenerator::IsArray(Node* input, Node* arg_count,
186 : Node* context) {
187 129 : return IsInstanceType(input, JS_ARRAY_TYPE);
188 : }
189 :
190 0 : Node* IntrinsicsGenerator::IsJSProxy(Node* input, Node* arg_count,
191 : Node* context) {
192 129 : return IsInstanceType(input, JS_PROXY_TYPE);
193 : }
194 :
195 0 : Node* IntrinsicsGenerator::IsTypedArray(Node* input, Node* arg_count,
196 : Node* context) {
197 129 : return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
198 : }
199 :
200 129 : Node* IntrinsicsGenerator::IsSmi(Node* input, Node* arg_count, Node* context) {
201 : // TODO(ishell): Use SelectBooleanConstant here.
202 : InterpreterAssembler::Variable return_value(assembler_,
203 129 : MachineRepresentation::kTagged);
204 387 : InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
205 258 : end(assembler_);
206 :
207 129 : Node* arg = __ LoadRegister(input);
208 :
209 129 : __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi);
210 129 : __ Bind(&if_smi);
211 : {
212 129 : return_value.Bind(__ BooleanConstant(true));
213 129 : __ Goto(&end);
214 : }
215 :
216 129 : __ Bind(&if_not_smi);
217 : {
218 129 : return_value.Bind(__ BooleanConstant(false));
219 129 : __ Goto(&end);
220 : }
221 :
222 129 : __ Bind(&end);
223 258 : return return_value.value();
224 : }
225 :
226 1290 : Node* IntrinsicsGenerator::IntrinsicAsStubCall(Node* args_reg, Node* context,
227 1290 : Callable const& callable) {
228 : int param_count = callable.descriptor().GetParameterCount();
229 1290 : int input_count = param_count + 2; // +2 for target and context
230 1290 : Node** args = zone()->NewArray<Node*>(input_count);
231 : int index = 0;
232 1290 : args[index++] = __ HeapConstant(callable.code());
233 3483 : for (int i = 0; i < param_count; i++) {
234 2193 : args[index++] = __ LoadRegister(args_reg);
235 2193 : args_reg = __ NextRegister(args_reg);
236 : }
237 1290 : args[index++] = context;
238 1290 : return __ CallStubN(callable.descriptor(), 1, input_count, args);
239 : }
240 :
241 258 : Node* IntrinsicsGenerator::IntrinsicAsBuiltinCall(Node* input, Node* context,
242 : Builtins::Name name) {
243 258 : Callable callable = Builtins::CallableFor(isolate_, name);
244 258 : return IntrinsicAsStubCall(input, context, callable);
245 : }
246 :
247 129 : Node* IntrinsicsGenerator::CreateIterResultObject(Node* input, Node* arg_count,
248 129 : Node* context) {
249 : return IntrinsicAsStubCall(input, context,
250 129 : CodeFactory::CreateIterResultObject(isolate()));
251 : }
252 :
253 129 : Node* IntrinsicsGenerator::HasProperty(Node* input, Node* arg_count,
254 129 : Node* context) {
255 : return IntrinsicAsStubCall(input, context,
256 129 : CodeFactory::HasProperty(isolate()));
257 : }
258 :
259 129 : Node* IntrinsicsGenerator::SubString(Node* input, Node* arg_count,
260 129 : Node* context) {
261 129 : return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
262 : }
263 :
264 129 : Node* IntrinsicsGenerator::ToString(Node* input, Node* arg_count,
265 129 : Node* context) {
266 129 : return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
267 : }
268 :
269 129 : Node* IntrinsicsGenerator::ToLength(Node* input, Node* arg_count,
270 129 : Node* context) {
271 129 : return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
272 : }
273 :
274 129 : Node* IntrinsicsGenerator::ToInteger(Node* input, Node* arg_count,
275 129 : Node* context) {
276 129 : return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
277 : }
278 :
279 129 : Node* IntrinsicsGenerator::ToNumber(Node* input, Node* arg_count,
280 129 : Node* context) {
281 129 : return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
282 : }
283 :
284 129 : Node* IntrinsicsGenerator::ToObject(Node* input, Node* arg_count,
285 129 : Node* context) {
286 129 : return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
287 : }
288 :
289 129 : Node* IntrinsicsGenerator::Call(Node* args_reg, Node* arg_count,
290 : Node* context) {
291 : // First argument register contains the function target.
292 129 : Node* function = __ LoadRegister(args_reg);
293 :
294 : // Receiver is the second runtime call argument.
295 129 : Node* receiver_reg = __ NextRegister(args_reg);
296 129 : Node* receiver_arg = __ RegisterLocation(receiver_reg);
297 :
298 : // Subtract function and receiver from arg count.
299 129 : Node* function_and_receiver_count = __ Int32Constant(2);
300 129 : Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);
301 :
302 129 : if (FLAG_debug_code) {
303 0 : InterpreterAssembler::Label arg_count_positive(assembler_);
304 0 : Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
305 0 : __ GotoIfNot(comparison, &arg_count_positive);
306 0 : __ Abort(kWrongArgumentCountForInvokeIntrinsic);
307 0 : __ Goto(&arg_count_positive);
308 0 : __ Bind(&arg_count_positive);
309 : }
310 :
311 : Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
312 129 : ConvertReceiverMode::kAny, TailCallMode::kDisallow);
313 129 : return result;
314 : }
315 :
316 0 : Node* IntrinsicsGenerator::ClassOf(Node* args_reg, Node* arg_count,
317 : Node* context) {
318 129 : Node* value = __ LoadRegister(args_reg);
319 129 : return __ ClassOf(value);
320 : }
321 :
322 129 : Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(Node* args_reg,
323 : Node* arg_count,
324 : Node* context) {
325 : InterpreterAssembler::Label not_receiver(
326 129 : assembler_, InterpreterAssembler::Label::kDeferred);
327 258 : InterpreterAssembler::Label done(assembler_);
328 : InterpreterAssembler::Variable return_value(assembler_,
329 258 : MachineRepresentation::kTagged);
330 :
331 129 : Node* sync_iterator = __ LoadRegister(args_reg);
332 :
333 129 : __ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver);
334 129 : __ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver);
335 :
336 129 : Node* const native_context = __ LoadNativeContext(context);
337 : Node* const map = __ LoadContextElement(
338 129 : native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
339 129 : Node* const iterator = __ AllocateJSObjectFromMap(map);
340 :
341 : __ StoreObjectFieldNoWriteBarrier(
342 129 : iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
343 :
344 129 : return_value.Bind(iterator);
345 129 : __ Goto(&done);
346 :
347 129 : __ Bind(¬_receiver);
348 : {
349 : return_value.Bind(
350 129 : __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
351 :
352 : // Unreachable due to the Throw in runtime call.
353 129 : __ Goto(&done);
354 : }
355 :
356 129 : __ Bind(&done);
357 258 : return return_value.value();
358 : }
359 :
360 129 : Node* IntrinsicsGenerator::AsyncGeneratorGetAwaitInputOrDebugPos(
361 : Node* args_reg, Node* arg_count, Node* context) {
362 129 : Node* generator = __ LoadRegister(args_reg);
363 : CSA_SLOW_ASSERT(assembler_, __ HasInstanceType(
364 : generator, JS_ASYNC_GENERATOR_OBJECT_TYPE));
365 :
366 : Node* const value = __ LoadObjectField(
367 129 : generator, JSAsyncGeneratorObject::kAwaitInputOrDebugPosOffset);
368 :
369 129 : return value;
370 : }
371 :
372 0 : Node* IntrinsicsGenerator::AsyncGeneratorReject(Node* input, Node* arg_count,
373 : Node* context) {
374 : return IntrinsicAsBuiltinCall(input, context,
375 129 : Builtins::kAsyncGeneratorReject);
376 : }
377 :
378 0 : Node* IntrinsicsGenerator::AsyncGeneratorResolve(Node* input, Node* arg_count,
379 : Node* context) {
380 : return IntrinsicAsBuiltinCall(input, context,
381 129 : Builtins::kAsyncGeneratorResolve);
382 : }
383 :
384 0 : void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
385 0 : InterpreterAssembler::Label match(assembler_);
386 0 : Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
387 0 : __ GotoIf(comparison, &match);
388 0 : __ Abort(kWrongArgumentCountForInvokeIntrinsic);
389 0 : __ Goto(&match);
390 0 : __ Bind(&match);
391 0 : }
392 :
393 : } // namespace interpreter
394 : } // namespace internal
395 : } // namespace v8
|