• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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-type-hint-lowering.h"
6 
7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-heap-broker.h"
10 #include "src/compiler/operator-properties.h"
11 #include "src/compiler/simplified-operator.h"
12 #include "src/objects/feedback-vector.h"
13 #include "src/objects/type-hints.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
19 namespace {
20 
BinaryOperationHintToNumberOperationHint(BinaryOperationHint binop_hint,NumberOperationHint * number_hint)21 bool BinaryOperationHintToNumberOperationHint(
22     BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
23   switch (binop_hint) {
24     case BinaryOperationHint::kSignedSmall:
25       *number_hint = NumberOperationHint::kSignedSmall;
26       return true;
27     case BinaryOperationHint::kSignedSmallInputs:
28       *number_hint = NumberOperationHint::kSignedSmallInputs;
29       return true;
30     case BinaryOperationHint::kNumber:
31       *number_hint = NumberOperationHint::kNumber;
32       return true;
33     case BinaryOperationHint::kNumberOrOddball:
34       *number_hint = NumberOperationHint::kNumberOrOddball;
35       return true;
36     case BinaryOperationHint::kAny:
37     case BinaryOperationHint::kNone:
38     case BinaryOperationHint::kString:
39     case BinaryOperationHint::kBigInt:
40       break;
41   }
42   return false;
43 }
44 
BinaryOperationHintToBigIntOperationHint(BinaryOperationHint binop_hint,BigIntOperationHint * bigint_hint)45 bool BinaryOperationHintToBigIntOperationHint(
46     BinaryOperationHint binop_hint, BigIntOperationHint* bigint_hint) {
47   switch (binop_hint) {
48     case BinaryOperationHint::kSignedSmall:
49     case BinaryOperationHint::kSignedSmallInputs:
50     case BinaryOperationHint::kNumber:
51     case BinaryOperationHint::kNumberOrOddball:
52     case BinaryOperationHint::kAny:
53     case BinaryOperationHint::kNone:
54     case BinaryOperationHint::kString:
55       return false;
56     case BinaryOperationHint::kBigInt:
57       *bigint_hint = BigIntOperationHint::kBigInt;
58       return true;
59   }
60   UNREACHABLE();
61 }
62 
63 }  // namespace
64 
65 class JSSpeculativeBinopBuilder final {
66  public:
JSSpeculativeBinopBuilder(const JSTypeHintLowering * lowering,const Operator * op,Node * left,Node * right,Node * effect,Node * control,FeedbackSlot slot)67   JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
68                             const Operator* op, Node* left, Node* right,
69                             Node* effect, Node* control, FeedbackSlot slot)
70       : lowering_(lowering),
71         op_(op),
72         left_(left),
73         right_(right),
74         effect_(effect),
75         control_(control),
76         slot_(slot) {}
77 
GetBinaryNumberOperationHint(NumberOperationHint * hint)78   bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
79     return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
80                                                     hint);
81   }
82 
GetBinaryBigIntOperationHint(BigIntOperationHint * hint)83   bool GetBinaryBigIntOperationHint(BigIntOperationHint* hint) {
84     return BinaryOperationHintToBigIntOperationHint(GetBinaryOperationHint(),
85                                                     hint);
86   }
87 
GetCompareNumberOperationHint(NumberOperationHint * hint)88   bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
89     switch (GetCompareOperationHint()) {
90       case CompareOperationHint::kSignedSmall:
91         *hint = NumberOperationHint::kSignedSmall;
92         return true;
93       case CompareOperationHint::kNumber:
94         *hint = NumberOperationHint::kNumber;
95         return true;
96       case CompareOperationHint::kNumberOrBoolean:
97         *hint = NumberOperationHint::kNumberOrBoolean;
98         return true;
99       case CompareOperationHint::kNumberOrOddball:
100         *hint = NumberOperationHint::kNumberOrOddball;
101         return true;
102       case CompareOperationHint::kAny:
103       case CompareOperationHint::kNone:
104       case CompareOperationHint::kString:
105       case CompareOperationHint::kSymbol:
106       case CompareOperationHint::kBigInt:
107       case CompareOperationHint::kReceiver:
108       case CompareOperationHint::kReceiverOrNullOrUndefined:
109       case CompareOperationHint::kInternalizedString:
110         break;
111     }
112     return false;
113   }
114 
SpeculativeNumberOp(NumberOperationHint hint)115   const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
116     switch (op_->opcode()) {
117       case IrOpcode::kJSAdd:
118         if (hint == NumberOperationHint::kSignedSmall) {
119           return simplified()->SpeculativeSafeIntegerAdd(hint);
120         } else {
121           return simplified()->SpeculativeNumberAdd(hint);
122         }
123       case IrOpcode::kJSSubtract:
124         if (hint == NumberOperationHint::kSignedSmall) {
125           return simplified()->SpeculativeSafeIntegerSubtract(hint);
126         } else {
127           return simplified()->SpeculativeNumberSubtract(hint);
128         }
129       case IrOpcode::kJSMultiply:
130         return simplified()->SpeculativeNumberMultiply(hint);
131       case IrOpcode::kJSExponentiate:
132         return simplified()->SpeculativeNumberPow(hint);
133       case IrOpcode::kJSDivide:
134         return simplified()->SpeculativeNumberDivide(hint);
135       case IrOpcode::kJSModulus:
136         return simplified()->SpeculativeNumberModulus(hint);
137       case IrOpcode::kJSBitwiseAnd:
138         return simplified()->SpeculativeNumberBitwiseAnd(hint);
139       case IrOpcode::kJSBitwiseOr:
140         return simplified()->SpeculativeNumberBitwiseOr(hint);
141       case IrOpcode::kJSBitwiseXor:
142         return simplified()->SpeculativeNumberBitwiseXor(hint);
143       case IrOpcode::kJSShiftLeft:
144         return simplified()->SpeculativeNumberShiftLeft(hint);
145       case IrOpcode::kJSShiftRight:
146         return simplified()->SpeculativeNumberShiftRight(hint);
147       case IrOpcode::kJSShiftRightLogical:
148         return simplified()->SpeculativeNumberShiftRightLogical(hint);
149       default:
150         break;
151     }
152     UNREACHABLE();
153   }
154 
SpeculativeBigIntOp(BigIntOperationHint hint)155   const Operator* SpeculativeBigIntOp(BigIntOperationHint hint) {
156     DCHECK(jsgraph()->machine()->Is64());
157     switch (op_->opcode()) {
158       case IrOpcode::kJSAdd:
159         return simplified()->SpeculativeBigIntAdd(hint);
160       case IrOpcode::kJSSubtract:
161         return simplified()->SpeculativeBigIntSubtract(hint);
162       default:
163         break;
164     }
165     UNREACHABLE();
166   }
167 
SpeculativeCompareOp(NumberOperationHint hint)168   const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
169     switch (op_->opcode()) {
170       case IrOpcode::kJSEqual:
171         return simplified()->SpeculativeNumberEqual(hint);
172       case IrOpcode::kJSLessThan:
173         return simplified()->SpeculativeNumberLessThan(hint);
174       case IrOpcode::kJSGreaterThan:
175         std::swap(left_, right_);  // a > b => b < a
176         return simplified()->SpeculativeNumberLessThan(hint);
177       case IrOpcode::kJSLessThanOrEqual:
178         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
179       case IrOpcode::kJSGreaterThanOrEqual:
180         std::swap(left_, right_);  // a >= b => b <= a
181         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
182       default:
183         break;
184     }
185     UNREACHABLE();
186   }
187 
BuildSpeculativeOperation(const Operator * op)188   Node* BuildSpeculativeOperation(const Operator* op) {
189     DCHECK_EQ(2, op->ValueInputCount());
190     DCHECK_EQ(1, op->EffectInputCount());
191     DCHECK_EQ(1, op->ControlInputCount());
192     DCHECK_EQ(false, OperatorProperties::HasFrameStateInput(op));
193     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
194     DCHECK_EQ(1, op->EffectOutputCount());
195     DCHECK_EQ(0, op->ControlOutputCount());
196     return graph()->NewNode(op, left_, right_, effect_, control_);
197   }
198 
TryBuildNumberBinop()199   Node* TryBuildNumberBinop() {
200     NumberOperationHint hint;
201     if (GetBinaryNumberOperationHint(&hint)) {
202       const Operator* op = SpeculativeNumberOp(hint);
203       Node* node = BuildSpeculativeOperation(op);
204       return node;
205     }
206     return nullptr;
207   }
208 
TryBuildBigIntBinop()209   Node* TryBuildBigIntBinop() {
210     DCHECK(jsgraph()->machine()->Is64());
211     BigIntOperationHint hint;
212     if (GetBinaryBigIntOperationHint(&hint)) {
213       const Operator* op = SpeculativeBigIntOp(hint);
214       Node* node = BuildSpeculativeOperation(op);
215       return node;
216     }
217     return nullptr;
218   }
219 
TryBuildNumberCompare()220   Node* TryBuildNumberCompare() {
221     NumberOperationHint hint;
222     if (GetCompareNumberOperationHint(&hint)) {
223       const Operator* op = SpeculativeCompareOp(hint);
224       Node* node = BuildSpeculativeOperation(op);
225       return node;
226     }
227     return nullptr;
228   }
229 
jsgraph() const230   JSGraph* jsgraph() const { return lowering_->jsgraph(); }
isolate() const231   Isolate* isolate() const { return jsgraph()->isolate(); }
graph() const232   Graph* graph() const { return jsgraph()->graph(); }
javascript()233   JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
simplified()234   SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
common()235   CommonOperatorBuilder* common() { return jsgraph()->common(); }
236 
237  private:
GetBinaryOperationHint()238   BinaryOperationHint GetBinaryOperationHint() {
239     return lowering_->GetBinaryOperationHint(slot_);
240   }
241 
GetCompareOperationHint()242   CompareOperationHint GetCompareOperationHint() {
243     return lowering_->GetCompareOperationHint(slot_);
244   }
245 
246   JSTypeHintLowering const* const lowering_;
247   Operator const* const op_;
248   Node* left_;
249   Node* right_;
250   Node* const effect_;
251   Node* const control_;
252   FeedbackSlot const slot_;
253 };
254 
JSTypeHintLowering(JSHeapBroker * broker,JSGraph * jsgraph,FeedbackVectorRef feedback_vector,Flags flags)255 JSTypeHintLowering::JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
256                                        FeedbackVectorRef feedback_vector,
257                                        Flags flags)
258     : broker_(broker),
259       jsgraph_(jsgraph),
260       flags_(flags),
261       feedback_vector_(feedback_vector) {}
262 
isolate() const263 Isolate* JSTypeHintLowering::isolate() const { return jsgraph()->isolate(); }
264 
GetBinaryOperationHint(FeedbackSlot slot) const265 BinaryOperationHint JSTypeHintLowering::GetBinaryOperationHint(
266     FeedbackSlot slot) const {
267   FeedbackSource source(feedback_vector(), slot);
268   return broker()->GetFeedbackForBinaryOperation(source);
269 }
270 
GetCompareOperationHint(FeedbackSlot slot) const271 CompareOperationHint JSTypeHintLowering::GetCompareOperationHint(
272     FeedbackSlot slot) const {
273   FeedbackSource source(feedback_vector(), slot);
274   return broker()->GetFeedbackForCompareOperation(source);
275 }
276 
ReduceUnaryOperation(const Operator * op,Node * operand,Node * effect,Node * control,FeedbackSlot slot) const277 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
278     const Operator* op, Node* operand, Node* effect, Node* control,
279     FeedbackSlot slot) const {
280   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
281           slot, effect, control,
282           DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
283     return LoweringResult::Exit(node);
284   }
285 
286   // Note: Unary and binary operations collect the same kind of feedback.
287   FeedbackSource feedback(feedback_vector(), slot);
288 
289   Node* node;
290   switch (op->opcode()) {
291     case IrOpcode::kJSBitwiseNot: {
292       // Lower to a speculative xor with -1 if we have some kind of Number
293       // feedback.
294       JSSpeculativeBinopBuilder b(
295           this, jsgraph()->javascript()->BitwiseXor(feedback), operand,
296           jsgraph()->SmiConstant(-1), effect, control, slot);
297       node = b.TryBuildNumberBinop();
298       break;
299     }
300     case IrOpcode::kJSDecrement: {
301       // Lower to a speculative subtraction of 1 if we have some kind of Number
302       // feedback.
303       JSSpeculativeBinopBuilder b(
304           this, jsgraph()->javascript()->Subtract(feedback), operand,
305           jsgraph()->SmiConstant(1), effect, control, slot);
306       node = b.TryBuildNumberBinop();
307       break;
308     }
309     case IrOpcode::kJSIncrement: {
310       // Lower to a speculative addition of 1 if we have some kind of Number
311       // feedback.
312       JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Add(feedback),
313                                   operand, jsgraph()->SmiConstant(1), effect,
314                                   control, slot);
315       node = b.TryBuildNumberBinop();
316       break;
317     }
318     case IrOpcode::kJSNegate: {
319       // Lower to a speculative multiplication with -1 if we have some kind of
320       // Number feedback.
321       JSSpeculativeBinopBuilder b(
322           this, jsgraph()->javascript()->Multiply(feedback), operand,
323           jsgraph()->SmiConstant(-1), effect, control, slot);
324       node = b.TryBuildNumberBinop();
325       if (!node) {
326         if (jsgraph()->machine()->Is64()) {
327           if (GetBinaryOperationHint(slot) == BinaryOperationHint::kBigInt) {
328             op = jsgraph()->simplified()->SpeculativeBigIntNegate(
329                 BigIntOperationHint::kBigInt);
330             node = jsgraph()->graph()->NewNode(op, operand, effect, control);
331           }
332         }
333       }
334       break;
335     }
336     default:
337       UNREACHABLE();
338   }
339 
340   if (node != nullptr) {
341     return LoweringResult::SideEffectFree(node, node, control);
342   } else {
343     return LoweringResult::NoChange();
344   }
345 }
346 
ReduceBinaryOperation(const Operator * op,Node * left,Node * right,Node * effect,Node * control,FeedbackSlot slot) const347 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
348     const Operator* op, Node* left, Node* right, Node* effect, Node* control,
349     FeedbackSlot slot) const {
350   switch (op->opcode()) {
351     case IrOpcode::kJSStrictEqual: {
352       if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
353               slot, effect, control,
354               DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
355         return LoweringResult::Exit(node);
356       }
357       // TODO(turbofan): Should we generally support early lowering of
358       // JSStrictEqual operators here?
359       break;
360     }
361     case IrOpcode::kJSEqual:
362     case IrOpcode::kJSLessThan:
363     case IrOpcode::kJSGreaterThan:
364     case IrOpcode::kJSLessThanOrEqual:
365     case IrOpcode::kJSGreaterThanOrEqual: {
366       if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
367               slot, effect, control,
368               DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
369         return LoweringResult::Exit(node);
370       }
371       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
372       if (Node* node = b.TryBuildNumberCompare()) {
373         return LoweringResult::SideEffectFree(node, node, control);
374       }
375       break;
376     }
377     case IrOpcode::kJSInstanceOf: {
378       if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
379               slot, effect, control,
380               DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
381         return LoweringResult::Exit(node);
382       }
383       // TODO(turbofan): Should we generally support early lowering of
384       // JSInstanceOf operators here?
385       break;
386     }
387     case IrOpcode::kJSBitwiseOr:
388     case IrOpcode::kJSBitwiseXor:
389     case IrOpcode::kJSBitwiseAnd:
390     case IrOpcode::kJSShiftLeft:
391     case IrOpcode::kJSShiftRight:
392     case IrOpcode::kJSShiftRightLogical:
393     case IrOpcode::kJSAdd:
394     case IrOpcode::kJSSubtract:
395     case IrOpcode::kJSMultiply:
396     case IrOpcode::kJSDivide:
397     case IrOpcode::kJSModulus:
398     case IrOpcode::kJSExponentiate: {
399       if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
400               slot, effect, control,
401               DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
402         return LoweringResult::Exit(node);
403       }
404       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
405       if (Node* node = b.TryBuildNumberBinop()) {
406         return LoweringResult::SideEffectFree(node, node, control);
407       }
408       if (op->opcode() == IrOpcode::kJSAdd ||
409           op->opcode() == IrOpcode::kJSSubtract) {
410         if (jsgraph()->machine()->Is64()) {
411           if (Node* node = b.TryBuildBigIntBinop()) {
412             return LoweringResult::SideEffectFree(node, node, control);
413           }
414         }
415       }
416       break;
417     }
418     default:
419       UNREACHABLE();
420   }
421   return LoweringResult::NoChange();
422 }
423 
ReduceForInNextOperation(Node * receiver,Node * cache_array,Node * cache_type,Node * index,Node * effect,Node * control,FeedbackSlot slot) const424 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
425     Node* receiver, Node* cache_array, Node* cache_type, Node* index,
426     Node* effect, Node* control, FeedbackSlot slot) const {
427   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
428           slot, effect, control,
429           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
430     return LoweringResult::Exit(node);
431   }
432   return LoweringResult::NoChange();
433 }
434 
435 JSTypeHintLowering::LoweringResult
ReduceForInPrepareOperation(Node * enumerator,Node * effect,Node * control,FeedbackSlot slot) const436 JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
437                                                 Node* control,
438                                                 FeedbackSlot slot) const {
439   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
440           slot, effect, control,
441           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
442     return LoweringResult::Exit(node);
443   }
444   return LoweringResult::NoChange();
445 }
446 
ReduceToNumberOperation(Node * input,Node * effect,Node * control,FeedbackSlot slot) const447 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
448     Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
449   DCHECK(!slot.IsInvalid());
450   NumberOperationHint hint;
451   if (BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(slot),
452                                                &hint)) {
453     Node* node = jsgraph()->graph()->NewNode(
454         jsgraph()->simplified()->SpeculativeToNumber(hint, FeedbackSource()),
455         input, effect, control);
456     return LoweringResult::SideEffectFree(node, node, control);
457   }
458   return LoweringResult::NoChange();
459 }
460 
ReduceCallOperation(const Operator * op,Node * const * args,int arg_count,Node * effect,Node * control,FeedbackSlot slot) const461 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
462     const Operator* op, Node* const* args, int arg_count, Node* effect,
463     Node* control, FeedbackSlot slot) const {
464   DCHECK(op->opcode() == IrOpcode::kJSCall ||
465          op->opcode() == IrOpcode::kJSCallWithSpread);
466   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
467           slot, effect, control,
468           DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
469     return LoweringResult::Exit(node);
470   }
471   return LoweringResult::NoChange();
472 }
473 
ReduceConstructOperation(const Operator * op,Node * const * args,int arg_count,Node * effect,Node * control,FeedbackSlot slot) const474 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
475     const Operator* op, Node* const* args, int arg_count, Node* effect,
476     Node* control, FeedbackSlot slot) const {
477   DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
478          op->opcode() == IrOpcode::kJSConstructWithSpread);
479   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
480           slot, effect, control,
481           DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
482     return LoweringResult::Exit(node);
483   }
484   return LoweringResult::NoChange();
485 }
486 
487 JSTypeHintLowering::LoweringResult
ReduceGetIteratorOperation(const Operator * op,Node * receiver,Node * effect,Node * control,FeedbackSlot load_slot,FeedbackSlot call_slot) const488 JSTypeHintLowering::ReduceGetIteratorOperation(const Operator* op,
489                                                Node* receiver, Node* effect,
490                                                Node* control,
491                                                FeedbackSlot load_slot,
492                                                FeedbackSlot call_slot) const {
493   DCHECK_EQ(IrOpcode::kJSGetIterator, op->opcode());
494   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
495           load_slot, effect, control,
496           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
497     return LoweringResult::Exit(node);
498   }
499   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
500           call_slot, effect, control,
501           DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
502     return LoweringResult::Exit(node);
503   }
504   return LoweringResult::NoChange();
505 }
506 
ReduceLoadNamedOperation(const Operator * op,Node * effect,Node * control,FeedbackSlot slot) const507 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
508     const Operator* op, Node* effect, Node* control, FeedbackSlot slot) const {
509   DCHECK(op->opcode() == IrOpcode::kJSLoadNamed ||
510          op->opcode() == IrOpcode::kJSLoadNamedFromSuper);
511   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
512           slot, effect, control,
513           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
514     return LoweringResult::Exit(node);
515   }
516   return LoweringResult::NoChange();
517 }
518 
ReduceLoadKeyedOperation(const Operator * op,Node * obj,Node * key,Node * effect,Node * control,FeedbackSlot slot) const519 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
520     const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
521     FeedbackSlot slot) const {
522   DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
523   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
524           slot, effect, control,
525           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
526     return LoweringResult::Exit(node);
527   }
528   return LoweringResult::NoChange();
529 }
530 
531 JSTypeHintLowering::LoweringResult
ReduceStoreNamedOperation(const Operator * op,Node * obj,Node * val,Node * effect,Node * control,FeedbackSlot slot) const532 JSTypeHintLowering::ReduceStoreNamedOperation(const Operator* op, Node* obj,
533                                               Node* val, Node* effect,
534                                               Node* control,
535                                               FeedbackSlot slot) const {
536   DCHECK(op->opcode() == IrOpcode::kJSSetNamedProperty ||
537          op->opcode() == IrOpcode::kJSDefineNamedOwnProperty);
538   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
539           slot, effect, control,
540           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
541     return LoweringResult::Exit(node);
542   }
543   return LoweringResult::NoChange();
544 }
545 
546 JSTypeHintLowering::LoweringResult
ReduceStoreKeyedOperation(const Operator * op,Node * obj,Node * key,Node * val,Node * effect,Node * control,FeedbackSlot slot) const547 JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
548                                               Node* key, Node* val,
549                                               Node* effect, Node* control,
550                                               FeedbackSlot slot) const {
551   DCHECK(op->opcode() == IrOpcode::kJSSetKeyedProperty ||
552          op->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
553          op->opcode() == IrOpcode::kJSDefineKeyedOwnPropertyInLiteral ||
554          op->opcode() == IrOpcode::kJSDefineKeyedOwnProperty);
555   if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
556           slot, effect, control,
557           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
558     return LoweringResult::Exit(node);
559   }
560   return LoweringResult::NoChange();
561 }
562 
BuildDeoptIfFeedbackIsInsufficient(FeedbackSlot slot,Node * effect,Node * control,DeoptimizeReason reason) const563 Node* JSTypeHintLowering::BuildDeoptIfFeedbackIsInsufficient(
564     FeedbackSlot slot, Node* effect, Node* control,
565     DeoptimizeReason reason) const {
566   if (!(flags() & kBailoutOnUninitialized)) return nullptr;
567 
568   FeedbackSource source(feedback_vector(), slot);
569   if (!broker()->FeedbackIsInsufficient(source)) return nullptr;
570 
571   Node* deoptimize = jsgraph()->graph()->NewNode(
572       jsgraph()->common()->Deoptimize(reason, FeedbackSource()),
573       jsgraph()->Dead(), effect, control);
574   Node* frame_state =
575       NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
576   deoptimize->ReplaceInput(0, frame_state);
577   return deoptimize;
578 }
579 
580 }  // namespace compiler
581 }  // namespace internal
582 }  // namespace v8
583