@@ -46,7 +46,7 @@ class StackTraceBuilder : public ValueObject {
4646 void AddFrame (const Object& code, uword pc_offset);
4747
4848 private:
49- static constexpr int kNumTopframes = StackTrace::kPreallocatedStackdepth / 2 ;
49+ static constexpr int kNumTopframes = StackTrace::kFixedOOMStackdepth / 2 ;
5050
5151 const StackTrace& stacktrace_;
5252 intptr_t cur_index_;
@@ -56,10 +56,10 @@ class StackTraceBuilder : public ValueObject {
5656};
5757
5858void StackTraceBuilder::AddFrame (const Object& code, uword pc_offset) {
59- if (cur_index_ >= StackTrace::kPreallocatedStackdepth ) {
59+ if (cur_index_ >= StackTrace::kFixedOOMStackdepth ) {
6060 // The number of frames is overflowing the preallocated stack trace object.
6161 Object& frame_code = Object::Handle ();
62- intptr_t start = StackTrace::kPreallocatedStackdepth - (kNumTopframes - 1 );
62+ intptr_t start = StackTrace::kFixedOOMStackdepth - (kNumTopframes - 1 );
6363 intptr_t null_slot = start - 2 ;
6464 // We are going to drop one frame.
6565 dropped_frames_++;
@@ -73,14 +73,14 @@ void StackTraceBuilder::AddFrame(const Object& code, uword pc_offset) {
7373 // Encode the number of dropped frames into the pc offset.
7474 stacktrace_.SetPcOffsetAtFrame (null_slot, dropped_frames_);
7575 // Move frames one slot down so that we can accommodate the new frame.
76- for (intptr_t i = start; i < StackTrace::kPreallocatedStackdepth ; i++) {
76+ for (intptr_t i = start; i < StackTrace::kFixedOOMStackdepth ; i++) {
7777 intptr_t prev = (i - 1 );
7878 frame_code = stacktrace_.CodeAtFrame (i);
7979 const uword frame_offset = stacktrace_.PcOffsetAtFrame (i);
8080 stacktrace_.SetCodeAtFrame (prev, frame_code);
8181 stacktrace_.SetPcOffsetAtFrame (prev, frame_offset);
8282 }
83- cur_index_ = (StackTrace::kPreallocatedStackdepth - 1 );
83+ cur_index_ = (StackTrace::kFixedOOMStackdepth - 1 );
8484 }
8585 stacktrace_.SetCodeAtFrame (cur_index_, code);
8686 stacktrace_.SetPcOffsetAtFrame (cur_index_, pc_offset);
@@ -710,18 +710,46 @@ StackTracePtr Exceptions::CurrentStackTrace() {
710710
711711static StackTracePtr CreateStackTrace (Zone* zone) {
712712 const Array& code_array = Array::Handle (
713- zone, Array::New (StackTrace::kPreallocatedStackdepth , Heap::kOld ));
713+ zone, Array::New (StackTrace::kFixedOOMStackdepth , Heap::kOld ));
714+ if (code_array.IsNull ()) {
715+ return StackTrace::null ();
716+ }
714717 const TypedData& pc_offset_array = TypedData::Handle (
715- zone, TypedData::New (kUintPtrCid , StackTrace::kPreallocatedStackdepth ,
716- Heap::kOld ));
718+ zone,
719+ TypedData::New (kUintPtrCid , StackTrace::kFixedOOMStackdepth , Heap::kOld ));
720+ if (pc_offset_array.IsNull ()) {
721+ return StackTrace::null ();
722+ }
717723 const StackTrace& stack_trace =
718724 StackTrace::Handle (zone, StackTrace::New (code_array, pc_offset_array));
719725 // Expansion of inlined functions requires additional memory at run time,
720726 // avoid it.
727+ if (stack_trace.IsNull ()) {
728+ return StackTrace::null ();
729+ }
721730 stack_trace.set_expand_inlined (false );
722731 return stack_trace.ptr ();
723732}
724733
734+ static UnhandledExceptionPtr CreateUnhandledExceptionOrUsePrecanned (
735+ Thread* thread,
736+ const Instance& exception,
737+ const Instance& stacktrace) {
738+ UnhandledException& unhandled = UnhandledException::Handle (thread->zone ());
739+ {
740+ NoThrowOOMScope no_throw_oom_scope (thread);
741+ unhandled ^= UnhandledException::New (Heap::kOld );
742+ }
743+ if (unhandled.IsNull ()) {
744+ // If we failed to create new instance, use pre-canned one.
745+ unhandled ^= Object::unhandled_oom_exception ().ptr ();
746+ } else {
747+ unhandled.set_exception (exception);
748+ unhandled.set_stacktrace (stacktrace);
749+ }
750+ return unhandled.ptr ();
751+ }
752+
725753DART_NORETURN
726754static void ThrowExceptionHelper (Thread* thread,
727755 const Instance& incoming_exception,
@@ -745,7 +773,7 @@ static void ThrowExceptionHelper(Thread* thread,
745773 }
746774 }
747775#endif
748- bool use_preallocated_stacktrace = false ;
776+ bool create_stacktrace = false ;
749777 Instance& exception = Instance::Handle (zone, incoming_exception.ptr ());
750778 if (exception.IsNull ()) {
751779 const Array& args = Array::Handle (zone, Array::New (4 ));
@@ -758,7 +786,7 @@ static void ThrowExceptionHelper(Thread* thread,
758786 } else if (existing_stacktrace.IsNull () &&
759787 (exception.ptr () == object_store->out_of_memory () ||
760788 exception.ptr () == object_store->stack_overflow ())) {
761- use_preallocated_stacktrace = true ;
789+ create_stacktrace = true ;
762790 }
763791 // Find the exception handler and determine if the handler needs a
764792 // stacktrace.
@@ -769,24 +797,32 @@ static void ThrowExceptionHelper(Thread* thread,
769797 uword handler_fp = finder.handler_fp ;
770798 bool handler_needs_stacktrace = finder.needs_stacktrace ;
771799 Instance& stacktrace = Instance::Handle (zone);
772- if (use_preallocated_stacktrace) {
773- stacktrace = CreateStackTrace (zone);
774- if (handler_pc == 0 ) {
775- // No Dart frame.
776- ASSERT (incoming_exception.ptr () == object_store->out_of_memory ());
777- const UnhandledException& error = UnhandledException::Handle (
778- zone, UnhandledException::New (
779- Instance::Handle (zone, object_store->out_of_memory ()),
780- stacktrace));
781- thread->long_jump_base ()->Jump (1 , error);
782- UNREACHABLE ();
800+ if (create_stacktrace) {
801+ {
802+ NoThrowOOMScope no_throw_oom_scope (thread);
803+ stacktrace = CreateStackTrace (zone);
783804 }
784- StackTraceBuilder frame_builder (stacktrace);
785- ASSERT (existing_stacktrace.IsNull () ||
786- (existing_stacktrace.ptr () == stacktrace.ptr ()));
787- ASSERT (existing_stacktrace.IsNull () || is_rethrow);
788- if (handler_needs_stacktrace && existing_stacktrace.IsNull ()) {
789- BuildStackTrace (&frame_builder);
805+ // Ensure we have enough memory to create stacktrace,
806+ // otherwise fallback to reporting OOM without stacktrace.
807+ if (!stacktrace.IsNull ()) {
808+ if (handler_pc == 0 ) {
809+ // No Dart frame.
810+ ASSERT (incoming_exception.ptr () == object_store->out_of_memory ());
811+ UnhandledException& error = UnhandledException::Handle (
812+ zone,
813+ CreateUnhandledExceptionOrUsePrecanned (
814+ thread, Instance::Handle (zone, object_store->out_of_memory ()),
815+ stacktrace));
816+ thread->long_jump_base ()->Jump (1 , error);
817+ UNREACHABLE ();
818+ }
819+ StackTraceBuilder frame_builder (stacktrace);
820+ ASSERT (existing_stacktrace.IsNull () ||
821+ (existing_stacktrace.ptr () == stacktrace.ptr ()));
822+ ASSERT (existing_stacktrace.IsNull () || is_rethrow);
823+ if (handler_needs_stacktrace && existing_stacktrace.IsNull ()) {
824+ BuildStackTrace (&frame_builder);
825+ }
790826 }
791827 } else {
792828 if (!existing_stacktrace.IsNull ()) {
@@ -839,7 +875,8 @@ static void ThrowExceptionHelper(Thread* thread,
839875 // the isolate etc.). This can happen in the compiler, which is not
840876 // allowed to allocate in new space, so we pass the kOld argument.
841877 const UnhandledException& unhandled_exception = UnhandledException::Handle (
842- zone, UnhandledException::New (exception, stacktrace, Heap::kOld ));
878+ zone,
879+ CreateUnhandledExceptionOrUsePrecanned (thread, exception, stacktrace));
843880 stacktrace = StackTrace::null ();
844881 JumpToExceptionHandler (thread, handler_pc, handler_sp, handler_fp,
845882 unhandled_exception, stacktrace);
0 commit comments