• 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::kSigned32:
31       *number_hint = NumberOperationHint::kSigned32;
32       return true;
33     case BinaryOperationHint::kNumber:
34       *number_hint = NumberOperationHint::kNumber;
35       return true;
36     case BinaryOperationHint::kNumberOrOddball:
37       *number_hint = NumberOperationHint::kNumberOrOddball;
38       return true;
39     case BinaryOperationHint::kAny:
40     case BinaryOperationHint::kNone:
41     case BinaryOperationHint::kString:
42     case BinaryOperationHint::kBigInt:
43       break;
44   }
45   return false;
46 }
47 
BinaryOperationHintToBigIntOperationHint(BinaryOperationHint binop_hint,BigIntOperationHint * bigint_hint)48 bool BinaryOperationHintToBigIntOperationHint(
49     BinaryOperationHint binop_hint, BigIntOperationHint* bigint_hint) {
50   switch (binop_hint) {
51     case BinaryOperationHint::kSignedSmall:
52     case BinaryOperationHint::kSignedSmallInputs:
53     case BinaryOperationHint::kSigned32:
54     case BinaryOperationHint::kNumber:
55     case BinaryOperationHint::kNumberOrOddball:
56     case BinaryOperationHint::kAny:
57     case BinaryOperationHint::kNone:
58     case BinaryOperationHint::kString:
59       return false;
60     case BinaryOperationHint::kBigInt:
61       *bigint_hint = BigIntOperationHint::kBigInt;
62       return true;
63   }
64   UNREACHABLE();
65 }
66 
67 }  // namespace
68 
69 class JSSpeculativeBinopBuilder final {
70  public:
JSSpeculativeBinopBuilder(const JSTypeHintLowering * lowering,const Operator * op,Node * left,Node * right,Node * effect,Node * control,FeedbackSlot slot)71   JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
72                             const Operator* op, Node* left, Node* right,
73                             Node* effect, Node* control, FeedbackSlot slot)
74       : lowering_(lowering),
75         op_(op),
76         left_(left),
77         right_(right),
78         effect_(effect),
79         control_(control),
80         slot_(slot) {}
81 
GetBinaryNumberOperationHint(NumberOperationHint * hint)82   bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
83     return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
84                                                     hint);
85   }
86 
GetBinaryBigIntOperationHint(BigIntOperationHint * hint)87   bool GetBinaryBigIntOperationHint(BigIntOperationHint* hint) {
88     return BinaryOperationHintToBigIntOperationHint(GetBinaryOperationHint(),
89                                                     hint);
90   }
91 
GetCompareNumberOperationHint(NumberOperationHint * hint)92   bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
93     switch (GetCompareOperationHint()) {
94       case CompareOperationHint::kSignedSmall:
95         *hint = NumberOperationHint::kSignedSmall;
96         return true;
97       case CompareOperationHint::kNumber:
98         *hint = NumberOperationHint::kNumber;
99         return true;
100       case CompareOperationHint::kNumberOrBoolean:
101         *hint = NumberOperationHint::kNumberOrBoolean;
102         return true;
103       case CompareOperationHint::kNumberOrOddball:
104         *hint = NumberOperationHint::kNumberOrOddball;
105         return true;
106       case CompareOperationHint::kAny:
107       case CompareOperationHint::kNone:
108       case CompareOperationHint::kString:
109       case CompareOperationHint::kSymbol:
110       case CompareOperationHint::kBigInt:
111       case CompareOperationHint::kReceiver:
112       case CompareOperationHint::kReceiverOrNullOrUndefined:
113       case CompareOperationHint::kInternalizedString:
114         break;
115     }
116     return false;
117   }
118 
SpeculativeNumberOp(NumberOperationHint hint)119   const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
120     switch (op_->opcode()) {
121       case IrOpcode::kJSAdd:
122         if (hint == NumberOperationHint::kSignedSmall ||
123             hint == NumberOperationHint::kSigned32) {
124           return simplified()->SpeculativeSafeIntegerAdd(hint);
125         } else {
126           return simplified()->SpeculativeNumberAdd(hint);
127         }
128       case IrOpcode::kJSSubtract:
129         if (hint == NumberOperationHint::kSignedSmall ||
130             hint == NumberOperationHint::kSigned32) {
131           return simplified()->SpeculativeSafeIntegerSubtract(hint);
132         } else {
133           return simplified()->SpeculativeNumberSubtract(hint);
134         }
135       case IrOpcode::kJSMultiply:
136         return simplified()->SpeculativeNumberMultiply(hint);
137       case IrOpcode::kJSDivide:
138         return simplified()->SpeculativeNumberDivide(hint);
139       case IrOpcode::kJSModulus:
140         return simplified()->SpeculativeNumberModulus(hint);
141       case IrOpcode::kJSBitwiseAnd:
142         return simplified()->SpeculativeNumberBitwiseAnd(hint);
143       case IrOpcode::kJSBitwiseOr:
144         return simplified()->SpeculativeNumberBitwiseOr(hint);
145       case IrOpcode::kJSBitwiseXor:
146         return simplified()->SpeculativeNumberBitwiseXor(hint);
147       case IrOpcode::kJSShiftLeft:
148         return simplified()->SpeculativeNumberShiftLeft(hint);
149       case IrOpcode::kJSShiftRight:
150         return simplified()->SpeculativeNumberShiftRight(hint);
151       case IrOpcode::kJSShiftRightLogical:
152         return simplified()->SpeculativeNumberShiftRightLogical(hint);
153       default:
154         break;
155     }
156     UNREACHABLE();
157   }
158 
SpeculativeBigIntOp(BigIntOperationHint hint)159   const Operator* SpeculativeBigIntOp(BigIntOperationHint hint) {
160     switch (op_->opcode()) {
161       case IrOpcode::kJSAdd:
162         return simplified()->SpeculativeBigIntAdd(hint);
163       case IrOpcode::kJSSubtract:
164         return simplified()->SpeculativeBigIntSubtract(hint);
165       default:
166         break;
167     }
168     UNREACHABLE();
169   }
170 
SpeculativeCompareOp(NumberOperationHint hint)171   const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
172     switch (op_->opcode()) {
173       case IrOpcode::kJSEqual:
174         return simplified()->SpeculativeNumberEqual(hint);
175       case IrOpcode::kJSLessThan:
176         return simplified()->SpeculativeNumberLessThan(hint);
177       case IrOpcode::kJSGreaterThan:
178         std::swap(left_, right_);  // a > b => b < a
179         return simplified()->SpeculativeNumberLessThan(hint);
180       case IrOpcode::kJSLessThanOrEqual:
181         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
182       case IrOpcode::kJSGreaterThanOrEqual:
183         std::swap(left_, right_);  // a >= b => b <= a
184         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
185       default:
186         break;
187     }
188     UNREACHABLE();
189   }
190 
BuildSpeculativeOperation(const Operator * op)191   Node* BuildSpeculativeOperation(const Operator* op) {
192     DCHECK_EQ(2, op->ValueInputCount());
193     DCHECK_EQ(1, op->EffectInputCount());
194     DCHECK_EQ(1, op->ControlInputCount());
195     DCHECK_EQ(false, OperatorProperties::HasFrameStateInput(op));
196     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
197     DCHECK_EQ(1, op->EffectOutputCount());
198     DCHECK_EQ(0, op->ControlOutputCount());
199     return graph()->NewNode(op, left_, right_, effect_, control_);
200   }
201 
TryBuildNumberBinop()202   Node* TryBuildNumberBinop() {
203     NumberOperationHint hint;
204     if (GetBinaryNumberOperationHint(&hint)) {
205       const Operator* op = SpeculativeNumberOp(hint);
206       Node* node = BuildSpeculativeOperation(op);
207       return node;
208     }
209     return nullptr;
210   }
211 
TryBuildBigIntBinop()212   Node* TryBuildBigIntBinop() {
213     BigIntOperationHint hint;
214     if (GetBinaryBigIntOperationHint(&hint)) {
215       const Operator* op = SpeculativeBigIntOp(hint);
216       Node* node = BuildSpeculativeOperation(op);
217       return node;
218     }
219     return nullptr;
220   }
221 
TryBuildNumberCompare()222   Node* TryBuildNumberCompare() {
223     NumberOperationHint hint;
224     if (GetCompareNumberOperationHint(&hint)) {
225       const Operator* op = SpeculativeCompareOp(hint);
226       Node* node = BuildSpeculativeOperation(op);
227       return node;
228     }
229     return nullptr;
230   }
231 
jsgraph() const232   JSGraph* jsgraph() const { return lowering_->jsgraph(); }
isolate() const233   Isolate* isolate() const { return jsgraph()->isolate(); }
graph() const234   Graph* graph() const { return jsgraph()->graph(); }
javascript()235   JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
simplified()236   SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
common()237   CommonOperatorBuilder* common() { return jsgraph()->common(); }
238 
239  private:
GetBinaryOperationHint()240   BinaryOperationHint GetBinaryOperationHint() {
241     return lowering_->GetBinaryOperationHint(slot_);
242   }
243 
GetCompareOperationHint()244   CompareOperationHint GetCompareOperationHint() {
245     return lowering_->GetCompareOperationHint(slot_);
246   }
247 
248   JSTypeHintLowering const* const lowering_;
249   Operator const* const op_;
250   Node* left_;
251   Node* right_;
252   Node* const effect_;
253   Node* const control_;
254   FeedbackSlot const slot_;
255 };
256 
JSTypeHintLowering(JSHeapBroker * broker,JSGraph * jsgraph,FeedbackVectorRef feedback_vector,Flags flags)257 JSTypeHintLowering::JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
258                                        FeedbackVectorRef feedback_vector,
259                                        Flags flags)
260     : broker_(broker),
261       jsgraph_(jsgraph),
262       flags_(flags),
263       feedback_vector_(feedback_vector) {}
264 
isolate() const265 Isolate* JSTypeHintLowering::isolate() const { return jsgraph()->isolate(); }
266 
GetBinaryOperationHint(FeedbackSlot slot) const267 BinaryOperationHint JSTypeHintLowering::GetBinaryOperationHint(
268     FeedbackSlot slot) const {
269   FeedbackSource source(feedback_vector(), slot);
270   return broker()->GetFeedbackForBinaryOperation(source);
271 }
272 
GetCompareOperationHint(FeedbackSlot slot) const273 CompareOperationHint JSTypeHintLowering::GetCompareOperationHint(
274     FeedbackSlot slot) const {
275   FeedbackSource source(feedback_vector(), slot);
276   return broker()->GetFeedbackForCompareOperation(source);
277 }
278 
ReduceUnaryOperation(const Operator * op,Node * operand,Node * effect,Node * control,FeedbackSlot slot) const279 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
280     const Operator* op, Node* operand, Node* effect, Node* control,
281     FeedbackSlot slot) const {
282   if (Node* node = TryBuildSoftDeopt(
283           slot, effect, control,
284           DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
285     return LoweringResult::Exit(node);
286   }
287 
288   // Note: Unary and binary operations collect the same kind of feedback.
289   FeedbackSource feedback(feedback_vector(), slot);
290 
291   Node* node;
292   switch (op->opcode()) {
293     case IrOpcode::kJSBitwiseNot: {
294       // Lower to a speculative xor with -1 if we have some kind of Number
295       // feedback.
296       JSSpeculativeBinopBuilder b(
297           this, jsgraph()->javascript()->BitwiseXor(feedback), operand,
298           jsgraph()->SmiConstant(-1), effect, control, slot);
299       node = b.TryBuildNumberBinop();
300       break;
301     }
302     case IrOpcode::kJSDecrement: {
303       // Lower to a speculative subtraction of 1 if we have some kind of Number
304       // feedback.
305       JSSpeculativeBinopBuilder b(
306           this, jsgraph()->javascript()->Subtract(feedback), operand,
307           jsgraph()->SmiConstant(1), effect, control, slot);
308       node = b.TryBuildNumberBinop();
309       break;
310     }
311     case IrOpcode::kJSIncrement: {
312       // Lower to a speculative addition of 1 if we have some kind of Number
313       // feedback.
314       JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Add(feedback),
315                                   operand, jsgraph()->SmiConstant(1), effect,
316                                   control, slot);
317       node = b.TryBuildNumberBinop();
318       break;
319     }
320     case IrOpcode::kJSNegate: {
321       // Lower to a speculative multiplication with -1 if we have some kind of
322       // Number feedback.
323       JSSpeculativeBinopBuilder b(
324           this, jsgraph()->javascript()->Multiply(feedback), operand,
325           jsgraph()->SmiConstant(-1), effect, control, slot);
326       node = b.TryBuildNumberBinop();
327       if (!node) {
328         if (GetBinaryOperationHint(slot) == BinaryOperationHint::kBigInt) {
329           const Operator* op = jsgraph()->simplified()->SpeculativeBigIntNegate(
330               BigIntOperationHint::kBigInt);
331           node = jsgraph()->graph()->NewNode(op, operand, effect, control);
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 = TryBuildSoftDeopt(
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 = TryBuildSoftDeopt(
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 = TryBuildSoftDeopt(
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       if (Node* node = TryBuildSoftDeopt(
399               slot, effect, control,
400               DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
401         return LoweringResult::Exit(node);
402       }
403       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
404       if (Node* node = b.TryBuildNumberBinop()) {
405         return LoweringResult::SideEffectFree(node, node, control);
406       }
407       if (op->opcode() == IrOpcode::kJSAdd ||
408           op->opcode() == IrOpcode::kJSSubtract) {
409         if (Node* node = b.TryBuildBigIntBinop()) {
410           return LoweringResult::SideEffectFree(node, node, control);
411         }
412       }
413       break;
414     }
415     case IrOpcode::kJSExponentiate: {
416       if (Node* node = TryBuildSoftDeopt(
417               slot, effect, control,
418               DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
419         return LoweringResult::Exit(node);
420       }
421       // TODO(neis): Introduce a SpeculativeNumberPow operator?
422       break;
423     }
424     default:
425       UNREACHABLE();
426   }
427   return LoweringResult::NoChange();
428 }
429 
ReduceForInNextOperation(Node * receiver,Node * cache_array,Node * cache_type,Node * index,Node * effect,Node * control,FeedbackSlot slot) const430 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
431     Node* receiver, Node* cache_array, Node* cache_type, Node* index,
432     Node* effect, Node* control, FeedbackSlot slot) const {
433   if (Node* node = TryBuildSoftDeopt(
434           slot, effect, control,
435           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
436     return LoweringResult::Exit(node);
437   }
438   return LoweringResult::NoChange();
439 }
440 
441 JSTypeHintLowering::LoweringResult
ReduceForInPrepareOperation(Node * enumerator,Node * effect,Node * control,FeedbackSlot slot) const442 JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
443                                                 Node* control,
444                                                 FeedbackSlot slot) const {
445   if (Node* node = TryBuildSoftDeopt(
446           slot, effect, control,
447           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
448     return LoweringResult::Exit(node);
449   }
450   return LoweringResult::NoChange();
451 }
452 
ReduceToNumberOperation(Node * input,Node * effect,Node * control,FeedbackSlot slot) const453 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
454     Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
455   DCHECK(!slot.IsInvalid());
456   NumberOperationHint hint;
457   if (BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(slot),
458                                                &hint)) {
459     Node* node = jsgraph()->graph()->NewNode(
460         jsgraph()->simplified()->SpeculativeToNumber(hint, FeedbackSource()),
461         input, effect, control);
462     return LoweringResult::SideEffectFree(node, node, control);
463   }
464   return LoweringResult::NoChange();
465 }
466 
ReduceCallOperation(const Operator * op,Node * const * args,int arg_count,Node * effect,Node * control,FeedbackSlot slot) const467 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
468     const Operator* op, Node* const* args, int arg_count, Node* effect,
469     Node* control, FeedbackSlot slot) const {
470   DCHECK(op->opcode() == IrOpcode::kJSCall ||
471          op->opcode() == IrOpcode::kJSCallWithSpread);
472   if (Node* node = TryBuildSoftDeopt(
473           slot, effect, control,
474           DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
475     return LoweringResult::Exit(node);
476   }
477   return LoweringResult::NoChange();
478 }
479 
ReduceConstructOperation(const Operator * op,Node * const * args,int arg_count,Node * effect,Node * control,FeedbackSlot slot) const480 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
481     const Operator* op, Node* const* args, int arg_count, Node* effect,
482     Node* control, FeedbackSlot slot) const {
483   DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
484          op->opcode() == IrOpcode::kJSConstructWithSpread);
485   if (Node* node = TryBuildSoftDeopt(
486           slot, effect, control,
487           DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
488     return LoweringResult::Exit(node);
489   }
490   return LoweringResult::NoChange();
491 }
492 
493 JSTypeHintLowering::LoweringResult
ReduceGetIteratorOperation(const Operator * op,Node * receiver,Node * effect,Node * control,FeedbackSlot load_slot,FeedbackSlot call_slot) const494 JSTypeHintLowering::ReduceGetIteratorOperation(const Operator* op,
495                                                Node* receiver, Node* effect,
496                                                Node* control,
497                                                FeedbackSlot load_slot,
498                                                FeedbackSlot call_slot) const {
499   DCHECK_EQ(IrOpcode::kJSGetIterator, op->opcode());
500   // Insert soft deopt if the load feedback is invalid.
501   if (Node* node = TryBuildSoftDeopt(
502           load_slot, effect, control,
503           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
504     return LoweringResult::Exit(node);
505   }
506   // Insert soft deopt if the call feedback is invalid.
507   if (Node* node = TryBuildSoftDeopt(
508           call_slot, effect, control,
509           DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
510     return LoweringResult::Exit(node);
511   }
512   return LoweringResult::NoChange();
513 }
514 
ReduceLoadNamedOperation(const Operator * op,Node * effect,Node * control,FeedbackSlot slot) const515 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
516     const Operator* op, Node* effect, Node* control, FeedbackSlot slot) const {
517   DCHECK(op->opcode() == IrOpcode::kJSLoadNamed ||
518          op->opcode() == IrOpcode::kJSLoadNamedFromSuper);
519   if (Node* node = TryBuildSoftDeopt(
520           slot, effect, control,
521           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
522     return LoweringResult::Exit(node);
523   }
524   return LoweringResult::NoChange();
525 }
526 
ReduceLoadKeyedOperation(const Operator * op,Node * obj,Node * key,Node * effect,Node * control,FeedbackSlot slot) const527 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
528     const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
529     FeedbackSlot slot) const {
530   DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
531   if (Node* node = TryBuildSoftDeopt(
532           slot, effect, control,
533           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
534     return LoweringResult::Exit(node);
535   }
536   return LoweringResult::NoChange();
537 }
538 
539 JSTypeHintLowering::LoweringResult
ReduceStoreNamedOperation(const Operator * op,Node * obj,Node * val,Node * effect,Node * control,FeedbackSlot slot) const540 JSTypeHintLowering::ReduceStoreNamedOperation(const Operator* op, Node* obj,
541                                               Node* val, Node* effect,
542                                               Node* control,
543                                               FeedbackSlot slot) const {
544   DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
545          op->opcode() == IrOpcode::kJSStoreNamedOwn);
546   if (Node* node = TryBuildSoftDeopt(
547           slot, effect, control,
548           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
549     return LoweringResult::Exit(node);
550   }
551   return LoweringResult::NoChange();
552 }
553 
554 JSTypeHintLowering::LoweringResult
ReduceStoreKeyedOperation(const Operator * op,Node * obj,Node * key,Node * val,Node * effect,Node * control,FeedbackSlot slot) const555 JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
556                                               Node* key, Node* val,
557                                               Node* effect, Node* control,
558                                               FeedbackSlot slot) const {
559   DCHECK(op->opcode() == IrOpcode::kJSStoreProperty ||
560          op->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
561          op->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral);
562   if (Node* node = TryBuildSoftDeopt(
563           slot, effect, control,
564           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
565     return LoweringResult::Exit(node);
566   }
567   return LoweringResult::NoChange();
568 }
569 
TryBuildSoftDeopt(FeedbackSlot slot,Node * effect,Node * control,DeoptimizeReason reason) const570 Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackSlot slot, Node* effect,
571                                             Node* control,
572                                             DeoptimizeReason reason) const {
573   if (!(flags() & kBailoutOnUninitialized)) return nullptr;
574 
575   FeedbackSource source(feedback_vector(), slot);
576   // TODO(mythria): Think of adding flags to specify if we need a soft deopt for
577   // calls instead of using broker()->is_turboprop() here.
578   if (broker()->is_turboprop() &&
579       broker()->GetFeedbackSlotKind(source) == FeedbackSlotKind::kCall) {
580     return nullptr;
581   }
582 
583   if (!broker()->FeedbackIsInsufficient(source)) return nullptr;
584 
585   Node* deoptimize = jsgraph()->graph()->NewNode(
586       jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
587                                       FeedbackSource()),
588       jsgraph()->Dead(), effect, control);
589   Node* frame_state =
590       NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
591   deoptimize->ReplaceInput(0, frame_state);
592   return deoptimize;
593 }
594 
595 }  // namespace compiler
596 }  // namespace internal
597 }  // namespace v8
598