Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / js-generic-lowering.cc
1 // Copyright 2014 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/code-factory.h"
6 #include "src/code-stubs.h"
7 #include "src/compiler/common-operator.h"
8 #include "src/compiler/graph-inl.h"
9 #include "src/compiler/js-generic-lowering.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-aux-data-inl.h"
12 #include "src/compiler/node-matchers.h"
13 #include "src/compiler/node-properties-inl.h"
14 #include "src/unique.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19
20 JSGenericLowering::JSGenericLowering(CompilationInfo* info, JSGraph* jsgraph)
21     : info_(info),
22       jsgraph_(jsgraph),
23       linkage_(new (jsgraph->zone()) Linkage(jsgraph->zone(), info)) {}
24
25
26 void JSGenericLowering::PatchOperator(Node* node, const Operator* op) {
27   node->set_op(op);
28 }
29
30
31 void JSGenericLowering::PatchInsertInput(Node* node, int index, Node* input) {
32   node->InsertInput(zone(), index, input);
33 }
34
35
36 Node* JSGenericLowering::SmiConstant(int32_t immediate) {
37   return jsgraph()->SmiConstant(immediate);
38 }
39
40
41 Node* JSGenericLowering::Int32Constant(int immediate) {
42   return jsgraph()->Int32Constant(immediate);
43 }
44
45
46 Node* JSGenericLowering::CodeConstant(Handle<Code> code) {
47   return jsgraph()->HeapConstant(code);
48 }
49
50
51 Node* JSGenericLowering::FunctionConstant(Handle<JSFunction> function) {
52   return jsgraph()->HeapConstant(function);
53 }
54
55
56 Node* JSGenericLowering::ExternalConstant(ExternalReference ref) {
57   return jsgraph()->ExternalConstant(ref);
58 }
59
60
61 Reduction JSGenericLowering::Reduce(Node* node) {
62   switch (node->opcode()) {
63 #define DECLARE_CASE(x) \
64   case IrOpcode::k##x:  \
65     Lower##x(node);     \
66     break;
67     DECLARE_CASE(Branch)
68     JS_OP_LIST(DECLARE_CASE)
69 #undef DECLARE_CASE
70     default:
71       // Nothing to see.
72       return NoChange();
73   }
74   return Changed(node);
75 }
76
77
78 #define REPLACE_BINARY_OP_IC_CALL(op, token)                             \
79   void JSGenericLowering::Lower##op(Node* node) {                        \
80     ReplaceWithStubCall(node, CodeFactory::BinaryOpIC(isolate(), token), \
81                         CallDescriptor::kPatchableCallSiteWithNop);      \
82   }
83 REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
84 REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
85 REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
86 REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
87 REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
88 REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
89 REPLACE_BINARY_OP_IC_CALL(JSAdd, Token::ADD)
90 REPLACE_BINARY_OP_IC_CALL(JSSubtract, Token::SUB)
91 REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
92 REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
93 REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
94 #undef REPLACE_BINARY_OP_IC_CALL
95
96
97 #define REPLACE_COMPARE_IC_CALL(op, token, pure)  \
98   void JSGenericLowering::Lower##op(Node* node) { \
99     ReplaceWithCompareIC(node, token, pure);      \
100   }
101 REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ, false)
102 REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE, false)
103 REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT, true)
104 REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT, true)
105 REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT, false)
106 REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT, false)
107 REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE, false)
108 REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE, false)
109 #undef REPLACE_COMPARE_IC_CALL
110
111
112 #define REPLACE_RUNTIME_CALL(op, fun)             \
113   void JSGenericLowering::Lower##op(Node* node) { \
114     ReplaceWithRuntimeCall(node, fun);            \
115   }
116 REPLACE_RUNTIME_CALL(JSTypeOf, Runtime::kTypeof)
117 REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort)
118 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
119 REPLACE_RUNTIME_CALL(JSCreateCatchContext, Runtime::kPushCatchContext)
120 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
121 REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
122 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
123 REPLACE_RUNTIME_CALL(JSCreateGlobalContext, Runtime::kAbort)
124 #undef REPLACE_RUNTIME
125
126
127 #define REPLACE_UNIMPLEMENTED(op) \
128   void JSGenericLowering::Lower##op(Node* node) { UNIMPLEMENTED(); }
129 REPLACE_UNIMPLEMENTED(JSToName)
130 REPLACE_UNIMPLEMENTED(JSYield)
131 REPLACE_UNIMPLEMENTED(JSDebugger)
132 #undef REPLACE_UNIMPLEMENTED
133
134
135 static CallDescriptor::Flags FlagsForNode(Node* node) {
136   CallDescriptor::Flags result = CallDescriptor::kNoFlags;
137   if (OperatorProperties::HasFrameStateInput(node->op())) {
138     result |= CallDescriptor::kNeedsFrameState;
139   }
140   return result;
141 }
142
143
144 void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
145                                              bool pure) {
146   Callable callable = CodeFactory::CompareIC(isolate(), token);
147   bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
148   CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
149       callable.descriptor(), 0,
150       CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
151   NodeVector inputs(zone());
152   inputs.reserve(node->InputCount() + 1);
153   inputs.push_back(CodeConstant(callable.code()));
154   inputs.push_back(NodeProperties::GetValueInput(node, 0));
155   inputs.push_back(NodeProperties::GetValueInput(node, 1));
156   inputs.push_back(NodeProperties::GetContextInput(node));
157   if (pure) {
158     // A pure (strict) comparison doesn't have an effect, control or frame
159     // state.  But for the graph, we need to add control and effect inputs.
160     DCHECK(!has_frame_state);
161     inputs.push_back(graph()->start());
162     inputs.push_back(graph()->start());
163   } else {
164     DCHECK(has_frame_state == FLAG_turbo_deoptimization);
165     if (FLAG_turbo_deoptimization) {
166       inputs.push_back(NodeProperties::GetFrameStateInput(node));
167     }
168     inputs.push_back(NodeProperties::GetEffectInput(node));
169     inputs.push_back(NodeProperties::GetControlInput(node));
170   }
171   Node* compare =
172       graph()->NewNode(common()->Call(desc_compare),
173                        static_cast<int>(inputs.size()), &inputs.front());
174
175   node->ReplaceInput(0, compare);
176   node->ReplaceInput(1, SmiConstant(token));
177
178   if (has_frame_state) {
179     // Remove the frame state from inputs.
180     node->RemoveInput(NodeProperties::FirstFrameStateIndex(node));
181   }
182
183   ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
184 }
185
186
187 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
188                                             CallDescriptor::Flags flags) {
189   CallDescriptor* desc = linkage()->GetStubCallDescriptor(
190       callable.descriptor(), 0, flags | FlagsForNode(node));
191   Node* stub_code = CodeConstant(callable.code());
192   PatchInsertInput(node, 0, stub_code);
193   PatchOperator(node, common()->Call(desc));
194 }
195
196
197 void JSGenericLowering::ReplaceWithBuiltinCall(Node* node,
198                                                Builtins::JavaScript id,
199                                                int nargs) {
200   Callable callable =
201       CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
202   CallDescriptor* desc = linkage()->GetStubCallDescriptor(
203       callable.descriptor(), nargs, FlagsForNode(node));
204   // TODO(mstarzinger): Accessing the builtins object this way prevents sharing
205   // of code across native contexts. Fix this by loading from given context.
206   Handle<JSFunction> function(
207       JSFunction::cast(info()->context()->builtins()->javascript_builtin(id)));
208   Node* stub_code = CodeConstant(callable.code());
209   Node* function_node = FunctionConstant(function);
210   PatchInsertInput(node, 0, stub_code);
211   PatchInsertInput(node, 1, function_node);
212   PatchOperator(node, common()->Call(desc));
213 }
214
215
216 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
217                                                Runtime::FunctionId f,
218                                                int nargs_override) {
219   Operator::Properties properties = node->op()->properties();
220   const Runtime::Function* fun = Runtime::FunctionForId(f);
221   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
222   CallDescriptor* desc =
223       linkage()->GetRuntimeCallDescriptor(f, nargs, properties);
224   Node* ref = ExternalConstant(ExternalReference(f, isolate()));
225   Node* arity = Int32Constant(nargs);
226   PatchInsertInput(node, 0, jsgraph()->CEntryStubConstant());
227   PatchInsertInput(node, nargs + 1, ref);
228   PatchInsertInput(node, nargs + 2, arity);
229   PatchOperator(node, common()->Call(desc));
230 }
231
232
233 void JSGenericLowering::LowerBranch(Node* node) {
234   if (!info()->is_typing_enabled()) {
235     // TODO(mstarzinger): If typing is enabled then simplified lowering will
236     // have inserted the correct ChangeBoolToBit, otherwise we need to perform
237     // poor-man's representation inference here and insert manual change.
238     Node* test = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
239                                   jsgraph()->TrueConstant());
240     node->ReplaceInput(0, test);
241   }
242 }
243
244
245 void JSGenericLowering::LowerJSUnaryNot(Node* node) {
246   Callable callable = CodeFactory::ToBoolean(
247       isolate(), ToBooleanStub::RESULT_AS_INVERSE_ODDBALL);
248   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
249 }
250
251
252 void JSGenericLowering::LowerJSToBoolean(Node* node) {
253   Callable callable =
254       CodeFactory::ToBoolean(isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
255   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
256 }
257
258
259 void JSGenericLowering::LowerJSToNumber(Node* node) {
260   Callable callable = CodeFactory::ToNumber(isolate());
261   ReplaceWithStubCall(node, callable, FlagsForNode(node));
262 }
263
264
265 void JSGenericLowering::LowerJSToString(Node* node) {
266   ReplaceWithBuiltinCall(node, Builtins::TO_STRING, 1);
267 }
268
269
270 void JSGenericLowering::LowerJSToObject(Node* node) {
271   ReplaceWithBuiltinCall(node, Builtins::TO_OBJECT, 1);
272 }
273
274
275 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
276   const LoadPropertyParameters& p = LoadPropertyParametersOf(node->op());
277   Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
278   if (FLAG_vector_ics) {
279     PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
280     PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
281   }
282   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
283 }
284
285
286 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
287   const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
288   Callable callable =
289       CodeFactory::LoadICInOptimizedCode(isolate(), p.contextual_mode());
290   PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
291   if (FLAG_vector_ics) {
292     PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
293     PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
294   }
295   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
296 }
297
298
299 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
300   StrictMode strict_mode = OpParameter<StrictMode>(node);
301   Callable callable = CodeFactory::KeyedStoreIC(isolate(), strict_mode);
302   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
303 }
304
305
306 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
307   const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
308   Callable callable = CodeFactory::StoreIC(isolate(), p.strict_mode());
309   PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
310   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
311 }
312
313
314 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
315   StrictMode strict_mode = OpParameter<StrictMode>(node);
316   PatchInsertInput(node, 2, SmiConstant(strict_mode));
317   ReplaceWithBuiltinCall(node, Builtins::DELETE, 3);
318 }
319
320
321 void JSGenericLowering::LowerJSHasProperty(Node* node) {
322   ReplaceWithBuiltinCall(node, Builtins::IN, 2);
323 }
324
325
326 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
327   InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
328       InstanceofStub::kReturnTrueFalseObject |
329       InstanceofStub::kArgsInRegisters);
330   InstanceofStub stub(isolate(), flags);
331   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
332   CallDescriptor* desc =
333       linkage()->GetStubCallDescriptor(d, 0, FlagsForNode(node));
334   Node* stub_code = CodeConstant(stub.GetCode());
335   PatchInsertInput(node, 0, stub_code);
336   PatchOperator(node, common()->Call(desc));
337 }
338
339
340 void JSGenericLowering::LowerJSLoadContext(Node* node) {
341   const ContextAccess& access = ContextAccessOf(node->op());
342   for (size_t i = 0; i < access.depth(); ++i) {
343     node->ReplaceInput(
344         0, graph()->NewNode(
345                machine()->Load(kMachAnyTagged),
346                NodeProperties::GetValueInput(node, 0),
347                Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)),
348                NodeProperties::GetEffectInput(node), graph()->start()));
349   }
350   node->ReplaceInput(
351       1, Int32Constant(Context::SlotOffset(static_cast<int>(access.index()))));
352   node->AppendInput(zone(), graph()->start());
353   PatchOperator(node, machine()->Load(kMachAnyTagged));
354 }
355
356
357 void JSGenericLowering::LowerJSStoreContext(Node* node) {
358   const ContextAccess& access = ContextAccessOf(node->op());
359   for (size_t i = 0; i < access.depth(); ++i) {
360     node->ReplaceInput(
361         0, graph()->NewNode(
362                machine()->Load(kMachAnyTagged),
363                NodeProperties::GetValueInput(node, 0),
364                Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)),
365                NodeProperties::GetEffectInput(node), graph()->start()));
366   }
367   node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
368   node->ReplaceInput(
369       1, Int32Constant(Context::SlotOffset(static_cast<int>(access.index()))));
370   PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged,
371                                                            kFullWriteBarrier)));
372 }
373
374
375 void JSGenericLowering::LowerJSCallConstruct(Node* node) {
376   int arity = OpParameter<int>(node);
377   CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
378   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
379   CallDescriptor* desc =
380       linkage()->GetStubCallDescriptor(d, arity, FlagsForNode(node));
381   Node* stub_code = CodeConstant(stub.GetCode());
382   Node* construct = NodeProperties::GetValueInput(node, 0);
383   PatchInsertInput(node, 0, stub_code);
384   PatchInsertInput(node, 1, Int32Constant(arity - 1));
385   PatchInsertInput(node, 2, construct);
386   PatchInsertInput(node, 3, jsgraph()->UndefinedConstant());
387   PatchOperator(node, common()->Call(desc));
388 }
389
390
391 bool JSGenericLowering::TryLowerDirectJSCall(Node* node) {
392   // Lower to a direct call to a constant JSFunction if legal.
393   const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
394   int arg_count = static_cast<int>(p.arity() - 2);
395
396   // Check the function is a constant and is really a JSFunction.
397   HeapObjectMatcher<Object> function_const(node->InputAt(0));
398   if (!function_const.HasValue()) return false;  // not a constant.
399   Handle<Object> func = function_const.Value().handle();
400   if (!func->IsJSFunction()) return false;  // not a function.
401   Handle<JSFunction> function = Handle<JSFunction>::cast(func);
402   if (arg_count != function->shared()->formal_parameter_count()) return false;
403
404   // Check the receiver doesn't need to be wrapped.
405   Node* receiver = node->InputAt(1);
406   if (!NodeProperties::IsTyped(receiver)) return false;
407   Type* ok_receiver = Type::Union(Type::Undefined(), Type::Receiver(), zone());
408   if (!NodeProperties::GetBounds(receiver).upper->Is(ok_receiver)) return false;
409
410   int index = NodeProperties::FirstContextIndex(node);
411
412   // TODO(titzer): total hack to share function context constants.
413   // Remove this when the JSGraph canonicalizes heap constants.
414   Node* context = node->InputAt(index);
415   HeapObjectMatcher<Context> context_const(context);
416   if (!context_const.HasValue() ||
417       *(context_const.Value().handle()) != function->context()) {
418     context = jsgraph()->HeapConstant(Handle<Context>(function->context()));
419   }
420   node->ReplaceInput(index, context);
421   CallDescriptor* desc = linkage()->GetJSCallDescriptor(
422       1 + arg_count, jsgraph()->zone(), FlagsForNode(node));
423   PatchOperator(node, common()->Call(desc));
424   return true;
425 }
426
427
428 void JSGenericLowering::LowerJSCallFunction(Node* node) {
429   // Fast case: call function directly.
430   if (TryLowerDirectJSCall(node)) return;
431
432   // General case: CallFunctionStub.
433   const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
434   int arg_count = static_cast<int>(p.arity() - 2);
435   CallFunctionStub stub(isolate(), arg_count, p.flags());
436   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
437   CallDescriptor* desc = linkage()->GetStubCallDescriptor(
438       d, static_cast<int>(p.arity() - 1), FlagsForNode(node));
439   Node* stub_code = CodeConstant(stub.GetCode());
440   PatchInsertInput(node, 0, stub_code);
441   PatchOperator(node, common()->Call(desc));
442 }
443
444
445 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
446   const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
447   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
448 }
449
450 }  // namespace compiler
451 }  // namespace internal
452 }  // namespace v8