[VM interpreter] Generation of pc descriptors, exception handlers for bytecode.
Fixes in stack unwinding and frame iteration.
Change-Id: Ic67eb5727512138cbfa9313094d48e21384b220c
Reviewed-on: https://dart-review.googlesource.com/59520
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 23c595e..b100719 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
+#include "vm/code_descriptors.h"
#include "vm/compiler/aot/precompiler.h"
#include "vm/compiler/assembler/disassembler_kbc.h"
#include "vm/compiler/frontend/prologue_builder.h"
@@ -1168,7 +1169,7 @@
elem = pool.ObjectAt(elem_index);
array.SetAt(j, elem);
}
- obj = H.Canonicalize(Array::Cast(obj));
+ obj = H.Canonicalize(Array::Cast(array));
ASSERT(!obj.IsNull());
} break;
case ConstantPoolTag::kInstance: {
@@ -1354,37 +1355,62 @@
}
void BytecodeMetadataHelper::ReadExceptionsTable(const Code& bytecode) {
- const ObjectPool& pool =
- ObjectPool::Handle(builder_->zone_, bytecode.object_pool());
- AbstractType& handled_type = AbstractType::Handle(builder_->zone_);
+ const intptr_t try_block_count = builder_->reader_.ReadListLength();
+ if (try_block_count > 0) {
+ const ObjectPool& pool =
+ ObjectPool::Handle(builder_->zone_, bytecode.object_pool());
+ AbstractType& handler_type = AbstractType::Handle(builder_->zone_);
+ Array& handler_types = Array::Handle(builder_->zone_);
+ DescriptorList* pc_descriptors_list =
+ new (builder_->zone_) DescriptorList(64);
+ ExceptionHandlerList* exception_handlers_list =
+ new (builder_->zone_) ExceptionHandlerList();
- // Encoding of ExceptionsTable is described in
- // pkg/vm/lib/bytecode/exceptions.dart.
- intptr_t try_block_count = builder_->reader_.ReadListLength();
- for (intptr_t i = 0; i < try_block_count; i++) {
- intptr_t outer_try_index_plus1 = builder_->reader_.ReadUInt();
- intptr_t outer_try_index = outer_try_index_plus1 - 1;
- USE(outer_try_index);
- intptr_t start_pc = builder_->reader_.ReadUInt();
- USE(start_pc);
- intptr_t end_pc = builder_->reader_.ReadUInt();
- USE(end_pc);
- intptr_t handler_pc = builder_->reader_.ReadUInt();
- USE(handler_pc);
- uint8_t flags = builder_->reader_.ReadByte();
- // flagNeedsStackTrace = 1 << 0;
- // flagIsSynthetic = 1 << 1;
- USE(flags);
+ // Encoding of ExceptionsTable is described in
+ // pkg/vm/lib/bytecode/exceptions.dart.
+ for (intptr_t try_index = 0; try_index < try_block_count; try_index++) {
+ intptr_t outer_try_index_plus1 = builder_->reader_.ReadUInt();
+ intptr_t outer_try_index = outer_try_index_plus1 - 1;
+ intptr_t start_pc = builder_->reader_.ReadUInt();
+ intptr_t end_pc = builder_->reader_.ReadUInt();
+ intptr_t handler_pc = builder_->reader_.ReadUInt();
+ uint8_t flags = builder_->reader_.ReadByte();
+ const uint8_t kFlagNeedsStackTrace = 1 << 0;
+ const uint8_t kFlagIsSynthetic = 1 << 1;
+ const bool needs_stacktrace = (flags & kFlagNeedsStackTrace) != 0;
+ const bool is_generated = (flags & kFlagIsSynthetic) != 0;
+ intptr_t type_count = builder_->reader_.ReadListLength();
+ ASSERT(type_count > 0);
+ handler_types = Array::New(type_count, Heap::kOld);
+ for (intptr_t i = 0; i < type_count; i++) {
+ intptr_t type_index = builder_->reader_.ReadUInt();
+ ASSERT(type_index < pool.Length());
+ handler_type ^= pool.ObjectAt(type_index);
+ handler_types.SetAt(i, handler_type);
+ }
+ pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, start_pc,
+ Thread::kNoDeoptId,
+ TokenPosition::kNoSource, try_index);
+ pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, end_pc,
+ Thread::kNoDeoptId,
+ TokenPosition::kNoSource, -1);
- intptr_t type_count = builder_->reader_.ReadListLength();
- for (intptr_t j = 0; j < type_count; j++) {
- intptr_t type_index = builder_->reader_.ReadUInt();
- ASSERT(type_index < pool.Length());
- handled_type ^= pool.ObjectAt(type_index);
+ exception_handlers_list->AddHandler(
+ try_index, outer_try_index, handler_pc, TokenPosition::kNoSource,
+ is_generated, handler_types, needs_stacktrace);
}
+ const PcDescriptors& descriptors = PcDescriptors::Handle(
+ builder_->zone_,
+ pc_descriptors_list->FinalizePcDescriptors(bytecode.PayloadStart()));
+ bytecode.set_pc_descriptors(descriptors);
+ const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
+ builder_->zone_, exception_handlers_list->FinalizeExceptionHandlers(
+ bytecode.PayloadStart()));
+ bytecode.set_exception_handlers(handlers);
+ } else {
+ bytecode.set_pc_descriptors(Object::empty_descriptors());
+ bytecode.set_exception_handlers(Object::empty_exception_handlers());
}
- // TODO(regis): Generate exception handlers (as well as pc descriptors)
- // and store in bytecode: bytecode.set_exception_handlers(exception_handlers);
}
#endif // defined(DART_USE_INTERPRETER)
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index fdbc665..c61a2d5 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -841,6 +841,42 @@
*SP = fp - kKBCDartFrameFixedSize;
}
+// Note: functions below are marked DART_NOINLINE to recover performance on
+// ARM where inlining these functions into the interpreter loop seemed to cause
+// some code quality issues.
+static DART_NOINLINE bool InvokeRuntime(Thread* thread,
+ Interpreter* interpreter,
+ RuntimeFunction drt,
+ const NativeArguments& args) {
+ InterpreterSetjmpBuffer buffer(interpreter);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(drt));
+ drt(args);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ thread->set_top_exit_frame_info(0);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static DART_NOINLINE bool InvokeNative(Thread* thread,
+ Interpreter* interpreter,
+ NativeFunctionWrapper wrapper,
+ Dart_NativeFunction function,
+ Dart_NativeArguments args) {
+ InterpreterSetjmpBuffer buffer(interpreter);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(function));
+ wrapper(args, function);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ thread->set_top_exit_frame_info(0);
+ return true;
+ } else {
+ return false;
+ }
+}
+
DART_NOINLINE bool Interpreter::InvokeCompiled(Thread* thread,
RawFunction* function,
RawArray* argdesc,
@@ -849,64 +885,79 @@
uint32_t** pc,
RawObject*** FP,
RawObject*** SP) {
- InterpreterSetjmpBuffer buffer(this);
- if (!setjmp(buffer.buffer_)) {
#if defined(USING_SIMULATOR) || defined(TARGET_ARCH_DBC)
- // TODO(regis): Revisit.
- UNIMPLEMENTED();
+ // TODO(regis): Revisit.
+ UNIMPLEMENTED();
#endif
- ASSERT(thread->vm_tag() == VMTag::kDartTagId);
- ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
- if (!Function::HasCode(function)) {
- ASSERT(!Function::HasBytecode(function));
- call_top[1] = 0; // Code result.
- call_top[2] = function;
- CallRuntime(thread, *FP, call_top + 3, *pc, 1, call_top + 2, call_top + 1,
- reinterpret_cast<uword>(DRT_CompileFunction));
+ if (!Function::HasCode(function)) {
+ ASSERT(!Function::HasBytecode(function));
+ call_top[1] = 0; // Code result.
+ call_top[2] = function;
+ Exit(thread, *FP, call_top + 3, *pc);
+ NativeArguments native_args(thread, 1, call_top + 2, call_top + 1);
+ if (!InvokeRuntime(thread, this, DRT_CompileFunction, native_args)) {
+ return false;
}
- if (Function::HasCode(function)) {
- RawCode* code = function->ptr()->code_;
- ASSERT(code != StubCode::LazyCompile_entry()->code());
- // TODO(regis): Once we share the same stack, try to invoke directly.
-
- // On success, returns a RawInstance. On failure, a RawError.
- typedef RawObject* (*invokestub)(RawCode * code, RawArray * argdesc,
- RawObject * *arg0, Thread * thread);
- invokestub entrypoint = reinterpret_cast<invokestub>(
- StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint());
- RawObject* result = entrypoint(code, argdesc, call_base, thread);
-
- // Pop args and push result.
- *SP = call_base;
- **SP = result;
- } else {
- ASSERT(Function::HasBytecode(function));
- // Bytecode was loaded in the above compilation step.
- // Stay in interpreter.
- RawCode* bytecode = function->ptr()->bytecode_;
- RawObject** callee_fp = call_top + kKBCDartFrameFixedSize;
- callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
- callee_fp[kKBCSavedCallerPcSlotFromFp] =
- reinterpret_cast<RawObject*>(*pc);
- callee_fp[kKBCSavedCallerFpSlotFromFp] =
- reinterpret_cast<RawObject*>(*FP);
- pp_ = bytecode->ptr()->object_pool_;
- *pc = reinterpret_cast<uint32_t*>(bytecode->ptr()->entry_point_);
- pc_ = reinterpret_cast<uword>(*pc); // For the profiler.
- *FP = callee_fp;
- *SP = *FP - 1;
- // Dispatch will interpret function.
- }
- ASSERT(thread->vm_tag() == VMTag::kDartTagId);
- ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
- thread->set_top_exit_frame_info(0);
- return true;
- } else {
- return false;
}
+ if (Function::HasCode(function)) {
+ RawCode* code = function->ptr()->code_;
+ ASSERT(code != StubCode::LazyCompile_entry()->code());
+ // TODO(regis): Once we share the same stack, try to invoke directly.
+
+ // On success, returns a RawInstance. On failure, a RawError.
+ typedef RawObject* (*invokestub)(RawCode * code, RawArray * argdesc,
+ RawObject * *arg0, Thread * thread);
+ invokestub entrypoint = reinterpret_cast<invokestub>(
+ StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint());
+ Exit(thread, *FP, call_top + 1, *pc);
+ {
+ InterpreterSetjmpBuffer buffer(this);
+ if (!setjmp(buffer.buffer_)) {
+ thread->set_vm_tag(reinterpret_cast<uword>(entrypoint));
+ RawObject* result = entrypoint(code, argdesc, call_base, thread);
+ thread->set_vm_tag(VMTag::kDartTagId);
+ thread->set_top_exit_frame_info(0);
+ ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
+
+ // It is legit to call the constructor of an error object, however a
+ // result of class UnhandledException must be propagated.
+ if (result->IsHeapObject() &&
+ result->GetClassId() == kUnhandledExceptionCid) {
+ // TODO(regis): Shoudn't the callee have set these and thrown?
+ special_[kExceptionSpecialIndex] = result;
+ special_[kStackTraceSpecialIndex] = Object::null();
+ return false;
+ }
+
+ // Pop args and push result.
+ *SP = call_base;
+ **SP = result;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ ASSERT(Function::HasBytecode(function));
+ // Bytecode was loaded in the above compilation step.
+ // Stay in interpreter.
+ RawCode* bytecode = function->ptr()->bytecode_;
+ RawObject** callee_fp = call_top + kKBCDartFrameFixedSize;
+ callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
+ callee_fp[kKBCSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
+ callee_fp[kKBCSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP);
+ pp_ = bytecode->ptr()->object_pool_;
+ *pc = reinterpret_cast<uint32_t*>(bytecode->ptr()->entry_point_);
+ pc_ = reinterpret_cast<uword>(*pc); // For the profiler.
+ *FP = callee_fp;
+ *SP = *FP - 1;
+ // Dispatch will interpret function.
+ ASSERT(thread->vm_tag() == VMTag::kDartTagId);
+ ASSERT(thread->top_exit_frame_info() == 0);
+ return true;
}
-DART_FORCE_INLINE void Interpreter::Invoke(Thread* thread,
+DART_FORCE_INLINE bool Interpreter::Invoke(Thread* thread,
RawObject** call_base,
RawObject** call_top,
uint32_t** pc,
@@ -923,25 +974,19 @@
#endif
if (Function::HasCode(function) || !Function::HasBytecode(function)) {
// TODO(regis): If the function is a dispatcher, execute the dispatch here.
- if (!InvokeCompiled(thread, function, argdesc_, call_base, call_top, pc, FP,
- SP)) {
- // Handle exception
- *FP = reinterpret_cast<RawObject**>(fp_);
- *pc = reinterpret_cast<uint32_t*>(pc_);
- pp_ = InterpreterHelpers::FrameCode(*FP)->ptr()->object_pool_;
- *SP = *FP - 1;
- }
- } else {
- RawCode* bytecode = function->ptr()->bytecode_;
- callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
- callee_fp[kKBCSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
- callee_fp[kKBCSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP);
- pp_ = bytecode->ptr()->object_pool_;
- *pc = reinterpret_cast<uint32_t*>(bytecode->ptr()->entry_point_);
- pc_ = reinterpret_cast<uword>(*pc); // For the profiler.
- *FP = callee_fp;
- *SP = *FP - 1;
+ return InvokeCompiled(thread, function, argdesc_, call_base, call_top, pc,
+ FP, SP);
}
+ RawCode* bytecode = function->ptr()->bytecode_;
+ callee_fp[kKBCPcMarkerSlotFromFp] = bytecode;
+ callee_fp[kKBCSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
+ callee_fp[kKBCSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP);
+ pp_ = bytecode->ptr()->object_pool_;
+ *pc = reinterpret_cast<uint32_t*>(bytecode->ptr()->entry_point_);
+ pc_ = reinterpret_cast<uword>(*pc); // For the profiler.
+ *FP = callee_fp;
+ *SP = *FP - 1;
+ return true;
}
void Interpreter::InlineCacheMiss(int checked_args,
@@ -978,7 +1023,7 @@
result, reinterpret_cast<uword>(handler));
}
-DART_FORCE_INLINE void Interpreter::InstanceCall1(Thread* thread,
+DART_FORCE_INLINE bool Interpreter::InstanceCall1(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** top,
@@ -1020,10 +1065,10 @@
*pc, *FP, *SP);
}
- Invoke(thread, call_base, top, pc, FP, SP);
+ return Invoke(thread, call_base, top, pc, FP, SP);
}
-DART_FORCE_INLINE void Interpreter::InstanceCall2(Thread* thread,
+DART_FORCE_INLINE bool Interpreter::InstanceCall2(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** top,
@@ -1068,7 +1113,7 @@
*pc, *FP, *SP);
}
- Invoke(thread, call_base, top, pc, FP, SP);
+ return Invoke(thread, call_base, top, pc, FP, SP);
}
DART_FORCE_INLINE void Interpreter::PrepareForTailCall(
@@ -1089,42 +1134,6 @@
argdesc_ = args_desc;
}
-// Note: functions below are marked DART_NOINLINE to recover performance on
-// ARM where inlining these functions into the interpreter loop seemed to cause
-// some code quality issues.
-static DART_NOINLINE bool InvokeRuntime(Thread* thread,
- Interpreter* interpreter,
- RuntimeFunction drt,
- const NativeArguments& args) {
- InterpreterSetjmpBuffer buffer(interpreter);
- if (!setjmp(buffer.buffer_)) {
- thread->set_vm_tag(reinterpret_cast<uword>(drt));
- drt(args);
- thread->set_vm_tag(VMTag::kDartTagId);
- thread->set_top_exit_frame_info(0);
- return true;
- } else {
- return false;
- }
-}
-
-static DART_NOINLINE bool InvokeNative(Thread* thread,
- Interpreter* interpreter,
- NativeFunctionWrapper wrapper,
- Dart_NativeFunction function,
- Dart_NativeArguments args) {
- InterpreterSetjmpBuffer buffer(interpreter);
- if (!setjmp(buffer.buffer_)) {
- thread->set_vm_tag(reinterpret_cast<uword>(function));
- wrapper(args, function);
- thread->set_vm_tag(VMTag::kDartTagId);
- thread->set_top_exit_frame_info(0);
- return true;
- } else {
- return false;
- }
-}
-
// Note:
// All macro helpers are intended to be used only inside Interpreter::Call.
@@ -1965,7 +1974,9 @@
RawObject** call_base = SP - argc;
RawObject** call_top = SP; // *SP contains function
argdesc_ = static_cast<RawArray*>(LOAD_CONSTANT(rD));
- Invoke(thread, call_base, call_top, &pc, &FP, &SP);
+ if (!Invoke(thread, call_base, call_top, &pc, &FP, &SP)) {
+ HANDLE_EXCEPTION;
+ }
}
DISPATCH();
@@ -1977,7 +1988,9 @@
RawObject** call_base = SP - argc;
RawObject** call_top = SP; // *SP contains function
argdesc_ = static_cast<RawArray*>(LOAD_CONSTANT(rD));
- Invoke(thread, call_base, call_top, &pc, &FP, &SP);
+ if (!Invoke(thread, call_base, call_top, &pc, &FP, &SP)) {
+ HANDLE_EXCEPTION;
+ }
DISPATCH();
}
@@ -2001,8 +2014,10 @@
RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx));
InterpreterHelpers::IncrementUsageCounter(
RAW_CAST(Function, icdata->ptr()->owner_));
- InstanceCall1(thread, icdata, call_base, call_top, &pc, &FP, &SP,
- false /* optimized */);
+ if (!InstanceCall1(thread, icdata, call_base, call_top, &pc, &FP, &SP,
+ false /* optimized */)) {
+ HANDLE_EXCEPTION;
+ }
}
DISPATCH();
@@ -2026,8 +2041,10 @@
RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx));
InterpreterHelpers::IncrementUsageCounter(
RAW_CAST(Function, icdata->ptr()->owner_));
- InstanceCall2(thread, icdata, call_base, call_top, &pc, &FP, &SP,
- false /* optimized */);
+ if (!InstanceCall2(thread, icdata, call_base, call_top, &pc, &FP, &SP,
+ false /* optimized */)) {
+ HANDLE_EXCEPTION;
+ }
}
DISPATCH();
@@ -2045,8 +2062,10 @@
RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx));
InterpreterHelpers::IncrementUsageCounter(FrameFunction(FP));
- InstanceCall1(thread, icdata, call_base, call_top, &pc, &FP, &SP,
- true /* optimized */);
+ if (!InstanceCall1(thread, icdata, call_base, call_top, &pc, &FP, &SP,
+ true /* optimized */)) {
+ HANDLE_EXCEPTION;
+ }
}
DISPATCH();
@@ -2064,8 +2083,10 @@
RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx));
InterpreterHelpers::IncrementUsageCounter(FrameFunction(FP));
- InstanceCall2(thread, icdata, call_base, call_top, &pc, &FP, &SP,
- true /* optimized */);
+ if (!InstanceCall2(thread, icdata, call_base, call_top, &pc, &FP, &SP,
+ true /* optimized */)) {
+ HANDLE_EXCEPTION;
+ }
}
DISPATCH();
@@ -2990,7 +3011,7 @@
}
{
- BYTECODE(StoreFieldTOS, A_D);
+ BYTECODE(StoreFieldTOS, __D);
const uword offset_in_words =
static_cast<uword>(Smi::Value(RAW_CAST(Smi, LOAD_CONSTANT(rD))));
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index 517cbaa..0a87cc4 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -132,7 +132,7 @@
RawObject** result,
uword target);
- void Invoke(Thread* thread,
+ bool Invoke(Thread* thread,
RawObject** call_base,
RawObject** call_top,
uint32_t** pc,
@@ -163,7 +163,7 @@
RawObject** FP,
RawObject** SP);
- void InstanceCall1(Thread* thread,
+ bool InstanceCall1(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** call_top,
@@ -172,7 +172,7 @@
RawObject*** SP,
bool optimized);
- void InstanceCall2(Thread* thread,
+ bool InstanceCall2(Thread* thread,
RawICData* icdata,
RawObject** call_base,
RawObject** call_top,
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index 7e4ca4e..21d5e11 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -2667,7 +2667,7 @@
}
{
- BYTECODE(StoreFieldTOS, A_D);
+ BYTECODE(StoreFieldTOS, __D);
const uint16_t offset_in_words = rD;
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
RawObject* value = reinterpret_cast<RawObject*>(SP[0]);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 9cec45e..63e6fb4 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -325,19 +325,44 @@
PcDescriptors& descriptors = reused_pc_descriptors_handle.Handle();
descriptors = code.pc_descriptors();
PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
- while (iter.MoveNext()) {
- const intptr_t current_try_index = iter.TryIndex();
- if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
- ExceptionHandlerInfo handler_info;
- handlers.GetHandlerInfo(current_try_index, &handler_info);
- *handler_pc = code.PayloadStart() + handler_info.handler_pc_offset;
- *needs_stacktrace = handler_info.needs_stacktrace;
- *has_catch_all = handler_info.has_catch_all;
- cache->Insert(pc(), handler_info);
- return true;
+ intptr_t try_index = -1;
+ if (is_interpreted()) {
+ while (iter.MoveNext()) {
+ // PC descriptors for try blocks in bytecode are generated in pairs,
+ // marking start and end of a try block.
+ // See BytecodeMetadataHelper::ReadExceptionsTable for details.
+ const intptr_t current_try_index = iter.TryIndex();
+ const uword start_pc = iter.PcOffset();
+ if (pc_offset < start_pc) {
+ break;
+ }
+ const bool has_next = iter.MoveNext();
+ ASSERT(has_next);
+ const uword end_pc = iter.PcOffset();
+ if (start_pc <= pc_offset && pc_offset < end_pc) {
+ ASSERT(try_index < current_try_index);
+ try_index = current_try_index;
+ }
+ }
+ } else {
+ while (iter.MoveNext()) {
+ const intptr_t current_try_index = iter.TryIndex();
+ if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
+ try_index = current_try_index;
+ break;
+ }
}
}
- return false;
+ if (try_index == -1) {
+ return false;
+ }
+ ExceptionHandlerInfo handler_info;
+ handlers.GetHandlerInfo(try_index, &handler_info);
+ *handler_pc = code.PayloadStart() + handler_info.handler_pc_offset;
+ *needs_stacktrace = handler_info.needs_stacktrace;
+ *has_catch_all = handler_info.has_catch_all;
+ cache->Insert(pc(), handler_info);
+ return true;
}
TokenPosition StackFrame::GetTokenPos() const {