| Index: runtime/vm/exceptions.cc
|
| diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
|
| index 0ee20ad2f34ddbf796c25f926172cf0440938d47..6e731c8d4d79182ecf10a32cd83d024ffc04f19f 100644
|
| --- a/runtime/vm/exceptions.cc
|
| +++ b/runtime/vm/exceptions.cc
|
| @@ -10,7 +10,9 @@
|
|
|
| #include "vm/dart_api_impl.h"
|
| #include "vm/dart_entry.h"
|
| +#include "vm/datastream.h"
|
| #include "vm/debugger.h"
|
| +#include "vm/deopt_instructions.h"
|
| #include "vm/flags.h"
|
| #include "vm/log.h"
|
| #include "vm/longjump.h"
|
| @@ -143,50 +145,203 @@ static void BuildStackTrace(StackTraceBuilder* builder) {
|
| }
|
|
|
|
|
| -// Iterate through the stack frames and try to find a frame with an
|
| -// exception handler. Once found, set the pc, sp and fp so that execution
|
| -// can continue in that frame. Sets 'needs_stacktrace' if there is no
|
| -// cath-all handler or if a stack-trace is specified in the catch.
|
| -static bool FindExceptionHandler(Thread* thread,
|
| - uword* handler_pc,
|
| - uword* handler_sp,
|
| - uword* handler_fp,
|
| - bool* needs_stacktrace) {
|
| - StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
|
| - StackFrame* frame = frames.NextFrame();
|
| - if (frame == NULL) return false; // No Dart frame.
|
| - bool handler_pc_set = false;
|
| - *needs_stacktrace = false;
|
| - bool is_catch_all = false;
|
| - uword temp_handler_pc = kUwordMax;
|
| - while (!frame->IsEntryFrame()) {
|
| - if (frame->IsDartFrame()) {
|
| - if (frame->FindExceptionHandler(thread, &temp_handler_pc,
|
| - needs_stacktrace, &is_catch_all)) {
|
| - if (!handler_pc_set) {
|
| - handler_pc_set = true;
|
| - *handler_pc = temp_handler_pc;
|
| - *handler_sp = frame->sp();
|
| - *handler_fp = frame->fp();
|
| +static RawObject** VariableAt(uword fp, int stack_slot) {
|
| +#if defined(TARGET_ARCH_DBC)
|
| + return reinterpret_cast<RawObject**>(fp + stack_slot * kWordSize);
|
| +#else
|
| + if (stack_slot < 0) {
|
| + return reinterpret_cast<RawObject**>(ParamAddress(fp, -stack_slot));
|
| + } else {
|
| + return reinterpret_cast<RawObject**>(
|
| + LocalVarAddress(fp, kFirstLocalSlotFromFp - stack_slot));
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +
|
| +class ExceptionHandlerFinder : public StackResource {
|
| + public:
|
| + explicit ExceptionHandlerFinder(Thread* thread)
|
| + : StackResource(thread), thread_(thread), cache_(NULL), metadata_(NULL) {}
|
| +
|
| + // Iterate through the stack frames and try to find a frame with an
|
| + // exception handler. Once found, set the pc, sp and fp so that execution
|
| + // can continue in that frame. Sets 'needs_stacktrace' if there is no
|
| + // cath-all handler or if a stack-trace is specified in the catch.
|
| + bool Find() {
|
| + StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
|
| + StackFrame* frame = frames.NextFrame();
|
| + if (frame == NULL) return false; // No Dart frame.
|
| + handler_pc_set_ = false;
|
| + needs_stacktrace = false;
|
| + bool is_catch_all = false;
|
| + uword temp_handler_pc = kUwordMax;
|
| + bool is_optimized = false;
|
| + code_ = NULL;
|
| + cache_ = thread_->isolate()->catch_entry_state_cache();
|
| +
|
| + while (!frame->IsEntryFrame()) {
|
| + if (frame->IsDartFrame()) {
|
| + if (frame->FindExceptionHandler(thread_, &temp_handler_pc,
|
| + &needs_stacktrace, &is_catch_all,
|
| + &is_optimized)) {
|
| + if (!handler_pc_set_) {
|
| + handler_pc_set_ = true;
|
| + handler_pc = temp_handler_pc;
|
| + handler_sp = frame->sp();
|
| + handler_fp = frame->fp();
|
| + if (is_optimized) {
|
| + pc_ = frame->pc();
|
| + code_ = &Code::Handle(frame->LookupDartCode());
|
| + CatchEntryState* state = cache_->Lookup(pc_);
|
| + if (state != NULL) cached_ = *state;
|
| +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
|
| + intptr_t num_vars = Smi::Value(code_->variables());
|
| + if (cached_.Empty()) GetMetaDataFromDeopt(num_vars, frame);
|
| +#else
|
| + if (cached_.Empty()) ReadCompressedMetaData();
|
| +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
|
| + }
|
| + }
|
| + if (needs_stacktrace || is_catch_all) {
|
| + return true;
|
| + }
|
| }
|
| - if (*needs_stacktrace || is_catch_all) {
|
| - return true;
|
| + } // if frame->IsDartFrame
|
| + frame = frames.NextFrame();
|
| + ASSERT(frame != NULL);
|
| + } // while !frame->IsEntryFrame
|
| + ASSERT(frame->IsEntryFrame());
|
| + if (!handler_pc_set_) {
|
| + handler_pc = frame->pc();
|
| + handler_sp = frame->sp();
|
| + handler_fp = frame->fp();
|
| + }
|
| + // No catch-all encountered, needs stacktrace.
|
| + needs_stacktrace = true;
|
| + return handler_pc_set_;
|
| + }
|
| +
|
| + void TrySync() {
|
| + if (code_ == NULL || !code_->is_optimized()) {
|
| + return;
|
| + }
|
| + if (!cached_.Empty()) {
|
| + // Cache hit.
|
| + TrySyncCached(&cached_);
|
| + } else {
|
| + // New cache entry.
|
| + CatchEntryState m(metadata_);
|
| + TrySyncCached(&m);
|
| + cache_->Insert(pc_, m);
|
| + }
|
| + }
|
| +
|
| + void TrySyncCached(CatchEntryState* md) {
|
| + uword fp = handler_fp;
|
| + ObjectPool* pool = NULL;
|
| + intptr_t pairs = md->Pairs();
|
| + for (int j = 0; j < pairs; j++) {
|
| + intptr_t src = md->Src(j);
|
| + intptr_t dest = md->Dest(j);
|
| + if (md->isMove(j)) {
|
| + *VariableAt(fp, dest) = *VariableAt(fp, src);
|
| + } else {
|
| + if (pool == NULL) {
|
| + pool = &ObjectPool::Handle(code_->object_pool());
|
| }
|
| + RawObject* obj = pool->ObjectAt(src);
|
| + *VariableAt(fp, dest) = obj;
|
| }
|
| - } // if frame->IsDartFrame
|
| - frame = frames.NextFrame();
|
| - ASSERT(frame != NULL);
|
| - } // while !frame->IsEntryFrame
|
| - ASSERT(frame->IsEntryFrame());
|
| - if (!handler_pc_set) {
|
| - *handler_pc = frame->pc();
|
| - *handler_sp = frame->sp();
|
| - *handler_fp = frame->fp();
|
| + }
|
| }
|
| - // No catch-all encountered, needs stacktrace.
|
| - *needs_stacktrace = true;
|
| - return handler_pc_set;
|
| -}
|
| +
|
| +#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
|
| + void ReadCompressedMetaData() {
|
| + intptr_t pc_offset = pc_ - code_->PayloadStart();
|
| + const TypedData& td = TypedData::Handle(code_->catch_entry_state_maps());
|
| + NoSafepointScope no_safepoint;
|
| + ReadStream stream(static_cast<uint8_t*>(td.DataAddr(0)), td.Length());
|
| +
|
| + bool found_metadata = false;
|
| + while (stream.PendingBytes() > 0) {
|
| + intptr_t target_pc_offset = Reader::Read(&stream);
|
| + intptr_t variables = Reader::Read(&stream);
|
| + intptr_t suffix_length = Reader::Read(&stream);
|
| + intptr_t suffix_offset = Reader::Read(&stream);
|
| + if (pc_offset == target_pc_offset) {
|
| + metadata_ = new intptr_t[2 * (variables + suffix_length) + 1];
|
| + metadata_[0] = variables + suffix_length;
|
| + for (int j = 0; j < variables; j++) {
|
| + intptr_t src = Reader::Read(&stream);
|
| + intptr_t dest = Reader::Read(&stream);
|
| + metadata_[1 + 2 * j] = src;
|
| + metadata_[2 + 2 * j] = dest;
|
| + }
|
| + ReadCompressedSuffix(&stream, suffix_offset, suffix_length, metadata_,
|
| + 2 * variables + 1);
|
| + found_metadata = true;
|
| + break;
|
| + } else {
|
| + for (intptr_t j = 0; j < 2 * variables; j++) {
|
| + Reader::Read(&stream);
|
| + }
|
| + }
|
| + }
|
| + ASSERT(found_metadata);
|
| + }
|
| +
|
| + void ReadCompressedSuffix(ReadStream* stream,
|
| + intptr_t offset,
|
| + intptr_t length,
|
| + intptr_t* target,
|
| + intptr_t target_offset) {
|
| + stream->SetPosition(offset);
|
| + Reader::Read(stream); // skip pc_offset
|
| + Reader::Read(stream); // skip variables
|
| + intptr_t suffix_length = Reader::Read(stream);
|
| + intptr_t suffix_offset = Reader::Read(stream);
|
| + intptr_t to_read = length - suffix_length;
|
| + for (int j = 0; j < to_read; j++) {
|
| + target[target_offset + 2 * j] = Reader::Read(stream);
|
| + target[target_offset + 2 * j + 1] = Reader::Read(stream);
|
| + }
|
| + if (suffix_length > 0) {
|
| + ReadCompressedSuffix(stream, suffix_offset, suffix_length, target,
|
| + target_offset + to_read * 2);
|
| + }
|
| + }
|
| +
|
| +#else
|
| + void GetMetaDataFromDeopt(intptr_t num_vars, StackFrame* frame) {
|
| + Isolate* isolate = thread_->isolate();
|
| + DeoptContext* deopt_context =
|
| + new DeoptContext(frame, *code_, DeoptContext::kDestIsAllocated, NULL,
|
| + NULL, true, false /* deoptimizing_code */);
|
| + isolate->set_deopt_context(deopt_context);
|
| +
|
| + metadata_ = deopt_context->CatchEntryState(num_vars);
|
| +
|
| + isolate->set_deopt_context(NULL);
|
| + delete deopt_context;
|
| + }
|
| +#endif // defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
|
| +
|
| + bool needs_stacktrace;
|
| + uword handler_pc;
|
| + uword handler_sp;
|
| + uword handler_fp;
|
| +
|
| + private:
|
| + typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
|
| + Thread* thread_;
|
| + CatchEntryStateCache* cache_;
|
| + Code* code_;
|
| + bool handler_pc_set_;
|
| + intptr_t* metadata_; // MetaData generated from deopt.
|
| + CatchEntryState cached_; // Value of per PC MetaData cache.
|
| + intptr_t pc_; // Current pc in the handler frame.
|
| +};
|
|
|
|
|
| static void FindErrorHandler(uword* handler_pc,
|
| @@ -391,16 +546,15 @@ static void ThrowExceptionHelper(Thread* thread,
|
| exception.raw() == isolate->object_store()->stack_overflow()) {
|
| use_preallocated_stacktrace = true;
|
| }
|
| - uword handler_pc = 0;
|
| - uword handler_sp = 0;
|
| - uword handler_fp = 0;
|
| - Instance& stacktrace = Instance::Handle(zone);
|
| - bool handler_exists = false;
|
| - bool handler_needs_stacktrace = false;
|
| // Find the exception handler and determine if the handler needs a
|
| // stacktrace.
|
| - handler_exists = FindExceptionHandler(thread, &handler_pc, &handler_sp,
|
| - &handler_fp, &handler_needs_stacktrace);
|
| + ExceptionHandlerFinder finder(thread);
|
| + bool handler_exists = finder.Find();
|
| + uword handler_pc = finder.handler_pc;
|
| + uword handler_sp = finder.handler_sp;
|
| + uword handler_fp = finder.handler_fp;
|
| + bool handler_needs_stacktrace = finder.needs_stacktrace;
|
| + Instance& stacktrace = Instance::Handle(zone);
|
| if (use_preallocated_stacktrace) {
|
| if (handler_pc == 0) {
|
| // No Dart frame.
|
| @@ -455,6 +609,7 @@ static void ThrowExceptionHelper(Thread* thread,
|
| THR_Print("%s\n", stacktrace.ToCString());
|
| }
|
| if (handler_exists) {
|
| + finder.TrySync();
|
| // Found a dart handler for the exception, jump to it.
|
| JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp,
|
| exception, stacktrace);
|
|
|