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