| Index: src/full-codegen.cc
|
| diff --git a/src/full-codegen.cc b/src/full-codegen.cc
|
| index 1589b86a59785ea3928aa4ae8b4e724354462131..79427524860b3c1d99e26a443f606969ff9deb0a 100644
|
| --- a/src/full-codegen.cc
|
| +++ b/src/full-codegen.cc
|
| @@ -286,6 +286,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
|
| code->set_optimizable(info->IsOptimizable());
|
| cgen.PopulateDeoptimizationData(code);
|
| code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
|
| + code->set_handler_table(*cgen.handler_table());
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| code->set_has_debug_break_slots(
|
| info->isolate()->debugger()->IsDebuggerActive());
|
| @@ -1086,20 +1087,17 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| Comment cmnt(masm_, "[ TryCatchStatement");
|
| SetStatementPosition(stmt);
|
| - // The try block adds a handler to the exception handler chain
|
| - // before entering, and removes it again when exiting normally.
|
| - // If an exception is thrown during execution of the try block,
|
| - // control is passed to the handler, which also consumes the handler.
|
| - // At this point, the exception is in a register, and store it in
|
| - // the temporary local variable (prints as ".catch-var") before
|
| - // executing the catch block. The catch block has been rewritten
|
| - // to introduce a new scope to bind the catch variable and to remove
|
| - // that scope again afterwards.
|
| -
|
| - Label try_handler_setup, done;
|
| - __ Call(&try_handler_setup);
|
| - // Try handler code, exception in result register.
|
| -
|
| + // The try block adds a handler to the exception handler chain before
|
| + // entering, and removes it again when exiting normally. If an exception
|
| + // is thrown during execution of the try block, the handler is consumed
|
| + // and control is passed to the catch block with the exception in the
|
| + // result register.
|
| +
|
| + Label try_entry, handler_entry, exit;
|
| + __ jmp(&try_entry);
|
| + __ bind(&handler_entry);
|
| + handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
|
| + // Exception handler code, the exception is in the result register.
|
| // Extend the context before executing the catch block.
|
| { Comment cmnt(masm_, "[ Extend catch context");
|
| __ Push(stmt->variable()->name());
|
| @@ -1113,24 +1111,23 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| Scope* saved_scope = scope();
|
| scope_ = stmt->scope();
|
| ASSERT(scope_->declarations()->is_empty());
|
| - { WithOrCatch body(this);
|
| + { WithOrCatch catch_body(this);
|
| Visit(stmt->catch_block());
|
| }
|
| // Restore the context.
|
| LoadContextField(context_register(), Context::PREVIOUS_INDEX);
|
| StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
| scope_ = saved_scope;
|
| - __ jmp(&done);
|
| + __ jmp(&exit);
|
|
|
| // Try block code. Sets up the exception handler chain.
|
| - __ bind(&try_handler_setup);
|
| - {
|
| - TryCatch try_block(this);
|
| - __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
|
| + __ bind(&try_entry);
|
| + __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER, stmt->index());
|
| + { TryCatch try_body(this);
|
| Visit(stmt->try_block());
|
| - __ PopTryHandler();
|
| }
|
| - __ bind(&done);
|
| + __ PopTryHandler();
|
| + __ bind(&exit);
|
| }
|
|
|
|
|
| @@ -1142,12 +1139,12 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
| //
|
| // The try-finally construct can enter the finally block in three ways:
|
| // 1. By exiting the try-block normally. This removes the try-handler and
|
| - // calls the finally block code before continuing.
|
| + // calls the finally block code before continuing.
|
| // 2. By exiting the try-block with a function-local control flow transfer
|
| // (break/continue/return). The site of the, e.g., break removes the
|
| // try handler and calls the finally block code before continuing
|
| // its outward control transfer.
|
| - // 3. by exiting the try-block with a thrown exception.
|
| + // 3. By exiting the try-block with a thrown exception.
|
| // This can happen in nested function calls. It traverses the try-handler
|
| // chain and consumes the try-handler entry before jumping to the
|
| // handler code. The handler code then calls the finally-block before
|
| @@ -1158,44 +1155,39 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
| // exception) in the result register (rax/eax/r0), both of which must
|
| // be preserved. The return address isn't GC-safe, so it should be
|
| // cooked before GC.
|
| - Label finally_entry;
|
| - Label try_handler_setup;
|
| -
|
| - // Setup the try-handler chain. Use a call to
|
| - // Jump to try-handler setup and try-block code. Use call to put try-handler
|
| - // address on stack.
|
| - __ Call(&try_handler_setup);
|
| - // Try handler code. Return address of call is pushed on handler stack.
|
| - {
|
| - // This code is only executed during stack-handler traversal when an
|
| - // exception is thrown. The exception is in the result register, which
|
| - // is retained by the finally block.
|
| - // Call the finally block and then rethrow the exception if it returns.
|
| - __ Call(&finally_entry);
|
| - __ push(result_register());
|
| - __ CallRuntime(Runtime::kReThrow, 1);
|
| - }
|
| + Label try_entry, handler_entry, finally_entry;
|
| +
|
| + // Jump to try-handler setup and try-block code.
|
| + __ jmp(&try_entry);
|
| + __ bind(&handler_entry);
|
| + handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
|
| + // Exception handler code. This code is only executed when an exception
|
| + // is thrown. The exception is in the result register, and must be
|
| + // preserved by the finally block. Call the finally block and then
|
| + // rethrow the exception if it returns.
|
| + __ Call(&finally_entry);
|
| + __ push(result_register());
|
| + __ CallRuntime(Runtime::kReThrow, 1);
|
|
|
| + // Finally block implementation.
|
| __ bind(&finally_entry);
|
| - {
|
| - // Finally block implementation.
|
| - Finally finally_block(this);
|
| - EnterFinallyBlock();
|
| + EnterFinallyBlock();
|
| + { Finally finally_body(this);
|
| Visit(stmt->finally_block());
|
| - ExitFinallyBlock(); // Return to the calling code.
|
| }
|
| + ExitFinallyBlock(); // Return to the calling code.
|
|
|
| - __ bind(&try_handler_setup);
|
| - {
|
| - // Setup try handler (stack pointer registers).
|
| - TryFinally try_block(this, &finally_entry);
|
| - __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
|
| + // Setup try handler.
|
| + __ bind(&try_entry);
|
| + __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER, stmt->index());
|
| + { TryFinally try_body(this, &finally_entry);
|
| Visit(stmt->try_block());
|
| - __ PopTryHandler();
|
| }
|
| + __ PopTryHandler();
|
| // Execute the finally block on the way out. Clobber the unpredictable
|
| - // value in the accumulator with one that's safe for GC. The finally
|
| - // block will unconditionally preserve the accumulator on the stack.
|
| + // value in the result register with one that's safe for GC because the
|
| + // finally block will unconditionally preserve the result register on the
|
| + // stack.
|
| ClearAccumulator();
|
| __ Call(&finally_entry);
|
| }
|
|
|