1 // Copyright 2014 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/code-factory.h"
6 #include "src/compilation-dependencies.h"
7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-typed-lowering.h"
10 #include "src/compiler/linkage.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h"
14 #include "src/compiler/state-values-utils.h"
15 #include "src/type-cache.h"
16 #include "src/types.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 namespace {
23
24 // A helper class to construct inline allocations on the simplified operator
25 // level. This keeps track of the effect chain for initial stores on a newly
26 // allocated object and also provides helpers for commonly allocated objects.
27 class AllocationBuilder final {
28 public:
AllocationBuilder(JSGraph * jsgraph,Node * effect,Node * control)29 AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
30 : jsgraph_(jsgraph),
31 allocation_(nullptr),
32 effect_(effect),
33 control_(control) {}
34
35 // Primitive allocation of static size.
Allocate(int size,PretenureFlag pretenure=NOT_TENURED)36 void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) {
37 effect_ = graph()->NewNode(common()->BeginRegion(), effect_);
38 allocation_ =
39 graph()->NewNode(simplified()->Allocate(pretenure),
40 jsgraph()->Constant(size), effect_, control_);
41 effect_ = allocation_;
42 }
43
44 // Primitive store into a field.
Store(const FieldAccess & access,Node * value)45 void Store(const FieldAccess& access, Node* value) {
46 effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_,
47 value, effect_, control_);
48 }
49
50 // Primitive store into an element.
Store(ElementAccess const & access,Node * index,Node * value)51 void Store(ElementAccess const& access, Node* index, Node* value) {
52 effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_,
53 index, value, effect_, control_);
54 }
55
56 // Compound allocation of a FixedArray.
AllocateArray(int length,Handle<Map> map,PretenureFlag pretenure=NOT_TENURED)57 void AllocateArray(int length, Handle<Map> map,
58 PretenureFlag pretenure = NOT_TENURED) {
59 DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
60 map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
61 int size = (map->instance_type() == FIXED_ARRAY_TYPE)
62 ? FixedArray::SizeFor(length)
63 : FixedDoubleArray::SizeFor(length);
64 Allocate(size, pretenure);
65 Store(AccessBuilder::ForMap(), map);
66 Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length));
67 }
68
69 // Compound store of a constant into a field.
Store(const FieldAccess & access,Handle<Object> value)70 void Store(const FieldAccess& access, Handle<Object> value) {
71 Store(access, jsgraph()->Constant(value));
72 }
73
FinishAndChange(Node * node)74 void FinishAndChange(Node* node) {
75 NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
76 node->ReplaceInput(0, allocation_);
77 node->ReplaceInput(1, effect_);
78 node->TrimInputCount(2);
79 NodeProperties::ChangeOp(node, common()->FinishRegion());
80 }
81
Finish()82 Node* Finish() {
83 return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
84 }
85
86 protected:
jsgraph()87 JSGraph* jsgraph() { return jsgraph_; }
graph()88 Graph* graph() { return jsgraph_->graph(); }
common()89 CommonOperatorBuilder* common() { return jsgraph_->common(); }
simplified()90 SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
91
92 private:
93 JSGraph* const jsgraph_;
94 Node* allocation_;
95 Node* effect_;
96 Node* control_;
97 };
98
99 } // namespace
100
101
102 // A helper class to simplify the process of reducing a single binop node with a
103 // JSOperator. This class manages the rewriting of context, control, and effect
104 // dependencies during lowering of a binop and contains numerous helper
105 // functions for matching the types of inputs to an operation.
106 class JSBinopReduction final {
107 public:
JSBinopReduction(JSTypedLowering * lowering,Node * node)108 JSBinopReduction(JSTypedLowering* lowering, Node* node)
109 : lowering_(lowering), node_(node) {}
110
ConvertInputsToNumber(Node * frame_state)111 void ConvertInputsToNumber(Node* frame_state) {
112 // To convert the inputs to numbers, we have to provide frame states
113 // for lazy bailouts in the ToNumber conversions.
114 // We use a little hack here: we take the frame state before the binary
115 // operation and use it to construct the frame states for the conversion
116 // so that after the deoptimization, the binary operation IC gets
117 // already converted values from full code. This way we are sure that we
118 // will not re-do any of the side effects.
119
120 Node* left_input = nullptr;
121 Node* right_input = nullptr;
122 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
123 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
124 bool handles_exception = NodeProperties::IsExceptionalCall(node_);
125
126 if (!left_is_primitive && !right_is_primitive && handles_exception) {
127 ConvertBothInputsToNumber(&left_input, &right_input, frame_state);
128 } else {
129 left_input = left_is_primitive
130 ? ConvertPlainPrimitiveToNumber(left())
131 : ConvertSingleInputToNumber(
132 left(), CreateFrameStateForLeftInput(frame_state));
133 right_input = right_is_primitive
134 ? ConvertPlainPrimitiveToNumber(right())
135 : ConvertSingleInputToNumber(
136 right(), CreateFrameStateForRightInput(
137 frame_state, left_input));
138 }
139
140 node_->ReplaceInput(0, left_input);
141 node_->ReplaceInput(1, right_input);
142 }
143
ConvertInputsToUI32(Signedness left_signedness,Signedness right_signedness)144 void ConvertInputsToUI32(Signedness left_signedness,
145 Signedness right_signedness) {
146 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
147 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
148 }
149
SwapInputs()150 void SwapInputs() {
151 Node* l = left();
152 Node* r = right();
153 node_->ReplaceInput(0, r);
154 node_->ReplaceInput(1, l);
155 }
156
157 // Remove all effect and control inputs and outputs to this node and change
158 // to the pure operator {op}, possibly inserting a boolean inversion.
ChangeToPureOperator(const Operator * op,bool invert=false,Type * type=Type::Any ())159 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
160 Type* type = Type::Any()) {
161 DCHECK_EQ(0, op->EffectInputCount());
162 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
163 DCHECK_EQ(0, op->ControlInputCount());
164 DCHECK_EQ(2, op->ValueInputCount());
165
166 // Remove the effects from the node, and update its effect/control usages.
167 if (node_->op()->EffectInputCount() > 0) {
168 lowering_->RelaxEffectsAndControls(node_);
169 }
170 // Remove the inputs corresponding to context, effect, and control.
171 NodeProperties::RemoveNonValueInputs(node_);
172 // Finally, update the operator to the new one.
173 NodeProperties::ChangeOp(node_, op);
174
175 // TODO(jarin): Replace the explicit typing hack with a call to some method
176 // that encapsulates changing the operator and re-typing.
177 Type* node_type = NodeProperties::GetType(node_);
178 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
179
180 if (invert) {
181 // Insert an boolean not to invert the value.
182 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
183 node_->ReplaceUses(value);
184 // Note: ReplaceUses() smashes all uses, so smash it back here.
185 value->ReplaceInput(0, node_);
186 return lowering_->Replace(value);
187 }
188 return lowering_->Changed(node_);
189 }
190
ChangeToStringComparisonOperator(const Operator * op,bool invert=false)191 Reduction ChangeToStringComparisonOperator(const Operator* op,
192 bool invert = false) {
193 if (node_->op()->ControlInputCount() > 0) {
194 lowering_->RelaxControls(node_);
195 }
196 // String comparison operators need effect and control inputs, so copy them
197 // over.
198 Node* effect = NodeProperties::GetEffectInput(node_);
199 Node* control = NodeProperties::GetControlInput(node_);
200 node_->ReplaceInput(2, effect);
201 node_->ReplaceInput(3, control);
202
203 node_->TrimInputCount(4);
204 NodeProperties::ChangeOp(node_, op);
205
206 if (invert) {
207 // Insert a boolean-not to invert the value.
208 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
209 node_->ReplaceUses(value);
210 // Note: ReplaceUses() smashes all uses, so smash it back here.
211 value->ReplaceInput(0, node_);
212 return lowering_->Replace(value);
213 }
214 return lowering_->Changed(node_);
215 }
216
ChangeToPureOperator(const Operator * op,Type * type)217 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
218 return ChangeToPureOperator(op, false, type);
219 }
220
221 // TODO(turbofan): Strong mode should be killed soonish!
IsStrong() const222 bool IsStrong() const {
223 if (node_->opcode() == IrOpcode::kJSLessThan ||
224 node_->opcode() == IrOpcode::kJSLessThanOrEqual ||
225 node_->opcode() == IrOpcode::kJSGreaterThan ||
226 node_->opcode() == IrOpcode::kJSGreaterThanOrEqual) {
227 return is_strong(OpParameter<LanguageMode>(node_));
228 }
229 return is_strong(BinaryOperationParametersOf(node_->op()).language_mode());
230 }
231
LeftInputIs(Type * t)232 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
233
RightInputIs(Type * t)234 bool RightInputIs(Type* t) { return right_type()->Is(t); }
235
OneInputIs(Type * t)236 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
237
BothInputsAre(Type * t)238 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
239
OneInputCannotBe(Type * t)240 bool OneInputCannotBe(Type* t) {
241 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
242 }
243
NeitherInputCanBe(Type * t)244 bool NeitherInputCanBe(Type* t) {
245 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
246 }
247
effect()248 Node* effect() { return NodeProperties::GetEffectInput(node_); }
control()249 Node* control() { return NodeProperties::GetControlInput(node_); }
context()250 Node* context() { return NodeProperties::GetContextInput(node_); }
left()251 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
right()252 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
left_type()253 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
right_type()254 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
255
simplified()256 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
graph() const257 Graph* graph() const { return lowering_->graph(); }
jsgraph()258 JSGraph* jsgraph() { return lowering_->jsgraph(); }
javascript()259 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
machine()260 MachineOperatorBuilder* machine() { return lowering_->machine(); }
common()261 CommonOperatorBuilder* common() { return jsgraph()->common(); }
zone() const262 Zone* zone() const { return graph()->zone(); }
263
264 private:
265 JSTypedLowering* lowering_; // The containing lowering instance.
266 Node* node_; // The original node.
267
CreateFrameStateForLeftInput(Node * frame_state)268 Node* CreateFrameStateForLeftInput(Node* frame_state) {
269 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
270
271 if (state_info.bailout_id() == BailoutId::None()) {
272 // Dummy frame state => just leave it as is.
273 return frame_state;
274 }
275
276 // If the frame state is already the right one, just return it.
277 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
278 state_info.state_combine().GetOffsetToPokeAt() == 1) {
279 return frame_state;
280 }
281
282 // Here, we smash the result of the conversion into the slot just below
283 // the stack top. This is the slot that full code uses to store the
284 // left operand.
285 const Operator* op = jsgraph()->common()->FrameState(
286 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1),
287 state_info.function_info());
288
289 return graph()->NewNode(op,
290 frame_state->InputAt(kFrameStateParametersInput),
291 frame_state->InputAt(kFrameStateLocalsInput),
292 frame_state->InputAt(kFrameStateStackInput),
293 frame_state->InputAt(kFrameStateContextInput),
294 frame_state->InputAt(kFrameStateFunctionInput),
295 frame_state->InputAt(kFrameStateOuterStateInput));
296 }
297
CreateFrameStateForRightInput(Node * frame_state,Node * converted_left)298 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
299 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
300
301 if (state_info.bailout_id() == BailoutId::None()) {
302 // Dummy frame state => just leave it as is.
303 return frame_state;
304 }
305
306 // Create a frame state that stores the result of the operation to the
307 // top of the stack (i.e., the slot used for the right operand).
308 const Operator* op = jsgraph()->common()->FrameState(
309 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0),
310 state_info.function_info());
311
312 // Change the left operand {converted_left} on the expression stack.
313 Node* stack = frame_state->InputAt(2);
314 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
315 DCHECK_GE(stack->InputCount(), 2);
316
317 // TODO(jarin) Allocate in a local zone or a reusable buffer.
318 NodeVector new_values(stack->InputCount(), zone());
319 for (int i = 0; i < stack->InputCount(); i++) {
320 if (i == stack->InputCount() - 2) {
321 new_values[i] = converted_left;
322 } else {
323 new_values[i] = stack->InputAt(i);
324 }
325 }
326 Node* new_stack =
327 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
328
329 return graph()->NewNode(
330 op, frame_state->InputAt(kFrameStateParametersInput),
331 frame_state->InputAt(kFrameStateLocalsInput), new_stack,
332 frame_state->InputAt(kFrameStateContextInput),
333 frame_state->InputAt(kFrameStateFunctionInput),
334 frame_state->InputAt(kFrameStateOuterStateInput));
335 }
336
ConvertPlainPrimitiveToNumber(Node * node)337 Node* ConvertPlainPrimitiveToNumber(Node* node) {
338 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
339 // Avoid inserting too many eager ToNumber() operations.
340 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
341 if (reduction.Changed()) return reduction.replacement();
342 // TODO(jarin) Use PlainPrimitiveToNumber once we have it.
343 return graph()->NewNode(
344 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(),
345 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start());
346 }
347
ConvertSingleInputToNumber(Node * node,Node * frame_state)348 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
349 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
350 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
351 frame_state, effect(), control());
352 NodeProperties::ReplaceUses(node_, node_, node_, n, n);
353 update_effect(n);
354 return n;
355 }
356
ConvertBothInputsToNumber(Node ** left_result,Node ** right_result,Node * frame_state)357 void ConvertBothInputsToNumber(Node** left_result, Node** right_result,
358 Node* frame_state) {
359 Node* projections[2];
360
361 // Find {IfSuccess} and {IfException} continuations of the operation.
362 NodeProperties::CollectControlProjections(node_, projections, 2);
363 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]);
364 Node* if_exception = projections[1];
365 Node* if_success = projections[0];
366
367 // Insert two ToNumber() operations that both potentially throw.
368 Node* left_state = CreateFrameStateForLeftInput(frame_state);
369 Node* left_conv =
370 graph()->NewNode(javascript()->ToNumber(), left(), context(),
371 left_state, effect(), control());
372 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
373 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv);
374 Node* right_conv =
375 graph()->NewNode(javascript()->ToNumber(), right(), context(),
376 right_state, left_conv, left_success);
377 Node* left_exception =
378 graph()->NewNode(common()->IfException(hint), left_conv, left_conv);
379 Node* right_exception =
380 graph()->NewNode(common()->IfException(hint), right_conv, right_conv);
381 NodeProperties::ReplaceControlInput(if_success, right_conv);
382 update_effect(right_conv);
383
384 // Wire conversions to existing {IfException} continuation.
385 Node* exception_merge = if_exception;
386 Node* exception_value =
387 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
388 left_exception, right_exception, exception_merge);
389 Node* exception_effect =
390 graph()->NewNode(common()->EffectPhi(2), left_exception,
391 right_exception, exception_merge);
392 for (Edge edge : exception_merge->use_edges()) {
393 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
394 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
395 }
396 NodeProperties::RemoveType(exception_merge);
397 exception_merge->ReplaceInput(0, left_exception);
398 exception_merge->ReplaceInput(1, right_exception);
399 NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
400
401 *left_result = left_conv;
402 *right_result = right_conv;
403 }
404
ConvertToUI32(Node * node,Signedness signedness)405 Node* ConvertToUI32(Node* node, Signedness signedness) {
406 // Avoid introducing too many eager NumberToXXnt32() operations.
407 Type* type = NodeProperties::GetType(node);
408 if (signedness == kSigned) {
409 if (!type->Is(Type::Signed32())) {
410 node = graph()->NewNode(simplified()->NumberToInt32(), node);
411 }
412 } else {
413 DCHECK_EQ(kUnsigned, signedness);
414 if (!type->Is(Type::Unsigned32())) {
415 node = graph()->NewNode(simplified()->NumberToUint32(), node);
416 }
417 }
418 return node;
419 }
420
update_effect(Node * effect)421 void update_effect(Node* effect) {
422 NodeProperties::ReplaceEffectInput(node_, effect);
423 }
424 };
425
426
427 // TODO(turbofan): js-typed-lowering improvements possible
428 // - immediately put in type bounds for all new nodes
429 // - relax effects from generic but not-side-effecting operations
430
431
JSTypedLowering(Editor * editor,CompilationDependencies * dependencies,Flags flags,JSGraph * jsgraph,Zone * zone)432 JSTypedLowering::JSTypedLowering(Editor* editor,
433 CompilationDependencies* dependencies,
434 Flags flags, JSGraph* jsgraph, Zone* zone)
435 : AdvancedReducer(editor),
436 dependencies_(dependencies),
437 flags_(flags),
438 jsgraph_(jsgraph),
439 true_type_(Type::Constant(factory()->true_value(), graph()->zone())),
440 false_type_(Type::Constant(factory()->false_value(), graph()->zone())),
441 the_hole_type_(
442 Type::Constant(factory()->the_hole_value(), graph()->zone())),
443 type_cache_(TypeCache::Get()) {
444 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
445 double min = kMinInt / (1 << k);
446 double max = kMaxInt / (1 << k);
447 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
448 }
449 }
450
451
ReduceJSAdd(Node * node)452 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
453 if (flags() & kDisableBinaryOpReduction) return NoChange();
454
455 JSBinopReduction r(this, node);
456 if (r.BothInputsAre(Type::Number())) {
457 // JSAdd(x:number, y:number) => NumberAdd(x, y)
458 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
459 }
460 if (r.NeitherInputCanBe(Type::StringOrReceiver()) && !r.IsStrong()) {
461 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
462 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
463 r.ConvertInputsToNumber(frame_state);
464 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
465 }
466 if (r.BothInputsAre(Type::String())) {
467 // JSAdd(x:string, y:string) => CallStub[StringAdd](x, y)
468 Callable const callable =
469 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
470 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
471 isolate(), graph()->zone(), callable.descriptor(), 0,
472 CallDescriptor::kNeedsFrameState, node->op()->properties());
473 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
474 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
475 node->InsertInput(graph()->zone(), 0,
476 jsgraph()->HeapConstant(callable.code()));
477 NodeProperties::ChangeOp(node, common()->Call(desc));
478 return Changed(node);
479 }
480 return NoChange();
481 }
482
483
ReduceJSModulus(Node * node)484 Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
485 if (flags() & kDisableBinaryOpReduction) return NoChange();
486
487 JSBinopReduction r(this, node);
488 if (r.BothInputsAre(Type::Number())) {
489 // JSModulus(x:number, x:number) => NumberModulus(x, y)
490 return r.ChangeToPureOperator(simplified()->NumberModulus(),
491 Type::Number());
492 }
493 return NoChange();
494 }
495
496
ReduceNumberBinop(Node * node,const Operator * numberOp)497 Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
498 const Operator* numberOp) {
499 if (flags() & kDisableBinaryOpReduction) return NoChange();
500
501 JSBinopReduction r(this, node);
502 if (r.IsStrong() || numberOp == simplified()->NumberModulus()) {
503 if (r.BothInputsAre(Type::Number())) {
504 return r.ChangeToPureOperator(numberOp, Type::Number());
505 }
506 return NoChange();
507 }
508 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
509 r.ConvertInputsToNumber(frame_state);
510 return r.ChangeToPureOperator(numberOp, Type::Number());
511 }
512
513
ReduceInt32Binop(Node * node,const Operator * intOp)514 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
515 if (flags() & kDisableBinaryOpReduction) return NoChange();
516
517 JSBinopReduction r(this, node);
518 if (r.IsStrong()) {
519 if (r.BothInputsAre(Type::Number())) {
520 r.ConvertInputsToUI32(kSigned, kSigned);
521 return r.ChangeToPureOperator(intOp, Type::Integral32());
522 }
523 return NoChange();
524 }
525 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
526 r.ConvertInputsToNumber(frame_state);
527 r.ConvertInputsToUI32(kSigned, kSigned);
528 return r.ChangeToPureOperator(intOp, Type::Integral32());
529 }
530
531
ReduceUI32Shift(Node * node,Signedness left_signedness,const Operator * shift_op)532 Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
533 Signedness left_signedness,
534 const Operator* shift_op) {
535 if (flags() & kDisableBinaryOpReduction) return NoChange();
536
537 JSBinopReduction r(this, node);
538 if (r.IsStrong()) {
539 if (r.BothInputsAre(Type::Number())) {
540 r.ConvertInputsToUI32(left_signedness, kUnsigned);
541 return r.ChangeToPureOperator(shift_op);
542 }
543 return NoChange();
544 }
545 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
546 r.ConvertInputsToNumber(frame_state);
547 r.ConvertInputsToUI32(left_signedness, kUnsigned);
548 return r.ChangeToPureOperator(shift_op);
549 }
550
551
ReduceJSComparison(Node * node)552 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
553 if (flags() & kDisableBinaryOpReduction) return NoChange();
554
555 JSBinopReduction r(this, node);
556 if (r.BothInputsAre(Type::String())) {
557 // If both inputs are definitely strings, perform a string comparison.
558 const Operator* stringOp;
559 switch (node->opcode()) {
560 case IrOpcode::kJSLessThan:
561 stringOp = simplified()->StringLessThan();
562 break;
563 case IrOpcode::kJSGreaterThan:
564 stringOp = simplified()->StringLessThan();
565 r.SwapInputs(); // a > b => b < a
566 break;
567 case IrOpcode::kJSLessThanOrEqual:
568 stringOp = simplified()->StringLessThanOrEqual();
569 break;
570 case IrOpcode::kJSGreaterThanOrEqual:
571 stringOp = simplified()->StringLessThanOrEqual();
572 r.SwapInputs(); // a >= b => b <= a
573 break;
574 default:
575 return NoChange();
576 }
577 r.ChangeToStringComparisonOperator(stringOp);
578 return Changed(node);
579 }
580 if (r.OneInputCannotBe(Type::StringOrReceiver())) {
581 const Operator* less_than;
582 const Operator* less_than_or_equal;
583 if (r.BothInputsAre(Type::Unsigned32())) {
584 less_than = machine()->Uint32LessThan();
585 less_than_or_equal = machine()->Uint32LessThanOrEqual();
586 } else if (r.BothInputsAre(Type::Signed32())) {
587 less_than = machine()->Int32LessThan();
588 less_than_or_equal = machine()->Int32LessThanOrEqual();
589 } else {
590 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
591 if (r.IsStrong() && !r.BothInputsAre(Type::Number())) {
592 return NoChange();
593 }
594 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
595 r.ConvertInputsToNumber(frame_state);
596 less_than = simplified()->NumberLessThan();
597 less_than_or_equal = simplified()->NumberLessThanOrEqual();
598 }
599 const Operator* comparison;
600 switch (node->opcode()) {
601 case IrOpcode::kJSLessThan:
602 comparison = less_than;
603 break;
604 case IrOpcode::kJSGreaterThan:
605 comparison = less_than;
606 r.SwapInputs(); // a > b => b < a
607 break;
608 case IrOpcode::kJSLessThanOrEqual:
609 comparison = less_than_or_equal;
610 break;
611 case IrOpcode::kJSGreaterThanOrEqual:
612 comparison = less_than_or_equal;
613 r.SwapInputs(); // a >= b => b <= a
614 break;
615 default:
616 return NoChange();
617 }
618 return r.ChangeToPureOperator(comparison);
619 }
620 // TODO(turbofan): relax/remove effects of this operator in other cases.
621 return NoChange(); // Keep a generic comparison.
622 }
623
624
ReduceJSEqual(Node * node,bool invert)625 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
626 if (flags() & kDisableBinaryOpReduction) return NoChange();
627
628 JSBinopReduction r(this, node);
629
630 if (r.BothInputsAre(Type::Number())) {
631 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
632 }
633 if (r.BothInputsAre(Type::String())) {
634 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
635 invert);
636 }
637 if (r.BothInputsAre(Type::Boolean())) {
638 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
639 invert);
640 }
641 if (r.BothInputsAre(Type::Receiver())) {
642 return r.ChangeToPureOperator(
643 simplified()->ReferenceEqual(Type::Receiver()), invert);
644 }
645 if (r.OneInputIs(Type::NullOrUndefined())) {
646 Callable const callable = CodeFactory::CompareNilIC(isolate(), kNullValue);
647 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
648 isolate(), graph()->zone(), callable.descriptor(), 0,
649 CallDescriptor::kNeedsFrameState, node->op()->properties());
650 node->RemoveInput(r.LeftInputIs(Type::NullOrUndefined()) ? 0 : 1);
651 node->InsertInput(graph()->zone(), 0,
652 jsgraph()->HeapConstant(callable.code()));
653 NodeProperties::ChangeOp(node, common()->Call(desc));
654 if (invert) {
655 // Insert an boolean not to invert the value.
656 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
657 node->ReplaceUses(value);
658 // Note: ReplaceUses() smashes all uses, so smash it back here.
659 value->ReplaceInput(0, node);
660 return Replace(value);
661 }
662 return Changed(node);
663 }
664 return NoChange();
665 }
666
667
ReduceJSStrictEqual(Node * node,bool invert)668 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
669 if (flags() & kDisableBinaryOpReduction) return NoChange();
670
671 JSBinopReduction r(this, node);
672 if (r.left() == r.right()) {
673 // x === x is always true if x != NaN
674 if (!r.left_type()->Maybe(Type::NaN())) {
675 Node* replacement = jsgraph()->BooleanConstant(!invert);
676 ReplaceWithValue(node, replacement);
677 return Replace(replacement);
678 }
679 }
680 if (r.OneInputCannotBe(Type::NumberOrString())) {
681 // For values with canonical representation (i.e. not string nor number) an
682 // empty type intersection means the values cannot be strictly equal.
683 if (!r.left_type()->Maybe(r.right_type())) {
684 Node* replacement = jsgraph()->BooleanConstant(invert);
685 ReplaceWithValue(node, replacement);
686 return Replace(replacement);
687 }
688 }
689 if (r.OneInputIs(the_hole_type_)) {
690 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
691 invert);
692 }
693 if (r.OneInputIs(Type::Undefined())) {
694 return r.ChangeToPureOperator(
695 simplified()->ReferenceEqual(Type::Undefined()), invert);
696 }
697 if (r.OneInputIs(Type::Null())) {
698 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
699 invert);
700 }
701 if (r.OneInputIs(Type::Boolean())) {
702 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
703 invert);
704 }
705 if (r.OneInputIs(Type::Object())) {
706 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
707 invert);
708 }
709 if (r.OneInputIs(Type::Receiver())) {
710 return r.ChangeToPureOperator(
711 simplified()->ReferenceEqual(Type::Receiver()), invert);
712 }
713 if (r.BothInputsAre(Type::Unique())) {
714 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
715 invert);
716 }
717 if (r.BothInputsAre(Type::String())) {
718 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
719 invert);
720 }
721 if (r.BothInputsAre(Type::Number())) {
722 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
723 }
724 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
725 return NoChange();
726 }
727
728
ReduceJSToBoolean(Node * node)729 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
730 Node* const input = node->InputAt(0);
731 Type* const input_type = NodeProperties::GetType(input);
732 Node* const effect = NodeProperties::GetEffectInput(node);
733 if (input_type->Is(Type::Boolean())) {
734 // JSToBoolean(x:boolean) => x
735 ReplaceWithValue(node, input, effect);
736 return Replace(input);
737 } else if (input_type->Is(Type::OrderedNumber())) {
738 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
739 RelaxEffectsAndControls(node);
740 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
741 jsgraph()->ZeroConstant()));
742 node->TrimInputCount(1);
743 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
744 return Changed(node);
745 } else if (input_type->Is(Type::String())) {
746 // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
747 FieldAccess const access = AccessBuilder::ForStringLength();
748 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
749 effect, graph()->start());
750 ReplaceWithValue(node, node, length);
751 node->ReplaceInput(0, jsgraph()->ZeroConstant());
752 node->ReplaceInput(1, length);
753 node->TrimInputCount(2);
754 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
755 return Changed(node);
756 }
757 return NoChange();
758 }
759
760
ReduceJSToNumberInput(Node * input)761 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
762 if (input->opcode() == IrOpcode::kJSToNumber) {
763 // Recursively try to reduce the input first.
764 Reduction result = ReduceJSToNumber(input);
765 if (result.Changed()) return result;
766 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
767 }
768 // Check for ToNumber truncation of signaling NaN to undefined mapping.
769 if (input->opcode() == IrOpcode::kSelect) {
770 Node* check = NodeProperties::GetValueInput(input, 0);
771 Node* vtrue = NodeProperties::GetValueInput(input, 1);
772 Type* vtrue_type = NodeProperties::GetType(vtrue);
773 Node* vfalse = NodeProperties::GetValueInput(input, 2);
774 Type* vfalse_type = NodeProperties::GetType(vfalse);
775 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) {
776 if (check->opcode() == IrOpcode::kNumberIsHoleNaN &&
777 check->InputAt(0) == vfalse) {
778 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x
779 return Replace(vfalse);
780 }
781 }
782 }
783 // Check if we have a cached conversion.
784 Type* input_type = NodeProperties::GetType(input);
785 if (input_type->Is(Type::Number())) {
786 // JSToNumber(x:number) => x
787 return Changed(input);
788 }
789 if (input_type->Is(Type::Undefined())) {
790 // JSToNumber(undefined) => #NaN
791 return Replace(jsgraph()->NaNConstant());
792 }
793 if (input_type->Is(Type::Null())) {
794 // JSToNumber(null) => #0
795 return Replace(jsgraph()->ZeroConstant());
796 }
797 if (input_type->Is(Type::Boolean())) {
798 // JSToNumber(x:boolean) => BooleanToNumber(x)
799 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
800 }
801 // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
802 return NoChange();
803 }
804
805
ReduceJSToNumber(Node * node)806 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
807 // Try to reduce the input first.
808 Node* const input = node->InputAt(0);
809 Reduction reduction = ReduceJSToNumberInput(input);
810 if (reduction.Changed()) {
811 ReplaceWithValue(node, reduction.replacement());
812 return reduction;
813 }
814 Type* const input_type = NodeProperties::GetType(input);
815 if (input_type->Is(Type::PlainPrimitive())) {
816 if (NodeProperties::GetContextInput(node) !=
817 jsgraph()->NoContextConstant() ||
818 NodeProperties::GetEffectInput(node) != graph()->start() ||
819 NodeProperties::GetControlInput(node) != graph()->start()) {
820 // JSToNumber(x:plain-primitive,context,effect,control)
821 // => JSToNumber(x,no-context,start,start)
822 RelaxEffectsAndControls(node);
823 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
824 NodeProperties::ReplaceControlInput(node, graph()->start());
825 NodeProperties::ReplaceEffectInput(node, graph()->start());
826 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
827 NodeProperties::ReplaceFrameStateInput(node, 0,
828 jsgraph()->EmptyFrameState());
829 return Changed(node);
830 }
831 }
832 return NoChange();
833 }
834
835
ReduceJSToStringInput(Node * input)836 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
837 if (input->opcode() == IrOpcode::kJSToString) {
838 // Recursively try to reduce the input first.
839 Reduction result = ReduceJSToString(input);
840 if (result.Changed()) return result;
841 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
842 }
843 Type* input_type = NodeProperties::GetType(input);
844 if (input_type->Is(Type::String())) {
845 return Changed(input); // JSToString(x:string) => x
846 }
847 if (input_type->Is(Type::Boolean())) {
848 return Replace(graph()->NewNode(
849 common()->Select(MachineRepresentation::kTagged), input,
850 jsgraph()->HeapConstant(factory()->true_string()),
851 jsgraph()->HeapConstant(factory()->false_string())));
852 }
853 if (input_type->Is(Type::Undefined())) {
854 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
855 }
856 if (input_type->Is(Type::Null())) {
857 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
858 }
859 // TODO(turbofan): js-typed-lowering of ToString(x:number)
860 return NoChange();
861 }
862
863
ReduceJSToString(Node * node)864 Reduction JSTypedLowering::ReduceJSToString(Node* node) {
865 // Try to reduce the input first.
866 Node* const input = node->InputAt(0);
867 Reduction reduction = ReduceJSToStringInput(input);
868 if (reduction.Changed()) {
869 ReplaceWithValue(node, reduction.replacement());
870 return reduction;
871 }
872 return NoChange();
873 }
874
875
ReduceJSToObject(Node * node)876 Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
877 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
878 Node* receiver = NodeProperties::GetValueInput(node, 0);
879 Type* receiver_type = NodeProperties::GetType(receiver);
880 Node* context = NodeProperties::GetContextInput(node);
881 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
882 Node* effect = NodeProperties::GetEffectInput(node);
883 Node* control = NodeProperties::GetControlInput(node);
884 if (!receiver_type->Is(Type::Receiver())) {
885 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
886 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
887 NodeProperties::IsExceptionalCall(node)) {
888 // ToObject throws for null or undefined inputs.
889 return NoChange();
890 }
891
892 // Check whether {receiver} is a Smi.
893 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
894 Node* branch0 =
895 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
896 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
897 Node* etrue0 = effect;
898
899 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
900 Node* efalse0 = effect;
901
902 // Determine the instance type of {receiver}.
903 Node* receiver_map = efalse0 =
904 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
905 receiver, efalse0, if_false0);
906 Node* receiver_instance_type = efalse0 = graph()->NewNode(
907 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
908 receiver_map, efalse0, if_false0);
909
910 // Check whether {receiver} is a spec object.
911 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
912 Node* check1 =
913 graph()->NewNode(machine()->Uint32LessThanOrEqual(),
914 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
915 receiver_instance_type);
916 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
917 check1, if_false0);
918 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
919 Node* etrue1 = efalse0;
920
921 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
922 Node* efalse1 = efalse0;
923
924 // Convert {receiver} using the ToObjectStub.
925 Node* if_convert =
926 graph()->NewNode(common()->Merge(2), if_true0, if_false1);
927 Node* econvert =
928 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
929 Node* rconvert;
930 {
931 Callable callable = CodeFactory::ToObject(isolate());
932 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
933 isolate(), graph()->zone(), callable.descriptor(), 0,
934 CallDescriptor::kNeedsFrameState, node->op()->properties());
935 rconvert = econvert = graph()->NewNode(
936 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
937 receiver, context, frame_state, econvert, if_convert);
938 }
939
940 // The {receiver} is already a spec object.
941 Node* if_done = if_true1;
942 Node* edone = etrue1;
943 Node* rdone = receiver;
944
945 control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
946 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
947 receiver =
948 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
949 rconvert, rdone, control);
950 }
951 ReplaceWithValue(node, receiver, effect, control);
952 return Changed(receiver);
953 }
954
955
ReduceJSLoadNamed(Node * node)956 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
957 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
958 Node* receiver = NodeProperties::GetValueInput(node, 0);
959 Type* receiver_type = NodeProperties::GetType(receiver);
960 Node* effect = NodeProperties::GetEffectInput(node);
961 Node* control = NodeProperties::GetControlInput(node);
962 Handle<Name> name = NamedAccessOf(node->op()).name();
963 // Optimize "length" property of strings.
964 if (name.is_identical_to(factory()->length_string()) &&
965 receiver_type->Is(Type::String())) {
966 Node* value = effect = graph()->NewNode(
967 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
968 effect, control);
969 ReplaceWithValue(node, value, effect);
970 return Replace(value);
971 }
972 // Optimize "prototype" property of functions.
973 if (name.is_identical_to(factory()->prototype_string()) &&
974 receiver_type->IsConstant() &&
975 receiver_type->AsConstant()->Value()->IsJSFunction()) {
976 // TODO(turbofan): This lowering might not kick in if we ever lower
977 // the C++ accessor for "prototype" in an earlier optimization pass.
978 Handle<JSFunction> function =
979 Handle<JSFunction>::cast(receiver_type->AsConstant()->Value());
980 if (function->has_initial_map()) {
981 // We need to add a code dependency on the initial map of the {function}
982 // in order to be notified about changes to the "prototype" of {function},
983 // so it doesn't make sense to continue unless deoptimization is enabled.
984 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
985 Handle<Map> initial_map(function->initial_map(), isolate());
986 dependencies()->AssumeInitialMapCantChange(initial_map);
987 Node* value =
988 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
989 ReplaceWithValue(node, value);
990 return Replace(value);
991 }
992 }
993 return NoChange();
994 }
995
996
ReduceJSLoadProperty(Node * node)997 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
998 Node* key = NodeProperties::GetValueInput(node, 1);
999 Node* base = NodeProperties::GetValueInput(node, 0);
1000 Type* key_type = NodeProperties::GetType(key);
1001 HeapObjectMatcher mbase(base);
1002 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1003 Handle<JSTypedArray> const array =
1004 Handle<JSTypedArray>::cast(mbase.Value());
1005 if (!array->GetBuffer()->was_neutered()) {
1006 array->GetBuffer()->set_is_neuterable(false);
1007 BufferAccess const access(array->type());
1008 size_t const k =
1009 ElementSizeLog2Of(access.machine_type().representation());
1010 double const byte_length = array->byte_length()->Number();
1011 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1012 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1013 // JSLoadProperty(typed-array, int32)
1014 Handle<FixedTypedArrayBase> elements =
1015 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1016 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1017 Node* length = jsgraph()->Constant(byte_length);
1018 Node* effect = NodeProperties::GetEffectInput(node);
1019 Node* control = NodeProperties::GetControlInput(node);
1020 // Check if we can avoid the bounds check.
1021 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1022 Node* load = graph()->NewNode(
1023 simplified()->LoadElement(
1024 AccessBuilder::ForTypedArrayElement(array->type(), true)),
1025 buffer, key, effect, control);
1026 ReplaceWithValue(node, load, load);
1027 return Replace(load);
1028 }
1029 // Compute byte offset.
1030 Node* offset = Word32Shl(key, static_cast<int>(k));
1031 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
1032 offset, length, effect, control);
1033 ReplaceWithValue(node, load, load);
1034 return Replace(load);
1035 }
1036 }
1037 }
1038 return NoChange();
1039 }
1040
1041
ReduceJSStoreProperty(Node * node)1042 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
1043 Node* key = NodeProperties::GetValueInput(node, 1);
1044 Node* base = NodeProperties::GetValueInput(node, 0);
1045 Node* value = NodeProperties::GetValueInput(node, 2);
1046 Type* key_type = NodeProperties::GetType(key);
1047 Type* value_type = NodeProperties::GetType(value);
1048 HeapObjectMatcher mbase(base);
1049 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1050 Handle<JSTypedArray> const array =
1051 Handle<JSTypedArray>::cast(mbase.Value());
1052 if (!array->GetBuffer()->was_neutered()) {
1053 array->GetBuffer()->set_is_neuterable(false);
1054 BufferAccess const access(array->type());
1055 size_t const k =
1056 ElementSizeLog2Of(access.machine_type().representation());
1057 double const byte_length = array->byte_length()->Number();
1058 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1059 if (access.external_array_type() != kExternalUint8ClampedArray &&
1060 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1061 // JSLoadProperty(typed-array, int32)
1062 Handle<FixedTypedArrayBase> elements =
1063 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1064 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1065 Node* length = jsgraph()->Constant(byte_length);
1066 Node* context = NodeProperties::GetContextInput(node);
1067 Node* effect = NodeProperties::GetEffectInput(node);
1068 Node* control = NodeProperties::GetControlInput(node);
1069 // Convert to a number first.
1070 if (!value_type->Is(Type::Number())) {
1071 Reduction number_reduction = ReduceJSToNumberInput(value);
1072 if (number_reduction.Changed()) {
1073 value = number_reduction.replacement();
1074 } else {
1075 Node* frame_state_for_to_number =
1076 NodeProperties::GetFrameStateInput(node, 1);
1077 value = effect =
1078 graph()->NewNode(javascript()->ToNumber(), value, context,
1079 frame_state_for_to_number, effect, control);
1080 }
1081 }
1082 // Check if we can avoid the bounds check.
1083 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1084 RelaxControls(node);
1085 node->ReplaceInput(0, buffer);
1086 DCHECK_EQ(key, node->InputAt(1));
1087 node->ReplaceInput(2, value);
1088 node->ReplaceInput(3, effect);
1089 node->ReplaceInput(4, control);
1090 node->TrimInputCount(5);
1091 NodeProperties::ChangeOp(
1092 node,
1093 simplified()->StoreElement(
1094 AccessBuilder::ForTypedArrayElement(array->type(), true)));
1095 return Changed(node);
1096 }
1097 // Compute byte offset.
1098 Node* offset = Word32Shl(key, static_cast<int>(k));
1099 // Turn into a StoreBuffer operation.
1100 RelaxControls(node);
1101 node->ReplaceInput(0, buffer);
1102 node->ReplaceInput(1, offset);
1103 node->ReplaceInput(2, length);
1104 node->ReplaceInput(3, value);
1105 node->ReplaceInput(4, effect);
1106 node->ReplaceInput(5, control);
1107 node->TrimInputCount(6);
1108 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
1109 return Changed(node);
1110 }
1111 }
1112 }
1113 return NoChange();
1114 }
1115
1116
ReduceJSInstanceOf(Node * node)1117 Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
1118 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
1119 Node* const context = NodeProperties::GetContextInput(node);
1120 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1121
1122 // If deoptimization is disabled, we cannot optimize.
1123 if (!(flags() & kDeoptimizationEnabled) ||
1124 (flags() & kDisableBinaryOpReduction)) {
1125 return NoChange();
1126 }
1127
1128 // If we are in a try block, don't optimize since the runtime call
1129 // in the proxy case can throw.
1130 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
1131
1132 JSBinopReduction r(this, node);
1133 Node* effect = r.effect();
1134 Node* control = r.control();
1135
1136 if (!r.right_type()->IsConstant() ||
1137 !r.right_type()->AsConstant()->Value()->IsJSFunction()) {
1138 return NoChange();
1139 }
1140
1141 Handle<JSFunction> function =
1142 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value());
1143 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1144
1145 if (!function->IsConstructor() ||
1146 function->map()->has_non_instance_prototype()) {
1147 return NoChange();
1148 }
1149
1150 JSFunction::EnsureHasInitialMap(function);
1151 DCHECK(function->has_initial_map());
1152 Handle<Map> initial_map(function->initial_map(), isolate());
1153 this->dependencies()->AssumeInitialMapCantChange(initial_map);
1154 Node* prototype =
1155 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1156
1157 Node* if_is_smi = nullptr;
1158 Node* e_is_smi = nullptr;
1159 // If the left hand side is an object, no smi check is needed.
1160 if (r.left_type()->Maybe(Type::TaggedSigned())) {
1161 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
1162 Node* branch_is_smi =
1163 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
1164 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
1165 e_is_smi = effect;
1166 control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
1167 }
1168
1169 Node* object_map = effect =
1170 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1171 r.left(), effect, control);
1172
1173 // Loop through the {object}s prototype chain looking for the {prototype}.
1174 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1175
1176 Node* loop_effect = effect =
1177 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1178
1179 Node* loop_object_map =
1180 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1181 object_map, r.left(), loop);
1182
1183 // Check if the lhs needs access checks.
1184 Node* map_bit_field = effect =
1185 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
1186 loop_object_map, loop_effect, control);
1187 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
1188 Node* is_access_check_needed_num =
1189 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
1190 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1191 Node* is_access_check_needed =
1192 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num,
1193 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1194
1195 Node* branch_is_access_check_needed = graph()->NewNode(
1196 common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
1197 Node* if_is_access_check_needed =
1198 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
1199 Node* e_is_access_check_needed = effect;
1200
1201 control =
1202 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
1203
1204 // Check if the lhs is a proxy.
1205 Node* map_instance_type = effect = graph()->NewNode(
1206 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
1207 loop_object_map, loop_effect, control);
1208 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type,
1209 jsgraph()->Uint32Constant(JS_PROXY_TYPE));
1210 Node* branch_is_proxy =
1211 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
1212 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
1213 Node* e_is_proxy = effect;
1214
1215
1216 Node* runtime_has_in_proto_chain = control = graph()->NewNode(
1217 common()->Merge(2), if_is_access_check_needed, if_is_proxy);
1218 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
1219 e_is_proxy, control);
1220
1221 // If we need an access check or the object is a Proxy, make a runtime call
1222 // to finish the lowering.
1223 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode(
1224 javascript()->CallRuntime(Runtime::kHasInPrototypeChain, 2), r.left(),
1225 prototype, context, frame_state, effect, control);
1226
1227 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
1228
1229 Node* object_prototype = effect = graph()->NewNode(
1230 simplified()->LoadField(AccessBuilder::ForMapPrototype()),
1231 loop_object_map, loop_effect, control);
1232
1233 // Check if object prototype is equal to function prototype.
1234 Node* eq_proto =
1235 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1236 object_prototype, prototype);
1237 Node* branch_eq_proto =
1238 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
1239 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
1240 Node* e_eq_proto = effect;
1241
1242 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
1243
1244 // If not, check if object prototype is the null prototype.
1245 Node* null_proto =
1246 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1247 object_prototype, jsgraph()->NullConstant());
1248 Node* branch_null_proto = graph()->NewNode(
1249 common()->Branch(BranchHint::kFalse), null_proto, control);
1250 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
1251 Node* e_null_proto = effect;
1252
1253 control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
1254 Node* load_object_map = effect =
1255 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1256 object_prototype, effect, control);
1257 // Close the loop.
1258 loop_effect->ReplaceInput(1, effect);
1259 loop_object_map->ReplaceInput(1, load_object_map);
1260 loop->ReplaceInput(1, control);
1261
1262 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain,
1263 if_eq_proto, if_null_proto);
1264 effect = graph()->NewNode(common()->EffectPhi(3),
1265 bool_result_runtime_has_in_proto_chain_case,
1266 e_eq_proto, e_null_proto, control);
1267
1268 Node* result = graph()->NewNode(
1269 common()->Phi(MachineRepresentation::kTagged, 3),
1270 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(),
1271 jsgraph()->FalseConstant(), control);
1272
1273 if (if_is_smi != nullptr) {
1274 DCHECK_NOT_NULL(e_is_smi);
1275 control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
1276 effect =
1277 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
1278 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1279 jsgraph()->FalseConstant(), result, control);
1280 }
1281
1282 ReplaceWithValue(node, result, effect, control);
1283 return Changed(result);
1284 }
1285
1286
ReduceJSLoadContext(Node * node)1287 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1288 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1289 ContextAccess const& access = ContextAccessOf(node->op());
1290 Node* effect = NodeProperties::GetEffectInput(node);
1291 Node* control = graph()->start();
1292 for (size_t i = 0; i < access.depth(); ++i) {
1293 Node* previous = effect = graph()->NewNode(
1294 simplified()->LoadField(
1295 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1296 NodeProperties::GetValueInput(node, 0), effect, control);
1297 node->ReplaceInput(0, previous);
1298 }
1299 node->ReplaceInput(1, effect);
1300 node->ReplaceInput(2, control);
1301 NodeProperties::ChangeOp(
1302 node,
1303 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1304 return Changed(node);
1305 }
1306
1307
ReduceJSStoreContext(Node * node)1308 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1309 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1310 ContextAccess const& access = ContextAccessOf(node->op());
1311 Node* effect = NodeProperties::GetEffectInput(node);
1312 Node* control = graph()->start();
1313 for (size_t i = 0; i < access.depth(); ++i) {
1314 Node* previous = effect = graph()->NewNode(
1315 simplified()->LoadField(
1316 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1317 NodeProperties::GetValueInput(node, 0), effect, control);
1318 node->ReplaceInput(0, previous);
1319 }
1320 node->RemoveInput(2);
1321 node->ReplaceInput(2, effect);
1322 NodeProperties::ChangeOp(
1323 node,
1324 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1325 return Changed(node);
1326 }
1327
1328
ReduceJSConvertReceiver(Node * node)1329 Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1330 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1331 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1332 Node* receiver = NodeProperties::GetValueInput(node, 0);
1333 Type* receiver_type = NodeProperties::GetType(receiver);
1334 Node* context = NodeProperties::GetContextInput(node);
1335 Type* context_type = NodeProperties::GetType(context);
1336 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1337 Node* effect = NodeProperties::GetEffectInput(node);
1338 Node* control = NodeProperties::GetControlInput(node);
1339 if (!receiver_type->Is(Type::Receiver())) {
1340 if (receiver_type->Is(Type::NullOrUndefined()) ||
1341 mode == ConvertReceiverMode::kNullOrUndefined) {
1342 if (context_type->IsConstant()) {
1343 Handle<JSObject> global_proxy(
1344 Handle<Context>::cast(context_type->AsConstant()->Value())
1345 ->global_proxy(),
1346 isolate());
1347 receiver = jsgraph()->Constant(global_proxy);
1348 } else {
1349 Node* native_context = effect = graph()->NewNode(
1350 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1351 context, context, effect);
1352 receiver = effect = graph()->NewNode(
1353 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1354 native_context, native_context, effect);
1355 }
1356 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1357 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1358 receiver = effect =
1359 graph()->NewNode(javascript()->ToObject(), receiver, context,
1360 frame_state, effect, control);
1361 } else {
1362 // Check {receiver} for undefined.
1363 Node* check0 =
1364 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1365 receiver, jsgraph()->UndefinedConstant());
1366 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1367 check0, control);
1368 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1369 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1370
1371 // Check {receiver} for null.
1372 Node* check1 =
1373 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1374 receiver, jsgraph()->NullConstant());
1375 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1376 check1, if_false0);
1377 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1378 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1379
1380 // Convert {receiver} using ToObject.
1381 Node* if_convert = if_false1;
1382 Node* econvert = effect;
1383 Node* rconvert;
1384 {
1385 rconvert = econvert =
1386 graph()->NewNode(javascript()->ToObject(), receiver, context,
1387 frame_state, econvert, if_convert);
1388 }
1389
1390 // Replace {receiver} with global proxy of {context}.
1391 Node* if_global =
1392 graph()->NewNode(common()->Merge(2), if_true0, if_true1);
1393 Node* eglobal = effect;
1394 Node* rglobal;
1395 {
1396 if (context_type->IsConstant()) {
1397 Handle<JSObject> global_proxy(
1398 Handle<Context>::cast(context_type->AsConstant()->Value())
1399 ->global_proxy(),
1400 isolate());
1401 rglobal = jsgraph()->Constant(global_proxy);
1402 } else {
1403 Node* native_context = eglobal = graph()->NewNode(
1404 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1405 context, context, eglobal);
1406 rglobal = eglobal = graph()->NewNode(
1407 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1408 native_context, native_context, eglobal);
1409 }
1410 }
1411
1412 control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
1413 effect =
1414 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
1415 receiver =
1416 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1417 rconvert, rglobal, control);
1418 }
1419 }
1420 ReplaceWithValue(node, receiver, effect, control);
1421 return Changed(receiver);
1422 }
1423
1424
1425 namespace {
1426
1427 // Maximum instance size for which allocations will be inlined.
1428 const int kMaxInlineInstanceSize = 64 * kPointerSize;
1429
1430
1431 // Checks whether allocation using the given constructor can be inlined.
IsAllocationInlineable(Handle<JSFunction> constructor)1432 bool IsAllocationInlineable(Handle<JSFunction> constructor) {
1433 // TODO(bmeurer): Further relax restrictions on inlining, i.e.
1434 // instance type and maybe instance size (inobject properties
1435 // are limited anyways by the runtime).
1436 return constructor->has_initial_map() &&
1437 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
1438 constructor->initial_map()->instance_size() < kMaxInlineInstanceSize;
1439 }
1440
1441 } // namespace
1442
1443
ReduceJSCreate(Node * node)1444 Reduction JSTypedLowering::ReduceJSCreate(Node* node) {
1445 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
1446 Node* const target = NodeProperties::GetValueInput(node, 0);
1447 Type* const target_type = NodeProperties::GetType(target);
1448 Node* const new_target = NodeProperties::GetValueInput(node, 1);
1449 Node* const effect = NodeProperties::GetEffectInput(node);
1450 // TODO(turbofan): Add support for NewTarget passed to JSCreate.
1451 if (target != new_target) return NoChange();
1452 // Extract constructor function.
1453 if (target_type->IsConstant() &&
1454 target_type->AsConstant()->Value()->IsJSFunction()) {
1455 Handle<JSFunction> constructor =
1456 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1457 DCHECK(constructor->IsConstructor());
1458 // Force completion of inobject slack tracking before
1459 // generating code to finalize the instance size.
1460 constructor->CompleteInobjectSlackTrackingIfActive();
1461
1462 // TODO(bmeurer): We fall back to the runtime in case we cannot inline
1463 // the allocation here, which is sort of expensive. We should think about
1464 // a soft fallback to some NewObjectCodeStub.
1465 if (IsAllocationInlineable(constructor)) {
1466 // Compute instance size from initial map of {constructor}.
1467 Handle<Map> initial_map(constructor->initial_map(), isolate());
1468 int const instance_size = initial_map->instance_size();
1469
1470 // Add a dependency on the {initial_map} to make sure that this code is
1471 // deoptimized whenever the {initial_map} of the {constructor} changes.
1472 dependencies()->AssumeInitialMapCantChange(initial_map);
1473
1474 // Emit code to allocate the JSObject instance for the {constructor}.
1475 AllocationBuilder a(jsgraph(), effect, graph()->start());
1476 a.Allocate(instance_size);
1477 a.Store(AccessBuilder::ForMap(), initial_map);
1478 a.Store(AccessBuilder::ForJSObjectProperties(),
1479 jsgraph()->EmptyFixedArrayConstant());
1480 a.Store(AccessBuilder::ForJSObjectElements(),
1481 jsgraph()->EmptyFixedArrayConstant());
1482 for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
1483 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
1484 jsgraph()->UndefinedConstant());
1485 }
1486 a.FinishAndChange(node);
1487 return Changed(node);
1488 }
1489 }
1490 return NoChange();
1491 }
1492
1493
1494 namespace {
1495
1496 // Retrieves the frame state holding actual argument values.
GetArgumentsFrameState(Node * frame_state)1497 Node* GetArgumentsFrameState(Node* frame_state) {
1498 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
1499 FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
1500 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
1501 ? outer_state
1502 : frame_state;
1503 }
1504
1505 } // namespace
1506
1507
ReduceJSCreateArguments(Node * node)1508 Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) {
1509 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
1510 CreateArgumentsParameters const& p = CreateArgumentsParametersOf(node->op());
1511 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1512 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
1513 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1514
1515 // Use the ArgumentsAccessStub for materializing both mapped and unmapped
1516 // arguments object, but only for non-inlined (i.e. outermost) frames.
1517 if (outer_state->opcode() != IrOpcode::kFrameState) {
1518 Isolate* isolate = jsgraph()->isolate();
1519 int parameter_count = state_info.parameter_count() - 1;
1520 int parameter_offset = parameter_count * kPointerSize;
1521 int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset;
1522 Node* parameter_pointer = graph()->NewNode(
1523 machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()),
1524 jsgraph()->IntPtrConstant(offset));
1525
1526 if (p.type() != CreateArgumentsParameters::kRestArray) {
1527 Handle<SharedFunctionInfo> shared;
1528 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
1529 bool unmapped = p.type() == CreateArgumentsParameters::kUnmappedArguments;
1530 Callable callable = CodeFactory::ArgumentsAccess(
1531 isolate, unmapped, shared->has_duplicate_parameters());
1532 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1533 isolate, graph()->zone(), callable.descriptor(), 0,
1534 CallDescriptor::kNeedsFrameState);
1535 const Operator* new_op = common()->Call(desc);
1536 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1537 node->InsertInput(graph()->zone(), 0, stub_code);
1538 node->InsertInput(graph()->zone(), 2,
1539 jsgraph()->Constant(parameter_count));
1540 node->InsertInput(graph()->zone(), 3, parameter_pointer);
1541 NodeProperties::ChangeOp(node, new_op);
1542 return Changed(node);
1543 } else {
1544 Callable callable = CodeFactory::RestArgumentsAccess(isolate);
1545 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1546 isolate, graph()->zone(), callable.descriptor(), 0,
1547 CallDescriptor::kNeedsFrameState);
1548 const Operator* new_op = common()->Call(desc);
1549 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1550 node->InsertInput(graph()->zone(), 0, stub_code);
1551 node->ReplaceInput(1, jsgraph()->Constant(parameter_count));
1552 node->InsertInput(graph()->zone(), 2, parameter_pointer);
1553 node->InsertInput(graph()->zone(), 3,
1554 jsgraph()->Constant(p.start_index()));
1555 NodeProperties::ChangeOp(node, new_op);
1556 return Changed(node);
1557 }
1558 } else if (outer_state->opcode() == IrOpcode::kFrameState) {
1559 // Use inline allocation for all mapped arguments objects within inlined
1560 // (i.e. non-outermost) frames, independent of the object size.
1561 if (p.type() == CreateArgumentsParameters::kMappedArguments) {
1562 Handle<SharedFunctionInfo> shared;
1563 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
1564 Node* const callee = NodeProperties::GetValueInput(node, 0);
1565 Node* const control = NodeProperties::GetControlInput(node);
1566 Node* const context = NodeProperties::GetContextInput(node);
1567 Node* effect = NodeProperties::GetEffectInput(node);
1568 // TODO(mstarzinger): Duplicate parameters are not handled yet.
1569 if (shared->has_duplicate_parameters()) return NoChange();
1570 // Choose the correct frame state and frame state info depending on
1571 // whether there conceptually is an arguments adaptor frame in the call
1572 // chain.
1573 Node* const args_state = GetArgumentsFrameState(frame_state);
1574 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1575 // Prepare element backing store to be used by arguments object.
1576 bool has_aliased_arguments = false;
1577 Node* const elements = AllocateAliasedArguments(
1578 effect, control, args_state, context, shared, &has_aliased_arguments);
1579 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1580 // Load the arguments object map from the current native context.
1581 Node* const load_native_context = effect = graph()->NewNode(
1582 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1583 context, context, effect);
1584 Node* const load_arguments_map = effect = graph()->NewNode(
1585 simplified()->LoadField(AccessBuilder::ForContextSlot(
1586 has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX
1587 : Context::SLOPPY_ARGUMENTS_MAP_INDEX)),
1588 load_native_context, effect, control);
1589 // Actually allocate and initialize the arguments object.
1590 AllocationBuilder a(jsgraph(), effect, control);
1591 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1592 int length = args_state_info.parameter_count() - 1; // Minus receiver.
1593 STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize);
1594 a.Allocate(Heap::kSloppyArgumentsObjectSize);
1595 a.Store(AccessBuilder::ForMap(), load_arguments_map);
1596 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1597 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1598 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
1599 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
1600 RelaxControls(node);
1601 a.FinishAndChange(node);
1602 return Changed(node);
1603 } else if (p.type() == CreateArgumentsParameters::kUnmappedArguments) {
1604 // Use inline allocation for all unmapped arguments objects within inlined
1605 // (i.e. non-outermost) frames, independent of the object size.
1606 Node* const control = NodeProperties::GetControlInput(node);
1607 Node* const context = NodeProperties::GetContextInput(node);
1608 Node* effect = NodeProperties::GetEffectInput(node);
1609 // Choose the correct frame state and frame state info depending on
1610 // whether there conceptually is an arguments adaptor frame in the call
1611 // chain.
1612 Node* const args_state = GetArgumentsFrameState(frame_state);
1613 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1614 // Prepare element backing store to be used by arguments object.
1615 Node* const elements = AllocateArguments(effect, control, args_state);
1616 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1617 // Load the arguments object map from the current native context.
1618 Node* const load_native_context = effect = graph()->NewNode(
1619 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1620 context, context, effect);
1621 Node* const load_arguments_map = effect = graph()->NewNode(
1622 simplified()->LoadField(AccessBuilder::ForContextSlot(
1623 Context::STRICT_ARGUMENTS_MAP_INDEX)),
1624 load_native_context, effect, control);
1625 // Actually allocate and initialize the arguments object.
1626 AllocationBuilder a(jsgraph(), effect, control);
1627 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1628 int length = args_state_info.parameter_count() - 1; // Minus receiver.
1629 STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize);
1630 a.Allocate(Heap::kStrictArgumentsObjectSize);
1631 a.Store(AccessBuilder::ForMap(), load_arguments_map);
1632 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1633 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1634 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
1635 RelaxControls(node);
1636 a.FinishAndChange(node);
1637 return Changed(node);
1638 } else if (p.type() == CreateArgumentsParameters::kRestArray) {
1639 // Use inline allocation for all unmapped arguments objects within inlined
1640 // (i.e. non-outermost) frames, independent of the object size.
1641 Node* const control = NodeProperties::GetControlInput(node);
1642 Node* const context = NodeProperties::GetContextInput(node);
1643 Node* effect = NodeProperties::GetEffectInput(node);
1644 // Choose the correct frame state and frame state info depending on
1645 // whether there conceptually is an arguments adaptor frame in the call
1646 // chain.
1647 Node* const args_state = GetArgumentsFrameState(frame_state);
1648 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1649 // Prepare element backing store to be used by the rest array.
1650 Node* const elements =
1651 AllocateRestArguments(effect, control, args_state, p.start_index());
1652 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1653 // Load the JSArray object map from the current native context.
1654 Node* const load_native_context = effect = graph()->NewNode(
1655 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1656 context, context, effect);
1657 Node* const load_jsarray_map = effect = graph()->NewNode(
1658 simplified()->LoadField(AccessBuilder::ForContextSlot(
1659 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)),
1660 load_native_context, effect, control);
1661 // Actually allocate and initialize the jsarray.
1662 AllocationBuilder a(jsgraph(), effect, control);
1663 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1664
1665 // -1 to minus receiver
1666 int argument_count = args_state_info.parameter_count() - 1;
1667 int length = std::max(0, argument_count - p.start_index());
1668 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
1669 a.Allocate(JSArray::kSize);
1670 a.Store(AccessBuilder::ForMap(), load_jsarray_map);
1671 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1672 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1673 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS),
1674 jsgraph()->Constant(length));
1675 RelaxControls(node);
1676 a.FinishAndChange(node);
1677 return Changed(node);
1678 }
1679 }
1680
1681 return NoChange();
1682 }
1683
1684
ReduceNewArray(Node * node,Node * length,int capacity,Handle<AllocationSite> site)1685 Reduction JSTypedLowering::ReduceNewArray(Node* node, Node* length,
1686 int capacity,
1687 Handle<AllocationSite> site) {
1688 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
1689 Node* context = NodeProperties::GetContextInput(node);
1690 Node* effect = NodeProperties::GetEffectInput(node);
1691 Node* control = NodeProperties::GetControlInput(node);
1692
1693 // Extract transition and tenuring feedback from the {site} and add
1694 // appropriate code dependencies on the {site} if deoptimization is
1695 // enabled.
1696 PretenureFlag pretenure = site->GetPretenureMode();
1697 ElementsKind elements_kind = site->GetElementsKind();
1698 DCHECK(IsFastElementsKind(elements_kind));
1699 if (flags() & kDeoptimizationEnabled) {
1700 dependencies()->AssumeTenuringDecision(site);
1701 dependencies()->AssumeTransitionStable(site);
1702 }
1703
1704 // Retrieve the initial map for the array from the appropriate native context.
1705 Node* native_context = effect = graph()->NewNode(
1706 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1707 context, context, effect);
1708 Node* js_array_map = effect = graph()->NewNode(
1709 javascript()->LoadContext(0, Context::ArrayMapIndex(elements_kind), true),
1710 native_context, native_context, effect);
1711
1712 // Setup elements and properties.
1713 Node* elements;
1714 if (capacity == 0) {
1715 elements = jsgraph()->EmptyFixedArrayConstant();
1716 } else {
1717 elements = effect =
1718 AllocateElements(effect, control, elements_kind, capacity, pretenure);
1719 }
1720 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1721
1722 // Perform the allocation of the actual JSArray object.
1723 AllocationBuilder a(jsgraph(), effect, control);
1724 a.Allocate(JSArray::kSize, pretenure);
1725 a.Store(AccessBuilder::ForMap(), js_array_map);
1726 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1727 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1728 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
1729 RelaxControls(node);
1730 a.FinishAndChange(node);
1731 return Changed(node);
1732 }
1733
1734
ReduceJSCreateArray(Node * node)1735 Reduction JSTypedLowering::ReduceJSCreateArray(Node* node) {
1736 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
1737 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
1738 Node* target = NodeProperties::GetValueInput(node, 0);
1739 Node* new_target = NodeProperties::GetValueInput(node, 1);
1740
1741 // TODO(bmeurer): Optimize the subclassing case.
1742 if (target != new_target) return NoChange();
1743
1744 // Check if we have a feedback {site} on the {node}.
1745 Handle<AllocationSite> site = p.site();
1746 if (p.site().is_null()) return NoChange();
1747
1748 // Attempt to inline calls to the Array constructor for the relevant cases
1749 // where either no arguments are provided, or exactly one unsigned number
1750 // argument is given.
1751 if (site->CanInlineCall()) {
1752 if (p.arity() == 0) {
1753 Node* length = jsgraph()->ZeroConstant();
1754 int capacity = JSArray::kPreallocatedArrayElements;
1755 return ReduceNewArray(node, length, capacity, site);
1756 } else if (p.arity() == 1) {
1757 Node* length = NodeProperties::GetValueInput(node, 2);
1758 Type* length_type = NodeProperties::GetType(length);
1759 if (length_type->Is(type_cache_.kElementLoopUnrollType)) {
1760 int capacity = static_cast<int>(length_type->Max());
1761 return ReduceNewArray(node, length, capacity, site);
1762 }
1763 }
1764 }
1765
1766 // Reduce {node} to the appropriate ArrayConstructorStub backend.
1767 // Note that these stubs "behave" like JSFunctions, which means they
1768 // expect a receiver on the stack, which they remove. We just push
1769 // undefined for the receiver.
1770 ElementsKind elements_kind = site->GetElementsKind();
1771 AllocationSiteOverrideMode override_mode =
1772 (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE)
1773 ? DISABLE_ALLOCATION_SITES
1774 : DONT_OVERRIDE;
1775 if (p.arity() == 0) {
1776 ArrayNoArgumentConstructorStub stub(isolate(), elements_kind,
1777 override_mode);
1778 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1779 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1,
1780 CallDescriptor::kNeedsFrameState);
1781 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
1782 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
1783 node->InsertInput(graph()->zone(), 3, jsgraph()->UndefinedConstant());
1784 NodeProperties::ChangeOp(node, common()->Call(desc));
1785 return Changed(node);
1786 } else if (p.arity() == 1) {
1787 // TODO(bmeurer): Optimize for the 0 length non-holey case?
1788 ArraySingleArgumentConstructorStub stub(
1789 isolate(), GetHoleyElementsKind(elements_kind), override_mode);
1790 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1791 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
1792 CallDescriptor::kNeedsFrameState);
1793 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
1794 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
1795 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(1));
1796 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1797 NodeProperties::ChangeOp(node, common()->Call(desc));
1798 return Changed(node);
1799 } else {
1800 int const arity = static_cast<int>(p.arity());
1801 ArrayNArgumentsConstructorStub stub(isolate(), elements_kind,
1802 override_mode);
1803 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1804 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
1805 arity + 1, CallDescriptor::kNeedsFrameState);
1806 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
1807 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
1808 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1809 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1810 NodeProperties::ChangeOp(node, common()->Call(desc));
1811 return Changed(node);
1812 }
1813 }
1814
1815
ReduceJSCreateClosure(Node * node)1816 Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) {
1817 DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
1818 CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
1819 Handle<SharedFunctionInfo> shared = p.shared_info();
1820
1821 // Use the FastNewClosureStub that allocates in new space only for nested
1822 // functions that don't need literals cloning.
1823 if (p.pretenure() == NOT_TENURED && shared->num_literals() == 0) {
1824 Isolate* isolate = jsgraph()->isolate();
1825 Callable callable = CodeFactory::FastNewClosure(
1826 isolate, shared->language_mode(), shared->kind());
1827 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1828 isolate, graph()->zone(), callable.descriptor(), 0,
1829 CallDescriptor::kNoFlags);
1830 const Operator* new_op = common()->Call(desc);
1831 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1832 node->InsertInput(graph()->zone(), 0, stub_code);
1833 node->InsertInput(graph()->zone(), 1, jsgraph()->HeapConstant(shared));
1834 NodeProperties::ChangeOp(node, new_op);
1835 return Changed(node);
1836 }
1837
1838 return NoChange();
1839 }
1840
1841
ReduceJSCreateIterResultObject(Node * node)1842 Reduction JSTypedLowering::ReduceJSCreateIterResultObject(Node* node) {
1843 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
1844 Node* value = NodeProperties::GetValueInput(node, 0);
1845 Node* done = NodeProperties::GetValueInput(node, 1);
1846 Node* context = NodeProperties::GetContextInput(node);
1847 Node* effect = NodeProperties::GetEffectInput(node);
1848
1849 // Load the JSIteratorResult map for the {context}.
1850 Node* native_context = effect = graph()->NewNode(
1851 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1852 context, context, effect);
1853 Node* iterator_result_map = effect = graph()->NewNode(
1854 javascript()->LoadContext(0, Context::ITERATOR_RESULT_MAP_INDEX, true),
1855 native_context, native_context, effect);
1856
1857 // Emit code to allocate the JSIteratorResult instance.
1858 AllocationBuilder a(jsgraph(), effect, graph()->start());
1859 a.Allocate(JSIteratorResult::kSize);
1860 a.Store(AccessBuilder::ForMap(), iterator_result_map);
1861 a.Store(AccessBuilder::ForJSObjectProperties(),
1862 jsgraph()->EmptyFixedArrayConstant());
1863 a.Store(AccessBuilder::ForJSObjectElements(),
1864 jsgraph()->EmptyFixedArrayConstant());
1865 a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
1866 a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
1867 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1868 a.FinishAndChange(node);
1869 return Changed(node);
1870 }
1871
1872
ReduceJSCreateLiteralArray(Node * node)1873 Reduction JSTypedLowering::ReduceJSCreateLiteralArray(Node* node) {
1874 DCHECK_EQ(IrOpcode::kJSCreateLiteralArray, node->opcode());
1875 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
1876 Handle<FixedArray> const constants = Handle<FixedArray>::cast(p.constant());
1877 int const length = constants->length();
1878 int const flags = p.flags();
1879
1880 // Use the FastCloneShallowArrayStub only for shallow boilerplates up to the
1881 // initial length limit for arrays with "fast" elements kind.
1882 // TODO(rossberg): Teach strong mode to FastCloneShallowArrayStub.
1883 if ((flags & ArrayLiteral::kShallowElements) != 0 &&
1884 (flags & ArrayLiteral::kIsStrong) == 0 &&
1885 length < JSArray::kInitialMaxFastElementArray) {
1886 Isolate* isolate = jsgraph()->isolate();
1887 Callable callable = CodeFactory::FastCloneShallowArray(isolate);
1888 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1889 isolate, graph()->zone(), callable.descriptor(), 0,
1890 (OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
1891 ? CallDescriptor::kNeedsFrameState
1892 : CallDescriptor::kNoFlags);
1893 const Operator* new_op = common()->Call(desc);
1894 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1895 Node* literal_index = jsgraph()->SmiConstant(p.index());
1896 Node* constant_elements = jsgraph()->HeapConstant(constants);
1897 node->InsertInput(graph()->zone(), 0, stub_code);
1898 node->InsertInput(graph()->zone(), 2, literal_index);
1899 node->InsertInput(graph()->zone(), 3, constant_elements);
1900 NodeProperties::ChangeOp(node, new_op);
1901 return Changed(node);
1902 }
1903
1904 return NoChange();
1905 }
1906
1907
ReduceJSCreateLiteralObject(Node * node)1908 Reduction JSTypedLowering::ReduceJSCreateLiteralObject(Node* node) {
1909 DCHECK_EQ(IrOpcode::kJSCreateLiteralObject, node->opcode());
1910 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
1911 Handle<FixedArray> const constants = Handle<FixedArray>::cast(p.constant());
1912 // Constants are pairs, see ObjectLiteral::properties_count().
1913 int const length = constants->length() / 2;
1914 int const flags = p.flags();
1915
1916 // Use the FastCloneShallowObjectStub only for shallow boilerplates without
1917 // elements up to the number of properties that the stubs can handle.
1918 if ((flags & ObjectLiteral::kShallowProperties) != 0 &&
1919 length <= FastCloneShallowObjectStub::kMaximumClonedProperties) {
1920 Isolate* isolate = jsgraph()->isolate();
1921 Callable callable = CodeFactory::FastCloneShallowObject(isolate, length);
1922 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1923 isolate, graph()->zone(), callable.descriptor(), 0,
1924 (OperatorProperties::GetFrameStateInputCount(node->op()) != 0)
1925 ? CallDescriptor::kNeedsFrameState
1926 : CallDescriptor::kNoFlags);
1927 const Operator* new_op = common()->Call(desc);
1928 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1929 Node* literal_index = jsgraph()->SmiConstant(p.index());
1930 Node* literal_flags = jsgraph()->SmiConstant(flags);
1931 Node* constant_elements = jsgraph()->HeapConstant(constants);
1932 node->InsertInput(graph()->zone(), 0, stub_code);
1933 node->InsertInput(graph()->zone(), 2, literal_index);
1934 node->InsertInput(graph()->zone(), 3, constant_elements);
1935 node->InsertInput(graph()->zone(), 4, literal_flags);
1936 NodeProperties::ChangeOp(node, new_op);
1937 return Changed(node);
1938 }
1939
1940 return NoChange();
1941 }
1942
1943
ReduceJSCreateFunctionContext(Node * node)1944 Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
1945 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
1946 int slot_count = OpParameter<int>(node->op());
1947 Node* const closure = NodeProperties::GetValueInput(node, 0);
1948
1949 // Use inline allocation for function contexts up to a size limit.
1950 if (slot_count < kFunctionContextAllocationLimit) {
1951 // JSCreateFunctionContext[slot_count < limit]](fun)
1952 Node* effect = NodeProperties::GetEffectInput(node);
1953 Node* control = NodeProperties::GetControlInput(node);
1954 Node* context = NodeProperties::GetContextInput(node);
1955 Node* extension = jsgraph()->TheHoleConstant();
1956 Node* native_context = effect = graph()->NewNode(
1957 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1958 context, context, effect);
1959 AllocationBuilder a(jsgraph(), effect, control);
1960 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1961 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
1962 a.AllocateArray(context_length, factory()->function_context_map());
1963 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1964 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1965 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1966 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1967 native_context);
1968 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1969 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1970 }
1971 RelaxControls(node);
1972 a.FinishAndChange(node);
1973 return Changed(node);
1974 }
1975
1976 // Use the FastNewContextStub only for function contexts up maximum size.
1977 if (slot_count <= FastNewContextStub::kMaximumSlots) {
1978 Isolate* isolate = jsgraph()->isolate();
1979 Callable callable = CodeFactory::FastNewContext(isolate, slot_count);
1980 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1981 isolate, graph()->zone(), callable.descriptor(), 0,
1982 CallDescriptor::kNoFlags);
1983 const Operator* new_op = common()->Call(desc);
1984 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1985 node->InsertInput(graph()->zone(), 0, stub_code);
1986 NodeProperties::ChangeOp(node, new_op);
1987 return Changed(node);
1988 }
1989
1990 return NoChange();
1991 }
1992
1993
ReduceJSCreateWithContext(Node * node)1994 Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
1995 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
1996 Node* object = NodeProperties::GetValueInput(node, 0);
1997 Node* closure = NodeProperties::GetValueInput(node, 1);
1998 Node* effect = NodeProperties::GetEffectInput(node);
1999 Node* control = NodeProperties::GetControlInput(node);
2000 Node* context = NodeProperties::GetContextInput(node);
2001 Node* native_context = effect = graph()->NewNode(
2002 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
2003 context, context, effect);
2004 AllocationBuilder a(jsgraph(), effect, control);
2005 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
2006 a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
2007 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
2008 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
2009 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
2010 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
2011 native_context);
2012 RelaxControls(node);
2013 a.FinishAndChange(node);
2014 return Changed(node);
2015 }
2016
2017
ReduceJSCreateCatchContext(Node * node)2018 Reduction JSTypedLowering::ReduceJSCreateCatchContext(Node* node) {
2019 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
2020 Handle<String> name = OpParameter<Handle<String>>(node);
2021 Node* exception = NodeProperties::GetValueInput(node, 0);
2022 Node* closure = NodeProperties::GetValueInput(node, 1);
2023 Node* effect = NodeProperties::GetEffectInput(node);
2024 Node* control = NodeProperties::GetControlInput(node);
2025 Node* context = NodeProperties::GetContextInput(node);
2026 Node* native_context = effect = graph()->NewNode(
2027 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
2028 context, context, effect);
2029 AllocationBuilder a(jsgraph(), effect, control);
2030 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
2031 a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
2032 factory()->catch_context_map());
2033 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
2034 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
2035 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), name);
2036 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
2037 native_context);
2038 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
2039 exception);
2040 RelaxControls(node);
2041 a.FinishAndChange(node);
2042 return Changed(node);
2043 }
2044
2045
ReduceJSCreateBlockContext(Node * node)2046 Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
2047 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
2048 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
2049 int context_length = scope_info->ContextLength();
2050 Node* const closure = NodeProperties::GetValueInput(node, 0);
2051
2052 // Use inline allocation for block contexts up to a size limit.
2053 if (context_length < kBlockContextAllocationLimit) {
2054 // JSCreateBlockContext[scope[length < limit]](fun)
2055 Node* effect = NodeProperties::GetEffectInput(node);
2056 Node* control = NodeProperties::GetControlInput(node);
2057 Node* context = NodeProperties::GetContextInput(node);
2058 Node* extension = jsgraph()->Constant(scope_info);
2059 Node* native_context = effect = graph()->NewNode(
2060 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
2061 context, context, effect);
2062 AllocationBuilder a(jsgraph(), effect, control);
2063 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
2064 a.AllocateArray(context_length, factory()->block_context_map());
2065 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
2066 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
2067 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
2068 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
2069 native_context);
2070 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
2071 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
2072 }
2073 RelaxControls(node);
2074 a.FinishAndChange(node);
2075 return Changed(node);
2076 }
2077
2078 return NoChange();
2079 }
2080
2081
ReduceJSCallConstruct(Node * node)2082 Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
2083 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
2084 CallConstructParameters const& p = CallConstructParametersOf(node->op());
2085 DCHECK_LE(2u, p.arity());
2086 int const arity = static_cast<int>(p.arity() - 2);
2087 Node* target = NodeProperties::GetValueInput(node, 0);
2088 Type* target_type = NodeProperties::GetType(target);
2089 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
2090
2091 // Check if {target} is a known JSFunction.
2092 if (target_type->IsConstant() &&
2093 target_type->AsConstant()->Value()->IsJSFunction()) {
2094 Handle<JSFunction> function =
2095 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
2096 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
2097
2098 // Remove the eager bailout frame state.
2099 NodeProperties::RemoveFrameStateInput(node, 1);
2100
2101 // Patch {node} to an indirect call via the {function}s construct stub.
2102 Callable callable(handle(shared->construct_stub(), isolate()),
2103 ConstructStubDescriptor(isolate()));
2104 node->RemoveInput(arity + 1);
2105 node->InsertInput(graph()->zone(), 0,
2106 jsgraph()->HeapConstant(callable.code()));
2107 node->InsertInput(graph()->zone(), 2, new_target);
2108 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
2109 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2110 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
2111 NodeProperties::ChangeOp(
2112 node, common()->Call(Linkage::GetStubCallDescriptor(
2113 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2114 CallDescriptor::kNeedsFrameState)));
2115 return Changed(node);
2116 }
2117
2118 // Check if {target} is a JSFunction.
2119 if (target_type->Is(Type::Function())) {
2120 // Remove the eager bailout frame state.
2121 NodeProperties::RemoveFrameStateInput(node, 1);
2122
2123 // Patch {node} to an indirect call via the ConstructFunction builtin.
2124 Callable callable = CodeFactory::ConstructFunction(isolate());
2125 node->RemoveInput(arity + 1);
2126 node->InsertInput(graph()->zone(), 0,
2127 jsgraph()->HeapConstant(callable.code()));
2128 node->InsertInput(graph()->zone(), 2, new_target);
2129 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
2130 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2131 NodeProperties::ChangeOp(
2132 node, common()->Call(Linkage::GetStubCallDescriptor(
2133 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2134 CallDescriptor::kNeedsFrameState)));
2135 return Changed(node);
2136 }
2137
2138 return NoChange();
2139 }
2140
2141
ReduceJSCallFunction(Node * node)2142 Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
2143 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
2144 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
2145 int const arity = static_cast<int>(p.arity() - 2);
2146 ConvertReceiverMode convert_mode = p.convert_mode();
2147 Node* target = NodeProperties::GetValueInput(node, 0);
2148 Type* target_type = NodeProperties::GetType(target);
2149 Node* receiver = NodeProperties::GetValueInput(node, 1);
2150 Type* receiver_type = NodeProperties::GetType(receiver);
2151 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
2152 Node* effect = NodeProperties::GetEffectInput(node);
2153 Node* control = NodeProperties::GetControlInput(node);
2154
2155 // Try to infer receiver {convert_mode} from {receiver} type.
2156 if (receiver_type->Is(Type::NullOrUndefined())) {
2157 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2158 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
2159 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2160 }
2161
2162 // Check if {target} is a known JSFunction.
2163 if (target_type->IsConstant() &&
2164 target_type->AsConstant()->Value()->IsJSFunction()) {
2165 Handle<JSFunction> function =
2166 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
2167 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
2168
2169 // Class constructors are callable, but [[Call]] will raise an exception.
2170 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
2171 if (IsClassConstructor(shared->kind())) return NoChange();
2172
2173 // Load the context from the {target}.
2174 Node* context = effect = graph()->NewNode(
2175 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2176 effect, control);
2177 NodeProperties::ReplaceContextInput(node, context);
2178
2179 // Check if we need to convert the {receiver}.
2180 if (is_sloppy(shared->language_mode()) && !shared->native() &&
2181 !receiver_type->Is(Type::Receiver())) {
2182 receiver = effect =
2183 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
2184 receiver, context, frame_state, effect, control);
2185 NodeProperties::ReplaceValueInput(node, receiver, 1);
2186 }
2187
2188 // Update the effect dependency for the {node}.
2189 NodeProperties::ReplaceEffectInput(node, effect);
2190
2191 // Remove the eager bailout frame state.
2192 NodeProperties::RemoveFrameStateInput(node, 1);
2193
2194 // Compute flags for the call.
2195 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2196 if (p.tail_call_mode() == TailCallMode::kAllow) {
2197 flags |= CallDescriptor::kSupportsTailCalls;
2198 }
2199
2200 Node* new_target = jsgraph()->UndefinedConstant();
2201 Node* argument_count = jsgraph()->Int32Constant(arity);
2202 if (shared->internal_formal_parameter_count() == arity ||
2203 shared->internal_formal_parameter_count() ==
2204 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
2205 // Patch {node} to a direct call.
2206 node->InsertInput(graph()->zone(), arity + 2, new_target);
2207 node->InsertInput(graph()->zone(), arity + 3, argument_count);
2208 NodeProperties::ChangeOp(node,
2209 common()->Call(Linkage::GetJSCallDescriptor(
2210 graph()->zone(), false, 1 + arity, flags)));
2211 } else {
2212 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
2213 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
2214 node->InsertInput(graph()->zone(), 0,
2215 jsgraph()->HeapConstant(callable.code()));
2216 node->InsertInput(graph()->zone(), 2, new_target);
2217 node->InsertInput(graph()->zone(), 3, argument_count);
2218 node->InsertInput(
2219 graph()->zone(), 4,
2220 jsgraph()->Int32Constant(shared->internal_formal_parameter_count()));
2221 NodeProperties::ChangeOp(
2222 node, common()->Call(Linkage::GetStubCallDescriptor(
2223 isolate(), graph()->zone(), callable.descriptor(),
2224 1 + arity, flags)));
2225 }
2226 return Changed(node);
2227 }
2228
2229 // Check if {target} is a JSFunction.
2230 if (target_type->Is(Type::Function())) {
2231 // Remove the eager bailout frame state.
2232 NodeProperties::RemoveFrameStateInput(node, 1);
2233
2234 // Compute flags for the call.
2235 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2236 if (p.tail_call_mode() == TailCallMode::kAllow) {
2237 flags |= CallDescriptor::kSupportsTailCalls;
2238 }
2239
2240 // Patch {node} to an indirect call via the CallFunction builtin.
2241 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
2242 node->InsertInput(graph()->zone(), 0,
2243 jsgraph()->HeapConstant(callable.code()));
2244 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
2245 NodeProperties::ChangeOp(
2246 node, common()->Call(Linkage::GetStubCallDescriptor(
2247 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2248 flags)));
2249 return Changed(node);
2250 }
2251
2252 // Maybe we did at least learn something about the {receiver}.
2253 if (p.convert_mode() != convert_mode) {
2254 NodeProperties::ChangeOp(
2255 node,
2256 javascript()->CallFunction(p.arity(), p.language_mode(), p.feedback(),
2257 convert_mode, p.tail_call_mode()));
2258 return Changed(node);
2259 }
2260
2261 return NoChange();
2262 }
2263
2264
ReduceJSForInDone(Node * node)2265 Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
2266 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
2267 node->TrimInputCount(2);
2268 NodeProperties::ChangeOp(node, machine()->Word32Equal());
2269 return Changed(node);
2270 }
2271
2272
ReduceJSForInPrepare(Node * node)2273 Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) {
2274 DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
2275 Node* receiver = NodeProperties::GetValueInput(node, 0);
2276 Node* context = NodeProperties::GetContextInput(node);
2277 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
2278 Node* effect = NodeProperties::GetEffectInput(node);
2279 Node* control = NodeProperties::GetControlInput(node);
2280
2281 // Get the set of properties to enumerate.
2282 Node* cache_type = effect = graph()->NewNode(
2283 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), receiver,
2284 context, frame_state, effect, control);
2285 control = graph()->NewNode(common()->IfSuccess(), cache_type);
2286
2287 Node* receiver_map = effect =
2288 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2289 receiver, effect, control);
2290 Node* cache_type_map = effect =
2291 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2292 cache_type, effect, control);
2293 Node* meta_map = jsgraph()->HeapConstant(factory()->meta_map());
2294
2295 // If we got a map from the GetPropertyNamesFast runtime call, we can do a
2296 // fast modification check. Otherwise, we got a fixed array, and we have to
2297 // perform a slow check on every iteration.
2298 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
2299 cache_type_map, meta_map);
2300 Node* branch0 =
2301 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2302
2303 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2304 Node* cache_array_true0;
2305 Node* cache_length_true0;
2306 Node* cache_type_true0;
2307 Node* etrue0;
2308 {
2309 // Enum cache case.
2310 Node* cache_type_enum_length = etrue0 = graph()->NewNode(
2311 simplified()->LoadField(AccessBuilder::ForMapBitField3()), cache_type,
2312 effect, if_true0);
2313 cache_length_true0 = graph()->NewNode(
2314 simplified()->NumberBitwiseAnd(), cache_type_enum_length,
2315 jsgraph()->Int32Constant(Map::EnumLengthBits::kMask));
2316
2317 Node* check1 =
2318 graph()->NewNode(machine()->Word32Equal(), cache_length_true0,
2319 jsgraph()->Int32Constant(0));
2320 Node* branch1 =
2321 graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0);
2322
2323 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2324 Node* cache_array_true1;
2325 Node* etrue1;
2326 {
2327 // No properties to enumerate.
2328 cache_array_true1 =
2329 jsgraph()->HeapConstant(factory()->empty_fixed_array());
2330 etrue1 = etrue0;
2331 }
2332
2333 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2334 Node* cache_array_false1;
2335 Node* efalse1;
2336 {
2337 // Load the enumeration cache from the instance descriptors of {receiver}.
2338 Node* receiver_map_descriptors = efalse1 = graph()->NewNode(
2339 simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
2340 receiver_map, etrue0, if_false1);
2341 Node* object_map_enum_cache = efalse1 = graph()->NewNode(
2342 simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
2343 receiver_map_descriptors, efalse1, if_false1);
2344 cache_array_false1 = efalse1 = graph()->NewNode(
2345 simplified()->LoadField(
2346 AccessBuilder::ForDescriptorArrayEnumCacheBridgeCache()),
2347 object_map_enum_cache, efalse1, if_false1);
2348 }
2349
2350 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2351 etrue0 =
2352 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
2353 cache_array_true0 =
2354 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2355 cache_array_true1, cache_array_false1, if_true0);
2356
2357 cache_type_true0 = cache_type;
2358 }
2359
2360 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2361 Node* cache_array_false0;
2362 Node* cache_length_false0;
2363 Node* cache_type_false0;
2364 Node* efalse0;
2365 {
2366 // FixedArray case.
2367 cache_type_false0 = jsgraph()->OneConstant(); // Smi means slow check
2368 cache_array_false0 = cache_type;
2369 cache_length_false0 = efalse0 = graph()->NewNode(
2370 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
2371 cache_array_false0, effect, if_false0);
2372 }
2373
2374 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2375 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2376 Node* cache_array =
2377 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2378 cache_array_true0, cache_array_false0, control);
2379 Node* cache_length =
2380 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2381 cache_length_true0, cache_length_false0, control);
2382 cache_type =
2383 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2384 cache_type_true0, cache_type_false0, control);
2385
2386 for (auto edge : node->use_edges()) {
2387 Node* const use = edge.from();
2388 if (NodeProperties::IsEffectEdge(edge)) {
2389 edge.UpdateTo(effect);
2390 Revisit(use);
2391 } else {
2392 if (NodeProperties::IsControlEdge(edge)) {
2393 if (use->opcode() == IrOpcode::kIfSuccess) {
2394 Replace(use, control);
2395 } else if (use->opcode() == IrOpcode::kIfException) {
2396 edge.UpdateTo(cache_type_true0);
2397 continue;
2398 } else {
2399 UNREACHABLE();
2400 }
2401 } else {
2402 DCHECK(NodeProperties::IsValueEdge(edge));
2403 DCHECK_EQ(IrOpcode::kProjection, use->opcode());
2404 switch (ProjectionIndexOf(use->op())) {
2405 case 0:
2406 Replace(use, cache_type);
2407 break;
2408 case 1:
2409 Replace(use, cache_array);
2410 break;
2411 case 2:
2412 Replace(use, cache_length);
2413 break;
2414 default:
2415 UNREACHABLE();
2416 break;
2417 }
2418 }
2419 use->Kill();
2420 }
2421 }
2422 return NoChange(); // All uses were replaced already above.
2423 }
2424
2425
ReduceJSForInNext(Node * node)2426 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
2427 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
2428 Node* receiver = NodeProperties::GetValueInput(node, 0);
2429 Node* cache_array = NodeProperties::GetValueInput(node, 1);
2430 Node* cache_type = NodeProperties::GetValueInput(node, 2);
2431 Node* index = NodeProperties::GetValueInput(node, 3);
2432 Node* context = NodeProperties::GetContextInput(node);
2433 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
2434 Node* effect = NodeProperties::GetEffectInput(node);
2435 Node* control = NodeProperties::GetControlInput(node);
2436
2437 // Load the next {key} from the {cache_array}.
2438 Node* key = effect = graph()->NewNode(
2439 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
2440 cache_array, index, effect, control);
2441
2442 // Load the map of the {receiver}.
2443 Node* receiver_map = effect =
2444 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2445 receiver, effect, control);
2446
2447 // Check if the expected map still matches that of the {receiver}.
2448 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
2449 receiver_map, cache_type);
2450 Node* branch0 =
2451 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2452
2453 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2454 Node* etrue0;
2455 Node* vtrue0;
2456 {
2457 // Don't need filtering since expected map still matches that of the
2458 // {receiver}.
2459 etrue0 = effect;
2460 vtrue0 = key;
2461 }
2462
2463 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2464 Node* efalse0;
2465 Node* vfalse0;
2466 {
2467 // Check if the {cache_type} is zero, which indicates proxy.
2468 Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
2469 cache_type, jsgraph()->ZeroConstant());
2470 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
2471 check1, if_false0);
2472
2473 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2474 Node* etrue1;
2475 Node* vtrue1;
2476 {
2477 // Don't do filtering for proxies.
2478 etrue1 = effect;
2479 vtrue1 = key;
2480 }
2481
2482 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2483 Node* efalse1;
2484 Node* vfalse1;
2485 {
2486 // Filter the {key} to check if it's still a valid property of the
2487 // {receiver} (does the ToName conversion implicitly).
2488 vfalse1 = efalse1 = graph()->NewNode(
2489 javascript()->CallRuntime(Runtime::kForInFilter, 2), receiver, key,
2490 context, frame_state, effect, if_false1);
2491 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
2492 }
2493
2494 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2495 efalse0 =
2496 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
2497 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2498 vtrue1, vfalse1, if_false0);
2499 }
2500
2501 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2502 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2503 ReplaceWithValue(node, node, effect, control);
2504 node->ReplaceInput(0, vtrue0);
2505 node->ReplaceInput(1, vfalse0);
2506 node->ReplaceInput(2, control);
2507 node->TrimInputCount(3);
2508 NodeProperties::ChangeOp(node,
2509 common()->Phi(MachineRepresentation::kTagged, 2));
2510 return Changed(node);
2511 }
2512
2513
ReduceJSForInStep(Node * node)2514 Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
2515 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
2516 node->ReplaceInput(1, jsgraph()->Int32Constant(1));
2517 NodeProperties::ChangeOp(node, machine()->Int32Add());
2518 return Changed(node);
2519 }
2520
2521
ReduceSelect(Node * node)2522 Reduction JSTypedLowering::ReduceSelect(Node* node) {
2523 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
2524 Node* const condition = NodeProperties::GetValueInput(node, 0);
2525 Type* const condition_type = NodeProperties::GetType(condition);
2526 Node* const vtrue = NodeProperties::GetValueInput(node, 1);
2527 Type* const vtrue_type = NodeProperties::GetType(vtrue);
2528 Node* const vfalse = NodeProperties::GetValueInput(node, 2);
2529 Type* const vfalse_type = NodeProperties::GetType(vfalse);
2530 if (condition_type->Is(true_type_)) {
2531 // Select(condition:true, vtrue, vfalse) => vtrue
2532 return Replace(vtrue);
2533 }
2534 if (condition_type->Is(false_type_)) {
2535 // Select(condition:false, vtrue, vfalse) => vfalse
2536 return Replace(vfalse);
2537 }
2538 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
2539 // Select(condition, vtrue:true, vfalse:false) => condition
2540 return Replace(condition);
2541 }
2542 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
2543 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
2544 node->TrimInputCount(1);
2545 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
2546 return Changed(node);
2547 }
2548 return NoChange();
2549 }
2550
2551
Reduce(Node * node)2552 Reduction JSTypedLowering::Reduce(Node* node) {
2553 // Check if the output type is a singleton. In that case we already know the
2554 // result value and can simply replace the node if it's eliminable.
2555 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
2556 node->op()->HasProperty(Operator::kEliminatable)) {
2557 Type* upper = NodeProperties::GetType(node);
2558 if (upper->IsConstant()) {
2559 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
2560 ReplaceWithValue(node, replacement);
2561 return Changed(replacement);
2562 } else if (upper->Is(Type::MinusZero())) {
2563 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
2564 ReplaceWithValue(node, replacement);
2565 return Changed(replacement);
2566 } else if (upper->Is(Type::NaN())) {
2567 Node* replacement = jsgraph()->NaNConstant();
2568 ReplaceWithValue(node, replacement);
2569 return Changed(replacement);
2570 } else if (upper->Is(Type::Null())) {
2571 Node* replacement = jsgraph()->NullConstant();
2572 ReplaceWithValue(node, replacement);
2573 return Changed(replacement);
2574 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
2575 Node* replacement = jsgraph()->Constant(upper->Min());
2576 ReplaceWithValue(node, replacement);
2577 return Changed(replacement);
2578 } else if (upper->Is(Type::Undefined())) {
2579 Node* replacement = jsgraph()->UndefinedConstant();
2580 ReplaceWithValue(node, replacement);
2581 return Changed(replacement);
2582 }
2583 }
2584 switch (node->opcode()) {
2585 case IrOpcode::kJSEqual:
2586 return ReduceJSEqual(node, false);
2587 case IrOpcode::kJSNotEqual:
2588 return ReduceJSEqual(node, true);
2589 case IrOpcode::kJSStrictEqual:
2590 return ReduceJSStrictEqual(node, false);
2591 case IrOpcode::kJSStrictNotEqual:
2592 return ReduceJSStrictEqual(node, true);
2593 case IrOpcode::kJSLessThan: // fall through
2594 case IrOpcode::kJSGreaterThan: // fall through
2595 case IrOpcode::kJSLessThanOrEqual: // fall through
2596 case IrOpcode::kJSGreaterThanOrEqual:
2597 return ReduceJSComparison(node);
2598 case IrOpcode::kJSBitwiseOr:
2599 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
2600 case IrOpcode::kJSBitwiseXor:
2601 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
2602 case IrOpcode::kJSBitwiseAnd:
2603 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
2604 case IrOpcode::kJSShiftLeft:
2605 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
2606 case IrOpcode::kJSShiftRight:
2607 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
2608 case IrOpcode::kJSShiftRightLogical:
2609 return ReduceUI32Shift(node, kUnsigned,
2610 simplified()->NumberShiftRightLogical());
2611 case IrOpcode::kJSAdd:
2612 return ReduceJSAdd(node);
2613 case IrOpcode::kJSSubtract:
2614 return ReduceNumberBinop(node, simplified()->NumberSubtract());
2615 case IrOpcode::kJSMultiply:
2616 return ReduceNumberBinop(node, simplified()->NumberMultiply());
2617 case IrOpcode::kJSDivide:
2618 return ReduceNumberBinop(node, simplified()->NumberDivide());
2619 case IrOpcode::kJSModulus:
2620 return ReduceJSModulus(node);
2621 case IrOpcode::kJSToBoolean:
2622 return ReduceJSToBoolean(node);
2623 case IrOpcode::kJSToNumber:
2624 return ReduceJSToNumber(node);
2625 case IrOpcode::kJSToString:
2626 return ReduceJSToString(node);
2627 case IrOpcode::kJSToObject:
2628 return ReduceJSToObject(node);
2629 case IrOpcode::kJSLoadNamed:
2630 return ReduceJSLoadNamed(node);
2631 case IrOpcode::kJSLoadProperty:
2632 return ReduceJSLoadProperty(node);
2633 case IrOpcode::kJSStoreProperty:
2634 return ReduceJSStoreProperty(node);
2635 case IrOpcode::kJSInstanceOf:
2636 return ReduceJSInstanceOf(node);
2637 case IrOpcode::kJSLoadContext:
2638 return ReduceJSLoadContext(node);
2639 case IrOpcode::kJSStoreContext:
2640 return ReduceJSStoreContext(node);
2641 case IrOpcode::kJSConvertReceiver:
2642 return ReduceJSConvertReceiver(node);
2643 case IrOpcode::kJSCreate:
2644 return ReduceJSCreate(node);
2645 case IrOpcode::kJSCreateArguments:
2646 return ReduceJSCreateArguments(node);
2647 case IrOpcode::kJSCreateArray:
2648 return ReduceJSCreateArray(node);
2649 case IrOpcode::kJSCreateClosure:
2650 return ReduceJSCreateClosure(node);
2651 case IrOpcode::kJSCreateIterResultObject:
2652 return ReduceJSCreateIterResultObject(node);
2653 case IrOpcode::kJSCreateLiteralArray:
2654 return ReduceJSCreateLiteralArray(node);
2655 case IrOpcode::kJSCreateLiteralObject:
2656 return ReduceJSCreateLiteralObject(node);
2657 case IrOpcode::kJSCreateFunctionContext:
2658 return ReduceJSCreateFunctionContext(node);
2659 case IrOpcode::kJSCreateWithContext:
2660 return ReduceJSCreateWithContext(node);
2661 case IrOpcode::kJSCreateCatchContext:
2662 return ReduceJSCreateCatchContext(node);
2663 case IrOpcode::kJSCreateBlockContext:
2664 return ReduceJSCreateBlockContext(node);
2665 case IrOpcode::kJSCallConstruct:
2666 return ReduceJSCallConstruct(node);
2667 case IrOpcode::kJSCallFunction:
2668 return ReduceJSCallFunction(node);
2669 case IrOpcode::kJSForInDone:
2670 return ReduceJSForInDone(node);
2671 case IrOpcode::kJSForInNext:
2672 return ReduceJSForInNext(node);
2673 case IrOpcode::kJSForInPrepare:
2674 return ReduceJSForInPrepare(node);
2675 case IrOpcode::kJSForInStep:
2676 return ReduceJSForInStep(node);
2677 case IrOpcode::kSelect:
2678 return ReduceSelect(node);
2679 default:
2680 break;
2681 }
2682 return NoChange();
2683 }
2684
2685
Word32Shl(Node * const lhs,int32_t const rhs)2686 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
2687 if (rhs == 0) return lhs;
2688 return graph()->NewNode(machine()->Word32Shl(), lhs,
2689 jsgraph()->Int32Constant(rhs));
2690 }
2691
2692
2693 // Helper that allocates a FixedArray holding argument values recorded in the
2694 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
AllocateArguments(Node * effect,Node * control,Node * frame_state)2695 Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control,
2696 Node* frame_state) {
2697 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2698 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2699 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
2700
2701 // Prepare an iterator over argument values recorded in the frame state.
2702 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2703 StateValuesAccess parameters_access(parameters);
2704 auto parameters_it = ++parameters_access.begin();
2705
2706 // Actually allocate the backing store.
2707 AllocationBuilder a(jsgraph(), effect, control);
2708 a.AllocateArray(argument_count, factory()->fixed_array_map());
2709 for (int i = 0; i < argument_count; ++i, ++parameters_it) {
2710 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
2711 }
2712 return a.Finish();
2713 }
2714
2715
2716 // Helper that allocates a FixedArray holding argument values recorded in the
2717 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
AllocateRestArguments(Node * effect,Node * control,Node * frame_state,int start_index)2718 Node* JSTypedLowering::AllocateRestArguments(Node* effect, Node* control,
2719 Node* frame_state,
2720 int start_index) {
2721 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2722 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2723 int num_elements = std::max(0, argument_count - start_index);
2724 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
2725
2726 // Prepare an iterator over argument values recorded in the frame state.
2727 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2728 StateValuesAccess parameters_access(parameters);
2729 auto parameters_it = ++parameters_access.begin();
2730
2731 // Skip unused arguments.
2732 for (int i = 0; i < start_index; i++) {
2733 ++parameters_it;
2734 }
2735
2736 // Actually allocate the backing store.
2737 AllocationBuilder a(jsgraph(), effect, control);
2738 a.AllocateArray(num_elements, factory()->fixed_array_map());
2739 for (int i = 0; i < num_elements; ++i, ++parameters_it) {
2740 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
2741 }
2742 return a.Finish();
2743 }
2744
2745
2746 // Helper that allocates a FixedArray serving as a parameter map for values
2747 // recorded in the given {frame_state}. Some elements map to slots within the
2748 // given {context}. Serves as backing store for JSCreateArguments nodes.
AllocateAliasedArguments(Node * effect,Node * control,Node * frame_state,Node * context,Handle<SharedFunctionInfo> shared,bool * has_aliased_arguments)2749 Node* JSTypedLowering::AllocateAliasedArguments(
2750 Node* effect, Node* control, Node* frame_state, Node* context,
2751 Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
2752 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2753 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2754 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
2755
2756 // If there is no aliasing, the arguments object elements are not special in
2757 // any way, we can just return an unmapped backing store instead.
2758 int parameter_count = shared->internal_formal_parameter_count();
2759 if (parameter_count == 0) {
2760 return AllocateArguments(effect, control, frame_state);
2761 }
2762
2763 // Calculate number of argument values being aliased/mapped.
2764 int mapped_count = Min(argument_count, parameter_count);
2765 *has_aliased_arguments = true;
2766
2767 // Prepare an iterator over argument values recorded in the frame state.
2768 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2769 StateValuesAccess parameters_access(parameters);
2770 auto paratemers_it = ++parameters_access.begin();
2771
2772 // The unmapped argument values recorded in the frame state are stored yet
2773 // another indirection away and then linked into the parameter map below,
2774 // whereas mapped argument values are replaced with a hole instead.
2775 AllocationBuilder aa(jsgraph(), effect, control);
2776 aa.AllocateArray(argument_count, factory()->fixed_array_map());
2777 for (int i = 0; i < mapped_count; ++i, ++paratemers_it) {
2778 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
2779 }
2780 for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) {
2781 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node);
2782 }
2783 Node* arguments = aa.Finish();
2784
2785 // Actually allocate the backing store.
2786 AllocationBuilder a(jsgraph(), arguments, control);
2787 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
2788 a.Store(AccessBuilder::ForFixedArraySlot(0), context);
2789 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
2790 for (int i = 0; i < mapped_count; ++i) {
2791 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
2792 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
2793 }
2794 return a.Finish();
2795 }
2796
2797
AllocateElements(Node * effect,Node * control,ElementsKind elements_kind,int capacity,PretenureFlag pretenure)2798 Node* JSTypedLowering::AllocateElements(Node* effect, Node* control,
2799 ElementsKind elements_kind,
2800 int capacity, PretenureFlag pretenure) {
2801 DCHECK_LE(1, capacity);
2802 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
2803
2804 Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
2805 ? factory()->fixed_double_array_map()
2806 : factory()->fixed_array_map();
2807 ElementAccess access = IsFastDoubleElementsKind(elements_kind)
2808 ? AccessBuilder::ForFixedDoubleArrayElement()
2809 : AccessBuilder::ForFixedArrayElement();
2810 Node* value =
2811 IsFastDoubleElementsKind(elements_kind)
2812 ? jsgraph()->Float64Constant(bit_cast<double>(kHoleNanInt64))
2813 : jsgraph()->TheHoleConstant();
2814
2815 // Actually allocate the backing store.
2816 AllocationBuilder a(jsgraph(), effect, control);
2817 a.AllocateArray(capacity, elements_map, pretenure);
2818 for (int i = 0; i < capacity; ++i) {
2819 Node* index = jsgraph()->Constant(i);
2820 a.Store(access, index, value);
2821 }
2822 return a.Finish();
2823 }
2824
2825
factory() const2826 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2827
2828
graph() const2829 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2830
2831
isolate() const2832 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2833
2834
javascript() const2835 JSOperatorBuilder* JSTypedLowering::javascript() const {
2836 return jsgraph()->javascript();
2837 }
2838
2839
common() const2840 CommonOperatorBuilder* JSTypedLowering::common() const {
2841 return jsgraph()->common();
2842 }
2843
2844
simplified() const2845 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2846 return jsgraph()->simplified();
2847 }
2848
2849
machine() const2850 MachineOperatorBuilder* JSTypedLowering::machine() const {
2851 return jsgraph()->machine();
2852 }
2853
2854
dependencies() const2855 CompilationDependencies* JSTypedLowering::dependencies() const {
2856 return dependencies_;
2857 }
2858
2859 } // namespace compiler
2860 } // namespace internal
2861 } // namespace v8
2862