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 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
JSIntrinsicLowering(Editor * editor,JSGraph * jsgraph,DeoptimizationMode mode)23 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
24                                          DeoptimizationMode mode)
25     : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {}
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::kInlineDeoptimizeNow:
36       return ReduceDeoptimizeNow(node);
37     case Runtime::kInlineGeneratorClose:
38       return ReduceGeneratorClose(node);
39     case Runtime::kInlineGeneratorGetInputOrDebugPos:
40       return ReduceGeneratorGetInputOrDebugPos(node);
41     case Runtime::kInlineGeneratorGetResumeMode:
42       return ReduceGeneratorGetResumeMode(node);
43     case Runtime::kInlineIsArray:
44       return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
45     case Runtime::kInlineIsTypedArray:
46       return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
47     case Runtime::kInlineIsRegExp:
48       return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
49     case Runtime::kInlineIsJSReceiver:
50       return ReduceIsJSReceiver(node);
51     case Runtime::kInlineIsSmi:
52       return ReduceIsSmi(node);
53     case Runtime::kInlineFixedArrayGet:
54       return ReduceFixedArrayGet(node);
55     case Runtime::kInlineFixedArraySet:
56       return ReduceFixedArraySet(node);
57     case Runtime::kInlineRegExpExec:
58       return ReduceRegExpExec(node);
59     case Runtime::kInlineSubString:
60       return ReduceSubString(node);
61     case Runtime::kInlineToInteger:
62       return ReduceToInteger(node);
63     case Runtime::kInlineToLength:
64       return ReduceToLength(node);
65     case Runtime::kInlineToNumber:
66       return ReduceToNumber(node);
67     case Runtime::kInlineToObject:
68       return ReduceToObject(node);
69     case Runtime::kInlineToString:
70       return ReduceToString(node);
71     case Runtime::kInlineCall:
72       return ReduceCall(node);
73     case Runtime::kInlineNewObject:
74       return ReduceNewObject(node);
75     case Runtime::kInlineGetSuperConstructor:
76       return ReduceGetSuperConstructor(node);
77     default:
78       break;
79   }
80   return NoChange();
81 }
82 
83 
ReduceCreateIterResultObject(Node * node)84 Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
85   Node* const value = NodeProperties::GetValueInput(node, 0);
86   Node* const done = NodeProperties::GetValueInput(node, 1);
87   Node* const context = NodeProperties::GetContextInput(node);
88   Node* const effect = NodeProperties::GetEffectInput(node);
89   return Change(node, javascript()->CreateIterResultObject(), value, done,
90                 context, effect);
91 }
92 
93 
ReduceDeoptimizeNow(Node * node)94 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
95   if (mode() != kDeoptimizationEnabled) return NoChange();
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, DeoptimizeReason::kNoReason),
103       frame_state, effect, control);
104   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
105   Revisit(graph()->end());
106 
107   node->TrimInputCount(0);
108   NodeProperties::ChangeOp(node, common()->Dead());
109   return Changed(node);
110 }
111 
ReduceGeneratorClose(Node * node)112 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
113   Node* const generator = NodeProperties::GetValueInput(node, 0);
114   Node* const effect = NodeProperties::GetEffectInput(node);
115   Node* const control = NodeProperties::GetControlInput(node);
116   Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
117   Node* const undefined = jsgraph()->UndefinedConstant();
118   Operator const* const op = simplified()->StoreField(
119       AccessBuilder::ForJSGeneratorObjectContinuation());
120 
121   ReplaceWithValue(node, undefined, node);
122   NodeProperties::RemoveType(node);
123   return Change(node, op, generator, closed, effect, control);
124 }
125 
ReduceGeneratorGetInputOrDebugPos(Node * node)126 Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(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   Operator const* const op = simplified()->LoadField(
131       AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
132 
133   return Change(node, op, generator, effect, control);
134 }
135 
ReduceGeneratorGetResumeMode(Node * node)136 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(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   Operator const* const op =
141       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
142 
143   return Change(node, op, generator, effect, control);
144 }
145 
ReduceIsInstanceType(Node * node,InstanceType instance_type)146 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
147     Node* node, InstanceType instance_type) {
148   // if (%_IsSmi(value)) {
149   //   return false;
150   // } else {
151   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
152   // }
153   Node* value = NodeProperties::GetValueInput(node, 0);
154   Node* effect = NodeProperties::GetEffectInput(node);
155   Node* control = NodeProperties::GetControlInput(node);
156 
157   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
158   Node* branch = graph()->NewNode(common()->Branch(), check, control);
159 
160   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
161   Node* etrue = effect;
162   Node* vtrue = jsgraph()->FalseConstant();
163 
164   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
165   Node* efalse = graph()->NewNode(
166       simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
167       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
168                        effect, if_false),
169       effect, if_false);
170   Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse,
171                                   jsgraph()->Constant(instance_type));
172 
173   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
174 
175   // Replace all effect uses of {node} with the {ephi}.
176   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
177   ReplaceWithValue(node, node, ephi);
178 
179   // Turn the {node} into a Phi.
180   return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
181                 vfalse, merge);
182 }
183 
184 
ReduceIsJSReceiver(Node * node)185 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
186   return Change(node, simplified()->ObjectIsReceiver());
187 }
188 
189 
ReduceIsSmi(Node * node)190 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
191   return Change(node, simplified()->ObjectIsSmi());
192 }
193 
194 
Change(Node * node,const Operator * op)195 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
196   // Replace all effect uses of {node} with the effect dependency.
197   RelaxEffectsAndControls(node);
198   // Remove the inputs corresponding to context, effect and control.
199   NodeProperties::RemoveNonValueInputs(node);
200   // Finally update the operator to the new one.
201   NodeProperties::ChangeOp(node, op);
202   return Changed(node);
203 }
204 
205 
ReduceFixedArrayGet(Node * node)206 Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
207   Node* base = node->InputAt(0);
208   Node* index = node->InputAt(1);
209   Node* effect = NodeProperties::GetEffectInput(node);
210   Node* control = NodeProperties::GetControlInput(node);
211   return Change(
212       node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
213       base, index, effect, control);
214 }
215 
216 
ReduceFixedArraySet(Node * node)217 Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
218   Node* base = node->InputAt(0);
219   Node* index = node->InputAt(1);
220   Node* value = node->InputAt(2);
221   Node* effect = NodeProperties::GetEffectInput(node);
222   Node* control = NodeProperties::GetControlInput(node);
223   Node* store = (graph()->NewNode(
224       simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
225       index, value, effect, control));
226   ReplaceWithValue(node, value, store);
227   return Changed(store);
228 }
229 
230 
ReduceRegExpExec(Node * node)231 Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) {
232   return Change(node, CodeFactory::RegExpExec(isolate()), 4);
233 }
234 
235 
ReduceSubString(Node * node)236 Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
237   return Change(node, CodeFactory::SubString(isolate()), 3);
238 }
239 
240 
ReduceToInteger(Node * node)241 Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
242   NodeProperties::ChangeOp(node, javascript()->ToInteger());
243   return Changed(node);
244 }
245 
246 
ReduceToNumber(Node * node)247 Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
248   NodeProperties::ChangeOp(node, javascript()->ToNumber());
249   return Changed(node);
250 }
251 
252 
ReduceToLength(Node * node)253 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
254   NodeProperties::ChangeOp(node, javascript()->ToLength());
255   return Changed(node);
256 }
257 
258 
ReduceToObject(Node * node)259 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
260   NodeProperties::ChangeOp(node, javascript()->ToObject());
261   return Changed(node);
262 }
263 
264 
ReduceToString(Node * node)265 Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
266   NodeProperties::ChangeOp(node, javascript()->ToString());
267   return Changed(node);
268 }
269 
270 
ReduceCall(Node * node)271 Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
272   size_t const arity = CallRuntimeParametersOf(node->op()).arity();
273   NodeProperties::ChangeOp(
274       node, javascript()->CallFunction(arity, 0.0f, VectorSlotPair(),
275                                        ConvertReceiverMode::kAny,
276                                        TailCallMode::kDisallow));
277   return Changed(node);
278 }
279 
ReduceNewObject(Node * node)280 Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) {
281   return Change(node, CodeFactory::FastNewObject(isolate()), 0);
282 }
283 
ReduceGetSuperConstructor(Node * node)284 Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
285   Node* active_function = NodeProperties::GetValueInput(node, 0);
286   Node* effect = NodeProperties::GetEffectInput(node);
287   Node* control = NodeProperties::GetControlInput(node);
288   Node* active_function_map = effect =
289       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
290                        active_function, effect, control);
291   return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
292                 active_function_map, effect, control);
293 }
294 
Change(Node * node,const Operator * op,Node * a,Node * b)295 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
296                                       Node* b) {
297   RelaxControls(node);
298   node->ReplaceInput(0, a);
299   node->ReplaceInput(1, b);
300   node->TrimInputCount(2);
301   NodeProperties::ChangeOp(node, op);
302   return Changed(node);
303 }
304 
305 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c)306 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
307                                       Node* b, Node* c) {
308   RelaxControls(node);
309   node->ReplaceInput(0, a);
310   node->ReplaceInput(1, b);
311   node->ReplaceInput(2, c);
312   node->TrimInputCount(3);
313   NodeProperties::ChangeOp(node, op);
314   return Changed(node);
315 }
316 
317 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c,Node * d)318 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
319                                       Node* b, Node* c, Node* d) {
320   RelaxControls(node);
321   node->ReplaceInput(0, a);
322   node->ReplaceInput(1, b);
323   node->ReplaceInput(2, c);
324   node->ReplaceInput(3, d);
325   node->TrimInputCount(4);
326   NodeProperties::ChangeOp(node, op);
327   return Changed(node);
328 }
329 
330 
Change(Node * node,Callable const & callable,int stack_parameter_count)331 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
332                                       int stack_parameter_count) {
333   CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
334       isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
335       CallDescriptor::kNeedsFrameState, node->op()->properties());
336   node->InsertInput(graph()->zone(), 0,
337                     jsgraph()->HeapConstant(callable.code()));
338   NodeProperties::ChangeOp(node, common()->Call(desc));
339   return Changed(node);
340 }
341 
342 
graph() const343 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
344 
345 
isolate() const346 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
347 
348 
common() const349 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
350   return jsgraph()->common();
351 }
352 
javascript() const353 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
354   return jsgraph_->javascript();
355 }
356 
simplified() const357 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
358   return jsgraph()->simplified();
359 }
360 
361 }  // namespace compiler
362 }  // namespace internal
363 }  // namespace v8
364