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