Index: runtime/vm/intermediate_language_dbc.cc |
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc |
index 2f64861a0de662bc3ecac805d2d8519eb5f5f935..9904d01b5f35557ae6820aab3b10b5ef7da4b2f7 100644 |
--- a/runtime/vm/intermediate_language_dbc.cc |
+++ b/runtime/vm/intermediate_language_dbc.cc |
@@ -1185,24 +1185,67 @@ EMIT_NATIVE_CODE(CatchBlockEntry, 0) { |
if (HasParallelMove()) { |
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
} |
- if (compiler->is_optimizing()) { |
- // In optimized code, variables at the catch block entry reside at the top |
- // of the allocatable register range. |
- const intptr_t num_non_copied_params = |
- compiler->flow_graph().num_non_copied_params(); |
- const intptr_t exception_reg = |
- kNumberOfCpuRegisters - |
- (-exception_var().index() + num_non_copied_params); |
- const intptr_t stacktrace_reg = |
- kNumberOfCpuRegisters - |
- (-stacktrace_var().index() + num_non_copied_params); |
- __ MoveSpecial(exception_reg, Simulator::kExceptionSpecialIndex); |
- __ MoveSpecial(stacktrace_reg, Simulator::kStackTraceSpecialIndex); |
+ |
+ Register context_reg = kNoRegister; |
+ |
+ // Auxiliary variables introduced by the try catch can be captured if we are |
+ // inside a function with yield/resume points. In this case we first need |
+ // to restore the context to match the context at entry into the closure. |
+ if (should_restore_closure_context()) { |
+ const ParsedFunction& parsed_function = compiler->parsed_function(); |
+ |
+ ASSERT(parsed_function.function().IsClosureFunction()); |
+ LocalScope* scope = parsed_function.node_sequence()->scope(); |
+ |
+ LocalVariable* closure_parameter = scope->VariableAt(0); |
+ ASSERT(!closure_parameter->is_captured()); |
+ |
+ const LocalVariable& current_context_var = |
+ *parsed_function.current_context_var(); |
+ |
+ context_reg = compiler->is_optimizing() |
+ ? compiler->CatchEntryRegForVariable(current_context_var) |
+ : LocalVarIndex(0, current_context_var.index()); |
+ |
+ Register closure_reg; |
+ if (closure_parameter->index() > 0) { |
+ __ Move(context_reg, LocalVarIndex(0, closure_parameter->index())); |
+ closure_reg = context_reg; |
+ } else { |
+ closure_reg = LocalVarIndex(0, closure_parameter->index()); |
+ } |
+ |
+ __ LoadField(context_reg, closure_reg, |
+ Closure::context_offset() / kWordSize); |
+ } |
+ |
+ if (exception_var().is_captured()) { |
+ ASSERT(stacktrace_var().is_captured()); |
+ ASSERT(context_reg != kNoRegister); |
+ // This will be SP[1] register so we are free to use it as a temporary. |
+ const Register temp = compiler->StackSize(); |
+ __ MoveSpecial(temp, Simulator::kExceptionSpecialIndex); |
+ __ StoreField(context_reg, |
+ Context::variable_offset(exception_var().index()) / kWordSize, |
+ temp); |
+ __ MoveSpecial(temp, Simulator::kStackTraceSpecialIndex); |
+ __ StoreField( |
+ context_reg, |
+ Context::variable_offset(stacktrace_var().index()) / kWordSize, temp); |
} else { |
- __ MoveSpecial(LocalVarIndex(0, exception_var().index()), |
- Simulator::kExceptionSpecialIndex); |
- __ MoveSpecial(LocalVarIndex(0, stacktrace_var().index()), |
- Simulator::kStackTraceSpecialIndex); |
+ if (compiler->is_optimizing()) { |
+ const intptr_t exception_reg = |
+ compiler->CatchEntryRegForVariable(exception_var()); |
+ const intptr_t stacktrace_reg = |
+ compiler->CatchEntryRegForVariable(stacktrace_var()); |
+ __ MoveSpecial(exception_reg, Simulator::kExceptionSpecialIndex); |
+ __ MoveSpecial(stacktrace_reg, Simulator::kStackTraceSpecialIndex); |
+ } else { |
+ __ MoveSpecial(LocalVarIndex(0, exception_var().index()), |
+ Simulator::kExceptionSpecialIndex); |
+ __ MoveSpecial(LocalVarIndex(0, stacktrace_var().index()), |
+ Simulator::kStackTraceSpecialIndex); |
+ } |
} |
__ SetFrame(compiler->StackSize()); |
} |