OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/interpreter/interpreter-intrinsics.h" | 5 #include "src/interpreter/interpreter-intrinsics.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/base/logging.h" |
8 #include "src/objects-inl.h" | |
9 | 8 |
10 namespace v8 { | 9 namespace v8 { |
11 namespace internal { | 10 namespace internal { |
12 namespace interpreter { | 11 namespace interpreter { |
13 | 12 |
14 using compiler::Node; | |
15 | |
16 #define __ assembler_-> | |
17 | |
18 IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler) | |
19 : isolate_(assembler->isolate()), | |
20 zone_(assembler->zone()), | |
21 assembler_(assembler) {} | |
22 | |
23 // static | 13 // static |
24 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { | 14 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { |
25 switch (function_id) { | 15 switch (function_id) { |
26 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: | 16 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: |
27 INTRINSICS_LIST(SUPPORTED) | 17 INTRINSICS_LIST(SUPPORTED) |
28 return true; | 18 return true; |
29 #undef SUPPORTED | 19 #undef SUPPORTED |
30 default: | 20 default: |
31 return false; | 21 return false; |
32 } | 22 } |
(...skipping 22 matching lines...) Expand all Loading... |
55 case IntrinsicId::k##name: \ | 45 case IntrinsicId::k##name: \ |
56 return Runtime::kInline##name; | 46 return Runtime::kInline##name; |
57 INTRINSICS_LIST(TO_INTRINSIC_ID) | 47 INTRINSICS_LIST(TO_INTRINSIC_ID) |
58 #undef TO_INTRINSIC_ID | 48 #undef TO_INTRINSIC_ID |
59 default: | 49 default: |
60 UNREACHABLE(); | 50 UNREACHABLE(); |
61 return static_cast<Runtime::FunctionId>(-1); | 51 return static_cast<Runtime::FunctionId>(-1); |
62 } | 52 } |
63 } | 53 } |
64 | 54 |
65 Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context, | |
66 Node* first_arg_reg, Node* arg_count) { | |
67 InterpreterAssembler::Label abort(assembler_), end(assembler_); | |
68 InterpreterAssembler::Variable result(assembler_, | |
69 MachineRepresentation::kTagged); | |
70 | |
71 #define MAKE_LABEL(name, lower_case, count) \ | |
72 InterpreterAssembler::Label lower_case(assembler_); | |
73 INTRINSICS_LIST(MAKE_LABEL) | |
74 #undef MAKE_LABEL | |
75 | |
76 #define LABEL_POINTER(name, lower_case, count) &lower_case, | |
77 InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)}; | |
78 #undef LABEL_POINTER | |
79 | |
80 #define CASE(name, lower_case, count) \ | |
81 static_cast<int32_t>(IntrinsicId::k##name), | |
82 int32_t cases[] = {INTRINSICS_LIST(CASE)}; | |
83 #undef CASE | |
84 | |
85 __ Switch(function_id, &abort, cases, labels, arraysize(cases)); | |
86 #define HANDLE_CASE(name, lower_case, expected_arg_count) \ | |
87 __ Bind(&lower_case); \ | |
88 if (FLAG_debug_code && expected_arg_count >= 0) { \ | |
89 AbortIfArgCountMismatch(expected_arg_count, arg_count); \ | |
90 } \ | |
91 result.Bind(name(first_arg_reg, arg_count, context)); \ | |
92 __ Goto(&end); | |
93 INTRINSICS_LIST(HANDLE_CASE) | |
94 #undef HANDLE_CASE | |
95 | |
96 __ Bind(&abort); | |
97 { | |
98 __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic); | |
99 result.Bind(__ UndefinedConstant()); | |
100 __ Goto(&end); | |
101 } | |
102 | |
103 __ Bind(&end); | |
104 return result.value(); | |
105 } | |
106 | |
107 Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type, | |
108 InstanceTypeCompareMode mode) { | |
109 Node* instance_type = __ LoadInstanceType(object); | |
110 | |
111 if (mode == kInstanceTypeEqual) { | |
112 return __ Word32Equal(instance_type, __ Int32Constant(type)); | |
113 } else { | |
114 DCHECK(mode == kInstanceTypeGreaterThanOrEqual); | |
115 return __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type)); | |
116 } | |
117 } | |
118 | |
119 Node* IntrinsicsHelper::IsInstanceType(Node* input, int type) { | |
120 InterpreterAssembler::Variable return_value(assembler_, | |
121 MachineRepresentation::kTagged); | |
122 // TODO(ishell): Use Select here. | |
123 InterpreterAssembler::Label if_not_smi(assembler_), return_true(assembler_), | |
124 return_false(assembler_), end(assembler_); | |
125 Node* arg = __ LoadRegister(input); | |
126 __ GotoIf(__ TaggedIsSmi(arg), &return_false); | |
127 | |
128 Node* condition = CompareInstanceType(arg, type, kInstanceTypeEqual); | |
129 __ Branch(condition, &return_true, &return_false); | |
130 | |
131 __ Bind(&return_true); | |
132 { | |
133 return_value.Bind(__ BooleanConstant(true)); | |
134 __ Goto(&end); | |
135 } | |
136 | |
137 __ Bind(&return_false); | |
138 { | |
139 return_value.Bind(__ BooleanConstant(false)); | |
140 __ Goto(&end); | |
141 } | |
142 | |
143 __ Bind(&end); | |
144 return return_value.value(); | |
145 } | |
146 | |
147 Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count, | |
148 Node* context) { | |
149 // TODO(ishell): Use Select here. | |
150 // TODO(ishell): Use CSA::IsJSReceiverInstanceType here. | |
151 InterpreterAssembler::Variable return_value(assembler_, | |
152 MachineRepresentation::kTagged); | |
153 InterpreterAssembler::Label return_true(assembler_), return_false(assembler_), | |
154 end(assembler_); | |
155 | |
156 Node* arg = __ LoadRegister(input); | |
157 __ GotoIf(__ TaggedIsSmi(arg), &return_false); | |
158 | |
159 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
160 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 } | |
175 | |
176 __ Bind(&end); | |
177 return return_value.value(); | |
178 } | |
179 | |
180 Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) { | |
181 return IsInstanceType(input, JS_ARRAY_TYPE); | |
182 } | |
183 | |
184 Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) { | |
185 return IsInstanceType(input, JS_PROXY_TYPE); | |
186 } | |
187 | |
188 Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count, | |
189 Node* context) { | |
190 return IsInstanceType(input, JS_TYPED_ARRAY_TYPE); | |
191 } | |
192 | |
193 Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) { | |
194 // TODO(ishell): Use SelectBooleanConstant here. | |
195 InterpreterAssembler::Variable return_value(assembler_, | |
196 MachineRepresentation::kTagged); | |
197 InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), | |
198 end(assembler_); | |
199 | |
200 Node* arg = __ LoadRegister(input); | |
201 | |
202 __ Branch(__ TaggedIsSmi(arg), &if_smi, &if_not_smi); | |
203 __ Bind(&if_smi); | |
204 { | |
205 return_value.Bind(__ BooleanConstant(true)); | |
206 __ Goto(&end); | |
207 } | |
208 | |
209 __ Bind(&if_not_smi); | |
210 { | |
211 return_value.Bind(__ BooleanConstant(false)); | |
212 __ Goto(&end); | |
213 } | |
214 | |
215 __ Bind(&end); | |
216 return return_value.value(); | |
217 } | |
218 | |
219 Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context, | |
220 Callable const& callable) { | |
221 int param_count = callable.descriptor().GetParameterCount(); | |
222 int input_count = param_count + 2; // +2 for target and context | |
223 Node** args = zone()->NewArray<Node*>(input_count); | |
224 int index = 0; | |
225 args[index++] = __ HeapConstant(callable.code()); | |
226 for (int i = 0; i < param_count; i++) { | |
227 args[index++] = __ LoadRegister(args_reg); | |
228 args_reg = __ NextRegister(args_reg); | |
229 } | |
230 args[index++] = context; | |
231 return __ CallStubN(callable.descriptor(), 1, input_count, args); | |
232 } | |
233 | |
234 Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count, | |
235 Node* context) { | |
236 return IntrinsicAsStubCall(input, context, | |
237 CodeFactory::CreateIterResultObject(isolate())); | |
238 } | |
239 | |
240 Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count, | |
241 Node* context) { | |
242 return IntrinsicAsStubCall(input, context, | |
243 CodeFactory::HasProperty(isolate())); | |
244 } | |
245 | |
246 Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) { | |
247 return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate())); | |
248 } | |
249 | |
250 Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) { | |
251 return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate())); | |
252 } | |
253 | |
254 Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) { | |
255 return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate())); | |
256 } | |
257 | |
258 Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) { | |
259 return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate())); | |
260 } | |
261 | |
262 Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) { | |
263 return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate())); | |
264 } | |
265 | |
266 Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) { | |
267 return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate())); | |
268 } | |
269 | |
270 Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) { | |
271 // First argument register contains the function target. | |
272 Node* function = __ LoadRegister(args_reg); | |
273 | |
274 // Receiver is the second runtime call argument. | |
275 Node* receiver_reg = __ NextRegister(args_reg); | |
276 Node* receiver_arg = __ RegisterLocation(receiver_reg); | |
277 | |
278 // Subtract function and receiver from arg count. | |
279 Node* function_and_receiver_count = __ Int32Constant(2); | |
280 Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count); | |
281 | |
282 if (FLAG_debug_code) { | |
283 InterpreterAssembler::Label arg_count_positive(assembler_); | |
284 Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0)); | |
285 __ GotoIfNot(comparison, &arg_count_positive); | |
286 __ Abort(kWrongArgumentCountForInvokeIntrinsic); | |
287 __ Goto(&arg_count_positive); | |
288 __ Bind(&arg_count_positive); | |
289 } | |
290 | |
291 Node* result = __ CallJS(function, context, receiver_arg, target_args_count, | |
292 TailCallMode::kDisallow); | |
293 return result; | |
294 } | |
295 | |
296 Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count, | |
297 Node* context) { | |
298 Node* value = __ LoadRegister(args_reg); | |
299 return __ ClassOf(value); | |
300 } | |
301 | |
302 Node* IntrinsicsHelper::CreateAsyncFromSyncIterator(Node* args_reg, | |
303 Node* arg_count, | |
304 Node* context) { | |
305 InterpreterAssembler::Label not_receiver( | |
306 assembler_, InterpreterAssembler::Label::kDeferred); | |
307 InterpreterAssembler::Label done(assembler_); | |
308 InterpreterAssembler::Variable return_value(assembler_, | |
309 MachineRepresentation::kTagged); | |
310 | |
311 Node* sync_iterator = __ LoadRegister(args_reg); | |
312 | |
313 __ GotoIf(__ TaggedIsSmi(sync_iterator), ¬_receiver); | |
314 __ GotoIfNot(__ IsJSReceiver(sync_iterator), ¬_receiver); | |
315 | |
316 Node* const native_context = __ LoadNativeContext(context); | |
317 Node* const map = __ LoadContextElement( | |
318 native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX); | |
319 Node* const iterator = __ AllocateJSObjectFromMap(map); | |
320 | |
321 __ StoreObjectFieldNoWriteBarrier( | |
322 iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator); | |
323 | |
324 return_value.Bind(iterator); | |
325 __ Goto(&done); | |
326 | |
327 __ Bind(¬_receiver); | |
328 { | |
329 return_value.Bind( | |
330 __ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context)); | |
331 | |
332 // Unreachable due to the Throw in runtime call. | |
333 __ Goto(&done); | |
334 } | |
335 | |
336 __ Bind(&done); | |
337 return return_value.value(); | |
338 } | |
339 | |
340 void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) { | |
341 InterpreterAssembler::Label match(assembler_); | |
342 Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected)); | |
343 __ GotoIf(comparison, &match); | |
344 __ Abort(kWrongArgumentCountForInvokeIntrinsic); | |
345 __ Goto(&match); | |
346 __ Bind(&match); | |
347 } | |
348 | |
349 } // namespace interpreter | 55 } // namespace interpreter |
350 } // namespace internal | 56 } // namespace internal |
351 } // namespace v8 | 57 } // namespace v8 |
OLD | NEW |