• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
JSIntrinsicLowering(Editor * editor,JSGraph * jsgraph,DeoptimizationMode mode)23 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
24                                          DeoptimizationMode mode)
25     : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {}
26 
Reduce(Node * node)27 Reduction 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::kInlineDebugIsActive:
36       return ReduceDebugIsActive(node);
37     case Runtime::kInlineDeoptimizeNow:
38       return ReduceDeoptimizeNow(node);
39     case Runtime::kInlineGeneratorClose:
40       return ReduceGeneratorClose(node);
41     case Runtime::kInlineGeneratorGetInputOrDebugPos:
42       return ReduceGeneratorGetInputOrDebugPos(node);
43     case Runtime::kInlineGeneratorGetResumeMode:
44       return ReduceGeneratorGetResumeMode(node);
45     case Runtime::kInlineGeneratorGetContext:
46       return ReduceGeneratorGetContext(node);
47     case Runtime::kInlineIsArray:
48       return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
49     case Runtime::kInlineIsTypedArray:
50       return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
51     case Runtime::kInlineIsJSProxy:
52       return ReduceIsInstanceType(node, JS_PROXY_TYPE);
53     case Runtime::kInlineIsJSReceiver:
54       return ReduceIsJSReceiver(node);
55     case Runtime::kInlineIsSmi:
56       return ReduceIsSmi(node);
57     case Runtime::kInlineFixedArrayGet:
58       return ReduceFixedArrayGet(node);
59     case Runtime::kInlineFixedArraySet:
60       return ReduceFixedArraySet(node);
61     case Runtime::kInlineSubString:
62       return ReduceSubString(node);
63     case Runtime::kInlineToInteger:
64       return ReduceToInteger(node);
65     case Runtime::kInlineToLength:
66       return ReduceToLength(node);
67     case Runtime::kInlineToNumber:
68       return ReduceToNumber(node);
69     case Runtime::kInlineToObject:
70       return ReduceToObject(node);
71     case Runtime::kInlineToString:
72       return ReduceToString(node);
73     case Runtime::kInlineCall:
74       return ReduceCall(node);
75     case Runtime::kInlineGetSuperConstructor:
76       return ReduceGetSuperConstructor(node);
77     case Runtime::kInlineArrayBufferViewGetByteLength:
78       return ReduceArrayBufferViewField(
79           node, AccessBuilder::ForJSArrayBufferViewByteLength());
80     case Runtime::kInlineArrayBufferViewGetByteOffset:
81       return ReduceArrayBufferViewField(
82           node, AccessBuilder::ForJSArrayBufferViewByteOffset());
83     case Runtime::kInlineMaxSmi:
84       return ReduceMaxSmi(node);
85     case Runtime::kInlineTypedArrayGetLength:
86       return ReduceArrayBufferViewField(node,
87                                         AccessBuilder::ForJSTypedArrayLength());
88     case Runtime::kInlineTypedArrayMaxSizeInHeap:
89       return ReduceTypedArrayMaxSizeInHeap(node);
90     case Runtime::kInlineJSCollectionGetTable:
91       return ReduceJSCollectionGetTable(node);
92     case Runtime::kInlineStringGetRawHashField:
93       return ReduceStringGetRawHashField(node);
94     case Runtime::kInlineTheHole:
95       return ReduceTheHole(node);
96     case Runtime::kInlineClassOf:
97       return ReduceClassOf(node);
98     default:
99       break;
100   }
101   return NoChange();
102 }
103 
104 
ReduceCreateIterResultObject(Node * node)105 Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
106   Node* const value = NodeProperties::GetValueInput(node, 0);
107   Node* const done = NodeProperties::GetValueInput(node, 1);
108   Node* const context = NodeProperties::GetContextInput(node);
109   Node* const effect = NodeProperties::GetEffectInput(node);
110   return Change(node, javascript()->CreateIterResultObject(), value, done,
111                 context, effect);
112 }
113 
ReduceDebugIsActive(Node * node)114 Reduction JSIntrinsicLowering::ReduceDebugIsActive(Node* node) {
115   Node* const value = jsgraph()->ExternalConstant(
116       ExternalReference::debug_is_active_address(isolate()));
117   Node* const effect = NodeProperties::GetEffectInput(node);
118   Node* const control = NodeProperties::GetControlInput(node);
119   Operator const* const op =
120       simplified()->LoadField(AccessBuilder::ForExternalUint8Value());
121   return Change(node, op, value, effect, control);
122 }
123 
ReduceDeoptimizeNow(Node * node)124 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
125   if (mode() != kDeoptimizationEnabled) return NoChange();
126   Node* const frame_state = NodeProperties::GetFrameStateInput(node);
127   Node* const effect = NodeProperties::GetEffectInput(node);
128   Node* const control = NodeProperties::GetControlInput(node);
129 
130   // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
131   Node* deoptimize = graph()->NewNode(
132       common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason),
133       frame_state, effect, control);
134   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
135   Revisit(graph()->end());
136 
137   node->TrimInputCount(0);
138   NodeProperties::ChangeOp(node, common()->Dead());
139   return Changed(node);
140 }
141 
ReduceGeneratorClose(Node * node)142 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
143   Node* const generator = NodeProperties::GetValueInput(node, 0);
144   Node* const effect = NodeProperties::GetEffectInput(node);
145   Node* const control = NodeProperties::GetControlInput(node);
146   Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
147   Node* const undefined = jsgraph()->UndefinedConstant();
148   Operator const* const op = simplified()->StoreField(
149       AccessBuilder::ForJSGeneratorObjectContinuation());
150 
151   ReplaceWithValue(node, undefined, node);
152   NodeProperties::RemoveType(node);
153   return Change(node, op, generator, closed, effect, control);
154 }
155 
ReduceGeneratorGetInputOrDebugPos(Node * node)156 Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
157   Node* const generator = NodeProperties::GetValueInput(node, 0);
158   Node* const effect = NodeProperties::GetEffectInput(node);
159   Node* const control = NodeProperties::GetControlInput(node);
160   Operator const* const op = simplified()->LoadField(
161       AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
162 
163   return Change(node, op, generator, effect, control);
164 }
165 
ReduceGeneratorGetContext(Node * node)166 Reduction JSIntrinsicLowering::ReduceGeneratorGetContext(Node* node) {
167   Node* const generator = NodeProperties::GetValueInput(node, 0);
168   Node* const effect = NodeProperties::GetEffectInput(node);
169   Node* const control = NodeProperties::GetControlInput(node);
170   Operator const* const op =
171       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
172 
173   return Change(node, op, generator, effect, control);
174 }
175 
ReduceGeneratorGetResumeMode(Node * node)176 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
177   Node* const generator = NodeProperties::GetValueInput(node, 0);
178   Node* const effect = NodeProperties::GetEffectInput(node);
179   Node* const control = NodeProperties::GetControlInput(node);
180   Operator const* const op =
181       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
182 
183   return Change(node, op, generator, effect, control);
184 }
185 
ReduceIsInstanceType(Node * node,InstanceType instance_type)186 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
187     Node* node, InstanceType instance_type) {
188   // if (%_IsSmi(value)) {
189   //   return false;
190   // } else {
191   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
192   // }
193   Node* value = NodeProperties::GetValueInput(node, 0);
194   Node* effect = NodeProperties::GetEffectInput(node);
195   Node* control = NodeProperties::GetControlInput(node);
196 
197   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
198   Node* branch = graph()->NewNode(common()->Branch(), check, control);
199 
200   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
201   Node* etrue = effect;
202   Node* vtrue = jsgraph()->FalseConstant();
203 
204   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
205   Node* efalse = graph()->NewNode(
206       simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
207       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
208                        effect, if_false),
209       effect, if_false);
210   Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse,
211                                   jsgraph()->Constant(instance_type));
212 
213   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
214 
215   // Replace all effect uses of {node} with the {ephi}.
216   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
217   ReplaceWithValue(node, node, ephi);
218 
219   // Turn the {node} into a Phi.
220   return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
221                 vfalse, merge);
222 }
223 
224 
ReduceIsJSReceiver(Node * node)225 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
226   return Change(node, simplified()->ObjectIsReceiver());
227 }
228 
229 
ReduceIsSmi(Node * node)230 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
231   return Change(node, simplified()->ObjectIsSmi());
232 }
233 
234 
Change(Node * node,const Operator * op)235 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
236   // Replace all effect uses of {node} with the effect dependency.
237   RelaxEffectsAndControls(node);
238   // Remove the inputs corresponding to context, effect and control.
239   NodeProperties::RemoveNonValueInputs(node);
240   // Finally update the operator to the new one.
241   NodeProperties::ChangeOp(node, op);
242   return Changed(node);
243 }
244 
245 
ReduceFixedArrayGet(Node * node)246 Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
247   Node* base = node->InputAt(0);
248   Node* index = node->InputAt(1);
249   Node* effect = NodeProperties::GetEffectInput(node);
250   Node* control = NodeProperties::GetControlInput(node);
251   return Change(
252       node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
253       base, index, effect, control);
254 }
255 
256 
ReduceFixedArraySet(Node * node)257 Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
258   Node* base = node->InputAt(0);
259   Node* index = node->InputAt(1);
260   Node* value = node->InputAt(2);
261   Node* effect = NodeProperties::GetEffectInput(node);
262   Node* control = NodeProperties::GetControlInput(node);
263   Node* store = (graph()->NewNode(
264       simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
265       index, value, effect, control));
266   ReplaceWithValue(node, value, store);
267   return Changed(store);
268 }
269 
270 
ReduceSubString(Node * node)271 Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
272   return Change(node, CodeFactory::SubString(isolate()), 3);
273 }
274 
275 
ReduceToInteger(Node * node)276 Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
277   NodeProperties::ChangeOp(node, javascript()->ToInteger());
278   return Changed(node);
279 }
280 
281 
ReduceToNumber(Node * node)282 Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
283   NodeProperties::ChangeOp(node, javascript()->ToNumber());
284   return Changed(node);
285 }
286 
287 
ReduceToLength(Node * node)288 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
289   NodeProperties::ChangeOp(node, javascript()->ToLength());
290   return Changed(node);
291 }
292 
293 
ReduceToObject(Node * node)294 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
295   NodeProperties::ChangeOp(node, javascript()->ToObject());
296   return Changed(node);
297 }
298 
299 
ReduceToString(Node * node)300 Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
301   NodeProperties::ChangeOp(node, javascript()->ToString());
302   return Changed(node);
303 }
304 
305 
ReduceCall(Node * node)306 Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
307   size_t const arity = CallRuntimeParametersOf(node->op()).arity();
308   NodeProperties::ChangeOp(
309       node,
310       javascript()->Call(arity, 0.0f, VectorSlotPair(),
311                          ConvertReceiverMode::kAny, TailCallMode::kDisallow));
312   return Changed(node);
313 }
314 
ReduceGetSuperConstructor(Node * node)315 Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
316   Node* active_function = NodeProperties::GetValueInput(node, 0);
317   Node* effect = NodeProperties::GetEffectInput(node);
318   Node* control = NodeProperties::GetControlInput(node);
319   Node* active_function_map = effect =
320       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
321                        active_function, effect, control);
322   return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
323                 active_function_map, effect, control);
324 }
325 
ReduceArrayBufferViewField(Node * node,FieldAccess const & access)326 Reduction JSIntrinsicLowering::ReduceArrayBufferViewField(
327     Node* node, FieldAccess const& access) {
328   Node* receiver = NodeProperties::GetValueInput(node, 0);
329   Node* effect = NodeProperties::GetEffectInput(node);
330   Node* control = NodeProperties::GetControlInput(node);
331 
332   // Load the {receiver}s field.
333   Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
334                                           receiver, effect, control);
335 
336   // Check if the {receiver}s buffer was neutered.
337   Node* receiver_buffer = effect = graph()->NewNode(
338       simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
339       receiver, effect, control);
340   Node* check = effect = graph()->NewNode(
341       simplified()->ArrayBufferWasNeutered(), receiver_buffer, effect, control);
342 
343   // Default to zero if the {receiver}s buffer was neutered.
344   value = graph()->NewNode(
345       common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
346       check, jsgraph()->ZeroConstant(), value);
347 
348   ReplaceWithValue(node, value, effect, control);
349   return Replace(value);
350 }
351 
ReduceMaxSmi(Node * node)352 Reduction JSIntrinsicLowering::ReduceMaxSmi(Node* node) {
353   Node* value = jsgraph()->Constant(Smi::kMaxValue);
354   ReplaceWithValue(node, value);
355   return Replace(value);
356 }
357 
ReduceTypedArrayMaxSizeInHeap(Node * node)358 Reduction JSIntrinsicLowering::ReduceTypedArrayMaxSizeInHeap(Node* node) {
359   Node* value = jsgraph()->Constant(FLAG_typed_array_max_size_in_heap);
360   ReplaceWithValue(node, value);
361   return Replace(value);
362 }
363 
ReduceJSCollectionGetTable(Node * node)364 Reduction JSIntrinsicLowering::ReduceJSCollectionGetTable(Node* node) {
365   Node* collection = NodeProperties::GetValueInput(node, 0);
366   Node* effect = NodeProperties::GetEffectInput(node);
367   Node* control = NodeProperties::GetControlInput(node);
368   return Change(node,
369                 simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
370                 collection, effect, control);
371 }
372 
ReduceStringGetRawHashField(Node * node)373 Reduction JSIntrinsicLowering::ReduceStringGetRawHashField(Node* node) {
374   Node* string = NodeProperties::GetValueInput(node, 0);
375   Node* effect = NodeProperties::GetEffectInput(node);
376   Node* control = NodeProperties::GetControlInput(node);
377   return Change(node,
378                 simplified()->LoadField(AccessBuilder::ForNameHashField()),
379                 string, effect, control);
380 }
381 
ReduceTheHole(Node * node)382 Reduction JSIntrinsicLowering::ReduceTheHole(Node* node) {
383   Node* value = jsgraph()->TheHoleConstant();
384   ReplaceWithValue(node, value);
385   return Replace(value);
386 }
387 
ReduceClassOf(Node * node)388 Reduction JSIntrinsicLowering::ReduceClassOf(Node* node) {
389   RelaxEffectsAndControls(node);
390   node->TrimInputCount(2);
391   NodeProperties::ChangeOp(node, javascript()->ClassOf());
392   return Changed(node);
393 }
394 
Change(Node * node,const Operator * op,Node * a,Node * b)395 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
396                                       Node* b) {
397   RelaxControls(node);
398   node->ReplaceInput(0, a);
399   node->ReplaceInput(1, b);
400   node->TrimInputCount(2);
401   NodeProperties::ChangeOp(node, op);
402   return Changed(node);
403 }
404 
405 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c)406 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
407                                       Node* b, Node* c) {
408   RelaxControls(node);
409   node->ReplaceInput(0, a);
410   node->ReplaceInput(1, b);
411   node->ReplaceInput(2, c);
412   node->TrimInputCount(3);
413   NodeProperties::ChangeOp(node, op);
414   return Changed(node);
415 }
416 
417 
Change(Node * node,const Operator * op,Node * a,Node * b,Node * c,Node * d)418 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
419                                       Node* b, Node* c, Node* d) {
420   RelaxControls(node);
421   node->ReplaceInput(0, a);
422   node->ReplaceInput(1, b);
423   node->ReplaceInput(2, c);
424   node->ReplaceInput(3, d);
425   node->TrimInputCount(4);
426   NodeProperties::ChangeOp(node, op);
427   return Changed(node);
428 }
429 
430 
Change(Node * node,Callable const & callable,int stack_parameter_count)431 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
432                                       int stack_parameter_count) {
433   CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
434       isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
435       CallDescriptor::kNeedsFrameState, node->op()->properties());
436   node->InsertInput(graph()->zone(), 0,
437                     jsgraph()->HeapConstant(callable.code()));
438   NodeProperties::ChangeOp(node, common()->Call(desc));
439   return Changed(node);
440 }
441 
442 
graph() const443 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
444 
445 
isolate() const446 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
447 
448 
common() const449 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
450   return jsgraph()->common();
451 }
452 
javascript() const453 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
454   return jsgraph_->javascript();
455 }
456 
simplified() const457 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
458   return jsgraph()->simplified();
459 }
460 
461 }  // namespace compiler
462 }  // namespace internal
463 }  // namespace v8
464