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