V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
js-intrinsic-lowering.cc
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 
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23 
24 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph)
25  : AdvancedReducer(editor), jsgraph_(jsgraph) {}
26 
27 Reduction 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 
86 Reduction 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 
95 Reduction 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 
113 Reduction 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 
126 Reduction 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 
140 Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitCaught(Node* node) {
141  return Change(
142  node,
143  Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitCaught), 0);
144 }
145 
146 Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitUncaught(Node* node) {
147  return Change(
148  node,
149  Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitUncaught),
150  0);
151 }
152 
153 Reduction JSIntrinsicLowering::ReduceAsyncFunctionEnter(Node* node) {
154  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionEnter());
155  return Changed(node);
156 }
157 
158 Reduction JSIntrinsicLowering::ReduceAsyncFunctionReject(Node* node) {
159  RelaxControls(node);
160  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionReject());
161  return Changed(node);
162 }
163 
164 Reduction JSIntrinsicLowering::ReduceAsyncFunctionResolve(Node* node) {
165  RelaxControls(node);
166  NodeProperties::ChangeOp(node, javascript()->AsyncFunctionResolve());
167  return Changed(node);
168 }
169 
170 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitCaught(Node* node) {
171  return Change(
172  node,
173  Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitCaught),
174  0);
175 }
176 
177 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitUncaught(Node* node) {
178  return Change(
179  node,
180  Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorAwaitUncaught),
181  0);
182 }
183 
184 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
185  return Change(
186  node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject),
187  0);
188 }
189 
190 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
191  return Change(
192  node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorResolve),
193  0);
194 }
195 
196 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
197  return Change(
198  node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorYield),
199  0);
200 }
201 
202 Reduction 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 
212 Reduction 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 
254 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
255  return Change(node, simplified()->ObjectIsReceiver());
256 }
257 
258 
259 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
260  return Change(node, simplified()->ObjectIsSmi());
261 }
262 
263 Reduction 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 
274 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
275  NodeProperties::ChangeOp(node, javascript()->ToLength());
276  return Changed(node);
277 }
278 
279 
280 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
281  NodeProperties::ChangeOp(node, javascript()->ToObject());
282  return Changed(node);
283 }
284 
285 
286 Reduction 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 
298 Reduction 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 
304 Reduction 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 
315 Reduction 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 
327 Reduction 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 
340 Reduction 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 
352 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
353 
354 
355 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
356 
357 
358 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
359  return jsgraph()->common();
360 }
361 
362 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
363  return jsgraph_->javascript();
364 }
365 
366 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
367  return jsgraph()->simplified();
368 }
369 
370 } // namespace compiler
371 } // namespace internal
372 } // namespace v8
Definition: libplatform.h:13