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