• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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