deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / js-intrinsic-lowering.cc
1
2 // Copyright 2015 the V8 project authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "src/compiler/js-intrinsic-lowering.h"
7
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/node-properties.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17 JSIntrinsicLowering::JSIntrinsicLowering(JSGraph* jsgraph)
18     : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
19
20
21 Reduction JSIntrinsicLowering::Reduce(Node* node) {
22   if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
23   const Runtime::Function* const f =
24       Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
25   if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
26   switch (f->function_id) {
27     case Runtime::kInlineConstructDouble:
28       return ReduceConstructDouble(node);
29     case Runtime::kInlineDeoptimizeNow:
30       return ReduceDeoptimizeNow(node);
31     case Runtime::kInlineDoubleHi:
32       return ReduceDoubleHi(node);
33     case Runtime::kInlineDoubleLo:
34       return ReduceDoubleLo(node);
35     case Runtime::kInlineHeapObjectGetMap:
36       return ReduceHeapObjectGetMap(node);
37     case Runtime::kInlineIncrementStatsCounter:
38       return ReduceIncrementStatsCounter(node);
39     case Runtime::kInlineIsArray:
40       return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
41     case Runtime::kInlineIsFunction:
42       return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
43     case Runtime::kInlineIsNonNegativeSmi:
44       return ReduceIsNonNegativeSmi(node);
45     case Runtime::kInlineIsRegExp:
46       return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
47     case Runtime::kInlineIsSmi:
48       return ReduceIsSmi(node);
49     case Runtime::kInlineJSValueGetValue:
50       return ReduceJSValueGetValue(node);
51     case Runtime::kInlineMapGetInstanceType:
52       return ReduceMapGetInstanceType(node);
53     case Runtime::kInlineMathClz32:
54       return ReduceMathClz32(node);
55     case Runtime::kInlineMathFloor:
56       return ReduceMathFloor(node);
57     case Runtime::kInlineMathSqrt:
58       return ReduceMathSqrt(node);
59     case Runtime::kInlineOneByteSeqStringGetChar:
60       return ReduceSeqStringGetChar(node, String::ONE_BYTE_ENCODING);
61     case Runtime::kInlineOneByteSeqStringSetChar:
62       return ReduceSeqStringSetChar(node, String::ONE_BYTE_ENCODING);
63     case Runtime::kInlineStringGetLength:
64       return ReduceStringGetLength(node);
65     case Runtime::kInlineTwoByteSeqStringGetChar:
66       return ReduceSeqStringGetChar(node, String::TWO_BYTE_ENCODING);
67     case Runtime::kInlineTwoByteSeqStringSetChar:
68       return ReduceSeqStringSetChar(node, String::TWO_BYTE_ENCODING);
69     case Runtime::kInlineValueOf:
70       return ReduceValueOf(node);
71     default:
72       break;
73   }
74   return NoChange();
75 }
76
77
78 Reduction JSIntrinsicLowering::ReduceConstructDouble(Node* node) {
79   Node* high = NodeProperties::GetValueInput(node, 0);
80   Node* low = NodeProperties::GetValueInput(node, 1);
81   Node* value =
82       graph()->NewNode(machine()->Float64InsertHighWord32(),
83                        graph()->NewNode(machine()->Float64InsertLowWord32(),
84                                         jsgraph()->Constant(0), low),
85                        high);
86   NodeProperties::ReplaceWithValue(node, value);
87   return Replace(value);
88 }
89
90
91 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
92   if (!FLAG_turbo_deoptimization) return NoChange();
93
94   Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
95   DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
96
97   Node* effect = NodeProperties::GetEffectInput(node);
98   Node* control = NodeProperties::GetControlInput(node);
99
100   // We are making the continuation after the call dead. To
101   // model this, we generate if (true) statement with deopt
102   // in the true branch and continuation in the false branch.
103   Node* branch =
104       graph()->NewNode(common()->Branch(), jsgraph()->TrueConstant(), control);
105
106   // False branch - the original continuation.
107   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
108   NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect,
109                                    if_false);
110
111   // True branch: deopt.
112   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
113   Node* deopt =
114       graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_true);
115
116   // Connect the deopt to the merge exiting the graph.
117   NodeProperties::MergeControlToEnd(graph(), common(), deopt);
118
119   return Changed(deopt);
120 }
121
122
123 Reduction JSIntrinsicLowering::ReduceDoubleHi(Node* node) {
124   return Change(node, machine()->Float64ExtractHighWord32());
125 }
126
127
128 Reduction JSIntrinsicLowering::ReduceDoubleLo(Node* node) {
129   return Change(node, machine()->Float64ExtractLowWord32());
130 }
131
132
133 Reduction JSIntrinsicLowering::ReduceHeapObjectGetMap(Node* node) {
134   Node* value = NodeProperties::GetValueInput(node, 0);
135   Node* effect = NodeProperties::GetEffectInput(node);
136   Node* control = NodeProperties::GetControlInput(node);
137   return Change(node, simplified()->LoadField(AccessBuilder::ForMap()), value,
138                 effect, control);
139 }
140
141
142 Reduction JSIntrinsicLowering::ReduceIncrementStatsCounter(Node* node) {
143   if (!FLAG_native_code_counters) return ChangeToUndefined(node);
144   HeapObjectMatcher<String> m(NodeProperties::GetValueInput(node, 0));
145   if (!m.HasValue() || !m.Value().handle()->IsString()) {
146     return ChangeToUndefined(node);
147   }
148   SmartArrayPointer<char> name = m.Value().handle()->ToCString();
149   StatsCounter counter(jsgraph()->isolate(), name.get());
150   if (!counter.Enabled()) return ChangeToUndefined(node);
151
152   Node* effect = NodeProperties::GetEffectInput(node);
153   Node* control = NodeProperties::GetControlInput(node);
154   FieldAccess access = AccessBuilder::ForStatsCounter();
155   Node* cnt = jsgraph()->ExternalConstant(ExternalReference(&counter));
156   Node* load =
157       graph()->NewNode(simplified()->LoadField(access), cnt, effect, control);
158   Node* inc =
159       graph()->NewNode(machine()->Int32Add(), load, jsgraph()->OneConstant());
160   Node* store = graph()->NewNode(simplified()->StoreField(access), cnt, inc,
161                                  load, control);
162   return ChangeToUndefined(node, store);
163 }
164
165
166 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
167     Node* node, InstanceType instance_type) {
168   // if (%_IsSmi(value)) {
169   //   return false;
170   // } else {
171   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
172   // }
173   MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
174
175   Node* value = NodeProperties::GetValueInput(node, 0);
176   Node* effect = NodeProperties::GetEffectInput(node);
177   Node* control = NodeProperties::GetControlInput(node);
178
179   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
180   Node* branch = graph()->NewNode(common()->Branch(), check, control);
181
182   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
183   Node* etrue = effect;
184   Node* vtrue = jsgraph()->FalseConstant();
185
186   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
187   Node* efalse = graph()->NewNode(
188       simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
189       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
190                        effect, if_false),
191       effect, if_false);
192   Node* vfalse = graph()->NewNode(machine()->Word32Equal(), efalse,
193                                   jsgraph()->Int32Constant(instance_type));
194
195   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
196
197   // Replace all effect uses of {node} with the {ephi}.
198   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
199   NodeProperties::ReplaceWithValue(node, node, ephi);
200
201   // Turn the {node} into a Phi.
202   return Change(node, common()->Phi(type, 2), vtrue, vfalse, merge);
203 }
204
205
206 Reduction JSIntrinsicLowering::ReduceIsNonNegativeSmi(Node* node) {
207   return Change(node, simplified()->ObjectIsNonNegativeSmi());
208 }
209
210
211 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
212   return Change(node, simplified()->ObjectIsSmi());
213 }
214
215
216 Reduction JSIntrinsicLowering::ReduceJSValueGetValue(Node* node) {
217   Node* value = NodeProperties::GetValueInput(node, 0);
218   Node* effect = NodeProperties::GetEffectInput(node);
219   Node* control = NodeProperties::GetControlInput(node);
220   return Change(node, simplified()->LoadField(AccessBuilder::ForValue()), value,
221                 effect, control);
222 }
223
224
225 Reduction JSIntrinsicLowering::ReduceMapGetInstanceType(Node* node) {
226   Node* value = NodeProperties::GetValueInput(node, 0);
227   Node* effect = NodeProperties::GetEffectInput(node);
228   Node* control = NodeProperties::GetControlInput(node);
229   return Change(node,
230                 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
231                 value, effect, control);
232 }
233
234
235 Reduction JSIntrinsicLowering::ReduceMathClz32(Node* node) {
236   return Change(node, machine()->Word32Clz());
237 }
238
239
240 Reduction JSIntrinsicLowering::ReduceMathFloor(Node* node) {
241   if (!machine()->HasFloat64RoundDown()) return NoChange();
242   return Change(node, machine()->Float64RoundDown());
243 }
244
245
246 Reduction JSIntrinsicLowering::ReduceMathSqrt(Node* node) {
247   return Change(node, machine()->Float64Sqrt());
248 }
249
250
251 Reduction JSIntrinsicLowering::ReduceSeqStringGetChar(
252     Node* node, String::Encoding encoding) {
253   Node* effect = NodeProperties::GetEffectInput(node);
254   Node* control = NodeProperties::GetControlInput(node);
255   node->set_op(
256       simplified()->LoadElement(AccessBuilder::ForSeqStringChar(encoding)));
257   node->ReplaceInput(2, effect);
258   node->ReplaceInput(3, control);
259   node->TrimInputCount(4);
260   NodeProperties::ReplaceWithValue(node, node, node);
261   return Changed(node);
262 }
263
264
265 Reduction JSIntrinsicLowering::ReduceSeqStringSetChar(
266     Node* node, String::Encoding encoding) {
267   // Note: The intrinsic has a strange argument order, so we need to reshuffle.
268   Node* index = NodeProperties::GetValueInput(node, 0);
269   Node* chr = NodeProperties::GetValueInput(node, 1);
270   Node* string = NodeProperties::GetValueInput(node, 2);
271   Node* effect = NodeProperties::GetEffectInput(node);
272   Node* control = NodeProperties::GetControlInput(node);
273   node->set_op(
274       simplified()->StoreElement(AccessBuilder::ForSeqStringChar(encoding)));
275   node->ReplaceInput(0, string);
276   node->ReplaceInput(1, index);
277   node->ReplaceInput(2, chr);
278   node->ReplaceInput(3, effect);
279   node->ReplaceInput(4, control);
280   node->TrimInputCount(5);
281   NodeProperties::RemoveBounds(node);
282   NodeProperties::ReplaceWithValue(node, string, node);
283   return Changed(node);
284 }
285
286
287 Reduction JSIntrinsicLowering::ReduceStringGetLength(Node* node) {
288   Node* value = NodeProperties::GetValueInput(node, 0);
289   Node* effect = NodeProperties::GetEffectInput(node);
290   Node* control = NodeProperties::GetControlInput(node);
291   return Change(node, simplified()->LoadField(AccessBuilder::ForStringLength()),
292                 value, effect, control);
293 }
294
295
296 Reduction JSIntrinsicLowering::ReduceValueOf(Node* node) {
297   // if (%_IsSmi(value)) {
298   //   return value;
299   // } else if (%_GetInstanceType(%_GetMap(value)) == JS_VALUE_TYPE) {
300   //   return %_GetValue(value);
301   // } else {
302   //   return value;
303   // }
304   const Operator* const merge_op = common()->Merge(2);
305   const Operator* const ephi_op = common()->EffectPhi(2);
306   const Operator* const phi_op = common()->Phi(kMachAnyTagged, 2);
307
308   Node* value = NodeProperties::GetValueInput(node, 0);
309   Node* effect = NodeProperties::GetEffectInput(node);
310   Node* control = NodeProperties::GetControlInput(node);
311
312   Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
313   Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);
314
315   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
316   Node* etrue0 = effect;
317   Node* vtrue0 = value;
318
319   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
320   Node* efalse0;
321   Node* vfalse0;
322   {
323     Node* check1 = graph()->NewNode(
324         machine()->Word32Equal(),
325         graph()->NewNode(
326             simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
327             graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
328                              value, effect, if_false0),
329             effect, if_false0),
330         jsgraph()->Int32Constant(JS_VALUE_TYPE));
331     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
332
333     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
334     Node* etrue1 =
335         graph()->NewNode(simplified()->LoadField(AccessBuilder::ForValue()),
336                          value, effect, if_true1);
337     Node* vtrue1 = etrue1;
338
339     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
340     Node* efalse1 = effect;
341     Node* vfalse1 = value;
342
343     Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
344     efalse0 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
345     vfalse0 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
346   }
347
348   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
349
350   // Replace all effect uses of {node} with the {ephi0}.
351   Node* ephi0 = graph()->NewNode(ephi_op, etrue0, efalse0, merge0);
352   NodeProperties::ReplaceWithValue(node, node, ephi0);
353
354   // Turn the {node} into a Phi.
355   return Change(node, phi_op, vtrue0, vfalse0, merge0);
356 }
357
358
359 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
360   // Replace all effect uses of {node} with the effect dependency.
361   NodeProperties::ReplaceWithValue(node, node);
362   // Remove the inputs corresponding to context, effect and control.
363   NodeProperties::RemoveNonValueInputs(node);
364   // Finally update the operator to the new one.
365   node->set_op(op);
366   return Changed(node);
367 }
368
369
370 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
371                                       Node* b, Node* c) {
372   node->set_op(op);
373   node->ReplaceInput(0, a);
374   node->ReplaceInput(1, b);
375   node->ReplaceInput(2, c);
376   node->TrimInputCount(3);
377   NodeProperties::ReplaceWithValue(node, node, node);
378   return Changed(node);
379 }
380
381
382 Reduction JSIntrinsicLowering::ChangeToUndefined(Node* node, Node* effect) {
383   NodeProperties::ReplaceWithValue(node, jsgraph()->UndefinedConstant(),
384                                    effect);
385   return Changed(node);
386 }
387
388
389 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
390
391
392 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
393   return jsgraph()->common();
394 }
395
396
397 MachineOperatorBuilder* JSIntrinsicLowering::machine() const {
398   return jsgraph()->machine();
399 }
400
401 }  // namespace compiler
402 }  // namespace internal
403 }  // namespace v8