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