blob: 8d24013058a1d0f2c1bf2ef1676d1b57e921f9b1 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018
19namespace v8 {
20namespace internal {
21namespace compiler {
22
23JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
24 DeoptimizationMode mode)
Ben Murdochda12d292016-06-02 14:46:10 +010025 : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026
27Reduction 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) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 case Runtime::kInlineCreateIterResultObject:
34 return ReduceCreateIterResultObject(node);
35 case Runtime::kInlineDeoptimizeNow:
36 return ReduceDeoptimizeNow(node);
37 case Runtime::kInlineDoubleHi:
38 return ReduceDoubleHi(node);
39 case Runtime::kInlineDoubleLo:
40 return ReduceDoubleLo(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +010041 case Runtime::kInlineGeneratorClose:
42 return ReduceGeneratorClose(node);
43 case Runtime::kInlineGeneratorGetInputOrDebugPos:
44 return ReduceGeneratorGetInputOrDebugPos(node);
45 case Runtime::kInlineGeneratorGetResumeMode:
46 return ReduceGeneratorGetResumeMode(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 case Runtime::kInlineIsArray:
48 return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 case Runtime::kInlineIsTypedArray:
50 return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 case Runtime::kInlineIsRegExp:
52 return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
53 case Runtime::kInlineIsJSReceiver:
54 return ReduceIsJSReceiver(node);
55 case Runtime::kInlineIsSmi:
56 return ReduceIsSmi(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 case Runtime::kInlineValueOf:
58 return ReduceValueOf(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059 case Runtime::kInlineFixedArrayGet:
60 return ReduceFixedArrayGet(node);
61 case Runtime::kInlineFixedArraySet:
62 return ReduceFixedArraySet(node);
63 case Runtime::kInlineRegExpConstructResult:
64 return ReduceRegExpConstructResult(node);
65 case Runtime::kInlineRegExpExec:
66 return ReduceRegExpExec(node);
67 case Runtime::kInlineRegExpFlags:
68 return ReduceRegExpFlags(node);
69 case Runtime::kInlineRegExpSource:
70 return ReduceRegExpSource(node);
71 case Runtime::kInlineSubString:
72 return ReduceSubString(node);
73 case Runtime::kInlineToInteger:
74 return ReduceToInteger(node);
75 case Runtime::kInlineToLength:
76 return ReduceToLength(node);
77 case Runtime::kInlineToName:
78 return ReduceToName(node);
79 case Runtime::kInlineToNumber:
80 return ReduceToNumber(node);
81 case Runtime::kInlineToObject:
82 return ReduceToObject(node);
83 case Runtime::kInlineToPrimitive:
84 return ReduceToPrimitive(node);
85 case Runtime::kInlineToString:
86 return ReduceToString(node);
87 case Runtime::kInlineCall:
88 return ReduceCall(node);
Ben Murdochda12d292016-06-02 14:46:10 +010089 case Runtime::kInlineNewObject:
90 return ReduceNewObject(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 case Runtime::kInlineGetSuperConstructor:
92 return ReduceGetSuperConstructor(node);
93 default:
94 break;
95 }
96 return NoChange();
97}
98
99
100Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
101 Node* const value = NodeProperties::GetValueInput(node, 0);
102 Node* const done = NodeProperties::GetValueInput(node, 1);
103 Node* const context = NodeProperties::GetContextInput(node);
104 Node* const effect = NodeProperties::GetEffectInput(node);
105 return Change(node, javascript()->CreateIterResultObject(), value, done,
106 context, effect);
107}
108
109
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
111 if (mode() != kDeoptimizationEnabled) return NoChange();
112 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
113 Node* const effect = NodeProperties::GetEffectInput(node);
114 Node* const control = NodeProperties::GetControlInput(node);
115
116 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
117 Node* deoptimize =
118 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
119 frame_state, effect, control);
120 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100121 Revisit(graph()->end());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122
123 node->TrimInputCount(0);
124 NodeProperties::ChangeOp(node, common()->Dead());
125 return Changed(node);
126}
127
128
129Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100130 // Tell the compiler to assume number input.
Ben Murdochc5610432016-08-08 18:44:38 +0100131 Node* renamed = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
Ben Murdochda12d292016-06-02 14:46:10 +0100132 node->InputAt(0), graph()->start());
133 node->ReplaceInput(0, renamed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 return Change(node, machine()->Float64ExtractHighWord32());
135}
136
137
138Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100139 // Tell the compiler to assume number input.
Ben Murdochc5610432016-08-08 18:44:38 +0100140 Node* renamed = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
Ben Murdochda12d292016-06-02 14:46:10 +0100141 node->InputAt(0), graph()->start());
142 node->ReplaceInput(0, renamed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 return Change(node, machine()->Float64ExtractLowWord32());
144}
145
Ben Murdoch61f157c2016-09-16 13:49:30 +0100146Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
147 Node* const generator = NodeProperties::GetValueInput(node, 0);
148 Node* const effect = NodeProperties::GetEffectInput(node);
149 Node* const control = NodeProperties::GetControlInput(node);
150 Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
151 Node* const undefined = jsgraph()->UndefinedConstant();
152 Operator const* const op = simplified()->StoreField(
153 AccessBuilder::ForJSGeneratorObjectContinuation());
154
155 ReplaceWithValue(node, undefined, node);
156 NodeProperties::RemoveType(node);
157 return Change(node, op, generator, closed, effect, control);
158}
159
160Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
161 Node* const generator = NodeProperties::GetValueInput(node, 0);
162 Node* const effect = NodeProperties::GetEffectInput(node);
163 Node* const control = NodeProperties::GetControlInput(node);
164 Operator const* const op = simplified()->LoadField(
165 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
166
167 return Change(node, op, generator, effect, control);
168}
169
170Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
171 Node* const generator = NodeProperties::GetValueInput(node, 0);
172 Node* const effect = NodeProperties::GetEffectInput(node);
173 Node* const control = NodeProperties::GetControlInput(node);
174 Operator const* const op =
175 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
176
177 return Change(node, op, generator, effect, control);
178}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180Reduction JSIntrinsicLowering::ReduceIsInstanceType(
181 Node* node, InstanceType instance_type) {
182 // if (%_IsSmi(value)) {
183 // return false;
184 // } else {
185 // return %_GetInstanceType(%_GetMap(value)) == instance_type;
186 // }
187 Node* value = NodeProperties::GetValueInput(node, 0);
188 Node* effect = NodeProperties::GetEffectInput(node);
189 Node* control = NodeProperties::GetControlInput(node);
190
191 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
192 Node* branch = graph()->NewNode(common()->Branch(), check, control);
193
194 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
195 Node* etrue = effect;
196 Node* vtrue = jsgraph()->FalseConstant();
197
198 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
199 Node* efalse = graph()->NewNode(
200 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
201 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
202 effect, if_false),
203 effect, if_false);
204 Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
205 jsgraph()->Int32Constant(instance_type));
206
207 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
208
209 // Replace all effect uses of {node} with the {ephi}.
210 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
211 ReplaceWithValue(node, node, ephi);
212
213 // Turn the {node} into a Phi.
214 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
215 vfalse, merge);
216}
217
218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 return Change(node, simplified()->ObjectIsReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221}
222
223
224Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
225 return Change(node, simplified()->ObjectIsSmi());
226}
227
228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
230 // if (%_IsSmi(value)) {
231 // return value;
232 // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
233 // return %_GetValue(value);
234 // } else {
235 // return value;
236 // }
237 const Operator* const merge_op = common()->Merge(2);
238 const Operator* const ephi_op = common()->EffectPhi(2);
239 const Operator* const phi_op =
240 common()->Phi(MachineRepresentation::kTagged, 2);
241
242 Node* value = NodeProperties::GetValueInput(node, 0);
243 Node* effect = NodeProperties::GetEffectInput(node);
244 Node* control = NodeProperties::GetControlInput(node);
245
246 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
247 Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
248
249 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
250 Node* etrue0 = effect;
251 Node* vtrue0 = value;
252
253 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
254 Node* efalse0;
255 Node* vfalse0;
256 {
257 Node* check1 = graph()->NewNode(
258 machine()->Word32Equal(),
259 graph()->NewNode(
260 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
261 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
262 value, effect, if_false0),
263 effect, if_false0),
264 jsgraph()->Int32Constant(JS_VALUE_TYPE));
265 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
266
267 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
268 Node* etrue1 =
269 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
270 value, effect, if_true1);
271 Node* vtrue1 = etrue1;
272
273 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
274 Node* efalse1 = effect;
275 Node* vfalse1 = value;
276
277 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
278 efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
279 vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
280 }
281
282 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
283
284 // Replace all effect uses of {node} with the {ephi0}.
285 Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
286 ReplaceWithValue(node, node, ephi0);
287
288 // Turn the {node} into a Phi.
289 return Change(node, phi_op, vtrue0, vfalse0, merge0);
290}
291
292
293Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
294 // Replace all effect uses of {node} with the effect dependency.
295 RelaxEffectsAndControls(node);
296 // Remove the inputs corresponding to context, effect and control.
297 NodeProperties::RemoveNonValueInputs(node);
298 // Finally update the operator to the new one.
299 NodeProperties::ChangeOp(node, op);
300 return Changed(node);
301}
302
303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
305 Node* base = node->InputAt(0);
306 Node* index = node->InputAt(1);
307 Node* effect = NodeProperties::GetEffectInput(node);
308 Node* control = NodeProperties::GetControlInput(node);
309 return Change(
310 node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
311 base, index, effect, control);
312}
313
314
315Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
316 Node* base = node->InputAt(0);
317 Node* index = node->InputAt(1);
318 Node* value = node->InputAt(2);
319 Node* effect = NodeProperties::GetEffectInput(node);
320 Node* control = NodeProperties::GetControlInput(node);
321 Node* store = (graph()->NewNode(
322 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
323 index, value, effect, control));
324 ReplaceWithValue(node, value, store);
325 return Changed(store);
326}
327
328
329Reduction JSIntrinsicLowering::ReduceRegExpConstructResult(Node* node) {
330 // TODO(bmeurer): Introduce JSCreateRegExpResult?
331 return Change(node, CodeFactory::RegExpConstructResult(isolate()), 0);
332}
333
334
335Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) {
336 return Change(node, CodeFactory::RegExpExec(isolate()), 4);
337}
338
339
340Reduction JSIntrinsicLowering::ReduceRegExpFlags(Node* node) {
341 Node* const receiver = NodeProperties::GetValueInput(node, 0);
342 Node* const effect = NodeProperties::GetEffectInput(node);
343 Node* const control = NodeProperties::GetControlInput(node);
344 Operator const* const op =
345 simplified()->LoadField(AccessBuilder::ForJSRegExpFlags());
346 return Change(node, op, receiver, effect, control);
347}
348
349
350Reduction JSIntrinsicLowering::ReduceRegExpSource(Node* node) {
351 Node* const receiver = NodeProperties::GetValueInput(node, 0);
352 Node* const effect = NodeProperties::GetEffectInput(node);
353 Node* const control = NodeProperties::GetControlInput(node);
354 Operator const* const op =
355 simplified()->LoadField(AccessBuilder::ForJSRegExpSource());
356 return Change(node, op, receiver, effect, control);
357}
358
359
360Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
361 return Change(node, CodeFactory::SubString(isolate()), 3);
362}
363
364
365Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100366 NodeProperties::ChangeOp(node, javascript()->ToInteger());
367 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368}
369
370
371Reduction JSIntrinsicLowering::ReduceToName(Node* node) {
372 NodeProperties::ChangeOp(node, javascript()->ToName());
373 return Changed(node);
374}
375
376
377Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
378 NodeProperties::ChangeOp(node, javascript()->ToNumber());
379 return Changed(node);
380}
381
382
383Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100384 NodeProperties::ChangeOp(node, javascript()->ToLength());
385 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386}
387
388
389Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
390 NodeProperties::ChangeOp(node, javascript()->ToObject());
391 return Changed(node);
392}
393
394
395Reduction JSIntrinsicLowering::ReduceToPrimitive(Node* node) {
396 Node* value = NodeProperties::GetValueInput(node, 0);
397 Type* value_type = NodeProperties::GetType(value);
398 if (value_type->Is(Type::Primitive())) {
399 ReplaceWithValue(node, value);
400 return Replace(value);
401 }
402 return NoChange();
403}
404
405
406Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
407 NodeProperties::ChangeOp(node, javascript()->ToString());
408 return Changed(node);
409}
410
411
412Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
413 size_t const arity = CallRuntimeParametersOf(node->op()).arity();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100414 NodeProperties::ChangeOp(node,
415 javascript()->CallFunction(arity, VectorSlotPair(),
416 ConvertReceiverMode::kAny,
417 TailCallMode::kDisallow));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 return Changed(node);
419}
420
Ben Murdochda12d292016-06-02 14:46:10 +0100421Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +0100422 return Change(node, CodeFactory::FastNewObject(isolate()), 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423}
424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
426 Node* active_function = NodeProperties::GetValueInput(node, 0);
427 Node* effect = NodeProperties::GetEffectInput(node);
428 Node* control = NodeProperties::GetControlInput(node);
429 Node* active_function_map = effect =
430 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
431 active_function, effect, control);
432 return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
433 active_function_map, effect, control);
434}
435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
437 Node* b) {
438 RelaxControls(node);
439 node->ReplaceInput(0, a);
440 node->ReplaceInput(1, b);
441 node->TrimInputCount(2);
442 NodeProperties::ChangeOp(node, op);
443 return Changed(node);
444}
445
446
447Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
448 Node* b, Node* c) {
449 RelaxControls(node);
450 node->ReplaceInput(0, a);
451 node->ReplaceInput(1, b);
452 node->ReplaceInput(2, c);
453 node->TrimInputCount(3);
454 NodeProperties::ChangeOp(node, op);
455 return Changed(node);
456}
457
458
459Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
460 Node* b, Node* c, Node* d) {
461 RelaxControls(node);
462 node->ReplaceInput(0, a);
463 node->ReplaceInput(1, b);
464 node->ReplaceInput(2, c);
465 node->ReplaceInput(3, d);
466 node->TrimInputCount(4);
467 NodeProperties::ChangeOp(node, op);
468 return Changed(node);
469}
470
471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
473 int stack_parameter_count) {
474 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
475 isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
476 CallDescriptor::kNeedsFrameState, node->op()->properties());
477 node->InsertInput(graph()->zone(), 0,
478 jsgraph()->HeapConstant(callable.code()));
479 NodeProperties::ChangeOp(node, common()->Call(desc));
480 return Changed(node);
481}
482
483
484Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
485
486
487Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
488
489
490CommonOperatorBuilder* JSIntrinsicLowering::common() const {
491 return jsgraph()->common();
492}
493
494JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
495 return jsgraph_->javascript();
496}
497
498
499MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
500 return jsgraph()->machine();
501}
502
503
504SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
505 return jsgraph()->simplified();
506}
507
508} // namespace compiler
509} // namespace internal
510} // namespace v8