• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "src/interpreter/interpreter-intrinsics.h"
6 
7 #include "src/code-factory.h"
8 #include "src/objects-inl.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace interpreter {
13 
14 using compiler::Node;
15 
16 #define __ assembler_->
17 
IntrinsicsHelper(InterpreterAssembler * assembler)18 IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
19     : isolate_(assembler->isolate()),
20       zone_(assembler->zone()),
21       assembler_(assembler) {}
22 
23 // static
IsSupported(Runtime::FunctionId function_id)24 bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
25   switch (function_id) {
26 #define SUPPORTED(name, lower_case, count) case Runtime::kInline##name:
27     INTRINSICS_LIST(SUPPORTED)
28     return true;
29 #undef SUPPORTED
30     default:
31       return false;
32   }
33 }
34 
35 // static
FromRuntimeId(Runtime::FunctionId function_id)36 IntrinsicsHelper::IntrinsicId IntrinsicsHelper::FromRuntimeId(
37     Runtime::FunctionId function_id) {
38   switch (function_id) {
39 #define TO_RUNTIME_ID(name, lower_case, count) \
40   case Runtime::kInline##name:                 \
41     return IntrinsicId::k##name;
42     INTRINSICS_LIST(TO_RUNTIME_ID)
43 #undef TO_RUNTIME_ID
44     default:
45       UNREACHABLE();
46       return static_cast<IntrinsicsHelper::IntrinsicId>(-1);
47   }
48 }
49 
50 // static
ToRuntimeId(IntrinsicsHelper::IntrinsicId intrinsic_id)51 Runtime::FunctionId IntrinsicsHelper::ToRuntimeId(
52     IntrinsicsHelper::IntrinsicId intrinsic_id) {
53   switch (intrinsic_id) {
54 #define TO_INTRINSIC_ID(name, lower_case, count) \
55   case IntrinsicId::k##name:                     \
56     return Runtime::kInline##name;
57     INTRINSICS_LIST(TO_INTRINSIC_ID)
58 #undef TO_INTRINSIC_ID
59     default:
60       UNREACHABLE();
61       return static_cast<Runtime::FunctionId>(-1);
62   }
63 }
64 
InvokeIntrinsic(Node * function_id,Node * context,Node * first_arg_reg,Node * arg_count)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 
CompareInstanceType(Node * object,int type,InstanceTypeCompareMode mode)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 
IsInstanceType(Node * input,int type)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 
IsJSReceiver(Node * input,Node * arg_count,Node * context)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 
IsArray(Node * input,Node * arg_count,Node * context)180 Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
181   return IsInstanceType(input, JS_ARRAY_TYPE);
182 }
183 
IsJSProxy(Node * input,Node * arg_count,Node * context)184 Node* IntrinsicsHelper::IsJSProxy(Node* input, Node* arg_count, Node* context) {
185   return IsInstanceType(input, JS_PROXY_TYPE);
186 }
187 
IsTypedArray(Node * input,Node * arg_count,Node * context)188 Node* IntrinsicsHelper::IsTypedArray(Node* input, Node* arg_count,
189                                      Node* context) {
190   return IsInstanceType(input, JS_TYPED_ARRAY_TYPE);
191 }
192 
IsSmi(Node * input,Node * arg_count,Node * context)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 
IntrinsicAsStubCall(Node * args_reg,Node * context,Callable const & callable)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 
CreateIterResultObject(Node * input,Node * arg_count,Node * context)234 Node* IntrinsicsHelper::CreateIterResultObject(Node* input, Node* arg_count,
235                                                Node* context) {
236   return IntrinsicAsStubCall(input, context,
237                              CodeFactory::CreateIterResultObject(isolate()));
238 }
239 
HasProperty(Node * input,Node * arg_count,Node * context)240 Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
241                                     Node* context) {
242   return IntrinsicAsStubCall(input, context,
243                              CodeFactory::HasProperty(isolate()));
244 }
245 
SubString(Node * input,Node * arg_count,Node * context)246 Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) {
247   return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
248 }
249 
ToString(Node * input,Node * arg_count,Node * context)250 Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) {
251   return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
252 }
253 
ToLength(Node * input,Node * arg_count,Node * context)254 Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) {
255   return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
256 }
257 
ToInteger(Node * input,Node * arg_count,Node * context)258 Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) {
259   return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
260 }
261 
ToNumber(Node * input,Node * arg_count,Node * context)262 Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) {
263   return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
264 }
265 
ToObject(Node * input,Node * arg_count,Node * context)266 Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) {
267   return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
268 }
269 
Call(Node * args_reg,Node * arg_count,Node * context)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 
ClassOf(Node * args_reg,Node * arg_count,Node * context)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 
CreateAsyncFromSyncIterator(Node * args_reg,Node * arg_count,Node * context)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), &not_receiver);
314   __ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_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(&not_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 
AbortIfArgCountMismatch(int expected,Node * actual)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
350 }  // namespace internal
351 }  // namespace v8
352