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