blob: 70bcda5991de542c6724ee8d096428576934ff1b [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);
89 default:
90 break;
91 }
92 return NoChange();
93}
94
95
96Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
97 Node* const value = NodeProperties::GetValueInput(node, 0);
98 Node* const done = NodeProperties::GetValueInput(node, 1);
99 Node* const context = NodeProperties::GetContextInput(node);
100 Node* const effect = NodeProperties::GetEffectInput(node);
101 return Change(node, javascript()->CreateIterResultObject(), value, done,
102 context, effect);
103}
104
105
106Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
107 Node* high = NodeProperties::GetValueInput(node, 0);
108 Node* low = NodeProperties::GetValueInput(node, 1);
109 Node* value =
110 graph()->NewNode(machine()->Float64InsertHighWord32(),
111 graph()->NewNode(machine()->Float64InsertLowWord32(),
112 jsgraph()->Constant(0), low),
113 high);
114 ReplaceWithValue(node, value);
115 return Replace(value);
116}
117
118
119Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
120 if (mode() != kDeoptimizationEnabled) return NoChange();
121 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
122 Node* const effect = NodeProperties::GetEffectInput(node);
123 Node* const control = NodeProperties::GetControlInput(node);
124
125 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
126 Node* deoptimize =
127 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
128 frame_state, effect, control);
129 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100130 Revisit(graph()->end());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131
132 node->TrimInputCount(0);
133 NodeProperties::ChangeOp(node, common()->Dead());
134 return Changed(node);
135}
136
137
138Reduction JSIntrinsicLowering::ReduceDoubleHi(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()->Float64ExtractHighWord32());
144}
145
146
147Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100148 // Tell the compiler to assume number input.
Ben Murdochc5610432016-08-08 18:44:38 +0100149 Node* renamed = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
Ben Murdochda12d292016-06-02 14:46:10 +0100150 node->InputAt(0), graph()->start());
151 node->ReplaceInput(0, renamed);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 return Change(node, machine()->Float64ExtractLowWord32());
153}
154
155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156Reduction JSIntrinsicLowering::ReduceIsInstanceType(
157 Node* node, InstanceType instance_type) {
158 // if (%_IsSmi(value)) {
159 // return false;
160 // } else {
161 // return %_GetInstanceType(%_GetMap(value)) == instance_type;
162 // }
163 Node* value = NodeProperties::GetValueInput(node, 0);
164 Node* effect = NodeProperties::GetEffectInput(node);
165 Node* control = NodeProperties::GetControlInput(node);
166
167 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
168 Node* branch = graph()->NewNode(common()->Branch(), check, control);
169
170 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
171 Node* etrue = effect;
172 Node* vtrue = jsgraph()->FalseConstant();
173
174 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
175 Node* efalse = graph()->NewNode(
176 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
177 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
178 effect, if_false),
179 effect, if_false);
180 Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
181 jsgraph()->Int32Constant(instance_type));
182
183 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
184
185 // Replace all effect uses of {node} with the {ephi}.
186 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
187 ReplaceWithValue(node, node, ephi);
188
189 // Turn the {node} into a Phi.
190 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
191 vfalse, merge);
192}
193
194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100196 return Change(node, simplified()->ObjectIsReceiver());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197}
198
199
200Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
201 return Change(node, simplified()->ObjectIsSmi());
202}
203
204
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
206 // if (%_IsSmi(value)) {
207 // return value;
208 // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
209 // return %_GetValue(value);
210 // } else {
211 // return value;
212 // }
213 const Operator* const merge_op = common()->Merge(2);
214 const Operator* const ephi_op = common()->EffectPhi(2);
215 const Operator* const phi_op =
216 common()->Phi(MachineRepresentation::kTagged, 2);
217
218 Node* value = NodeProperties::GetValueInput(node, 0);
219 Node* effect = NodeProperties::GetEffectInput(node);
220 Node* control = NodeProperties::GetControlInput(node);
221
222 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
223 Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
224
225 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
226 Node* etrue0 = effect;
227 Node* vtrue0 = value;
228
229 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
230 Node* efalse0;
231 Node* vfalse0;
232 {
233 Node* check1 = graph()->NewNode(
234 machine()->Word32Equal(),
235 graph()->NewNode(
236 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
237 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
238 value, effect, if_false0),
239 effect, if_false0),
240 jsgraph()->Int32Constant(JS_VALUE_TYPE));
241 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
242
243 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
244 Node* etrue1 =
245 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
246 value, effect, if_true1);
247 Node* vtrue1 = etrue1;
248
249 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
250 Node* efalse1 = effect;
251 Node* vfalse1 = value;
252
253 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
254 efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
255 vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
256 }
257
258 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
259
260 // Replace all effect uses of {node} with the {ephi0}.
261 Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
262 ReplaceWithValue(node, node, ephi0);
263
264 // Turn the {node} into a Phi.
265 return Change(node, phi_op, vtrue0, vfalse0, merge0);
266}
267
268
269Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
270 // Replace all effect uses of {node} with the effect dependency.
271 RelaxEffectsAndControls(node);
272 // Remove the inputs corresponding to context, effect and control.
273 NodeProperties::RemoveNonValueInputs(node);
274 // Finally update the operator to the new one.
275 NodeProperties::ChangeOp(node, op);
276 return Changed(node);
277}
278
279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
281 Node* base = node->InputAt(0);
282 Node* index = node->InputAt(1);
283 Node* effect = NodeProperties::GetEffectInput(node);
284 Node* control = NodeProperties::GetControlInput(node);
285 return Change(
286 node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
287 base, index, effect, control);
288}
289
290
291Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
292 Node* base = node->InputAt(0);
293 Node* index = node->InputAt(1);
294 Node* value = node->InputAt(2);
295 Node* effect = NodeProperties::GetEffectInput(node);
296 Node* control = NodeProperties::GetControlInput(node);
297 Node* store = (graph()->NewNode(
298 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
299 index, value, effect, control));
300 ReplaceWithValue(node, value, store);
301 return Changed(store);
302}
303
304
305Reduction JSIntrinsicLowering::ReduceRegExpConstructResult(Node* node) {
306 // TODO(bmeurer): Introduce JSCreateRegExpResult?
307 return Change(node, CodeFactory::RegExpConstructResult(isolate()), 0);
308}
309
310
311Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) {
312 return Change(node, CodeFactory::RegExpExec(isolate()), 4);
313}
314
315
316Reduction JSIntrinsicLowering::ReduceRegExpFlags(Node* node) {
317 Node* const receiver = NodeProperties::GetValueInput(node, 0);
318 Node* const effect = NodeProperties::GetEffectInput(node);
319 Node* const control = NodeProperties::GetControlInput(node);
320 Operator const* const op =
321 simplified()->LoadField(AccessBuilder::ForJSRegExpFlags());
322 return Change(node, op, receiver, effect, control);
323}
324
325
326Reduction JSIntrinsicLowering::ReduceRegExpSource(Node* node) {
327 Node* const receiver = NodeProperties::GetValueInput(node, 0);
328 Node* const effect = NodeProperties::GetEffectInput(node);
329 Node* const control = NodeProperties::GetControlInput(node);
330 Operator const* const op =
331 simplified()->LoadField(AccessBuilder::ForJSRegExpSource());
332 return Change(node, op, receiver, effect, control);
333}
334
335
336Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
337 return Change(node, CodeFactory::SubString(isolate()), 3);
338}
339
340
341Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100342 NodeProperties::ChangeOp(node, javascript()->ToInteger());
343 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344}
345
346
347Reduction JSIntrinsicLowering::ReduceToName(Node* node) {
348 NodeProperties::ChangeOp(node, javascript()->ToName());
349 return Changed(node);
350}
351
352
353Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
354 NodeProperties::ChangeOp(node, javascript()->ToNumber());
355 return Changed(node);
356}
357
358
359Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +0100360 NodeProperties::ChangeOp(node, javascript()->ToLength());
361 return Changed(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362}
363
364
365Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
366 NodeProperties::ChangeOp(node, javascript()->ToObject());
367 return Changed(node);
368}
369
370
371Reduction JSIntrinsicLowering::ReduceToPrimitive(Node* node) {
372 Node* value = NodeProperties::GetValueInput(node, 0);
373 Type* value_type = NodeProperties::GetType(value);
374 if (value_type->Is(Type::Primitive())) {
375 ReplaceWithValue(node, value);
376 return Replace(value);
377 }
378 return NoChange();
379}
380
381
382Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
383 NodeProperties::ChangeOp(node, javascript()->ToString());
384 return Changed(node);
385}
386
387
388Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
389 size_t const arity = CallRuntimeParametersOf(node->op()).arity();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100390 NodeProperties::ChangeOp(node,
391 javascript()->CallFunction(arity, VectorSlotPair(),
392 ConvertReceiverMode::kAny,
393 TailCallMode::kDisallow));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 return Changed(node);
395}
396
Ben Murdochda12d292016-06-02 14:46:10 +0100397Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +0100398 return Change(node, CodeFactory::FastNewObject(isolate()), 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399}
400
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
402 Node* active_function = NodeProperties::GetValueInput(node, 0);
403 Node* effect = NodeProperties::GetEffectInput(node);
404 Node* control = NodeProperties::GetControlInput(node);
405 Node* active_function_map = effect =
406 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
407 active_function, effect, control);
408 return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
409 active_function_map, effect, control);
410}
411
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
413 Node* b) {
414 RelaxControls(node);
415 node->ReplaceInput(0, a);
416 node->ReplaceInput(1, b);
417 node->TrimInputCount(2);
418 NodeProperties::ChangeOp(node, op);
419 return Changed(node);
420}
421
422
423Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
424 Node* b, Node* c) {
425 RelaxControls(node);
426 node->ReplaceInput(0, a);
427 node->ReplaceInput(1, b);
428 node->ReplaceInput(2, c);
429 node->TrimInputCount(3);
430 NodeProperties::ChangeOp(node, op);
431 return Changed(node);
432}
433
434
435Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
436 Node* b, Node* c, Node* d) {
437 RelaxControls(node);
438 node->ReplaceInput(0, a);
439 node->ReplaceInput(1, b);
440 node->ReplaceInput(2, c);
441 node->ReplaceInput(3, d);
442 node->TrimInputCount(4);
443 NodeProperties::ChangeOp(node, op);
444 return Changed(node);
445}
446
447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
449 int stack_parameter_count) {
450 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
451 isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
452 CallDescriptor::kNeedsFrameState, node->op()->properties());
453 node->InsertInput(graph()->zone(), 0,
454 jsgraph()->HeapConstant(callable.code()));
455 NodeProperties::ChangeOp(node, common()->Call(desc));
456 return Changed(node);
457}
458
459
460Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
461
462
463Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
464
465
466CommonOperatorBuilder* JSIntrinsicLowering::common() const {
467 return jsgraph()->common();
468}
469
470JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
471 return jsgraph_->javascript();
472}
473
474
475MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
476 return jsgraph()->machine();
477}
478
479
480SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
481 return jsgraph()->simplified();
482}
483
484} // namespace compiler
485} // namespace internal
486} // namespace v8