[ignition] Add helper for TryCatch building
Change-Id: Ia39d2157eb7c0c644348e1762ee32fef84c6b51d Reviewed-on: https://chromium-review.googlesource.com/c/1409428 Commit-Queue: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#58816}
This commit is contained in:
parent
15e803c1b9
commit
4c8dd3c9f9
@ -1501,6 +1501,36 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TryBodyFunc, typename CatchBodyFunc>
|
||||||
|
void BytecodeGenerator::BuildTryCatch(
|
||||||
|
TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
|
||||||
|
HandlerTable::CatchPrediction catch_prediction,
|
||||||
|
TryCatchStatement* stmt_for_coverage) {
|
||||||
|
TryCatchBuilder try_control_builder(
|
||||||
|
builder(),
|
||||||
|
stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_,
|
||||||
|
stmt_for_coverage, catch_prediction);
|
||||||
|
|
||||||
|
// Preserve the context in a dedicated register, so that it can be restored
|
||||||
|
// when the handler is entered by the stack-unwinding machinery.
|
||||||
|
// TODO(mstarzinger): Be smarter about register allocation.
|
||||||
|
Register context = register_allocator()->NewRegister();
|
||||||
|
builder()->MoveRegister(Register::current_context(), context);
|
||||||
|
|
||||||
|
// Evaluate the try-block inside a control scope. This simulates a handler
|
||||||
|
// that is intercepting 'throw' control commands.
|
||||||
|
try_control_builder.BeginTry(context);
|
||||||
|
{
|
||||||
|
ControlScopeForTryCatch scope(this, &try_control_builder);
|
||||||
|
try_body_func();
|
||||||
|
}
|
||||||
|
try_control_builder.EndTry();
|
||||||
|
|
||||||
|
catch_body_func(context);
|
||||||
|
|
||||||
|
try_control_builder.EndCatch();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TryBodyFunc, typename FinallyBodyFunc>
|
template <typename TryBodyFunc, typename FinallyBodyFunc>
|
||||||
void BytecodeGenerator::BuildTryFinally(
|
void BytecodeGenerator::BuildTryFinally(
|
||||||
TryBodyFunc try_body_func, FinallyBodyFunc finally_body_func,
|
TryBodyFunc try_body_func, FinallyBodyFunc finally_body_func,
|
||||||
@ -1806,46 +1836,36 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
|||||||
HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
|
HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
|
||||||
set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
|
set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
|
||||||
|
|
||||||
TryCatchBuilder try_control_builder(builder(), block_coverage_builder_, stmt,
|
BuildTryCatch(
|
||||||
catch_prediction());
|
// Try body.
|
||||||
|
[&]() {
|
||||||
|
Visit(stmt->try_block());
|
||||||
|
set_catch_prediction(outer_catch_prediction);
|
||||||
|
},
|
||||||
|
// Catch body.
|
||||||
|
[&](Register context) {
|
||||||
|
if (stmt->scope()) {
|
||||||
|
// Create a catch scope that binds the exception.
|
||||||
|
BuildNewLocalCatchContext(stmt->scope());
|
||||||
|
builder()->StoreAccumulatorInRegister(context);
|
||||||
|
}
|
||||||
|
|
||||||
// Preserve the context in a dedicated register, so that it can be restored
|
// If requested, clear message object as we enter the catch block.
|
||||||
// when the handler is entered by the stack-unwinding machinery.
|
if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
|
||||||
// TODO(mstarzinger): Be smarter about register allocation.
|
builder()->LoadTheHole().SetPendingMessage();
|
||||||
Register context = register_allocator()->NewRegister();
|
}
|
||||||
builder()->MoveRegister(Register::current_context(), context);
|
|
||||||
|
|
||||||
// Evaluate the try-block inside a control scope. This simulates a handler
|
// Load the catch context into the accumulator.
|
||||||
// that is intercepting 'throw' control commands.
|
builder()->LoadAccumulatorWithRegister(context);
|
||||||
try_control_builder.BeginTry(context);
|
|
||||||
{
|
|
||||||
ControlScopeForTryCatch scope(this, &try_control_builder);
|
|
||||||
Visit(stmt->try_block());
|
|
||||||
set_catch_prediction(outer_catch_prediction);
|
|
||||||
}
|
|
||||||
try_control_builder.EndTry();
|
|
||||||
|
|
||||||
if (stmt->scope()) {
|
// Evaluate the catch-block.
|
||||||
// Create a catch scope that binds the exception.
|
if (stmt->scope()) {
|
||||||
BuildNewLocalCatchContext(stmt->scope());
|
VisitInScope(stmt->catch_block(), stmt->scope());
|
||||||
builder()->StoreAccumulatorInRegister(context);
|
} else {
|
||||||
}
|
VisitBlock(stmt->catch_block());
|
||||||
|
}
|
||||||
// If requested, clear message object as we enter the catch block.
|
},
|
||||||
if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
|
catch_prediction(), stmt);
|
||||||
builder()->LoadTheHole().SetPendingMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the catch context into the accumulator.
|
|
||||||
builder()->LoadAccumulatorWithRegister(context);
|
|
||||||
|
|
||||||
// Evaluate the catch-block.
|
|
||||||
if (stmt->scope()) {
|
|
||||||
VisitInScope(stmt->catch_block(), stmt->scope());
|
|
||||||
} else {
|
|
||||||
VisitBlock(stmt->catch_block());
|
|
||||||
}
|
|
||||||
try_control_builder.EndCatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
||||||
@ -3173,67 +3193,54 @@ void BytecodeGenerator::BuildFinalizeIteration(
|
|||||||
}
|
}
|
||||||
builder()->Bind(&if_callable);
|
builder()->Bind(&if_callable);
|
||||||
|
|
||||||
// try {
|
|
||||||
// let return_val = method.call(iterator)
|
|
||||||
// if (!%IsObject(return_val)) throw TypeError
|
|
||||||
// }
|
|
||||||
|
|
||||||
{
|
{
|
||||||
RegisterAllocationScope register_scope(this);
|
RegisterAllocationScope register_scope(this);
|
||||||
TryCatchBuilder try_control_builder(builder(), nullptr, nullptr,
|
BuildTryCatch(
|
||||||
HandlerTable::UNCAUGHT);
|
// try {
|
||||||
|
// let return_val = method.call(iterator)
|
||||||
|
// if (!%IsObject(return_val)) throw TypeError
|
||||||
|
// }
|
||||||
|
[&]() {
|
||||||
|
RegisterList args(iterator.object());
|
||||||
|
builder()->CallProperty(
|
||||||
|
method, args, feedback_index(feedback_spec()->AddCallICSlot()));
|
||||||
|
if (iterator.type() == IteratorType::kAsync) {
|
||||||
|
BuildAwait();
|
||||||
|
}
|
||||||
|
builder()->JumpIfJSReceiver(iterator_is_done.New());
|
||||||
|
{
|
||||||
|
// Throw this exception inside the try block so that it is
|
||||||
|
// suppressed by the iteration continuation if necessary.
|
||||||
|
RegisterAllocationScope register_scope(this);
|
||||||
|
Register return_result = register_allocator()->NewRegister();
|
||||||
|
builder()
|
||||||
|
->StoreAccumulatorInRegister(return_result)
|
||||||
|
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject,
|
||||||
|
return_result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Preserve the context in a dedicated register, so that it can be restored
|
// catch (e) {
|
||||||
// when the handler is entered by the stack-unwinding machinery.
|
// if (iteration_continuation != RETHROW)
|
||||||
// TODO(mstarzinger): Be smarter about register allocation.
|
// rethrow e
|
||||||
Register context = register_allocator()->NewRegister();
|
// }
|
||||||
builder()->MoveRegister(Register::current_context(), context);
|
[&](Register context) {
|
||||||
|
// Reuse context register to store the exception.
|
||||||
|
Register close_exception = context;
|
||||||
|
builder()->StoreAccumulatorInRegister(close_exception);
|
||||||
|
|
||||||
// Evaluate the try-block inside a control scope. This simulates a handler
|
BytecodeLabel suppress_close_exception;
|
||||||
// that is intercepting 'throw' control commands.
|
builder()
|
||||||
try_control_builder.BeginTry(context);
|
->LoadLiteral(
|
||||||
{
|
Smi::FromInt(ControlScope::DeferredCommands::kRethrowToken))
|
||||||
ControlScopeForTryCatch scope(this, &try_control_builder);
|
.CompareReference(iteration_continuation_token)
|
||||||
|
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean,
|
||||||
RegisterList args(iterator.object());
|
&suppress_close_exception)
|
||||||
builder()->CallProperty(method, args,
|
.LoadAccumulatorWithRegister(close_exception)
|
||||||
feedback_index(feedback_spec()->AddCallICSlot()));
|
.ReThrow()
|
||||||
if (iterator.type() == IteratorType::kAsync) {
|
.Bind(&suppress_close_exception);
|
||||||
BuildAwait();
|
},
|
||||||
}
|
HandlerTable::UNCAUGHT);
|
||||||
builder()->JumpIfJSReceiver(iterator_is_done.New());
|
|
||||||
{
|
|
||||||
// Throw this exception inside the try block so that it is suppressed by
|
|
||||||
// the iteration continuation if necessary.
|
|
||||||
RegisterAllocationScope register_scope(this);
|
|
||||||
Register return_result = register_allocator()->NewRegister();
|
|
||||||
builder()
|
|
||||||
->StoreAccumulatorInRegister(return_result)
|
|
||||||
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject,
|
|
||||||
return_result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try_control_builder.EndTry();
|
|
||||||
|
|
||||||
// catch (e) {
|
|
||||||
// if (iteration_continuation != RETHROW)
|
|
||||||
// rethrow e
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Reuse context register to store the exception.
|
|
||||||
Register close_exception = context;
|
|
||||||
builder()->StoreAccumulatorInRegister(close_exception);
|
|
||||||
|
|
||||||
BytecodeLabel suppress_close_exception;
|
|
||||||
builder()
|
|
||||||
->LoadLiteral(
|
|
||||||
Smi::FromInt(ControlScope::DeferredCommands::kRethrowToken))
|
|
||||||
.CompareReference(iteration_continuation_token)
|
|
||||||
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &suppress_close_exception)
|
|
||||||
.LoadAccumulatorWithRegister(close_exception)
|
|
||||||
.ReThrow()
|
|
||||||
.Bind(&suppress_close_exception);
|
|
||||||
try_control_builder.EndCatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator_is_done.Bind(builder());
|
iterator_is_done.Bind(builder());
|
||||||
|
@ -344,6 +344,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
|
|||||||
void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
|
void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
|
||||||
BytecodeLabels* else_labels, TestFallthrough fallthrough);
|
BytecodeLabels* else_labels, TestFallthrough fallthrough);
|
||||||
|
|
||||||
|
template <typename TryBodyFunc, typename CatchBodyFunc>
|
||||||
|
void BuildTryCatch(TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
|
||||||
|
HandlerTable::CatchPrediction catch_prediction,
|
||||||
|
TryCatchStatement* stmt_for_coverage = nullptr);
|
||||||
template <typename TryBodyFunc, typename FinallyBodyFunc>
|
template <typename TryBodyFunc, typename FinallyBodyFunc>
|
||||||
void BuildTryFinally(TryBodyFunc try_body_func,
|
void BuildTryFinally(TryBodyFunc try_body_func,
|
||||||
FinallyBodyFunc finally_body_func,
|
FinallyBodyFunc finally_body_func,
|
||||||
|
Loading…
Reference in New Issue
Block a user