• 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/compiler/js-typed-lowering.h"
6 
7 #include "src/ast/modules.h"
8 #include "src/builtins/builtins-utils.h"
9 #include "src/code-factory.h"
10 #include "src/compilation-dependencies.h"
11 #include "src/compiler/access-builder.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/operator-properties.h"
17 #include "src/compiler/type-cache.h"
18 #include "src/compiler/types.h"
19 #include "src/objects-inl.h"
20 
21 namespace v8 {
22 namespace internal {
23 namespace compiler {
24 
25 // A helper class to simplify the process of reducing a single binop node with a
26 // JSOperator. This class manages the rewriting of context, control, and effect
27 // dependencies during lowering of a binop and contains numerous helper
28 // functions for matching the types of inputs to an operation.
29 class JSBinopReduction final {
30  public:
JSBinopReduction(JSTypedLowering * lowering,Node * node)31   JSBinopReduction(JSTypedLowering* lowering, Node* node)
32       : lowering_(lowering), node_(node) {}
33 
GetCompareNumberOperationHint(NumberOperationHint * hint)34   bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
35     if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
36       DCHECK_EQ(1, node_->op()->EffectOutputCount());
37       switch (CompareOperationHintOf(node_->op())) {
38         case CompareOperationHint::kSignedSmall:
39           *hint = NumberOperationHint::kSignedSmall;
40           return true;
41         case CompareOperationHint::kNumber:
42           *hint = NumberOperationHint::kNumber;
43           return true;
44         case CompareOperationHint::kNumberOrOddball:
45           *hint = NumberOperationHint::kNumberOrOddball;
46           return true;
47         case CompareOperationHint::kAny:
48         case CompareOperationHint::kNone:
49         case CompareOperationHint::kString:
50         case CompareOperationHint::kReceiver:
51         case CompareOperationHint::kInternalizedString:
52           break;
53       }
54     }
55     return false;
56   }
57 
IsInternalizedStringCompareOperation()58   bool IsInternalizedStringCompareOperation() {
59     if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
60       DCHECK_EQ(1, node_->op()->EffectOutputCount());
61       return (CompareOperationHintOf(node_->op()) ==
62               CompareOperationHint::kInternalizedString) &&
63              BothInputsMaybe(Type::InternalizedString());
64     }
65     return false;
66   }
67 
IsReceiverCompareOperation()68   bool IsReceiverCompareOperation() {
69     if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
70       DCHECK_EQ(1, node_->op()->EffectOutputCount());
71       return (CompareOperationHintOf(node_->op()) ==
72               CompareOperationHint::kReceiver) &&
73              BothInputsMaybe(Type::Receiver());
74     }
75     return false;
76   }
77 
IsStringCompareOperation()78   bool IsStringCompareOperation() {
79     if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
80       DCHECK_EQ(1, node_->op()->EffectOutputCount());
81       return (CompareOperationHintOf(node_->op()) ==
82               CompareOperationHint::kString) &&
83              BothInputsMaybe(Type::String());
84     }
85     return false;
86   }
87 
88   // Check if a string addition will definitely result in creating a ConsString,
89   // i.e. if the combined length of the resulting string exceeds the ConsString
90   // minimum length.
ShouldCreateConsString()91   bool ShouldCreateConsString() {
92     DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
93     DCHECK(OneInputIs(Type::String()));
94     if (BothInputsAre(Type::String()) ||
95         ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) &&
96          BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) {
97       HeapObjectBinopMatcher m(node_);
98       if (m.right().HasValue() && m.right().Value()->IsString()) {
99         Handle<String> right_string = Handle<String>::cast(m.right().Value());
100         if (right_string->length() >= ConsString::kMinLength) return true;
101       }
102       if (m.left().HasValue() && m.left().Value()->IsString()) {
103         Handle<String> left_string = Handle<String>::cast(m.left().Value());
104         if (left_string->length() >= ConsString::kMinLength) {
105           // The invariant for ConsString requires the left hand side to be
106           // a sequential or external string if the right hand side is the
107           // empty string. Since we don't know anything about the right hand
108           // side here, we must ensure that the left hand side satisfy the
109           // constraints independent of the right hand side.
110           return left_string->IsSeqString() || left_string->IsExternalString();
111         }
112       }
113     }
114     return false;
115   }
116 
117   // Inserts a CheckReceiver for the left input.
CheckLeftInputToReceiver()118   void CheckLeftInputToReceiver() {
119     Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
120                                         effect(), control());
121     node_->ReplaceInput(0, left_input);
122     update_effect(left_input);
123   }
124 
125   // Checks that both inputs are Receiver, and if we don't know
126   // statically that one side is already a Receiver, insert a
127   // CheckReceiver node.
CheckInputsToReceiver()128   void CheckInputsToReceiver() {
129     if (!left_type()->Is(Type::Receiver())) {
130       CheckLeftInputToReceiver();
131     }
132     if (!right_type()->Is(Type::Receiver())) {
133       Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
134                                            right(), effect(), control());
135       node_->ReplaceInput(1, right_input);
136       update_effect(right_input);
137     }
138   }
139 
140   // Checks that both inputs are String, and if we don't know
141   // statically that one side is already a String, insert a
142   // CheckString node.
CheckInputsToString()143   void CheckInputsToString() {
144     if (!left_type()->Is(Type::String())) {
145       Node* left_input = graph()->NewNode(simplified()->CheckString(), left(),
146                                           effect(), control());
147       node_->ReplaceInput(0, left_input);
148       update_effect(left_input);
149     }
150     if (!right_type()->Is(Type::String())) {
151       Node* right_input = graph()->NewNode(simplified()->CheckString(), right(),
152                                            effect(), control());
153       node_->ReplaceInput(1, right_input);
154       update_effect(right_input);
155     }
156   }
157 
158   // Checks that both inputs are InternalizedString, and if we don't know
159   // statically that one side is already an InternalizedString, insert a
160   // CheckInternalizedString node.
CheckInputsToInternalizedString()161   void CheckInputsToInternalizedString() {
162     if (!left_type()->Is(Type::UniqueName())) {
163       Node* left_input = graph()->NewNode(
164           simplified()->CheckInternalizedString(), left(), effect(), control());
165       node_->ReplaceInput(0, left_input);
166       update_effect(left_input);
167     }
168     if (!right_type()->Is(Type::UniqueName())) {
169       Node* right_input =
170           graph()->NewNode(simplified()->CheckInternalizedString(), right(),
171                            effect(), control());
172       node_->ReplaceInput(1, right_input);
173       update_effect(right_input);
174     }
175   }
176 
ConvertInputsToNumber()177   void ConvertInputsToNumber() {
178     // To convert the inputs to numbers, we have to provide frame states
179     // for lazy bailouts in the ToNumber conversions.
180     // We use a little hack here: we take the frame state before the binary
181     // operation and use it to construct the frame states for the conversion
182     // so that after the deoptimization, the binary operation IC gets
183     // already converted values from full code. This way we are sure that we
184     // will not re-do any of the side effects.
185 
186     Node* left_input = nullptr;
187     Node* right_input = nullptr;
188     bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
189     bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
190     bool handles_exception = NodeProperties::IsExceptionalCall(node_);
191 
192     if (!left_is_primitive && !right_is_primitive && handles_exception) {
193       ConvertBothInputsToNumber(&left_input, &right_input);
194     } else {
195       left_input = left_is_primitive
196                        ? ConvertPlainPrimitiveToNumber(left())
197                        : ConvertSingleInputToNumber(
198                              left(), CreateFrameStateForLeftInput());
199       right_input =
200           right_is_primitive
201               ? ConvertPlainPrimitiveToNumber(right())
202               : ConvertSingleInputToNumber(
203                     right(), CreateFrameStateForRightInput(left_input));
204     }
205 
206     node_->ReplaceInput(0, left_input);
207     node_->ReplaceInput(1, right_input);
208   }
209 
ConvertInputsToUI32(Signedness left_signedness,Signedness right_signedness)210   void ConvertInputsToUI32(Signedness left_signedness,
211                            Signedness right_signedness) {
212     node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
213     node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
214   }
215 
SwapInputs()216   void SwapInputs() {
217     Node* l = left();
218     Node* r = right();
219     node_->ReplaceInput(0, r);
220     node_->ReplaceInput(1, l);
221   }
222 
223   // Remove all effect and control inputs and outputs to this node and change
224   // to the pure operator {op}, possibly inserting a boolean inversion.
ChangeToPureOperator(const Operator * op,bool invert=false,Type * type=Type::Any ())225   Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
226                                  Type* type = Type::Any()) {
227     DCHECK_EQ(0, op->EffectInputCount());
228     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
229     DCHECK_EQ(0, op->ControlInputCount());
230     DCHECK_EQ(2, op->ValueInputCount());
231 
232     // Remove the effects from the node, and update its effect/control usages.
233     if (node_->op()->EffectInputCount() > 0) {
234       lowering_->RelaxEffectsAndControls(node_);
235     }
236     // Remove the inputs corresponding to context, effect, and control.
237     NodeProperties::RemoveNonValueInputs(node_);
238     // Finally, update the operator to the new one.
239     NodeProperties::ChangeOp(node_, op);
240 
241     // TODO(jarin): Replace the explicit typing hack with a call to some method
242     // that encapsulates changing the operator and re-typing.
243     Type* node_type = NodeProperties::GetType(node_);
244     NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
245 
246     if (invert) {
247       // Insert an boolean not to invert the value.
248       Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
249       node_->ReplaceUses(value);
250       // Note: ReplaceUses() smashes all uses, so smash it back here.
251       value->ReplaceInput(0, node_);
252       return lowering_->Replace(value);
253     }
254     return lowering_->Changed(node_);
255   }
256 
ChangeToSpeculativeOperator(const Operator * op,bool invert,Type * upper_bound)257   Reduction ChangeToSpeculativeOperator(const Operator* op, bool invert,
258                                         Type* upper_bound) {
259     DCHECK_EQ(1, op->EffectInputCount());
260     DCHECK_EQ(1, op->EffectOutputCount());
261     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
262     DCHECK_EQ(1, op->ControlInputCount());
263     DCHECK_EQ(0, op->ControlOutputCount());
264     DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
265     DCHECK_EQ(2, op->ValueInputCount());
266 
267     DCHECK_EQ(1, node_->op()->EffectInputCount());
268     DCHECK_EQ(1, node_->op()->EffectOutputCount());
269     DCHECK_EQ(1, node_->op()->ControlInputCount());
270     DCHECK_EQ(2, node_->op()->ValueInputCount());
271 
272     // Reconnect the control output to bypass the IfSuccess node and
273     // possibly disconnect from the IfException node.
274     for (Edge edge : node_->use_edges()) {
275       Node* const user = edge.from();
276       DCHECK(!user->IsDead());
277       if (NodeProperties::IsControlEdge(edge)) {
278         if (user->opcode() == IrOpcode::kIfSuccess) {
279           user->ReplaceUses(NodeProperties::GetControlInput(node_));
280           user->Kill();
281         } else {
282           DCHECK_EQ(user->opcode(), IrOpcode::kIfException);
283           edge.UpdateTo(jsgraph()->Dead());
284         }
285       }
286     }
287 
288     // Remove the frame state and the context.
289     if (OperatorProperties::HasFrameStateInput(node_->op())) {
290       node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
291     }
292     node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
293 
294     NodeProperties::ChangeOp(node_, op);
295 
296     // Update the type to number.
297     Type* node_type = NodeProperties::GetType(node_);
298     NodeProperties::SetType(node_,
299                             Type::Intersect(node_type, upper_bound, zone()));
300 
301     if (invert) {
302       // Insert an boolean not to invert the value.
303       Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
304       node_->ReplaceUses(value);
305       // Note: ReplaceUses() smashes all uses, so smash it back here.
306       value->ReplaceInput(0, node_);
307       return lowering_->Replace(value);
308     }
309     return lowering_->Changed(node_);
310   }
311 
ChangeToPureOperator(const Operator * op,Type * type)312   Reduction ChangeToPureOperator(const Operator* op, Type* type) {
313     return ChangeToPureOperator(op, false, type);
314   }
315 
ChangeToSpeculativeOperator(const Operator * op,Type * type)316   Reduction ChangeToSpeculativeOperator(const Operator* op, Type* type) {
317     return ChangeToSpeculativeOperator(op, false, type);
318   }
319 
NumberOp()320   const Operator* NumberOp() {
321     switch (node_->opcode()) {
322       case IrOpcode::kJSAdd:
323         return simplified()->NumberAdd();
324       case IrOpcode::kJSSubtract:
325         return simplified()->NumberSubtract();
326       case IrOpcode::kJSMultiply:
327         return simplified()->NumberMultiply();
328       case IrOpcode::kJSDivide:
329         return simplified()->NumberDivide();
330       case IrOpcode::kJSModulus:
331         return simplified()->NumberModulus();
332       case IrOpcode::kJSBitwiseAnd:
333         return simplified()->NumberBitwiseAnd();
334       case IrOpcode::kJSBitwiseOr:
335         return simplified()->NumberBitwiseOr();
336       case IrOpcode::kJSBitwiseXor:
337         return simplified()->NumberBitwiseXor();
338       case IrOpcode::kJSShiftLeft:
339         return simplified()->NumberShiftLeft();
340       case IrOpcode::kJSShiftRight:
341         return simplified()->NumberShiftRight();
342       case IrOpcode::kJSShiftRightLogical:
343         return simplified()->NumberShiftRightLogical();
344       default:
345         break;
346     }
347     UNREACHABLE();
348     return nullptr;
349   }
350 
NumberOpFromSpeculativeNumberOp()351   const Operator* NumberOpFromSpeculativeNumberOp() {
352     switch (node_->opcode()) {
353       case IrOpcode::kSpeculativeNumberAdd:
354         return simplified()->NumberAdd();
355       case IrOpcode::kSpeculativeNumberSubtract:
356         return simplified()->NumberSubtract();
357       case IrOpcode::kSpeculativeNumberMultiply:
358         return simplified()->NumberMultiply();
359       case IrOpcode::kSpeculativeNumberDivide:
360         return simplified()->NumberDivide();
361       case IrOpcode::kSpeculativeNumberModulus:
362         return simplified()->NumberModulus();
363       default:
364         break;
365     }
366     UNREACHABLE();
367     return nullptr;
368   }
369 
LeftInputIs(Type * t)370   bool LeftInputIs(Type* t) { return left_type()->Is(t); }
371 
RightInputIs(Type * t)372   bool RightInputIs(Type* t) { return right_type()->Is(t); }
373 
OneInputIs(Type * t)374   bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
375 
BothInputsAre(Type * t)376   bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
377 
BothInputsMaybe(Type * t)378   bool BothInputsMaybe(Type* t) {
379     return left_type()->Maybe(t) && right_type()->Maybe(t);
380   }
381 
OneInputCannotBe(Type * t)382   bool OneInputCannotBe(Type* t) {
383     return !left_type()->Maybe(t) || !right_type()->Maybe(t);
384   }
385 
NeitherInputCanBe(Type * t)386   bool NeitherInputCanBe(Type* t) {
387     return !left_type()->Maybe(t) && !right_type()->Maybe(t);
388   }
389 
effect()390   Node* effect() { return NodeProperties::GetEffectInput(node_); }
control()391   Node* control() { return NodeProperties::GetControlInput(node_); }
context()392   Node* context() { return NodeProperties::GetContextInput(node_); }
left()393   Node* left() { return NodeProperties::GetValueInput(node_, 0); }
right()394   Node* right() { return NodeProperties::GetValueInput(node_, 1); }
left_type()395   Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
right_type()396   Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
type()397   Type* type() { return NodeProperties::GetType(node_); }
398 
simplified()399   SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
graph() const400   Graph* graph() const { return lowering_->graph(); }
jsgraph()401   JSGraph* jsgraph() { return lowering_->jsgraph(); }
javascript()402   JSOperatorBuilder* javascript() { return lowering_->javascript(); }
common()403   CommonOperatorBuilder* common() { return jsgraph()->common(); }
zone() const404   Zone* zone() const { return graph()->zone(); }
405 
406  private:
407   JSTypedLowering* lowering_;  // The containing lowering instance.
408   Node* node_;                 // The original node.
409 
CreateFrameStateForLeftInput()410   Node* CreateFrameStateForLeftInput() {
411     // Deoptimization is disabled => return dummy frame state instead.
412     Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
413     DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
414     return dummy_state;
415   }
416 
CreateFrameStateForRightInput(Node * converted_left)417   Node* CreateFrameStateForRightInput(Node* converted_left) {
418     // Deoptimization is disabled => return dummy frame state instead.
419     Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
420     DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
421     return dummy_state;
422   }
423 
ConvertPlainPrimitiveToNumber(Node * node)424   Node* ConvertPlainPrimitiveToNumber(Node* node) {
425     DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
426     // Avoid inserting too many eager ToNumber() operations.
427     Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
428     if (reduction.Changed()) return reduction.replacement();
429     if (NodeProperties::GetType(node)->Is(Type::Number())) {
430       return node;
431     }
432     return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
433   }
434 
ConvertSingleInputToNumber(Node * node,Node * frame_state)435   Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
436     DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
437     Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
438                                      frame_state, effect(), control());
439     Node* const if_success = graph()->NewNode(common()->IfSuccess(), n);
440     NodeProperties::ReplaceControlInput(node_, if_success);
441     NodeProperties::ReplaceUses(node_, node_, node_, node_, n);
442     update_effect(n);
443     return n;
444   }
445 
ConvertBothInputsToNumber(Node ** left_result,Node ** right_result)446   void ConvertBothInputsToNumber(Node** left_result, Node** right_result) {
447     Node* projections[2];
448 
449     // Find {IfSuccess} and {IfException} continuations of the operation.
450     NodeProperties::CollectControlProjections(node_, projections, 2);
451     Node* if_exception = projections[1];
452     Node* if_success = projections[0];
453 
454     // Insert two ToNumber() operations that both potentially throw.
455     Node* left_state = CreateFrameStateForLeftInput();
456     Node* left_conv =
457         graph()->NewNode(javascript()->ToNumber(), left(), context(),
458                          left_state, effect(), control());
459     Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
460     Node* right_state = CreateFrameStateForRightInput(left_conv);
461     Node* right_conv =
462         graph()->NewNode(javascript()->ToNumber(), right(), context(),
463                          right_state, left_conv, left_success);
464     Node* left_exception =
465         graph()->NewNode(common()->IfException(), left_conv, left_conv);
466     Node* right_exception =
467         graph()->NewNode(common()->IfException(), right_conv, right_conv);
468     NodeProperties::ReplaceControlInput(if_success, right_conv);
469     update_effect(right_conv);
470 
471     // Wire conversions to existing {IfException} continuation.
472     Node* exception_merge = if_exception;
473     Node* exception_value =
474         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
475                          left_exception, right_exception, exception_merge);
476     Node* exception_effect =
477         graph()->NewNode(common()->EffectPhi(2), left_exception,
478                          right_exception, exception_merge);
479     for (Edge edge : exception_merge->use_edges()) {
480       if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
481       if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
482     }
483     NodeProperties::RemoveType(exception_merge);
484     exception_merge->ReplaceInput(0, left_exception);
485     exception_merge->ReplaceInput(1, right_exception);
486     NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
487 
488     *left_result = left_conv;
489     *right_result = right_conv;
490   }
491 
ConvertToUI32(Node * node,Signedness signedness)492   Node* ConvertToUI32(Node* node, Signedness signedness) {
493     // Avoid introducing too many eager NumberToXXnt32() operations.
494     Type* type = NodeProperties::GetType(node);
495     if (signedness == kSigned) {
496       if (!type->Is(Type::Signed32())) {
497         node = graph()->NewNode(simplified()->NumberToInt32(), node);
498       }
499     } else {
500       DCHECK_EQ(kUnsigned, signedness);
501       if (!type->Is(Type::Unsigned32())) {
502         node = graph()->NewNode(simplified()->NumberToUint32(), node);
503       }
504     }
505     return node;
506   }
507 
update_effect(Node * effect)508   void update_effect(Node* effect) {
509     NodeProperties::ReplaceEffectInput(node_, effect);
510   }
511 };
512 
513 
514 // TODO(turbofan): js-typed-lowering improvements possible
515 // - immediately put in type bounds for all new nodes
516 // - relax effects from generic but not-side-effecting operations
517 
JSTypedLowering(Editor * editor,CompilationDependencies * dependencies,Flags flags,JSGraph * jsgraph,Zone * zone)518 JSTypedLowering::JSTypedLowering(Editor* editor,
519                                  CompilationDependencies* dependencies,
520                                  Flags flags, JSGraph* jsgraph, Zone* zone)
521     : AdvancedReducer(editor),
522       dependencies_(dependencies),
523       flags_(flags),
524       jsgraph_(jsgraph),
525       pointer_comparable_type_(Type::Union(
526           Type::Oddball(),
527           Type::Union(
528               Type::SymbolOrReceiver(),
529               Type::HeapConstant(factory()->empty_string(), graph()->zone()),
530               graph()->zone()),
531           graph()->zone())),
532       type_cache_(TypeCache::Get()) {
533   for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
534     double min = kMinInt / (1 << k);
535     double max = kMaxInt / (1 << k);
536     shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
537   }
538 }
539 
ReduceSpeculativeNumberAdd(Node * node)540 Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
541   JSBinopReduction r(this, node);
542   NumberOperationHint hint = NumberOperationHintOf(node->op());
543   if (hint == NumberOperationHint::kNumberOrOddball &&
544       r.BothInputsAre(Type::PlainPrimitive()) &&
545       r.NeitherInputCanBe(Type::StringOrReceiver())) {
546     // SpeculativeNumberAdd(x:-string, y:-string) =>
547     //     NumberAdd(ToNumber(x), ToNumber(y))
548     r.ConvertInputsToNumber();
549     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
550   }
551   return NoChange();
552 }
553 
ReduceJSAdd(Node * node)554 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
555   JSBinopReduction r(this, node);
556   if (r.BothInputsAre(Type::Number())) {
557     // JSAdd(x:number, y:number) => NumberAdd(x, y)
558     r.ConvertInputsToNumber();
559     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
560   }
561   if ((r.BothInputsAre(Type::PlainPrimitive()) ||
562        !(flags() & kDeoptimizationEnabled)) &&
563       r.NeitherInputCanBe(Type::StringOrReceiver())) {
564     // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
565     r.ConvertInputsToNumber();
566     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
567   }
568   if (r.OneInputIs(Type::String())) {
569     if (r.ShouldCreateConsString()) {
570       return ReduceCreateConsString(node);
571     }
572     StringAddFlags flags = STRING_ADD_CHECK_NONE;
573     if (!r.LeftInputIs(Type::String())) {
574       flags = STRING_ADD_CONVERT_LEFT;
575     } else if (!r.RightInputIs(Type::String())) {
576       flags = STRING_ADD_CONVERT_RIGHT;
577     }
578     Operator::Properties properties = node->op()->properties();
579     if (r.NeitherInputCanBe(Type::Receiver())) {
580       // Both sides are already strings, so we know that the
581       // string addition will not cause any observable side
582       // effects; it can still throw obviously.
583       properties = Operator::kNoWrite | Operator::kNoDeopt;
584     }
585     // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
586     // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
587     Callable const callable =
588         CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
589     CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
590         isolate(), graph()->zone(), callable.descriptor(), 0,
591         CallDescriptor::kNeedsFrameState, properties);
592     DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
593     node->InsertInput(graph()->zone(), 0,
594                       jsgraph()->HeapConstant(callable.code()));
595     NodeProperties::ChangeOp(node, common()->Call(desc));
596     return Changed(node);
597   }
598   return NoChange();
599 }
600 
ReduceNumberBinop(Node * node)601 Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
602   JSBinopReduction r(this, node);
603   if (r.BothInputsAre(Type::PlainPrimitive()) ||
604       !(flags() & kDeoptimizationEnabled)) {
605     r.ConvertInputsToNumber();
606     return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
607   }
608   return NoChange();
609 }
610 
ReduceSpeculativeNumberBinop(Node * node)611 Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
612   JSBinopReduction r(this, node);
613   NumberOperationHint hint = NumberOperationHintOf(node->op());
614   if (hint == NumberOperationHint::kNumberOrOddball &&
615       r.BothInputsAre(Type::NumberOrOddball())) {
616     r.ConvertInputsToNumber();
617     return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
618                                   Type::Number());
619   }
620   return NoChange();
621 }
622 
ReduceInt32Binop(Node * node)623 Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
624   JSBinopReduction r(this, node);
625   if (r.BothInputsAre(Type::PlainPrimitive()) ||
626       !(flags() & kDeoptimizationEnabled)) {
627     r.ConvertInputsToNumber();
628     r.ConvertInputsToUI32(kSigned, kSigned);
629     return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
630   }
631   return NoChange();
632 }
633 
ReduceUI32Shift(Node * node,Signedness signedness)634 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
635   JSBinopReduction r(this, node);
636   if (r.BothInputsAre(Type::PlainPrimitive()) ||
637       !(flags() & kDeoptimizationEnabled)) {
638     r.ConvertInputsToNumber();
639     r.ConvertInputsToUI32(signedness, kUnsigned);
640     return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
641                                                     ? Type::Unsigned32()
642                                                     : Type::Signed32());
643   }
644   return NoChange();
645 }
646 
ReduceCreateConsString(Node * node)647 Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
648   Node* first = NodeProperties::GetValueInput(node, 0);
649   Node* second = NodeProperties::GetValueInput(node, 1);
650   Node* context = NodeProperties::GetContextInput(node);
651   Node* frame_state = NodeProperties::GetFrameStateInput(node);
652   Node* effect = NodeProperties::GetEffectInput(node);
653   Node* control = NodeProperties::GetControlInput(node);
654 
655   // Make sure {first} is actually a String.
656   Type* first_type = NodeProperties::GetType(first);
657   if (!first_type->Is(Type::String())) {
658     first = effect =
659         graph()->NewNode(simplified()->CheckString(), first, effect, control);
660     first_type = NodeProperties::GetType(first);
661   }
662 
663   // Make sure {second} is actually a String.
664   Type* second_type = NodeProperties::GetType(second);
665   if (!second_type->Is(Type::String())) {
666     second = effect =
667         graph()->NewNode(simplified()->CheckString(), second, effect, control);
668     second_type = NodeProperties::GetType(second);
669   }
670 
671   // Determine the {first} length.
672   HeapObjectBinopMatcher m(node);
673   Node* first_length =
674       (m.left().HasValue() && m.left().Value()->IsString())
675           ? jsgraph()->Constant(
676                 Handle<String>::cast(m.left().Value())->length())
677           : effect = graph()->NewNode(
678                 simplified()->LoadField(AccessBuilder::ForStringLength()),
679                 first, effect, control);
680 
681   // Determine the {second} length.
682   Node* second_length =
683       (m.right().HasValue() && m.right().Value()->IsString())
684           ? jsgraph()->Constant(
685                 Handle<String>::cast(m.right().Value())->length())
686           : effect = graph()->NewNode(
687                 simplified()->LoadField(AccessBuilder::ForStringLength()),
688                 second, effect, control);
689 
690   // Compute the resulting length.
691   Node* length =
692       graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
693 
694   // Check if we would overflow the allowed maximum string length.
695   Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
696                                  jsgraph()->Constant(String::kMaxLength));
697   if (isolate()->IsStringLengthOverflowIntact()) {
698     // Add a code dependency on the string length overflow protector.
699     dependencies()->AssumePropertyCell(factory()->string_length_protector());
700 
701     // We can just deoptimize if the {check} fails. Besides generating a
702     // shorter code sequence than the version below, this has the additional
703     // benefit of not holding on to the lazy {frame_state} and thus potentially
704     // reduces the number of live ranges and allows for more truncations.
705     effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
706   } else {
707     Node* branch =
708         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
709     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
710     Node* efalse = effect;
711     {
712       // Throw a RangeError in case of overflow.
713       Node* vfalse = efalse = graph()->NewNode(
714           javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
715           context, frame_state, efalse, if_false);
716       if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
717       if_false = graph()->NewNode(common()->Throw(), vfalse, efalse, if_false);
718       // TODO(bmeurer): This should be on the AdvancedReducer somehow.
719       NodeProperties::MergeControlToEnd(graph(), common(), if_false);
720       Revisit(graph()->end());
721 
722       // Update potential {IfException} uses of {node} to point to the
723       // %ThrowInvalidStringLength runtime call node instead.
724       for (Edge edge : node->use_edges()) {
725         if (edge.from()->opcode() == IrOpcode::kIfException) {
726           DCHECK(NodeProperties::IsControlEdge(edge) ||
727                  NodeProperties::IsEffectEdge(edge));
728           edge.UpdateTo(vfalse);
729           Revisit(edge.from());
730         }
731       }
732     }
733     control = graph()->NewNode(common()->IfTrue(), branch);
734   }
735 
736   // Figure out the map for the resulting ConsString.
737   // TODO(turbofan): We currently just use the cons_string_map here for
738   // the sake of simplicity; we could also try to be smarter here and
739   // use the one_byte_cons_string_map instead when the resulting ConsString
740   // contains only one byte characters.
741   Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
742 
743   // Allocate the resulting ConsString.
744   effect = graph()->NewNode(
745       common()->BeginRegion(RegionObservability::kNotObservable), effect);
746   Node* value = effect =
747       graph()->NewNode(simplified()->Allocate(NOT_TENURED),
748                        jsgraph()->Constant(ConsString::kSize), effect, control);
749   NodeProperties::SetType(value, Type::OtherString());
750   effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
751                             value, value_map, effect, control);
752   effect = graph()->NewNode(
753       simplified()->StoreField(AccessBuilder::ForNameHashField()), value,
754       jsgraph()->Constant(Name::kEmptyHashField), effect, control);
755   effect = graph()->NewNode(
756       simplified()->StoreField(AccessBuilder::ForStringLength()), value, length,
757       effect, control);
758   effect = graph()->NewNode(
759       simplified()->StoreField(AccessBuilder::ForConsStringFirst()), value,
760       first, effect, control);
761   effect = graph()->NewNode(
762       simplified()->StoreField(AccessBuilder::ForConsStringSecond()), value,
763       second, effect, control);
764 
765   // Morph the {node} into a {FinishRegion}.
766   ReplaceWithValue(node, node, node, control);
767   node->ReplaceInput(0, value);
768   node->ReplaceInput(1, effect);
769   node->TrimInputCount(2);
770   NodeProperties::ChangeOp(node, common()->FinishRegion());
771   return Changed(node);
772 }
773 
ReduceJSComparison(Node * node)774 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
775   JSBinopReduction r(this, node);
776   if (r.BothInputsAre(Type::String())) {
777     // If both inputs are definitely strings, perform a string comparison.
778     const Operator* stringOp;
779     switch (node->opcode()) {
780       case IrOpcode::kJSLessThan:
781         stringOp = simplified()->StringLessThan();
782         break;
783       case IrOpcode::kJSGreaterThan:
784         stringOp = simplified()->StringLessThan();
785         r.SwapInputs();  // a > b => b < a
786         break;
787       case IrOpcode::kJSLessThanOrEqual:
788         stringOp = simplified()->StringLessThanOrEqual();
789         break;
790       case IrOpcode::kJSGreaterThanOrEqual:
791         stringOp = simplified()->StringLessThanOrEqual();
792         r.SwapInputs();  // a >= b => b <= a
793         break;
794       default:
795         return NoChange();
796     }
797     r.ChangeToPureOperator(stringOp);
798     return Changed(node);
799   }
800 
801   NumberOperationHint hint;
802   const Operator* less_than;
803   const Operator* less_than_or_equal;
804   if (r.BothInputsAre(Type::Signed32()) ||
805       r.BothInputsAre(Type::Unsigned32())) {
806     less_than = simplified()->NumberLessThan();
807     less_than_or_equal = simplified()->NumberLessThanOrEqual();
808   } else if (r.GetCompareNumberOperationHint(&hint)) {
809     less_than = simplified()->SpeculativeNumberLessThan(hint);
810     less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
811   } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
812              (r.BothInputsAre(Type::PlainPrimitive()) ||
813               !(flags() & kDeoptimizationEnabled))) {
814     r.ConvertInputsToNumber();
815     less_than = simplified()->NumberLessThan();
816     less_than_or_equal = simplified()->NumberLessThanOrEqual();
817   } else if (r.IsStringCompareOperation()) {
818     r.CheckInputsToString();
819     less_than = simplified()->StringLessThan();
820     less_than_or_equal = simplified()->StringLessThanOrEqual();
821   } else {
822     return NoChange();
823   }
824   const Operator* comparison;
825   switch (node->opcode()) {
826     case IrOpcode::kJSLessThan:
827       comparison = less_than;
828       break;
829     case IrOpcode::kJSGreaterThan:
830       comparison = less_than;
831       r.SwapInputs();  // a > b => b < a
832       break;
833     case IrOpcode::kJSLessThanOrEqual:
834       comparison = less_than_or_equal;
835       break;
836     case IrOpcode::kJSGreaterThanOrEqual:
837       comparison = less_than_or_equal;
838       r.SwapInputs();  // a >= b => b <= a
839       break;
840     default:
841       return NoChange();
842   }
843   if (comparison->EffectInputCount() > 0) {
844     return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
845   } else {
846     return r.ChangeToPureOperator(comparison);
847   }
848 }
849 
ReduceJSTypeOf(Node * node)850 Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
851   Node* const input = node->InputAt(0);
852   Type* type = NodeProperties::GetType(input);
853   Factory* const f = factory();
854   if (type->Is(Type::Boolean())) {
855     return Replace(jsgraph()->Constant(f->boolean_string()));
856   } else if (type->Is(Type::Number())) {
857     return Replace(jsgraph()->Constant(f->number_string()));
858   } else if (type->Is(Type::String())) {
859     return Replace(jsgraph()->Constant(f->string_string()));
860   } else if (type->Is(Type::Symbol())) {
861     return Replace(jsgraph()->Constant(f->symbol_string()));
862   } else if (type->Is(Type::OtherUndetectableOrUndefined())) {
863     return Replace(jsgraph()->Constant(f->undefined_string()));
864   } else if (type->Is(Type::NonCallableOrNull())) {
865     return Replace(jsgraph()->Constant(f->object_string()));
866   } else if (type->Is(Type::Function())) {
867     return Replace(jsgraph()->Constant(f->function_string()));
868   } else if (type->IsHeapConstant()) {
869     return Replace(jsgraph()->Constant(
870         Object::TypeOf(isolate(), type->AsHeapConstant()->Value())));
871   }
872 
873   return NoChange();
874 }
875 
ReduceJSEqualTypeOf(Node * node,bool invert)876 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
877   Node* input;
878   Handle<String> type;
879   HeapObjectBinopMatcher m(node);
880   if (m.left().IsJSTypeOf() && m.right().HasValue() &&
881       m.right().Value()->IsString()) {
882     input = m.left().InputAt(0);
883     type = Handle<String>::cast(m.right().Value());
884   } else if (m.right().IsJSTypeOf() && m.left().HasValue() &&
885              m.left().Value()->IsString()) {
886     input = m.right().InputAt(0);
887     type = Handle<String>::cast(m.left().Value());
888   } else {
889     return NoChange();
890   }
891   Node* value;
892   if (String::Equals(type, factory()->boolean_string())) {
893     value =
894         graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
895                          graph()->NewNode(simplified()->ReferenceEqual(), input,
896                                           jsgraph()->TrueConstant()),
897                          jsgraph()->TrueConstant(),
898                          graph()->NewNode(simplified()->ReferenceEqual(), input,
899                                           jsgraph()->FalseConstant()));
900   } else if (String::Equals(type, factory()->function_string())) {
901     value = graph()->NewNode(simplified()->ObjectIsDetectableCallable(), input);
902   } else if (String::Equals(type, factory()->number_string())) {
903     value = graph()->NewNode(simplified()->ObjectIsNumber(), input);
904   } else if (String::Equals(type, factory()->object_string())) {
905     value = graph()->NewNode(
906         common()->Select(MachineRepresentation::kTagged),
907         graph()->NewNode(simplified()->ObjectIsNonCallable(), input),
908         jsgraph()->TrueConstant(),
909         graph()->NewNode(simplified()->ReferenceEqual(), input,
910                          jsgraph()->NullConstant()));
911   } else if (String::Equals(type, factory()->string_string())) {
912     value = graph()->NewNode(simplified()->ObjectIsString(), input);
913   } else if (String::Equals(type, factory()->undefined_string())) {
914     value = graph()->NewNode(
915         common()->Select(MachineRepresentation::kTagged),
916         graph()->NewNode(simplified()->ReferenceEqual(), input,
917                          jsgraph()->NullConstant()),
918         jsgraph()->FalseConstant(),
919         graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
920   } else {
921     return NoChange();
922   }
923   if (invert) {
924     value = graph()->NewNode(simplified()->BooleanNot(), value);
925   }
926   ReplaceWithValue(node, value);
927   return Replace(value);
928 }
929 
ReduceJSEqual(Node * node,bool invert)930 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
931   Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
932   if (reduction.Changed()) return reduction;
933 
934   JSBinopReduction r(this, node);
935 
936   if (r.BothInputsAre(Type::UniqueName())) {
937     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
938   }
939   if (r.IsInternalizedStringCompareOperation()) {
940     r.CheckInputsToInternalizedString();
941     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
942   }
943   if (r.BothInputsAre(Type::String())) {
944     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
945   }
946   if (r.BothInputsAre(Type::Boolean())) {
947     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
948   }
949   if (r.BothInputsAre(Type::Receiver())) {
950     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
951   }
952   if (r.OneInputIs(Type::Undetectable())) {
953     RelaxEffectsAndControls(node);
954     node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
955     node->TrimInputCount(1);
956     NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
957     if (invert) {
958       // Insert an boolean not to invert the value.
959       Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
960       node->ReplaceUses(value);
961       // Note: ReplaceUses() smashes all uses, so smash it back here.
962       value->ReplaceInput(0, node);
963       return Replace(value);
964     }
965     return Changed(node);
966   }
967 
968   NumberOperationHint hint;
969   if (r.BothInputsAre(Type::Signed32()) ||
970       r.BothInputsAre(Type::Unsigned32())) {
971     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
972   } else if (r.GetCompareNumberOperationHint(&hint)) {
973     return r.ChangeToSpeculativeOperator(
974         simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean());
975   } else if (r.BothInputsAre(Type::Number())) {
976     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
977   } else if (r.IsReceiverCompareOperation()) {
978     r.CheckInputsToReceiver();
979     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
980   } else if (r.IsStringCompareOperation()) {
981     r.CheckInputsToString();
982     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
983   }
984   return NoChange();
985 }
986 
ReduceJSStrictEqual(Node * node,bool invert)987 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
988   JSBinopReduction r(this, node);
989   if (r.left() == r.right()) {
990     // x === x is always true if x != NaN
991     if (!r.left_type()->Maybe(Type::NaN())) {
992       Node* replacement = jsgraph()->BooleanConstant(!invert);
993       ReplaceWithValue(node, replacement);
994       return Replace(replacement);
995     }
996   }
997   if (r.OneInputCannotBe(Type::NumberOrString())) {
998     // For values with canonical representation (i.e. neither String, nor
999     // Number) an empty type intersection means the values cannot be strictly
1000     // equal.
1001     if (!r.left_type()->Maybe(r.right_type())) {
1002       Node* replacement = jsgraph()->BooleanConstant(invert);
1003       ReplaceWithValue(node, replacement);
1004       return Replace(replacement);
1005     }
1006   }
1007 
1008   Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
1009   if (reduction.Changed()) return reduction;
1010 
1011   if (r.BothInputsAre(Type::Unique())) {
1012     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1013   }
1014   if (r.OneInputIs(pointer_comparable_type_)) {
1015     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1016   }
1017   if (r.IsInternalizedStringCompareOperation()) {
1018     r.CheckInputsToInternalizedString();
1019     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1020   }
1021   if (r.BothInputsAre(Type::String())) {
1022     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
1023   }
1024 
1025   NumberOperationHint hint;
1026   if (r.BothInputsAre(Type::Signed32()) ||
1027       r.BothInputsAre(Type::Unsigned32())) {
1028     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
1029   } else if (r.GetCompareNumberOperationHint(&hint)) {
1030     return r.ChangeToSpeculativeOperator(
1031         simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean());
1032   } else if (r.BothInputsAre(Type::Number())) {
1033     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
1034   } else if (r.IsReceiverCompareOperation()) {
1035     // For strict equality, it's enough to know that one input is a Receiver,
1036     // as a strict equality comparison with a Receiver can only yield true if
1037     // both sides refer to the same Receiver than.
1038     r.CheckLeftInputToReceiver();
1039     return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1040   } else if (r.IsStringCompareOperation()) {
1041     r.CheckInputsToString();
1042     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
1043   }
1044   return NoChange();
1045 }
1046 
ReduceJSToBoolean(Node * node)1047 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
1048   Node* const input = node->InputAt(0);
1049   Type* const input_type = NodeProperties::GetType(input);
1050   if (input_type->Is(Type::Boolean())) {
1051     // JSToBoolean(x:boolean) => x
1052     return Replace(input);
1053   } else if (input_type->Is(Type::OrderedNumber())) {
1054     // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
1055     node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
1056                                            jsgraph()->ZeroConstant()));
1057     node->TrimInputCount(1);
1058     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1059     return Changed(node);
1060   } else if (input_type->Is(Type::Number())) {
1061     // JSToBoolean(x:number) => NumberToBoolean(x)
1062     node->TrimInputCount(1);
1063     NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
1064     return Changed(node);
1065   } else if (input_type->Is(Type::DetectableReceiverOrNull())) {
1066     // JSToBoolean(x:detectable receiver \/ null)
1067     //   => BooleanNot(ReferenceEqual(x,#null))
1068     node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
1069                                            input, jsgraph()->NullConstant()));
1070     node->TrimInputCount(1);
1071     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1072     return Changed(node);
1073   } else if (input_type->Is(Type::ReceiverOrNullOrUndefined())) {
1074     // JSToBoolean(x:receiver \/ null \/ undefined)
1075     //   => BooleanNot(ObjectIsUndetectable(x))
1076     node->ReplaceInput(
1077         0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
1078     node->TrimInputCount(1);
1079     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1080     return Changed(node);
1081   } else if (input_type->Is(Type::String())) {
1082     // JSToBoolean(x:string) => BooleanNot(ReferenceEqual(x,""))
1083     node->ReplaceInput(0,
1084                        graph()->NewNode(simplified()->ReferenceEqual(), input,
1085                                         jsgraph()->EmptyStringConstant()));
1086     node->TrimInputCount(1);
1087     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1088     return Changed(node);
1089   }
1090   return NoChange();
1091 }
1092 
ReduceJSToInteger(Node * node)1093 Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
1094   Node* const input = NodeProperties::GetValueInput(node, 0);
1095   Type* const input_type = NodeProperties::GetType(input);
1096   if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
1097     // JSToInteger(x:integer) => x
1098     ReplaceWithValue(node, input);
1099     return Replace(input);
1100   }
1101   return NoChange();
1102 }
1103 
ReduceJSToName(Node * node)1104 Reduction JSTypedLowering::ReduceJSToName(Node* node) {
1105   Node* const input = NodeProperties::GetValueInput(node, 0);
1106   Type* const input_type = NodeProperties::GetType(input);
1107   if (input_type->Is(Type::Name())) {
1108     // JSToName(x:name) => x
1109     ReplaceWithValue(node, input);
1110     return Replace(input);
1111   }
1112   return NoChange();
1113 }
1114 
ReduceJSToLength(Node * node)1115 Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
1116   Node* input = NodeProperties::GetValueInput(node, 0);
1117   Type* input_type = NodeProperties::GetType(input);
1118   if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
1119     if (input_type->Max() <= 0.0) {
1120       input = jsgraph()->ZeroConstant();
1121     } else if (input_type->Min() >= kMaxSafeInteger) {
1122       input = jsgraph()->Constant(kMaxSafeInteger);
1123     } else {
1124       if (input_type->Min() <= 0.0) {
1125         input = graph()->NewNode(simplified()->NumberMax(),
1126                                  jsgraph()->ZeroConstant(), input);
1127       }
1128       if (input_type->Max() > kMaxSafeInteger) {
1129         input = graph()->NewNode(simplified()->NumberMin(),
1130                                  jsgraph()->Constant(kMaxSafeInteger), input);
1131       }
1132     }
1133     ReplaceWithValue(node, input);
1134     return Replace(input);
1135   }
1136   return NoChange();
1137 }
1138 
ReduceJSToNumberInput(Node * input)1139 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
1140   // Try constant-folding of JSToNumber with constant inputs.
1141   Type* input_type = NodeProperties::GetType(input);
1142   if (input_type->Is(Type::String())) {
1143     HeapObjectMatcher m(input);
1144     if (m.HasValue() && m.Value()->IsString()) {
1145       Handle<Object> input_value = m.Value();
1146       return Replace(jsgraph()->Constant(
1147           String::ToNumber(Handle<String>::cast(input_value))));
1148     }
1149   }
1150   if (input_type->IsHeapConstant()) {
1151     Handle<Object> input_value = input_type->AsHeapConstant()->Value();
1152     if (input_value->IsOddball()) {
1153       return Replace(jsgraph()->Constant(
1154           Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
1155     }
1156   }
1157   if (input_type->Is(Type::Number())) {
1158     // JSToNumber(x:number) => x
1159     return Changed(input);
1160   }
1161   if (input_type->Is(Type::Undefined())) {
1162     // JSToNumber(undefined) => #NaN
1163     return Replace(jsgraph()->NaNConstant());
1164   }
1165   if (input_type->Is(Type::Null())) {
1166     // JSToNumber(null) => #0
1167     return Replace(jsgraph()->ZeroConstant());
1168   }
1169   return NoChange();
1170 }
1171 
ReduceJSToNumber(Node * node)1172 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
1173   // Try to reduce the input first.
1174   Node* const input = node->InputAt(0);
1175   Reduction reduction = ReduceJSToNumberInput(input);
1176   if (reduction.Changed()) {
1177     ReplaceWithValue(node, reduction.replacement());
1178     return reduction;
1179   }
1180   Type* const input_type = NodeProperties::GetType(input);
1181   if (input_type->Is(Type::PlainPrimitive())) {
1182     RelaxEffectsAndControls(node);
1183     node->TrimInputCount(1);
1184     NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1185     return Changed(node);
1186   }
1187   return NoChange();
1188 }
1189 
ReduceJSToStringInput(Node * input)1190 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1191   if (input->opcode() == IrOpcode::kJSToString) {
1192     // Recursively try to reduce the input first.
1193     Reduction result = ReduceJSToString(input);
1194     if (result.Changed()) return result;
1195     return Changed(input);  // JSToString(JSToString(x)) => JSToString(x)
1196   }
1197   Type* input_type = NodeProperties::GetType(input);
1198   if (input_type->Is(Type::String())) {
1199     return Changed(input);  // JSToString(x:string) => x
1200   }
1201   if (input_type->Is(Type::Boolean())) {
1202     return Replace(graph()->NewNode(
1203         common()->Select(MachineRepresentation::kTagged), input,
1204         jsgraph()->HeapConstant(factory()->true_string()),
1205         jsgraph()->HeapConstant(factory()->false_string())));
1206   }
1207   if (input_type->Is(Type::Undefined())) {
1208     return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1209   }
1210   if (input_type->Is(Type::Null())) {
1211     return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1212   }
1213   // TODO(turbofan): js-typed-lowering of ToString(x:number)
1214   return NoChange();
1215 }
1216 
ReduceJSToString(Node * node)1217 Reduction JSTypedLowering::ReduceJSToString(Node* node) {
1218   // Try to reduce the input first.
1219   Node* const input = node->InputAt(0);
1220   Reduction reduction = ReduceJSToStringInput(input);
1221   if (reduction.Changed()) {
1222     ReplaceWithValue(node, reduction.replacement());
1223     return reduction;
1224   }
1225   return NoChange();
1226 }
1227 
ReduceJSToObject(Node * node)1228 Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1229   DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1230   Node* receiver = NodeProperties::GetValueInput(node, 0);
1231   Type* receiver_type = NodeProperties::GetType(receiver);
1232   Node* context = NodeProperties::GetContextInput(node);
1233   Node* frame_state = NodeProperties::GetFrameStateInput(node);
1234   Node* effect = NodeProperties::GetEffectInput(node);
1235   Node* control = NodeProperties::GetControlInput(node);
1236   if (receiver_type->Is(Type::Receiver())) {
1237     ReplaceWithValue(node, receiver, effect, control);
1238     return Replace(receiver);
1239   }
1240 
1241   // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
1242   if (receiver_type->Maybe(Type::NullOrUndefined()) &&
1243       NodeProperties::IsExceptionalCall(node)) {
1244     // ToObject throws for null or undefined inputs.
1245     return NoChange();
1246   }
1247 
1248   // Check whether {receiver} is a spec object.
1249   Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1250   Node* branch =
1251       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1252 
1253   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1254   Node* etrue = effect;
1255   Node* rtrue = receiver;
1256 
1257   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1258   Node* efalse = effect;
1259   Node* rfalse;
1260   {
1261     // Convert {receiver} using the ToObjectStub.
1262     Callable callable = CodeFactory::ToObject(isolate());
1263     CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1264         isolate(), graph()->zone(), callable.descriptor(), 0,
1265         CallDescriptor::kNeedsFrameState, node->op()->properties());
1266     rfalse = efalse = graph()->NewNode(
1267         common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1268         receiver, context, frame_state, efalse, if_false);
1269     if_false = graph()->NewNode(common()->IfSuccess(), rfalse);
1270   }
1271 
1272   control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1273   effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1274 
1275   // Morph the {node} into an appropriate Phi.
1276   ReplaceWithValue(node, node, effect, control);
1277   node->ReplaceInput(0, rtrue);
1278   node->ReplaceInput(1, rfalse);
1279   node->ReplaceInput(2, control);
1280   node->TrimInputCount(3);
1281   NodeProperties::ChangeOp(node,
1282                            common()->Phi(MachineRepresentation::kTagged, 2));
1283   return Changed(node);
1284 }
1285 
ReduceJSLoadNamed(Node * node)1286 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1287   DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1288   Node* receiver = NodeProperties::GetValueInput(node, 0);
1289   Type* receiver_type = NodeProperties::GetType(receiver);
1290   Node* effect = NodeProperties::GetEffectInput(node);
1291   Node* control = NodeProperties::GetControlInput(node);
1292   Handle<Name> name = NamedAccessOf(node->op()).name();
1293   // Optimize "length" property of strings.
1294   if (name.is_identical_to(factory()->length_string()) &&
1295       receiver_type->Is(Type::String())) {
1296     Node* value = effect = graph()->NewNode(
1297         simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1298         effect, control);
1299     ReplaceWithValue(node, value, effect);
1300     return Replace(value);
1301   }
1302   return NoChange();
1303 }
1304 
ReduceJSLoadProperty(Node * node)1305 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
1306   Node* key = NodeProperties::GetValueInput(node, 1);
1307   Node* base = NodeProperties::GetValueInput(node, 0);
1308   Type* key_type = NodeProperties::GetType(key);
1309   HeapObjectMatcher mbase(base);
1310   if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1311     Handle<JSTypedArray> const array =
1312         Handle<JSTypedArray>::cast(mbase.Value());
1313     if (!array->GetBuffer()->was_neutered()) {
1314       array->GetBuffer()->set_is_neuterable(false);
1315       BufferAccess const access(array->type());
1316       size_t const k =
1317           ElementSizeLog2Of(access.machine_type().representation());
1318       double const byte_length = array->byte_length()->Number();
1319       CHECK_LT(k, arraysize(shifted_int32_ranges_));
1320       if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1321         // JSLoadProperty(typed-array, int32)
1322         Handle<FixedTypedArrayBase> elements =
1323             Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1324         Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1325         Node* length = jsgraph()->Constant(byte_length);
1326         Node* effect = NodeProperties::GetEffectInput(node);
1327         Node* control = NodeProperties::GetControlInput(node);
1328         // Check if we can avoid the bounds check.
1329         if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1330           Node* load = graph()->NewNode(
1331               simplified()->LoadElement(
1332                   AccessBuilder::ForTypedArrayElement(array->type(), true)),
1333               buffer, key, effect, control);
1334           ReplaceWithValue(node, load, load);
1335           return Replace(load);
1336         }
1337         // Compute byte offset.
1338         Node* offset =
1339             (k == 0) ? key : graph()->NewNode(
1340                                  simplified()->NumberShiftLeft(), key,
1341                                  jsgraph()->Constant(static_cast<double>(k)));
1342         Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
1343                                       offset, length, effect, control);
1344         ReplaceWithValue(node, load, load);
1345         return Replace(load);
1346       }
1347     }
1348   }
1349   return NoChange();
1350 }
1351 
ReduceJSStoreProperty(Node * node)1352 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
1353   Node* key = NodeProperties::GetValueInput(node, 1);
1354   Node* base = NodeProperties::GetValueInput(node, 0);
1355   Node* value = NodeProperties::GetValueInput(node, 2);
1356   Type* key_type = NodeProperties::GetType(key);
1357   Type* value_type = NodeProperties::GetType(value);
1358 
1359   if (!value_type->Is(Type::PlainPrimitive())) return NoChange();
1360 
1361   HeapObjectMatcher mbase(base);
1362   if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1363     Handle<JSTypedArray> const array =
1364         Handle<JSTypedArray>::cast(mbase.Value());
1365     if (!array->GetBuffer()->was_neutered()) {
1366       array->GetBuffer()->set_is_neuterable(false);
1367       BufferAccess const access(array->type());
1368       size_t const k =
1369           ElementSizeLog2Of(access.machine_type().representation());
1370       double const byte_length = array->byte_length()->Number();
1371       CHECK_LT(k, arraysize(shifted_int32_ranges_));
1372       if (access.external_array_type() != kExternalUint8ClampedArray &&
1373           key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1374         // JSLoadProperty(typed-array, int32)
1375         Handle<FixedTypedArrayBase> elements =
1376             Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1377         Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1378         Node* length = jsgraph()->Constant(byte_length);
1379         Node* effect = NodeProperties::GetEffectInput(node);
1380         Node* control = NodeProperties::GetControlInput(node);
1381         // Convert to a number first.
1382         if (!value_type->Is(Type::Number())) {
1383           Reduction number_reduction = ReduceJSToNumberInput(value);
1384           if (number_reduction.Changed()) {
1385             value = number_reduction.replacement();
1386           } else {
1387             value =
1388                 graph()->NewNode(simplified()->PlainPrimitiveToNumber(), value);
1389           }
1390         }
1391         // Check if we can avoid the bounds check.
1392         if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1393           RelaxControls(node);
1394           node->ReplaceInput(0, buffer);
1395           DCHECK_EQ(key, node->InputAt(1));
1396           node->ReplaceInput(2, value);
1397           node->ReplaceInput(3, effect);
1398           node->ReplaceInput(4, control);
1399           node->TrimInputCount(5);
1400           NodeProperties::ChangeOp(
1401               node,
1402               simplified()->StoreElement(
1403                   AccessBuilder::ForTypedArrayElement(array->type(), true)));
1404           return Changed(node);
1405         }
1406         // Compute byte offset.
1407         Node* offset =
1408             (k == 0) ? key : graph()->NewNode(
1409                                  simplified()->NumberShiftLeft(), key,
1410                                  jsgraph()->Constant(static_cast<double>(k)));
1411         // Turn into a StoreBuffer operation.
1412         RelaxControls(node);
1413         node->ReplaceInput(0, buffer);
1414         node->ReplaceInput(1, offset);
1415         node->ReplaceInput(2, length);
1416         node->ReplaceInput(3, value);
1417         node->ReplaceInput(4, effect);
1418         node->ReplaceInput(5, control);
1419         node->TrimInputCount(6);
1420         NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
1421         return Changed(node);
1422       }
1423     }
1424   }
1425   return NoChange();
1426 }
1427 
ReduceJSOrdinaryHasInstance(Node * node)1428 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1429   DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1430   Node* constructor = NodeProperties::GetValueInput(node, 0);
1431   Type* constructor_type = NodeProperties::GetType(constructor);
1432   Node* object = NodeProperties::GetValueInput(node, 1);
1433   Type* object_type = NodeProperties::GetType(object);
1434   Node* context = NodeProperties::GetContextInput(node);
1435   Node* frame_state = NodeProperties::GetFrameStateInput(node);
1436   Node* effect = NodeProperties::GetEffectInput(node);
1437   Node* control = NodeProperties::GetControlInput(node);
1438 
1439   // Check if the {constructor} cannot be callable.
1440   // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1441   if (!constructor_type->Maybe(Type::Callable())) {
1442     Node* value = jsgraph()->FalseConstant();
1443     ReplaceWithValue(node, value, effect, control);
1444     return Replace(value);
1445   }
1446 
1447   // If the {constructor} cannot be a JSBoundFunction and then {object}
1448   // cannot be a JSReceiver, then this can be constant-folded to false.
1449   // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1450   if (!object_type->Maybe(Type::Receiver()) &&
1451       !constructor_type->Maybe(Type::BoundFunction())) {
1452     Node* value = jsgraph()->FalseConstant();
1453     ReplaceWithValue(node, value, effect, control);
1454     return Replace(value);
1455   }
1456 
1457   // Check if the {constructor} is a (known) JSFunction.
1458   if (!constructor_type->IsHeapConstant() ||
1459       !constructor_type->AsHeapConstant()->Value()->IsJSFunction()) {
1460     return NoChange();
1461   }
1462   Handle<JSFunction> function =
1463       Handle<JSFunction>::cast(constructor_type->AsHeapConstant()->Value());
1464 
1465   // Check if the {function} already has an initial map (i.e. the
1466   // {function} has been used as a constructor at least once).
1467   if (!function->has_initial_map()) return NoChange();
1468 
1469   // Check if the {function}s "prototype" is a JSReceiver.
1470   if (!function->prototype()->IsJSReceiver()) return NoChange();
1471 
1472   // Install a code dependency on the {function}s initial map.
1473   Handle<Map> initial_map(function->initial_map(), isolate());
1474   dependencies()->AssumeInitialMapCantChange(initial_map);
1475 
1476   Node* prototype =
1477       jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1478 
1479   Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
1480   Node* branch0 =
1481       graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1482 
1483   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1484   Node* etrue0 = effect;
1485   Node* vtrue0 = jsgraph()->FalseConstant();
1486 
1487   control = graph()->NewNode(common()->IfFalse(), branch0);
1488 
1489   // Loop through the {object}s prototype chain looking for the {prototype}.
1490   Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1491   Node* eloop = effect =
1492       graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1493   Node* vloop = object = graph()->NewNode(
1494       common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop);
1495   // TODO(jarin): This is a very ugly hack to work-around the super-smart
1496   // implicit typing of the Phi, which goes completely nuts if the {object}
1497   // is for example a HeapConstant.
1498   NodeProperties::SetType(vloop, Type::NonInternal());
1499 
1500   // Load the {object} map and instance type.
1501   Node* object_map = effect =
1502       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object,
1503                        effect, control);
1504   Node* object_instance_type = effect = graph()->NewNode(
1505       simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map,
1506       effect, control);
1507 
1508   // Check if the {object} is a special receiver, because for special
1509   // receivers, i.e. proxies or API objects that need access checks,
1510   // we have to use the %HasInPrototypeChain runtime function instead.
1511   Node* check1 = graph()->NewNode(
1512       simplified()->NumberLessThanOrEqual(), object_instance_type,
1513       jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1514   Node* branch1 =
1515       graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1516 
1517   control = graph()->NewNode(common()->IfFalse(), branch1);
1518 
1519   Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1520   Node* etrue1 = effect;
1521   Node* vtrue1;
1522 
1523   // Check if the {object} is not a receiver at all.
1524   Node* check10 =
1525       graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
1526                        jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1527   Node* branch10 =
1528       graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1529 
1530   // A primitive value cannot match the {prototype} we're looking for.
1531   if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1532   vtrue1 = jsgraph()->FalseConstant();
1533 
1534   Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
1535   Node* efalse1 = etrue1;
1536   Node* vfalse1;
1537   {
1538     // Slow path, need to call the %HasInPrototypeChain runtime function.
1539     vfalse1 = efalse1 = graph()->NewNode(
1540         javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
1541         prototype, context, frame_state, efalse1, if_false1);
1542     if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1543 
1544     // Replace any potential IfException on {node} to catch exceptions
1545     // from this %HasInPrototypeChain runtime call instead.
1546     for (Edge edge : node->use_edges()) {
1547       if (edge.from()->opcode() == IrOpcode::kIfException) {
1548         edge.UpdateTo(vfalse1);
1549         Revisit(edge.from());
1550       }
1551     }
1552   }
1553 
1554   // Load the {object} prototype.
1555   Node* object_prototype = effect = graph()->NewNode(
1556       simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
1557       effect, control);
1558 
1559   // Check if we reached the end of {object}s prototype chain.
1560   Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1561                                   object_prototype, jsgraph()->NullConstant());
1562   Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1563 
1564   Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1565   Node* etrue2 = effect;
1566   Node* vtrue2 = jsgraph()->FalseConstant();
1567 
1568   control = graph()->NewNode(common()->IfFalse(), branch2);
1569 
1570   // Check if we reached the {prototype}.
1571   Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1572                                   object_prototype, prototype);
1573   Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1574 
1575   Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1576   Node* etrue3 = effect;
1577   Node* vtrue3 = jsgraph()->TrueConstant();
1578 
1579   control = graph()->NewNode(common()->IfFalse(), branch3);
1580 
1581   // Close the loop.
1582   vloop->ReplaceInput(1, object_prototype);
1583   eloop->ReplaceInput(1, effect);
1584   loop->ReplaceInput(1, control);
1585 
1586   control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1587                              if_true3, if_false1);
1588   effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
1589                             etrue3, efalse1, control);
1590 
1591   // Morph the {node} into an appropriate Phi.
1592   ReplaceWithValue(node, node, effect, control);
1593   node->ReplaceInput(0, vtrue0);
1594   node->ReplaceInput(1, vtrue1);
1595   node->ReplaceInput(2, vtrue2);
1596   node->ReplaceInput(3, vtrue3);
1597   node->ReplaceInput(4, vfalse1);
1598   node->ReplaceInput(5, control);
1599   node->TrimInputCount(6);
1600   NodeProperties::ChangeOp(node,
1601                            common()->Phi(MachineRepresentation::kTagged, 5));
1602   return Changed(node);
1603 }
1604 
ReduceJSLoadContext(Node * node)1605 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1606   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1607   ContextAccess const& access = ContextAccessOf(node->op());
1608   Node* effect = NodeProperties::GetEffectInput(node);
1609   Node* context = NodeProperties::GetContextInput(node);
1610   Node* control = graph()->start();
1611   for (size_t i = 0; i < access.depth(); ++i) {
1612     context = effect = graph()->NewNode(
1613         simplified()->LoadField(
1614             AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1615         context, effect, control);
1616   }
1617   node->ReplaceInput(0, context);
1618   node->ReplaceInput(1, effect);
1619   node->AppendInput(jsgraph()->zone(), control);
1620   NodeProperties::ChangeOp(
1621       node,
1622       simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1623   return Changed(node);
1624 }
1625 
ReduceJSStoreContext(Node * node)1626 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1627   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1628   ContextAccess const& access = ContextAccessOf(node->op());
1629   Node* effect = NodeProperties::GetEffectInput(node);
1630   Node* context = NodeProperties::GetContextInput(node);
1631   Node* control = graph()->start();
1632   Node* value = NodeProperties::GetValueInput(node, 0);
1633   for (size_t i = 0; i < access.depth(); ++i) {
1634     context = effect = graph()->NewNode(
1635         simplified()->LoadField(
1636             AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1637         context, effect, control);
1638   }
1639   node->ReplaceInput(0, context);
1640   node->ReplaceInput(1, value);
1641   node->ReplaceInput(2, effect);
1642   NodeProperties::ChangeOp(
1643       node,
1644       simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1645   return Changed(node);
1646 }
1647 
ReduceJSLoadModule(Node * node)1648 Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1649   DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1650   Node* effect = NodeProperties::GetEffectInput(node);
1651   Node* control = NodeProperties::GetControlInput(node);
1652 
1653   int32_t cell_index = OpParameter<int32_t>(node);
1654   Node* module = NodeProperties::GetValueInput(node, 0);
1655 
1656   Node* array;
1657   int index;
1658   if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1659       ModuleDescriptor::kExport) {
1660     array = effect = graph()->NewNode(
1661         simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1662         module, effect, control);
1663     index = cell_index - 1;
1664   } else {
1665     DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1666               ModuleDescriptor::kImport);
1667     array = effect = graph()->NewNode(
1668         simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1669         module, effect, control);
1670     index = -cell_index - 1;
1671   }
1672 
1673   Node* cell = effect = graph()->NewNode(
1674       simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1675       effect, control);
1676 
1677   Node* value = effect =
1678       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1679                        cell, effect, control);
1680 
1681   ReplaceWithValue(node, value, effect, control);
1682   return Changed(value);
1683 }
1684 
ReduceJSStoreModule(Node * node)1685 Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1686   DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1687   Node* effect = NodeProperties::GetEffectInput(node);
1688   Node* control = NodeProperties::GetControlInput(node);
1689 
1690   int32_t cell_index = OpParameter<int32_t>(node);
1691   Node* module = NodeProperties::GetValueInput(node, 0);
1692   Node* value = NodeProperties::GetValueInput(node, 1);
1693 
1694   Node* array;
1695   int index;
1696   if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1697       ModuleDescriptor::kExport) {
1698     array = effect = graph()->NewNode(
1699         simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1700         module, effect, control);
1701     index = cell_index - 1;
1702   } else {
1703     DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1704               ModuleDescriptor::kImport);
1705     array = effect = graph()->NewNode(
1706         simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1707         module, effect, control);
1708     index = -cell_index - 1;
1709   }
1710 
1711   Node* cell = effect = graph()->NewNode(
1712       simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1713       effect, control);
1714 
1715   effect =
1716       graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1717                        cell, value, effect, control);
1718 
1719   ReplaceWithValue(node, effect, effect, control);
1720   return Changed(value);
1721 }
1722 
ReduceJSConvertReceiver(Node * node)1723 Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1724   DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1725   ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1726   Node* receiver = NodeProperties::GetValueInput(node, 0);
1727   Type* receiver_type = NodeProperties::GetType(receiver);
1728   Node* context = NodeProperties::GetContextInput(node);
1729   Type* context_type = NodeProperties::GetType(context);
1730   Node* effect = NodeProperties::GetEffectInput(node);
1731   Node* control = NodeProperties::GetControlInput(node);
1732 
1733   // Check if {receiver} is known to be a receiver.
1734   if (receiver_type->Is(Type::Receiver())) {
1735     ReplaceWithValue(node, receiver, effect, control);
1736     return Replace(receiver);
1737   }
1738 
1739   // If the {receiver} is known to be null or undefined, we can just replace it
1740   // with the global proxy unconditionally.
1741   if (receiver_type->Is(Type::NullOrUndefined()) ||
1742       mode == ConvertReceiverMode::kNullOrUndefined) {
1743     if (context_type->IsHeapConstant()) {
1744       Handle<JSObject> global_proxy(
1745           Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1746               ->global_proxy(),
1747           isolate());
1748       receiver = jsgraph()->Constant(global_proxy);
1749     } else {
1750       Node* native_context = effect = graph()->NewNode(
1751           javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1752           context, effect);
1753       receiver = effect = graph()->NewNode(
1754           javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1755           native_context, effect);
1756     }
1757     ReplaceWithValue(node, receiver, effect, control);
1758     return Replace(receiver);
1759   }
1760 
1761   // If {receiver} cannot be null or undefined we can skip a few checks.
1762   if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1763       mode == ConvertReceiverMode::kNotNullOrUndefined) {
1764     Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1765     Node* branch =
1766         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1767 
1768     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1769     Node* etrue = effect;
1770     Node* rtrue = receiver;
1771 
1772     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1773     Node* efalse = effect;
1774     Node* rfalse;
1775     {
1776       // Convert {receiver} using the ToObjectStub. The call does not require a
1777       // frame-state in this case, because neither null nor undefined is passed.
1778       Callable callable = CodeFactory::ToObject(isolate());
1779       CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1780           isolate(), graph()->zone(), callable.descriptor(), 0,
1781           CallDescriptor::kNoFlags, node->op()->properties());
1782       rfalse = efalse = graph()->NewNode(
1783           common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1784           receiver, context, efalse);
1785     }
1786 
1787     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1788     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1789 
1790     // Morph the {node} into an appropriate Phi.
1791     ReplaceWithValue(node, node, effect, control);
1792     node->ReplaceInput(0, rtrue);
1793     node->ReplaceInput(1, rfalse);
1794     node->ReplaceInput(2, control);
1795     node->TrimInputCount(3);
1796     NodeProperties::ChangeOp(node,
1797                              common()->Phi(MachineRepresentation::kTagged, 2));
1798     return Changed(node);
1799   }
1800 
1801   // Check if {receiver} is already a JSReceiver.
1802   Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1803   Node* branch0 =
1804       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1805   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1806   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1807 
1808   // Check {receiver} for undefined.
1809   Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1810                                   jsgraph()->UndefinedConstant());
1811   Node* branch1 =
1812       graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0);
1813   Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1814   Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1815 
1816   // Check {receiver} for null.
1817   Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1818                                   jsgraph()->NullConstant());
1819   Node* branch2 =
1820       graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1);
1821   Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1822   Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1823 
1824   // We just use {receiver} directly.
1825   Node* if_noop = if_true0;
1826   Node* enoop = effect;
1827   Node* rnoop = receiver;
1828 
1829   // Convert {receiver} using ToObject.
1830   Node* if_convert = if_false2;
1831   Node* econvert = effect;
1832   Node* rconvert;
1833   {
1834     // Convert {receiver} using the ToObjectStub. The call does not require a
1835     // frame-state in this case, because neither null nor undefined is passed.
1836     Callable callable = CodeFactory::ToObject(isolate());
1837     CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1838         isolate(), graph()->zone(), callable.descriptor(), 0,
1839         CallDescriptor::kNoFlags, node->op()->properties());
1840     rconvert = econvert = graph()->NewNode(
1841         common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1842         receiver, context, econvert);
1843   }
1844 
1845   // Replace {receiver} with global proxy of {context}.
1846   Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2);
1847   Node* eglobal = effect;
1848   Node* rglobal;
1849   {
1850     if (context_type->IsHeapConstant()) {
1851       Handle<JSObject> global_proxy(
1852           Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1853               ->global_proxy(),
1854           isolate());
1855       rglobal = jsgraph()->Constant(global_proxy);
1856     } else {
1857       Node* native_context = eglobal = graph()->NewNode(
1858           javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1859           context, eglobal);
1860       rglobal = eglobal = graph()->NewNode(
1861           javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1862           native_context, eglobal);
1863     }
1864   }
1865 
1866   control =
1867       graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global);
1868   effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal,
1869                             control);
1870   // Morph the {node} into an appropriate Phi.
1871   ReplaceWithValue(node, node, effect, control);
1872   node->ReplaceInput(0, rnoop);
1873   node->ReplaceInput(1, rconvert);
1874   node->ReplaceInput(2, rglobal);
1875   node->ReplaceInput(3, control);
1876   node->TrimInputCount(4);
1877   NodeProperties::ChangeOp(node,
1878                            common()->Phi(MachineRepresentation::kTagged, 3));
1879   return Changed(node);
1880 }
1881 
1882 namespace {
1883 
ReduceBuiltin(Isolate * isolate,JSGraph * jsgraph,Node * node,int builtin_index,int arity,CallDescriptor::Flags flags)1884 void ReduceBuiltin(Isolate* isolate, JSGraph* jsgraph, Node* node,
1885                    int builtin_index, int arity, CallDescriptor::Flags flags) {
1886   // Patch {node} to a direct CEntryStub call.
1887   //
1888   // ----------- A r g u m e n t s -----------
1889   // -- 0: CEntryStub
1890   // --- Stack args ---
1891   // -- 1: receiver
1892   // -- [2, 2 + n[: the n actual arguments passed to the builtin
1893   // -- 2 + n: argc, including the receiver and implicit args (Smi)
1894   // -- 2 + n + 1: target
1895   // -- 2 + n + 2: new_target
1896   // --- Register args ---
1897   // -- 2 + n + 3: the C entry point
1898   // -- 2 + n + 4: argc (Int32)
1899   // -----------------------------------
1900 
1901   // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1902   // Keep these in sync.
1903 
1904   const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct);
1905 
1906   DCHECK(Builtins::HasCppImplementation(builtin_index));
1907   DCHECK_EQ(0, flags & CallDescriptor::kSupportsTailCalls);
1908 
1909   Node* target = NodeProperties::GetValueInput(node, 0);
1910   Node* new_target = is_construct
1911                          ? NodeProperties::GetValueInput(node, arity + 1)
1912                          : jsgraph->UndefinedConstant();
1913 
1914   // API and CPP builtins are implemented in C++, and we can inline both.
1915   // CPP builtins create a builtin exit frame, API builtins don't.
1916   const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1917 
1918   Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1919                                            has_builtin_exit_frame);
1920   node->ReplaceInput(0, stub);
1921 
1922   Zone* zone = jsgraph->zone();
1923   if (is_construct) {
1924     // Unify representations between construct and call nodes.
1925     // Remove new target and add receiver as a stack parameter.
1926     Node* receiver = jsgraph->UndefinedConstant();
1927     node->RemoveInput(arity + 1);
1928     node->InsertInput(zone, 1, receiver);
1929   }
1930 
1931   const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1932   Node* argc_node = jsgraph->Constant(argc);
1933 
1934   static const int kStubAndReceiver = 2;
1935   int cursor = arity + kStubAndReceiver;
1936   node->InsertInput(zone, cursor++, argc_node);
1937   node->InsertInput(zone, cursor++, target);
1938   node->InsertInput(zone, cursor++, new_target);
1939 
1940   Address entry = Builtins::CppEntryOf(builtin_index);
1941   ExternalReference entry_ref(ExternalReference(entry, isolate));
1942   Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1943 
1944   node->InsertInput(zone, cursor++, entry_node);
1945   node->InsertInput(zone, cursor++, argc_node);
1946 
1947   static const int kReturnCount = 1;
1948   const char* debug_name = Builtins::name(builtin_index);
1949   Operator::Properties properties = node->op()->properties();
1950   CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor(
1951       zone, kReturnCount, argc, debug_name, properties, flags);
1952 
1953   NodeProperties::ChangeOp(node, jsgraph->common()->Call(desc));
1954 }
1955 
NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared,int arity)1956 bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
1957   static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1958   const int num_decl_parms = shared->internal_formal_parameter_count();
1959   return (num_decl_parms != arity && num_decl_parms != sentinel);
1960 }
1961 
1962 }  // namespace
1963 
ReduceJSConstruct(Node * node)1964 Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1965   DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1966   ConstructParameters const& p = ConstructParametersOf(node->op());
1967   DCHECK_LE(2u, p.arity());
1968   int const arity = static_cast<int>(p.arity() - 2);
1969   Node* target = NodeProperties::GetValueInput(node, 0);
1970   Type* target_type = NodeProperties::GetType(target);
1971   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1972   Node* effect = NodeProperties::GetEffectInput(node);
1973   Node* control = NodeProperties::GetControlInput(node);
1974 
1975   // Check if {target} is a known JSFunction.
1976   if (target_type->IsHeapConstant() &&
1977       target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1978     Handle<JSFunction> function =
1979         Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1980     Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1981     const int builtin_index = shared->construct_stub()->builtin_index();
1982     const bool is_builtin = (builtin_index != -1);
1983 
1984     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1985 
1986     if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
1987         !NeedsArgumentAdaptorFrame(shared, arity)) {
1988       // Patch {node} to a direct CEntryStub call.
1989 
1990       // Load the context from the {target}.
1991       Node* context = effect = graph()->NewNode(
1992           simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
1993           target, effect, control);
1994       NodeProperties::ReplaceContextInput(node, context);
1995 
1996       // Update the effect dependency for the {node}.
1997       NodeProperties::ReplaceEffectInput(node, effect);
1998 
1999       ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
2000     } else {
2001       // Patch {node} to an indirect call via the {function}s construct stub.
2002       Callable callable(handle(shared->construct_stub(), isolate()),
2003                         ConstructStubDescriptor(isolate()));
2004       node->RemoveInput(arity + 1);
2005       node->InsertInput(graph()->zone(), 0,
2006                         jsgraph()->HeapConstant(callable.code()));
2007       node->InsertInput(graph()->zone(), 2, new_target);
2008       node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
2009       node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2010       node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
2011       NodeProperties::ChangeOp(
2012           node, common()->Call(Linkage::GetStubCallDescriptor(
2013                     isolate(), graph()->zone(), callable.descriptor(),
2014                     1 + arity, flags)));
2015     }
2016     return Changed(node);
2017   }
2018 
2019   // Check if {target} is a JSFunction.
2020   if (target_type->Is(Type::Function())) {
2021     // Patch {node} to an indirect call via the ConstructFunction builtin.
2022     Callable callable = CodeFactory::ConstructFunction(isolate());
2023     node->RemoveInput(arity + 1);
2024     node->InsertInput(graph()->zone(), 0,
2025                       jsgraph()->HeapConstant(callable.code()));
2026     node->InsertInput(graph()->zone(), 2, new_target);
2027     node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
2028     node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2029     NodeProperties::ChangeOp(
2030         node, common()->Call(Linkage::GetStubCallDescriptor(
2031                   isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2032                   CallDescriptor::kNeedsFrameState)));
2033     return Changed(node);
2034   }
2035 
2036   return NoChange();
2037 }
2038 
ReduceJSCallForwardVarargs(Node * node)2039 Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
2040   DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
2041   CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
2042   Node* target = NodeProperties::GetValueInput(node, 0);
2043   Type* target_type = NodeProperties::GetType(target);
2044 
2045   // Check if {target} is a JSFunction.
2046   if (target_type->Is(Type::Function())) {
2047     // Compute flags for the call.
2048     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2049     if (p.tail_call_mode() == TailCallMode::kAllow) {
2050       flags |= CallDescriptor::kSupportsTailCalls;
2051     }
2052 
2053     // Patch {node} to an indirect call via CallFunctionForwardVarargs.
2054     Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
2055     node->InsertInput(graph()->zone(), 0,
2056                       jsgraph()->HeapConstant(callable.code()));
2057     node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(p.start_index()));
2058     NodeProperties::ChangeOp(
2059         node,
2060         common()->Call(Linkage::GetStubCallDescriptor(
2061             isolate(), graph()->zone(), callable.descriptor(), 1, flags)));
2062     return Changed(node);
2063   }
2064 
2065   return NoChange();
2066 }
2067 
ReduceJSCall(Node * node)2068 Reduction JSTypedLowering::ReduceJSCall(Node* node) {
2069   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
2070   CallParameters const& p = CallParametersOf(node->op());
2071   int const arity = static_cast<int>(p.arity() - 2);
2072   ConvertReceiverMode convert_mode = p.convert_mode();
2073   Node* target = NodeProperties::GetValueInput(node, 0);
2074   Type* target_type = NodeProperties::GetType(target);
2075   Node* receiver = NodeProperties::GetValueInput(node, 1);
2076   Type* receiver_type = NodeProperties::GetType(receiver);
2077   Node* effect = NodeProperties::GetEffectInput(node);
2078   Node* control = NodeProperties::GetControlInput(node);
2079 
2080   // Try to infer receiver {convert_mode} from {receiver} type.
2081   if (receiver_type->Is(Type::NullOrUndefined())) {
2082     convert_mode = ConvertReceiverMode::kNullOrUndefined;
2083   } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
2084     convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2085   }
2086 
2087   // Check if {target} is a known JSFunction.
2088   if (target_type->IsHeapConstant() &&
2089       target_type->AsHeapConstant()->Value()->IsJSFunction()) {
2090     Handle<JSFunction> function =
2091         Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
2092     Handle<SharedFunctionInfo> shared(function->shared(), isolate());
2093     const int builtin_index = shared->code()->builtin_index();
2094     const bool is_builtin = (builtin_index != -1);
2095 
2096     // Class constructors are callable, but [[Call]] will raise an exception.
2097     // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
2098     if (IsClassConstructor(shared->kind())) return NoChange();
2099 
2100     // Load the context from the {target}.
2101     Node* context = effect = graph()->NewNode(
2102         simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2103         effect, control);
2104     NodeProperties::ReplaceContextInput(node, context);
2105 
2106     // Check if we need to convert the {receiver}.
2107     if (is_sloppy(shared->language_mode()) && !shared->native() &&
2108         !receiver_type->Is(Type::Receiver())) {
2109       receiver = effect =
2110           graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
2111                            receiver, context, effect, control);
2112       NodeProperties::ReplaceValueInput(node, receiver, 1);
2113     }
2114 
2115     // Update the effect dependency for the {node}.
2116     NodeProperties::ReplaceEffectInput(node, effect);
2117 
2118     // Compute flags for the call.
2119     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2120     if (p.tail_call_mode() == TailCallMode::kAllow) {
2121       flags |= CallDescriptor::kSupportsTailCalls;
2122     }
2123 
2124     Node* new_target = jsgraph()->UndefinedConstant();
2125     Node* argument_count = jsgraph()->Constant(arity);
2126     if (NeedsArgumentAdaptorFrame(shared, arity)) {
2127       // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
2128       Callable callable = CodeFactory::ArgumentAdaptor(isolate());
2129       node->InsertInput(graph()->zone(), 0,
2130                         jsgraph()->HeapConstant(callable.code()));
2131       node->InsertInput(graph()->zone(), 2, new_target);
2132       node->InsertInput(graph()->zone(), 3, argument_count);
2133       node->InsertInput(
2134           graph()->zone(), 4,
2135           jsgraph()->Constant(shared->internal_formal_parameter_count()));
2136       NodeProperties::ChangeOp(
2137           node, common()->Call(Linkage::GetStubCallDescriptor(
2138                     isolate(), graph()->zone(), callable.descriptor(),
2139                     1 + arity, flags)));
2140     } else if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
2141                ((flags & CallDescriptor::kSupportsTailCalls) == 0)) {
2142       // Patch {node} to a direct CEntryStub call.
2143       ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
2144     } else {
2145       // Patch {node} to a direct call.
2146       node->InsertInput(graph()->zone(), arity + 2, new_target);
2147       node->InsertInput(graph()->zone(), arity + 3, argument_count);
2148       NodeProperties::ChangeOp(node,
2149                                common()->Call(Linkage::GetJSCallDescriptor(
2150                                    graph()->zone(), false, 1 + arity, flags)));
2151     }
2152     return Changed(node);
2153   }
2154 
2155   // Check if {target} is a JSFunction.
2156   if (target_type->Is(Type::Function())) {
2157     // Compute flags for the call.
2158     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2159     if (p.tail_call_mode() == TailCallMode::kAllow) {
2160       flags |= CallDescriptor::kSupportsTailCalls;
2161     }
2162 
2163     // Patch {node} to an indirect call via the CallFunction builtin.
2164     Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
2165     node->InsertInput(graph()->zone(), 0,
2166                       jsgraph()->HeapConstant(callable.code()));
2167     node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
2168     NodeProperties::ChangeOp(
2169         node, common()->Call(Linkage::GetStubCallDescriptor(
2170                   isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2171                   flags)));
2172     return Changed(node);
2173   }
2174 
2175   // Maybe we did at least learn something about the {receiver}.
2176   if (p.convert_mode() != convert_mode) {
2177     NodeProperties::ChangeOp(
2178         node,
2179         javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
2180                            p.tail_call_mode()));
2181     return Changed(node);
2182   }
2183 
2184   return NoChange();
2185 }
2186 
2187 
ReduceJSForInNext(Node * node)2188 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
2189   DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
2190   Node* receiver = NodeProperties::GetValueInput(node, 0);
2191   Node* cache_array = NodeProperties::GetValueInput(node, 1);
2192   Node* cache_type = NodeProperties::GetValueInput(node, 2);
2193   Node* index = NodeProperties::GetValueInput(node, 3);
2194   Node* context = NodeProperties::GetContextInput(node);
2195   Node* frame_state = NodeProperties::GetFrameStateInput(node);
2196   Node* effect = NodeProperties::GetEffectInput(node);
2197   Node* control = NodeProperties::GetControlInput(node);
2198 
2199   // We don't support lowering JSForInNext inside try blocks.
2200   if (NodeProperties::IsExceptionalCall(node)) return NoChange();
2201 
2202   // We know that the {index} is in Unsigned32 range here, otherwise executing
2203   // the JSForInNext wouldn't be valid. Unfortunately due to OSR and generators
2204   // this is not always reflected in the types, hence we might need to rename
2205   // the {index} here.
2206   if (!NodeProperties::GetType(index)->Is(Type::Unsigned32())) {
2207     index = graph()->NewNode(common()->TypeGuard(Type::Unsigned32()), index,
2208                              control);
2209   }
2210 
2211   // Load the next {key} from the {cache_array}.
2212   Node* key = effect = graph()->NewNode(
2213       simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
2214       cache_array, index, effect, control);
2215 
2216   // Load the map of the {receiver}.
2217   Node* receiver_map = effect =
2218       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2219                        receiver, effect, control);
2220 
2221   // Check if the expected map still matches that of the {receiver}.
2222   Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
2223                                   cache_type);
2224   Node* branch0 =
2225       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2226 
2227   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2228   Node* etrue0;
2229   Node* vtrue0;
2230   {
2231     // Don't need filtering since expected map still matches that of the
2232     // {receiver}.
2233     etrue0 = effect;
2234     vtrue0 = key;
2235   }
2236 
2237   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2238   Node* efalse0;
2239   Node* vfalse0;
2240   {
2241     // Filter the {key} to check if it's still a valid property of the
2242     // {receiver} (does the ToName conversion implicitly).
2243     Callable const callable = CodeFactory::ForInFilter(isolate());
2244     CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
2245         isolate(), graph()->zone(), callable.descriptor(), 0,
2246         CallDescriptor::kNeedsFrameState);
2247     vfalse0 = efalse0 = graph()->NewNode(
2248         common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key,
2249         receiver, context, frame_state, effect, if_false0);
2250     if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
2251   }
2252 
2253   control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2254   effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2255   ReplaceWithValue(node, node, effect, control);
2256   node->ReplaceInput(0, vtrue0);
2257   node->ReplaceInput(1, vfalse0);
2258   node->ReplaceInput(2, control);
2259   node->TrimInputCount(3);
2260   NodeProperties::ChangeOp(node,
2261                            common()->Phi(MachineRepresentation::kTagged, 2));
2262   return Changed(node);
2263 }
2264 
ReduceJSLoadMessage(Node * node)2265 Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2266   DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2267   ExternalReference const ref =
2268       ExternalReference::address_of_pending_message_obj(isolate());
2269   node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2270   NodeProperties::ChangeOp(
2271       node, simplified()->LoadField(AccessBuilder::ForExternalTaggedValue()));
2272   return Changed(node);
2273 }
2274 
ReduceJSStoreMessage(Node * node)2275 Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2276   DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2277   ExternalReference const ref =
2278       ExternalReference::address_of_pending_message_obj(isolate());
2279   Node* value = NodeProperties::GetValueInput(node, 0);
2280   node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2281   node->ReplaceInput(1, value);
2282   NodeProperties::ChangeOp(
2283       node, simplified()->StoreField(AccessBuilder::ForExternalTaggedValue()));
2284   return Changed(node);
2285 }
2286 
ReduceJSGeneratorStore(Node * node)2287 Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2288   DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2289   Node* generator = NodeProperties::GetValueInput(node, 0);
2290   Node* continuation = NodeProperties::GetValueInput(node, 1);
2291   Node* offset = NodeProperties::GetValueInput(node, 2);
2292   Node* context = NodeProperties::GetContextInput(node);
2293   Node* effect = NodeProperties::GetEffectInput(node);
2294   Node* control = NodeProperties::GetControlInput(node);
2295   int register_count = OpParameter<int>(node);
2296 
2297   FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2298   FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2299   FieldAccess continuation_field =
2300       AccessBuilder::ForJSGeneratorObjectContinuation();
2301   FieldAccess input_or_debug_pos_field =
2302       AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2303 
2304   Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2305                                           generator, effect, control);
2306 
2307   for (int i = 0; i < register_count; ++i) {
2308     Node* value = NodeProperties::GetValueInput(node, 3 + i);
2309     effect = graph()->NewNode(
2310         simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2311         value, effect, control);
2312   }
2313 
2314   effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2315                             context, effect, control);
2316   effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2317                             generator, continuation, effect, control);
2318   effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2319                             generator, offset, effect, control);
2320 
2321   ReplaceWithValue(node, effect, effect, control);
2322   return Changed(effect);
2323 }
2324 
ReduceJSGeneratorRestoreContinuation(Node * node)2325 Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2326   DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2327   Node* generator = NodeProperties::GetValueInput(node, 0);
2328   Node* effect = NodeProperties::GetEffectInput(node);
2329   Node* control = NodeProperties::GetControlInput(node);
2330 
2331   FieldAccess continuation_field =
2332       AccessBuilder::ForJSGeneratorObjectContinuation();
2333 
2334   Node* continuation = effect = graph()->NewNode(
2335       simplified()->LoadField(continuation_field), generator, effect, control);
2336   Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2337   effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2338                             generator, executing, effect, control);
2339 
2340   ReplaceWithValue(node, continuation, effect, control);
2341   return Changed(continuation);
2342 }
2343 
ReduceJSGeneratorRestoreRegister(Node * node)2344 Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2345   DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2346   Node* generator = NodeProperties::GetValueInput(node, 0);
2347   Node* effect = NodeProperties::GetEffectInput(node);
2348   Node* control = NodeProperties::GetControlInput(node);
2349   int index = OpParameter<int>(node);
2350 
2351   FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2352   FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2353 
2354   Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2355                                           generator, effect, control);
2356   Node* element = effect = graph()->NewNode(
2357       simplified()->LoadField(element_field), array, effect, control);
2358   Node* stale = jsgraph()->StaleRegisterConstant();
2359   effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2360                             stale, effect, control);
2361 
2362   ReplaceWithValue(node, element, effect, control);
2363   return Changed(element);
2364 }
2365 
Reduce(Node * node)2366 Reduction JSTypedLowering::Reduce(Node* node) {
2367   switch (node->opcode()) {
2368     case IrOpcode::kJSEqual:
2369       return ReduceJSEqual(node, false);
2370     case IrOpcode::kJSNotEqual:
2371       return ReduceJSEqual(node, true);
2372     case IrOpcode::kJSStrictEqual:
2373       return ReduceJSStrictEqual(node, false);
2374     case IrOpcode::kJSStrictNotEqual:
2375       return ReduceJSStrictEqual(node, true);
2376     case IrOpcode::kJSLessThan:         // fall through
2377     case IrOpcode::kJSGreaterThan:      // fall through
2378     case IrOpcode::kJSLessThanOrEqual:  // fall through
2379     case IrOpcode::kJSGreaterThanOrEqual:
2380       return ReduceJSComparison(node);
2381     case IrOpcode::kJSBitwiseOr:
2382     case IrOpcode::kJSBitwiseXor:
2383     case IrOpcode::kJSBitwiseAnd:
2384       return ReduceInt32Binop(node);
2385     case IrOpcode::kJSShiftLeft:
2386     case IrOpcode::kJSShiftRight:
2387       return ReduceUI32Shift(node, kSigned);
2388     case IrOpcode::kJSShiftRightLogical:
2389       return ReduceUI32Shift(node, kUnsigned);
2390     case IrOpcode::kJSAdd:
2391       return ReduceJSAdd(node);
2392     case IrOpcode::kJSSubtract:
2393     case IrOpcode::kJSMultiply:
2394     case IrOpcode::kJSDivide:
2395     case IrOpcode::kJSModulus:
2396       return ReduceNumberBinop(node);
2397     case IrOpcode::kJSOrdinaryHasInstance:
2398       return ReduceJSOrdinaryHasInstance(node);
2399     case IrOpcode::kJSToBoolean:
2400       return ReduceJSToBoolean(node);
2401     case IrOpcode::kJSToInteger:
2402       return ReduceJSToInteger(node);
2403     case IrOpcode::kJSToLength:
2404       return ReduceJSToLength(node);
2405     case IrOpcode::kJSToName:
2406       return ReduceJSToName(node);
2407     case IrOpcode::kJSToNumber:
2408       return ReduceJSToNumber(node);
2409     case IrOpcode::kJSToString:
2410       return ReduceJSToString(node);
2411     case IrOpcode::kJSToObject:
2412       return ReduceJSToObject(node);
2413     case IrOpcode::kJSTypeOf:
2414       return ReduceJSTypeOf(node);
2415     case IrOpcode::kJSLoadNamed:
2416       return ReduceJSLoadNamed(node);
2417     case IrOpcode::kJSLoadProperty:
2418       return ReduceJSLoadProperty(node);
2419     case IrOpcode::kJSStoreProperty:
2420       return ReduceJSStoreProperty(node);
2421     case IrOpcode::kJSLoadContext:
2422       return ReduceJSLoadContext(node);
2423     case IrOpcode::kJSStoreContext:
2424       return ReduceJSStoreContext(node);
2425     case IrOpcode::kJSLoadModule:
2426       return ReduceJSLoadModule(node);
2427     case IrOpcode::kJSStoreModule:
2428       return ReduceJSStoreModule(node);
2429     case IrOpcode::kJSConvertReceiver:
2430       return ReduceJSConvertReceiver(node);
2431     case IrOpcode::kJSConstruct:
2432       return ReduceJSConstruct(node);
2433     case IrOpcode::kJSCallForwardVarargs:
2434       return ReduceJSCallForwardVarargs(node);
2435     case IrOpcode::kJSCall:
2436       return ReduceJSCall(node);
2437     case IrOpcode::kJSForInNext:
2438       return ReduceJSForInNext(node);
2439     case IrOpcode::kJSLoadMessage:
2440       return ReduceJSLoadMessage(node);
2441     case IrOpcode::kJSStoreMessage:
2442       return ReduceJSStoreMessage(node);
2443     case IrOpcode::kJSGeneratorStore:
2444       return ReduceJSGeneratorStore(node);
2445     case IrOpcode::kJSGeneratorRestoreContinuation:
2446       return ReduceJSGeneratorRestoreContinuation(node);
2447     case IrOpcode::kJSGeneratorRestoreRegister:
2448       return ReduceJSGeneratorRestoreRegister(node);
2449     // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
2450     // fooling anyone. Consider moving this into a separate reducer.
2451     case IrOpcode::kSpeculativeNumberAdd:
2452       return ReduceSpeculativeNumberAdd(node);
2453     case IrOpcode::kSpeculativeNumberSubtract:
2454     case IrOpcode::kSpeculativeNumberMultiply:
2455     case IrOpcode::kSpeculativeNumberDivide:
2456     case IrOpcode::kSpeculativeNumberModulus:
2457       return ReduceSpeculativeNumberBinop(node);
2458     default:
2459       break;
2460   }
2461   return NoChange();
2462 }
2463 
2464 
factory() const2465 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2466 
2467 
graph() const2468 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2469 
2470 
isolate() const2471 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2472 
2473 
javascript() const2474 JSOperatorBuilder* JSTypedLowering::javascript() const {
2475   return jsgraph()->javascript();
2476 }
2477 
2478 
common() const2479 CommonOperatorBuilder* JSTypedLowering::common() const {
2480   return jsgraph()->common();
2481 }
2482 
simplified() const2483 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2484   return jsgraph()->simplified();
2485 }
2486 
2487 
dependencies() const2488 CompilationDependencies* JSTypedLowering::dependencies() const {
2489   return dependencies_;
2490 }
2491 
2492 }  // namespace compiler
2493 }  // namespace internal
2494 }  // namespace v8
2495