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(ToNumeric)
86 REPLACE_STUB_CALL(ToName)
87 REPLACE_STUB_CALL(ToObject)
88 REPLACE_STUB_CALL(ToString)
89 REPLACE_STUB_CALL(ForInEnumerate)
90 REPLACE_STUB_CALL(FulfillPromise)
91 REPLACE_STUB_CALL(PerformPromiseThen)
92 REPLACE_STUB_CALL(PromiseResolve)
93 REPLACE_STUB_CALL(RejectPromise)
94 REPLACE_STUB_CALL(ResolvePromise)
95 #undef REPLACE_STUB_CALL
96
97 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
98 CallDescriptor::Flags flags) {
99 ReplaceWithStubCall(node, callable, flags, node->op()->properties());
100 }
101
ReplaceWithStubCall(Node * node,Callable callable,CallDescriptor::Flags flags,Operator::Properties properties,int result_size)102 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
103 CallDescriptor::Flags flags,
104 Operator::Properties properties,
105 int result_size) {
106 const CallInterfaceDescriptor& descriptor = callable.descriptor();
107 auto call_descriptor = Linkage::GetStubCallDescriptor(
108 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(), flags,
109 properties, MachineType::AnyTagged(), result_size);
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 Handle<AllocationSite> const site = p.site();
363 ArrayConstructorDescriptor descriptor(isolate());
364 auto call_descriptor = Linkage::GetStubCallDescriptor(
365 isolate(), zone(), descriptor, arity + 1,
366 CallDescriptor::kNeedsFrameState, node->op()->properties(),
367 MachineType::AnyTagged());
368 Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
369 Node* stub_arity = jsgraph()->Int32Constant(arity);
370 Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
371 : jsgraph()->HeapConstant(site);
372 Node* receiver = jsgraph()->UndefinedConstant();
373 node->InsertInput(zone(), 0, stub_code);
374 node->InsertInput(zone(), 3, stub_arity);
375 node->InsertInput(zone(), 4, type_info);
376 node->InsertInput(zone(), 5, receiver);
377 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
378 }
379
LowerJSCreateArrayIterator(Node * node)380 void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
381 UNREACHABLE(); // Eliminated in typed lowering.
382 }
383
LowerJSCreateCollectionIterator(Node * node)384 void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
385 UNREACHABLE(); // Eliminated in typed lowering.
386 }
387
LowerJSCreateBoundFunction(Node * node)388 void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
389 UNREACHABLE(); // Eliminated in typed lowering.
390 }
391
LowerJSObjectIsArray(Node * node)392 void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
393 UNREACHABLE(); // Eliminated in typed lowering.
394 }
395
LowerJSCreateObject(Node * node)396 void JSGenericLowering::LowerJSCreateObject(Node* node) {
397 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
398 Callable callable = Builtins::CallableFor(
399 isolate(), Builtins::kCreateObjectWithoutProperties);
400 ReplaceWithStubCall(node, callable, flags);
401 }
402
LowerJSParseInt(Node * node)403 void JSGenericLowering::LowerJSParseInt(Node* node) {
404 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
405 Callable callable = Builtins::CallableFor(isolate(), Builtins::kParseInt);
406 ReplaceWithStubCall(node, callable, flags);
407 }
408
LowerJSCreateClosure(Node * node)409 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
410 CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
411 Handle<SharedFunctionInfo> const shared_info = p.shared_info();
412 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
413 node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.feedback_cell()));
414 node->RemoveInput(4); // control
415
416 // Use the FastNewClosure builtin only for functions allocated in new space.
417 if (p.pretenure() == NOT_TENURED) {
418 Callable callable =
419 Builtins::CallableFor(isolate(), Builtins::kFastNewClosure);
420 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
421 ReplaceWithStubCall(node, callable, flags);
422 } else {
423 ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
424 }
425 }
426
427
LowerJSCreateFunctionContext(Node * node)428 void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
429 const CreateFunctionContextParameters& parameters =
430 CreateFunctionContextParametersOf(node->op());
431 Handle<ScopeInfo> scope_info = parameters.scope_info();
432 int slot_count = parameters.slot_count();
433 ScopeType scope_type = parameters.scope_type();
434 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
435
436 if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
437 Callable callable =
438 CodeFactory::FastNewFunctionContext(isolate(), scope_type);
439 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
440 node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
441 ReplaceWithStubCall(node, callable, flags);
442 } else {
443 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
444 ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
445 }
446 }
447
LowerJSCreateGeneratorObject(Node * node)448 void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
449 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
450 Callable callable =
451 Builtins::CallableFor(isolate(), Builtins::kCreateGeneratorObject);
452 node->RemoveInput(4); // control
453 ReplaceWithStubCall(node, callable, flags);
454 }
455
LowerJSCreateIterResultObject(Node * node)456 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
457 UNREACHABLE(); // Eliminated in typed lowering.
458 }
459
LowerJSCreateStringIterator(Node * node)460 void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
461 UNREACHABLE(); // Eliminated in typed lowering.
462 }
463
LowerJSCreateKeyValueArray(Node * node)464 void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
465 UNREACHABLE(); // Eliminated in typed lowering.
466 }
467
LowerJSCreatePromise(Node * node)468 void JSGenericLowering::LowerJSCreatePromise(Node* node) {
469 UNREACHABLE(); // Eliminated in typed lowering.
470 }
471
LowerJSCreateTypedArray(Node * node)472 void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
473 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
474 Callable callable =
475 Builtins::CallableFor(isolate(), Builtins::kCreateTypedArray);
476 ReplaceWithStubCall(node, callable, flags);
477 }
478
LowerJSCreateLiteralArray(Node * node)479 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
480 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
481 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
482 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
483 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
484 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
485
486 // Use the CreateShallowArrayLiteratlr builtin only for shallow boilerplates
487 // without properties up to the number of elements that the stubs can handle.
488 if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
489 p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
490 Callable callable =
491 Builtins::CallableFor(isolate(), Builtins::kCreateShallowArrayLiteral);
492 ReplaceWithStubCall(node, callable, flags);
493 } else {
494 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
495 ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
496 }
497 }
498
LowerJSCreateEmptyLiteralArray(Node * node)499 void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
500 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
501 FeedbackParameter const& p = FeedbackParameterOf(node->op());
502 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
503 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
504 node->RemoveInput(4); // control
505 Callable callable =
506 Builtins::CallableFor(isolate(), Builtins::kCreateEmptyArrayLiteral);
507 ReplaceWithStubCall(node, callable, flags);
508 }
509
LowerJSCreateLiteralObject(Node * node)510 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
511 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
512 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
513 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
514 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
515 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
516 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
517
518 // Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
519 // without elements up to the number of properties that the stubs can handle.
520 if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
521 p.length() <=
522 ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
523 Callable callable =
524 Builtins::CallableFor(isolate(), Builtins::kCreateShallowObjectLiteral);
525 ReplaceWithStubCall(node, callable, flags);
526 } else {
527 ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
528 }
529 }
530
LowerJSCreateEmptyLiteralObject(Node * node)531 void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
532 UNREACHABLE(); // Eliminated in typed lowering.
533 }
534
LowerJSCreateLiteralRegExp(Node * node)535 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
536 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
537 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
538 Callable callable =
539 Builtins::CallableFor(isolate(), Builtins::kCreateRegExpLiteral);
540 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
541 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
542 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
543 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
544 ReplaceWithStubCall(node, callable, flags);
545 }
546
547
LowerJSCreateCatchContext(Node * node)548 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
549 UNREACHABLE(); // Eliminated in typed lowering.
550 }
551
LowerJSCreateWithContext(Node * node)552 void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
553 UNREACHABLE(); // Eliminated in typed lowering.
554 }
555
LowerJSCreateBlockContext(Node * node)556 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
557 Handle<ScopeInfo> scope_info = ScopeInfoOf(node->op());
558 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
559 ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
560 }
561
LowerJSConstructForwardVarargs(Node * node)562 void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
563 ConstructForwardVarargsParameters p =
564 ConstructForwardVarargsParametersOf(node->op());
565 int const arg_count = static_cast<int>(p.arity() - 2);
566 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
567 Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
568 auto call_descriptor = Linkage::GetStubCallDescriptor(
569 isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
570 Node* stub_code = jsgraph()->HeapConstant(callable.code());
571 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
572 Node* start_index = jsgraph()->Uint32Constant(p.start_index());
573 Node* new_target = node->InputAt(arg_count + 1);
574 Node* receiver = jsgraph()->UndefinedConstant();
575 node->RemoveInput(arg_count + 1); // Drop new target.
576 node->InsertInput(zone(), 0, stub_code);
577 node->InsertInput(zone(), 2, new_target);
578 node->InsertInput(zone(), 3, stub_arity);
579 node->InsertInput(zone(), 4, start_index);
580 node->InsertInput(zone(), 5, receiver);
581 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
582 }
583
LowerJSConstruct(Node * node)584 void JSGenericLowering::LowerJSConstruct(Node* node) {
585 ConstructParameters const& p = ConstructParametersOf(node->op());
586 int const arg_count = static_cast<int>(p.arity() - 2);
587 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
588 Callable callable = CodeFactory::Construct(isolate());
589 auto call_descriptor = 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* new_target = node->InputAt(arg_count + 1);
594 Node* receiver = jsgraph()->UndefinedConstant();
595 node->RemoveInput(arg_count + 1); // Drop new target.
596 node->InsertInput(zone(), 0, stub_code);
597 node->InsertInput(zone(), 2, new_target);
598 node->InsertInput(zone(), 3, stub_arity);
599 node->InsertInput(zone(), 4, receiver);
600 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
601 }
602
LowerJSConstructWithArrayLike(Node * node)603 void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
604 Callable callable =
605 Builtins::CallableFor(isolate(), Builtins::kConstructWithArrayLike);
606 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
607 auto call_descriptor = Linkage::GetStubCallDescriptor(
608 isolate(), zone(), callable.descriptor(), 1, flags);
609 Node* stub_code = jsgraph()->HeapConstant(callable.code());
610 Node* receiver = jsgraph()->UndefinedConstant();
611 Node* arguments_list = node->InputAt(1);
612 Node* new_target = node->InputAt(2);
613 node->InsertInput(zone(), 0, stub_code);
614 node->ReplaceInput(2, new_target);
615 node->ReplaceInput(3, arguments_list);
616 node->InsertInput(zone(), 4, receiver);
617 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
618 }
619
LowerJSConstructWithSpread(Node * node)620 void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
621 ConstructParameters const& p = ConstructParametersOf(node->op());
622 int const arg_count = static_cast<int>(p.arity() - 2);
623 int const spread_index = arg_count;
624 int const new_target_index = arg_count + 1;
625 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
626 Callable callable = CodeFactory::ConstructWithSpread(isolate());
627 auto call_descriptor = Linkage::GetStubCallDescriptor(
628 isolate(), zone(), callable.descriptor(), arg_count, flags);
629 Node* stub_code = jsgraph()->HeapConstant(callable.code());
630 Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
631 Node* new_target = node->InputAt(new_target_index);
632 Node* spread = node->InputAt(spread_index);
633 Node* receiver = jsgraph()->UndefinedConstant();
634 DCHECK(new_target_index > spread_index);
635 node->RemoveInput(new_target_index); // Drop new target.
636 node->RemoveInput(spread_index);
637
638 node->InsertInput(zone(), 0, stub_code);
639 node->InsertInput(zone(), 2, new_target);
640 node->InsertInput(zone(), 3, stack_arg_count);
641 node->InsertInput(zone(), 4, spread);
642 node->InsertInput(zone(), 5, receiver);
643 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
644 }
645
LowerJSCallForwardVarargs(Node * node)646 void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
647 CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
648 int const arg_count = static_cast<int>(p.arity() - 2);
649 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
650 Callable callable = CodeFactory::CallForwardVarargs(isolate());
651 auto call_descriptor = Linkage::GetStubCallDescriptor(
652 isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
653 Node* stub_code = jsgraph()->HeapConstant(callable.code());
654 Node* stub_arity = jsgraph()->Int32Constant(arg_count);
655 Node* start_index = jsgraph()->Uint32Constant(p.start_index());
656 node->InsertInput(zone(), 0, stub_code);
657 node->InsertInput(zone(), 2, stub_arity);
658 node->InsertInput(zone(), 3, start_index);
659 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
660 }
661
LowerJSCall(Node * node)662 void JSGenericLowering::LowerJSCall(Node* node) {
663 CallParameters const& p = CallParametersOf(node->op());
664 int const arg_count = static_cast<int>(p.arity() - 2);
665 ConvertReceiverMode const mode = p.convert_mode();
666 Callable callable = CodeFactory::Call(isolate(), mode);
667 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
668 auto call_descriptor = Linkage::GetStubCallDescriptor(
669 isolate(), 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->InsertInput(zone(), 0, stub_code);
673 node->InsertInput(zone(), 2, stub_arity);
674 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
675 }
676
LowerJSCallWithArrayLike(Node * node)677 void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
678 Callable callable = CodeFactory::CallWithArrayLike(isolate());
679 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
680 auto call_descriptor = Linkage::GetStubCallDescriptor(
681 isolate(), zone(), callable.descriptor(), 1, flags);
682 Node* stub_code = jsgraph()->HeapConstant(callable.code());
683 Node* receiver = node->InputAt(1);
684 Node* arguments_list = node->InputAt(2);
685 node->InsertInput(zone(), 0, stub_code);
686 node->ReplaceInput(3, receiver);
687 node->ReplaceInput(2, arguments_list);
688 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
689 }
690
LowerJSCallWithSpread(Node * node)691 void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
692 CallParameters const& p = CallParametersOf(node->op());
693 int const arg_count = static_cast<int>(p.arity() - 2);
694 int const spread_index = static_cast<int>(p.arity() + 1);
695 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
696 Callable callable = CodeFactory::CallWithSpread(isolate());
697 auto call_descriptor = Linkage::GetStubCallDescriptor(
698 isolate(), zone(), callable.descriptor(), arg_count, flags);
699 Node* stub_code = jsgraph()->HeapConstant(callable.code());
700 // We pass the spread in a register, not on the stack.
701 Node* stack_arg_count = jsgraph()->Int32Constant(arg_count - 1);
702 node->InsertInput(zone(), 0, stub_code);
703 node->InsertInput(zone(), 2, stack_arg_count);
704 node->InsertInput(zone(), 3, node->InputAt(spread_index));
705 node->RemoveInput(spread_index + 1);
706 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
707 }
708
LowerJSCallRuntime(Node * node)709 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
710 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
711 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
712 }
713
LowerJSForInNext(Node * node)714 void JSGenericLowering::LowerJSForInNext(Node* node) {
715 UNREACHABLE(); // Eliminated in typed lowering.
716 }
717
LowerJSForInPrepare(Node * node)718 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
719 UNREACHABLE(); // Eliminated in typed lowering.
720 }
721
LowerJSLoadMessage(Node * node)722 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
723 UNREACHABLE(); // Eliminated in typed lowering.
724 }
725
726
LowerJSStoreMessage(Node * node)727 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
728 UNREACHABLE(); // Eliminated in typed lowering.
729 }
730
LowerJSLoadModule(Node * node)731 void JSGenericLowering::LowerJSLoadModule(Node* node) {
732 UNREACHABLE(); // Eliminated in typed lowering.
733 }
734
LowerJSStoreModule(Node * node)735 void JSGenericLowering::LowerJSStoreModule(Node* node) {
736 UNREACHABLE(); // Eliminated in typed lowering.
737 }
738
LowerJSGeneratorStore(Node * node)739 void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
740 UNREACHABLE(); // Eliminated in typed lowering.
741 }
742
LowerJSGeneratorRestoreContinuation(Node * node)743 void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
744 UNREACHABLE(); // Eliminated in typed lowering.
745 }
746
LowerJSGeneratorRestoreContext(Node * node)747 void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
748 UNREACHABLE(); // Eliminated in typed lowering.
749 }
750
LowerJSGeneratorRestoreInputOrDebugPos(Node * node)751 void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
752 UNREACHABLE(); // Eliminated in typed lowering.
753 }
754
LowerJSGeneratorRestoreRegister(Node * node)755 void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
756 UNREACHABLE(); // Eliminated in typed lowering.
757 }
758
LowerJSStackCheck(Node * node)759 void JSGenericLowering::LowerJSStackCheck(Node* node) {
760 Node* effect = NodeProperties::GetEffectInput(node);
761 Node* control = NodeProperties::GetControlInput(node);
762
763 Node* limit = effect = graph()->NewNode(
764 machine()->Load(MachineType::Pointer()),
765 jsgraph()->ExternalConstant(
766 ExternalReference::address_of_stack_limit(isolate())),
767 jsgraph()->IntPtrConstant(0), effect, control);
768 Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
769
770 Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
771 Node* branch =
772 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
773
774 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
775 Node* etrue = effect;
776
777 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
778 NodeProperties::ReplaceControlInput(node, if_false);
779 NodeProperties::ReplaceEffectInput(node, effect);
780 Node* efalse = if_false = node;
781
782 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
783 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
784
785 // Wire the new diamond into the graph, {node} can still throw.
786 NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
787 NodeProperties::ReplaceControlInput(merge, if_false, 1);
788 NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
789
790 // This iteration cuts out potential {IfSuccess} or {IfException} projection
791 // uses of the original node and places them inside the diamond, so that we
792 // can change the original {node} into the slow-path runtime call.
793 for (Edge edge : merge->use_edges()) {
794 if (!NodeProperties::IsControlEdge(edge)) continue;
795 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
796 NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
797 NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
798 edge.UpdateTo(node);
799 }
800 if (edge.from()->opcode() == IrOpcode::kIfException) {
801 NodeProperties::ReplaceEffectInput(edge.from(), node);
802 edge.UpdateTo(node);
803 }
804 }
805
806 // Turn the stack check into a runtime call.
807 ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
808 }
809
LowerJSDebugger(Node * node)810 void JSGenericLowering::LowerJSDebugger(Node* node) {
811 CallDescriptor::Flags flags = FrameStateFlagForCall(node);
812 Callable callable = CodeFactory::HandleDebuggerStatement(isolate());
813 ReplaceWithStubCall(node, callable, flags);
814 }
815
zone() const816 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
817
818
isolate() const819 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
820
821
graph() const822 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
823
824
common() const825 CommonOperatorBuilder* JSGenericLowering::common() const {
826 return jsgraph()->common();
827 }
828
829
machine() const830 MachineOperatorBuilder* JSGenericLowering::machine() const {
831 return jsgraph()->machine();
832 }
833
834 } // namespace compiler
835 } // namespace internal
836 } // namespace v8
837