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