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