blob: 48864423146007ec632915d4ac1ad0658ca80c93 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/compiler/node-matchers.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/compiler/node-properties-inl.h"
14#include "src/unique.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20JSGenericLowering::JSGenericLowering(CompilationInfo* info, JSGraph* jsgraph)
21 : info_(info),
22 jsgraph_(jsgraph),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 linkage_(new (jsgraph->zone()) Linkage(jsgraph->zone(), info)) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024
25
26void JSGenericLowering::PatchOperator(Node* node, const Operator* op) {
27 node->set_op(op);
28}
29
30
31void JSGenericLowering::PatchInsertInput(Node* node, int index, Node* input) {
32 node->InsertInput(zone(), index, input);
33}
34
35
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036Reduction JSGenericLowering::Reduce(Node* node) {
37 switch (node->opcode()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038#define DECLARE_CASE(x) \
39 case IrOpcode::k##x: \
40 Lower##x(node); \
41 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 JS_OP_LIST(DECLARE_CASE)
43#undef DECLARE_CASE
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 case IrOpcode::kBranch:
45 // TODO(mstarzinger): If typing is enabled then simplified lowering will
46 // have inserted the correct ChangeBoolToBit, otherwise we need to perform
47 // poor-man's representation inference here and insert manual change.
48 if (!info()->is_typing_enabled()) {
49 Node* test = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
50 jsgraph()->TrueConstant());
51 node->ReplaceInput(0, test);
52 break;
53 }
54 // Fall-through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 default:
56 // Nothing to see.
57 return NoChange();
58 }
59 return Changed(node);
60}
61
62
63#define REPLACE_BINARY_OP_IC_CALL(op, token) \
64 void JSGenericLowering::Lower##op(Node* node) { \
65 ReplaceWithStubCall(node, CodeFactory::BinaryOpIC(isolate(), token), \
66 CallDescriptor::kPatchableCallSiteWithNop); \
67 }
68REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
69REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
70REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
71REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
72REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
73REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
74REPLACE_BINARY_OP_IC_CALL(JSAdd, Token::ADD)
75REPLACE_BINARY_OP_IC_CALL(JSSubtract, Token::SUB)
76REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
77REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
78REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
79#undef REPLACE_BINARY_OP_IC_CALL
80
81
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082#define REPLACE_COMPARE_IC_CALL(op, token) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 void JSGenericLowering::Lower##op(Node* node) { \
Emily Bernierd0a1eb72015-03-24 16:35:39 -040084 ReplaceWithCompareIC(node, token); \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000085 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ)
87REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE)
88REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT)
89REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT)
90REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT)
91REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT)
92REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE)
93REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094#undef REPLACE_COMPARE_IC_CALL
95
96
97#define REPLACE_RUNTIME_CALL(op, fun) \
98 void JSGenericLowering::Lower##op(Node* node) { \
99 ReplaceWithRuntimeCall(node, fun); \
100 }
101REPLACE_RUNTIME_CALL(JSTypeOf, Runtime::kTypeof)
102REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort)
103REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
104REPLACE_RUNTIME_CALL(JSCreateCatchContext, Runtime::kPushCatchContext)
105REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
106REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
107REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400108REPLACE_RUNTIME_CALL(JSCreateScriptContext, Runtime::kAbort)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109#undef REPLACE_RUNTIME
110
111
112#define REPLACE_UNIMPLEMENTED(op) \
113 void JSGenericLowering::Lower##op(Node* node) { UNIMPLEMENTED(); }
114REPLACE_UNIMPLEMENTED(JSToName)
115REPLACE_UNIMPLEMENTED(JSYield)
116REPLACE_UNIMPLEMENTED(JSDebugger)
117#undef REPLACE_UNIMPLEMENTED
118
119
120static CallDescriptor::Flags FlagsForNode(Node* node) {
121 CallDescriptor::Flags result = CallDescriptor::kNoFlags;
122 if (OperatorProperties::HasFrameStateInput(node->op())) {
123 result |= CallDescriptor::kNeedsFrameState;
124 }
125 return result;
126}
127
128
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 Callable callable = CodeFactory::CompareIC(isolate(), token);
131 bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
132 CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
133 callable.descriptor(), 0,
134 CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
135 NodeVector inputs(zone());
136 inputs.reserve(node->InputCount() + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137 inputs.push_back(jsgraph()->HeapConstant(callable.code()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 inputs.push_back(NodeProperties::GetValueInput(node, 0));
139 inputs.push_back(NodeProperties::GetValueInput(node, 1));
140 inputs.push_back(NodeProperties::GetContextInput(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400141 if (node->op()->HasProperty(Operator::kPure)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 // A pure (strict) comparison doesn't have an effect, control or frame
143 // state. But for the graph, we need to add control and effect inputs.
144 DCHECK(!has_frame_state);
145 inputs.push_back(graph()->start());
146 inputs.push_back(graph()->start());
147 } else {
148 DCHECK(has_frame_state == FLAG_turbo_deoptimization);
149 if (FLAG_turbo_deoptimization) {
150 inputs.push_back(NodeProperties::GetFrameStateInput(node));
151 }
152 inputs.push_back(NodeProperties::GetEffectInput(node));
153 inputs.push_back(NodeProperties::GetControlInput(node));
154 }
155 Node* compare =
156 graph()->NewNode(common()->Call(desc_compare),
157 static_cast<int>(inputs.size()), &inputs.front());
158
159 node->ReplaceInput(0, compare);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400160 node->ReplaceInput(1, jsgraph()->SmiConstant(token));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161
162 if (has_frame_state) {
163 // Remove the frame state from inputs.
164 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node));
165 }
166
167 ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
168}
169
170
171void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
172 CallDescriptor::Flags flags) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400173 Operator::Properties properties = node->op()->properties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 CallDescriptor* desc = linkage()->GetStubCallDescriptor(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 callable.descriptor(), 0, flags | FlagsForNode(node), properties);
176 Node* stub_code = jsgraph()->HeapConstant(callable.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 PatchInsertInput(node, 0, stub_code);
178 PatchOperator(node, common()->Call(desc));
179}
180
181
182void JSGenericLowering::ReplaceWithBuiltinCall(Node* node,
183 Builtins::JavaScript id,
184 int nargs) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 Operator::Properties properties = node->op()->properties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 Callable callable =
187 CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400188 CallDescriptor* desc = linkage()->GetStubCallDescriptor(
189 callable.descriptor(), nargs, FlagsForNode(node), properties);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 // TODO(mstarzinger): Accessing the builtins object this way prevents sharing
191 // of code across native contexts. Fix this by loading from given context.
192 Handle<JSFunction> function(
193 JSFunction::cast(info()->context()->builtins()->javascript_builtin(id)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194 Node* stub_code = jsgraph()->HeapConstant(callable.code());
195 Node* function_node = jsgraph()->HeapConstant(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 PatchInsertInput(node, 0, stub_code);
197 PatchInsertInput(node, 1, function_node);
198 PatchOperator(node, common()->Call(desc));
199}
200
201
202void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
203 Runtime::FunctionId f,
204 int nargs_override) {
205 Operator::Properties properties = node->op()->properties();
206 const Runtime::Function* fun = Runtime::FunctionForId(f);
207 int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
208 CallDescriptor* desc =
209 linkage()->GetRuntimeCallDescriptor(f, nargs, properties);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
211 Node* arity = jsgraph()->Int32Constant(nargs);
212 PatchInsertInput(node, 0, jsgraph()->CEntryStubConstant(fun->result_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 PatchInsertInput(node, nargs + 1, ref);
214 PatchInsertInput(node, nargs + 2, arity);
215 PatchOperator(node, common()->Call(desc));
216}
217
218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219void JSGenericLowering::LowerJSUnaryNot(Node* node) {
220 Callable callable = CodeFactory::ToBoolean(
221 isolate(), ToBooleanStub::RESULT_AS_INVERSE_ODDBALL);
222 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
223}
224
225
226void JSGenericLowering::LowerJSToBoolean(Node* node) {
227 Callable callable =
228 CodeFactory::ToBoolean(isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
229 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
230}
231
232
233void JSGenericLowering::LowerJSToNumber(Node* node) {
234 Callable callable = CodeFactory::ToNumber(isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235 ReplaceWithStubCall(node, callable, FlagsForNode(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236}
237
238
239void JSGenericLowering::LowerJSToString(Node* node) {
240 ReplaceWithBuiltinCall(node, Builtins::TO_STRING, 1);
241}
242
243
244void JSGenericLowering::LowerJSToObject(Node* node) {
245 ReplaceWithBuiltinCall(node, Builtins::TO_OBJECT, 1);
246}
247
248
249void JSGenericLowering::LowerJSLoadProperty(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400250 const LoadPropertyParameters& p = LoadPropertyParametersOf(node->op());
251 Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
252 if (FLAG_vector_ics) {
253 PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
254 PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
255 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
257}
258
259
260void JSGenericLowering::LowerJSLoadNamed(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261 const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
262 Callable callable =
263 CodeFactory::LoadICInOptimizedCode(isolate(), p.contextual_mode());
264 PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
265 if (FLAG_vector_ics) {
266 PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
267 PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
268 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
270}
271
272
273void JSGenericLowering::LowerJSStoreProperty(Node* node) {
274 StrictMode strict_mode = OpParameter<StrictMode>(node);
275 Callable callable = CodeFactory::KeyedStoreIC(isolate(), strict_mode);
276 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
277}
278
279
280void JSGenericLowering::LowerJSStoreNamed(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
282 Callable callable = CodeFactory::StoreIC(isolate(), p.strict_mode());
283 PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
285}
286
287
288void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
289 StrictMode strict_mode = OpParameter<StrictMode>(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290 PatchInsertInput(node, 2, jsgraph()->SmiConstant(strict_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 ReplaceWithBuiltinCall(node, Builtins::DELETE, 3);
292}
293
294
295void JSGenericLowering::LowerJSHasProperty(Node* node) {
296 ReplaceWithBuiltinCall(node, Builtins::IN, 2);
297}
298
299
300void JSGenericLowering::LowerJSInstanceOf(Node* node) {
301 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
302 InstanceofStub::kReturnTrueFalseObject |
303 InstanceofStub::kArgsInRegisters);
304 InstanceofStub stub(isolate(), flags);
305 CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400306 CallDescriptor* desc =
307 linkage()->GetStubCallDescriptor(d, 0, FlagsForNode(node));
308 Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000309 PatchInsertInput(node, 0, stub_code);
310 PatchOperator(node, common()->Call(desc));
311}
312
313
314void JSGenericLowering::LowerJSLoadContext(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400315 const ContextAccess& access = ContextAccessOf(node->op());
316 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 node->ReplaceInput(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400318 0, graph()->NewNode(machine()->Load(kMachAnyTagged),
319 NodeProperties::GetValueInput(node, 0),
320 jsgraph()->Int32Constant(
321 Context::SlotOffset(Context::PREVIOUS_INDEX)),
322 NodeProperties::GetEffectInput(node),
323 graph()->start()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400325 node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
326 static_cast<int>(access.index()))));
327 node->AppendInput(zone(), graph()->start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 PatchOperator(node, machine()->Load(kMachAnyTagged));
329}
330
331
332void JSGenericLowering::LowerJSStoreContext(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400333 const ContextAccess& access = ContextAccessOf(node->op());
334 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 node->ReplaceInput(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400336 0, graph()->NewNode(machine()->Load(kMachAnyTagged),
337 NodeProperties::GetValueInput(node, 0),
338 jsgraph()->Int32Constant(
339 Context::SlotOffset(Context::PREVIOUS_INDEX)),
340 NodeProperties::GetEffectInput(node),
341 graph()->start()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 }
343 node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
345 static_cast<int>(access.index()))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged,
347 kFullWriteBarrier)));
348}
349
350
351void JSGenericLowering::LowerJSCallConstruct(Node* node) {
352 int arity = OpParameter<int>(node);
353 CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
354 CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
355 CallDescriptor* desc =
356 linkage()->GetStubCallDescriptor(d, arity, FlagsForNode(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400357 Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358 Node* construct = NodeProperties::GetValueInput(node, 0);
359 PatchInsertInput(node, 0, stub_code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360 PatchInsertInput(node, 1, jsgraph()->Int32Constant(arity - 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 PatchInsertInput(node, 2, construct);
362 PatchInsertInput(node, 3, jsgraph()->UndefinedConstant());
363 PatchOperator(node, common()->Call(desc));
364}
365
366
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400367bool JSGenericLowering::TryLowerDirectJSCall(Node* node) {
368 // Lower to a direct call to a constant JSFunction if legal.
369 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
370 int arg_count = static_cast<int>(p.arity() - 2);
371
372 // Check the function is a constant and is really a JSFunction.
373 HeapObjectMatcher<Object> function_const(node->InputAt(0));
374 if (!function_const.HasValue()) return false; // not a constant.
375 Handle<Object> func = function_const.Value().handle();
376 if (!func->IsJSFunction()) return false; // not a function.
377 Handle<JSFunction> function = Handle<JSFunction>::cast(func);
378 if (arg_count != function->shared()->formal_parameter_count()) return false;
379
380 // Check the receiver doesn't need to be wrapped.
381 Node* receiver = node->InputAt(1);
382 if (!NodeProperties::IsTyped(receiver)) return false;
383 Type* ok_receiver = Type::Union(Type::Undefined(), Type::Receiver(), zone());
384 if (!NodeProperties::GetBounds(receiver).upper->Is(ok_receiver)) return false;
385
386 int index = NodeProperties::FirstContextIndex(node);
387
388 // TODO(titzer): total hack to share function context constants.
389 // Remove this when the JSGraph canonicalizes heap constants.
390 Node* context = node->InputAt(index);
391 HeapObjectMatcher<Context> context_const(context);
392 if (!context_const.HasValue() ||
393 *(context_const.Value().handle()) != function->context()) {
394 context = jsgraph()->HeapConstant(Handle<Context>(function->context()));
395 }
396 node->ReplaceInput(index, context);
397 CallDescriptor* desc = linkage()->GetJSCallDescriptor(
398 1 + arg_count, jsgraph()->zone(), FlagsForNode(node));
399 PatchOperator(node, common()->Call(desc));
400 return true;
401}
402
403
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404void JSGenericLowering::LowerJSCallFunction(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400405 // Fast case: call function directly.
406 if (TryLowerDirectJSCall(node)) return;
407
408 // General case: CallFunctionStub.
409 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
410 int arg_count = static_cast<int>(p.arity() - 2);
411 CallFunctionStub stub(isolate(), arg_count, p.flags());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000412 CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400413 CallDescriptor* desc = linkage()->GetStubCallDescriptor(
414 d, static_cast<int>(p.arity() - 1), FlagsForNode(node));
415 Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 PatchInsertInput(node, 0, stub_code);
417 PatchOperator(node, common()->Call(desc));
418}
419
420
421void JSGenericLowering::LowerJSCallRuntime(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
423 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424}
425
426} // namespace compiler
427} // namespace internal
428} // namespace v8