v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-type-hint-lowering.cc
Go to the documentation of this file.
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
6
7#include "src/base/logging.h"
14
15namespace v8 {
16namespace internal {
17namespace compiler {
18
19namespace {
20
21bool BinaryOperationHintToNumberOperationHint(
22 BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
23 switch (binop_hint) {
26 return true;
29 return true;
32 return true;
34 *number_hint = NumberOperationHint::kNumber;
35 return true;
38 return true;
45 break;
46 }
47 return false;
48}
49
50bool BinaryOperationHintToBigIntOperationHint(
51 BinaryOperationHint binop_hint, BigIntOperationHint* bigint_hint) {
52 switch (binop_hint) {
62 return false;
64 *bigint_hint = BigIntOperationHint::kBigInt64;
65 return true;
67 *bigint_hint = BigIntOperationHint::kBigInt;
68 return true;
69 }
71}
72
73} // namespace
74
76 public:
78 const Operator* op, Node* left, Node* right,
79 Node* effect, Node* control, FeedbackSlot slot)
80 : lowering_(lowering),
81 op_(op),
82 left_(left),
83 right_(right),
84 effect_(effect),
85 control_(control),
86 slot_(slot) {}
87
89 return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
90 hint);
91 }
92
94 return BinaryOperationHintToBigIntOperationHint(GetBinaryOperationHint(),
95 hint);
96 }
97
125
148
150 switch (op_->opcode()) {
151 case IrOpcode::kJSAdd:
156 } else {
157 return simplified()->SpeculativeNumberAdd(hint);
158 }
159 case IrOpcode::kJSSubtract:
164 } else {
166 }
167 case IrOpcode::kJSMultiply:
169 case IrOpcode::kJSExponentiate:
170 return simplified()->SpeculativeNumberPow(hint);
171 case IrOpcode::kJSDivide:
172 return simplified()->SpeculativeNumberDivide(hint);
173 case IrOpcode::kJSModulus:
174 return simplified()->SpeculativeNumberModulus(hint);
175 case IrOpcode::kJSBitwiseAnd:
177 case IrOpcode::kJSBitwiseOr:
179 case IrOpcode::kJSBitwiseXor:
181 case IrOpcode::kJSShiftLeft:
183 case IrOpcode::kJSShiftRight:
185 case IrOpcode::kJSShiftRightLogical:
187 default:
188 break;
189 }
190 UNREACHABLE();
191 }
192
194 switch (op_->opcode()) {
195 case IrOpcode::kJSAdd:
196 return simplified()->SpeculativeBigIntAdd(hint);
197 case IrOpcode::kJSSubtract:
199 case IrOpcode::kJSMultiply:
201 case IrOpcode::kJSDivide:
202 return simplified()->SpeculativeBigIntDivide(hint);
203 case IrOpcode::kJSModulus:
204 return simplified()->SpeculativeBigIntModulus(hint);
205 case IrOpcode::kJSBitwiseAnd:
207 case IrOpcode::kJSBitwiseOr:
209 case IrOpcode::kJSBitwiseXor:
211 case IrOpcode::kJSShiftLeft:
213 case IrOpcode::kJSShiftRight:
215 default:
216 break;
217 }
218 UNREACHABLE();
219 }
220
222 switch (op_->opcode()) {
223 case IrOpcode::kJSEqual:
224 return simplified()->SpeculativeNumberEqual(hint);
225 case IrOpcode::kJSLessThan:
227 case IrOpcode::kJSGreaterThan:
228 std::swap(left_, right_); // a > b => b < a
230 case IrOpcode::kJSLessThanOrEqual:
232 case IrOpcode::kJSGreaterThanOrEqual:
233 std::swap(left_, right_); // a >= b => b <= a
235 default:
236 break;
237 }
238 UNREACHABLE();
239 }
240
242 switch (op_->opcode()) {
243 case IrOpcode::kJSEqual:
244 return simplified()->SpeculativeBigIntEqual(hint);
245 case IrOpcode::kJSLessThan:
247 case IrOpcode::kJSGreaterThan:
248 std::swap(left_, right_);
250 case IrOpcode::kJSLessThanOrEqual:
252 case IrOpcode::kJSGreaterThanOrEqual:
253 std::swap(left_, right_);
255 default:
256 break;
257 }
258 UNREACHABLE();
259 }
260
271
274 if (GetBinaryNumberOperationHint(&hint)) {
275 const Operator* op = SpeculativeNumberOp(hint);
277 return node;
278 }
279 return nullptr;
280 }
281
284 if (GetBinaryBigIntOperationHint(&hint)) {
285 const Operator* op = SpeculativeBigIntOp(hint);
287 return node;
288 }
289 return nullptr;
290 }
291
295 const Operator* op = SpeculativeNumberCompareOp(hint);
297 return node;
298 }
299 return nullptr;
300 }
301
305 const Operator* op = SpeculativeBigIntCompareOp(hint);
307 return node;
308 }
309 return nullptr;
310 }
311
312 JSGraph* jsgraph() const { return lowering_->jsgraph(); }
313 Isolate* isolate() const { return jsgraph()->isolate(); }
314 TFGraph* graph() const { return jsgraph()->graph(); }
318
319 private:
323
327
329 Operator const* const op_;
332 Node* const effect_;
335};
336
338 FeedbackVectorRef feedback_vector,
339 Flags flags)
340 : broker_(broker),
341 jsgraph_(jsgraph),
342 flags_(flags),
343 feedback_vector_(feedback_vector) {}
344
346
352
358
360 const Operator* op, Node* operand, Node* effect, Node* control,
361 FeedbackSlot slot) const {
363 slot, effect, control,
364 DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
365 return LoweringResult::Exit(node);
366 }
367
368 // Note: Unary and binary operations collect the same kind of feedback.
369 FeedbackSource feedback(feedback_vector(), slot);
370
371 Node* node;
372 Node* check = nullptr;
373 switch (op->opcode()) {
374 case IrOpcode::kJSBitwiseNot: {
375 // Lower to a speculative xor with -1 if we have some kind of Number
376 // feedback.
378 this, jsgraph()->javascript()->BitwiseXor(feedback), operand,
379 jsgraph()->SmiConstant(-1), effect, control, slot);
380 node = b.TryBuildNumberBinop();
381 break;
382 }
383 case IrOpcode::kJSDecrement: {
384 // Lower to a speculative subtraction of 1 if we have some kind of Number
385 // feedback.
387 this, jsgraph()->javascript()->Subtract(feedback), operand,
388 jsgraph()->SmiConstant(1), effect, control, slot);
389 node = b.TryBuildNumberBinop();
390 break;
391 }
392 case IrOpcode::kJSIncrement: {
393 // Lower to a speculative addition of 1 if we have some kind of Number
394 // feedback.
395 JSSpeculativeBinopBuilder b(this, jsgraph()->javascript()->Add(feedback),
396 operand, jsgraph()->SmiConstant(1), effect,
397 control, slot);
398 node = b.TryBuildNumberBinop();
399 break;
400 }
401 case IrOpcode::kJSNegate: {
402 // Lower to a speculative multiplication with -1 if we have some kind of
403 // Number feedback.
405 this, jsgraph()->javascript()->Multiply(feedback), operand,
406 jsgraph()->SmiConstant(-1), effect, control, slot);
407 node = b.TryBuildNumberBinop();
408 if (!node) {
409 if (jsgraph()->machine()->Is64()) {
413 node = jsgraph()->graph()->NewNode(op, operand, effect, control);
414 }
415 }
416 }
417 break;
418 }
419 case IrOpcode::kTypeOf: {
421 switch (hint) {
423 check = jsgraph()->graph()->NewNode(
424 jsgraph()->simplified()->CheckNumber(FeedbackSource()), operand,
425 effect, control);
426 node = jsgraph()->ConstantNoHole(broker()->number_string(), broker());
427 break;
429 check = jsgraph()->graph()->NewNode(
430 jsgraph()->simplified()->CheckString(FeedbackSource()), operand,
431 effect, control);
432 node = jsgraph()->ConstantNoHole(broker()->string_string(), broker());
433 break;
436 jsgraph()->simplified()->ObjectIsDetectableCallable(), operand);
437 check = jsgraph()->graph()->NewNode(
438 jsgraph()->simplified()->CheckIf(
439 DeoptimizeReason::kNotDetectableReceiver, FeedbackSource()),
440 condition, effect, control);
441 node =
442 jsgraph()->ConstantNoHole(broker()->function_string(), broker());
443 break;
444 }
445 default:
446 node = nullptr;
447 break;
448 }
449 break;
450 }
451 default:
452 UNREACHABLE();
453 }
454
455 if (node != nullptr) {
456 return LoweringResult::SideEffectFree(node, check ? check : node, control);
457 } else {
459 }
460}
461
463 const Operator* op, Node* left, Node* right, Node* effect, Node* control,
464 FeedbackSlot slot) const {
465 switch (op->opcode()) {
466 case IrOpcode::kJSStrictEqual: {
468 slot, effect, control,
469 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
470 return LoweringResult::Exit(node);
471 }
472 // TODO(turbofan): Should we generally support early lowering of
473 // JSStrictEqual operators here?
474 break;
475 }
476 case IrOpcode::kJSEqual:
477 case IrOpcode::kJSLessThan:
478 case IrOpcode::kJSGreaterThan:
479 case IrOpcode::kJSLessThanOrEqual:
480 case IrOpcode::kJSGreaterThanOrEqual: {
482 slot, effect, control,
483 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
484 return LoweringResult::Exit(node);
485 }
486 JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
487 if (Node* node = b.TryBuildNumberCompare()) {
488 return LoweringResult::SideEffectFree(node, node, control);
489 }
490 if (Node* node = b.TryBuildBigIntCompare()) {
491 return LoweringResult::SideEffectFree(node, node, control);
492 }
493 break;
494 }
495 case IrOpcode::kJSInstanceOf: {
497 slot, effect, control,
498 DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
499 return LoweringResult::Exit(node);
500 }
501 // TODO(turbofan): Should we generally support early lowering of
502 // JSInstanceOf operators here?
503 break;
504 }
505 case IrOpcode::kJSBitwiseOr:
506 case IrOpcode::kJSBitwiseXor:
507 case IrOpcode::kJSBitwiseAnd:
508 case IrOpcode::kJSShiftLeft:
509 case IrOpcode::kJSShiftRight:
510 case IrOpcode::kJSShiftRightLogical:
511 case IrOpcode::kJSAdd:
512 case IrOpcode::kJSSubtract:
513 case IrOpcode::kJSMultiply:
514 case IrOpcode::kJSDivide:
515 case IrOpcode::kJSModulus:
516 case IrOpcode::kJSExponentiate: {
518 slot, effect, control,
519 DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
520 return LoweringResult::Exit(node);
521 }
522 JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
523 if (Node* node = b.TryBuildNumberBinop()) {
524 return LoweringResult::SideEffectFree(node, node, control);
525 }
526 if (op->opcode() != IrOpcode::kJSShiftRightLogical &&
527 op->opcode() != IrOpcode::kJSExponentiate) {
528 if (Node* node = b.TryBuildBigIntBinop()) {
529 return LoweringResult::SideEffectFree(node, node, control);
530 }
531 }
532 break;
533 }
534 default:
535 UNREACHABLE();
536 }
538}
539
541 Node* receiver, Node* cache_array, Node* cache_type, Node* index,
542 Node* effect, Node* control, FeedbackSlot slot) const {
544 slot, effect, control,
545 DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
546 return LoweringResult::Exit(node);
547 }
549}
550
553 Node* control,
554 FeedbackSlot slot) const {
556 slot, effect, control,
557 DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
558 return LoweringResult::Exit(node);
559 }
561}
562
564 Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
565 DCHECK(!slot.IsInvalid());
567 if (BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(slot),
568 &hint)) {
569 Node* node = jsgraph()->graph()->NewNode(
570 jsgraph()->simplified()->SpeculativeToNumber(hint, FeedbackSource()),
571 input, effect, control);
572 return LoweringResult::SideEffectFree(node, node, control);
573 }
575}
576
578 const Operator* op, Node* const* args, int arg_count, Node* effect,
579 Node* control, FeedbackSlot slot) const {
580 DCHECK(op->opcode() == IrOpcode::kJSCall ||
581 op->opcode() == IrOpcode::kJSCallWithSpread);
583 slot, effect, control,
584 DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
585 return LoweringResult::Exit(node);
586 }
588}
589
591 const Operator* op, Node* const* args, int arg_count, Node* effect,
592 Node* control, FeedbackSlot slot) const {
593 DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
594 op->opcode() == IrOpcode::kJSConstructWithSpread ||
595 op->opcode() == IrOpcode::kJSConstructForwardAllArgs);
597 slot, effect, control,
598 DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
599 return LoweringResult::Exit(node);
600 }
602}
603
606 Node* receiver, Node* effect,
607 Node* control,
608 FeedbackSlot load_slot,
609 FeedbackSlot call_slot) const {
610 DCHECK_EQ(IrOpcode::kJSGetIterator, op->opcode());
612 load_slot, effect, control,
613 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
614 return LoweringResult::Exit(node);
615 }
617}
618
620 const Operator* op, Node* effect, Node* control, FeedbackSlot slot) const {
621 DCHECK(op->opcode() == IrOpcode::kJSLoadNamed ||
622 op->opcode() == IrOpcode::kJSLoadNamedFromSuper);
624 slot, effect, control,
625 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
626 return LoweringResult::Exit(node);
627 }
629}
630
632 const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
633 FeedbackSlot slot) const {
634 DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
636 slot, effect, control,
637 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
638 return LoweringResult::Exit(node);
639 }
641}
642
645 Node* val, Node* effect,
646 Node* control,
647 FeedbackSlot slot) const {
648 DCHECK(op->opcode() == IrOpcode::kJSSetNamedProperty ||
649 op->opcode() == IrOpcode::kJSDefineNamedOwnProperty);
651 slot, effect, control,
652 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
653 return LoweringResult::Exit(node);
654 }
656}
657
660 Node* key, Node* val,
661 Node* effect, Node* control,
662 FeedbackSlot slot) const {
663 DCHECK(op->opcode() == IrOpcode::kJSSetKeyedProperty ||
664 op->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
665 op->opcode() == IrOpcode::kJSDefineKeyedOwnPropertyInLiteral ||
666 op->opcode() == IrOpcode::kJSDefineKeyedOwnProperty);
668 slot, effect, control,
669 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
670 return LoweringResult::Exit(node);
671 }
673}
674
676 FeedbackSlot slot, Node* effect, Node* control,
677 DeoptimizeReason reason) const {
678 if (!(flags() & kBailoutOnUninitialized)) return nullptr;
679
681 if (!broker()->FeedbackIsInsufficient(source)) return nullptr;
682
683 Node* deoptimize = jsgraph()->graph()->NewNode(
684 jsgraph()->common()->Deoptimize(reason, FeedbackSource()),
685 jsgraph()->Dead(), effect, control);
686 Node* frame_state =
687 NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
688 deoptimize->ReplaceInput(0, frame_state);
689 return deoptimize;
690}
691
692} // namespace compiler
693} // namespace internal
694} // namespace v8
JSGraph * jsgraph
SimplifiedOperatorBuilder * simplified
bool IsInvalid() const
Definition utils.h:649
JSOperatorBuilder * javascript() const
Definition js-graph.h:104
SimplifiedOperatorBuilder * simplified() const
Definition js-graph.h:105
Isolate * isolate() const
Definition js-graph.h:106
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:51
BinaryOperationHint GetFeedbackForBinaryOperation(FeedbackSource const &source)
TypeOfFeedback::Result GetFeedbackForTypeOf(FeedbackSource const &source)
CompareOperationHint GetFeedbackForCompareOperation(FeedbackSource const &source)
bool GetBinaryBigIntOperationHint(BigIntOperationHint *hint)
bool GetCompareNumberOperationHint(NumberOperationHint *hint)
bool GetBinaryNumberOperationHint(NumberOperationHint *hint)
const Operator * SpeculativeNumberCompareOp(NumberOperationHint hint)
JSSpeculativeBinopBuilder(const JSTypeHintLowering *lowering, const Operator *op, Node *left, Node *right, Node *effect, Node *control, FeedbackSlot slot)
const Operator * SpeculativeNumberOp(NumberOperationHint hint)
bool GetCompareBigIntOperationHint(BigIntOperationHint *hint)
const Operator * SpeculativeBigIntCompareOp(BigIntOperationHint hint)
const Operator * SpeculativeBigIntOp(BigIntOperationHint hint)
static LoweringResult SideEffectFree(Node *value, Node *effect, Node *control)
CompareOperationHint GetCompareOperationHint(FeedbackSlot slot) const
BinaryOperationHint GetBinaryOperationHint(FeedbackSlot slot) const
LoweringResult ReduceLoadNamedOperation(const Operator *op, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceConstructOperation(const Operator *op, Node *const *args, int arg_count, Node *effect, Node *control, FeedbackSlot slot) const
Node * BuildDeoptIfFeedbackIsInsufficient(FeedbackSlot slot, Node *effect, Node *control, DeoptimizeReason reson) const
LoweringResult ReduceForInPrepareOperation(Node *enumerator, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceLoadKeyedOperation(const Operator *op, Node *obj, Node *key, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceForInNextOperation(Node *receiver, Node *cache_array, Node *cache_type, Node *index, Node *effect, Node *control, FeedbackSlot slot) const
JSTypeHintLowering(JSHeapBroker *broker, JSGraph *jsgraph, FeedbackVectorRef feedback_vector, Flags flags)
LoweringResult ReduceToNumberOperation(Node *value, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceBinaryOperation(const Operator *op, Node *left, Node *right, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceGetIteratorOperation(const Operator *op, Node *obj, Node *effect, Node *control, FeedbackSlot load_slot, FeedbackSlot call_slot) const
LoweringResult ReduceUnaryOperation(const Operator *op, Node *operand, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceStoreKeyedOperation(const Operator *op, Node *obj, Node *key, Node *val, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceStoreNamedOperation(const Operator *op, Node *obj, Node *val, Node *effect, Node *control, FeedbackSlot slot) const
LoweringResult ReduceCallOperation(const Operator *op, Node *const *args, int arg_count, Node *effect, Node *control, FeedbackSlot slot) const
CommonOperatorBuilder * common() const
static Node * FindFrameStateBefore(Node *node, Node *unreachable_sentinel)
void ReplaceInput(int index, Node *new_to)
Definition node.h:76
static bool HasContextInput(const Operator *op)
static bool HasFrameStateInput(const Operator *op)
constexpr Opcode opcode() const
Definition operator.h:75
const Operator * SpeculativeSmallIntegerSubtract(NumberOperationHint hint)
const Operator * SpeculativeAdditiveSafeIntegerAdd(NumberOperationHint hint)
const Operator * SpeculativeNumberLessThanOrEqual(NumberOperationHint hint)
const Operator * SpeculativeBigIntLessThanOrEqual(BigIntOperationHint hint)
const Operator * SpeculativeBigIntLessThan(BigIntOperationHint hint)
const Operator * SpeculativeBigIntModulus(BigIntOperationHint hint)
const Operator * SpeculativeNumberLessThan(NumberOperationHint hint)
const Operator * SpeculativeBigIntBitwiseXor(BigIntOperationHint hint)
const Operator * SpeculativeNumberSubtract(NumberOperationHint hint)
const Operator * SpeculativeBigIntAdd(BigIntOperationHint hint)
const Operator * SpeculativeBigIntSubtract(BigIntOperationHint hint)
const Operator * SpeculativeBigIntEqual(BigIntOperationHint hint)
const Operator * SpeculativeBigIntBitwiseOr(BigIntOperationHint hint)
const Operator * SpeculativeNumberAdd(NumberOperationHint hint)
const Operator * SpeculativeAdditiveSafeIntegerSubtract(NumberOperationHint hint)
const Operator * SpeculativeNumberModulus(NumberOperationHint hint)
const Operator * SpeculativeBigIntShiftRight(BigIntOperationHint hint)
const Operator * SpeculativeNumberBitwiseAnd(NumberOperationHint hint)
const Operator * SpeculativeNumberShiftLeft(NumberOperationHint hint)
const Operator * SpeculativeNumberShiftRightLogical(NumberOperationHint hint)
const Operator * SpeculativeNumberMultiply(NumberOperationHint hint)
const Operator * SpeculativeNumberShiftRight(NumberOperationHint hint)
const Operator * SpeculativeSmallIntegerAdd(NumberOperationHint hint)
const Operator * SpeculativeBigIntBitwiseAnd(BigIntOperationHint hint)
const Operator * SpeculativeNumberBitwiseXor(NumberOperationHint hint)
const Operator * SpeculativeBigIntNegate(BigIntOperationHint hint)
const Operator * SpeculativeNumberDivide(NumberOperationHint hint)
const Operator * SpeculativeBigIntDivide(BigIntOperationHint hint)
const Operator * SpeculativeNumberBitwiseOr(NumberOperationHint hint)
const Operator * SpeculativeBigIntMultiply(BigIntOperationHint hint)
const Operator * SpeculativeNumberPow(NumberOperationHint hint)
const Operator * SpeculativeBigIntShiftLeft(BigIntOperationHint hint)
const Operator * SpeculativeNumberEqual(NumberOperationHint hint)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
JSRegExp::Flags flags_
JSHeapBroker *const broker_
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
JSHeapBroker * broker
TNode< Object > receiver
Node * node
InstructionOperand source
constexpr bool Is64()
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485