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