5 #include "src/compiler/js-type-hint-lowering.h" 7 #include "src/compiler/access-builder.h" 8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/operator-properties.h" 10 #include "src/compiler/simplified-operator.h" 11 #include "src/feedback-vector.h" 12 #include "src/type-hints.h" 20 bool BinaryOperationHintToNumberOperationHint(
21 BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
23 case BinaryOperationHint::kSignedSmall:
24 *number_hint = NumberOperationHint::kSignedSmall;
26 case BinaryOperationHint::kSignedSmallInputs:
27 *number_hint = NumberOperationHint::kSignedSmallInputs;
29 case BinaryOperationHint::kSigned32:
30 *number_hint = NumberOperationHint::kSigned32;
32 case BinaryOperationHint::kNumber:
33 *number_hint = NumberOperationHint::kNumber;
35 case BinaryOperationHint::kNumberOrOddball:
36 *number_hint = NumberOperationHint::kNumberOrOddball;
38 case BinaryOperationHint::kAny:
39 case BinaryOperationHint::kNone:
40 case BinaryOperationHint::kString:
41 case BinaryOperationHint::kBigInt:
54 : lowering_(lowering),
62 BinaryOperationHint GetBinaryOperationHint() {
64 return nexus.GetBinaryOperationFeedback();
67 CompareOperationHint GetCompareOperationHint() {
69 return nexus.GetCompareOperationFeedback();
72 bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
73 return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
77 bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
78 switch (GetCompareOperationHint()) {
79 case CompareOperationHint::kSignedSmall:
80 *hint = NumberOperationHint::kSignedSmall;
82 case CompareOperationHint::kNumber:
83 *hint = NumberOperationHint::kNumber;
85 case CompareOperationHint::kNumberOrOddball:
86 *hint = NumberOperationHint::kNumberOrOddball;
88 case CompareOperationHint::kAny:
89 case CompareOperationHint::kNone:
90 case CompareOperationHint::kString:
91 case CompareOperationHint::kSymbol:
92 case CompareOperationHint::kBigInt:
93 case CompareOperationHint::kReceiver:
94 case CompareOperationHint::kReceiverOrNullOrUndefined:
95 case CompareOperationHint::kInternalizedString:
101 const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
102 switch (op_->opcode()) {
103 case IrOpcode::kJSAdd:
104 if (hint == NumberOperationHint::kSignedSmall ||
105 hint == NumberOperationHint::kSigned32) {
106 return simplified()->SpeculativeSafeIntegerAdd(hint);
108 return simplified()->SpeculativeNumberAdd(hint);
110 case IrOpcode::kJSSubtract:
111 if (hint == NumberOperationHint::kSignedSmall ||
112 hint == NumberOperationHint::kSigned32) {
113 return simplified()->SpeculativeSafeIntegerSubtract(hint);
115 return simplified()->SpeculativeNumberSubtract(hint);
117 case IrOpcode::kJSMultiply:
118 return simplified()->SpeculativeNumberMultiply(hint);
119 case IrOpcode::kJSDivide:
120 return simplified()->SpeculativeNumberDivide(hint);
121 case IrOpcode::kJSModulus:
122 return simplified()->SpeculativeNumberModulus(hint);
123 case IrOpcode::kJSBitwiseAnd:
124 return simplified()->SpeculativeNumberBitwiseAnd(hint);
125 case IrOpcode::kJSBitwiseOr:
126 return simplified()->SpeculativeNumberBitwiseOr(hint);
127 case IrOpcode::kJSBitwiseXor:
128 return simplified()->SpeculativeNumberBitwiseXor(hint);
129 case IrOpcode::kJSShiftLeft:
130 return simplified()->SpeculativeNumberShiftLeft(hint);
131 case IrOpcode::kJSShiftRight:
132 return simplified()->SpeculativeNumberShiftRight(hint);
133 case IrOpcode::kJSShiftRightLogical:
134 return simplified()->SpeculativeNumberShiftRightLogical(hint);
141 const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
142 switch (op_->opcode()) {
143 case IrOpcode::kJSEqual:
144 return simplified()->SpeculativeNumberEqual(hint);
145 case IrOpcode::kJSLessThan:
146 return simplified()->SpeculativeNumberLessThan(hint);
147 case IrOpcode::kJSGreaterThan:
148 std::swap(left_, right_);
149 return simplified()->SpeculativeNumberLessThan(hint);
150 case IrOpcode::kJSLessThanOrEqual:
151 return simplified()->SpeculativeNumberLessThanOrEqual(hint);
152 case IrOpcode::kJSGreaterThanOrEqual:
153 std::swap(left_, right_);
154 return simplified()->SpeculativeNumberLessThanOrEqual(hint);
162 DCHECK_EQ(2, op->ValueInputCount());
163 DCHECK_EQ(1, op->EffectInputCount());
164 DCHECK_EQ(1, op->ControlInputCount());
165 DCHECK_EQ(
false, OperatorProperties::HasFrameStateInput(op));
166 DCHECK_EQ(
false, OperatorProperties::HasContextInput(op));
167 DCHECK_EQ(1, op->EffectOutputCount());
168 DCHECK_EQ(0, op->ControlOutputCount());
169 return graph()->NewNode(op, left_, right_, effect_, control_);
172 Node* TryBuildNumberBinop() {
173 NumberOperationHint hint;
174 if (GetBinaryNumberOperationHint(&hint)) {
175 const Operator* op = SpeculativeNumberOp(hint);
176 Node* node = BuildSpeculativeOperation(op);
182 Node* TryBuildNumberCompare() {
183 NumberOperationHint hint;
184 if (GetCompareNumberOperationHint(&hint)) {
185 const Operator* op = SpeculativeCompareOp(hint);
186 Node* node = BuildSpeculativeOperation(op);
192 JSGraph* jsgraph()
const {
return lowering_->jsgraph(); }
193 Isolate* isolate()
const {
return jsgraph()->isolate(); }
194 Graph* graph()
const {
return jsgraph()->graph(); }
199 return lowering_->feedback_vector();
212 JSTypeHintLowering::JSTypeHintLowering(
JSGraph* jsgraph,
215 : jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
217 Isolate* JSTypeHintLowering::isolate()
const {
return jsgraph()->isolate(); }
219 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
220 const Operator* op, Node* operand, Node* effect, Node* control,
221 FeedbackSlot slot)
const {
222 DCHECK(!slot.IsInvalid());
223 FeedbackNexus nexus(feedback_vector(), slot);
224 if (Node* node = TryBuildSoftDeopt(
225 nexus, effect, control,
226 DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
227 return LoweringResult::Exit(node);
231 switch (op->opcode()) {
232 case IrOpcode::kJSBitwiseNot: {
235 JSSpeculativeBinopBuilder b(
this, jsgraph()->javascript()->BitwiseXor(),
236 operand, jsgraph()->SmiConstant(-1), effect,
238 node = b.TryBuildNumberBinop();
241 case IrOpcode::kJSDecrement: {
244 JSSpeculativeBinopBuilder b(
this, jsgraph()->javascript()->Subtract(),
245 operand, jsgraph()->SmiConstant(1), effect,
247 node = b.TryBuildNumberBinop();
250 case IrOpcode::kJSIncrement: {
253 BinaryOperationHint hint = BinaryOperationHint::kAny;
254 JSSpeculativeBinopBuilder b(
this, jsgraph()->javascript()->Add(hint),
255 operand, jsgraph()->SmiConstant(1), effect,
257 node = b.TryBuildNumberBinop();
260 case IrOpcode::kJSNegate: {
263 JSSpeculativeBinopBuilder b(
this, jsgraph()->javascript()->Multiply(),
264 operand, jsgraph()->SmiConstant(-1), effect,
266 node = b.TryBuildNumberBinop();
274 if (node !=
nullptr) {
275 return LoweringResult::SideEffectFree(node, node, control);
277 return LoweringResult::NoChange();
281 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
282 const Operator* op, Node* left, Node* right, Node* effect, Node* control,
283 FeedbackSlot slot)
const {
284 switch (op->opcode()) {
285 case IrOpcode::kJSStrictEqual: {
286 DCHECK(!slot.IsInvalid());
287 FeedbackNexus nexus(feedback_vector(), slot);
288 if (Node* node = TryBuildSoftDeopt(
289 nexus, effect, control,
290 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
291 return LoweringResult::Exit(node);
297 case IrOpcode::kJSEqual:
298 case IrOpcode::kJSLessThan:
299 case IrOpcode::kJSGreaterThan:
300 case IrOpcode::kJSLessThanOrEqual:
301 case IrOpcode::kJSGreaterThanOrEqual: {
302 DCHECK(!slot.IsInvalid());
303 FeedbackNexus nexus(feedback_vector(), slot);
304 if (Node* node = TryBuildSoftDeopt(
305 nexus, effect, control,
306 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
307 return LoweringResult::Exit(node);
309 JSSpeculativeBinopBuilder b(
this, op, left, right, effect, control, slot);
310 if (Node* node = b.TryBuildNumberCompare()) {
311 return LoweringResult::SideEffectFree(node, node, control);
315 case IrOpcode::kJSInstanceOf: {
316 DCHECK(!slot.IsInvalid());
317 FeedbackNexus nexus(feedback_vector(), slot);
318 if (Node* node = TryBuildSoftDeopt(
319 nexus, effect, control,
320 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
321 return LoweringResult::Exit(node);
327 case IrOpcode::kJSBitwiseOr:
328 case IrOpcode::kJSBitwiseXor:
329 case IrOpcode::kJSBitwiseAnd:
330 case IrOpcode::kJSShiftLeft:
331 case IrOpcode::kJSShiftRight:
332 case IrOpcode::kJSShiftRightLogical:
333 case IrOpcode::kJSAdd:
334 case IrOpcode::kJSSubtract:
335 case IrOpcode::kJSMultiply:
336 case IrOpcode::kJSDivide:
337 case IrOpcode::kJSModulus: {
338 DCHECK(!slot.IsInvalid());
339 FeedbackNexus nexus(feedback_vector(), slot);
340 if (Node* node = TryBuildSoftDeopt(
341 nexus, effect, control,
342 DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
343 return LoweringResult::Exit(node);
345 JSSpeculativeBinopBuilder b(
this, op, left, right, effect, control, slot);
346 if (Node* node = b.TryBuildNumberBinop()) {
347 return LoweringResult::SideEffectFree(node, node, control);
351 case IrOpcode::kJSExponentiate: {
359 return LoweringResult::NoChange();
362 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
363 Node* receiver, Node* cache_array, Node* cache_type, Node* index,
364 Node* effect, Node* control, FeedbackSlot slot)
const {
365 DCHECK(!slot.IsInvalid());
366 FeedbackNexus nexus(feedback_vector(), slot);
367 if (Node* node = TryBuildSoftDeopt(
368 nexus, effect, control,
369 DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
370 return LoweringResult::Exit(node);
372 return LoweringResult::NoChange();
375 JSTypeHintLowering::LoweringResult
376 JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
378 FeedbackSlot slot)
const {
379 DCHECK(!slot.IsInvalid());
380 FeedbackNexus nexus(feedback_vector(), slot);
381 if (Node* node = TryBuildSoftDeopt(
382 nexus, effect, control,
383 DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
384 return LoweringResult::Exit(node);
386 return LoweringResult::NoChange();
389 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
390 Node* input, Node* effect, Node* control, FeedbackSlot slot)
const {
391 DCHECK(!slot.IsInvalid());
392 FeedbackNexus nexus(feedback_vector(), slot);
393 NumberOperationHint hint;
394 if (BinaryOperationHintToNumberOperationHint(
395 nexus.GetBinaryOperationFeedback(), &hint)) {
396 Node* node = jsgraph()->graph()->NewNode(
397 jsgraph()->simplified()->SpeculativeToNumber(hint, VectorSlotPair()),
398 input, effect, control);
399 return LoweringResult::SideEffectFree(node, node, control);
401 return LoweringResult::NoChange();
404 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
405 const Operator* op, Node*
const* args,
int arg_count, Node* effect,
406 Node* control, FeedbackSlot slot)
const {
407 DCHECK(op->opcode() == IrOpcode::kJSCall ||
408 op->opcode() == IrOpcode::kJSCallWithSpread);
409 DCHECK(!slot.IsInvalid());
410 FeedbackNexus nexus(feedback_vector(), slot);
411 if (Node* node = TryBuildSoftDeopt(
412 nexus, effect, control,
413 DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
414 return LoweringResult::Exit(node);
416 return LoweringResult::NoChange();
419 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
420 const Operator* op, Node*
const* args,
int arg_count, Node* effect,
421 Node* control, FeedbackSlot slot)
const {
422 DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
423 op->opcode() == IrOpcode::kJSConstructWithSpread);
424 DCHECK(!slot.IsInvalid());
425 FeedbackNexus nexus(feedback_vector(), slot);
426 if (Node* node = TryBuildSoftDeopt(
427 nexus, effect, control,
428 DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
429 return LoweringResult::Exit(node);
431 return LoweringResult::NoChange();
434 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
435 const Operator* op, Node* receiver, Node* effect, Node* control,
436 FeedbackSlot slot)
const {
437 DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
438 DCHECK(!slot.IsInvalid());
439 FeedbackNexus nexus(feedback_vector(), slot);
440 if (Node* node = TryBuildSoftDeopt(
441 nexus, effect, control,
442 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
443 return LoweringResult::Exit(node);
445 return LoweringResult::NoChange();
448 JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
449 const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
450 FeedbackSlot slot)
const {
451 DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
452 DCHECK(!slot.IsInvalid());
453 FeedbackNexus nexus(feedback_vector(), slot);
454 if (Node* node = TryBuildSoftDeopt(
455 nexus, effect, control,
456 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
457 return LoweringResult::Exit(node);
459 return LoweringResult::NoChange();
462 JSTypeHintLowering::LoweringResult
463 JSTypeHintLowering::ReduceStoreNamedOperation(
const Operator* op, Node* obj,
464 Node* val, Node* effect,
466 FeedbackSlot slot)
const {
467 DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
468 op->opcode() == IrOpcode::kJSStoreNamedOwn);
469 DCHECK(!slot.IsInvalid());
470 FeedbackNexus nexus(feedback_vector(), slot);
471 if (Node* node = TryBuildSoftDeopt(
472 nexus, effect, control,
473 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
474 return LoweringResult::Exit(node);
476 return LoweringResult::NoChange();
479 JSTypeHintLowering::LoweringResult
480 JSTypeHintLowering::ReduceStoreKeyedOperation(
const Operator* op, Node* obj,
481 Node* key, Node* val,
482 Node* effect, Node* control,
483 FeedbackSlot slot)
const {
484 DCHECK(op->opcode() == IrOpcode::kJSStoreProperty ||
485 op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
486 DCHECK(!slot.IsInvalid());
487 FeedbackNexus nexus(feedback_vector(), slot);
488 if (Node* node = TryBuildSoftDeopt(
489 nexus, effect, control,
490 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
491 return LoweringResult::Exit(node);
493 return LoweringResult::NoChange();
496 Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
498 DeoptimizeReason reason)
const {
499 if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
500 Node* deoptimize = jsgraph()->graph()->NewNode(
501 jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
503 jsgraph()->Dead(), effect, control);
504 Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
505 deoptimize->ReplaceInput(0, frame_state);