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