[turbofan] Introduce prediction for exception handlers.
This introduces a conservative prediction for each exception handler whether it will locally catch an exception or re-throw it to outside the code bondaries. It will allow for a more intuitive prediction of whether an exception is considered "caught" or "uncaught". R=bmeurer@chromium.org,yangguo@chromium.org BUG=chromium:492522 LOG=N Review URL: https://codereview.chromium.org/1158563008 Cr-Commit-Position: refs/heads/master@{#28681}
This commit is contained in:
parent
9079b99ad4
commit
d8b94f34cc
@ -1106,6 +1106,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -1276,6 +1276,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler != nullptr) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -335,9 +335,11 @@ class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
|
||||
ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control)
|
||||
: ControlScope(owner), control_(control) {
|
||||
builder()->try_nesting_level_++; // Increment nesting.
|
||||
builder()->try_catch_nesting_level_++;
|
||||
}
|
||||
~ControlScopeForCatch() {
|
||||
builder()->try_nesting_level_--; // Decrement nesting.
|
||||
builder()->try_catch_nesting_level_--;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -437,6 +439,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
||||
globals_(0, local_zone),
|
||||
execution_control_(nullptr),
|
||||
execution_context_(nullptr),
|
||||
try_catch_nesting_level_(0),
|
||||
try_nesting_level_(0),
|
||||
input_buffer_size_(0),
|
||||
input_buffer_(nullptr),
|
||||
@ -3563,17 +3566,22 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
|
||||
}
|
||||
// Add implicit exception continuation for throwing nodes.
|
||||
if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
|
||||
// Conservative prediction whether caught locally.
|
||||
IfExceptionHint hint = try_catch_nesting_level_ > 0
|
||||
? IfExceptionHint::kLocallyCaught
|
||||
: IfExceptionHint::kLocallyUncaught;
|
||||
// Copy the environment for the success continuation.
|
||||
Environment* success_env = environment()->CopyForConditional();
|
||||
|
||||
Node* on_exception = graph()->NewNode(common()->IfException(), result);
|
||||
const Operator* op = common()->IfException(hint);
|
||||
Node* on_exception = graph()->NewNode(op, result);
|
||||
environment_->UpdateControlDependency(on_exception);
|
||||
execution_control()->ThrowValue(on_exception);
|
||||
set_environment(success_env);
|
||||
}
|
||||
// Add implicit success continuation for throwing nodes.
|
||||
if (!result->op()->HasProperty(Operator::kNoThrow)) {
|
||||
Node* on_success = graph()->NewNode(common()->IfSuccess(), result);
|
||||
const Operator* op = common()->IfSuccess();
|
||||
Node* on_success = graph()->NewNode(op, result);
|
||||
environment_->UpdateControlDependency(on_success);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ class AstGraphBuilder : public AstVisitor {
|
||||
SetOncePointer<Node> function_context_;
|
||||
|
||||
// Tracks how many try-blocks are currently entered.
|
||||
int try_catch_nesting_level_;
|
||||
int try_nesting_level_;
|
||||
|
||||
// Temporary storage for building node input lists.
|
||||
|
@ -156,8 +156,12 @@ Handle<Code> CodeGenerator::GenerateCode() {
|
||||
HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())),
|
||||
TENURED));
|
||||
for (size_t i = 0; i < handlers_.size(); ++i) {
|
||||
int position = handlers_[i].handler->pos();
|
||||
HandlerTable::CatchPrediction prediction = handlers_[i].caught_locally
|
||||
? HandlerTable::CAUGHT
|
||||
: HandlerTable::UNCAUGHT;
|
||||
table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
|
||||
table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos());
|
||||
table->SetReturnHandler(static_cast<int>(i), position, prediction);
|
||||
}
|
||||
result->set_handler_table(*table);
|
||||
}
|
||||
@ -379,9 +383,9 @@ void CodeGenerator::RecordCallPosition(Instruction* instr) {
|
||||
|
||||
if (flags & CallDescriptor::kHasExceptionHandler) {
|
||||
InstructionOperandConverter i(this, instr);
|
||||
RpoNumber handler_rpo =
|
||||
i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
|
||||
handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()});
|
||||
bool caught = flags & CallDescriptor::kHasLocalCatchHandler;
|
||||
RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1);
|
||||
handlers_.push_back({caught, GetLabel(handler_rpo), masm()->pc_offset()});
|
||||
}
|
||||
|
||||
if (flags & CallDescriptor::kNeedsNopAfterCall) {
|
||||
|
@ -160,6 +160,7 @@ class CodeGenerator final : public GapResolver::Assembler {
|
||||
};
|
||||
|
||||
struct HandlerInfo {
|
||||
bool caught_locally;
|
||||
Label* handler;
|
||||
int pc_offset;
|
||||
};
|
||||
|
@ -36,6 +36,21 @@ BranchHint BranchHintOf(const Operator* const op) {
|
||||
}
|
||||
|
||||
|
||||
size_t hash_value(IfExceptionHint hint) { return static_cast<size_t>(hint); }
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, IfExceptionHint hint) {
|
||||
switch (hint) {
|
||||
case IfExceptionHint::kLocallyCaught:
|
||||
return os << "Caught";
|
||||
case IfExceptionHint::kLocallyUncaught:
|
||||
return os << "Uncaught";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
|
||||
return lhs.type() == rhs.type() && lhs.hint() == rhs.hint();
|
||||
}
|
||||
@ -105,7 +120,6 @@ std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) {
|
||||
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(IfException, Operator::kKontrol, 0, 0, 1, 1, 0, 1) \
|
||||
V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \
|
||||
V(Deoptimize, Operator::kNoThrow, 1, 1, 1, 0, 0, 1) \
|
||||
@ -210,6 +224,18 @@ struct CommonOperatorGlobalCache final {
|
||||
CACHED_OP_LIST(CACHED)
|
||||
#undef CACHED
|
||||
|
||||
template <IfExceptionHint kCaughtLocally>
|
||||
struct IfExceptionOperator final : public Operator1<IfExceptionHint> {
|
||||
IfExceptionOperator()
|
||||
: Operator1<IfExceptionHint>( // --
|
||||
IrOpcode::kIfException, Operator::kKontrol, // opcode
|
||||
"IfException", // name
|
||||
0, 0, 1, 1, 0, 1, // counts
|
||||
kCaughtLocally) {} // parameter
|
||||
};
|
||||
IfExceptionOperator<IfExceptionHint::kLocallyCaught> kIfExceptionCOperator;
|
||||
IfExceptionOperator<IfExceptionHint::kLocallyUncaught> kIfExceptionUOperator;
|
||||
|
||||
template <size_t kInputCount>
|
||||
struct EndOperator final : public Operator {
|
||||
EndOperator()
|
||||
@ -385,6 +411,18 @@ const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
|
||||
}
|
||||
|
||||
|
||||
const Operator* CommonOperatorBuilder::IfException(IfExceptionHint hint) {
|
||||
switch (hint) {
|
||||
case IfExceptionHint::kLocallyCaught:
|
||||
return &cache_.kIfExceptionCOperator;
|
||||
case IfExceptionHint::kLocallyUncaught:
|
||||
return &cache_.kIfExceptionUOperator;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) {
|
||||
DCHECK_GE(control_output_count, 3u); // Disallow trivial switches.
|
||||
return new (zone()) Operator( // --
|
||||
|
@ -34,6 +34,14 @@ std::ostream& operator<<(std::ostream&, BranchHint);
|
||||
BranchHint BranchHintOf(const Operator* const);
|
||||
|
||||
|
||||
// Prediction whether throw-site is surrounded by any local catch-scope.
|
||||
enum class IfExceptionHint { kLocallyUncaught, kLocallyCaught };
|
||||
|
||||
size_t hash_value(IfExceptionHint hint);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, IfExceptionHint);
|
||||
|
||||
|
||||
class SelectParameters final {
|
||||
public:
|
||||
explicit SelectParameters(MachineType type,
|
||||
@ -94,7 +102,7 @@ class CommonOperatorBuilder final : public ZoneObject {
|
||||
const Operator* IfTrue();
|
||||
const Operator* IfFalse();
|
||||
const Operator* IfSuccess();
|
||||
const Operator* IfException();
|
||||
const Operator* IfException(IfExceptionHint hint);
|
||||
const Operator* Switch(size_t control_output_count);
|
||||
const Operator* IfValue(int32_t value);
|
||||
const Operator* IfDefault();
|
||||
|
@ -843,6 +843,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -73,7 +73,8 @@ class CallDescriptor final : public ZoneObject {
|
||||
kPatchableCallSite = 1u << 1,
|
||||
kNeedsNopAfterCall = 1u << 2,
|
||||
kHasExceptionHandler = 1u << 3,
|
||||
kSupportsTailCalls = 1u << 4,
|
||||
kHasLocalCatchHandler = 1u << 4,
|
||||
kSupportsTailCalls = 1u << 5,
|
||||
kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
|
||||
};
|
||||
typedef base::Flags<Flag> Flags;
|
||||
|
@ -541,6 +541,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -690,6 +690,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -1461,6 +1461,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -1047,6 +1047,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
// Pass label of exception handler block.
|
||||
CallDescriptor::Flags flags = descriptor->flags();
|
||||
if (handler) {
|
||||
DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode());
|
||||
IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front());
|
||||
if (hint == IfExceptionHint::kLocallyCaught) {
|
||||
flags |= CallDescriptor::kHasLocalCatchHandler;
|
||||
}
|
||||
flags |= CallDescriptor::kHasExceptionHandler;
|
||||
buffer.instruction_args.push_back(g.Label(handler));
|
||||
}
|
||||
|
@ -983,7 +983,8 @@ int OptimizedFrame::LookupExceptionHandlerInTable(int* stack_slots) {
|
||||
HandlerTable* table = HandlerTable::cast(code->handler_table());
|
||||
int pc_offset = static_cast<int>(pc() - code->entry());
|
||||
*stack_slots = code->stack_slots();
|
||||
return table->LookupReturn(pc_offset);
|
||||
HandlerTable::CatchPrediction prediction; // TODO(yangguo): For debugger.
|
||||
return table->LookupReturn(pc_offset, &prediction);
|
||||
}
|
||||
|
||||
|
||||
|
@ -8638,11 +8638,14 @@ int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out) {
|
||||
|
||||
|
||||
// TODO(turbofan): Make sure table is sorted and use binary search.
|
||||
int HandlerTable::LookupReturn(int pc_offset) {
|
||||
int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction) {
|
||||
for (int i = 0; i < length(); i += kReturnEntrySize) {
|
||||
int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
|
||||
int handler_offset = Smi::cast(get(i + kReturnHandlerIndex))->value();
|
||||
if (pc_offset == return_offset) return handler_offset;
|
||||
int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
|
||||
if (pc_offset == return_offset) {
|
||||
*prediction = HandlerPredictionField::decode(handler_field);
|
||||
return HandlerOffsetField::decode(handler_field);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -11841,12 +11844,14 @@ void HandlerTable::HandlerTableRangePrint(std::ostream& os) {
|
||||
|
||||
|
||||
void HandlerTable::HandlerTableReturnPrint(std::ostream& os) {
|
||||
os << " off hdlr\n";
|
||||
os << " off hdlr (c)\n";
|
||||
for (int i = 0; i < length(); i += kReturnEntrySize) {
|
||||
int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
|
||||
int handler = Smi::cast(get(i + kReturnHandlerIndex))->value();
|
||||
int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
|
||||
int handler_offset = HandlerOffsetField::decode(handler_field);
|
||||
CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
|
||||
os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4)
|
||||
<< handler << "\n";
|
||||
<< handler_offset << " (" << prediction << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5159,6 +5159,11 @@ class DeoptimizationOutputData: public FixedArray {
|
||||
// [ return-address-offset , handler-offset ]
|
||||
class HandlerTable : public FixedArray {
|
||||
public:
|
||||
// Conservative prediction whether a given handler will locally catch an
|
||||
// exception or cause a re-throw to outside the code boundary. Since this is
|
||||
// undecidable it is merely an approximation (e.g. useful for debugger).
|
||||
enum CatchPrediction { UNCAUGHT, CAUGHT };
|
||||
|
||||
// Accessors for handler table based on ranges.
|
||||
void SetRangeStart(int index, int value) {
|
||||
set(index * kRangeEntrySize + kRangeStartIndex, Smi::FromInt(value));
|
||||
@ -5177,7 +5182,9 @@ class HandlerTable : public FixedArray {
|
||||
void SetReturnOffset(int index, int value) {
|
||||
set(index * kReturnEntrySize + kReturnOffsetIndex, Smi::FromInt(value));
|
||||
}
|
||||
void SetReturnHandler(int index, int value) {
|
||||
void SetReturnHandler(int index, int offset, CatchPrediction prediction) {
|
||||
int value = HandlerOffsetField::encode(offset) |
|
||||
HandlerPredictionField::encode(prediction);
|
||||
set(index * kReturnEntrySize + kReturnHandlerIndex, Smi::FromInt(value));
|
||||
}
|
||||
|
||||
@ -5185,7 +5192,7 @@ class HandlerTable : public FixedArray {
|
||||
int LookupRange(int pc_offset, int* stack_depth);
|
||||
|
||||
// Lookup handler in a table based on return addresses.
|
||||
int LookupReturn(int pc_offset);
|
||||
int LookupReturn(int pc_offset, CatchPrediction* prediction);
|
||||
|
||||
// Returns the required length of the underlying fixed array.
|
||||
static int LengthForRange(int entries) { return entries * kRangeEntrySize; }
|
||||
@ -5210,6 +5217,10 @@ class HandlerTable : public FixedArray {
|
||||
static const int kReturnOffsetIndex = 0;
|
||||
static const int kReturnHandlerIndex = 1;
|
||||
static const int kReturnEntrySize = 2;
|
||||
|
||||
// Encoding of the {handler} field.
|
||||
class HandlerPredictionField : public BitField<CatchPrediction, 0, 1> {};
|
||||
class HandlerOffsetField : public BitField<int, 1, 30> {};
|
||||
};
|
||||
|
||||
|
||||
|
@ -52,7 +52,6 @@ const SharedOperator kSharedOperators[] = {
|
||||
SHARED(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
|
||||
SHARED(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
|
||||
SHARED(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1),
|
||||
SHARED(IfException, Operator::kKontrol, 0, 0, 1, 1, 0, 1),
|
||||
SHARED(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1),
|
||||
SHARED(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1),
|
||||
SHARED(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1)
|
||||
@ -178,8 +177,8 @@ const int32_t kInt32Values[] = {
|
||||
2008792749, 2045320228, std::numeric_limits<int32_t>::max()};
|
||||
|
||||
|
||||
const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue,
|
||||
BranchHint::kFalse};
|
||||
const BranchHint kBranchHints[] = {BranchHint::kNone, BranchHint::kTrue,
|
||||
BranchHint::kFalse};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -201,7 +200,7 @@ TEST_F(CommonOperatorTest, End) {
|
||||
|
||||
|
||||
TEST_F(CommonOperatorTest, Branch) {
|
||||
TRACED_FOREACH(BranchHint, hint, kHints) {
|
||||
TRACED_FOREACH(BranchHint, hint, kBranchHints) {
|
||||
const Operator* const op = common()->Branch(hint);
|
||||
EXPECT_EQ(IrOpcode::kBranch, op->opcode());
|
||||
EXPECT_EQ(Operator::kKontrol, op->properties());
|
||||
@ -217,6 +216,24 @@ TEST_F(CommonOperatorTest, Branch) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CommonOperatorTest, IfException) {
|
||||
static const IfExceptionHint kIfExceptionHints[] = {
|
||||
IfExceptionHint::kLocallyCaught, IfExceptionHint::kLocallyUncaught};
|
||||
TRACED_FOREACH(IfExceptionHint, hint, kIfExceptionHints) {
|
||||
const Operator* const op = common()->IfException(hint);
|
||||
EXPECT_EQ(IrOpcode::kIfException, op->opcode());
|
||||
EXPECT_EQ(Operator::kKontrol, op->properties());
|
||||
EXPECT_EQ(0, op->ValueInputCount());
|
||||
EXPECT_EQ(0, op->EffectInputCount());
|
||||
EXPECT_EQ(1, op->ControlInputCount());
|
||||
EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
|
||||
EXPECT_EQ(1, op->ValueOutputCount());
|
||||
EXPECT_EQ(0, op->EffectOutputCount());
|
||||
EXPECT_EQ(1, op->ControlOutputCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CommonOperatorTest, Switch) {
|
||||
TRACED_FOREACH(size_t, cases, kCases) {
|
||||
const Operator* const op = common()->Switch(cases);
|
||||
@ -256,7 +273,7 @@ TEST_F(CommonOperatorTest, Select) {
|
||||
kMachInt32, kMachUint32, kMachInt64, kMachUint64,
|
||||
kMachFloat32, kMachFloat64, kMachAnyTagged};
|
||||
TRACED_FOREACH(MachineType, type, kTypes) {
|
||||
TRACED_FOREACH(BranchHint, hint, kHints) {
|
||||
TRACED_FOREACH(BranchHint, hint, kBranchHints) {
|
||||
const Operator* const op = common()->Select(type, hint);
|
||||
EXPECT_EQ(IrOpcode::kSelect, op->opcode());
|
||||
EXPECT_EQ(Operator::kPure, op->properties());
|
||||
|
@ -478,7 +478,8 @@ TEST_F(LoopPeelingTest, TwoExitLoopWithCall_nope) {
|
||||
|
||||
Node* call = graph()->NewNode(&kMockCall, b1.if_true);
|
||||
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
|
||||
Node* if_exception = graph()->NewNode(common()->IfException(), call);
|
||||
Node* if_exception = graph()->NewNode(
|
||||
common()->IfException(IfExceptionHint::kLocallyUncaught), call);
|
||||
|
||||
loop->ReplaceInput(1, if_success);
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), b1.if_false, if_exception);
|
||||
|
@ -104,8 +104,9 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
|
||||
TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
|
||||
Node* result[2];
|
||||
CommonOperatorBuilder common(zone());
|
||||
IfExceptionHint h = IfExceptionHint::kLocallyUncaught;
|
||||
Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false);
|
||||
Node* if_ex = Node::New(zone(), 2, common.IfException(), 1, &call, false);
|
||||
Node* if_ex = Node::New(zone(), 2, common.IfException(h), 1, &call, false);
|
||||
Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false);
|
||||
NodeProperties::CollectControlProjections(call, result, arraysize(result));
|
||||
EXPECT_EQ(if_ok, result[0]);
|
||||
|
@ -1059,10 +1059,12 @@ TARGET_TEST_F(SchedulerTest, CallException) {
|
||||
Node* p0 = graph()->NewNode(common()->Parameter(0), start);
|
||||
Node* c1 = graph()->NewNode(&kMockCall, start);
|
||||
Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1);
|
||||
Node* ex1 = graph()->NewNode(common()->IfException(), c1);
|
||||
Node* ex1 = graph()->NewNode(
|
||||
common()->IfException(IfExceptionHint::kLocallyUncaught), c1);
|
||||
Node* c2 = graph()->NewNode(&kMockCall, ok1);
|
||||
Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2);
|
||||
Node* ex2 = graph()->NewNode(common()->IfException(), c2);
|
||||
Node* ex2 = graph()->NewNode(
|
||||
common()->IfException(IfExceptionHint::kLocallyUncaught), c2);
|
||||
Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2);
|
||||
Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl);
|
||||
Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m);
|
||||
|
@ -59,7 +59,8 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) {
|
||||
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
|
||||
graph()->start(), graph()->start());
|
||||
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
|
||||
Node* if_exception = graph()->NewNode(common()->IfException(), call);
|
||||
Node* if_exception = graph()->NewNode(
|
||||
common()->IfException(IfExceptionHint::kLocallyUncaught), call);
|
||||
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
|
||||
Node* end = graph()->NewNode(common()->End(1), if_exception);
|
||||
graph()->SetEnd(end);
|
||||
@ -124,7 +125,8 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) {
|
||||
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
|
||||
graph()->start(), graph()->start());
|
||||
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
|
||||
Node* if_exception = graph()->NewNode(common()->IfException(), call);
|
||||
Node* if_exception = graph()->NewNode(
|
||||
common()->IfException(IfExceptionHint::kLocallyUncaught), call);
|
||||
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
|
||||
Node* end = graph()->NewNode(common()->End(1), if_exception);
|
||||
graph()->SetEnd(end);
|
||||
|
Loading…
Reference in New Issue
Block a user