• 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/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 
JSIntrinsicLowering(Editor * editor,JSGraph * jsgraph)24 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph)
25     : AdvancedReducer(editor), jsgraph_(jsgraph) {}
26 
Reduce(Node * node)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::kInlineDebugIsActive:
36       return ReduceDebugIsActive(node);
37     case Runtime::kInlineDeoptimizeNow:
38       return ReduceDeoptimizeNow(node);
39     case Runtime::kInlineGeneratorClose:
40       return ReduceGeneratorClose(node);
41     case Runtime::kInlineCreateJSGeneratorObject:
42       return ReduceCreateJSGeneratorObject(node);
43     case Runtime::kInlineGeneratorGetInputOrDebugPos:
44       return ReduceGeneratorGetInputOrDebugPos(node);
45     case Runtime::kInlineAsyncGeneratorReject:
46       return ReduceAsyncGeneratorReject(node);
47     case Runtime::kInlineAsyncGeneratorResolve:
48       return ReduceAsyncGeneratorResolve(node);
49     case Runtime::kInlineAsyncGeneratorYield:
50       return ReduceAsyncGeneratorYield(node);
51     case Runtime::kInlineGeneratorGetResumeMode:
52       return ReduceGeneratorGetResumeMode(node);
53     case Runtime::kInlineIsArray:
54       return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
55     case Runtime::kInlineIsTypedArray:
56       return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
57     case Runtime::kInlineIsJSProxy:
58       return ReduceIsInstanceType(node, JS_PROXY_TYPE);
59     case Runtime::kInlineIsJSReceiver:
60       return ReduceIsJSReceiver(node);
61     case Runtime::kInlineIsSmi:
62       return ReduceIsSmi(node);
63     case Runtime::kInlineRejectPromise:
64       return ReduceRejectPromise(node);
65     case Runtime::kInlineResolvePromise:
66       return ReduceResolvePromise(node);
67     case Runtime::kInlineToInteger:
68       return ReduceToInteger(node);
69     case Runtime::kInlineToLength:
70       return ReduceToLength(node);
71     case Runtime::kInlineToNumber:
72       return ReduceToNumber(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 
ReduceCreateIterResultObject(Node * node)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 
ReduceDebugIsActive(Node * node)95 Reduction JSIntrinsicLowering::ReduceDebugIsActive(Node* node) {
96   Node* const value = jsgraph()->ExternalConstant(
97       ExternalReference::debug_is_active_address(isolate()));
98   Node* const effect = NodeProperties::GetEffectInput(node);
99   Node* const control = NodeProperties::GetControlInput(node);
100   Operator const* const op =
101       simplified()->LoadField(AccessBuilder::ForExternalUint8Value());
102   return Change(node, op, value, effect, control);
103 }
104 
ReduceDeoptimizeNow(Node * node)105 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
106   Node* const frame_state = NodeProperties::GetFrameStateInput(node);
107   Node* const effect = NodeProperties::GetEffectInput(node);
108   Node* const control = NodeProperties::GetControlInput(node);
109 
110   // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
111   Node* deoptimize = graph()->NewNode(
112       common()->Deoptimize(DeoptimizeKind::kEager,
113                            DeoptimizeReason::kDeoptimizeNow, VectorSlotPair()),
114       frame_state, effect, control);
115   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
116   Revisit(graph()->end());
117 
118   node->TrimInputCount(0);
119   NodeProperties::ChangeOp(node, common()->Dead());
120   return Changed(node);
121 }
122 
ReduceCreateJSGeneratorObject(Node * node)123 Reduction JSIntrinsicLowering::ReduceCreateJSGeneratorObject(Node* node) {
124   Node* const closure = NodeProperties::GetValueInput(node, 0);
125   Node* const receiver = NodeProperties::GetValueInput(node, 1);
126   Node* const context = NodeProperties::GetContextInput(node);
127   Node* const effect = NodeProperties::GetEffectInput(node);
128   Node* const control = NodeProperties::GetControlInput(node);
129   Operator const* const op = javascript()->CreateGeneratorObject();
130   Node* create_generator =
131       graph()->NewNode(op, closure, receiver, context, effect, control);
132   ReplaceWithValue(node, create_generator, create_generator);
133   return Changed(create_generator);
134 }
135 
ReduceGeneratorClose(Node * node)136 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
137   Node* const generator = NodeProperties::GetValueInput(node, 0);
138   Node* const effect = NodeProperties::GetEffectInput(node);
139   Node* const control = NodeProperties::GetControlInput(node);
140   Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
141   Node* const undefined = jsgraph()->UndefinedConstant();
142   Operator const* const op = simplified()->StoreField(
143       AccessBuilder::ForJSGeneratorObjectContinuation());
144 
145   ReplaceWithValue(node, undefined, node);
146   NodeProperties::RemoveType(node);
147   return Change(node, op, generator, closed, effect, control);
148 }
149 
ReduceGeneratorGetInputOrDebugPos(Node * node)150 Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
151   Node* const generator = NodeProperties::GetValueInput(node, 0);
152   Node* const effect = NodeProperties::GetEffectInput(node);
153   Node* const control = NodeProperties::GetControlInput(node);
154   Operator const* const op = simplified()->LoadField(
155       AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
156 
157   return Change(node, op, generator, effect, control);
158 }
159 
ReduceAsyncGeneratorReject(Node * node)160 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
161   return Change(
162       node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject),
163       0);
164 }
165 
ReduceAsyncGeneratorResolve(Node * node)166 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
167   return Change(
168       node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorResolve),
169       0);
170 }
171 
ReduceAsyncGeneratorYield(Node * node)172 Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
173   return Change(
174       node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorYield),
175       0);
176 }
177 
ReduceGeneratorGetResumeMode(Node * node)178 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
179   Node* const generator = NodeProperties::GetValueInput(node, 0);
180   Node* const effect = NodeProperties::GetEffectInput(node);
181   Node* const control = NodeProperties::GetControlInput(node);
182   Operator const* const op =
183       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
184 
185   return Change(node, op, generator, effect, control);
186 }
187 
ReduceIsInstanceType(Node * node,InstanceType instance_type)188 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
189     Node* node, InstanceType instance_type) {
190   // if (%_IsSmi(value)) {
191   //   return false;
192   // } else {
193   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
194   // }
195   Node* value = NodeProperties::GetValueInput(node, 0);
196   Node* effect = NodeProperties::GetEffectInput(node);
197   Node* control = NodeProperties::GetControlInput(node);
198 
199   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
200   Node* branch = graph()->NewNode(common()->Branch(), check, control);
201 
202   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
203   Node* etrue = effect;
204   Node* vtrue = jsgraph()->FalseConstant();
205 
206   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
207   Node* efalse = effect;
208   Node* map = efalse =
209       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
210                        efalse, if_false);
211   Node* map_instance_type = efalse = graph()->NewNode(
212       simplified()->LoadField(AccessBuilder::ForMapInstanceType()), map, efalse,
213       if_false);
214   Node* vfalse =
215       graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
216                        jsgraph()->Constant(instance_type));
217 
218   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
219 
220   // Replace all effect uses of {node} with the {ephi}.
221   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
222   ReplaceWithValue(node, node, ephi, merge);
223 
224   // Turn the {node} into a Phi.
225   return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
226                 vfalse, merge);
227 }
228 
229 
ReduceIsJSReceiver(Node * node)230 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
231   return Change(node, simplified()->ObjectIsReceiver());
232 }
233 
234 
ReduceIsSmi(Node * node)235 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
236   return Change(node, simplified()->ObjectIsSmi());
237 }
238 
ReduceRejectPromise(Node * node)239 Reduction JSIntrinsicLowering::ReduceRejectPromise(Node* node) {
240   RelaxControls(node);
241   NodeProperties::ChangeOp(node, javascript()->RejectPromise());
242   return Changed(node);
243 }
244 
ReduceResolvePromise(Node * node)245 Reduction JSIntrinsicLowering::ReduceResolvePromise(Node* node) {
246   RelaxControls(node);
247   NodeProperties::ChangeOp(node, javascript()->ResolvePromise());
248   return Changed(node);
249 }
250 
Change(Node * node,const Operator * op)251 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
252   // Replace all effect uses of {node} with the effect dependency.
253   RelaxEffectsAndControls(node);
254   // Remove the inputs corresponding to context, effect and control.
255   NodeProperties::RemoveNonValueInputs(node);
256   // Finally update the operator to the new one.
257   NodeProperties::ChangeOp(node, op);
258   return Changed(node);
259 }
260 
ReduceToInteger(Node * node)261 Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
262   NodeProperties::ChangeOp(node, javascript()->ToInteger());
263   return Changed(node);
264 }
265 
266 
ReduceToNumber(Node * node)267 Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
268   NodeProperties::ChangeOp(node, javascript()->ToNumber());
269   return Changed(node);
270 }
271 
272 
ReduceToLength(Node * node)273 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
274   NodeProperties::ChangeOp(node, javascript()->ToLength());
275   return Changed(node);
276 }
277 
278 
ReduceToObject(Node * node)279 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
280   NodeProperties::ChangeOp(node, javascript()->ToObject());
281   return Changed(node);
282 }
283 
284 
ReduceToString(Node * node)285 Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
286   // ToString is unnecessary if the input is a string.
287   HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
288   if (m.HasValue() && m.Value()->IsString()) {
289     ReplaceWithValue(node, m.node());
290     return Replace(m.node());
291   }
292   NodeProperties::ChangeOp(node, javascript()->ToString());
293   return Changed(node);
294 }
295 
296 
ReduceCall(Node * node)297 Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
298   size_t const arity = CallRuntimeParametersOf(node->op()).arity();
299   NodeProperties::ChangeOp(node, javascript()->Call(arity));
300   return Changed(node);
301 }
302 
ReduceGetSuperConstructor(Node * node)303 Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
304   NodeProperties::ChangeOp(node, javascript()->GetSuperConstructor());
305   return Changed(node);
306 }
307 
Change(Node * node,const Operator * op,Node * a,Node * b)308 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
309                                       Node* b) {
310   RelaxControls(node);
311   node->ReplaceInput(0, a);
312   node->ReplaceInput(1, b);
313   node->TrimInputCount(2);
314   NodeProperties::ChangeOp(node, op);
315   return Changed(node);
316 }
317 
318 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c)319 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
320                                       Node* b, Node* c) {
321   RelaxControls(node);
322   node->ReplaceInput(0, a);
323   node->ReplaceInput(1, b);
324   node->ReplaceInput(2, c);
325   node->TrimInputCount(3);
326   NodeProperties::ChangeOp(node, op);
327   return Changed(node);
328 }
329 
330 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c,Node * d)331 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
332                                       Node* b, Node* c, Node* d) {
333   RelaxControls(node);
334   node->ReplaceInput(0, a);
335   node->ReplaceInput(1, b);
336   node->ReplaceInput(2, c);
337   node->ReplaceInput(3, d);
338   node->TrimInputCount(4);
339   NodeProperties::ChangeOp(node, op);
340   return Changed(node);
341 }
342 
343 
Change(Node * node,Callable const & callable,int stack_parameter_count)344 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
345                                       int stack_parameter_count) {
346   auto call_descriptor = Linkage::GetStubCallDescriptor(
347       graph()->zone(), callable.descriptor(), stack_parameter_count,
348       CallDescriptor::kNeedsFrameState, node->op()->properties());
349   node->InsertInput(graph()->zone(), 0,
350                     jsgraph()->HeapConstant(callable.code()));
351   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
352   return Changed(node);
353 }
354 
355 
graph() const356 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
357 
358 
isolate() const359 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
360 
361 
common() const362 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
363   return jsgraph()->common();
364 }
365 
javascript() const366 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
367   return jsgraph_->javascript();
368 }
369 
simplified() const370 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
371   return jsgraph()->simplified();
372 }
373 
374 }  // namespace compiler
375 }  // namespace internal
376 }  // namespace v8
377