| 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); | 
|  |