Commit a4743bae authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Remove IfExceptionHint from exception projections.

This completely removes translation of exception handler predictions
from the graph IR. We now rely on the runtime using deoptimization
infomation via {FrameSummary} for predictions in optimized code.

R=bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/2207533002
Cr-Commit-Position: refs/heads/master@{#38250}
parent 7e511904
......@@ -361,15 +361,11 @@ class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
public:
ControlScopeForCatch(AstGraphBuilder* owner, TryCatchStatement* stmt,
TryCatchBuilder* control)
: ControlScope(owner),
control_(control),
outer_prediction_(owner->try_catch_prediction_) {
: ControlScope(owner), control_(control) {
builder()->try_nesting_level_++; // Increment nesting.
builder()->try_catch_prediction_ = stmt->catch_prediction();
}
~ControlScopeForCatch() {
builder()->try_nesting_level_--; // Decrement nesting.
builder()->try_catch_prediction_ = outer_prediction_;
}
protected:
......@@ -388,7 +384,6 @@ class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
private:
TryCatchBuilder* control_;
HandlerTable::CatchPrediction outer_prediction_;
};
......@@ -397,16 +392,11 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
public:
ControlScopeForFinally(AstGraphBuilder* owner, TryFinallyStatement* stmt,
DeferredCommands* commands, TryFinallyBuilder* control)
: ControlScope(owner),
commands_(commands),
control_(control),
outer_prediction_(owner->try_catch_prediction_) {
: ControlScope(owner), commands_(commands), control_(control) {
builder()->try_nesting_level_++; // Increment nesting.
builder()->try_catch_prediction_ = stmt->catch_prediction();
}
~ControlScopeForFinally() {
builder()->try_nesting_level_--; // Decrement nesting.
builder()->try_catch_prediction_ = outer_prediction_;
}
protected:
......@@ -419,7 +409,6 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
private:
DeferredCommands* commands_;
TryFinallyBuilder* control_;
HandlerTable::CatchPrediction outer_prediction_;
};
......@@ -489,7 +478,6 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
execution_control_(nullptr),
execution_context_(nullptr),
try_nesting_level_(0),
try_catch_prediction_(HandlerTable::UNCAUGHT),
input_buffer_size_(0),
input_buffer_(nullptr),
exit_controls_(local_zone),
......@@ -4157,12 +4145,9 @@ 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 =
ExceptionHintFromCatchPrediction(try_catch_prediction_);
// Copy the environment for the success continuation.
Environment* success_env = environment()->CopyForConditional();
const Operator* op = common()->IfException(hint);
const Operator* op = common()->IfException();
Node* effect = environment()->GetEffectDependency();
Node* on_exception = graph()->NewNode(op, effect, result);
environment_->UpdateControlDependency(on_exception);
......
......@@ -101,9 +101,6 @@ class AstGraphBuilder : public AstVisitor<AstGraphBuilder> {
// Tracks how many try-blocks are currently entered.
int try_nesting_level_;
// Tracks the prediction of the innermost try-block.
HandlerTable::CatchPrediction try_catch_prediction_;
// Temporary storage for building node input lists.
int input_buffer_size_;
Node** input_buffer_;
......
......@@ -1670,10 +1670,8 @@ void BytecodeGraphBuilder::EnterAndExitExceptionHandlers(int current_offset) {
int next_end = table->GetRangeEnd(current_exception_handler_);
int next_handler = table->GetRangeHandler(current_exception_handler_);
int context_register = table->GetRangeData(current_exception_handler_);
CatchPrediction pred =
table->GetRangePrediction(current_exception_handler_);
exception_handlers_.push(
{next_start, next_end, next_handler, context_register, pred});
{next_start, next_end, next_handler, context_register});
current_exception_handler_++;
}
}
......@@ -1731,11 +1729,9 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) {
int handler_offset = exception_handlers_.top().handler_offset_;
int context_index = exception_handlers_.top().context_register_;
CatchPrediction prediction = exception_handlers_.top().pred_;
interpreter::Register context_register(context_index);
IfExceptionHint hint = ExceptionHintFromCatchPrediction(prediction);
Environment* success_env = environment()->CopyForConditional();
const Operator* op = common()->IfException(hint);
const Operator* op = common()->IfException();
Node* effect = environment()->GetEffectDependency();
Node* on_exception = graph()->NewNode(op, effect, result);
Node* context = environment()->LookupRegister(context_register);
......
......@@ -155,9 +155,6 @@ class BytecodeGraphBuilder {
// new nodes.
static const int kInputBufferSizeIncrement = 64;
// The catch prediction from the handler table is reused.
typedef HandlerTable::CatchPrediction CatchPrediction;
// An abstract representation for an exception handler that is being
// entered and exited while the graph builder is iterating over the
// underlying bytecode. The exception handlers within the bytecode are
......@@ -167,7 +164,6 @@ class BytecodeGraphBuilder {
int end_offset_; // End offset of the handled area in the bytecode.
int handler_offset_; // Handler entry offset within the bytecode.
int context_register_; // Index of register holding handler context.
CatchPrediction pred_; // Prediction of whether handler is catching.
};
// Field accessors
......
......@@ -229,9 +229,9 @@ Handle<Code> CodeGenerator::GenerateCode() {
TENURED));
for (size_t i = 0; i < handlers_.size(); ++i) {
int position = handlers_[i].handler->pos();
HandlerTable::CatchPrediction prediction = HandlerTable::UNCAUGHT;
table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
table->SetReturnHandler(static_cast<int>(i), position,
handlers_[i].catch_prediction);
table->SetReturnHandler(static_cast<int>(i), position, prediction);
}
result->set_handler_table(*table);
}
......@@ -603,15 +603,8 @@ void CodeGenerator::RecordCallPosition(Instruction* instr) {
if (flags & CallDescriptor::kHasExceptionHandler) {
InstructionOperandConverter i(this, instr);
HandlerTable::CatchPrediction prediction = HandlerTable::UNCAUGHT;
if (flags & CallDescriptor::kHasLocalCatchHandler) {
prediction = HandlerTable::CAUGHT;
} else if (flags & CallDescriptor::kHasLocalCatchHandlerForPromiseReject) {
prediction = HandlerTable::PROMISE;
}
RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1);
handlers_.push_back(
{prediction, GetLabel(handler_rpo), masm()->pc_offset()});
handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()});
}
if (needs_frame_state) {
......
......@@ -250,7 +250,6 @@ class CodeGenerator final : public GapResolver::Assembler {
};
struct HandlerInfo {
HandlerTable::CatchPrediction catch_prediction;
Label* handler;
int pc_offset;
};
......
......@@ -75,36 +75,6 @@ DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const op) {
return OpParameter<DeoptimizeParameters>(op);
}
IfExceptionHint ExceptionHintFromCatchPrediction(
HandlerTable::CatchPrediction prediction) {
switch (prediction) {
case HandlerTable::UNCAUGHT:
return IfExceptionHint::kLocallyUncaught;
case HandlerTable::CAUGHT:
return IfExceptionHint::kLocallyCaught;
case HandlerTable::PROMISE:
return IfExceptionHint::kLocallyCaughtForPromiseReject;
}
UNREACHABLE();
return IfExceptionHint::kLocallyUncaught;
}
size_t hash_value(IfExceptionHint hint) { return static_cast<size_t>(hint); }
std::ostream& operator<<(std::ostream& os, IfExceptionHint hint) {
switch (hint) {
case IfExceptionHint::kLocallyUncaught:
return os << "Uncaught";
case IfExceptionHint::kLocallyCaught:
return os << "Caught";
case IfExceptionHint::kLocallyCaughtForPromiseReject:
return os << "CaughtForPromiseReject";
}
UNREACHABLE();
return os;
}
bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
return lhs.representation() == rhs.representation() &&
......@@ -240,6 +210,7 @@ std::ostream& operator<<(std::ostream& os,
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, 1, 1, 1, 1, 1) \
V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \
V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
......@@ -358,20 +329,6 @@ 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, 1, 1, 1, 1, 1, // counts
kCaughtLocally) {} // parameter
};
IfExceptionOperator<IfExceptionHint::kLocallyUncaught> kIfExceptionUOperator;
IfExceptionOperator<IfExceptionHint::kLocallyCaught> kIfExceptionCOperator;
IfExceptionOperator<IfExceptionHint::kLocallyCaughtForPromiseReject>
kIfExceptionPOperator;
template <size_t kInputCount>
struct EndOperator final : public Operator {
EndOperator()
......@@ -638,19 +595,6 @@ const Operator* CommonOperatorBuilder::DeoptimizeUnless(
reason); // parameter
}
const Operator* CommonOperatorBuilder::IfException(IfExceptionHint hint) {
switch (hint) {
case IfExceptionHint::kLocallyUncaught:
return &cache_.kIfExceptionUOperator;
case IfExceptionHint::kLocallyCaught:
return &cache_.kIfExceptionCOperator;
case IfExceptionHint::kLocallyCaughtForPromiseReject:
return &cache_.kIfExceptionPOperator;
}
UNREACHABLE();
return nullptr;
}
const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) {
return new (zone()) Operator( // --
......
......@@ -76,20 +76,6 @@ std::ostream& operator<<(std::ostream&, DeoptimizeParameters p);
DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const);
// Prediction whether throw-site is surrounded by any local catch-scope.
enum class IfExceptionHint {
kLocallyUncaught,
kLocallyCaught,
kLocallyCaughtForPromiseReject
};
IfExceptionHint ExceptionHintFromCatchPrediction(
HandlerTable::CatchPrediction prediction);
size_t hash_value(IfExceptionHint hint);
std::ostream& operator<<(std::ostream&, IfExceptionHint);
class SelectParameters final {
public:
......@@ -195,7 +181,7 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* IfTrue();
const Operator* IfFalse();
const Operator* IfSuccess();
const Operator* IfException(IfExceptionHint hint);
const Operator* IfException();
const Operator* Switch(size_t control_output_count);
const Operator* IfValue(int32_t value);
const Operator* IfDefault();
......
......@@ -1779,12 +1779,6 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
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;
} else if (hint == IfExceptionHint::kLocallyCaughtForPromiseReject) {
flags |= CallDescriptor::kHasLocalCatchHandlerForPromiseReject;
}
flags |= CallDescriptor::kHasExceptionHandler;
buffer.instruction_args.push_back(g.Label(handler));
}
......
......@@ -338,7 +338,6 @@ class JSBinopReduction final {
// Find {IfSuccess} and {IfException} continuations of the operation.
NodeProperties::CollectControlProjections(node_, projections, 2);
IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]);
Node* if_exception = projections[1];
Node* if_success = projections[0];
......@@ -353,9 +352,9 @@ class JSBinopReduction final {
graph()->NewNode(javascript()->ToNumber(), right(), context(),
right_state, left_conv, left_success);
Node* left_exception =
graph()->NewNode(common()->IfException(hint), left_conv, left_conv);
graph()->NewNode(common()->IfException(), left_conv, left_conv);
Node* right_exception =
graph()->NewNode(common()->IfException(hint), right_conv, right_conv);
graph()->NewNode(common()->IfException(), right_conv, right_conv);
NodeProperties::ReplaceControlInput(if_success, right_conv);
update_effect(right_conv);
......
......@@ -174,19 +174,17 @@ class CallDescriptor final : public ZoneObject {
kNoFlags = 0u,
kNeedsFrameState = 1u << 0,
kHasExceptionHandler = 1u << 1,
kHasLocalCatchHandler = 1u << 2,
kHasLocalCatchHandlerForPromiseReject = 1u << 3,
kSupportsTailCalls = 1u << 4,
kCanUseRoots = 1u << 5,
kSupportsTailCalls = 1u << 2,
kCanUseRoots = 1u << 3,
// (arm64 only) native stack should be used for arguments.
kUseNativeStack = 1u << 6,
kUseNativeStack = 1u << 4,
// (arm64 only) call instruction has to restore JSSP or CSP.
kRestoreJSSP = 1u << 7,
kRestoreCSP = 1u << 8,
kRestoreJSSP = 1u << 5,
kRestoreCSP = 1u << 6,
// Causes the code generator to initialize the root register.
kInitializeRootRegister = 1u << 9,
kInitializeRootRegister = 1u << 7,
// Does not ever try to allocate space on our heap.
kNoAllocate = 1u << 10
kNoAllocate = 1u << 8
};
typedef base::Flags<Flag> Flags;
......
......@@ -38,7 +38,6 @@ std::ostream& operator<<(std::ostream& os, const SharedOperator& fop) {
return os << IrOpcode::Mnemonic(fop.opcode);
}
const SharedOperator kSharedOperators[] = {
#define SHARED(Name, properties, value_input_count, effect_input_count, \
control_input_count, value_output_count, effect_output_count, \
......@@ -52,6 +51,7 @@ 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, 1, 1, 1, 1, 1),
SHARED(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1),
SHARED(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1)
#undef SHARED
......@@ -220,24 +220,6 @@ 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(1, op->EffectInputCount());
EXPECT_EQ(1, op->ControlInputCount());
EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(1, op->ValueOutputCount());
EXPECT_EQ(1, op->EffectOutputCount());
EXPECT_EQ(1, op->ControlOutputCount());
}
}
TEST_F(CommonOperatorTest, Switch) {
TRACED_FOREACH(size_t, cases, kCases) {
const Operator* const op = common()->Switch(cases);
......
......@@ -124,15 +124,11 @@ TEST_F(DeadCodeEliminationTest, IfSuccessWithDeadInput) {
TEST_F(DeadCodeEliminationTest, IfExceptionWithDeadControlInput) {
IfExceptionHint const kHints[] = {IfExceptionHint::kLocallyCaught,
IfExceptionHint::kLocallyUncaught};
TRACED_FOREACH(IfExceptionHint, hint, kHints) {
Reduction const r =
Reduce(graph()->NewNode(common()->IfException(hint), graph()->start(),
graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
Reduction const r =
Reduce(graph()->NewNode(common()->IfException(), graph()->start(),
graph()->NewNode(common()->Dead())));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsDead());
}
......
......@@ -283,8 +283,6 @@ const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties,
const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties,
"MockOpControl", 0, 0, 1, 1, 0, 1);
const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
} // namespace
......@@ -348,7 +346,7 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
Node* dead = graph()->NewNode(&kMockOperator);
Node* node = graph()->NewNode(&kMockOpControl, start);
Node* success = graph()->NewNode(common.IfSuccess(), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
Node* exception = graph()->NewNode(common.IfException(), effect, node);
Node* use_control = graph()->NewNode(common.Merge(1), success);
Node* replacement = graph()->NewNode(&kMockOperator);
GraphReducer graph_reducer(zone(), graph(), dead);
......@@ -372,7 +370,7 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse3) {
Node* dead = graph()->NewNode(&kMockOperator);
Node* node = graph()->NewNode(&kMockOpControl, start);
Node* success = graph()->NewNode(common.IfSuccess(), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
Node* exception = graph()->NewNode(common.IfException(), effect, node);
Node* use_control = graph()->NewNode(common.Merge(1), success);
Node* replacement = graph()->NewNode(&kMockOperator);
GraphReducer graph_reducer(zone(), graph(), dead);
......
......@@ -37,8 +37,6 @@ const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties,
"MockCallOperator", 0, 0, 0, 0, 0, 2);
const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
} // namespace
......@@ -49,7 +47,7 @@ TEST_F(NodePropertiesTest, ReplaceUses) {
Node* use_value = NewMockNode(common.Return(), node);
Node* use_effect = NewMockNode(common.EffectPhi(1), node);
Node* use_success = NewMockNode(common.IfSuccess(), node);
Node* use_exception = NewMockNode(common.IfException(kNoHint), effect, node);
Node* use_exception = NewMockNode(common.IfException(), effect, node);
Node* r_value = NewMockNode(&kMockOperator);
Node* r_effect = NewMockNode(&kMockOperator);
Node* r_success = NewMockNode(&kMockOperator);
......@@ -99,7 +97,7 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
Node* result[2];
CommonOperatorBuilder common(zone());
Node* call = NewMockNode(&kMockCallOperator);
Node* if_ex = NewMockNode(common.IfException(kNoHint), call, call);
Node* if_ex = NewMockNode(common.IfException(), call, call);
Node* if_ok = NewMockNode(common.IfSuccess(), call);
NodeProperties::CollectControlProjections(call, result, arraysize(result));
EXPECT_EQ(if_ok, result[0]);
......
......@@ -552,12 +552,10 @@ 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(IfExceptionHint::kLocallyUncaught), c1, c1);
Node* ex1 = graph()->NewNode(common()->IfException(), c1, c1);
Node* c2 = graph()->NewNode(&kMockCall, ok1);
Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2);
Node* ex2 = graph()->NewNode(
common()->IfException(IfExceptionHint::kLocallyUncaught), c2, c2);
Node* ex2 = graph()->NewNode(common()->IfException(), c2, 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(MachineRepresentation::kTagged, 2),
......
......@@ -59,8 +59,7 @@ 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(IfExceptionHint::kLocallyUncaught), call, call);
Node* if_exception = graph()->NewNode(common()->IfException(), call, call);
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
......@@ -125,8 +124,7 @@ 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(IfExceptionHint::kLocallyUncaught), call, call);
Node* if_exception = graph()->NewNode(common()->IfException(), call, call);
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment