blob: 034ee6fd76577feabb08b922fad375b9c9242727 [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) {
33 case Runtime::kInlineConstructDouble:
34 return ReduceConstructDouble(node);
35 case Runtime::kInlineCreateIterResultObject:
36 return ReduceCreateIterResultObject(node);
37 case Runtime::kInlineDeoptimizeNow:
38 return ReduceDeoptimizeNow(node);
39 case Runtime::kInlineDoubleHi:
40 return ReduceDoubleHi(node);
41 case Runtime::kInlineDoubleLo:
42 return ReduceDoubleLo(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 case Runtime::kInlineIsArray:
44 return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 case Runtime::kInlineIsTypedArray:
46 return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 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);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 case Runtime::kInlineValueOf:
54 return ReduceValueOf(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055 case Runtime::kInlineFixedArrayGet:
56 return ReduceFixedArrayGet(node);
57 case Runtime::kInlineFixedArraySet:
58 return ReduceFixedArraySet(node);
59 case Runtime::kInlineRegExpConstructResult:
60 return ReduceRegExpConstructResult(node);
61 case Runtime::kInlineRegExpExec:
62 return ReduceRegExpExec(node);
63 case Runtime::kInlineRegExpFlags:
64 return ReduceRegExpFlags(node);
65 case Runtime::kInlineRegExpSource:
66 return ReduceRegExpSource(node);
67 case Runtime::kInlineSubString:
68 return ReduceSubString(node);
69 case Runtime::kInlineToInteger:
70 return ReduceToInteger(node);
71 case Runtime::kInlineToLength:
72 return ReduceToLength(node);
73 case Runtime::kInlineToName:
74 return ReduceToName(node);
75 case Runtime::kInlineToNumber:
76 return ReduceToNumber(node);
77 case Runtime::kInlineToObject:
78 return ReduceToObject(node);
79 case Runtime::kInlineToPrimitive:
80 return ReduceToPrimitive(node);
81 case Runtime::kInlineToString:
82 return ReduceToString(node);
83 case Runtime::kInlineCall:
84 return ReduceCall(node);
Ben Murdochda12d292016-06-02 14:46:10 +010085 case Runtime::kInlineNewObject:
86 return ReduceNewObject(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 case Runtime::kInlineGetSuperConstructor:
88 return ReduceGetSuperConstructor(node);
Ben Murdochda12d292016-06-02 14:46:10 +010089 case Runtime::kInlineGetOrdinaryHasInstance:
90 return ReduceGetOrdinaryHasInstance(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 default:
92 break;
93 }
94 return NoChange();
95}
96
97
98Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
99 Node* const value = NodeProperties::GetValueInput(node, 0);
100 Node* const done = NodeProperties::GetValueInput(node, 1);
101 Node* const context = NodeProperties::GetContextInput(node);
102 Node* const effect = NodeProperties::GetEffectInput(node);
103 return Change(node, javascript()->CreateIterResultObject(), value, done,
104 context, effect);
105}
106
107
108Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
109 Node* high = NodeProperties::GetValueInput(node, 0);
110 Node* low = NodeProperties::GetValueInput(node, 1);
111 Node* value =
112 graph()->NewNode(machine()->Float64InsertHighWord32(),
113 graph()->NewNode(machine()->Float64InsertLowWord32(),
114 jsgraph()->Constant(0), low),
115 high);
116 ReplaceWithValue(node, value);
117 return Replace(value);
118}
119
120
121Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
122 if (mode() != kDeoptimizationEnabled) return NoChange();
123 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
124 Node* const effect = NodeProperties::GetEffectInput(node);
125 Node* const control = NodeProperties::GetControlInput(node);
126
127 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
128 Node* deoptimize =
129 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
130 frame_state, effect, control);
131 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100132 Revisit(graph()->end());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133
134 node->TrimInputCount(0);
135 NodeProperties::ChangeOp(node, common()->Dead());
136 return Changed(node);
137}
138
139
140Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100141 // Tell the compiler to assume number input.
142 Node* renamed = graph()->NewNode(common()->Guard(Type::Number()),
143 node->InputAt(0), graph()->start());
144 node->ReplaceInput(0, renamed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 return Change(node, machine()->Float64ExtractHighWord32());
146}
147
148
149Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100150 // Tell the compiler to assume number input.
151 Node* renamed = graph()->NewNode(common()->Guard(Type::Number()),
152 node->InputAt(0), graph()->start());
153 node->ReplaceInput(0, renamed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 return Change(node, machine()->Float64ExtractLowWord32());
155}
156
157
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158Reduction JSIntrinsicLowering::ReduceIsInstanceType(
159 Node* node, InstanceType instance_type) {
160 // if (%_IsSmi(value)) {
161 // return false;
162 // } else {
163 // return %_GetInstanceType(%_GetMap(value)) == instance_type;
164 // }
165 Node* value = NodeProperties::GetValueInput(node, 0);
166 Node* effect = NodeProperties::GetEffectInput(node);
167 Node* control = NodeProperties::GetControlInput(node);
168
169 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
170 Node* branch = graph()->NewNode(common()->Branch(), check, control);
171
172 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
173 Node* etrue = effect;
174 Node* vtrue = jsgraph()->FalseConstant();
175
176 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
177 Node* efalse = graph()->NewNode(
178 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
179 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
180 effect, if_false),
181 effect, if_false);
182 Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
183 jsgraph()->Int32Constant(instance_type));
184
185 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
186
187 // Replace all effect uses of {node} with the {ephi}.
188 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
189 ReplaceWithValue(node, node, ephi);
190
191 // Turn the {node} into a Phi.
192 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
193 vfalse, merge);
194}
195
196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100198 return Change(node, simplified()->ObjectIsReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199}
200
201
202Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
203 return Change(node, simplified()->ObjectIsSmi());
204}
205
206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
208 // if (%_IsSmi(value)) {
209 // return value;
210 // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
211 // return %_GetValue(value);
212 // } else {
213 // return value;
214 // }
215 const Operator* const merge_op = common()->Merge(2);
216 const Operator* const ephi_op = common()->EffectPhi(2);
217 const Operator* const phi_op =
218 common()->Phi(MachineRepresentation::kTagged, 2);
219
220 Node* value = NodeProperties::GetValueInput(node, 0);
221 Node* effect = NodeProperties::GetEffectInput(node);
222 Node* control = NodeProperties::GetControlInput(node);
223
224 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
225 Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
226
227 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
228 Node* etrue0 = effect;
229 Node* vtrue0 = value;
230
231 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
232 Node* efalse0;
233 Node* vfalse0;
234 {
235 Node* check1 = graph()->NewNode(
236 machine()->Word32Equal(),
237 graph()->NewNode(
238 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
239 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
240 value, effect, if_false0),
241 effect, if_false0),
242 jsgraph()->Int32Constant(JS_VALUE_TYPE));
243 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
244
245 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
246 Node* etrue1 =
247 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
248 value, effect, if_true1);
249 Node* vtrue1 = etrue1;
250
251 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
252 Node* efalse1 = effect;
253 Node* vfalse1 = value;
254
255 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
256 efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
257 vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
258 }
259
260 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
261
262 // Replace all effect uses of {node} with the {ephi0}.
263 Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
264 ReplaceWithValue(node, node, ephi0);
265
266 // Turn the {node} into a Phi.
267 return Change(node, phi_op, vtrue0, vfalse0, merge0);
268}
269
270
271Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
272 // Replace all effect uses of {node} with the effect dependency.
273 RelaxEffectsAndControls(node);
274 // Remove the inputs corresponding to context, effect and control.
275 NodeProperties::RemoveNonValueInputs(node);
276 // Finally update the operator to the new one.
277 NodeProperties::ChangeOp(node, op);
278 return Changed(node);
279}
280
281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
283 Node* base = node->InputAt(0);
284 Node* index = node->InputAt(1);
285 Node* effect = NodeProperties::GetEffectInput(node);
286 Node* control = NodeProperties::GetControlInput(node);
287 return Change(
288 node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
289 base, index, effect, control);
290}
291
292
293Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
294 Node* base = node->InputAt(0);
295 Node* index = node->InputAt(1);
296 Node* value = node->InputAt(2);
297 Node* effect = NodeProperties::GetEffectInput(node);
298 Node* control = NodeProperties::GetControlInput(node);
299 Node* store = (graph()->NewNode(
300 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
301 index, value, effect, control));
302 ReplaceWithValue(node, value, store);
303 return Changed(store);
304}
305
306
307Reduction JSIntrinsicLowering::ReduceRegExpConstructResult(Node* node) {
308 // TODO(bmeurer): Introduce JSCreateRegExpResult?
309 return Change(node, CodeFactory::RegExpConstructResult(isolate()), 0);
310}
311
312
313Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) {
314 return Change(node, CodeFactory::RegExpExec(isolate()), 4);
315}
316
317
318Reduction JSIntrinsicLowering::ReduceRegExpFlags(Node* node) {
319 Node* const receiver = NodeProperties::GetValueInput(node, 0);
320 Node* const effect = NodeProperties::GetEffectInput(node);
321 Node* const control = NodeProperties::GetControlInput(node);
322 Operator const* const op =
323 simplified()->LoadField(AccessBuilder::ForJSRegExpFlags());
324 return Change(node, op, receiver, effect, control);
325}
326
327
328Reduction JSIntrinsicLowering::ReduceRegExpSource(Node* node) {
329 Node* const receiver = NodeProperties::GetValueInput(node, 0);
330 Node* const effect = NodeProperties::GetEffectInput(node);
331 Node* const control = NodeProperties::GetControlInput(node);
332 Operator const* const op =
333 simplified()->LoadField(AccessBuilder::ForJSRegExpSource());
334 return Change(node, op, receiver, effect, control);
335}
336
337
338Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
339 return Change(node, CodeFactory::SubString(isolate()), 3);
340}
341
342
343Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100344 NodeProperties::ChangeOp(node, javascript()->ToInteger());
345 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346}
347
348
349Reduction JSIntrinsicLowering::ReduceToName(Node* node) {
350 NodeProperties::ChangeOp(node, javascript()->ToName());
351 return Changed(node);
352}
353
354
355Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
356 NodeProperties::ChangeOp(node, javascript()->ToNumber());
357 return Changed(node);
358}
359
360
361Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100362 NodeProperties::ChangeOp(node, javascript()->ToLength());
363 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364}
365
366
367Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
368 NodeProperties::ChangeOp(node, javascript()->ToObject());
369 return Changed(node);
370}
371
372
373Reduction JSIntrinsicLowering::ReduceToPrimitive(Node* node) {
374 Node* value = NodeProperties::GetValueInput(node, 0);
375 Type* value_type = NodeProperties::GetType(value);
376 if (value_type->Is(Type::Primitive())) {
377 ReplaceWithValue(node, value);
378 return Replace(value);
379 }
380 return NoChange();
381}
382
383
384Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
385 NodeProperties::ChangeOp(node, javascript()->ToString());
386 return Changed(node);
387}
388
389
390Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
391 size_t const arity = CallRuntimeParametersOf(node->op()).arity();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100392 NodeProperties::ChangeOp(node,
393 javascript()->CallFunction(arity, VectorSlotPair(),
394 ConvertReceiverMode::kAny,
395 TailCallMode::kDisallow));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 return Changed(node);
397}
398
Ben Murdochda12d292016-06-02 14:46:10 +0100399Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) {
400 Node* constructor = NodeProperties::GetValueInput(node, 0);
401 Node* new_target = NodeProperties::GetValueInput(node, 1);
402 Node* context = NodeProperties::GetContextInput(node);
403 Node* effect = NodeProperties::GetEffectInput(node);
404 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
405 Node* value = graph()->NewNode(javascript()->Create(), constructor,
406 new_target, context, frame_state, effect);
407 ReplaceWithValue(node, value, value);
408 return Replace(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409}
410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
412 Node* active_function = NodeProperties::GetValueInput(node, 0);
413 Node* effect = NodeProperties::GetEffectInput(node);
414 Node* control = NodeProperties::GetControlInput(node);
415 Node* active_function_map = effect =
416 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
417 active_function, effect, control);
418 return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
419 active_function_map, effect, control);
420}
421
Ben Murdochda12d292016-06-02 14:46:10 +0100422Reduction JSIntrinsicLowering::ReduceGetOrdinaryHasInstance(Node* node) {
423 Node* effect = NodeProperties::GetEffectInput(node);
424 Node* context = NodeProperties::GetContextInput(node);
425 Node* native_context = effect = graph()->NewNode(
426 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
427 context, context, effect);
428 return Change(node, javascript()->LoadContext(
429 0, Context::ORDINARY_HAS_INSTANCE_INDEX, true),
430 native_context, context, effect);
431}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432
433Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
434 Node* b) {
435 RelaxControls(node);
436 node->ReplaceInput(0, a);
437 node->ReplaceInput(1, b);
438 node->TrimInputCount(2);
439 NodeProperties::ChangeOp(node, op);
440 return Changed(node);
441}
442
443
444Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
445 Node* b, Node* c) {
446 RelaxControls(node);
447 node->ReplaceInput(0, a);
448 node->ReplaceInput(1, b);
449 node->ReplaceInput(2, c);
450 node->TrimInputCount(3);
451 NodeProperties::ChangeOp(node, op);
452 return Changed(node);
453}
454
455
456Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
457 Node* b, Node* c, Node* d) {
458 RelaxControls(node);
459 node->ReplaceInput(0, a);
460 node->ReplaceInput(1, b);
461 node->ReplaceInput(2, c);
462 node->ReplaceInput(3, d);
463 node->TrimInputCount(4);
464 NodeProperties::ChangeOp(node, op);
465 return Changed(node);
466}
467
468
469Reduction JSIntrinsicLowering::ChangeToUndefined(Node* node, Node* effect) {
470 ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect);
471 return Changed(node);
472}
473
474
475Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
476 int stack_parameter_count) {
477 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
478 isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
479 CallDescriptor::kNeedsFrameState, node->op()->properties());
480 node->InsertInput(graph()->zone(), 0,
481 jsgraph()->HeapConstant(callable.code()));
482 NodeProperties::ChangeOp(node, common()->Call(desc));
483 return Changed(node);
484}
485
486
487Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
488
489
490Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
491
492
493CommonOperatorBuilder* JSIntrinsicLowering::common() const {
494 return jsgraph()->common();
495}
496
497JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
498 return jsgraph_->javascript();
499}
500
501
502MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
503 return jsgraph()->machine();
504}
505
506
507SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
508 return jsgraph()->simplified();
509}
510
511} // namespace compiler
512} // namespace internal
513} // namespace v8