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/compiler/js-generic-lowering.h"
6
7 #include "src/ast/ast.h"
8 #include "src/code-factory.h"
9 #include "src/code-stubs.h"
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/js-graph.h"
12 #include "src/compiler/machine-operator.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/node-properties.h"
15 #include "src/compiler/operator-properties.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20
21 namespace {
22
FrameStateFlagForCall(Node * node)23 CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
24 return OperatorProperties::HasFrameStateInput(node->op())
25 ? CallDescriptor::kNeedsFrameState
26 : CallDescriptor::kNoFlags;
27 }
28
29 } // namespace
30
JSGenericLowering(JSGraph * jsgraph)31 JSGenericLowering::JSGenericLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
32
~JSGenericLowering()33 JSGenericLowering::~JSGenericLowering() {}
34
35
Reduce(Node * node)36 Reduction JSGenericLowering::Reduce(Node* node) {
37 switch (node->opcode()) {
38 #define DECLARE_CASE(x) \
39 case IrOpcode::k##x: \
40 Lower##x(node); \
41 break;
42 JS_OP_LIST(DECLARE_CASE)
43 #undef DECLARE_CASE
44 default:
45 // Nothing to see.
46 return NoChange();
47 }
48 return Changed(node);
49 }
50
51 #define REPLACE_STUB_CALL(Name) \
52 void JSGenericLowering::LowerJS##Name(Node* node) { \
53 CallDescriptor::Flags flags = FrameStateFlagForCall(node); \
54 Callable callable = CodeFactory::Name(isolate()); \
55 ReplaceWithStubCall(node, callable, flags); \
56 }
57 REPLACE_STUB_CALL(Add)
REPLACE_STUB_CALL(Subtract)58 REPLACE_STUB_CALL(Subtract)
59 REPLACE_STUB_CALL(Multiply)
60 REPLACE_STUB_CALL(Divide)
61 REPLACE_STUB_CALL(Modulus)
62 REPLACE_STUB_CALL(BitwiseAnd)
63 REPLACE_STUB_CALL(BitwiseOr)
64 REPLACE_STUB_CALL(BitwiseXor)
65 REPLACE_STUB_CALL(ShiftLeft)
66 REPLACE_STUB_CALL(ShiftRight)
67 REPLACE_STUB_CALL(ShiftRightLogical)
68 REPLACE_STUB_CALL(LessThan)
69 REPLACE_STUB_CALL(LessThanOrEqual)
70 REPLACE_STUB_CALL(GreaterThan)
71 REPLACE_STUB_CALL(GreaterThanOrEqual)
72 REPLACE_STUB_CALL(HasProperty)
73 REPLACE_STUB_CALL(Equal)
74 REPLACE_STUB_CALL(NotEqual)
75 REPLACE_STUB_CALL(ToInteger)
76 REPLACE_STUB_CALL(ToLength)
77 REPLACE_STUB_CALL(ToNumber)
78 REPLACE_STUB_CALL(ToName)
79 REPLACE_STUB_CALL(ToObject)
80 REPLACE_STUB_CALL(ToString)
81 #undef REPLACE_STUB_CALL
82
83 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
84 CallDescriptor::Flags flags) {
85 ReplaceWithStubCall(node, callable, flags, node->op()->properties());
86 }
87
ReplaceWithStubCall(Node * node,Callable callable,CallDescriptor::Flags flags,Operator::Properties properties)88 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
89 CallDescriptor::Flags flags,
90 Operator::Properties properties) {
91 const CallInterfaceDescriptor& descriptor = callable.descriptor();
92 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
93 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(), flags,
94 properties);
95 Node* stub_code = jsgraph()->HeapConstant(callable.code());
96 node->InsertInput(zone(), 0, stub_code);
97 NodeProperties::ChangeOp(node, common()->Call(desc));
98 }
99
100
ReplaceWithRuntimeCall(Node * node,Runtime::FunctionId f,int nargs_override)101 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
102 Runtime::FunctionId f,
103 int nargs_override) {
104 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
105 Operator::Properties properties = node->op()->properties();
106 const Runtime::Function* fun = Runtime::FunctionForId(f);
107 int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
108 CallDescriptor* desc =
109 Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
110 Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
111 Node* arity = jsgraph()->Int32Constant(nargs);
112 node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
113 node->InsertInput(zone(), nargs + 1, ref);
114 node->InsertInput(zone(), nargs + 2, arity);
115 NodeProperties::ChangeOp(node, common()->Call(desc));
116 }
117
LowerJSStrictEqual(Node * node)118 void JSGenericLowering::LowerJSStrictEqual(Node* node) {
119 // The === operator doesn't need the current context.
120 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
121 Callable callable = CodeFactory::StrictEqual(isolate());
122 node->RemoveInput(4); // control
123 ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
124 Operator::kEliminatable);
125 }
126
LowerJSStrictNotEqual(Node * node)127 void JSGenericLowering::LowerJSStrictNotEqual(Node* node) {
128 // The !== operator doesn't need the current context.
129 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
130 Callable callable = CodeFactory::StrictNotEqual(isolate());
131 node->RemoveInput(4); // control
132 ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
133 Operator::kEliminatable);
134 }
135
LowerJSToBoolean(Node * node)136 void JSGenericLowering::LowerJSToBoolean(Node* node) {
137 // The ToBoolean conversion doesn't need the current context.
138 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
139 Callable callable = CodeFactory::ToBoolean(isolate());
140 node->AppendInput(zone(), graph()->start());
141 ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate,
142 Operator::kEliminatable);
143 }
144
LowerJSTypeOf(Node * node)145 void JSGenericLowering::LowerJSTypeOf(Node* node) {
146 // The typeof operator doesn't need the current context.
147 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
148 Callable callable = CodeFactory::Typeof(isolate());
149 node->AppendInput(zone(), graph()->start());
150 ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate,
151 Operator::kEliminatable);
152 }
153
154
LowerJSLoadProperty(Node * node)155 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
156 Node* closure = NodeProperties::GetValueInput(node, 2);
157 Node* effect = NodeProperties::GetEffectInput(node);
158 Node* control = NodeProperties::GetControlInput(node);
159 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
160 const PropertyAccess& p = PropertyAccessOf(node->op());
161 Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
162 // Load the type feedback vector from the closure.
163 Node* literals = effect = graph()->NewNode(
164 machine()->Load(MachineType::AnyTagged()), closure,
165 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
166 effect, control);
167 Node* vector = effect = graph()->NewNode(
168 machine()->Load(MachineType::AnyTagged()), literals,
169 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
170 kHeapObjectTag),
171 effect, control);
172 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
173 node->ReplaceInput(3, vector);
174 node->ReplaceInput(6, effect);
175 ReplaceWithStubCall(node, callable, flags);
176 }
177
178
LowerJSLoadNamed(Node * node)179 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
180 Node* closure = NodeProperties::GetValueInput(node, 1);
181 Node* effect = NodeProperties::GetEffectInput(node);
182 Node* control = NodeProperties::GetControlInput(node);
183 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
184 NamedAccess const& p = NamedAccessOf(node->op());
185 Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
186 // Load the type feedback vector from the closure.
187 Node* literals = effect = graph()->NewNode(
188 machine()->Load(MachineType::AnyTagged()), closure,
189 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
190 effect, control);
191 Node* vector = effect = graph()->NewNode(
192 machine()->Load(MachineType::AnyTagged()), literals,
193 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
194 kHeapObjectTag),
195 effect, control);
196 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
197 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
198 node->ReplaceInput(3, vector);
199 node->ReplaceInput(6, effect);
200 ReplaceWithStubCall(node, callable, flags);
201 }
202
203
LowerJSLoadGlobal(Node * node)204 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
205 Node* closure = NodeProperties::GetValueInput(node, 0);
206 Node* effect = NodeProperties::GetEffectInput(node);
207 Node* control = NodeProperties::GetControlInput(node);
208 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
209 const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
210 Callable callable =
211 CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
212 // Load the type feedback vector from the closure.
213 Node* literals = effect = graph()->NewNode(
214 machine()->Load(MachineType::AnyTagged()), closure,
215 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
216 effect, control);
217 Node* vector = effect = graph()->NewNode(
218 machine()->Load(MachineType::AnyTagged()), literals,
219 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
220 kHeapObjectTag),
221 effect, control);
222 node->InsertInput(zone(), 0, jsgraph()->SmiConstant(p.feedback().index()));
223 node->ReplaceInput(1, vector);
224 node->ReplaceInput(4, effect);
225 ReplaceWithStubCall(node, callable, flags);
226 }
227
228
LowerJSStoreProperty(Node * node)229 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
230 Node* receiver = NodeProperties::GetValueInput(node, 0);
231 Node* key = NodeProperties::GetValueInput(node, 1);
232 Node* value = NodeProperties::GetValueInput(node, 2);
233 Node* closure = NodeProperties::GetValueInput(node, 3);
234 Node* effect = NodeProperties::GetEffectInput(node);
235 Node* control = NodeProperties::GetControlInput(node);
236 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
237 PropertyAccess const& p = PropertyAccessOf(node->op());
238 LanguageMode language_mode = p.language_mode();
239 Callable callable =
240 CodeFactory::KeyedStoreICInOptimizedCode(isolate(), language_mode);
241 // Load the type feedback vector from the closure.
242 Node* literals = effect = graph()->NewNode(
243 machine()->Load(MachineType::AnyTagged()), closure,
244 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
245 effect, control);
246 Node* vector = effect = graph()->NewNode(
247 machine()->Load(MachineType::AnyTagged()), literals,
248 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
249 kHeapObjectTag),
250 effect, control);
251 typedef StoreWithVectorDescriptor Descriptor;
252 node->InsertInputs(zone(), 0, 1);
253 node->ReplaceInput(Descriptor::kReceiver, receiver);
254 node->ReplaceInput(Descriptor::kName, key);
255 node->ReplaceInput(Descriptor::kValue, value);
256 node->ReplaceInput(Descriptor::kSlot,
257 jsgraph()->SmiConstant(p.feedback().index()));
258 node->ReplaceInput(Descriptor::kVector, vector);
259 node->ReplaceInput(7, effect);
260 ReplaceWithStubCall(node, callable, flags);
261 }
262
263
LowerJSStoreNamed(Node * node)264 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
265 Node* receiver = NodeProperties::GetValueInput(node, 0);
266 Node* value = NodeProperties::GetValueInput(node, 1);
267 Node* closure = NodeProperties::GetValueInput(node, 2);
268 Node* effect = NodeProperties::GetEffectInput(node);
269 Node* control = NodeProperties::GetControlInput(node);
270 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
271 NamedAccess const& p = NamedAccessOf(node->op());
272 Callable callable =
273 CodeFactory::StoreICInOptimizedCode(isolate(), p.language_mode());
274 // Load the type feedback vector from the closure.
275 Node* literals = effect = graph()->NewNode(
276 machine()->Load(MachineType::AnyTagged()), closure,
277 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
278 effect, control);
279 Node* vector = effect = graph()->NewNode(
280 machine()->Load(MachineType::AnyTagged()), literals,
281 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
282 kHeapObjectTag),
283 effect, control);
284 typedef StoreWithVectorDescriptor Descriptor;
285 node->InsertInputs(zone(), 0, 2);
286 node->ReplaceInput(Descriptor::kReceiver, receiver);
287 node->ReplaceInput(Descriptor::kName, jsgraph()->HeapConstant(p.name()));
288 node->ReplaceInput(Descriptor::kValue, value);
289 node->ReplaceInput(Descriptor::kSlot,
290 jsgraph()->SmiConstant(p.feedback().index()));
291 node->ReplaceInput(Descriptor::kVector, vector);
292 node->ReplaceInput(7, effect);
293 ReplaceWithStubCall(node, callable, flags);
294 }
295
296
LowerJSStoreGlobal(Node * node)297 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
298 Node* value = NodeProperties::GetValueInput(node, 0);
299 Node* closure = NodeProperties::GetValueInput(node, 1);
300 Node* context = NodeProperties::GetContextInput(node);
301 Node* effect = NodeProperties::GetEffectInput(node);
302 Node* control = NodeProperties::GetControlInput(node);
303 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
304 const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
305 Callable callable =
306 CodeFactory::StoreICInOptimizedCode(isolate(), p.language_mode());
307 // Load the type feedback vector from the closure.
308 Node* literals = effect = graph()->NewNode(
309 machine()->Load(MachineType::AnyTagged()), closure,
310 jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
311 effect, control);
312 Node* vector = effect = graph()->NewNode(
313 machine()->Load(MachineType::AnyTagged()), literals,
314 jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
315 kHeapObjectTag),
316 effect, control);
317 // Load global object from the context.
318 Node* native_context = effect =
319 graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
320 jsgraph()->IntPtrConstant(
321 Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
322 effect, control);
323 Node* global = effect = graph()->NewNode(
324 machine()->Load(MachineType::AnyTagged()), native_context,
325 jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
326 effect, control);
327 typedef StoreWithVectorDescriptor Descriptor;
328 node->InsertInputs(zone(), 0, 3);
329 node->ReplaceInput(Descriptor::kReceiver, global);
330 node->ReplaceInput(Descriptor::kName, jsgraph()->HeapConstant(p.name()));
331 node->ReplaceInput(Descriptor::kValue, value);
332 node->ReplaceInput(Descriptor::kSlot,
333 jsgraph()->SmiConstant(p.feedback().index()));
334 node->ReplaceInput(Descriptor::kVector, vector);
335 node->ReplaceInput(7, effect);
336 ReplaceWithStubCall(node, callable, flags);
337 }
338
339
LowerJSDeleteProperty(Node * node)340 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
341 LanguageMode language_mode = OpParameter<LanguageMode>(node);
342 ReplaceWithRuntimeCall(node, is_strict(language_mode)
343 ? Runtime::kDeleteProperty_Strict
344 : Runtime::kDeleteProperty_Sloppy);
345 }
346
347
LowerJSInstanceOf(Node * node)348 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
349 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
350 Callable callable = CodeFactory::InstanceOf(isolate());
351 ReplaceWithStubCall(node, callable, flags);
352 }
353
LowerJSOrdinaryHasInstance(Node * node)354 void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
355 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
356 Callable callable = CodeFactory::OrdinaryHasInstance(isolate());
357 ReplaceWithStubCall(node, callable, flags);
358 }
359
LowerJSLoadContext(Node * node)360 void JSGenericLowering::LowerJSLoadContext(Node* node) {
361 const ContextAccess& access = ContextAccessOf(node->op());
362 for (size_t i = 0; i < access.depth(); ++i) {
363 node->ReplaceInput(
364 0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
365 NodeProperties::GetValueInput(node, 0),
366 jsgraph()->Int32Constant(
367 Context::SlotOffset(Context::PREVIOUS_INDEX)),
368 NodeProperties::GetEffectInput(node),
369 graph()->start()));
370 }
371 node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
372 static_cast<int>(access.index()))));
373 node->AppendInput(zone(), graph()->start());
374 NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
375 }
376
377
LowerJSStoreContext(Node * node)378 void JSGenericLowering::LowerJSStoreContext(Node* node) {
379 const ContextAccess& access = ContextAccessOf(node->op());
380 for (size_t i = 0; i < access.depth(); ++i) {
381 node->ReplaceInput(
382 0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
383 NodeProperties::GetValueInput(node, 0),
384 jsgraph()->Int32Constant(
385 Context::SlotOffset(Context::PREVIOUS_INDEX)),
386 NodeProperties::GetEffectInput(node),
387 graph()->start()));
388 }
389 node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
390 node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
391 static_cast<int>(access.index()))));
392 NodeProperties::ChangeOp(
393 node, machine()->Store(StoreRepresentation(MachineRepresentation::kTagged,
394 kFullWriteBarrier)));
395 }
396
397
LowerJSCreate(Node * node)398 void JSGenericLowering::LowerJSCreate(Node* node) {
399 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
400 Callable callable = CodeFactory::FastNewObject(isolate());
401 ReplaceWithStubCall(node, callable, flags);
402 }
403
404
LowerJSCreateArguments(Node * node)405 void JSGenericLowering::LowerJSCreateArguments(Node* node) {
406 CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
407 switch (type) {
408 case CreateArgumentsType::kMappedArguments:
409 ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
410 break;
411 case CreateArgumentsType::kUnmappedArguments:
412 ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
413 break;
414 case CreateArgumentsType::kRestParameter:
415 ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
416 break;
417 }
418 }
419
420
LowerJSCreateArray(Node * node)421 void JSGenericLowering::LowerJSCreateArray(Node* node) {
422 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
423 int const arity = static_cast<int>(p.arity());
424 Handle<AllocationSite> const site = p.site();
425 Node* new_target = node->InputAt(1);
426 Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
427 : jsgraph()->HeapConstant(site);
428 node->RemoveInput(1);
429 node->InsertInput(zone(), 1 + arity, new_target);
430 node->InsertInput(zone(), 2 + arity, type_info);
431 ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3);
432 }
433
434
LowerJSCreateClosure(Node * node)435 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
436 CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
437 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
438 Handle<SharedFunctionInfo> const shared_info = p.shared_info();
439 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
440
441 // Use the FastNewClosureStub only for functions allocated in new space.
442 if (p.pretenure() == NOT_TENURED) {
443 Callable callable = CodeFactory::FastNewClosure(isolate());
444 ReplaceWithStubCall(node, callable, flags);
445 } else {
446 ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED)
447 ? Runtime::kNewClosure_Tenured
448 : Runtime::kNewClosure);
449 }
450 }
451
452
LowerJSCreateFunctionContext(Node * node)453 void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
454 int const slot_count = OpParameter<int>(node->op());
455 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
456
457 if (slot_count <= FastNewFunctionContextStub::kMaximumSlots) {
458 Callable callable = CodeFactory::FastNewFunctionContext(isolate());
459 node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
460 ReplaceWithStubCall(node, callable, flags);
461 } else {
462 ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
463 }
464 }
465
466
LowerJSCreateIterResultObject(Node * node)467 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
468 ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject);
469 }
470
LowerJSCreateKeyValueArray(Node * node)471 void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
472 ReplaceWithRuntimeCall(node, Runtime::kCreateKeyValueArray);
473 }
474
LowerJSCreateLiteralArray(Node * node)475 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
476 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
477 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
478 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
479 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
480
481 // Use the FastCloneShallowArrayStub only for shallow boilerplates up to the
482 // initial length limit for arrays with "fast" elements kind.
483 if ((p.flags() & ArrayLiteral::kShallowElements) != 0 &&
484 p.length() < JSArray::kInitialMaxFastElementArray) {
485 Callable callable = CodeFactory::FastCloneShallowArray(isolate());
486 ReplaceWithStubCall(node, callable, flags);
487 } else {
488 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
489 ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
490 }
491 }
492
493
LowerJSCreateLiteralObject(Node * node)494 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
495 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
496 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
497 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
498 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
499 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
500
501 // Use the FastCloneShallowObjectStub only for shallow boilerplates without
502 // elements up to the number of properties that the stubs can handle.
503 if ((p.flags() & ObjectLiteral::kShallowProperties) != 0 &&
504 p.length() <= FastCloneShallowObjectStub::kMaximumClonedProperties) {
505 Callable callable =
506 CodeFactory::FastCloneShallowObject(isolate(), p.length());
507 ReplaceWithStubCall(node, callable, flags);
508 } else {
509 ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
510 }
511 }
512
513
LowerJSCreateLiteralRegExp(Node * node)514 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
515 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
516 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
517 Callable callable = CodeFactory::FastCloneRegExp(isolate());
518 Node* literal_index = jsgraph()->SmiConstant(p.index());
519 Node* literal_flags = jsgraph()->SmiConstant(p.flags());
520 Node* pattern = jsgraph()->HeapConstant(p.constant());
521 node->InsertInput(graph()->zone(), 1, literal_index);
522 node->InsertInput(graph()->zone(), 2, pattern);
523 node->InsertInput(graph()->zone(), 3, literal_flags);
524 ReplaceWithStubCall(node, callable, flags);
525 }
526
527
LowerJSCreateCatchContext(Node * node)528 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
529 const CreateCatchContextParameters& parameters =
530 CreateCatchContextParametersOf(node->op());
531 node->InsertInput(zone(), 0,
532 jsgraph()->HeapConstant(parameters.catch_name()));
533 node->InsertInput(zone(), 2,
534 jsgraph()->HeapConstant(parameters.scope_info()));
535 ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
536 }
537
LowerJSCreateWithContext(Node * node)538 void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
539 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
540 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
541 ReplaceWithRuntimeCall(node, Runtime::kPushWithContext);
542 }
543
LowerJSCreateBlockContext(Node * node)544 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
545 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
546 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
547 ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
548 }
549
550
LowerJSCreateScriptContext(Node * node)551 void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
552 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
553 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
554 ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
555 }
556
557
LowerJSCallConstruct(Node * node)558 void JSGenericLowering::LowerJSCallConstruct(Node* node) {
559 CallConstructParameters const& p = CallConstructParametersOf(node->op());
560 int const arg_count = static_cast<int>(p.arity() - 2);
561 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
562 Callable callable = CodeFactory::Construct(isolate());
563 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
564 isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
565 Node* stub_code = jsgraph()->HeapConstant(callable.code());
566 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
567 Node* new_target = node->InputAt(arg_count + 1);
568 Node* receiver = jsgraph()->UndefinedConstant();
569 node->RemoveInput(arg_count + 1); // Drop new target.
570 node->InsertInput(zone(), 0, stub_code);
571 node->InsertInput(zone(), 2, new_target);
572 node->InsertInput(zone(), 3, stub_arity);
573 node->InsertInput(zone(), 4, receiver);
574 NodeProperties::ChangeOp(node, common()->Call(desc));
575 }
576
577
LowerJSCallFunction(Node * node)578 void JSGenericLowering::LowerJSCallFunction(Node* node) {
579 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
580 int const arg_count = static_cast<int>(p.arity() - 2);
581 ConvertReceiverMode const mode = p.convert_mode();
582 Callable callable = CodeFactory::Call(isolate(), mode);
583 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
584 if (p.tail_call_mode() == TailCallMode::kAllow) {
585 flags |= CallDescriptor::kSupportsTailCalls;
586 }
587 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
588 isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
589 Node* stub_code = jsgraph()->HeapConstant(callable.code());
590 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
591 node->InsertInput(zone(), 0, stub_code);
592 node->InsertInput(zone(), 2, stub_arity);
593 NodeProperties::ChangeOp(node, common()->Call(desc));
594 }
595
596
LowerJSCallRuntime(Node * node)597 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
598 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
599 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
600 }
601
LowerJSConvertReceiver(Node * node)602 void JSGenericLowering::LowerJSConvertReceiver(Node* node) {
603 ReplaceWithRuntimeCall(node, Runtime::kConvertReceiver);
604 }
605
LowerJSForInNext(Node * node)606 void JSGenericLowering::LowerJSForInNext(Node* node) {
607 ReplaceWithRuntimeCall(node, Runtime::kForInNext);
608 }
609
610
LowerJSForInPrepare(Node * node)611 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
612 ReplaceWithRuntimeCall(node, Runtime::kForInPrepare);
613 }
614
LowerJSLoadMessage(Node * node)615 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
616 ExternalReference message_address =
617 ExternalReference::address_of_pending_message_obj(isolate());
618 node->RemoveInput(NodeProperties::FirstContextIndex(node));
619 node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
620 node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
621 NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
622 }
623
624
LowerJSStoreMessage(Node * node)625 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
626 ExternalReference message_address =
627 ExternalReference::address_of_pending_message_obj(isolate());
628 node->RemoveInput(NodeProperties::FirstContextIndex(node));
629 node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
630 node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
631 StoreRepresentation representation(MachineRepresentation::kTagged,
632 kNoWriteBarrier);
633 NodeProperties::ChangeOp(node, machine()->Store(representation));
634 }
635
LowerJSLoadModule(Node * node)636 void JSGenericLowering::LowerJSLoadModule(Node* node) {
637 UNREACHABLE(); // Eliminated in typed lowering.
638 }
639
LowerJSStoreModule(Node * node)640 void JSGenericLowering::LowerJSStoreModule(Node* node) {
641 UNREACHABLE(); // Eliminated in typed lowering.
642 }
643
LowerJSGeneratorStore(Node * node)644 void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
645 UNREACHABLE(); // Eliminated in typed lowering.
646 }
647
LowerJSGeneratorRestoreContinuation(Node * node)648 void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
649 UNREACHABLE(); // Eliminated in typed lowering.
650 }
651
LowerJSGeneratorRestoreRegister(Node * node)652 void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
653 UNREACHABLE(); // Eliminated in typed lowering.
654 }
655
LowerJSStackCheck(Node * node)656 void JSGenericLowering::LowerJSStackCheck(Node* node) {
657 Node* effect = NodeProperties::GetEffectInput(node);
658 Node* control = NodeProperties::GetControlInput(node);
659
660 Node* limit = graph()->NewNode(
661 machine()->Load(MachineType::Pointer()),
662 jsgraph()->ExternalConstant(
663 ExternalReference::address_of_stack_limit(isolate())),
664 jsgraph()->IntPtrConstant(0), effect, control);
665 Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
666
667 Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
668 Node* branch =
669 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
670
671 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
672 Node* etrue = effect;
673
674 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
675 NodeProperties::ReplaceControlInput(node, if_false);
676 Node* efalse = node;
677
678 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
679 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
680
681 // Wire the new diamond into the graph, {node} can still throw.
682 NodeProperties::ReplaceUses(node, node, ephi, node, node);
683 NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
684
685 // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
686 // the node and places it inside the diamond. Come up with a helper method!
687 for (Node* use : node->uses()) {
688 if (use->opcode() == IrOpcode::kIfSuccess) {
689 use->ReplaceUses(merge);
690 merge->ReplaceInput(1, use);
691 }
692 }
693
694 // Turn the stack check into a runtime call.
695 ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
696 }
697
698
zone() const699 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
700
701
isolate() const702 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
703
704
graph() const705 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
706
707
common() const708 CommonOperatorBuilder* JSGenericLowering::common() const {
709 return jsgraph()->common();
710 }
711
712
machine() const713 MachineOperatorBuilder* JSGenericLowering::machine() const {
714 return jsgraph()->machine();
715 }
716
717 } // namespace compiler
718 } // namespace internal
719 } // namespace v8
720