Revert "Reland "[VM] Use IR for code in [CatchEntryInstr]s to populate captured exception/stacktrace variables""
This reverts commit 23b4a505ece3dea8326fe3181d6a4e6aa4e4108b.
Reason for revert: The language_2/custom_await_stack_trace_test started failing.
Original change's description:
> Reland "[VM] Use IR for code in [CatchEntryInstr]s to populate captured exception/stacktrace variables"
>
> This fixes an issue when a program got loaded via dill, a function
> with a try-catch got optimized and the exception/stacktrace variables
> got captured.
>
> Change-Id: Icb626965019b248afe3b72a6679c5049ea7b7b00
> Reviewed-on: https://dart-review.googlesource.com/55681
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
> Commit-Queue: Martin Kustermann <kustermann@google.com>
TBR=vegorov@google.com,kustermann@google.com
Change-Id: Ic825c1e3ed14c731da1d43aa6f27d37ed5d36b4c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/55720
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 8003fb4..4253ba1 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -30,6 +30,7 @@
complex_reload_test: RuntimeError
[ $arch == simdbc64 && $compiler == dartk ]
+coverage_optimized_function_test: Crash # Please triage
get_cpu_profile_timeline_rpc_test: Pass, RuntimeError # http://dartbug.com/31794
pause_on_unhandled_async_exceptions_test: RuntimeError, Timeout # Issue 31765
diff --git a/runtime/platform/growable_array.h b/runtime/platform/growable_array.h
index f6c0598..32ffcc4 100644
--- a/runtime/platform/growable_array.h
+++ b/runtime/platform/growable_array.h
@@ -70,16 +70,6 @@
}
}
- void EnsureLength(intptr_t new_length, const T& default_value) {
- const intptr_t old_length = length_;
- if (old_length < new_length) {
- Resize(new_length);
- for (intptr_t i = old_length; i < new_length; ++i) {
- (*this)[i] = default_value;
- }
- }
- }
-
const T& At(intptr_t index) const { return operator[](index); }
T& Last() const {
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 4cc0e2e..5411f90 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -1081,34 +1081,10 @@
}
}
}
- } else if (CatchBlockEntryInstr* catch_entry =
- block_entry->AsCatchBlockEntry()) {
- const intptr_t raw_exception_var_envindex =
- catch_entry->raw_exception_var() != nullptr
- ? catch_entry->raw_exception_var()->BitIndexIn(
- num_direct_parameters_)
- : -1;
- const intptr_t raw_stacktrace_var_envindex =
- catch_entry->raw_stacktrace_var() != nullptr
- ? catch_entry->raw_stacktrace_var()->BitIndexIn(
- num_direct_parameters_)
- : -1;
-
+ } else if (block_entry->IsCatchBlockEntry()) {
// Add real definitions for all locals and parameters.
for (intptr_t i = 0; i < env->length(); ++i) {
- // Replace usages of the raw exception/stacktrace variables with
- // [SpecialParameterInstr]s.
- Definition* param = nullptr;
- if (raw_exception_var_envindex == i) {
- param = new SpecialParameterInstr(SpecialParameterInstr::kException,
- Thread::kNoDeoptId);
- } else if (raw_stacktrace_var_envindex == i) {
- param = new SpecialParameterInstr(SpecialParameterInstr::kStackTrace,
- Thread::kNoDeoptId);
- } else {
- param = new (zone()) ParameterInstr(i, block_entry);
- }
-
+ ParameterInstr* param = new (zone()) ParameterInstr(i, block_entry);
param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
(*env)[i] = param;
block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param);
@@ -1130,30 +1106,6 @@
// Attach environment to the block entry.
AttachEnvironment(block_entry, env);
-#if defined(TARGET_ARCH_DBC)
- // On DBC the exception/stacktrace variables are in special registers when
- // entering the catch block. The only usage of those special registers is
- // within the catch block. A possible lazy-deopt at the beginning of the
- // catch does not need to move those around, since the registers will be
- // up-to-date when arriving in the unoptimized code and unoptimized code will
- // take care of moving them to appropriate slots.
- if (CatchBlockEntryInstr* catch_entry = block_entry->AsCatchBlockEntry()) {
- Environment* deopt_env = catch_entry->env();
- const LocalVariable* raw_exception_var = catch_entry->raw_exception_var();
- const LocalVariable* raw_stacktrace_var = catch_entry->raw_stacktrace_var();
- if (raw_exception_var != nullptr) {
- Value* value = deopt_env->ValueAt(
- raw_exception_var->BitIndexIn(num_direct_parameters_));
- value->BindToEnvironment(constant_null());
- }
- if (raw_stacktrace_var != nullptr) {
- Value* value = deopt_env->ValueAt(
- raw_stacktrace_var->BitIndexIn(num_direct_parameters_));
- value->BindToEnvironment(constant_null());
- }
- }
-#endif // defined(TARGET_ARCH_DBC)
-
// 2. Process normal instructions.
for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
Instruction* current = it.Current();
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_dbc.cc b/runtime/vm/compiler/backend/flow_graph_compiler_dbc.cc
index 557f69a..0e9f214 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_dbc.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_dbc.cc
@@ -17,7 +17,6 @@
#include "vm/instructions.h"
#include "vm/object_store.h"
#include "vm/parser.h"
-#include "vm/simulator.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
@@ -384,12 +383,6 @@
} else if (source.IsArgsDescRegister()) {
ASSERT(destination.IsRegister());
__ LoadArgDescriptorOpt(destination.reg());
- } else if (source.IsExceptionRegister()) {
- ASSERT(destination.IsRegister());
- __ MoveSpecial(destination.reg(), Simulator::kExceptionSpecialIndex);
- } else if (source.IsStackTraceRegister()) {
- ASSERT(destination.IsRegister());
- __ MoveSpecial(destination.reg(), Simulator::kStackTraceSpecialIndex);
} else if (source.IsConstant() && destination.IsRegister()) {
if (source.constant_instruction()->representation() == kUnboxedDouble) {
const Register result = destination.reg();
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 9b33e12..a957568 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -1641,8 +1641,7 @@
const LocalVariable& stacktrace_var,
bool needs_stacktrace,
intptr_t deopt_id,
- const LocalVariable* raw_exception_var,
- const LocalVariable* raw_stacktrace_var)
+ bool should_restore_closure_context = false)
: BlockEntryInstr(block_id, try_index, deopt_id),
graph_entry_(graph_entry),
predecessor_(NULL),
@@ -1650,9 +1649,8 @@
catch_try_index_(catch_try_index),
exception_var_(exception_var),
stacktrace_var_(stacktrace_var),
- raw_exception_var_(raw_exception_var),
- raw_stacktrace_var_(raw_stacktrace_var),
needs_stacktrace_(needs_stacktrace),
+ should_restore_closure_context_(should_restore_closure_context),
handler_token_pos_(handler_token_pos),
is_generated_(is_generated) {}
@@ -1671,11 +1669,6 @@
const LocalVariable& exception_var() const { return exception_var_; }
const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
- const LocalVariable* raw_exception_var() const { return raw_exception_var_; }
- const LocalVariable* raw_stacktrace_var() const {
- return raw_stacktrace_var_;
- }
-
bool needs_stacktrace() const { return needs_stacktrace_; }
bool is_generated() const { return is_generated_; }
@@ -1699,6 +1692,12 @@
predecessor_ = predecessor;
}
+ bool should_restore_closure_context() const {
+ ASSERT(exception_var_.is_captured() == stacktrace_var_.is_captured());
+ ASSERT(!exception_var_.is_captured() || should_restore_closure_context_);
+ return should_restore_closure_context_;
+ }
+
GraphEntryInstr* graph_entry_;
BlockEntryInstr* predecessor_;
const Array& catch_handler_types_;
@@ -1706,9 +1705,8 @@
GrowableArray<Definition*> initial_definitions_;
const LocalVariable& exception_var_;
const LocalVariable& stacktrace_var_;
- const LocalVariable* raw_exception_var_;
- const LocalVariable* raw_stacktrace_var_;
const bool needs_stacktrace_;
+ const bool should_restore_closure_context_;
TokenPosition handler_token_pos_;
bool is_generated_;
@@ -3000,13 +2998,7 @@
// the type arguments of a generic function or an arguments descriptor.
class SpecialParameterInstr : public TemplateDefinition<0, NoThrow> {
public:
- enum SpecialParameterKind {
- kContext,
- kTypeArgs,
- kArgDescriptor,
- kException,
- kStackTrace
- };
+ enum SpecialParameterKind { kContext, kTypeArgs, kArgDescriptor };
SpecialParameterInstr(SpecialParameterKind kind, intptr_t deopt_id)
: TemplateDefinition(deopt_id), kind_(kind) {}
@@ -3035,10 +3027,6 @@
return "kTypeArgs";
case kArgDescriptor:
return "kArgDescriptor";
- case kException:
- return "kException";
- case kStackTrace:
- return "kStackTrace";
}
UNREACHABLE();
return NULL;
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index b3547cb..9b5729c 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -2888,15 +2888,38 @@
ASSERT(fp_sp_dist <= 0);
__ AddImmediate(SP, FP, fp_sp_dist);
- if (!compiler->is_optimizing()) {
- if (raw_exception_var_ != nullptr) {
- __ str(kExceptionObjectReg,
- Address(FP, raw_exception_var_->index() * kWordSize));
- }
- if (raw_stacktrace_var_ != nullptr) {
- __ str(kStackTraceObjectReg,
- Address(FP, raw_stacktrace_var_->index() * kWordSize));
- }
+ // 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());
+ __ LoadFromOffset(kWord, R6, FP, closure_parameter->index() * kWordSize);
+ __ LoadFieldFromOffset(kWord, R6, R6, Closure::context_offset());
+
+ const intptr_t context_index =
+ parsed_function.current_context_var()->index();
+ __ StoreToOffset(kWord, R6, FP, context_index * kWordSize);
+ }
+
+ // Initialize exception and stack trace variables.
+ if (exception_var().is_captured()) {
+ ASSERT(stacktrace_var().is_captured());
+ __ StoreIntoObjectOffset(R6,
+ Context::variable_offset(exception_var().index()),
+ kExceptionObjectReg);
+ __ StoreIntoObjectOffset(R6,
+ Context::variable_offset(stacktrace_var().index()),
+ kStackTraceObjectReg);
+ } else {
+ __ StoreToOffset(kWord, kExceptionObjectReg, FP,
+ exception_var().index() * kWordSize);
+ __ StoreToOffset(kWord, kStackTraceObjectReg, FP,
+ stacktrace_var().index() * kWordSize);
}
}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 5cba834..9c0a698 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -2637,15 +2637,40 @@
ASSERT(fp_sp_dist <= 0);
__ AddImmediate(SP, FP, fp_sp_dist);
- if (!compiler->is_optimizing()) {
- if (raw_exception_var_ != nullptr) {
- __ str(kExceptionObjectReg,
- Address(FP, raw_exception_var_->index() * kWordSize));
- }
- if (raw_stacktrace_var_ != nullptr) {
- __ str(kStackTraceObjectReg,
- Address(FP, raw_stacktrace_var_->index() * kWordSize));
- }
+ // 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());
+ __ LoadFromOffset(R28, FP, closure_parameter->index() * kWordSize);
+ __ LoadFieldFromOffset(R28, R28, Closure::context_offset());
+
+ const intptr_t context_index =
+ parsed_function.current_context_var()->index();
+ __ StoreToOffset(R28, FP, context_index * kWordSize);
+ }
+
+ // Initialize exception and stack trace variables.
+ if (exception_var().is_captured()) {
+ ASSERT(stacktrace_var().is_captured());
+ __ StoreIntoObjectOffset(R28,
+ Context::variable_offset(exception_var().index()),
+ kExceptionObjectReg);
+ __ StoreIntoObjectOffset(R28,
+ Context::variable_offset(stacktrace_var().index()),
+ kStackTraceObjectReg);
+ } else {
+ // Restore stack and initialize the two exception variables:
+ // exception and stack trace variables.
+ __ StoreToOffset(kExceptionObjectReg, FP,
+ exception_var().index() * kWordSize);
+ __ StoreToOffset(kStackTraceObjectReg, FP,
+ stacktrace_var().index() * kWordSize);
}
}
diff --git a/runtime/vm/compiler/backend/il_dbc.cc b/runtime/vm/compiler/backend/il_dbc.cc
index c00e4e9..093c340 100644
--- a/runtime/vm/compiler/backend/il_dbc.cc
+++ b/runtime/vm/compiler/backend/il_dbc.cc
@@ -1184,18 +1184,69 @@
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
- __ SetFrame(compiler->StackSize());
- if (!compiler->is_optimizing()) {
- if (raw_exception_var_ != nullptr) {
- __ MoveSpecial(LocalVarIndex(0, raw_exception_var_->index()),
- Simulator::kExceptionSpecialIndex);
+ 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());
}
- if (raw_stacktrace_var_ != nullptr) {
- __ MoveSpecial(LocalVarIndex(0, raw_stacktrace_var_->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 {
+ 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());
}
EMIT_NATIVE_CODE(Throw, 0, Location::NoLocation(), LocationSummary::kCall) {
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index e8ec6e3..c92b517 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -2496,15 +2496,51 @@
ASSERT(fp_sp_dist <= 0);
__ leal(ESP, Address(EBP, fp_sp_dist));
- if (!compiler->is_optimizing()) {
- if (raw_exception_var_ != nullptr) {
- __ movl(Address(EBP, raw_exception_var_->index() * kWordSize),
- kExceptionObjectReg);
- }
- if (raw_stacktrace_var_ != nullptr) {
- __ movl(Address(EBP, raw_stacktrace_var_->index() * kWordSize),
- kStackTraceObjectReg);
- }
+ // 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());
+ __ movl(EDI, Address(EBP, closure_parameter->index() * kWordSize));
+ __ movl(EDI, FieldAddress(EDI, Closure::context_offset()));
+
+#ifdef DEBUG
+ Label ok;
+ __ LoadClassId(EBX, EDI);
+ __ cmpl(EBX, Immediate(kContextCid));
+ __ j(EQUAL, &ok, Assembler::kNearJump);
+ __ Stop("Incorrect context at entry");
+ __ Bind(&ok);
+#endif
+
+ const intptr_t context_index =
+ parsed_function.current_context_var()->index();
+ __ movl(Address(EBP, context_index * kWordSize), EDI);
+ }
+
+ // Initialize exception and stack trace variables.
+ if (exception_var().is_captured()) {
+ ASSERT(stacktrace_var().is_captured());
+ __ StoreIntoObject(
+ EDI,
+ FieldAddress(EDI, Context::variable_offset(exception_var().index())),
+ kExceptionObjectReg);
+ __ StoreIntoObject(
+ EDI,
+ FieldAddress(EDI, Context::variable_offset(stacktrace_var().index())),
+ kStackTraceObjectReg);
+ } else {
+ // Restore stack and initialize the two exception variables:
+ // exception and stack trace variables.
+ __ movl(Address(EBP, exception_var().index() * kWordSize),
+ kExceptionObjectReg);
+ __ movl(Address(EBP, stacktrace_var().index() * kWordSize),
+ kStackTraceObjectReg);
}
}
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index cbbd640..b44d650 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -2571,15 +2571,49 @@
ASSERT(fp_sp_dist <= 0);
__ leaq(RSP, Address(RBP, fp_sp_dist));
- if (!compiler->is_optimizing()) {
- if (raw_exception_var_ != nullptr) {
- __ movq(Address(RBP, raw_exception_var_->index() * kWordSize),
- kExceptionObjectReg);
- }
- if (raw_stacktrace_var_ != nullptr) {
- __ movq(Address(RBP, raw_stacktrace_var_->index() * kWordSize),
- kStackTraceObjectReg);
- }
+ // 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());
+ __ movq(R12, Address(RBP, closure_parameter->index() * kWordSize));
+ __ movq(R12, FieldAddress(R12, Closure::context_offset()));
+
+#ifdef DEBUG
+ Label ok;
+ __ LoadClassId(RBX, R12);
+ __ cmpq(RBX, Immediate(kContextCid));
+ __ j(EQUAL, &ok, Assembler::kNearJump);
+ __ Stop("Incorrect context at entry");
+ __ Bind(&ok);
+#endif
+
+ const intptr_t context_index =
+ parsed_function.current_context_var()->index();
+ __ movq(Address(RBP, context_index * kWordSize), R12);
+ }
+
+ // Initialize exception and stack trace variables.
+ if (exception_var().is_captured()) {
+ ASSERT(stacktrace_var().is_captured());
+ __ StoreIntoObject(
+ R12,
+ FieldAddress(R12, Context::variable_offset(exception_var().index())),
+ kExceptionObjectReg);
+ __ StoreIntoObject(
+ R12,
+ FieldAddress(R12, Context::variable_offset(stacktrace_var().index())),
+ kStackTraceObjectReg);
+ } else {
+ __ movq(Address(RBP, exception_var().index() * kWordSize),
+ kExceptionObjectReg);
+ __ movq(Address(RBP, stacktrace_var().index() * kWordSize),
+ kStackTraceObjectReg);
}
}
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index f96a09d..10d2c09 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -595,6 +595,23 @@
range->DefineAt(catch_entry->start_pos()); // Defined at block entry.
ProcessInitialDefinition(defn, range, catch_entry);
}
+ // Block the two fixed registers used by CatchBlockEntryInstr from the
+ // block start to until the end of the instruction so that they are
+ // preserved.
+ intptr_t start = catch_entry->start_pos();
+#if !defined(TARGET_ARCH_DBC)
+ const Register exception_reg = kExceptionObjectReg;
+ const Register stacktrace_reg = kStackTraceObjectReg;
+#else
+ const intptr_t exception_reg =
+ LocalVarIndex(0, catch_entry->exception_var().index());
+ const intptr_t stacktrace_reg =
+ LocalVarIndex(0, catch_entry->stacktrace_var().index());
+#endif
+ BlockLocation(Location::RegisterLocation(exception_reg), start,
+ ToInstructionEnd(start));
+ BlockLocation(Location::RegisterLocation(stacktrace_reg), start,
+ ToInstructionEnd(start));
}
}
@@ -622,42 +639,11 @@
void FlowGraphAllocator::ProcessInitialDefinition(Definition* defn,
LiveRange* range,
BlockEntryInstr* block) {
- // Save the range end because it may change below.
- const intptr_t range_end = range->End();
-
- // TODO(31956): Clean up this code and factor common functionality out.
- // Consider also making a separate [ProcessInitialDefinition] for
- // [CatchBlockEntry]'s.
- if (block->IsCatchBlockEntry()) {
- if (SpecialParameterInstr* param = defn->AsSpecialParameter()) {
- Location loc;
- switch (param->kind()) {
- case SpecialParameterInstr::kException:
- loc = Location::ExceptionLocation();
- break;
- case SpecialParameterInstr::kStackTrace:
- loc = Location::StackTraceLocation();
- break;
- default:
- UNREACHABLE();
- }
- range->set_assigned_location(loc);
- AssignSafepoints(defn, range);
- range->finger()->Initialize(range);
- SplitInitialDefinitionAt(range, block->lifetime_position() + 1);
- ConvertAllUses(range);
-
- // On non-DBC we'll have exception/stacktrace in a register and need to
- // ensure this register is not available for register allocation during
- // the [CatchBlockEntry] to ensure it's not overwritten.
- if (loc.IsRegister()) {
- BlockLocation(loc, block->lifetime_position(),
- block->lifetime_position() + 1);
- }
- return;
#if defined(TARGET_ARCH_DBC)
- } else if (ParameterInstr* param = defn->AsParameter()) {
+ if (block->IsCatchBlockEntry()) {
+ if (defn->IsParameter()) {
// This must be in sync with FlowGraphCompiler::CatchEntryRegForVariable.
+ ParameterInstr* param = defn->AsParameter();
intptr_t slot_index = param->index();
AssignSafepoints(defn, range);
range->finger()->Initialize(range);
@@ -666,8 +652,8 @@
SplitInitialDefinitionAt(range, block->lifetime_position() + 2);
ConvertAllUses(range);
BlockLocation(Location::RegisterLocation(slot_index), 0, kMaxPosition);
- return;
- } else if (ConstantInstr* constant = defn->AsConstant()) {
+ } else {
+ ConstantInstr* constant = defn->AsConstant();
ASSERT(constant != NULL);
range->set_assigned_location(Location::Constant(constant));
range->set_spill_slot(Location::Constant(constant));
@@ -682,11 +668,13 @@
CompleteRange(tail, Location::kRegister);
}
ConvertAllUses(range);
- return;
-#endif // defined(TARGET_ARCH_DBC)
}
+ return;
}
+#endif
+ // Save the range end because it may change below.
+ intptr_t range_end = range->End();
if (defn->IsParameter()) {
ParameterInstr* param = defn->AsParameter();
intptr_t slot_index = param->index();
@@ -717,14 +705,16 @@
Location loc;
#if defined(TARGET_ARCH_DBC)
loc = Location::ArgumentsDescriptorLocation();
+ range->set_assigned_location(loc);
#else
loc = Location::RegisterLocation(ARGS_DESC_REG);
-#endif // defined(TARGET_ARCH_DBC)
range->set_assigned_location(loc);
+#endif // defined(TARGET_ARCH_DBC)
if (loc.IsRegister()) {
AssignSafepoints(defn, range);
if (range->End() > kNormalEntryPos) {
- SplitInitialDefinitionAt(range, kNormalEntryPos);
+ LiveRange* tail = range->SplitAt(kNormalEntryPos);
+ CompleteRange(tail, Location::kRegister);
}
ConvertAllUses(range);
return;
@@ -1973,15 +1963,7 @@
}
}
- while (idx > spill_slots_.length()) {
- spill_slots_.Add(kMaxPosition);
- quad_spill_slots_.Add(false);
- untagged_spill_slots_.Add(false);
- }
-
if (idx == spill_slots_.length()) {
- idx = spill_slots_.length();
-
// No free spill slot found. Allocate a new one.
spill_slots_.Add(0);
quad_spill_slots_.Add(need_quad);
diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc
index 44c88ee..a01abb2 100644
--- a/runtime/vm/compiler/backend/locations.cc
+++ b/runtime/vm/compiler/backend/locations.cc
@@ -180,17 +180,8 @@
}
UNREACHABLE();
#if TARGET_ARCH_DBC
- case kSpecialDbcRegister:
- switch (payload()) {
- case kArgsDescriptorReg:
- return "ArgDescReg";
- case kExceptionReg:
- return "ExceptionReg";
- case kStackTraceReg:
- return "StackTraceReg";
- default:
- UNREACHABLE();
- }
+ case kArgsDescRegister:
+ return "ArgDesc";
#endif
default:
if (IsConstant()) {
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index fd4d576..f6ffbab 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -62,14 +62,6 @@
static const uword kLocationTagMask = 0x3;
public:
-#if defined(TARGET_ARCH_DBC)
- enum SpecialDbcRegister{
- kArgsDescriptorReg,
- kExceptionReg,
- kStackTraceReg,
- };
-#endif
-
// Constant payload can overlap with kind field so Kind values
// have to be chosen in a way that their last 2 bits are never
// the same as kConstantTag or kPairLocationTag.
@@ -107,9 +99,9 @@
kFpuRegister = 12,
#ifdef TARGET_ARCH_DBC
- // We use this to signify a special `Location` where the different
- // [SpecialDbcRegister]s can be found on DBC.
- kSpecialDbcRegister = 15,
+ // We use this to signify a special `Location` where the arguments
+ // descriptor can be found on DBC.
+ kArgsDescRegister = 15,
#endif
};
@@ -138,9 +130,8 @@
COMPILE_ASSERT((kFpuRegister & kLocationTagMask) != kPairLocationTag);
#ifdef TARGET_ARCH_DBC
- COMPILE_ASSERT((kSpecialDbcRegister & kLocationTagMask) != kConstantTag);
- COMPILE_ASSERT((kSpecialDbcRegister & kLocationTagMask) !=
- kPairLocationTag);
+ COMPILE_ASSERT((kArgsDescRegister & kLocationTagMask) != kConstantTag);
+ COMPILE_ASSERT((kArgsDescRegister & kLocationTagMask) != kPairLocationTag);
#endif
// Verify tags and tagmask.
@@ -256,44 +247,12 @@
bool IsFpuRegister() const { return kind() == kFpuRegister; }
+#ifdef TARGET_ARCH_DBC
static Location ArgumentsDescriptorLocation() {
-#ifdef TARGET_ARCH_DBC
- return Location(kSpecialDbcRegister, kArgsDescriptorReg);
-#else
- return Location::RegisterLocation(ARGS_DESC_REG);
-#endif
+ return Location(kArgsDescRegister, 0);
}
- static Location ExceptionLocation() {
-#ifdef TARGET_ARCH_DBC
- return Location(kSpecialDbcRegister, kExceptionReg);
-#else
- return Location::RegisterLocation(kExceptionObjectReg);
-#endif
- }
-
- static Location StackTraceLocation() {
-#ifdef TARGET_ARCH_DBC
- return Location(kSpecialDbcRegister, kStackTraceReg);
-#else
- return Location::RegisterLocation(kStackTraceObjectReg);
-#endif
- }
-
-#ifdef TARGET_ARCH_DBC
- bool IsArgsDescRegister() const {
- return IsSpecialDbcRegister(kArgsDescriptorReg);
- }
- bool IsExceptionRegister() const {
- return IsSpecialDbcRegister(kExceptionReg);
- }
- bool IsStackTraceRegister() const {
- return IsSpecialDbcRegister(kStackTraceReg);
- }
-
- bool IsSpecialDbcRegister(SpecialDbcRegister reg) const {
- return kind() == kSpecialDbcRegister && payload() == reg;
- }
+ bool IsArgsDescRegister() const { return kind() == kArgsDescRegister; }
#endif
FpuRegister fpu_reg() const {
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 449ace0..2623846 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -3157,9 +3157,12 @@
// not tracked in the environment anyway.
const intptr_t parameter_count = flow_graph->num_direct_parameters();
- cdefs[catch_entry->raw_exception_var()->BitIndexIn(parameter_count)] = NULL;
- cdefs[catch_entry->raw_stacktrace_var()->BitIndexIn(parameter_count)] =
- NULL;
+ if (!catch_entry->exception_var().is_captured()) {
+ cdefs[catch_entry->exception_var().BitIndexIn(parameter_count)] = NULL;
+ }
+ if (!catch_entry->stacktrace_var().is_captured()) {
+ cdefs[catch_entry->stacktrace_var().BitIndexIn(parameter_count)] = NULL;
+ }
for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
!block_it.Done(); block_it.Advance()) {
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index efb2d42..6b9c5bb 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1051,10 +1051,6 @@
return CompileType::FromCid(kTypeArgumentsCid);
case kArgDescriptor:
return CompileType::FromCid(kImmutableArrayCid);
- case kException:
- return CompileType::Dynamic();
- case kStackTrace:
- return CompileType::FromCid(kStackTraceCid);
}
UNREACHABLE();
return CompileType::Dynamic();
diff --git a/runtime/vm/compiler/frontend/flow_graph_builder.cc b/runtime/vm/compiler/frontend/flow_graph_builder.cc
index aa65f19..c26f4a6 100644
--- a/runtime/vm/compiler/frontend/flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/flow_graph_builder.cc
@@ -4116,8 +4116,7 @@
owner()->AllocateBlockId(), catch_handler_index, owner()->graph_entry(),
catch_block->handler_types(), try_handler_index,
catch_block->exception_var(), catch_block->stacktrace_var(),
- catch_block->needs_stacktrace(), owner()->GetNextDeoptId(),
- &catch_block->exception_var(), &catch_block->stacktrace_var());
+ catch_block->needs_stacktrace(), owner()->GetNextDeoptId());
owner()->AddCatchEntry(catch_entry);
AppendFragment(catch_entry, for_catch);
@@ -4163,8 +4162,7 @@
owner()->AllocateBlockId(), original_handler_index,
owner()->graph_entry(), types, catch_handler_index,
catch_block->exception_var(), catch_block->stacktrace_var(),
- catch_block->needs_stacktrace(), owner()->GetNextDeoptId(),
- &catch_block->exception_var(), &catch_block->stacktrace_var());
+ catch_block->needs_stacktrace(), owner()->GetNextDeoptId());
owner()->AddCatchEntry(finally_entry);
AppendFragment(finally_entry, for_finally);
}
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 95b1c04..4c13e12 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -2155,9 +2155,6 @@
ExitScope(builder_->reader_.min_position(),
builder_->reader_.max_position());
}
-
- FinalizeCatchVariables();
-
--depth_.catch_;
return;
}
@@ -2175,8 +2172,6 @@
VisitStatement(); // read finalizer.
- FinalizeCatchVariables();
-
--depth_.catch_;
return;
}
@@ -2601,30 +2596,6 @@
variables->Add(v);
}
-void StreamingScopeBuilder::FinalizeExceptionVariable(
- GrowableArray<LocalVariable*>* variables,
- GrowableArray<LocalVariable*>* raw_variables,
- const String& symbol,
- intptr_t nesting_depth) {
- // No need to create variables for try/catch-statements inside
- // nested functions.
- if (depth_.function_ > 0) return;
-
- LocalVariable* variable = (*variables)[nesting_depth - 1];
- LocalVariable* raw_variable;
- if (variable->is_captured()) {
- raw_variable =
- new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
- symbol, AbstractType::dynamic_type());
- const bool ok = scope_->AddVariable(raw_variable);
- ASSERT(ok);
- } else {
- raw_variable = variable;
- }
- raw_variables->EnsureLength(nesting_depth, nullptr);
- (*raw_variables)[nesting_depth - 1] = raw_variable;
-}
-
void StreamingScopeBuilder::AddTryVariables() {
AddExceptionVariable(&result_->catch_context_variables,
":saved_try_context_var", depth_.try_);
@@ -2637,16 +2608,6 @@
depth_.catch_);
}
-void StreamingScopeBuilder::FinalizeCatchVariables() {
- const intptr_t unique_id = result_->raw_variable_counter_++;
- FinalizeExceptionVariable(
- &result_->exception_variables, &result_->raw_exception_variables,
- GenerateName(":raw_exception", unique_id), depth_.catch_);
- FinalizeExceptionVariable(
- &result_->stack_trace_variables, &result_->raw_stack_trace_variables,
- GenerateName(":raw_stacktrace", unique_id), depth_.catch_);
-}
-
void StreamingScopeBuilder::AddIteratorVariable() {
if (depth_.function_ > 0) return;
if (result_->iterator_variables.length() >= depth_.for_in_) return;
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 15a54cc..4b71c8f 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -822,14 +822,8 @@
const char* prefix,
intptr_t nesting_depth);
- void FinalizeExceptionVariable(GrowableArray<LocalVariable*>* variables,
- GrowableArray<LocalVariable*>* raw_variables,
- const String& symbol,
- intptr_t nesting_depth);
-
void AddTryVariables();
void AddCatchVariables();
- void FinalizeCatchVariables();
void AddIteratorVariable();
void AddSwitchVariable();
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 8470128..ee05a9c 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1178,54 +1178,19 @@
intptr_t handler_index,
bool needs_stacktrace,
bool is_synthesized) {
- LocalVariable* exception_var = CurrentException();
- LocalVariable* stacktrace_var = CurrentStackTrace();
- LocalVariable* raw_exception_var = CurrentRawException();
- LocalVariable* raw_stacktrace_var = CurrentRawStackTrace();
-
+ ASSERT(CurrentException()->is_captured() ==
+ CurrentStackTrace()->is_captured());
+ const bool should_restore_closure_context =
+ CurrentException()->is_captured() || CurrentCatchContext()->is_captured();
CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr(
TokenPosition::kNoSource, // Token position of catch block.
is_synthesized, // whether catch block was synthesized by FE compiler
AllocateBlockId(), CurrentTryIndex(), graph_entry_, handler_types,
- handler_index, *exception_var, *stacktrace_var, needs_stacktrace,
- GetNextDeoptId(), raw_exception_var, raw_stacktrace_var);
+ handler_index, *CurrentException(), *CurrentStackTrace(),
+ needs_stacktrace, GetNextDeoptId(), should_restore_closure_context);
graph_entry_->AddCatchEntry(entry);
-
Fragment instructions(entry);
- // 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.
- const bool should_restore_closure_context =
- CurrentException()->is_captured() || CurrentCatchContext()->is_captured();
- LocalVariable* context_variable = parsed_function_->current_context_var();
- if (should_restore_closure_context) {
- ASSERT(parsed_function_->function().IsClosureFunction());
- LocalScope* scope = parsed_function_->node_sequence()->scope();
-
- LocalVariable* closure_parameter = scope->VariableAt(0);
- ASSERT(!closure_parameter->is_captured());
- instructions += LoadLocal(closure_parameter);
- instructions += LoadField(Closure::context_offset());
- instructions += StoreLocal(TokenPosition::kNoSource, context_variable);
- instructions += Drop();
- }
-
- if (exception_var->is_captured()) {
- instructions += LoadLocal(context_variable);
- instructions += LoadLocal(raw_exception_var);
- instructions +=
- StoreInstanceField(TokenPosition::kNoSource,
- Context::variable_offset(exception_var->index()));
- }
- if (stacktrace_var->is_captured()) {
- instructions += LoadLocal(context_variable);
- instructions += LoadLocal(raw_stacktrace_var);
- instructions +=
- StoreInstanceField(TokenPosition::kNoSource,
- Context::variable_offset(stacktrace_var->index()));
- }
-
// :saved_try_context_var can be captured in the context of
// of the closure, in this case CatchBlockEntryInstr restores
// :current_context_var to point to closure context in the
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 0181499..17ca4fa 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -485,8 +485,7 @@
finally_return_variable(NULL),
setter_value(NULL),
yield_jump_variable(NULL),
- yield_context_variable(NULL),
- raw_variable_counter_(0) {}
+ yield_context_variable(NULL) {}
IntMap<LocalVariable*> locals;
IntMap<LocalScope*> scopes;
@@ -523,12 +522,6 @@
GrowableArray<LocalVariable*> stack_trace_variables;
GrowableArray<LocalVariable*> catch_context_variables;
- // These are used to access the raw exception/stacktrace variables (and are
- // used to put them into the captured variables in the context).
- GrowableArray<LocalVariable*> raw_exception_variables;
- GrowableArray<LocalVariable*> raw_stack_trace_variables;
- intptr_t raw_variable_counter_;
-
// For-in iterators, one per for-in nesting level.
GrowableArray<LocalVariable*> iterator_variables;
};
@@ -878,12 +871,6 @@
LocalVariable* CurrentStackTrace() {
return scopes_->stack_trace_variables[catch_depth_ - 1];
}
- LocalVariable* CurrentRawException() {
- return scopes_->raw_exception_variables[catch_depth_ - 1];
- }
- LocalVariable* CurrentRawStackTrace() {
- return scopes_->raw_stack_trace_variables[catch_depth_ - 1];
- }
LocalVariable* CurrentCatchContext() {
return scopes_->catch_context_variables[try_depth_];
}
diff --git a/tests/language_2/vm/regress_31946_test.dart b/tests/language_2/vm/regress_31946_test.dart
deleted file mode 100644
index 19554a0..0000000
--- a/tests/language_2/vm/regress_31946_test.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--no_background_compilation --optimization_counter_threshold=10
-
-import 'dart:async';
-
-import 'package:expect/expect.dart';
-
-var root = [];
-var tests = <dynamic>[
- () async {},
- () async {
- await new Future.value();
- root.singleWhere((f) => f.name == 'optimizedFunction');
- },
-];
-
-main(args) async {
- for (int i = 0; i < 100; ++i) {
- int exceptions = 0;
- for (final test in tests) {
- try {
- await test();
- } on StateError {
- exceptions++;
- }
- }
- Expect.isTrue(exceptions == 1);
- }
-}