| Index: runtime/vm/exceptions.cc
|
| ===================================================================
|
| --- runtime/vm/exceptions.cc (revision 19094)
|
| +++ runtime/vm/exceptions.cc (working copy)
|
| @@ -26,6 +26,106 @@
|
| const char* Exceptions::kCastErrorDstName = "type cast";
|
|
|
|
|
| +class StacktraceBuilder : public ValueObject {
|
| + public:
|
| + StacktraceBuilder() { }
|
| + virtual ~StacktraceBuilder() { }
|
| +
|
| + virtual void AddFrame(const Function& func,
|
| + const Code& code,
|
| + const Smi& offset) = 0;
|
| +};
|
| +
|
| +
|
| +class RegularStacktraceBuilder : public StacktraceBuilder {
|
| + public:
|
| + RegularStacktraceBuilder()
|
| + : func_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
|
| + code_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
|
| + pc_offset_list_(
|
| + GrowableObjectArray::Handle(GrowableObjectArray::New())) { }
|
| + ~RegularStacktraceBuilder() { }
|
| +
|
| + const GrowableObjectArray& func_list() const { return func_list_; }
|
| + const GrowableObjectArray& code_list() const { return code_list_; }
|
| + const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; }
|
| +
|
| + virtual void AddFrame(const Function& func,
|
| + const Code& code,
|
| + const Smi& offset) {
|
| + func_list_.Add(func);
|
| + code_list_.Add(code);
|
| + pc_offset_list_.Add(offset);
|
| + }
|
| +
|
| + private:
|
| + const GrowableObjectArray& func_list_;
|
| + const GrowableObjectArray& code_list_;
|
| + const GrowableObjectArray& pc_offset_list_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder);
|
| +};
|
| +
|
| +
|
| +class PreallocatedStacktraceBuilder : public StacktraceBuilder {
|
| + public:
|
| + explicit PreallocatedStacktraceBuilder(const Stacktrace& stacktrace)
|
| + : stacktrace_(stacktrace),
|
| + cur_index_(0) {
|
| + ASSERT(stacktrace_.raw() ==
|
| + Isolate::Current()->object_store()->preallocated_stack_trace());
|
| + }
|
| + ~PreallocatedStacktraceBuilder() { }
|
| +
|
| + virtual void AddFrame(const Function& func,
|
| + const Code& code,
|
| + const Smi& offset);
|
| +
|
| + private:
|
| + static const int kNumTopframes = 3;
|
| +
|
| + const Stacktrace& stacktrace_;
|
| + intptr_t cur_index_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder);
|
| +};
|
| +
|
| +
|
| +void PreallocatedStacktraceBuilder::AddFrame(const Function& func,
|
| + const Code& code,
|
| + const Smi& offset) {
|
| + if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) {
|
| + // The number of frames is overflowing the preallocated stack trace object.
|
| + Function& frame_func = Function::Handle();
|
| + Code& frame_code = Code::Handle();
|
| + Smi& frame_offset = Smi::Handle();
|
| + intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1);
|
| + intptr_t null_slot = start - 2;
|
| + // Add an empty slot to indicate the overflow so that the toString
|
| + // method can account for the overflow.
|
| + if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) {
|
| + stacktrace_.SetFunctionAtFrame(null_slot, frame_func);
|
| + stacktrace_.SetCodeAtFrame(null_slot, frame_code);
|
| + }
|
| + // Move frames one slot down so that we can accomadate the new frame.
|
| + for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) {
|
| + intptr_t prev = (i - 1);
|
| + frame_func = stacktrace_.FunctionAtFrame(i);
|
| + frame_code = stacktrace_.CodeAtFrame(i);
|
| + frame_offset = stacktrace_.PcOffsetAtFrame(i);
|
| + stacktrace_.SetFunctionAtFrame(prev, frame_func);
|
| + stacktrace_.SetCodeAtFrame(prev, frame_code);
|
| + stacktrace_.SetPcOffsetAtFrame(prev, frame_offset);
|
| + }
|
| + cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1);
|
| + }
|
| + stacktrace_.SetFunctionAtFrame(cur_index_, func);
|
| + stacktrace_.SetCodeAtFrame(cur_index_, code);
|
| + stacktrace_.SetPcOffsetAtFrame(cur_index_, offset);
|
| + cur_index_ += 1;
|
| +}
|
| +
|
| +
|
| static bool ShouldShowFunction(const Function& function) {
|
| if (FLAG_verbose_stacktrace) {
|
| return true;
|
| @@ -40,9 +140,7 @@
|
| static bool FindExceptionHandler(uword* handler_pc,
|
| uword* handler_sp,
|
| uword* handler_fp,
|
| - const GrowableObjectArray& func_list,
|
| - const GrowableObjectArray& code_list,
|
| - const GrowableObjectArray& pc_offset_list) {
|
| + StacktraceBuilder* builder) {
|
| StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
|
| StackFrame* frame = frames.NextFrame();
|
| ASSERT(frame != NULL); // We expect to find a dart invocation frame.
|
| @@ -64,18 +162,14 @@
|
| ASSERT(pc < (code.EntryPoint() + code.Size()));
|
| if (ShouldShowFunction(func)) {
|
| offset = Smi::New(pc - code.EntryPoint());
|
| - func_list.Add(func);
|
| - code_list.Add(code);
|
| - pc_offset_list.Add(offset);
|
| + builder->AddFrame(func, code, offset);
|
| }
|
| }
|
| } else {
|
| offset = Smi::New(frame->pc() - code.EntryPoint());
|
| func = code.function();
|
| if (ShouldShowFunction(func)) {
|
| - func_list.Add(func);
|
| - code_list.Add(code);
|
| - pc_offset_list.Add(offset);
|
| + builder->AddFrame(func, code, offset);
|
| }
|
| }
|
| if (frame->FindExceptionHandler(handler_pc)) {
|
| @@ -171,46 +265,62 @@
|
|
|
| static void ThrowExceptionHelper(const Instance& incoming_exception,
|
| const Instance& existing_stacktrace) {
|
| - Instance& exception = Instance::Handle(incoming_exception.raw());
|
| + bool use_preallocated_stacktrace = false;
|
| + Isolate* isolate = Isolate::Current();
|
| + Instance& exception = Instance::Handle(isolate, incoming_exception.raw());
|
| if (exception.IsNull()) {
|
| exception ^= Exceptions::Create(Exceptions::kNullThrown,
|
| Object::empty_array());
|
| + } else if (exception.raw() == isolate->object_store()->out_of_memory() ||
|
| + exception.raw() == isolate->object_store()->stack_overflow()) {
|
| + use_preallocated_stacktrace = true;
|
| }
|
| uword handler_pc = 0;
|
| uword handler_sp = 0;
|
| uword handler_fp = 0;
|
| - const GrowableObjectArray& func_list =
|
| - GrowableObjectArray::Handle(GrowableObjectArray::New());
|
| - const GrowableObjectArray& code_list =
|
| - GrowableObjectArray::Handle(GrowableObjectArray::New());
|
| - const GrowableObjectArray& pc_offset_list =
|
| - GrowableObjectArray::Handle(GrowableObjectArray::New());
|
| - bool handler_exists = FindExceptionHandler(&handler_pc,
|
| - &handler_sp,
|
| - &handler_fp,
|
| - func_list,
|
| - code_list,
|
| - pc_offset_list);
|
| + Stacktrace& stacktrace = Stacktrace::Handle(isolate);
|
| + bool handler_exists = false;
|
| + if (use_preallocated_stacktrace) {
|
| + stacktrace ^= isolate->object_store()->preallocated_stack_trace();
|
| + PreallocatedStacktraceBuilder frame_builder(stacktrace);
|
| + handler_exists = FindExceptionHandler(&handler_pc,
|
| + &handler_sp,
|
| + &handler_fp,
|
| + &frame_builder);
|
| + } else {
|
| + RegularStacktraceBuilder frame_builder;
|
| + handler_exists = FindExceptionHandler(&handler_pc,
|
| + &handler_sp,
|
| + &handler_fp,
|
| + &frame_builder);
|
| + // TODO(5411263): At some point we can optimize by figuring out if a
|
| + // stack trace is needed based on whether the catch code specifies a
|
| + // stack trace object or there is a rethrow in the catch clause.
|
| + if (frame_builder.pc_offset_list().Length() != 0) {
|
| + // Create arrays for function, code and pc_offset triplet for each frame.
|
| + const Array& func_array =
|
| + Array::Handle(isolate, Array::MakeArray(frame_builder.func_list()));
|
| + const Array& code_array =
|
| + Array::Handle(isolate, Array::MakeArray(frame_builder.code_list()));
|
| + const Array& pc_offset_array =
|
| + Array::Handle(isolate,
|
| + Array::MakeArray(frame_builder.pc_offset_list()));
|
| + if (existing_stacktrace.IsNull()) {
|
| + stacktrace = Stacktrace::New(func_array, code_array, pc_offset_array);
|
| + } else {
|
| + stacktrace ^= existing_stacktrace.raw();
|
| + stacktrace.Append(func_array, code_array, pc_offset_array);
|
| + }
|
| + } else {
|
| + stacktrace ^= existing_stacktrace.raw();
|
| + }
|
| + }
|
| // We expect to find a handler_pc, if the exception is unhandled
|
| // then we expect to at least have the dart entry frame on the
|
| // stack as Exceptions::Throw should happen only after a dart
|
| // invocation has been done.
|
| ASSERT(handler_pc != 0);
|
|
|
| - // TODO(5411263): At some point we can optimize by figuring out if a
|
| - // stack trace is needed based on whether the catch code specifies a
|
| - // stack trace object or there is a rethrow in the catch clause.
|
| - Stacktrace& stacktrace = Stacktrace::Handle();
|
| - if (pc_offset_list.Length() != 0) {
|
| - if (existing_stacktrace.IsNull()) {
|
| - stacktrace = Stacktrace::New(func_list, code_list, pc_offset_list);
|
| - } else {
|
| - stacktrace ^= existing_stacktrace.raw();
|
| - stacktrace.Append(func_list, code_list, pc_offset_list);
|
| - }
|
| - } else {
|
| - stacktrace ^= existing_stacktrace.raw();
|
| - }
|
| if (FLAG_print_stacktrace_at_throw) {
|
| OS::Print("Exception '%s' thrown:\n", exception.ToCString());
|
| OS::Print("%s\n", stacktrace.ToCString());
|
| @@ -224,7 +334,6 @@
|
| stacktrace);
|
| } else {
|
| if (FLAG_heap_profile_out_of_memory) {
|
| - Isolate* isolate = Isolate::Current();
|
| if (exception.raw() == isolate->object_store()->out_of_memory()) {
|
| isolate->heap()->ProfileToFile("out-of-memory");
|
| }
|
|
|