1// Copyright 2015 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-intrinsic-lowering.h"
6
7#include <stack>
8
9#include "src/code-factory.h"
10#include "src/compiler/access-builder.h"
11#include "src/compiler/js-graph.h"
12#include "src/compiler/linkage.h"
13#include "src/compiler/node-matchers.h"
14#include "src/compiler/node-properties.h"
15#include "src/compiler/operator-properties.h"
16#include "src/counters.h"
17#include "src/objects-inl.h"
18#include "src/objects/js-generator.h"
19
20namespace v8 {
21namespace internal {
22namespace compiler {
23
24JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph)
25 : AdvancedReducer(editor), jsgraph_(jsgraph) {}
26
27Reduction JSIntrinsicLowering::Reduce(Node* node) {
28 if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
29 const Runtime::Function* const f =
30 Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
31 if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
32 switch (f->function_id) {
33 case Runtime::kInlineCreateIterResultObject:
34 return ReduceCreateIterResultObject(node);
35 case Runtime::kInlineDeoptimizeNow:
36 return ReduceDeoptimizeNow(node);
37 case Runtime::kInlineGeneratorClose:
38 return ReduceGeneratorClose(node);
39 case Runtime::kInlineCreateJSGeneratorObject:
40 return ReduceCreateJSGeneratorObject(node);
41 case Runtime::kInlineAsyncFunctionAwaitCaught:
42 return ReduceAsyncFunctionAwaitCaught(node);
43 case Runtime::kInlineAsyncFunctionAwaitUncaught:
44 return ReduceAsyncFunctionAwaitUncaught(node);
45 case Runtime::kInlineAsyncFunctionEnter:
46 return ReduceAsyncFunctionEnter(node);
47 case Runtime::kInlineAsyncFunctionReject:
48 return ReduceAsyncFunctionReject(node);
49 case Runtime::kInlineAsyncFunctionResolve:
50 return ReduceAsyncFunctionResolve(node);
51 case Runtime::kInlineAsyncGeneratorAwaitCaught:
52 return ReduceAsyncGeneratorAwaitCaught(node);
53 case Runtime::kInlineAsyncGeneratorAwaitUncaught:
54 return ReduceAsyncGeneratorAwaitUncaught(node);
55 case Runtime::kInlineAsyncGeneratorReject:
56 return ReduceAsyncGeneratorReject(node);
57 case Runtime::kInlineAsyncGeneratorResolve:
58 return ReduceAsyncGeneratorResolve(node);
59 case Runtime::kInlineAsyncGeneratorYield:
60 return ReduceAsyncGeneratorYield(node);
61 case Runtime::kInlineGeneratorGetResumeMode:
62 return ReduceGeneratorGetResumeMode(node);
63 case Runtime::kInlineIsArray:
64 return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
65 case Runtime::kInlineIsTypedArray:
66 return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
67 case Runtime::kInlineIsJSReceiver:
68 return ReduceIsJSReceiver(node);
69 case Runtime::kInlineIsSmi:
70 return ReduceIsSmi(node);
71 case Runtime::kInlineToLength:
72 return ReduceToLength(node);
73 case Runtime::kInlineToObject:
74 return ReduceToObject(node);
75 case Runtime::kInlineToString:
76 return ReduceToString(node);
77 case Runtime::kInlineCall:
78 return ReduceCall(node);
79 default:
80 break;
81 }
82 return NoChange();
83}
84
85
86Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
87 Node* const value = NodeProperties::GetValueInput(node, 0);
88 Node* const done = NodeProperties::GetValueInput(node, 1);
89 Node* const context = NodeProperties::GetContextInput(node);
90 Node* const effect = NodeProperties::GetEffectInput(node);
91 return Change(node, javascript()->CreateIterResultObject(), value, done,
92 context, effect);
93}
94
95Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
96 Node* const frame_state = NodeProperties::GetFrameStateInput(node);
97 Node* const effect = NodeProperties::GetEffectInput(node);
98 Node* const control = NodeProperties::GetControlInput(node);
99
100 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
101 Node* deoptimize = graph()->NewNode(
102 common()->Deoptimize(DeoptimizeKind::kEager,
103 DeoptimizeReason::kDeoptimizeNow, VectorSlotPair()),
104 frame_state, effect, control);
105 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
106 Revisit(graph()->end());
107
108 node->TrimInputCount(0);
109 NodeProperties::ChangeOp(node, common()->Dead());
110 return Changed(node);
111}
112
113Reduction JSIntrinsicLowering::ReduceCreateJSGeneratorObject(Node* node) {
114 Node* const closure = NodeProperties::GetValueInput(node, 0);
115 Node* const receiver = NodeProperties::GetValueInput(node, 1);
116 Node* const context = NodeProperties::GetContextInput(node);
117 Node* const effect = NodeProperties::GetEffectInput(node);
118 Node* const control = NodeProperties::GetControlInput(node);
119 Operator const* const op = javascript()->CreateGeneratorObject();
120 Node* create_generator =
121 graph()->NewNode(op, closure, receiver, context, effect, control);
122 ReplaceWithValue(node, create_generator, create_generator);
123 return Changed(create_generator);
124}
125
126Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
127 Node* const generator = NodeProperties::GetValueInput(node, 0);
128 Node* const effect = NodeProperties::GetEffectInput(node);
129 Node* const control = NodeProperties::GetControlInput(node);
130 Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
131 Node* const undefined = jsgraph()->UndefinedConstant();
132 Operator const* const op = simplified()->StoreField(
133 AccessBuilder::ForJSGeneratorObjectContinuation());
134
135 ReplaceWithValue(node, undefined, node);
136 NodeProperties::RemoveType(node);
137 return Change(node, op, generator, closed, effect, control);
138}
139
140Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitCaught(Node* node) {
141 return Change(
142 node,
143 Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitCaught), 0);
144}
145
146Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitUncaught(Node* node) {
147 return Change(
148 node,
149 Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitUncaught),
150 0);
151}
152
153Reduction JSIntrinsicLowering::ReduceAsyncFunctionEnter(Node* node) {
154 NodeProperties::ChangeOp(node, javascript()->AsyncFunctionEnter());
155 return Changed(node);
156}
157
158Reduction JSIntrinsicLowering::ReduceAsyncFunctionReject(Node* node) {
159 RelaxControls(node);
160 NodeProperties::ChangeOp(node, javascript()->AsyncFunctionReject());
161 return Changed(node);
162}
163
164Reduction JSIntrinsicLowering::ReduceAsyncFunctionResolve(Node* node) {
165 RelaxControls(node);
166 NodeProperties::ChangeOp(node, javascript()->AsyncFunctionResolve());
167 return Changed(node);
168}
169
170Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitCaught(Node* node) {
171 return Change(
172 node,
173 Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitCaught),
174 0);
175}
176
177Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitUncaught(Node* node) {
178 return Change(
179 node,
180 Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitUncaught),
181 0);
182}
183
184Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
185 return Change(
186 node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject),
187 0);
188}
189
190Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
191 return Change(
192 node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorResolve),
193 0);
194}
195
196Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
197 return Change(
198 node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorYield),
199 0);
200}
201
202Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
203 Node* const generator = NodeProperties::GetValueInput(node, 0);
204 Node* const effect = NodeProperties::GetEffectInput(node);
205 Node* const control = NodeProperties::GetControlInput(node);
206 Operator const* const op =
207 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
208
209 return Change(node, op, generator, effect, control);
210}
211
212Reduction JSIntrinsicLowering::ReduceIsInstanceType(
213 Node* node, InstanceType instance_type) {
214 // if (%_IsSmi(value)) {
215 // return false;
216 // } else {
217 // return %_GetInstanceType(%_GetMap(value)) == instance_type;
218 // }
219 Node* value = NodeProperties::GetValueInput(node, 0);
220 Node* effect = NodeProperties::GetEffectInput(node);
221 Node* control = NodeProperties::GetControlInput(node);
222
223 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
224 Node* branch = graph()->NewNode(common()->Branch(), check, control);
225
226 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
227 Node* etrue = effect;
228 Node* vtrue = jsgraph()->FalseConstant();
229
230 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
231 Node* efalse = effect;
232 Node* map = efalse =
233 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
234 efalse, if_false);
235 Node* map_instance_type = efalse = graph()->NewNode(
236 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), map, efalse,
237 if_false);
238 Node* vfalse =
239 graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
240 jsgraph()->Constant(instance_type));
241
242 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
243
244 // Replace all effect uses of {node} with the {ephi}.
245 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
246 ReplaceWithValue(node, node, ephi, merge);
247
248 // Turn the {node} into a Phi.
249 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
250 vfalse, merge);
251}
252
253
254Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
255 return Change(node, simplified()->ObjectIsReceiver());
256}
257
258
259Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
260 return Change(node, simplified()->ObjectIsSmi());
261}
262
263Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
264 // Replace all effect uses of {node} with the effect dependency.
265 RelaxEffectsAndControls(node);
266 // Remove the inputs corresponding to context, effect and control.
267 NodeProperties::RemoveNonValueInputs(node);
268 // Finally update the operator to the new one.
269 NodeProperties::ChangeOp(node, op);
270 return Changed(node);
271}
272
273
274Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
275 NodeProperties::ChangeOp(node, javascript()->ToLength());
276 return Changed(node);
277}
278
279
280Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
281 NodeProperties::ChangeOp(node, javascript()->ToObject());
282 return Changed(node);
283}
284
285
286Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
287 // ToString is unnecessary if the input is a string.
288 HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
289 if (m.HasValue() && m.Value()->IsString()) {
290 ReplaceWithValue(node, m.node());
291 return Replace(m.node());
292 }
293 NodeProperties::ChangeOp(node, javascript()->ToString());
294 return Changed(node);
295}
296
297
298Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
299 size_t const arity = CallRuntimeParametersOf(node->op()).arity();
300 NodeProperties::ChangeOp(node, javascript()->Call(arity));
301 return Changed(node);
302}
303
304Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
305 Node* b) {
306 RelaxControls(node);
307 node->ReplaceInput(0, a);
308 node->ReplaceInput(1, b);
309 node->TrimInputCount(2);
310 NodeProperties::ChangeOp(node, op);
311 return Changed(node);
312}
313
314
315Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
316 Node* b, Node* c) {
317 RelaxControls(node);
318 node->ReplaceInput(0, a);
319 node->ReplaceInput(1, b);
320 node->ReplaceInput(2, c);
321 node->TrimInputCount(3);
322 NodeProperties::ChangeOp(node, op);
323 return Changed(node);
324}
325
326
327Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
328 Node* b, Node* c, Node* d) {
329 RelaxControls(node);
330 node->ReplaceInput(0, a);
331 node->ReplaceInput(1, b);
332 node->ReplaceInput(2, c);
333 node->ReplaceInput(3, d);
334 node->TrimInputCount(4);
335 NodeProperties::ChangeOp(node, op);
336 return Changed(node);
337}
338
339
340Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
341 int stack_parameter_count) {
342 auto call_descriptor = Linkage::GetStubCallDescriptor(
343 graph()->zone(), callable.descriptor(), stack_parameter_count,
344 CallDescriptor::kNeedsFrameState, node->op()->properties());
345 node->InsertInput(graph()->zone(), 0,
346 jsgraph()->HeapConstant(callable.code()));
347 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
348 return Changed(node);
349}
350
351
352Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
353
354
355Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
356
357
358CommonOperatorBuilder* JSIntrinsicLowering::common() const {
359 return jsgraph()->common();
360}
361
362JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
363 return jsgraph_->javascript();
364}
365
366SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
367 return jsgraph()->simplified();
368}
369
370} // namespace compiler
371} // namespace internal
372} // namespace v8
373