blob: 109bf8ec342548a451c3be9e54e6f302076908a1 [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2015 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.h"
6
Ben Murdoch61f157c2016-09-16 13:49:30 +01007#include "src/code-factory.h"
8
Ben Murdochda12d292016-06-02 14:46:10 +01009namespace v8 {
10namespace internal {
11namespace interpreter {
12
13using compiler::Node;
14
15#define __ assembler_->
16
17IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
Ben Murdoch61f157c2016-09-16 13:49:30 +010018 : isolate_(assembler->isolate()),
19 zone_(assembler->zone()),
20 assembler_(assembler) {}
Ben Murdochda12d292016-06-02 14:46:10 +010021
Ben Murdoch61f157c2016-09-16 13:49:30 +010022// static
Ben Murdochda12d292016-06-02 14:46:10 +010023bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
24 switch (function_id) {
25#define SUPPORTED(name, lower_case, count) case Runtime::kInline##name:
26 INTRINSICS_LIST(SUPPORTED)
27 return true;
28#undef SUPPORTED
29 default:
30 return false;
31 }
32}
33
Ben Murdoch61f157c2016-09-16 13:49:30 +010034// static
35IntrinsicsHelper::IntrinsicId IntrinsicsHelper::FromRuntimeId(
36 Runtime::FunctionId function_id) {
37 switch (function_id) {
38#define TO_RUNTIME_ID(name, lower_case, count) \
39 case Runtime::kInline##name: \
40 return IntrinsicId::k##name;
41 INTRINSICS_LIST(TO_RUNTIME_ID)
42#undef TO_RUNTIME_ID
43 default:
44 UNREACHABLE();
45 return static_cast<IntrinsicsHelper::IntrinsicId>(-1);
46 }
47}
48
49// static
50Runtime::FunctionId IntrinsicsHelper::ToRuntimeId(
51 IntrinsicsHelper::IntrinsicId intrinsic_id) {
52 switch (intrinsic_id) {
53#define TO_INTRINSIC_ID(name, lower_case, count) \
54 case IntrinsicId::k##name: \
55 return Runtime::kInline##name;
56 INTRINSICS_LIST(TO_INTRINSIC_ID)
57#undef TO_INTRINSIC_ID
58 default:
59 UNREACHABLE();
60 return static_cast<Runtime::FunctionId>(-1);
61 }
62}
63
Ben Murdochda12d292016-06-02 14:46:10 +010064Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
65 Node* first_arg_reg, Node* arg_count) {
66 InterpreterAssembler::Label abort(assembler_), end(assembler_);
67 InterpreterAssembler::Variable result(assembler_,
68 MachineRepresentation::kTagged);
69
70#define MAKE_LABEL(name, lower_case, count) \
71 InterpreterAssembler::Label lower_case(assembler_);
72 INTRINSICS_LIST(MAKE_LABEL)
73#undef MAKE_LABEL
74
75#define LABEL_POINTER(name, lower_case, count) &lower_case,
76 InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)};
77#undef LABEL_POINTER
78
79#define CASE(name, lower_case, count) \
Ben Murdoch61f157c2016-09-16 13:49:30 +010080 static_cast<int32_t>(IntrinsicId::k##name),
Ben Murdochda12d292016-06-02 14:46:10 +010081 int32_t cases[] = {INTRINSICS_LIST(CASE)};
82#undef CASE
83
84 __ Switch(function_id, &abort, cases, labels, arraysize(cases));
85#define HANDLE_CASE(name, lower_case, expected_arg_count) \
86 __ Bind(&lower_case); \
Ben Murdoch61f157c2016-09-16 13:49:30 +010087 if (FLAG_debug_code && expected_arg_count >= 0) { \
Ben Murdochda12d292016-06-02 14:46:10 +010088 AbortIfArgCountMismatch(expected_arg_count, arg_count); \
89 } \
Ben Murdoch61f157c2016-09-16 13:49:30 +010090 result.Bind(name(first_arg_reg, arg_count, context)); \
Ben Murdochda12d292016-06-02 14:46:10 +010091 __ Goto(&end);
92 INTRINSICS_LIST(HANDLE_CASE)
93#undef HANDLE_CASE
94
95 __ Bind(&abort);
Ben Murdoch61f157c2016-09-16 13:49:30 +010096 {
97 __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
98 result.Bind(__ UndefinedConstant());
99 __ Goto(&end);
100 }
Ben Murdochda12d292016-06-02 14:46:10 +0100101
102 __ Bind(&end);
103 return result.value();
104}
105
106Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type,
107 InstanceTypeCompareMode mode) {
108 InterpreterAssembler::Variable return_value(assembler_,
109 MachineRepresentation::kTagged);
110 Node* instance_type = __ LoadInstanceType(map);
111
112 InterpreterAssembler::Label if_true(assembler_), if_false(assembler_),
113 end(assembler_);
Ben Murdochda12d292016-06-02 14:46:10 +0100114 if (mode == kInstanceTypeEqual) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100115 return __ Word32Equal(instance_type, __ Int32Constant(type));
Ben Murdochda12d292016-06-02 14:46:10 +0100116 } else {
117 DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100118 return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
Ben Murdochda12d292016-06-02 14:46:10 +0100119 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100120}
Ben Murdochda12d292016-06-02 14:46:10 +0100121
Ben Murdoch61f157c2016-09-16 13:49:30 +0100122Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) {
123 InterpreterAssembler::Variable return_value(assembler_,
124 MachineRepresentation::kTagged);
125 InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_),
126 return_false(assembler_), end(assembler_);
127 Node* arg = __ LoadRegister(input);
128 __ GotoIf(__ WordIsSmi(arg), &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +0100129
Ben Murdoch61f157c2016-09-16 13:49:30 +0100130 Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual);
131 __ Branch(condition, &return_true, &return_false);
132
133 __ Bind(&return_true);
134 {
135 return_value.Bind(__ BooleanConstant(true));
136 __ Goto(&end);
137 }
138
139 __ Bind(&return_false);
140 {
141 return_value.Bind(__ BooleanConstant(false));
142 __ Goto(&end);
143 }
Ben Murdochda12d292016-06-02 14:46:10 +0100144
145 __ Bind(&end);
146 return return_value.value();
147}
148
Ben Murdoch61f157c2016-09-16 13:49:30 +0100149Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count,
150 Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +0100151 InterpreterAssembler::Variable return_value(assembler_,
152 MachineRepresentation::kTagged);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100153 InterpreterAssembler::Label return_true(assembler_), return_false(assembler_),
Ben Murdochda12d292016-06-02 14:46:10 +0100154 end(assembler_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100155
Ben Murdochda12d292016-06-02 14:46:10 +0100156 Node* arg = __ LoadRegister(input);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157 __ GotoIf(__ WordIsSmi(arg), &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +0100158
Ben Murdochda12d292016-06-02 14:46:10 +0100159 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100160 Node* condition = CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
161 kInstanceTypeGreaterThanOrEqual);
162 __ Branch(condition, &return_true, &return_false);
163
164 __ Bind(&return_true);
165 {
166 return_value.Bind(__ BooleanConstant(true));
167 __ Goto(&end);
168 }
169
170 __ Bind(&return_false);
171 {
172 return_value.Bind(__ BooleanConstant(false));
173 __ Goto(&end);
174 }
Ben Murdochda12d292016-06-02 14:46:10 +0100175
176 __ Bind(&end);
177 return return_value.value();
178}
179
Ben Murdoch61f157c2016-09-16 13:49:30 +0100180Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
181 return IsInstanceType(input, JS_ARRAY_TYPE);
182}
183
184Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) {
185 return IsInstanceType(input, JS_PROXY_TYPE);
186}
187
188Node* IntrinsicsHelper::IsRegExp(Node* input, Node* arg_count, Node* context) {
189 return IsInstanceType(input, JS_REGEXP_TYPE);
190}
191
192Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count,
193 Node* context) {
194 return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
195}
196
197Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +0100198 InterpreterAssembler::Variable return_value(assembler_,
199 MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +0100200 InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
201 end(assembler_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100202
Ben Murdochda12d292016-06-02 14:46:10 +0100203 Node* arg = __ LoadRegister(input);
204
205 __ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi);
206 __ Bind(&if_smi);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100207 {
208 return_value.Bind(__ BooleanConstant(true));
209 __ Goto(&end);
210 }
Ben Murdochda12d292016-06-02 14:46:10 +0100211
212 __ Bind(&if_not_smi);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100213 {
214 return_value.Bind(__ BooleanConstant(false));
215 __ Goto(&end);
216 }
Ben Murdochda12d292016-06-02 14:46:10 +0100217
218 __ Bind(&end);
219 return return_value.value();
220}
221
Ben Murdoch61f157c2016-09-16 13:49:30 +0100222Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context,
223 Callable const& callable) {
224 int param_count = callable.descriptor().GetParameterCount();
225 Node** args = zone()->NewArray<Node*>(param_count + 1); // 1 for context
226 for (int i = 0; i < param_count; i++) {
227 args[i] = __ LoadRegister(args_reg);
228 args_reg = __ NextRegister(args_reg);
229 }
230 args[param_count] = context;
231
232 return __ CallStubN(callable, args);
233}
234
235Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
236 Node* context) {
237 return IntrinsicAsStubCall(input, context,
238 CodeFactory::HasProperty(isolate()));
239}
240
241Node* IntrinsicsHelper::MathPow(Node* input, Node* arg_count, Node* context) {
242 return IntrinsicAsStubCall(input, context, CodeFactory::MathPow(isolate()));
243}
244
245Node* IntrinsicsHelper::NewObject(Node* input, Node* arg_count, Node* context) {
246 return IntrinsicAsStubCall(input, context,
247 CodeFactory::FastNewObject(isolate()));
248}
249
250Node* IntrinsicsHelper::NumberToString(Node* input, Node* arg_count,
251 Node* context) {
252 return IntrinsicAsStubCall(input, context,
253 CodeFactory::NumberToString(isolate()));
254}
255
256Node* IntrinsicsHelper::RegExpConstructResult(Node* input, Node* arg_count,
257 Node* context) {
258 return IntrinsicAsStubCall(input, context,
259 CodeFactory::RegExpConstructResult(isolate()));
260}
261
262Node* IntrinsicsHelper::RegExpExec(Node* input, Node* arg_count,
263 Node* context) {
264 return IntrinsicAsStubCall(input, context,
265 CodeFactory::RegExpExec(isolate()));
266}
267
268Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) {
269 return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
270}
271
272Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) {
273 return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
274}
275
276Node* IntrinsicsHelper::ToName(Node* input, Node* arg_count, Node* context) {
277 return IntrinsicAsStubCall(input, context, CodeFactory::ToName(isolate()));
278}
279
280Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) {
281 return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
282}
283
284Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) {
285 return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
286}
287
288Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) {
289 return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
290}
291
292Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) {
293 return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
294}
295
296Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) {
297 // First argument register contains the function target.
298 Node* function = __ LoadRegister(args_reg);
299
300 // Receiver is the second runtime call argument.
301 Node* receiver_reg = __ NextRegister(args_reg);
302 Node* receiver_arg = __ RegisterLocation(receiver_reg);
303
304 // Subtract function and receiver from arg count.
305 Node* function_and_receiver_count = __ Int32Constant(2);
306 Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);
307
308 if (FLAG_debug_code) {
309 InterpreterAssembler::Label arg_count_positive(assembler_);
310 Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
311 __ GotoUnless(comparison, &arg_count_positive);
312 __ Abort(kWrongArgumentCountForInvokeIntrinsic);
313 __ Goto(&arg_count_positive);
314 __ Bind(&arg_count_positive);
315 }
316
317 Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
318 TailCallMode::kDisallow);
319 return result;
320}
321
322Node* IntrinsicsHelper::ValueOf(Node* args_reg, Node* arg_count,
323 Node* context) {
324 InterpreterAssembler::Variable return_value(assembler_,
325 MachineRepresentation::kTagged);
326 InterpreterAssembler::Label done(assembler_);
327
328 Node* object = __ LoadRegister(args_reg);
329 return_value.Bind(object);
330
331 // If the object is a smi return the object.
332 __ GotoIf(__ WordIsSmi(object), &done);
333
334 // If the object is not a value type, return the object.
335 Node* condition =
336 CompareInstanceType(object, JS_VALUE_TYPE, kInstanceTypeEqual);
337 __ GotoUnless(condition, &done);
338
339 // If the object is a value type, return the value field.
340 return_value.Bind(__ LoadObjectField(object, JSValue::kValueOffset));
341 __ Goto(&done);
342
343 __ Bind(&done);
344 return return_value.value();
345}
346
Ben Murdochda12d292016-06-02 14:46:10 +0100347void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100348 InterpreterAssembler::Label match(assembler_);
Ben Murdochda12d292016-06-02 14:46:10 +0100349 Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100350 __ GotoIf(comparison, &match);
Ben Murdochda12d292016-06-02 14:46:10 +0100351 __ Abort(kWrongArgumentCountForInvokeIntrinsic);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100352 __ Goto(&match);
Ben Murdochda12d292016-06-02 14:46:10 +0100353 __ Bind(&match);
Ben Murdochda12d292016-06-02 14:46:10 +0100354}
355
356} // namespace interpreter
357} // namespace internal
358} // namespace v8