• 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   if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
31   const Runtime::Function* const f =
32       Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
33   switch (f->function_id) {
34     case Runtime::kIsBeingInterpreted:
35       return ReduceIsBeingInterpreted(node);
36     case Runtime::kTurbofanStaticAssert:
37       return ReduceTurbofanStaticAssert(node);
38     case Runtime::kVerifyType:
39       return ReduceVerifyType(node);
40     default:
41       break;
42   }
43   if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
44   switch (f->function_id) {
45     case Runtime::kInlineCopyDataProperties:
46       return ReduceCopyDataProperties(node);
47     case Runtime::kInlineCopyDataPropertiesWithExcludedPropertiesOnStack:
48       return ReduceCopyDataPropertiesWithExcludedPropertiesOnStack(node);
49     case Runtime::kInlineCreateIterResultObject:
50       return ReduceCreateIterResultObject(node);
51     case Runtime::kInlineDeoptimizeNow:
52       return ReduceDeoptimizeNow(node);
53     case Runtime::kInlineGeneratorClose:
54       return ReduceGeneratorClose(node);
55     case Runtime::kInlineCreateJSGeneratorObject:
56       return ReduceCreateJSGeneratorObject(node);
57     case Runtime::kInlineAsyncFunctionAwaitCaught:
58       return ReduceAsyncFunctionAwaitCaught(node);
59     case Runtime::kInlineAsyncFunctionAwaitUncaught:
60       return ReduceAsyncFunctionAwaitUncaught(node);
61     case Runtime::kInlineAsyncFunctionEnter:
62       return ReduceAsyncFunctionEnter(node);
63     case Runtime::kInlineAsyncFunctionReject:
64       return ReduceAsyncFunctionReject(node);
65     case Runtime::kInlineAsyncFunctionResolve:
66       return ReduceAsyncFunctionResolve(node);
67     case Runtime::kInlineAsyncGeneratorAwaitCaught:
68       return ReduceAsyncGeneratorAwaitCaught(node);
69     case Runtime::kInlineAsyncGeneratorAwaitUncaught:
70       return ReduceAsyncGeneratorAwaitUncaught(node);
71     case Runtime::kInlineAsyncGeneratorReject:
72       return ReduceAsyncGeneratorReject(node);
73     case Runtime::kInlineAsyncGeneratorResolve:
74       return ReduceAsyncGeneratorResolve(node);
75     case Runtime::kInlineAsyncGeneratorYield:
76       return ReduceAsyncGeneratorYield(node);
77     case Runtime::kInlineGeneratorGetResumeMode:
78       return ReduceGeneratorGetResumeMode(node);
79     case Runtime::kInlineIncBlockCounter:
80       return ReduceIncBlockCounter(node);
81     case Runtime::kInlineGetImportMetaObject:
82       return ReduceGetImportMetaObject(node);
83     default:
84       break;
85   }
86   return NoChange();
87 }
88 
ReduceCopyDataProperties(Node * node)89 Reduction JSIntrinsicLowering::ReduceCopyDataProperties(Node* node) {
90   return Change(
91       node, Builtins::CallableFor(isolate(), Builtin::kCopyDataProperties), 0);
92 }
93 
94 Reduction
ReduceCopyDataPropertiesWithExcludedPropertiesOnStack(Node * node)95 JSIntrinsicLowering::ReduceCopyDataPropertiesWithExcludedPropertiesOnStack(
96     Node* node) {
97   int input_count =
98       static_cast<int>(CallRuntimeParametersOf(node->op()).arity());
99   CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
100   auto callable = Builtins::CallableFor(
101       isolate(), Builtin::kCopyDataPropertiesWithExcludedProperties);
102   auto call_descriptor = Linkage::GetStubCallDescriptor(
103       graph()->zone(), callable.descriptor(), input_count - 1, flags,
104       node->op()->properties());
105   node->InsertInput(graph()->zone(), 0,
106                     jsgraph()->HeapConstant(callable.code()));
107   node->InsertInput(graph()->zone(), 2,
108                     jsgraph()->SmiConstant(input_count - 1));
109   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
110   return Changed(node);
111 }
112 
ReduceCreateIterResultObject(Node * node)113 Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
114   Node* const value = NodeProperties::GetValueInput(node, 0);
115   Node* const done = NodeProperties::GetValueInput(node, 1);
116   Node* const context = NodeProperties::GetContextInput(node);
117   Node* const effect = NodeProperties::GetEffectInput(node);
118   return Change(node, javascript()->CreateIterResultObject(), value, done,
119                 context, effect);
120 }
121 
ReduceDeoptimizeNow(Node * node)122 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
123   Node* const frame_state = NodeProperties::GetFrameStateInput(node);
124   Node* const effect = NodeProperties::GetEffectInput(node);
125   Node* const control = NodeProperties::GetControlInput(node);
126 
127   // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
128   Node* deoptimize = graph()->NewNode(
129       common()->Deoptimize(DeoptimizeReason::kDeoptimizeNow, FeedbackSource()),
130       frame_state, effect, control);
131   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
132   Revisit(graph()->end());
133 
134   node->TrimInputCount(0);
135   NodeProperties::ChangeOp(node, common()->Dead());
136   return Changed(node);
137 }
138 
ReduceCreateJSGeneratorObject(Node * node)139 Reduction JSIntrinsicLowering::ReduceCreateJSGeneratorObject(Node* node) {
140   Node* const closure = NodeProperties::GetValueInput(node, 0);
141   Node* const receiver = NodeProperties::GetValueInput(node, 1);
142   Node* const context = NodeProperties::GetContextInput(node);
143   Node* const effect = NodeProperties::GetEffectInput(node);
144   Node* const control = NodeProperties::GetControlInput(node);
145   Operator const* const op = javascript()->CreateGeneratorObject();
146   Node* create_generator =
147       graph()->NewNode(op, closure, receiver, context, effect, control);
148   ReplaceWithValue(node, create_generator, create_generator);
149   return Changed(create_generator);
150 }
151 
ReduceGeneratorClose(Node * node)152 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
153   Node* const generator = NodeProperties::GetValueInput(node, 0);
154   Node* const effect = NodeProperties::GetEffectInput(node);
155   Node* const control = NodeProperties::GetControlInput(node);
156   Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
157   Node* const undefined = jsgraph()->UndefinedConstant();
158   Operator const* const op = simplified()->StoreField(
159       AccessBuilder::ForJSGeneratorObjectContinuation());
160 
161   ReplaceWithValue(node, undefined, node);
162   NodeProperties::RemoveType(node);
163   return Change(node, op, generator, closed, effect, control);
164 }
165 
ReduceAsyncFunctionAwaitCaught(Node * node)166 Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitCaught(Node* node) {
167   return Change(
168       node,
169       Builtins::CallableFor(isolate(), Builtin::kAsyncFunctionAwaitCaught), 0);
170 }
171 
ReduceAsyncFunctionAwaitUncaught(Node * node)172 Reduction JSIntrinsicLowering::ReduceAsyncFunctionAwaitUncaught(Node* node) {
173   return Change(
174       node,
175       Builtins::CallableFor(isolate(), Builtin::kAsyncFunctionAwaitUncaught),
176       0);
177 }
178 
ReduceAsyncFunctionEnter(Node * node)179 Reduction JSIntrinsicLowering::ReduceAsyncFunctionEnter(Node* node) {
180   NodeProperties::ChangeOp(node, javascript()->AsyncFunctionEnter());
181   return Changed(node);
182 }
183 
ReduceAsyncFunctionReject(Node * node)184 Reduction JSIntrinsicLowering::ReduceAsyncFunctionReject(Node* node) {
185   RelaxControls(node);
186   NodeProperties::ChangeOp(node, javascript()->AsyncFunctionReject());
187   return Changed(node);
188 }
189 
ReduceAsyncFunctionResolve(Node * node)190 Reduction JSIntrinsicLowering::ReduceAsyncFunctionResolve(Node* node) {
191   RelaxControls(node);
192   NodeProperties::ChangeOp(node, javascript()->AsyncFunctionResolve());
193   return Changed(node);
194 }
195 
ReduceAsyncGeneratorAwaitCaught(Node * node)196 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitCaught(Node* node) {
197   return Change(
198       node,
199       Builtins::CallableFor(isolate(), Builtin::kAsyncGeneratorAwaitCaught), 0);
200 }
201 
ReduceAsyncGeneratorAwaitUncaught(Node * node)202 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorAwaitUncaught(Node* node) {
203   return Change(
204       node,
205       Builtins::CallableFor(isolate(), Builtin::kAsyncGeneratorAwaitUncaught),
206       0);
207 }
208 
ReduceAsyncGeneratorReject(Node * node)209 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
210   return Change(
211       node, Builtins::CallableFor(isolate(), Builtin::kAsyncGeneratorReject),
212       0);
213 }
214 
ReduceAsyncGeneratorResolve(Node * node)215 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
216   return Change(
217       node, Builtins::CallableFor(isolate(), Builtin::kAsyncGeneratorResolve),
218       0);
219 }
220 
ReduceAsyncGeneratorYield(Node * node)221 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
222   return Change(
223       node, Builtins::CallableFor(isolate(), Builtin::kAsyncGeneratorYield), 0);
224 }
225 
ReduceGeneratorGetResumeMode(Node * node)226 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
227   Node* const generator = NodeProperties::GetValueInput(node, 0);
228   Node* const effect = NodeProperties::GetEffectInput(node);
229   Node* const control = NodeProperties::GetControlInput(node);
230   Operator const* const op =
231       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
232 
233   return Change(node, op, generator, effect, control);
234 }
235 
ReduceIsInstanceType(Node * node,InstanceType instance_type)236 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
237     Node* node, InstanceType instance_type) {
238   // if (%_IsSmi(value)) {
239   //   return false;
240   // } else {
241   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
242   // }
243   Node* value = NodeProperties::GetValueInput(node, 0);
244   Node* effect = NodeProperties::GetEffectInput(node);
245   Node* control = NodeProperties::GetControlInput(node);
246 
247   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
248   Node* branch = graph()->NewNode(common()->Branch(), check, control);
249 
250   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
251   Node* etrue = effect;
252   Node* vtrue = jsgraph()->FalseConstant();
253 
254   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
255   Node* efalse = effect;
256   Node* map = efalse =
257       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
258                        efalse, if_false);
259   Node* map_instance_type = efalse = graph()->NewNode(
260       simplified()->LoadField(AccessBuilder::ForMapInstanceType()), map, efalse,
261       if_false);
262   Node* vfalse =
263       graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
264                        jsgraph()->Constant(instance_type));
265 
266   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
267 
268   // Replace all effect uses of {node} with the {ephi}.
269   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
270   ReplaceWithValue(node, node, ephi, merge);
271 
272   // Turn the {node} into a Phi.
273   return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
274                 vfalse, merge);
275 }
276 
ReduceIsJSReceiver(Node * node)277 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
278   return Change(node, simplified()->ObjectIsReceiver());
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 
ReduceVerifyType(Node * node)295 Reduction JSIntrinsicLowering::ReduceVerifyType(Node* node) {
296   return Change(node, simplified()->VerifyType());
297 }
298 
ReduceIsBeingInterpreted(Node * node)299 Reduction JSIntrinsicLowering::ReduceIsBeingInterpreted(Node* node) {
300   RelaxEffectsAndControls(node);
301   return Changed(jsgraph_->FalseConstant());
302 }
303 
Change(Node * node,const Operator * op)304 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
305   // Replace all effect uses of {node} with the effect dependency.
306   RelaxEffectsAndControls(node);
307   // Remove the inputs corresponding to context, effect and control.
308   NodeProperties::RemoveNonValueInputs(node);
309   // Finally update the operator to the new one.
310   NodeProperties::ChangeOp(node, op);
311   return Changed(node);
312 }
313 
ReduceToLength(Node * node)314 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
315   NodeProperties::ChangeOp(node, javascript()->ToLength());
316   return Changed(node);
317 }
318 
ReduceToObject(Node * node)319 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
320   NodeProperties::ChangeOp(node, javascript()->ToObject());
321   return Changed(node);
322 }
323 
ReduceToString(Node * node)324 Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
325   // ToString is unnecessary if the input is a string.
326   HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
327   if (m.HasResolvedValue() && m.Ref(broker()).IsString()) {
328     ReplaceWithValue(node, m.node());
329     return Replace(m.node());
330   }
331   NodeProperties::ChangeOp(node, javascript()->ToString());
332   return Changed(node);
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(), Builtin::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 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c)371 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
372                                       Node* b, Node* c) {
373   RelaxControls(node);
374   node->ReplaceInput(0, a);
375   node->ReplaceInput(1, b);
376   node->ReplaceInput(2, c);
377   node->TrimInputCount(3);
378   NodeProperties::ChangeOp(node, op);
379   return Changed(node);
380 }
381 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c,Node * d)382 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
383                                       Node* b, Node* c, Node* d) {
384   RelaxControls(node);
385   node->ReplaceInput(0, a);
386   node->ReplaceInput(1, b);
387   node->ReplaceInput(2, c);
388   node->ReplaceInput(3, d);
389   node->TrimInputCount(4);
390   NodeProperties::ChangeOp(node, op);
391   return Changed(node);
392 }
393 
Change(Node * node,Callable const & callable,int stack_parameter_count,enum FrameStateFlag frame_state_flag)394 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
395                                       int stack_parameter_count,
396                                       enum FrameStateFlag frame_state_flag) {
397   CallDescriptor::Flags flags = frame_state_flag == kNeedsFrameState
398                                     ? CallDescriptor::kNeedsFrameState
399                                     : CallDescriptor::kNoFlags;
400   auto call_descriptor = Linkage::GetStubCallDescriptor(
401       graph()->zone(), callable.descriptor(), stack_parameter_count, flags,
402       node->op()->properties());
403   node->InsertInput(graph()->zone(), 0,
404                     jsgraph()->HeapConstant(callable.code()));
405   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
406   return Changed(node);
407 }
408 
graph() const409 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
410 
isolate() const411 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
412 
common() const413 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
414   return jsgraph()->common();
415 }
416 
javascript() const417 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
418   return jsgraph_->javascript();
419 }
420 
simplified() const421 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
422   return jsgraph()->simplified();
423 }
424 
425 }  // namespace compiler
426 }  // namespace internal
427 }  // namespace v8
428