Line data Source code
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 :
23 443387 : JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph)
24 443387 : : AdvancedReducer(editor), jsgraph_(jsgraph) {}
25 :
26 30788608 : Reduction JSIntrinsicLowering::Reduce(Node* node) {
27 30788608 : if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
28 : const Runtime::Function* const f =
29 327901 : Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
30 327901 : if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
31 50832 : switch (f->function_id) {
32 : case Runtime::kInlineCreateIterResultObject:
33 1982 : return ReduceCreateIterResultObject(node);
34 : case Runtime::kInlineDebugIsActive:
35 0 : return ReduceDebugIsActive(node);
36 : case Runtime::kInlineDeoptimizeNow:
37 9110 : return ReduceDeoptimizeNow(node);
38 : case Runtime::kInlineGeneratorClose:
39 145 : return ReduceGeneratorClose(node);
40 : case Runtime::kInlineCreateJSGeneratorObject:
41 1587 : return ReduceCreateJSGeneratorObject(node);
42 : case Runtime::kInlineGeneratorGetInputOrDebugPos:
43 5145 : return ReduceGeneratorGetInputOrDebugPos(node);
44 : case Runtime::kInlineAsyncGeneratorReject:
45 145 : return ReduceAsyncGeneratorReject(node);
46 : case Runtime::kInlineAsyncGeneratorResolve:
47 145 : return ReduceAsyncGeneratorResolve(node);
48 : case Runtime::kInlineAsyncGeneratorYield:
49 51 : return ReduceAsyncGeneratorYield(node);
50 : case Runtime::kInlineGeneratorGetResumeMode:
51 5138 : return ReduceGeneratorGetResumeMode(node);
52 : case Runtime::kInlineGeneratorGetContext:
53 1586 : return ReduceGeneratorGetContext(node);
54 : case Runtime::kInlineIsArray:
55 1047 : return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
56 : case Runtime::kInlineIsTypedArray:
57 160 : return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
58 : case Runtime::kInlineIsJSProxy:
59 14 : return ReduceIsInstanceType(node, JS_PROXY_TYPE);
60 : case Runtime::kInlineIsJSMap:
61 114 : return ReduceIsInstanceType(node, JS_MAP_TYPE);
62 : case Runtime::kInlineIsJSSet:
63 114 : return ReduceIsInstanceType(node, JS_SET_TYPE);
64 : case Runtime::kInlineIsJSWeakMap:
65 133 : return ReduceIsInstanceType(node, JS_WEAK_MAP_TYPE);
66 : case Runtime::kInlineIsJSWeakSet:
67 124 : return ReduceIsInstanceType(node, JS_WEAK_SET_TYPE);
68 : case Runtime::kInlineIsJSReceiver:
69 7965 : return ReduceIsJSReceiver(node);
70 : case Runtime::kInlineIsSmi:
71 699 : return ReduceIsSmi(node);
72 : case Runtime::kInlineToInteger:
73 175 : return ReduceToInteger(node);
74 : case Runtime::kInlineToLength:
75 867 : return ReduceToLength(node);
76 : case Runtime::kInlineToNumber:
77 149 : return ReduceToNumber(node);
78 : case Runtime::kInlineToObject:
79 1015 : return ReduceToObject(node);
80 : case Runtime::kInlineToString:
81 3239 : return ReduceToString(node);
82 : case Runtime::kInlineCall:
83 8597 : return ReduceCall(node);
84 : case Runtime::kInlineGetSuperConstructor:
85 10 : return ReduceGetSuperConstructor(node);
86 : case Runtime::kInlineArrayBufferViewGetByteLength:
87 : return ReduceArrayBufferViewField(
88 40 : node, AccessBuilder::ForJSArrayBufferViewByteLength());
89 : case Runtime::kInlineArrayBufferViewGetByteOffset:
90 : return ReduceArrayBufferViewField(
91 44 : node, AccessBuilder::ForJSArrayBufferViewByteOffset());
92 : case Runtime::kInlineArrayBufferViewWasNeutered:
93 24 : return ReduceArrayBufferViewWasNeutered(node);
94 : case Runtime::kInlineMaxSmi:
95 8 : return ReduceMaxSmi(node);
96 : case Runtime::kInlineTypedArrayGetLength:
97 : return ReduceArrayBufferViewField(node,
98 161 : AccessBuilder::ForJSTypedArrayLength());
99 : case Runtime::kInlineTheHole:
100 0 : return ReduceTheHole(node);
101 : case Runtime::kInlineClassOf:
102 962 : return ReduceClassOf(node);
103 : case Runtime::kInlineStringMaxLength:
104 0 : return ReduceStringMaxLength(node);
105 : default:
106 : break;
107 : }
108 : return NoChange();
109 : }
110 :
111 :
112 1982 : Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
113 1982 : Node* const value = NodeProperties::GetValueInput(node, 0);
114 1982 : Node* const done = NodeProperties::GetValueInput(node, 1);
115 1982 : Node* const context = NodeProperties::GetContextInput(node);
116 1982 : Node* const effect = NodeProperties::GetEffectInput(node);
117 : return Change(node, javascript()->CreateIterResultObject(), value, done,
118 1982 : context, effect);
119 : }
120 :
121 0 : Reduction JSIntrinsicLowering::ReduceDebugIsActive(Node* node) {
122 : Node* const value = jsgraph()->ExternalConstant(
123 0 : ExternalReference::debug_is_active_address(isolate()));
124 0 : Node* const effect = NodeProperties::GetEffectInput(node);
125 0 : Node* const control = NodeProperties::GetControlInput(node);
126 : Operator const* const op =
127 0 : simplified()->LoadField(AccessBuilder::ForExternalUint8Value());
128 0 : return Change(node, op, value, effect, control);
129 : }
130 :
131 9110 : Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
132 9110 : Node* const frame_state = NodeProperties::GetFrameStateInput(node);
133 9110 : Node* const effect = NodeProperties::GetEffectInput(node);
134 9110 : Node* const control = NodeProperties::GetControlInput(node);
135 :
136 : // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
137 : Node* deoptimize = graph()->NewNode(
138 : common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason),
139 9110 : frame_state, effect, control);
140 9110 : NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
141 9110 : Revisit(graph()->end());
142 :
143 9110 : node->TrimInputCount(0);
144 9110 : NodeProperties::ChangeOp(node, common()->Dead());
145 9110 : return Changed(node);
146 : }
147 :
148 1587 : Reduction JSIntrinsicLowering::ReduceCreateJSGeneratorObject(Node* node) {
149 1587 : Node* const closure = NodeProperties::GetValueInput(node, 0);
150 1587 : Node* const receiver = NodeProperties::GetValueInput(node, 1);
151 1587 : Node* const context = NodeProperties::GetContextInput(node);
152 1587 : Node* const effect = NodeProperties::GetEffectInput(node);
153 1587 : Node* const control = NodeProperties::GetControlInput(node);
154 1587 : Operator const* const op = javascript()->CreateGeneratorObject();
155 : Node* create_generator =
156 : graph()->NewNode(op, closure, receiver, context, effect, control);
157 1587 : ReplaceWithValue(node, create_generator, create_generator);
158 1587 : return Changed(create_generator);
159 : }
160 :
161 435 : Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
162 145 : Node* const generator = NodeProperties::GetValueInput(node, 0);
163 145 : Node* const effect = NodeProperties::GetEffectInput(node);
164 145 : Node* const control = NodeProperties::GetControlInput(node);
165 145 : Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
166 145 : Node* const undefined = jsgraph()->UndefinedConstant();
167 : Operator const* const op = simplified()->StoreField(
168 290 : AccessBuilder::ForJSGeneratorObjectContinuation());
169 :
170 145 : ReplaceWithValue(node, undefined, node);
171 : NodeProperties::RemoveType(node);
172 145 : return Change(node, op, generator, closed, effect, control);
173 : }
174 :
175 5145 : Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
176 5145 : Node* const generator = NodeProperties::GetValueInput(node, 0);
177 5145 : Node* const effect = NodeProperties::GetEffectInput(node);
178 5145 : Node* const control = NodeProperties::GetControlInput(node);
179 : Operator const* const op = simplified()->LoadField(
180 10290 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
181 :
182 5145 : return Change(node, op, generator, effect, control);
183 : }
184 :
185 145 : Reduction JSIntrinsicLowering::ReduceAsyncGeneratorReject(Node* node) {
186 : return Change(
187 : node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorReject),
188 145 : 0);
189 : }
190 :
191 145 : Reduction JSIntrinsicLowering::ReduceAsyncGeneratorResolve(Node* node) {
192 : return Change(
193 : node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorResolve),
194 145 : 0);
195 : }
196 :
197 51 : Reduction JSIntrinsicLowering::ReduceAsyncGeneratorYield(Node* node) {
198 : return Change(
199 : node, Builtins::CallableFor(isolate(), Builtins::kAsyncGeneratorYield),
200 51 : 0);
201 : }
202 :
203 1586 : Reduction JSIntrinsicLowering::ReduceGeneratorGetContext(Node* node) {
204 1586 : Node* const generator = NodeProperties::GetValueInput(node, 0);
205 1586 : Node* const effect = NodeProperties::GetEffectInput(node);
206 1586 : Node* const control = NodeProperties::GetControlInput(node);
207 : Operator const* const op =
208 3172 : simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
209 :
210 1586 : return Change(node, op, generator, effect, control);
211 : }
212 :
213 5138 : Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
214 5138 : Node* const generator = NodeProperties::GetValueInput(node, 0);
215 5138 : Node* const effect = NodeProperties::GetEffectInput(node);
216 5138 : Node* const control = NodeProperties::GetControlInput(node);
217 : Operator const* const op =
218 10276 : simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
219 :
220 5138 : return Change(node, op, generator, effect, control);
221 : }
222 :
223 1706 : Reduction JSIntrinsicLowering::ReduceIsInstanceType(
224 3412 : Node* node, InstanceType instance_type) {
225 : // if (%_IsSmi(value)) {
226 : // return false;
227 : // } else {
228 : // return %_GetInstanceType(%_GetMap(value)) == instance_type;
229 : // }
230 1706 : Node* value = NodeProperties::GetValueInput(node, 0);
231 1706 : Node* effect = NodeProperties::GetEffectInput(node);
232 1706 : Node* control = NodeProperties::GetControlInput(node);
233 :
234 1706 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
235 1706 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
236 :
237 1706 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
238 : Node* etrue = effect;
239 1706 : Node* vtrue = jsgraph()->FalseConstant();
240 :
241 1706 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
242 : Node* efalse = effect;
243 : Node* map = efalse =
244 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
245 5118 : efalse, if_false);
246 : Node* map_instance_type = efalse = graph()->NewNode(
247 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()), map, efalse,
248 5118 : if_false);
249 : Node* vfalse =
250 : graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
251 5118 : jsgraph()->Constant(instance_type));
252 :
253 1706 : Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
254 :
255 : // Replace all effect uses of {node} with the {ephi}.
256 1706 : Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
257 1706 : ReplaceWithValue(node, node, ephi);
258 :
259 : // Turn the {node} into a Phi.
260 : return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
261 1706 : vfalse, merge);
262 : }
263 :
264 :
265 7965 : Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
266 7965 : return Change(node, simplified()->ObjectIsReceiver());
267 : }
268 :
269 :
270 699 : Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
271 699 : return Change(node, simplified()->ObjectIsSmi());
272 : }
273 :
274 :
275 8664 : Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
276 : // Replace all effect uses of {node} with the effect dependency.
277 : RelaxEffectsAndControls(node);
278 : // Remove the inputs corresponding to context, effect and control.
279 8664 : NodeProperties::RemoveNonValueInputs(node);
280 : // Finally update the operator to the new one.
281 8664 : NodeProperties::ChangeOp(node, op);
282 8664 : return Changed(node);
283 : }
284 :
285 175 : Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
286 175 : NodeProperties::ChangeOp(node, javascript()->ToInteger());
287 175 : return Changed(node);
288 : }
289 :
290 :
291 149 : Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
292 149 : NodeProperties::ChangeOp(node, javascript()->ToNumber());
293 149 : return Changed(node);
294 : }
295 :
296 :
297 867 : Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
298 867 : NodeProperties::ChangeOp(node, javascript()->ToLength());
299 867 : return Changed(node);
300 : }
301 :
302 :
303 1015 : Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
304 1015 : NodeProperties::ChangeOp(node, javascript()->ToObject());
305 1015 : return Changed(node);
306 : }
307 :
308 :
309 3239 : Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
310 : // ToString is unnecessary if the input is a string.
311 3239 : HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
312 3704 : if (m.HasValue() && m.Value()->IsString()) {
313 447 : ReplaceWithValue(node, m.node());
314 : return Replace(m.node());
315 : }
316 2792 : NodeProperties::ChangeOp(node, javascript()->ToString());
317 : return Changed(node);
318 : }
319 :
320 :
321 8597 : Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
322 8597 : size_t const arity = CallRuntimeParametersOf(node->op()).arity();
323 17194 : NodeProperties::ChangeOp(node, javascript()->Call(arity));
324 8597 : return Changed(node);
325 : }
326 :
327 10 : Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
328 10 : NodeProperties::ChangeOp(node, javascript()->GetSuperConstructor());
329 10 : return Changed(node);
330 : }
331 :
332 245 : Reduction JSIntrinsicLowering::ReduceArrayBufferViewField(
333 245 : Node* node, FieldAccess const& access) {
334 245 : Node* receiver = NodeProperties::GetValueInput(node, 0);
335 245 : Node* effect = NodeProperties::GetEffectInput(node);
336 245 : Node* control = NodeProperties::GetControlInput(node);
337 :
338 : // Load the {receiver}s field.
339 : Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
340 245 : receiver, effect, control);
341 :
342 : // Check if the {receiver}s buffer was neutered.
343 : Node* receiver_buffer = effect = graph()->NewNode(
344 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
345 735 : receiver, effect, control);
346 : Node* check = effect = graph()->NewNode(
347 245 : simplified()->ArrayBufferWasNeutered(), receiver_buffer, effect, control);
348 :
349 : // Default to zero if the {receiver}s buffer was neutered.
350 : value = graph()->NewNode(
351 : common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
352 490 : check, jsgraph()->ZeroConstant(), value);
353 :
354 245 : ReplaceWithValue(node, value, effect, control);
355 245 : return Replace(value);
356 : }
357 :
358 24 : Reduction JSIntrinsicLowering::ReduceArrayBufferViewWasNeutered(Node* node) {
359 24 : Node* receiver = NodeProperties::GetValueInput(node, 0);
360 24 : Node* effect = NodeProperties::GetEffectInput(node);
361 24 : Node* control = NodeProperties::GetControlInput(node);
362 :
363 : // Check if the {receiver}s buffer was neutered.
364 : Node* receiver_buffer = effect = graph()->NewNode(
365 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
366 72 : receiver, effect, control);
367 : Node* value = effect = graph()->NewNode(
368 24 : simplified()->ArrayBufferWasNeutered(), receiver_buffer, effect, control);
369 :
370 24 : ReplaceWithValue(node, value, effect, control);
371 24 : return Replace(value);
372 : }
373 :
374 8 : Reduction JSIntrinsicLowering::ReduceMaxSmi(Node* node) {
375 8 : Node* value = jsgraph()->Constant(Smi::kMaxValue);
376 8 : ReplaceWithValue(node, value);
377 8 : return Replace(value);
378 : }
379 :
380 0 : Reduction JSIntrinsicLowering::ReduceTheHole(Node* node) {
381 0 : Node* value = jsgraph()->TheHoleConstant();
382 0 : ReplaceWithValue(node, value);
383 0 : return Replace(value);
384 : }
385 :
386 962 : Reduction JSIntrinsicLowering::ReduceClassOf(Node* node) {
387 : RelaxEffectsAndControls(node);
388 : // The ClassOf operator has a single value input and control input.
389 962 : Node* control_input = NodeProperties::GetControlInput(node, 0);
390 962 : node->TrimInputCount(2);
391 962 : node->ReplaceInput(1, control_input);
392 962 : NodeProperties::ChangeOp(node, simplified()->ClassOf());
393 962 : return Changed(node);
394 : }
395 :
396 0 : Reduction JSIntrinsicLowering::ReduceStringMaxLength(Node* node) {
397 0 : Node* value = jsgraph()->Constant(String::kMaxLength);
398 0 : ReplaceWithValue(node, value);
399 0 : return Replace(value);
400 : }
401 :
402 0 : Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
403 : Node* b) {
404 : RelaxControls(node);
405 0 : node->ReplaceInput(0, a);
406 0 : node->ReplaceInput(1, b);
407 0 : node->TrimInputCount(2);
408 0 : NodeProperties::ChangeOp(node, op);
409 0 : return Changed(node);
410 : }
411 :
412 :
413 13575 : Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
414 : Node* b, Node* c) {
415 : RelaxControls(node);
416 13575 : node->ReplaceInput(0, a);
417 13575 : node->ReplaceInput(1, b);
418 13575 : node->ReplaceInput(2, c);
419 13575 : node->TrimInputCount(3);
420 13575 : NodeProperties::ChangeOp(node, op);
421 13575 : return Changed(node);
422 : }
423 :
424 :
425 2127 : Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
426 : Node* b, Node* c, Node* d) {
427 : RelaxControls(node);
428 2127 : node->ReplaceInput(0, a);
429 2127 : node->ReplaceInput(1, b);
430 2127 : node->ReplaceInput(2, c);
431 2127 : node->ReplaceInput(3, d);
432 2127 : node->TrimInputCount(4);
433 2127 : NodeProperties::ChangeOp(node, op);
434 2127 : return Changed(node);
435 : }
436 :
437 :
438 341 : Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
439 341 : int stack_parameter_count) {
440 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
441 : isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
442 1023 : CallDescriptor::kNeedsFrameState, node->op()->properties());
443 : node->InsertInput(graph()->zone(), 0,
444 682 : jsgraph()->HeapConstant(callable.code()));
445 341 : NodeProperties::ChangeOp(node, common()->Call(desc));
446 341 : return Changed(node);
447 : }
448 :
449 :
450 45981 : Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
451 :
452 :
453 682 : Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
454 :
455 :
456 38152 : CommonOperatorBuilder* JSIntrinsicLowering::common() const {
457 38152 : return jsgraph()->common();
458 : }
459 :
460 0 : JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
461 17174 : return jsgraph_->javascript();
462 : }
463 :
464 29247 : SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
465 29247 : return jsgraph()->simplified();
466 : }
467 :
468 : } // namespace compiler
469 : } // namespace internal
470 : } // namespace v8
|