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/feedback-vector.h"
18 #include "src/objects/scope-info.h"
19
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23
24 namespace {
25
FrameStateFlagForCall(Node * node)26 CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
27 return OperatorProperties::HasFrameStateInput(node->op())
28 ? CallDescriptor::kNeedsFrameState
29 : CallDescriptor::kNoFlags;
30 }
31
32 } // namespace
33
JSGenericLowering(JSGraph * jsgraph)34 JSGenericLowering::JSGenericLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
35
~JSGenericLowering()36 JSGenericLowering::~JSGenericLowering() {}
37
38
Reduce(Node * node)39 Reduction JSGenericLowering::Reduce(Node* node) {
40 switch (node->opcode()) {
41 #define DECLARE_CASE(x) \
42 case IrOpcode::k##x: \
43 Lower##x(node); \
44 break;
45 JS_OP_LIST(DECLARE_CASE)
46 #undef DECLARE_CASE
47 default:
48 // Nothing to see.
49 return NoChange();
50 }
51 return Changed(node);
52 }
53
54 #define REPLACE_STUB_CALL(Name) \
55 void JSGenericLowering::LowerJS##Name(Node* node) { \
56 CallDescriptor::Flags flags = FrameStateFlagForCall(node); \
57 Callable callable = Builtins::CallableFor(isolate(), Builtins::k##Name); \
58 ReplaceWithStubCall(node, callable, flags); \
59 }
60 REPLACE_STUB_CALL(Add)
REPLACE_STUB_CALL(Subtract)61 REPLACE_STUB_CALL(Subtract)
62 REPLACE_STUB_CALL(Multiply)
63 REPLACE_STUB_CALL(Divide)
64 REPLACE_STUB_CALL(Modulus)
65 REPLACE_STUB_CALL(Exponentiate)
66 REPLACE_STUB_CALL(BitwiseAnd)
67 REPLACE_STUB_CALL(BitwiseOr)
68 REPLACE_STUB_CALL(BitwiseXor)
69 REPLACE_STUB_CALL(ShiftLeft)
70 REPLACE_STUB_CALL(ShiftRight)
71 REPLACE_STUB_CALL(ShiftRightLogical)
72 REPLACE_STUB_CALL(LessThan)
73 REPLACE_STUB_CALL(LessThanOrEqual)
74 REPLACE_STUB_CALL(GreaterThan)
75 REPLACE_STUB_CALL(GreaterThanOrEqual)
76 REPLACE_STUB_CALL(BitwiseNot)
77 REPLACE_STUB_CALL(Decrement)
78 REPLACE_STUB_CALL(Increment)
79 REPLACE_STUB_CALL(Negate)
80 REPLACE_STUB_CALL(HasProperty)
81 REPLACE_STUB_CALL(Equal)
82 REPLACE_STUB_CALL(ToInteger)
83 REPLACE_STUB_CALL(ToLength)
84 REPLACE_STUB_CALL(ToNumber)
85 REPLACE_STUB_CALL(ToNumberConvertBigInt)
86 REPLACE_STUB_CALL(ToNumeric)
87 REPLACE_STUB_CALL(ToName)
88 REPLACE_STUB_CALL(ToObject)
89 REPLACE_STUB_CALL(ToString)
90 REPLACE_STUB_CALL(ForInEnumerate)
91 REPLACE_STUB_CALL(FulfillPromise)
92 REPLACE_STUB_CALL(PerformPromiseThen)
93 REPLACE_STUB_CALL(PromiseResolve)
94 REPLACE_STUB_CALL(RejectPromise)
95 REPLACE_STUB_CALL(ResolvePromise)
96 #undef REPLACE_STUB_CALL
97
98 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
99 CallDescriptor::Flags flags) {
100 ReplaceWithStubCall(node, callable, flags, node->op()->properties());
101 }
102
ReplaceWithStubCall(Node * node,Callable callable,CallDescriptor::Flags flags,Operator::Properties properties)103 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
104 CallDescriptor::Flags flags,
105 Operator::Properties properties) {
106 const CallInterfaceDescriptor& descriptor = callable.descriptor();
107 auto call_descriptor = Linkage::GetStubCallDescriptor(
108 zone(), descriptor, descriptor.GetStackParameterCount(), flags,
109 properties);
110 Node* stub_code = jsgraph()->HeapConstant(callable.code());
111 node->InsertInput(zone(), 0, stub_code);
112 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
113 }
114
115
ReplaceWithRuntimeCall(Node * node,Runtime::FunctionId f,int nargs_override)116 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
117 Runtime::FunctionId f,
118 int nargs_override) {
119 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
120 Operator::Properties properties = node->op()->properties();
121 const Runtime::Function* fun = Runtime::FunctionForId(f);
122 int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
123 auto call_descriptor =
124 Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
125 Node* ref = jsgraph()->ExternalConstant(ExternalReference::Create(f));
126 Node* arity = jsgraph()->Int32Constant(nargs);
127 node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
128 node->InsertInput(zone(), nargs + 1, ref);
129 node->InsertInput(zone(), nargs + 2, arity);
130 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
131 }
132
LowerJSStrictEqual(Node * node)133 void JSGenericLowering::LowerJSStrictEqual(Node* node) {
134 // The === operator doesn't need the current context.
135 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
136 Callable callable = Builtins::CallableFor(isolate(), Builtins::kStrictEqual);
137 node->RemoveInput(4); // control
138 ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
139 Operator::kEliminatable);
140 }
141
LowerJSLoadProperty(Node * node)142 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
143 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
144 const PropertyAccess& p = PropertyAccessOf(node->op());
145 Node* frame_state = NodeProperties::GetFrameStateInput(node);
146 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
147 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
148 if (outer_state->opcode() != IrOpcode::kFrameState) {
149 Callable callable =
150 Builtins::CallableFor(isolate(), Builtins::kKeyedLoadICTrampoline);
151 ReplaceWithStubCall(node, callable, flags);
152 } else {
153 Callable callable =
154 Builtins::CallableFor(isolate(), Builtins::kKeyedLoadIC);
155 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
156 node->InsertInput(zone(), 3, vector);
157 ReplaceWithStubCall(node, callable, flags);
158 }
159 }
160
LowerJSLoadNamed(Node * node)161 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
162 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
163 NamedAccess const& p = NamedAccessOf(node->op());
164 Node* frame_state = NodeProperties::GetFrameStateInput(node);
165 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
166 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
167 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
168 if (outer_state->opcode() != IrOpcode::kFrameState) {
169 Callable callable =
170 Builtins::CallableFor(isolate(), Builtins::kLoadICTrampoline);
171 ReplaceWithStubCall(node, callable, flags);
172 } else {
173 Callable callable = Builtins::CallableFor(isolate(), Builtins::kLoadIC);
174 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
175 node->InsertInput(zone(), 3, vector);
176 ReplaceWithStubCall(node, callable, flags);
177 }
178 }
179
180
LowerJSLoadGlobal(Node * node)181 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
182 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
183 const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
184 Node* frame_state = NodeProperties::GetFrameStateInput(node);
185 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
186 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
187 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
188 if (outer_state->opcode() != IrOpcode::kFrameState) {
189 Callable callable = CodeFactory::LoadGlobalIC(isolate(), p.typeof_mode());
190 ReplaceWithStubCall(node, callable, flags);
191 } else {
192 Callable callable =
193 CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
194 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
195 node->InsertInput(zone(), 2, vector);
196 ReplaceWithStubCall(node, callable, flags);
197 }
198 }
199
LowerJSStoreProperty(Node * node)200 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
201 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
202 PropertyAccess const& p = PropertyAccessOf(node->op());
203 Node* frame_state = NodeProperties::GetFrameStateInput(node);
204 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
205 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
206 if (outer_state->opcode() != IrOpcode::kFrameState) {
207 Callable callable =
208 Builtins::CallableFor(isolate(), Builtins::kKeyedStoreICTrampoline);
209 ReplaceWithStubCall(node, callable, flags);
210 } else {
211 Callable callable =
212 Builtins::CallableFor(isolate(), Builtins::kKeyedStoreIC);
213 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
214 node->InsertInput(zone(), 4, vector);
215 ReplaceWithStubCall(node, callable, flags);
216 }
217 }
218
LowerJSStoreNamed(Node * node)219 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
220 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
221 NamedAccess const& p = NamedAccessOf(node->op());
222 Node* frame_state = NodeProperties::GetFrameStateInput(node);
223 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
224 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
225 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
226 if (outer_state->opcode() != IrOpcode::kFrameState) {
227 Callable callable =
228 Builtins::CallableFor(isolate(), Builtins::kStoreICTrampoline);
229 ReplaceWithStubCall(node, callable, flags);
230 } else {
231 Callable callable = Builtins::CallableFor(isolate(), Builtins::kStoreIC);
232 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
233 node->InsertInput(zone(), 4, vector);
234 ReplaceWithStubCall(node, callable, flags);
235 }
236 }
237
LowerJSStoreNamedOwn(Node * node)238 void JSGenericLowering::LowerJSStoreNamedOwn(Node* node) {
239 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
240 StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
241 Node* frame_state = NodeProperties::GetFrameStateInput(node);
242 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
243 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
244 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
245 if (outer_state->opcode() != IrOpcode::kFrameState) {
246 Callable callable = CodeFactory::StoreOwnIC(isolate());
247 ReplaceWithStubCall(node, callable, flags);
248 } else {
249 Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
250 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
251 node->InsertInput(zone(), 4, vector);
252 ReplaceWithStubCall(node, callable, flags);
253 }
254 }
255
LowerJSStoreGlobal(Node * node)256 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
257 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
258 const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
259 Node* frame_state = NodeProperties::GetFrameStateInput(node);
260 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
261 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.name()));
262 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
263 if (outer_state->opcode() != IrOpcode::kFrameState) {
264 Callable callable =
265 Builtins::CallableFor(isolate(), Builtins::kStoreGlobalICTrampoline);
266 ReplaceWithStubCall(node, callable, flags);
267 } else {
268 Callable callable =
269 Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
270 Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
271 node->InsertInput(zone(), 3, vector);
272 ReplaceWithStubCall(node, callable, flags);
273 }
274 }
275
LowerJSStoreDataPropertyInLiteral(Node * node)276 void JSGenericLowering::LowerJSStoreDataPropertyInLiteral(Node* node) {
277 FeedbackParameter const& p = FeedbackParameterOf(node->op());
278 node->InsertInputs(zone(), 4, 2);
279 node->ReplaceInput(4, jsgraph()->HeapConstant(p.feedback().vector()));
280 node->ReplaceInput(5, jsgraph()->SmiConstant(p.feedback().index()));
281 ReplaceWithRuntimeCall(node, Runtime::kDefineDataPropertyInLiteral);
282 }
283
LowerJSStoreInArrayLiteral(Node * node)284 void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
285 Callable callable =
286 Builtins::CallableFor(isolate(), Builtins::kStoreInArrayLiteralIC);
287 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
288 FeedbackParameter const& p = FeedbackParameterOf(node->op());
289 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
290 node->InsertInput(zone(), 4, jsgraph()->HeapConstant(p.feedback().vector()));
291 ReplaceWithStubCall(node, callable, flags);
292 }
293
LowerJSDeleteProperty(Node * node)294 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
295 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
296 Callable callable =
297 Builtins::CallableFor(isolate(), Builtins::kDeleteProperty);
298 ReplaceWithStubCall(node, callable, flags);
299 }
300
LowerJSGetSuperConstructor(Node * node)301 void JSGenericLowering::LowerJSGetSuperConstructor(Node* node) {
302 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
303 Callable callable =
304 Builtins::CallableFor(isolate(), Builtins::kGetSuperConstructor);
305 ReplaceWithStubCall(node, callable, flags);
306 }
307
LowerJSHasInPrototypeChain(Node * node)308 void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
309 ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
310 }
311
LowerJSInstanceOf(Node * node)312 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
313 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
314 Callable callable = Builtins::CallableFor(isolate(), Builtins::kInstanceOf);
315 ReplaceWithStubCall(node, callable, flags);
316 }
317
LowerJSOrdinaryHasInstance(Node * node)318 void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
319 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
320 Callable callable =
321 Builtins::CallableFor(isolate(), Builtins::kOrdinaryHasInstance);
322 ReplaceWithStubCall(node, callable, flags);
323 }
324
LowerJSLoadContext(Node * node)325 void JSGenericLowering::LowerJSLoadContext(Node* node) {
326 UNREACHABLE(); // Eliminated in typed lowering.
327 }
328
329
LowerJSStoreContext(Node * node)330 void JSGenericLowering::LowerJSStoreContext(Node* node) {
331 UNREACHABLE(); // Eliminated in typed lowering.
332 }
333
334
LowerJSCreate(Node * node)335 void JSGenericLowering::LowerJSCreate(Node* node) {
336 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
337 Callable callable =
338 Builtins::CallableFor(isolate(), Builtins::kFastNewObject);
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 auto call_descriptor = Linkage::GetStubCallDescriptor(
363 zone(), ArrayConstructorDescriptor{}, arity + 1,
364 CallDescriptor::kNeedsFrameState, node->op()->properties());
365 Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
366 Node* stub_arity = jsgraph()->Int32Constant(arity);
367 MaybeHandle<AllocationSite> const maybe_site = p.site();
368 Handle<AllocationSite> site;
369 Node* type_info = maybe_site.ToHandle(&site) ? jsgraph()->HeapConstant(site)
370 : jsgraph()->UndefinedConstant();
371 Node* receiver = jsgraph()->UndefinedConstant();
372 node->InsertInput(zone(), 0, stub_code);
373 node->InsertInput(zone(), 3, stub_arity);
374 node->InsertInput(zone(), 4, type_info);
375 node->InsertInput(zone(), 5, receiver);
376 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
377 }
378
LowerJSCreateArrayIterator(Node * node)379 void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
380 UNREACHABLE(); // Eliminated in typed lowering.
381 }
382
LowerJSCreateCollectionIterator(Node * node)383 void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
384 UNREACHABLE(); // Eliminated in typed lowering.
385 }
386
LowerJSCreateBoundFunction(Node * node)387 void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
388 UNREACHABLE(); // Eliminated in typed lowering.
389 }
390
LowerJSObjectIsArray(Node * node)391 void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
392 UNREACHABLE(); // Eliminated in typed lowering.
393 }
394
LowerJSCreateObject(Node * node)395 void JSGenericLowering::LowerJSCreateObject(Node* node) {
396 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
397 Callable callable = Builtins::CallableFor(
398 isolate(), Builtins::kCreateObjectWithoutProperties);
399 ReplaceWithStubCall(node, callable, flags);
400 }
401
LowerJSParseInt(Node * node)402 void JSGenericLowering::LowerJSParseInt(Node* node) {
403 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
404 Callable callable = Builtins::CallableFor(isolate(), Builtins::kParseInt);
405 ReplaceWithStubCall(node, callable, flags);
406 }
407
LowerJSRegExpTest(Node * node)408 void JSGenericLowering::LowerJSRegExpTest(Node* node) {
409 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
410 Callable callable =
411 Builtins::CallableFor(isolate(), Builtins::kRegExpPrototypeTestFast);
412 ReplaceWithStubCall(node, callable, flags);
413 }
414
LowerJSCreateClosure(Node * node)415 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
416 CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
417 Handle<SharedFunctionInfo> const shared_info = p.shared_info();
418 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
419 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.feedback_cell()));
420 node->RemoveInput(4); // control
421
422 // Use the FastNewClosure builtin only for functions allocated in new space.
423 if (p.pretenure() == NOT_TENURED) {
424 Callable callable =
425 Builtins::CallableFor(isolate(), Builtins::kFastNewClosure);
426 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
427 ReplaceWithStubCall(node, callable, flags);
428 } else {
429 ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
430 }
431 }
432
433
LowerJSCreateFunctionContext(Node * node)434 void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
435 const CreateFunctionContextParameters& parameters =
436 CreateFunctionContextParametersOf(node->op());
437 Handle<ScopeInfo> scope_info = parameters.scope_info();
438 int slot_count = parameters.slot_count();
439 ScopeType scope_type = parameters.scope_type();
440 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
441
442 if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
443 Callable callable =
444 CodeFactory::FastNewFunctionContext(isolate(), scope_type);
445 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
446 node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
447 ReplaceWithStubCall(node, callable, flags);
448 } else {
449 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
450 ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
451 }
452 }
453
LowerJSCreateGeneratorObject(Node * node)454 void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
455 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
456 Callable callable =
457 Builtins::CallableFor(isolate(), Builtins::kCreateGeneratorObject);
458 node->RemoveInput(4); // control
459 ReplaceWithStubCall(node, callable, flags);
460 }
461
LowerJSCreateIterResultObject(Node * node)462 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
463 UNREACHABLE(); // Eliminated in typed lowering.
464 }
465
LowerJSCreateStringIterator(Node * node)466 void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
467 UNREACHABLE(); // Eliminated in typed lowering.
468 }
469
LowerJSCreateKeyValueArray(Node * node)470 void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
471 UNREACHABLE(); // Eliminated in typed lowering.
472 }
473
LowerJSCreatePromise(Node * node)474 void JSGenericLowering::LowerJSCreatePromise(Node* node) {
475 UNREACHABLE(); // Eliminated in typed lowering.
476 }
477
LowerJSCreateTypedArray(Node * node)478 void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
479 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
480 Callable callable =
481 Builtins::CallableFor(isolate(), Builtins::kCreateTypedArray);
482 ReplaceWithStubCall(node, callable, flags);
483 }
484
LowerJSCreateLiteralArray(Node * node)485 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
486 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
487 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
488 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
489 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
490 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
491
492 // Use the CreateShallowArrayLiteratlr builtin only for shallow boilerplates
493 // without properties up to the number of elements that the stubs can handle.
494 if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
495 p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
496 Callable callable =
497 Builtins::CallableFor(isolate(), Builtins::kCreateShallowArrayLiteral);
498 ReplaceWithStubCall(node, callable, flags);
499 } else {
500 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
501 ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
502 }
503 }
504
LowerJSCreateEmptyLiteralArray(Node * node)505 void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
506 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
507 FeedbackParameter const& p = FeedbackParameterOf(node->op());
508 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
509 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
510 node->RemoveInput(4); // control
511 Callable callable =
512 Builtins::CallableFor(isolate(), Builtins::kCreateEmptyArrayLiteral);
513 ReplaceWithStubCall(node, callable, flags);
514 }
515
LowerJSCreateLiteralObject(Node * node)516 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
517 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
518 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
519 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
520 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
521 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
522 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
523
524 // Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
525 // without elements up to the number of properties that the stubs can handle.
526 if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
527 p.length() <=
528 ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
529 Callable callable =
530 Builtins::CallableFor(isolate(), Builtins::kCreateShallowObjectLiteral);
531 ReplaceWithStubCall(node, callable, flags);
532 } else {
533 ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
534 }
535 }
536
LowerJSCloneObject(Node * node)537 void JSGenericLowering::LowerJSCloneObject(Node* node) {
538 CloneObjectParameters const& p = CloneObjectParametersOf(node->op());
539 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
540 Callable callable =
541 Builtins::CallableFor(isolate(), Builtins::kCloneObjectIC);
542 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
543 node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
544 node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector()));
545 ReplaceWithStubCall(node, callable, flags);
546 }
547
LowerJSCreateEmptyLiteralObject(Node * node)548 void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
549 UNREACHABLE(); // Eliminated in typed lowering.
550 }
551
LowerJSCreateLiteralRegExp(Node * node)552 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
553 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
554 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
555 Callable callable =
556 Builtins::CallableFor(isolate(), Builtins::kCreateRegExpLiteral);
557 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
558 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
559 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
560 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
561 ReplaceWithStubCall(node, callable, flags);
562 }
563
564
LowerJSCreateCatchContext(Node * node)565 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
566 UNREACHABLE(); // Eliminated in typed lowering.
567 }
568
LowerJSCreateWithContext(Node * node)569 void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
570 UNREACHABLE(); // Eliminated in typed lowering.
571 }
572
LowerJSCreateBlockContext(Node * node)573 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
574 Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
575 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
576 ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
577 }
578
LowerJSConstructForwardVarargs(Node * node)579 void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
580 ConstructForwardVarargsParameters p =
581 ConstructForwardVarargsParametersOf(node->op());
582 int const arg_count = static_cast<int>(p.arity() - 2);
583 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
584 Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
585 auto call_descriptor = Linkage::GetStubCallDescriptor(
586 zone(), callable.descriptor(), arg_count + 1, flags);
587 Node* stub_code = jsgraph()->HeapConstant(callable.code());
588 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
589 Node* start_index = jsgraph()->Uint32Constant(p.start_index());
590 Node* new_target = node->InputAt(arg_count + 1);
591 Node* receiver = jsgraph()->UndefinedConstant();
592 node->RemoveInput(arg_count + 1); // Drop new target.
593 node->InsertInput(zone(), 0, stub_code);
594 node->InsertInput(zone(), 2, new_target);
595 node->InsertInput(zone(), 3, stub_arity);
596 node->InsertInput(zone(), 4, start_index);
597 node->InsertInput(zone(), 5, receiver);
598 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
599 }
600
LowerJSConstruct(Node * node)601 void JSGenericLowering::LowerJSConstruct(Node* node) {
602 ConstructParameters const& p = ConstructParametersOf(node->op());
603 int const arg_count = static_cast<int>(p.arity() - 2);
604 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
605 Callable callable = CodeFactory::Construct(isolate());
606 auto call_descriptor = Linkage::GetStubCallDescriptor(
607 zone(), callable.descriptor(), arg_count + 1, flags);
608 Node* stub_code = jsgraph()->HeapConstant(callable.code());
609 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
610 Node* new_target = node->InputAt(arg_count + 1);
611 Node* receiver = jsgraph()->UndefinedConstant();
612 node->RemoveInput(arg_count + 1); // Drop new target.
613 node->InsertInput(zone(), 0, stub_code);
614 node->InsertInput(zone(), 2, new_target);
615 node->InsertInput(zone(), 3, stub_arity);
616 node->InsertInput(zone(), 4, receiver);
617 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
618 }
619
LowerJSConstructWithArrayLike(Node * node)620 void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
621 Callable callable =
622 Builtins::CallableFor(isolate(), Builtins::kConstructWithArrayLike);
623 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
624 auto call_descriptor =
625 Linkage::GetStubCallDescriptor(zone(), callable.descriptor(), 1, flags);
626 Node* stub_code = jsgraph()->HeapConstant(callable.code());
627 Node* receiver = jsgraph()->UndefinedConstant();
628 Node* arguments_list = node->InputAt(1);
629 Node* new_target = node->InputAt(2);
630 node->InsertInput(zone(), 0, stub_code);
631 node->ReplaceInput(2, new_target);
632 node->ReplaceInput(3, arguments_list);
633 node->InsertInput(zone(), 4, receiver);
634 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
635 }
636
LowerJSConstructWithSpread(Node * node)637 void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
638 ConstructParameters const& p = ConstructParametersOf(node->op());
639 int const arg_count = static_cast<int>(p.arity() - 2);
640 int const spread_index = arg_count;
641 int const new_target_index = arg_count + 1;
642 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
643 Callable callable = CodeFactory::ConstructWithSpread(isolate());
644 auto call_descriptor = Linkage::GetStubCallDescriptor(
645 zone(), callable.descriptor(), arg_count, flags);
646 Node* stub_code = jsgraph()->HeapConstant(callable.code());
647 Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
648 Node* new_target = node->InputAt(new_target_index);
649 Node* spread = node->InputAt(spread_index);
650 Node* receiver = jsgraph()->UndefinedConstant();
651 DCHECK(new_target_index > spread_index);
652 node->RemoveInput(new_target_index); // Drop new target.
653 node->RemoveInput(spread_index);
654
655 node->InsertInput(zone(), 0, stub_code);
656 node->InsertInput(zone(), 2, new_target);
657 node->InsertInput(zone(), 3, stack_arg_count);
658 node->InsertInput(zone(), 4, spread);
659 node->InsertInput(zone(), 5, receiver);
660 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
661 }
662
LowerJSCallForwardVarargs(Node * node)663 void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
664 CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
665 int const arg_count = static_cast<int>(p.arity() - 2);
666 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
667 Callable callable = CodeFactory::CallForwardVarargs(isolate());
668 auto call_descriptor = Linkage::GetStubCallDescriptor(
669 zone(), callable.descriptor(), arg_count + 1, flags);
670 Node* stub_code = jsgraph()->HeapConstant(callable.code());
671 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
672 Node* start_index = jsgraph()->Uint32Constant(p.start_index());
673 node->InsertInput(zone(), 0, stub_code);
674 node->InsertInput(zone(), 2, stub_arity);
675 node->InsertInput(zone(), 3, start_index);
676 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
677 }
678
LowerJSCall(Node * node)679 void JSGenericLowering::LowerJSCall(Node* node) {
680 CallParameters const& p = CallParametersOf(node->op());
681 int const arg_count = static_cast<int>(p.arity() - 2);
682 ConvertReceiverMode const mode = p.convert_mode();
683 Callable callable = CodeFactory::Call(isolate(), mode);
684 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
685 auto call_descriptor = Linkage::GetStubCallDescriptor(
686 zone(), callable.descriptor(), arg_count + 1, flags);
687 Node* stub_code = jsgraph()->HeapConstant(callable.code());
688 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
689 node->InsertInput(zone(), 0, stub_code);
690 node->InsertInput(zone(), 2, stub_arity);
691 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
692 }
693
LowerJSCallWithArrayLike(Node * node)694 void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
695 Callable callable = CodeFactory::CallWithArrayLike(isolate());
696 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
697 auto call_descriptor =
698 Linkage::GetStubCallDescriptor(zone(), callable.descriptor(), 1, flags);
699 Node* stub_code = jsgraph()->HeapConstant(callable.code());
700 Node* receiver = node->InputAt(1);
701 Node* arguments_list = node->InputAt(2);
702 node->InsertInput(zone(), 0, stub_code);
703 node->ReplaceInput(3, receiver);
704 node->ReplaceInput(2, arguments_list);
705 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
706 }
707
LowerJSCallWithSpread(Node * node)708 void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
709 CallParameters const& p = CallParametersOf(node->op());
710 int const arg_count = static_cast<int>(p.arity() - 2);
711 int const spread_index = static_cast<int>(p.arity() + 1);
712 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
713 Callable callable = CodeFactory::CallWithSpread(isolate());
714 auto call_descriptor = Linkage::GetStubCallDescriptor(
715 zone(), callable.descriptor(), arg_count, flags);
716 Node* stub_code = jsgraph()->HeapConstant(callable.code());
717 // We pass the spread in a register, not on the stack.
718 Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
719 node->InsertInput(zone(), 0, stub_code);
720 node->InsertInput(zone(), 2, stack_arg_count);
721 node->InsertInput(zone(), 3, node->InputAt(spread_index));
722 node->RemoveInput(spread_index + 1);
723 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
724 }
725
LowerJSCallRuntime(Node * node)726 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
727 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
728 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
729 }
730
LowerJSForInNext(Node * node)731 void JSGenericLowering::LowerJSForInNext(Node* node) {
732 UNREACHABLE(); // Eliminated in typed lowering.
733 }
734
LowerJSForInPrepare(Node * node)735 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
736 UNREACHABLE(); // Eliminated in typed lowering.
737 }
738
LowerJSLoadMessage(Node * node)739 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
740 UNREACHABLE(); // Eliminated in typed lowering.
741 }
742
743
LowerJSStoreMessage(Node * node)744 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
745 UNREACHABLE(); // Eliminated in typed lowering.
746 }
747
LowerJSLoadModule(Node * node)748 void JSGenericLowering::LowerJSLoadModule(Node* node) {
749 UNREACHABLE(); // Eliminated in typed lowering.
750 }
751
LowerJSStoreModule(Node * node)752 void JSGenericLowering::LowerJSStoreModule(Node* node) {
753 UNREACHABLE(); // Eliminated in typed lowering.
754 }
755
LowerJSGeneratorStore(Node * node)756 void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
757 UNREACHABLE(); // Eliminated in typed lowering.
758 }
759
LowerJSGeneratorRestoreContinuation(Node * node)760 void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
761 UNREACHABLE(); // Eliminated in typed lowering.
762 }
763
LowerJSGeneratorRestoreContext(Node * node)764 void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
765 UNREACHABLE(); // Eliminated in typed lowering.
766 }
767
LowerJSGeneratorRestoreInputOrDebugPos(Node * node)768 void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
769 UNREACHABLE(); // Eliminated in typed lowering.
770 }
771
LowerJSGeneratorRestoreRegister(Node * node)772 void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
773 UNREACHABLE(); // Eliminated in typed lowering.
774 }
775
LowerJSStackCheck(Node * node)776 void JSGenericLowering::LowerJSStackCheck(Node* node) {
777 Node* effect = NodeProperties::GetEffectInput(node);
778 Node* control = NodeProperties::GetControlInput(node);
779
780 Node* limit = effect = graph()->NewNode(
781 machine()->Load(MachineType::Pointer()),
782 jsgraph()->ExternalConstant(
783 ExternalReference::address_of_stack_limit(isolate())),
784 jsgraph()->IntPtrConstant(0), effect, control);
785 Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
786
787 Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
788 Node* branch =
789 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
790
791 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
792 Node* etrue = effect;
793
794 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
795 NodeProperties::ReplaceControlInput(node, if_false);
796 NodeProperties::ReplaceEffectInput(node, effect);
797 Node* efalse = if_false = node;
798
799 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
800 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
801
802 // Wire the new diamond into the graph, {node} can still throw.
803 NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
804 NodeProperties::ReplaceControlInput(merge, if_false, 1);
805 NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
806
807 // This iteration cuts out potential {IfSuccess} or {IfException} projection
808 // uses of the original node and places them inside the diamond, so that we
809 // can change the original {node} into the slow-path runtime call.
810 for (Edge edge : merge->use_edges()) {
811 if (!NodeProperties::IsControlEdge(edge)) continue;
812 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
813 NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
814 NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
815 edge.UpdateTo(node);
816 }
817 if (edge.from()->opcode() == IrOpcode::kIfException) {
818 NodeProperties::ReplaceEffectInput(edge.from(), node);
819 edge.UpdateTo(node);
820 }
821 }
822
823 // Turn the stack check into a runtime call.
824 ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
825 }
826
LowerJSDebugger(Node * node)827 void JSGenericLowering::LowerJSDebugger(Node* node) {
828 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
829 Callable callable = CodeFactory::HandleDebuggerStatement(isolate());
830 ReplaceWithStubCall(node, callable, flags);
831 }
832
zone() const833 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
834
835
isolate() const836 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
837
838
graph() const839 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
840
841
common() const842 CommonOperatorBuilder* JSGenericLowering::common() const {
843 return jsgraph()->common();
844 }
845
846
machine() const847 MachineOperatorBuilder* JSGenericLowering::machine() const {
848 return jsgraph()->machine();
849 }
850
851 } // namespace compiler
852 } // namespace internal
853 } // namespace v8
854