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
19namespace v8 {
20namespace internal {
21namespace compiler {
22
23JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
24                                         DeoptimizationMode mode)
25    : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {}
26
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::kInlineCreateIterResultObject:
34      return ReduceCreateIterResultObject(node);
35    case Runtime::kInlineDeoptimizeNow:
36      return ReduceDeoptimizeNow(node);
37    case Runtime::kInlineGeneratorClose:
38      return ReduceGeneratorClose(node);
39    case Runtime::kInlineGeneratorGetInputOrDebugPos:
40      return ReduceGeneratorGetInputOrDebugPos(node);
41    case Runtime::kInlineGeneratorGetResumeMode:
42      return ReduceGeneratorGetResumeMode(node);
43    case Runtime::kInlineIsArray:
44      return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
45    case Runtime::kInlineIsTypedArray:
46      return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
47    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);
53    case Runtime::kInlineFixedArrayGet:
54      return ReduceFixedArrayGet(node);
55    case Runtime::kInlineFixedArraySet:
56      return ReduceFixedArraySet(node);
57    case Runtime::kInlineRegExpExec:
58      return ReduceRegExpExec(node);
59    case Runtime::kInlineSubString:
60      return ReduceSubString(node);
61    case Runtime::kInlineToInteger:
62      return ReduceToInteger(node);
63    case Runtime::kInlineToLength:
64      return ReduceToLength(node);
65    case Runtime::kInlineToNumber:
66      return ReduceToNumber(node);
67    case Runtime::kInlineToObject:
68      return ReduceToObject(node);
69    case Runtime::kInlineToString:
70      return ReduceToString(node);
71    case Runtime::kInlineCall:
72      return ReduceCall(node);
73    case Runtime::kInlineNewObject:
74      return ReduceNewObject(node);
75    case Runtime::kInlineGetSuperConstructor:
76      return ReduceGetSuperConstructor(node);
77    default:
78      break;
79  }
80  return NoChange();
81}
82
83
84Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
85  Node* const value = NodeProperties::GetValueInput(node, 0);
86  Node* const done = NodeProperties::GetValueInput(node, 1);
87  Node* const context = NodeProperties::GetContextInput(node);
88  Node* const effect = NodeProperties::GetEffectInput(node);
89  return Change(node, javascript()->CreateIterResultObject(), value, done,
90                context, effect);
91}
92
93
94Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
95  if (mode() != kDeoptimizationEnabled) return NoChange();
96  Node* const frame_state = NodeProperties::GetFrameStateInput(node);
97  Node* const effect = NodeProperties::GetEffectInput(node);
98  Node* const control = NodeProperties::GetControlInput(node);
99
100  // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
101  Node* deoptimize = graph()->NewNode(
102      common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason),
103      frame_state, effect, control);
104  NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
105  Revisit(graph()->end());
106
107  node->TrimInputCount(0);
108  NodeProperties::ChangeOp(node, common()->Dead());
109  return Changed(node);
110}
111
112Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
113  Node* const generator = NodeProperties::GetValueInput(node, 0);
114  Node* const effect = NodeProperties::GetEffectInput(node);
115  Node* const control = NodeProperties::GetControlInput(node);
116  Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
117  Node* const undefined = jsgraph()->UndefinedConstant();
118  Operator const* const op = simplified()->StoreField(
119      AccessBuilder::ForJSGeneratorObjectContinuation());
120
121  ReplaceWithValue(node, undefined, node);
122  NodeProperties::RemoveType(node);
123  return Change(node, op, generator, closed, effect, control);
124}
125
126Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
127  Node* const generator = NodeProperties::GetValueInput(node, 0);
128  Node* const effect = NodeProperties::GetEffectInput(node);
129  Node* const control = NodeProperties::GetControlInput(node);
130  Operator const* const op = simplified()->LoadField(
131      AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
132
133  return Change(node, op, generator, effect, control);
134}
135
136Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
137  Node* const generator = NodeProperties::GetValueInput(node, 0);
138  Node* const effect = NodeProperties::GetEffectInput(node);
139  Node* const control = NodeProperties::GetControlInput(node);
140  Operator const* const op =
141      simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
142
143  return Change(node, op, generator, effect, control);
144}
145
146Reduction JSIntrinsicLowering::ReduceIsInstanceType(
147    Node* node, InstanceType instance_type) {
148  // if (%_IsSmi(value)) {
149  //   return false;
150  // } else {
151  //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
152  // }
153  Node* value = NodeProperties::GetValueInput(node, 0);
154  Node* effect = NodeProperties::GetEffectInput(node);
155  Node* control = NodeProperties::GetControlInput(node);
156
157  Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
158  Node* branch = graph()->NewNode(common()->Branch(), check, control);
159
160  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
161  Node* etrue = effect;
162  Node* vtrue = jsgraph()->FalseConstant();
163
164  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
165  Node* efalse = graph()->NewNode(
166      simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
167      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
168                       effect, if_false),
169      effect, if_false);
170  Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse,
171                                  jsgraph()->Constant(instance_type));
172
173  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
174
175  // Replace all effect uses of {node} with the {ephi}.
176  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
177  ReplaceWithValue(node, node, ephi);
178
179  // Turn the {node} into a Phi.
180  return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
181                vfalse, merge);
182}
183
184
185Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
186  return Change(node, simplified()->ObjectIsReceiver());
187}
188
189
190Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
191  return Change(node, simplified()->ObjectIsSmi());
192}
193
194
195Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
196  // Replace all effect uses of {node} with the effect dependency.
197  RelaxEffectsAndControls(node);
198  // Remove the inputs corresponding to context, effect and control.
199  NodeProperties::RemoveNonValueInputs(node);
200  // Finally update the operator to the new one.
201  NodeProperties::ChangeOp(node, op);
202  return Changed(node);
203}
204
205
206Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
207  Node* base = node->InputAt(0);
208  Node* index = node->InputAt(1);
209  Node* effect = NodeProperties::GetEffectInput(node);
210  Node* control = NodeProperties::GetControlInput(node);
211  return Change(
212      node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
213      base, index, effect, control);
214}
215
216
217Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
218  Node* base = node->InputAt(0);
219  Node* index = node->InputAt(1);
220  Node* value = node->InputAt(2);
221  Node* effect = NodeProperties::GetEffectInput(node);
222  Node* control = NodeProperties::GetControlInput(node);
223  Node* store = (graph()->NewNode(
224      simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
225      index, value, effect, control));
226  ReplaceWithValue(node, value, store);
227  return Changed(store);
228}
229
230
231Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) {
232  return Change(node, CodeFactory::RegExpExec(isolate()), 4);
233}
234
235
236Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
237  return Change(node, CodeFactory::SubString(isolate()), 3);
238}
239
240
241Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
242  NodeProperties::ChangeOp(node, javascript()->ToInteger());
243  return Changed(node);
244}
245
246
247Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
248  NodeProperties::ChangeOp(node, javascript()->ToNumber());
249  return Changed(node);
250}
251
252
253Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
254  NodeProperties::ChangeOp(node, javascript()->ToLength());
255  return Changed(node);
256}
257
258
259Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
260  NodeProperties::ChangeOp(node, javascript()->ToObject());
261  return Changed(node);
262}
263
264
265Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
266  NodeProperties::ChangeOp(node, javascript()->ToString());
267  return Changed(node);
268}
269
270
271Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
272  size_t const arity = CallRuntimeParametersOf(node->op()).arity();
273  NodeProperties::ChangeOp(
274      node, javascript()->CallFunction(arity, 0.0f, VectorSlotPair(),
275                                       ConvertReceiverMode::kAny,
276                                       TailCallMode::kDisallow));
277  return Changed(node);
278}
279
280Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) {
281  return Change(node, CodeFactory::FastNewObject(isolate()), 0);
282}
283
284Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
285  Node* active_function = NodeProperties::GetValueInput(node, 0);
286  Node* effect = NodeProperties::GetEffectInput(node);
287  Node* control = NodeProperties::GetControlInput(node);
288  Node* active_function_map = effect =
289      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
290                       active_function, effect, control);
291  return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
292                active_function_map, effect, control);
293}
294
295Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
296                                      Node* b) {
297  RelaxControls(node);
298  node->ReplaceInput(0, a);
299  node->ReplaceInput(1, b);
300  node->TrimInputCount(2);
301  NodeProperties::ChangeOp(node, op);
302  return Changed(node);
303}
304
305
306Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
307                                      Node* b, Node* c) {
308  RelaxControls(node);
309  node->ReplaceInput(0, a);
310  node->ReplaceInput(1, b);
311  node->ReplaceInput(2, c);
312  node->TrimInputCount(3);
313  NodeProperties::ChangeOp(node, op);
314  return Changed(node);
315}
316
317
318Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
319                                      Node* b, Node* c, Node* d) {
320  RelaxControls(node);
321  node->ReplaceInput(0, a);
322  node->ReplaceInput(1, b);
323  node->ReplaceInput(2, c);
324  node->ReplaceInput(3, d);
325  node->TrimInputCount(4);
326  NodeProperties::ChangeOp(node, op);
327  return Changed(node);
328}
329
330
331Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
332                                      int stack_parameter_count) {
333  CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
334      isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
335      CallDescriptor::kNeedsFrameState, node->op()->properties());
336  node->InsertInput(graph()->zone(), 0,
337                    jsgraph()->HeapConstant(callable.code()));
338  NodeProperties::ChangeOp(node, common()->Call(desc));
339  return Changed(node);
340}
341
342
343Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
344
345
346Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
347
348
349CommonOperatorBuilder* JSIntrinsicLowering::common() const {
350  return jsgraph()->common();
351}
352
353JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
354  return jsgraph_->javascript();
355}
356
357SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
358  return jsgraph()->simplified();
359}
360
361}  // namespace compiler
362}  // namespace internal
363}  // namespace v8
364