Files
sdk/runtime/vm/exceptions.cc
T
regis@google.com dec11d8b7b Add support for javascript incompatibility warnings (work in progress).
For now, warnings are only issued when applicable for type tests, type casts,
and toString.
Fix newly reported lint errors.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//260713008

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@36001 260f80e4-7a28-3924-810f-c04153c831b5
2014-05-09 22:42:10 +00:00

780 lines
29 KiB
C++

// 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 "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/flags.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"
// Allow the use of ASan (AddressSanitizer). This is needed as ASan needs to be
// told about areas where the VM does the equivalent of a long-jump.
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
extern "C" void __asan_unpoison_memory_region(void *, size_t);
#else // __has_feature(address_sanitizer)
void __asan_unpoison_memory_region(void* ignore1, size_t ignore2) {}
#endif // __has_feature(address_sanitizer)
#else // defined(__has_feature)
void __asan_unpoison_memory_region(void* ignore1, size_t ignore2) {}
#endif // defined(__has_feature)
namespace dart {
DEFINE_FLAG(bool, print_stacktrace_at_throw, false,
"Prints a stack trace everytime a throw occurs.");
DEFINE_FLAG(bool, verbose_stacktrace, false,
"Stack traces will include methods marked invisible.");
DEFINE_FLAG(int, stacktrace_depth_on_warning, 5,
"Maximal number of stack frames to print after a runtime warning.");
DECLARE_FLAG(bool, silent_warnings);
DECLARE_FLAG(bool, warning_as_error);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
const char* Exceptions::kCastErrorDstName = "type cast";
class StacktraceBuilder : public ValueObject {
public:
StacktraceBuilder() { }
virtual ~StacktraceBuilder() { }
virtual void AddFrame(const Code& code,
const Smi& offset,
bool is_catch_frame) = 0;
virtual bool FullStacktrace() const = 0;
};
class RegularStacktraceBuilder : public StacktraceBuilder {
public:
explicit RegularStacktraceBuilder(bool full_stacktrace)
: code_list_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
pc_offset_list_(
GrowableObjectArray::Handle(GrowableObjectArray::New())),
catch_code_list_(
full_stacktrace ?
GrowableObjectArray::Handle(GrowableObjectArray::New()) :
GrowableObjectArray::Handle()),
catch_pc_offset_list_(
full_stacktrace ?
GrowableObjectArray::Handle(GrowableObjectArray::New()) :
GrowableObjectArray::Handle()),
full_stacktrace_(full_stacktrace) { }
~RegularStacktraceBuilder() { }
const GrowableObjectArray& code_list() const { return code_list_; }
const GrowableObjectArray& pc_offset_list() const { return pc_offset_list_; }
const GrowableObjectArray& catch_code_list() const {
return catch_code_list_;
}
const GrowableObjectArray& catch_pc_offset_list() const {
return catch_pc_offset_list_;
}
virtual bool FullStacktrace() const { return full_stacktrace_; }
virtual void AddFrame(const Code& code,
const Smi& offset,
bool is_catch_frame) {
if (is_catch_frame) {
catch_code_list_.Add(code);
catch_pc_offset_list_.Add(offset);
} else {
code_list_.Add(code);
pc_offset_list_.Add(offset);
}
}
private:
const GrowableObjectArray& code_list_;
const GrowableObjectArray& pc_offset_list_;
const GrowableObjectArray& catch_code_list_;
const GrowableObjectArray& catch_pc_offset_list_;
bool full_stacktrace_;
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 Code& code,
const Smi& offset,
bool is_catch_frame);
virtual bool FullStacktrace() const { return false; }
private:
static const int kNumTopframes = 3;
const Stacktrace& stacktrace_;
intptr_t cur_index_;
DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder);
};
void PreallocatedStacktraceBuilder::AddFrame(const Code& code,
const Smi& offset,
bool is_catch_frame) {
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;
// 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);
}
// 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();
bool dart_handler_found = false;
bool handler_pc_set = false;
while (frame != NULL) {
while (!frame->IsEntryFrame()) {
if (frame->IsDartFrame()) {
code = frame->LookupDartCode();
offset = Smi::New(frame->pc() - code.EntryPoint());
builder->AddFrame(code, offset, dart_handler_found);
bool needs_stacktrace = false;
bool is_catch_all = false;
uword handler_pc = kUwordMax;
if (!handler_pc_set &&
frame->FindExceptionHandler(&handler_pc,
&needs_stacktrace,
&is_catch_all)) {
handler_pc_set = true;
dart_handler_found = true;
if (!builder->FullStacktrace()) {
return;
}
}
}
frame = frames.NextFrame();
ASSERT(frame != NULL);
}
ASSERT(frame->IsEntryFrame());
if (!handler_pc_set) {
handler_pc_set = true;
if (!builder->FullStacktrace()) {
return;
}
}
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(uword* handler_pc,
uword* handler_sp,
uword* handler_fp,
bool* needs_stacktrace) {
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
StackFrame* frame = frames.NextFrame();
ASSERT(frame != NULL); // We expect to find a dart invocation 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(&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(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.
NoGCScope no_gc;
RawObject* raw_exception = exception_object.raw();
RawObject* raw_stacktrace = stacktrace_object.raw();
Isolate* isolate = Isolate::Current();
#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.
isolate->set_vm_tag(VMTag::kScriptTagId);
isolate->set_top_context(Context::null());
Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer,
raw_exception, raw_stacktrace);
#else
// Prepare for unwinding frames by destroying all the stack resources
// in the previous frames.
while (isolate->top_resource() != NULL &&
(reinterpret_cast<uword>(isolate->top_resource()) < stack_pointer)) {
isolate->top_resource()->~StackResource();
}
// 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*);
ExcpHandler func = reinterpret_cast<ExcpHandler>(
StubCode::JumpToExceptionHandlerEntryPoint());
// Unpoison the stack before we tear it down in the generated stub code.
uword current_sp = reinterpret_cast<uword>(&program_counter) - 1024;
__asan_unpoison_memory_region(reinterpret_cast<void*>(current_sp),
stack_pointer - current_sp);
isolate->set_vm_tag(VMTag::kScriptTagId);
isolate->set_top_context(Context::null());
func(program_counter, stack_pointer, frame_pointer,
raw_exception, raw_stacktrace);
#endif
UNREACHABLE();
}
static RawField* LookupStacktraceField(const Instance& instance) {
if (instance.GetClassId() < kNumPredefinedCids) {
// 'class Error' is not a predefined class.
return Field::null();
}
Isolate* isolate = Isolate::Current();
Class& error_class = Class::Handle(isolate,
isolate->object_store()->error_class());
if (error_class.IsNull()) {
const Library& core_lib = Library::Handle(isolate, 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(isolate, instance.clazz());
AbstractType& type = AbstractType::Handle(isolate, AbstractType::null());
while (true) {
if (test_class.raw() == error_class.raw()) {
return error_class.LookupInstanceField(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() {
Isolate* isolate = Isolate::Current();
RegularStacktraceBuilder frame_builder(true);
BuildStackTrace(&frame_builder);
// Create arrays for code and pc_offset tuples of each frame.
const Array& full_code_array = Array::Handle(isolate,
Array::MakeArray(frame_builder.code_list()));
const Array& full_pc_offset_array = Array::Handle(isolate,
Array::MakeArray(frame_builder.pc_offset_list()));
const Array& full_catch_code_array = Array::Handle(isolate,
Array::MakeArray(frame_builder.catch_code_list()));
const Array& full_catch_pc_offset_array = Array::Handle(isolate,
Array::MakeArray(frame_builder.catch_pc_offset_list()));
const Stacktrace& full_stacktrace = Stacktrace::Handle(
Stacktrace::New(full_code_array, full_pc_offset_array));
full_stacktrace.SetCatchStacktrace(full_catch_code_array,
full_catch_pc_offset_array);
return full_stacktrace.raw();
}
static void ThrowExceptionHelper(const Instance& incoming_exception,
const Instance& existing_stacktrace) {
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;
Stacktrace& stacktrace = Stacktrace::Handle(isolate);
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(&handler_pc,
&handler_sp,
&handler_fp,
&handler_needs_stacktrace);
if (handler_needs_stacktrace) {
BuildStackTrace(&frame_builder);
}
} else {
// Get stacktrace field of class Error.
const Field& stacktrace_field =
Field::Handle(isolate, LookupStacktraceField(exception));
handler_exists = FindExceptionHandler(&handler_pc,
&handler_sp,
&handler_fp,
&handler_needs_stacktrace);
Array& code_array = Array::Handle(isolate, Object::empty_array().raw());
Array& pc_offset_array =
Array::Handle(isolate, Object::empty_array().raw());
// If we have an error with a stacktrace field then collect the full stack
// trace and store it into the field.
if (!stacktrace_field.IsNull()) {
if (exception.GetField(stacktrace_field) == Object::null()) {
// This is an error object and we need to capture the full stack trace
// here implicitly, so we set up the stack trace. The stack trace field
// is set only once, it is not overriden.
const Stacktrace& full_stacktrace =
Stacktrace::Handle(isolate, Exceptions::CurrentStacktrace());
exception.SetField(stacktrace_field, full_stacktrace);
}
}
if (handler_needs_stacktrace) {
RegularStacktraceBuilder frame_builder(false);
BuildStackTrace(&frame_builder);
// Create arrays for code and pc_offset tuples of each frame.
code_array = Array::MakeArray(frame_builder.code_list());
pc_offset_array = Array::MakeArray(frame_builder.pc_offset_list());
}
if (existing_stacktrace.IsNull()) {
stacktrace = Stacktrace::New(code_array, pc_offset_array);
} else {
stacktrace ^= existing_stacktrace.raw();
if (pc_offset_array.Length() != 0) {
stacktrace.Append(code_array, pc_offset_array);
}
// Since we are re throwing and appending to the existing stack trace
// we clear out the catch trace collected in the existing stack trace
// as that trace will not be valid anymore.
stacktrace.SetCatchStacktrace(Object::empty_array(),
Object::empty_array());
}
}
// 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) {
OS::Print("Exception '%s' thrown:\n", exception.ToCString());
OS::Print("%s\n", stacktrace.ToCString());
}
if (handler_exists) {
// Found a dart handler for the exception, jump to it.
JumpToExceptionHandler(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(
UnhandledException::New(exception, stacktrace));
stacktrace = Stacktrace::null();
JumpToExceptionHandler(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) {
const String& cls_name = String::Handle(Symbols::New(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(intptr_t location,
const String& src_type_name,
const String& dst_type_name,
const String& dst_name,
const String& error_msg) {
const Array& args = Array::Handle(Array::New(7));
ExceptionType exception_type =
(error_msg.IsNull() && dst_name.Equals(kCastErrorDstName)) ?
kCast : kType;
DartFrameIterator iterator;
const Script& script = Script::Handle(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(script.url()));
args.SetAt(1, Smi::Handle(Smi::New(line)));
args.SetAt(2, Smi::Handle(Smi::New(column)));
// Initialize '_srcType', '_dstType', '_dstName', and '_errorMsg'.
args.SetAt(3, src_type_name);
args.SetAt(4, dst_type_name);
args.SetAt(5, dst_name);
args.SetAt(6, 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) {
if (!error_msg.IsNull()) {
OS::Print("%s\n", error_msg.ToCString());
}
OS::Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ",
String::Handle(script.url()).ToCString(), line, column);
if (!dst_name.IsNull() && (dst_name.Length() > 0)) {
OS::Print("type '%s' is not a subtype of type '%s' of '%s'.\n",
src_type_name.ToCString(),
dst_type_name.ToCString(),
dst_name.ToCString());
} else {
OS::Print("type error.\n");
}
}
// Throw TypeError or CastError instance.
Exceptions::ThrowByType(exception_type, args);
UNREACHABLE();
}
void Exceptions::Throw(const Instance& exception) {
Isolate* isolate = Isolate::Current();
isolate->debugger()->SignalExceptionThrown(exception);
// Null object is a valid exception object.
ThrowExceptionHelper(exception, Instance::Handle(isolate));
}
void Exceptions::ReThrow(const Instance& exception,
const Instance& stacktrace) {
// Null object is a valid exception object.
ThrowExceptionHelper(exception, stacktrace);
}
void Exceptions::PropagateError(const Error& error) {
ASSERT(Isolate::Current()->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(uhe.exception());
const Instance& stk = Instance::Handle(uhe.stacktrace());
Exceptions::ReThrow(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(handler_pc, handler_sp, handler_fp, error,
Stacktrace::Handle()); // Null stacktrace.
}
UNREACHABLE();
}
void Exceptions::ThrowByType(ExceptionType type, const Array& arguments) {
const Object& result = Object::Handle(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(Instance::Cast(result));
}
}
void Exceptions::ThrowOOM() {
Isolate* isolate = Isolate::Current();
const Instance& oom = Instance::Handle(
isolate, isolate->object_store()->out_of_memory());
Throw(oom);
}
void Exceptions::ThrowStackOverflow() {
Isolate* isolate = Isolate::Current();
const Instance& stack_overflow = Instance::Handle(
isolate, isolate->object_store()->stack_overflow());
Throw(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);
}
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();
break;
case kArgument:
library = Library::CoreLibrary();
class_name = &Symbols::ArgumentError();
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 kInternalError:
library = Library::CoreLibrary();
class_name = &Symbols::InternalError();
break;
case kNullThrown:
library = Library::CoreLibrary();
class_name = &Symbols::NullThrownError();
break;
case kIsolateSpawn:
library = Library::IsolateLibrary();
class_name = &Symbols::IsolateSpawnException();
break;
case kIsolateUnhandledException:
library = Library::IsolateLibrary();
class_name = &Symbols::IsolateUnhandledException();
break;
case kJavascriptIntegerOverflowError:
library = Library::CoreLibrary();
class_name = &Symbols::JavascriptIntegerOverflowError();
break;
case kJavascriptCompatibilityError:
library = Library::CoreLibrary();
class_name = &Symbols::JavascriptCompatibilityError();
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 kMirroredCompilationError:
library = Library::MirrorsLibrary();
class_name = &Symbols::MirroredCompilationError();
break;
}
return DartLibraryCalls::InstanceCreate(library,
*class_name,
*constructor_name,
arguments);
}
// Throw JavascriptCompatibilityError exception.
static void ThrowJavascriptCompatibilityError(const char* msg) {
const Array& exc_args = Array::Handle(Array::New(1));
const String& msg_str = String::Handle(String::New(msg));
exc_args.SetAt(0, msg_str);
Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args);
}
void Exceptions::JSWarning(StackFrame* caller_frame, const char* format, ...) {
ASSERT(caller_frame != NULL);
ASSERT(FLAG_warn_on_javascript_compatibility);
if (FLAG_silent_warnings) return;
const Code& caller_code = Code::Handle(caller_frame->LookupDartCode());
ASSERT(!caller_code.IsNull());
const uword caller_pc = caller_frame->pc();
const intptr_t token_pos = caller_code.GetTokenIndexOfPC(caller_pc);
const Function& caller = Function::Handle(caller_code.function());
const Script& script = Script::Handle(caller.script());
va_list args;
va_start(args, format);
const Error& error = Error::Handle(
LanguageError::NewFormattedV(Error::Handle(), // No previous error.
script, token_pos, LanguageError::kWarning,
Heap::kNew, format, args));
va_end(args);
if (FLAG_warning_as_error) {
ThrowJavascriptCompatibilityError(error.ToErrorCString());
} else {
OS::Print("javascript compatibility warning: %s", error.ToErrorCString());
}
const Stacktrace& stacktrace =
Stacktrace::Handle(Exceptions::CurrentStacktrace());
intptr_t idx = 0;
OS::Print("%s",
stacktrace.ToCStringInternal(&idx,
FLAG_stacktrace_depth_on_warning));
}
} // namespace dart