// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/exceptions.h" #include "platform/address_sanitizer.h" #include "vm/dart_api_impl.h" #include "vm/dart_entry.h" #include "vm/debugger.h" #include "vm/flags.h" #include "vm/log.h" #include "vm/longjump.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/stack_frame.h" #include "vm/stub_code.h" #include "vm/symbols.h" #include "vm/tags.h" namespace dart { DECLARE_FLAG(bool, trace_deoptimization); DEFINE_FLAG(bool, print_stacktrace_at_throw, false, "Prints a stack trace everytime a throw occurs."); class StacktraceBuilder : public ValueObject { public: StacktraceBuilder() { } virtual ~StacktraceBuilder() { } virtual void AddFrame(const Code& code, const Smi& offset) = 0; }; class RegularStacktraceBuilder : public StacktraceBuilder { public: explicit RegularStacktraceBuilder(Zone* zone) : code_list_( GrowableObjectArray::Handle(zone, GrowableObjectArray::New())), pc_offset_list_( GrowableObjectArray::Handle(zone, GrowableObjectArray::New())) { } ~RegularStacktraceBuilder() { } const GrowableObjectArray& code_list() const { return code_list_; } const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; } virtual void AddFrame(const Code& code, const Smi& offset) { code_list_.Add(code); pc_offset_list_.Add(offset); } private: const GrowableObjectArray& code_list_; const GrowableObjectArray& pc_offset_list_; DISALLOW_COPY_AND_ASSIGN(RegularStacktraceBuilder); }; class PreallocatedStacktraceBuilder : public StacktraceBuilder { public: explicit PreallocatedStacktraceBuilder(const Instance& stacktrace) : stacktrace_(Stacktrace::Cast(stacktrace)), cur_index_(0), dropped_frames_(0) { ASSERT(stacktrace_.raw() == Isolate::Current()->object_store()->preallocated_stack_trace()); } ~PreallocatedStacktraceBuilder() { } virtual void AddFrame(const Code& code, const Smi& offset); private: static const int kNumTopframes = Stacktrace::kPreallocatedStackdepth / 2; const Stacktrace& stacktrace_; intptr_t cur_index_; intptr_t dropped_frames_; DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder); }; void PreallocatedStacktraceBuilder::AddFrame(const Code& code, const Smi& offset) { if (cur_index_ >= Stacktrace::kPreallocatedStackdepth) { // The number of frames is overflowing the preallocated stack trace object. Code& frame_code = Code::Handle(); Smi& frame_offset = Smi::Handle(); intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1); intptr_t null_slot = start - 2; // We are going to drop one frame. dropped_frames_++; // 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_.SetCodeAtFrame(null_slot, frame_code); // We drop an extra frame here too. dropped_frames_++; } // Encode the number of dropped frames into the pc offset. frame_offset ^= Smi::New(dropped_frames_); stacktrace_.SetPcOffsetAtFrame(null_slot, frame_offset); // Move frames one slot down so that we can accomodate the new frame. for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) { intptr_t prev = (i - 1); frame_code = stacktrace_.CodeAtFrame(i); frame_offset = stacktrace_.PcOffsetAtFrame(i); stacktrace_.SetCodeAtFrame(prev, frame_code); stacktrace_.SetPcOffsetAtFrame(prev, frame_offset); } cur_index_ = (Stacktrace::kPreallocatedStackdepth - 1); } stacktrace_.SetCodeAtFrame(cur_index_, code); stacktrace_.SetPcOffsetAtFrame(cur_index_, offset); cur_index_ += 1; } static void BuildStackTrace(StacktraceBuilder* builder) { StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); StackFrame* frame = frames.NextFrame(); ASSERT(frame != NULL); // We expect to find a dart invocation frame. Code& code = Code::Handle(); Smi& offset = Smi::Handle(); while (frame != NULL) { if (frame->IsDartFrame()) { code = frame->LookupDartCode(); ASSERT(code.ContainsInstructionAt(frame->pc())); offset = Smi::New(frame->pc() - code.PayloadStart()); builder->AddFrame(code, offset); } frame = frames.NextFrame(); } } // 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(); } 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; } static void FindErrorHandler(uword* handler_pc, uword* handler_sp, uword* handler_fp) { // TODO(turnidge): Is there a faster way to get the next entry frame? StackFrameIterator frames(StackFrameIterator::kDontValidateFrames); StackFrame* frame = frames.NextFrame(); ASSERT(frame != NULL); while (!frame->IsEntryFrame()) { frame = frames.NextFrame(); ASSERT(frame != NULL); } ASSERT(frame->IsEntryFrame()); *handler_pc = frame->pc(); *handler_sp = frame->sp(); *handler_fp = frame->fp(); } static void JumpToExceptionHandler(Thread* thread, uword program_counter, uword stack_pointer, uword frame_pointer, const Object& exception_object, const Object& stacktrace_object) { // The no_gc StackResource is unwound through the tear down of // stack resources below. NoSafepointScope no_safepoint; RawObject* raw_exception = exception_object.raw(); RawObject* raw_stacktrace = stacktrace_object.raw(); #if !defined(TARGET_ARCH_DBC) MallocGrowableArray* pending_deopts = thread->isolate()->pending_deopts(); if (pending_deopts->length() > 0) { // Check if the target frame is scheduled for lazy deopt. for (intptr_t i = 0; i < pending_deopts->length(); i++) { if ((*pending_deopts)[i].fp() == frame_pointer) { // Deopt should now resume in the catch handler instead of after the // call. (*pending_deopts)[i].set_pc(program_counter); // Jump to the deopt stub instead of the catch handler. program_counter = StubCode::DeoptimizeLazyFromThrow_entry()->EntryPoint(); if (FLAG_trace_deoptimization) { THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n", frame_pointer); } break; } } // We may be jumping over frames scheduled for lazy deopt. Remove these // frames from the pending deopt table, but only after unmarking them so // any stack walk that happens before the stack is unwound will still work. { DartFrameIterator frames(thread); StackFrame* frame = frames.NextFrame(); while ((frame != NULL) && (frame->fp() < frame_pointer)) { if (frame->IsMarkedForLazyDeopt()) { frame->UnmarkForLazyDeopt(); } frame = frames.NextFrame(); } } #if defined(DEBUG) ValidateFrames(); #endif for (intptr_t i = 0; i < pending_deopts->length(); i++) { if ((*pending_deopts)[i].fp() < frame_pointer) { if (FLAG_trace_deoptimization) { THR_Print("Lazy deopt skipped due to throw for " "fp=%" Pp ", pc=%" Pp "\n", (*pending_deopts)[i].fp(), (*pending_deopts)[i].pc()); } pending_deopts->RemoveAt(i); } } #if defined(DEBUG) ValidateFrames(); #endif } #endif // !DBC #if defined(USING_SIMULATOR) // Unwinding of the C++ frames and destroying of their stack resources is done // by the simulator, because the target stack_pointer is a simulated stack // pointer and not the C++ stack pointer. // Continue simulating at the given pc in the given frame after setting up the // exception object in the kExceptionObjectReg register and the stacktrace // object (may be raw null) in the kStackTraceObjectReg register. Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, raw_exception, raw_stacktrace, thread); #else // Prepare for unwinding frames by destroying all the stack resources // in the previous frames. StackResource::Unwind(thread); // Call a stub to set up the exception object in kExceptionObjectReg, // to set up the stacktrace object in kStackTraceObjectReg, and to // continue execution at the given pc in the given frame. typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*, Thread*); ExcpHandler func = reinterpret_cast( StubCode::JumpToExceptionHandler_entry()->EntryPoint()); // Unpoison the stack before we tear it down in the generated stub code. uword current_sp = Thread::GetCurrentStackPointer() - 1024; ASAN_UNPOISON(reinterpret_cast(current_sp), stack_pointer - current_sp); func(program_counter, stack_pointer, frame_pointer, raw_exception, raw_stacktrace, thread); #endif UNREACHABLE(); } static RawField* LookupStacktraceField(const Instance& instance) { if (instance.GetClassId() < kNumPredefinedCids) { // 'class Error' is not a predefined class. return Field::null(); } Thread* thread = Thread::Current(); Zone* zone = thread->zone(); Isolate* isolate = thread->isolate(); Class& error_class = Class::Handle(zone, isolate->object_store()->error_class()); if (error_class.IsNull()) { const Library& core_lib = Library::Handle(zone, Library::CoreLibrary()); error_class = core_lib.LookupClass(Symbols::Error()); ASSERT(!error_class.IsNull()); isolate->object_store()->set_error_class(error_class); } // If instance class extends 'class Error' return '_stackTrace' field. Class& test_class = Class::Handle(zone, instance.clazz()); AbstractType& type = AbstractType::Handle(zone, AbstractType::null()); while (true) { if (test_class.raw() == error_class.raw()) { return error_class.LookupInstanceFieldAllowPrivate( Symbols::_stackTrace()); } type = test_class.super_type(); if (type.IsNull()) return Field::null(); test_class = type.type_class(); } UNREACHABLE(); return Field::null(); } RawStacktrace* Exceptions::CurrentStacktrace() { Zone* zone = Thread::Current()->zone(); RegularStacktraceBuilder frame_builder(zone); BuildStackTrace(&frame_builder); // Create arrays for code and pc_offset tuples of each frame. const Array& full_code_array = Array::Handle(zone, Array::MakeArray(frame_builder.code_list())); const Array& full_pc_offset_array = Array::Handle(zone, Array::MakeArray(frame_builder.pc_offset_list())); const Stacktrace& full_stacktrace = Stacktrace::Handle( Stacktrace::New(full_code_array, full_pc_offset_array)); return full_stacktrace.raw(); } static void ThrowExceptionHelper(Thread* thread, const Instance& incoming_exception, const Instance& existing_stacktrace, const bool is_rethrow) { Zone* zone = thread->zone(); Isolate* isolate = thread->isolate(); bool use_preallocated_stacktrace = false; Instance& exception = Instance::Handle(zone, 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; Instance& stacktrace = Instance::Handle(zone); bool handler_exists = false; bool handler_needs_stacktrace = false; if (use_preallocated_stacktrace) { stacktrace ^= isolate->object_store()->preallocated_stack_trace(); PreallocatedStacktraceBuilder frame_builder(stacktrace); handler_exists = FindExceptionHandler(thread, &handler_pc, &handler_sp, &handler_fp, &handler_needs_stacktrace); if (handler_pc == 0) { // No Dart frame. ASSERT(incoming_exception.raw() == isolate->object_store()->out_of_memory()); const UnhandledException& error = UnhandledException::Handle( zone, isolate->object_store()->preallocated_unhandled_exception()); thread->long_jump_base()->Jump(1, error); UNREACHABLE(); } if (handler_needs_stacktrace) { BuildStackTrace(&frame_builder); } } else { // Get stacktrace field of class Error. This is needed to determine whether // we have a subclass of Error which carries around its stack trace. const Field& stacktrace_field = Field::Handle(zone, LookupStacktraceField(exception)); // 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); if (!existing_stacktrace.IsNull()) { // If we have an existing stack trace then this better be a rethrow. The // reverse is not necessarily true (e.g. Dart_PropagateError can cause // a rethrow being called without an existing stacktrace.) ASSERT(is_rethrow); ASSERT(stacktrace_field.IsNull() || (exception.GetField(stacktrace_field) != Object::null())); stacktrace = existing_stacktrace.raw(); } else if (!stacktrace_field.IsNull() || handler_needs_stacktrace) { // Collect the stacktrace if needed. ASSERT(existing_stacktrace.IsNull()); stacktrace = Exceptions::CurrentStacktrace(); // If we have an Error object, then set its stackTrace field only if it // not yet initialized. if (!stacktrace_field.IsNull() && (exception.GetField(stacktrace_field) == Object::null())) { exception.SetField(stacktrace_field, stacktrace); } } } // 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); if (FLAG_print_stacktrace_at_throw) { THR_Print("Exception '%s' thrown:\n", exception.ToCString()); THR_Print("%s\n", stacktrace.ToCString()); } if (handler_exists) { // Found a dart handler for the exception, jump to it. JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, exception, stacktrace); } else { // No dart exception handler found in this invocation sequence, // so we create an unhandled exception object and return to the // invocation stub so that it returns this unhandled exception // object. The C++ code which invoked this dart sequence can check // and do the appropriate thing (rethrow the exception to the // dart invocation sequence above it, print diagnostics and terminate // the isolate etc.). const UnhandledException& unhandled_exception = UnhandledException::Handle( zone, UnhandledException::New(exception, stacktrace)); stacktrace = Stacktrace::null(); JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, unhandled_exception, stacktrace); } UNREACHABLE(); } // Static helpers for allocating, initializing, and throwing an error instance. // Return the script of the Dart function that called the native entry or the // runtime entry. The frame iterator points to the callee. RawScript* Exceptions::GetCallerScript(DartFrameIterator* iterator) { StackFrame* caller_frame = iterator->NextFrame(); ASSERT(caller_frame != NULL && caller_frame->IsDartFrame()); const Function& caller = Function::Handle(caller_frame->LookupDartFunction()); ASSERT(!caller.IsNull()); return caller.script(); } // Allocate a new instance of the given class name. // TODO(hausner): Rename this NewCoreInstance to call out the fact that // the class name is resolved in the core library implicitly? RawInstance* Exceptions::NewInstance(const char* class_name) { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); const String& cls_name = String::Handle(zone, Symbols::New(thread, class_name)); const Library& core_lib = Library::Handle(Library::CoreLibrary()); // No ambiguity error expected: passing NULL. Class& cls = Class::Handle(core_lib.LookupClass(cls_name)); ASSERT(!cls.IsNull()); // There are no parameterized error types, so no need to set type arguments. return Instance::New(cls); } // Allocate, initialize, and throw a TypeError or CastError. // If error_msg is not null, throw a TypeError, even for a type cast. void Exceptions::CreateAndThrowTypeError(TokenPosition location, const AbstractType& src_type, const AbstractType& dst_type, const String& dst_name, const String& bound_error_msg) { ASSERT(!dst_name.IsNull()); // Pass Symbols::Empty() instead. Zone* zone = Thread::Current()->zone(); const Array& args = Array::Handle(zone, Array::New(4)); ExceptionType exception_type = (bound_error_msg.IsNull() && (dst_name.raw() == Symbols::InTypeCast().raw())) ? kCast : kType; DartFrameIterator iterator; const Script& script = Script::Handle(zone, GetCallerScript(&iterator)); intptr_t line; intptr_t column = -1; if (script.HasSource()) { script.GetTokenLocation(location, &line, &column); } else { script.GetTokenLocation(location, &line, NULL); } // Initialize '_url', '_line', and '_column' arguments. args.SetAt(0, String::Handle(zone, script.url())); args.SetAt(1, Smi::Handle(zone, Smi::New(line))); args.SetAt(2, Smi::Handle(zone, Smi::New(column))); // Construct '_errorMsg'. const GrowableObjectArray& pieces = GrowableObjectArray::Handle(zone, GrowableObjectArray::New(20)); // Print bound error first, if any. if (!bound_error_msg.IsNull() && (bound_error_msg.Length() > 0)) { pieces.Add(bound_error_msg); pieces.Add(Symbols::NewLine()); } // If dst_type is malformed or malbounded, only print the embedded error. if (!dst_type.IsNull()) { const LanguageError& error = LanguageError::Handle(zone, dst_type.error()); if (!error.IsNull()) { // Print the embedded error only. pieces.Add(String::Handle(zone, String::New(error.ToErrorCString()))); pieces.Add(Symbols::NewLine()); } else { // Describe the type error. if (!src_type.IsNull()) { pieces.Add(Symbols::TypeQuote()); pieces.Add(String::Handle(zone, src_type.UserVisibleName())); pieces.Add(Symbols::QuoteIsNotASubtypeOf()); } pieces.Add(Symbols::TypeQuote()); pieces.Add(String::Handle(zone, dst_type.UserVisibleName())); pieces.Add(Symbols::SingleQuote()); if (exception_type == kCast) { pieces.Add(dst_name); } else if (dst_name.Length() > 0) { pieces.Add(Symbols::SpaceOfSpace()); pieces.Add(Symbols::SingleQuote()); pieces.Add(dst_name); pieces.Add(Symbols::SingleQuote()); } // Print URIs of src and dst types. // Do not print "where" when no URIs get printed. bool printed_where = false; if (!src_type.IsNull()) { const String& uris = String::Handle(zone, src_type.EnumerateURIs()); if (uris.Length() > Symbols::SpaceIsFromSpace().Length()) { printed_where = true; pieces.Add(Symbols::SpaceWhereNewLine()); pieces.Add(uris); } } if (!dst_type.IsDynamicType() && !dst_type.IsVoidType()) { const String& uris = String::Handle(zone, dst_type.EnumerateURIs()); if (uris.Length() > Symbols::SpaceIsFromSpace().Length()) { if (!printed_where) { pieces.Add(Symbols::SpaceWhereNewLine()); } pieces.Add(uris); } } } } const Array& arr = Array::Handle(zone, Array::MakeArray(pieces)); const String& error_msg = String::Handle(zone, String::ConcatAll(arr)); args.SetAt(3, error_msg); // Type errors in the core library may be difficult to diagnose. // Print type error information before throwing the error when debugging. if (FLAG_print_stacktrace_at_throw) { THR_Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ", String::Handle(zone, script.url()).ToCString(), line, column); THR_Print("%s\n", error_msg.ToCString()); } // Throw TypeError or CastError instance. Exceptions::ThrowByType(exception_type, args); UNREACHABLE(); } void Exceptions::Throw(Thread* thread, const Instance& exception) { // Do not notify debugger on stack overflow and out of memory exceptions. // The VM would crash when the debugger calls back into the VM to // get values of variables. if (FLAG_support_debugger) { Isolate* isolate = thread->isolate(); if (exception.raw() != isolate->object_store()->out_of_memory() && exception.raw() != isolate->object_store()->stack_overflow()) { isolate->debugger()->PauseException(exception); } } // Null object is a valid exception object. ThrowExceptionHelper(thread, exception, Stacktrace::Handle(thread->zone()), false); } void Exceptions::ReThrow(Thread* thread, const Instance& exception, const Instance& stacktrace) { // Null object is a valid exception object. ThrowExceptionHelper(thread, exception, stacktrace, true); } void Exceptions::PropagateError(const Error& error) { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); ASSERT(thread->top_exit_frame_info() != 0); if (error.IsUnhandledException()) { // If the error object represents an unhandled exception, then // rethrow the exception in the normal fashion. const UnhandledException& uhe = UnhandledException::Cast(error); const Instance& exc = Instance::Handle(zone, uhe.exception()); const Instance& stk = Instance::Handle(zone, uhe.stacktrace()); Exceptions::ReThrow(thread, exc, stk); } else { // Return to the invocation stub and return this error object. The // C++ code which invoked this dart sequence can check and do the // appropriate thing. uword handler_pc = 0; uword handler_sp = 0; uword handler_fp = 0; FindErrorHandler(&handler_pc, &handler_sp, &handler_fp); JumpToExceptionHandler(thread, handler_pc, handler_sp, handler_fp, error, Stacktrace::Handle(zone)); // Null stacktrace. } UNREACHABLE(); } void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) { Thread* thread = Thread::Current(); const Object& result = Object::Handle(thread->zone(), Create(type, arguments)); if (result.IsError()) { // We got an error while constructing the exception object. // Propagate the error instead of throwing the exception. PropagateError(Error::Cast(result)); } else { ASSERT(result.IsInstance()); Throw(thread, Instance::Cast(result)); } } void Exceptions::ThrowOOM() { Thread* thread = Thread::Current(); Isolate* isolate = thread->isolate(); const Instance& oom = Instance::Handle( thread->zone(), isolate->object_store()->out_of_memory()); Throw(thread, oom); } void Exceptions::ThrowStackOverflow() { Thread* thread = Thread::Current(); Isolate* isolate = thread->isolate(); const Instance& stack_overflow = Instance::Handle( thread->zone(), isolate->object_store()->stack_overflow()); Throw(thread, stack_overflow); } void Exceptions::ThrowArgumentError(const Instance& arg) { const Array& args = Array::Handle(Array::New(1)); args.SetAt(0, arg); Exceptions::ThrowByType(Exceptions::kArgument, args); } void Exceptions::ThrowRangeError(const char* argument_name, const Integer& argument_value, intptr_t expected_from, intptr_t expected_to) { const Array& args = Array::Handle(Array::New(4)); args.SetAt(0, argument_value); args.SetAt(1, Integer::Handle(Integer::New(expected_from))); args.SetAt(2, Integer::Handle(Integer::New(expected_to))); args.SetAt(3, String::Handle(String::New(argument_name))); Exceptions::ThrowByType(Exceptions::kRange, args); } void Exceptions::ThrowCompileTimeError(const LanguageError& error) { const Array& args = Array::Handle(Array::New(1)); args.SetAt(0, String::Handle(error.FormatMessage())); Exceptions::ThrowByType(Exceptions::kCompileTimeError, args); } RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) { Library& library = Library::Handle(); const String* class_name = NULL; const String* constructor_name = &Symbols::Dot(); switch (type) { case kNone: case kStackOverflow: case kOutOfMemory: UNREACHABLE(); break; case kRange: library = Library::CoreLibrary(); class_name = &Symbols::RangeError(); constructor_name = &Symbols::DotRange(); break; case kArgument: library = Library::CoreLibrary(); class_name = &Symbols::ArgumentError(); break; case kArgumentValue: library = Library::CoreLibrary(); class_name = &Symbols::ArgumentError(); constructor_name = &Symbols::DotValue(); break; case kNoSuchMethod: library = Library::CoreLibrary(); class_name = &Symbols::NoSuchMethodError(); constructor_name = &Symbols::DotWithType(); break; case kFormat: library = Library::CoreLibrary(); class_name = &Symbols::FormatException(); break; case kUnsupported: library = Library::CoreLibrary(); class_name = &Symbols::UnsupportedError(); break; case kNullThrown: library = Library::CoreLibrary(); class_name = &Symbols::NullThrownError(); break; case kIsolateSpawn: library = Library::IsolateLibrary(); class_name = &Symbols::IsolateSpawnException(); break; case kAssertion: library = Library::CoreLibrary(); class_name = &Symbols::AssertionError(); constructor_name = &Symbols::DotCreate(); break; case kCast: library = Library::CoreLibrary(); class_name = &Symbols::CastError(); constructor_name = &Symbols::DotCreate(); break; case kType: library = Library::CoreLibrary(); class_name = &Symbols::TypeError(); constructor_name = &Symbols::DotCreate(); break; case kFallThrough: library = Library::CoreLibrary(); class_name = &Symbols::FallThroughError(); constructor_name = &Symbols::DotCreate(); break; case kAbstractClassInstantiation: library = Library::CoreLibrary(); class_name = &Symbols::AbstractClassInstantiationError(); constructor_name = &Symbols::DotCreate(); break; case kCyclicInitializationError: library = Library::CoreLibrary(); class_name = &Symbols::CyclicInitializationError(); break; case kCompileTimeError: library = Library::CoreLibrary(); class_name = &Symbols::_CompileTimeError(); break; } return DartLibraryCalls::InstanceCreate(library, *class_name, *constructor_name, arguments); } } // namespace dart