[vm] Fix some cases of dropped errors and confusion between Exceptions::PropagateError and LongJumpScope::Jump.

Assert against Exceptions::PropagateError skipping over LongJumpScopes and LongJumpScope::Jump skipping over exit frames.

Bug: https://github.com/dart-lang/sdk/issues/35224
Change-Id: I67004a73265882191cb1945cb5a049559b747e89
Reviewed-on: https://dart-review.googlesource.com/c/85411
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Ryan Macnak 2018-12-05 18:57:02 +00:00 committed by commit-bot@chromium.org
parent 679a1a7867
commit 07f43510a2
21 changed files with 186 additions and 167 deletions

View file

@ -28,10 +28,8 @@ DEFINE_NATIVE_ENTRY(RegExp_factory, 4) {
// Parse the pattern once in order to throw any format exceptions within
// the factory constructor. It is parsed again upon compilation.
RegExpCompileData compileData;
if (!RegExpParser::ParseRegExp(pattern, multi_line, &compileData)) {
// Parsing failures throw an exception.
UNREACHABLE();
}
// Throws an exception on parsing failure.
RegExpParser::ParseRegExp(pattern, multi_line, &compileData);
// Create a RegExp object containing only the initial parameters.
return RegExpEngine::CreateRegExp(thread, pattern, multi_line, ignore_case);

View file

@ -247,7 +247,7 @@ RawObject* CompilationTraceLoader::CompileTriple(const char* uri_cstr,
if (!field_.IsNull() && field_.is_const() && field_.is_static() &&
(field_.StaticValue() == Object::sentinel().raw())) {
processed = true;
error_ = EvaluateInitializer(field_);
error_ = field_.EvaluateInitializer();
if (error_.IsError()) {
if (FLAG_trace_compilation_trace) {
THR_Print(
@ -303,16 +303,6 @@ RawObject* CompilationTraceLoader::CompileFunction(const Function& function) {
return Compiler::CompileFunction(thread_, function);
}
RawObject* CompilationTraceLoader::EvaluateInitializer(const Field& field) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
field_.EvaluateInitializer();
return Error::null();
} else {
return Thread::Current()->StealStickyError();
}
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart

View file

@ -43,7 +43,6 @@ class CompilationTraceLoader : public ValueObject {
const char* cls_cstr,
const char* func_cstr);
RawObject* CompileFunction(const Function& function);
RawObject* EvaluateInitializer(const Field& field);
Thread* thread_;
Zone* zone_;

View file

@ -2295,7 +2295,7 @@ bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
done = true;
} else {
// We bailed out or we encountered an error.
const Error& error = Error::Handle(thread()->sticky_error());
const Error& error = Error::Handle(thread()->StealStickyError());
if (error.raw() == Object::branch_offset_error().raw()) {
// Compilation failed due to an out of range branch offset in the
@ -2327,10 +2327,12 @@ bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
done = true;
}
// Clear the error if it was not a real error, but just a bailout.
if (error.IsLanguageError() &&
(LanguageError::Cast(error).kind() == Report::kBailout)) {
thread()->ClearStickyError();
// Discard the error if it was not a real error, but just a bailout.
} else {
// Otherwise, continue propagating.
thread()->set_sticky_error(error);
}
is_compiled = false;
}

View file

@ -587,7 +587,7 @@ static bool HasAnnotation(const Function& function, const char* annotation) {
auto& metadata_or_error = Object::Handle(library.GetMetadata(function));
if (metadata_or_error.IsError()) {
Exceptions::PropagateError(Error::Cast(metadata_or_error));
Report::LongJump(Error::Cast(metadata_or_error));
}
const Array& metadata = Array::Cast(metadata_or_error);
if (metadata.Length() > 0) {

View file

@ -376,10 +376,9 @@ void ConstantEvaluator::EvaluateStaticGet() {
}
Thread* thread = H.thread();
const Error& error =
Error::Handle(thread->zone(), thread->sticky_error());
Error::Handle(thread->zone(), thread->StealStickyError());
if (!error.IsNull()) {
field.SetStaticValue(Object::null_instance());
thread->ClearStickyError();
H.ReportError(error, script_, position, "Not a constant expression.");
UNREACHABLE();
}

View file

@ -168,10 +168,8 @@ void IrregexpCompilationPipeline::ParseFunction(
const bool multiline = regexp.is_multi_line();
RegExpCompileData* compile_data = new (zone) RegExpCompileData();
if (!RegExpParser::ParseRegExp(pattern, multiline, compile_data)) {
// Parsing failures are handled in the RegExp factory constructor.
UNREACHABLE();
}
// Parsing failures are handled in the RegExp factory constructor.
RegExpParser::ParseRegExp(pattern, multiline, compile_data);
regexp.set_num_bracket_expressions(compile_data->capture_count);
if (compile_data->simple) {
@ -862,7 +860,7 @@ RawCode* CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
done = true;
} else {
// We bailed out or we encountered an error.
const Error& error = Error::Handle(thread()->sticky_error());
const Error& error = Error::Handle(thread()->StealStickyError());
if (error.raw() == Object::branch_offset_error().raw()) {
// Compilation failed due to an out of range branch offset in the
@ -882,12 +880,14 @@ RawCode* CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
done = true;
}
// If is is not a background compilation, clear the error if it was not a
// real error, but just a bailout. If we're it a background compilation
// this will be dealt with in the caller.
if (!Compiler::IsBackgroundCompilation() && error.IsLanguageError() &&
(LanguageError::Cast(error).kind() == Report::kBailout)) {
thread()->ClearStickyError();
// If is is not a background compilation, discard the error if it was
// not a real error, but just a bailout. If we're it a background
// compilation this will be dealt with in the caller.
} else {
// Otherwise, continue propagating.
thread()->set_sticky_error(error);
}
}
}
@ -948,6 +948,8 @@ static RawObject* CompileFunctionHelper(CompilationPipeline* pipeline,
const Code& result = Code::Handle(helper.Compile(pipeline));
if (result.IsNull()) {
const Error& error = Error::Handle(thread->StealStickyError());
if (Compiler::IsBackgroundCompilation()) {
// Try again later, background compilation may abort because of
// state change during compilation.
@ -955,54 +957,58 @@ static RawObject* CompileFunctionHelper(CompilationPipeline* pipeline,
THR_Print("Aborted background compilation: %s\n",
function.ToFullyQualifiedCString());
}
{
// We got an error during compilation.
// If it was a bailout, then disable optimization.
const Error& error = Error::Handle(thread->StealStickyError());
if (error.raw() == Object::background_compilation_error().raw()) {
if (FLAG_trace_compiler) {
THR_Print(
"--> disabling background optimizations for '%s' (will "
"try to re-compile on isolate thread again)\n",
function.ToFullyQualifiedCString());
}
// Ensure we don't attempt to re-compile the function on the
// background compiler.
function.set_is_background_optimizable(false);
// Trigger another optimization soon on the main thread.
function.SetUsageCounter(optimized
? FLAG_optimization_counter_threshold
: FLAG_compilation_counter_threshold);
} else if ((error.IsLanguageError() &&
LanguageError::Cast(error).kind() == Report::kBailout) ||
error.IsUnhandledException()) {
if (FLAG_trace_compiler) {
THR_Print("--> disabling optimizations for '%s'\n",
function.ToFullyQualifiedCString());
}
function.SetIsOptimizable(false);
// We got an error during compilation.
// If it was a bailout, then disable optimization.
if (error.raw() == Object::background_compilation_error().raw()) {
if (FLAG_trace_compiler) {
THR_Print(
"--> disabling background optimizations for '%s' (will "
"try to re-compile on isolate thread again)\n",
function.ToFullyQualifiedCString());
}
// Ensure we don't attempt to re-compile the function on the
// background compiler.
function.set_is_background_optimizable(false);
// Trigger another optimization soon on the main thread.
function.SetUsageCounter(optimized
? FLAG_optimization_counter_threshold
: FLAG_compilation_counter_threshold);
return Error::null();
} else if (error.IsLanguageError() &&
LanguageError::Cast(error).kind() == Report::kBailout) {
if (FLAG_trace_compiler) {
THR_Print("--> disabling optimizations for '%s'\n",
function.ToFullyQualifiedCString());
}
function.SetIsOptimizable(false);
return Error::null();
} else {
// The background compiler does not execute Dart code or handle
// isolate messages.
ASSERT(!error.IsUnwindError());
return error.raw();
}
return Error::null();
}
if (optimized) {
// Optimizer bailed out. Disable optimizations and never try again.
if (trace_compiler) {
THR_Print("--> disabling optimizations for '%s'\n",
function.ToFullyQualifiedCString());
} else if (FLAG_trace_failed_optimization_attempts) {
THR_Print("Cannot optimize: %s\n",
function.ToFullyQualifiedCString());
if (error.IsLanguageError() &&
LanguageError::Cast(error).kind() == Report::kBailout) {
// Optimizer bailed out. Disable optimizations and never try again.
if (trace_compiler) {
THR_Print("--> disabling optimizations for '%s'\n",
function.ToFullyQualifiedCString());
} else if (FLAG_trace_failed_optimization_attempts) {
THR_Print("Cannot optimize: %s\n",
function.ToFullyQualifiedCString());
}
function.SetIsOptimizable(false);
return Error::null();
}
function.SetIsOptimizable(false);
return Error::null();
return error.raw();
} else {
ASSERT(!optimized);
// We got an error during compilation.
const Error& error = Error::Handle(thread->StealStickyError());
// The non-optimizing compiler can get an unhandled exception
// due to OOM or Stack overflow errors, it should not however
// bail out.

View file

@ -324,7 +324,7 @@ RawError* Debugger::PauseRequest(ServiceEvent::EventKind kind) {
if (ignore_breakpoints_ || IsPaused()) {
// We don't let the isolate get interrupted if we are already
// paused or ignoring breakpoints.
return Error::null();
return Thread::Current()->StealStickyError();
}
ServiceEvent event(isolate_, kind);
DebuggerStackTrace* trace = CollectStackTrace();
@ -732,7 +732,9 @@ RawObject* ActivationFrame::GetAsyncCompleter() {
}
RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) {
Instance& future = Instance::Handle();
DEBUG_ASSERT(Thread::Current()->TopErrorHandlerIsExitFrame());
Object& future = Object::Handle();
if (FLAG_sync_async) {
const Class& completer_cls = Class::Handle(completer.clazz());
ASSERT(!completer_cls.IsNull());
@ -741,7 +743,7 @@ RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) {
ASSERT(!future_getter.IsNull());
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, Instance::Cast(completer));
future ^= DartEntry::InvokeFunction(future_getter, args);
future = DartEntry::InvokeFunction(future_getter, args);
} else {
const Class& sync_completer_cls = Class::Handle(completer.clazz());
ASSERT(!sync_completer_cls.IsNull());
@ -750,7 +752,10 @@ RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) {
Field::Handle(completer_cls.LookupInstanceFieldAllowPrivate(
Symbols::CompleterFuture()));
ASSERT(!future_field.IsNull());
future ^= Instance::Cast(completer).GetField(future_field);
future = Instance::Cast(completer).GetField(future_field);
}
if (future.IsError()) {
Exceptions::PropagateError(Error::Cast(future));
}
if (future.IsNull()) {
// The completer object may not be fully initialized yet.
@ -761,7 +766,7 @@ RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) {
const Field& awaiter_field = Field::Handle(
future_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter()));
ASSERT(!awaiter_field.IsNull());
return future.GetField(awaiter_field);
return Instance::Cast(future).GetField(awaiter_field);
}
RawObject* ActivationFrame::GetAsyncStreamControllerStream() {

View file

@ -21,7 +21,6 @@
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/tags.h"
namespace dart {
@ -623,6 +622,7 @@ static void ThrowExceptionHelper(Thread* thread,
const Instance& incoming_exception,
const Instance& existing_stacktrace,
const bool is_rethrow) {
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
bool use_preallocated_stacktrace = false;
@ -875,9 +875,10 @@ void Exceptions::ReThrow(Thread* thread,
}
void Exceptions::PropagateError(const Error& error) {
ASSERT(!error.IsNull());
Thread* thread = Thread::Current();
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
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.

View file

@ -2856,6 +2856,7 @@ void Isolate::UnscheduleThread(Thread* thread,
} else {
ASSERT(thread->api_top_scope_ == NULL);
ASSERT(thread->zone_ == NULL);
ASSERT(thread->sticky_error() == Error::null());
}
if (!bypass_safepoint) {
// Ensure that the thread reports itself as being at a safepoint.

View file

@ -9,7 +9,6 @@
#include "vm/dart_api_impl.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/os.h"
namespace dart {
@ -24,8 +23,10 @@ void LongJumpScope::Jump(int value, const Error& error) {
// A zero is the default return value from setting up a LongJumpScope
// using Set.
ASSERT(value != 0);
ASSERT(!error.IsNull());
Thread* thread = Thread::Current();
DEBUG_ASSERT(thread->TopErrorHandlerIsSetJump());
#if defined(DEBUG)
#define CHECK_REUSABLE_HANDLE(name) \

View file

@ -5988,8 +5988,9 @@ void Function::ClearCode() const {
void Function::EnsureHasCompiledUnoptimizedCode() const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
ASSERT(thread->IsMutatorThread());
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
Zone* zone = thread->zone();
const Error& error =
Error::Handle(zone, Compiler::EnsureUnoptimizedCode(thread, *this));
@ -6004,6 +6005,7 @@ void Function::SwitchToUnoptimizedCode() const {
Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
ASSERT(thread->IsMutatorThread());
// TODO(35224): DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
const Code& current_code = Code::Handle(zone, CurrentCode());
if (FLAG_trace_deoptimization_verbose) {
@ -8259,6 +8261,8 @@ bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const {
RawCode* Function::EnsureHasCode() const {
if (HasCode()) return CurrentCode();
Thread* thread = Thread::Current();
ASSERT(thread->IsMutatorThread());
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
Zone* zone = thread->zone();
const Object& result =
Object::Handle(zone, Compiler::CompileFunction(thread, *this));
@ -8921,31 +8925,29 @@ bool Field::HasPrecompiledInitializer() const {
raw_ptr()->initializer_.precompiled_->IsFunction();
}
void Field::EvaluateInitializer() const {
RawError* Field::EvaluateInitializer() const {
ASSERT(IsOriginal());
ASSERT(is_static());
if (StaticValue() == Object::sentinel().raw()) {
SetStaticValue(Object::transition_sentinel());
const Object& value =
Object::Handle(Compiler::EvaluateStaticInitializer(*this));
if (value.IsError()) {
if (!value.IsNull() && value.IsError()) {
SetStaticValue(Object::null_instance());
Exceptions::PropagateError(Error::Cast(value));
UNREACHABLE();
return Error::Cast(value).raw();
}
ASSERT(value.IsNull() || value.IsInstance());
SetStaticValue(value.IsNull() ? Instance::null_instance()
: Instance::Cast(value));
return;
return Error::null();
} else if (StaticValue() == Object::transition_sentinel().raw()) {
const Array& ctor_args = Array::Handle(Array::New(1));
const String& field_name = String::Handle(name());
ctor_args.SetAt(0, field_name);
Exceptions::ThrowByType(Exceptions::kCyclicInitializationError, ctor_args);
UNREACHABLE();
return;
}
UNREACHABLE();
return Error::null();
}
static intptr_t GetListLength(const Object& value) {
@ -21947,7 +21949,9 @@ const char* Closure::ToCString() const {
}
int64_t Closure::ComputeHash() const {
Zone* zone = Thread::Current()->zone();
Thread* thread = Thread::Current();
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
Zone* zone = thread->zone();
const Function& func = Function::Handle(zone, function());
uint32_t result = 0;
if (func.IsImplicitInstanceClosureFunction()) {

View file

@ -3437,7 +3437,7 @@ class Field : public Object {
bool IsUninitialized() const;
void EvaluateInitializer() const;
DART_WARN_UNUSED_RESULT RawError* EvaluateInitializer() const;
RawFunction* PrecompiledInitializer() const {
return raw_ptr()->initializer_.precompiled_;

View file

@ -430,10 +430,9 @@ static intptr_t Prepare(const RegExp& regexp,
const bool multiline = regexp.is_multi_line();
RegExpCompileData* compile_data = new (zone) RegExpCompileData();
if (!RegExpParser::ParseRegExp(pattern, multiline, compile_data)) {
// Parsing failures are handled in the RegExp factory constructor.
UNREACHABLE();
}
// Parsing failures are handled in the RegExp factory constructor.
RegExpParser::ParseRegExp(pattern, multiline, compile_data);
regexp.set_num_bracket_expressions(compile_data->capture_count);
if (compile_data->simple) {

View file

@ -11,6 +11,7 @@
#include "vm/compiler/frontend/flow_graph_builder.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_entry.h"
#include "vm/longjump.h"
#include "vm/object_store.h"
#include "vm/regexp.h"
#include "vm/resolver.h"
@ -385,9 +386,14 @@ ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const {
regexp_class.LookupStaticFieldAllowPrivate(Symbols::_wordCharacterMap()));
ASSERT(!word_character_field.IsNull());
DEBUG_ASSERT(Thread::Current()->TopErrorHandlerIsSetJump());
if (word_character_field.IsUninitialized()) {
ASSERT(!Compiler::IsBackgroundCompilation());
word_character_field.EvaluateInitializer();
const Error& error =
Error::Handle(Z, word_character_field.EvaluateInitializer());
if (!error.IsNull()) {
Report::LongJump(error);
}
}
ASSERT(!word_character_field.IsUninitialized());

View file

@ -190,7 +190,6 @@ void RegExpBuilder::AddQuantifierToAtom(
RegExpParser::RegExpParser(const String& in, String* error, bool multiline)
: zone_(Thread::Current()->zone()),
error_(error),
captures_(NULL),
in_(in),
current_(kEndMarker),
@ -200,8 +199,7 @@ RegExpParser::RegExpParser(const String& in, String* error, bool multiline)
multiline_(multiline),
simple_(false),
contains_anchor_(false),
is_scanned_for_captures_(false),
failed_(false) {
is_scanned_for_captures_(false) {
Advance();
}
@ -239,14 +237,16 @@ bool RegExpParser::simple() {
}
void RegExpParser::ReportError(const char* message) {
failed_ = true;
*error_ = String::New(message);
// Zip to the end to make sure the no more input is read.
current_ = kEndMarker;
next_pos_ = in().Length();
const Error& error = Error::Handle(LanguageError::New(*error_));
Report::LongJump(error);
// Throw a FormatException on parsing failures.
const String& msg = String::Handle(
String::Concat(String::Handle(String::New(message)), in()));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, msg);
Exceptions::ThrowByType(Exceptions::kFormat, args);
UNREACHABLE();
}
@ -1012,34 +1012,20 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
// ----------------------------------------------------------------------------
// The Parser interface.
bool RegExpParser::ParseRegExp(const String& input,
void RegExpParser::ParseRegExp(const String& input,
bool multiline,
RegExpCompileData* result) {
ASSERT(result != NULL);
LongJumpScope jump;
RegExpParser parser(input, &result->error, multiline);
if (setjmp(*jump.Set()) == 0) {
RegExpTree* tree = parser.ParsePattern();
ASSERT(tree != NULL);
ASSERT(result->error.IsNull());
result->tree = tree;
intptr_t capture_count = parser.captures_started();
result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
result->contains_anchor = parser.contains_anchor();
result->capture_count = capture_count;
} else {
ASSERT(!result->error.IsNull());
Thread::Current()->ClearStickyError();
// Throw a FormatException on parsing failures.
const String& message =
String::Handle(String::Concat(result->error, input));
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, message);
Exceptions::ThrowByType(Exceptions::kFormat, args);
}
return !parser.failed();
// Throws an exception if 'input' is not valid.
RegExpTree* tree = parser.ParsePattern();
ASSERT(tree != NULL);
ASSERT(result->error.IsNull());
result->tree = tree;
intptr_t capture_count = parser.captures_started();
result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
result->contains_anchor = parser.contains_anchor();
result->capture_count = capture_count;
}
} // namespace dart

View file

@ -53,7 +53,7 @@ class RegExpParser : public ValueObject {
public:
RegExpParser(const String& in, String* error, bool multiline_mode);
static bool ParseRegExp(const String& input,
static void ParseRegExp(const String& input,
bool multiline,
RegExpCompileData* result);
@ -97,7 +97,6 @@ class RegExpParser : public ValueObject {
return captures_ == NULL ? 0 : captures_->length();
}
intptr_t position() { return next_pos_ - 1; }
bool failed() { return failed_; }
static const intptr_t kMaxCaptures = 1 << 16;
static const uint32_t kEndMarker = (1 << 21);
@ -154,7 +153,6 @@ class RegExpParser : public ValueObject {
void ScanForCaptures();
Zone* zone_;
String* error_;
ZoneGrowableArray<RegExpCapture*>* captures_;
const String& in_;
uint32_t current_;
@ -166,7 +164,6 @@ class RegExpParser : public ValueObject {
bool simple_;
bool contains_anchor_;
bool is_scanned_for_captures_;
bool failed_;
};
} // namespace dart

View file

@ -473,8 +473,8 @@ DEFINE_RUNTIME_ENTRY(ExtractMethod, 2) {
// Result of an invoke may be an unhandled exception, in which case we
// rethrow it.
static void CheckResultError(const Object& result) {
if (result.IsError()) {
static void ThrowIfError(const Object& result) {
if (!result.IsNull() && result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
}
}
@ -501,7 +501,7 @@ DEFINE_RUNTIME_ENTRY(GetFieldForDispatch, 2) {
args.SetAt(0, receiver);
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(getter, args));
CheckResultError(result);
ThrowIfError(result);
arguments.SetReturn(result);
}
@ -1013,20 +1013,14 @@ DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
zone, isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
const Error& error =
Error::Handle(zone, isolate->debugger()->PauseBreakpoint());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
ThrowIfError(error);
arguments.SetReturn(orig_stub);
}
#else
// Gets called from the simulator when the breakpoint is reached.
DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
const Error& error = Error::Handle(isolate->debugger()->PauseBreakpoint());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
ThrowIfError(error);
}
#endif // !defined(TARGET_ARCH_DBC)
@ -1036,10 +1030,7 @@ DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
#else
const Error& error =
Error::Handle(zone, isolate->debugger()->PauseStepping());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
ThrowIfError(error);
#endif
}
@ -1715,7 +1706,7 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) {
const Object& result = Object::Handle( \
zone, DartEntry::InvokeNoSuchMethod( \
receiver, target_name, orig_arguments, orig_arguments_desc)); \
CheckResultError(result); \
ThrowIfError(result); \
arguments.SetReturn(result);
#define CLOSURIZE(some_function) \
@ -1750,7 +1741,7 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) {
// would perform the closure call.
const Object& result = Object::Handle(
zone, DartEntry::InvokeClosure(orig_arguments, orig_arguments_desc));
CheckResultError(result);
ThrowIfError(result);
arguments.SetReturn(result);
return;
}
@ -1770,14 +1761,14 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) {
getter_arguments.SetAt(0, receiver);
const Object& getter_result = Object::Handle(
zone, DartEntry::InvokeFunction(function, getter_arguments));
CheckResultError(getter_result);
ThrowIfError(getter_result);
ASSERT(getter_result.IsNull() || getter_result.IsInstance());
orig_arguments.SetAt(args_desc.FirstArgIndex(), getter_result);
const Object& call_result = Object::Handle(
zone,
DartEntry::InvokeClosure(orig_arguments, orig_arguments_desc));
CheckResultError(call_result);
ThrowIfError(call_result);
arguments.SetReturn(call_result);
return;
}
@ -1810,7 +1801,7 @@ DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) {
String::Handle(function.QualifiedUserVisibleName());
const Object& result = Object::Handle(DartEntry::InvokeNoSuchMethod(
receiver, original_function_name, orig_arguments, orig_arguments_desc));
CheckResultError(result);
ThrowIfError(result);
arguments.SetReturn(result);
}
@ -2010,9 +2001,7 @@ static void HandleOSRRequest(Thread* thread) {
// it cannot have been removed from the function.
const Object& result = Object::Handle(
Compiler::CompileOptimizedFunction(thread, function, osr_id));
if (result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
}
ThrowIfError(result);
if (!result.IsNull()) {
const Code& code = Code::Cast(result);
@ -2072,10 +2061,7 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
// - store buffer overflow
// - OOB message (vm-service or dart:isolate)
const Error& error = Error::Handle(thread->HandleInterrupts());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
ThrowIfError(error);
#if !defined(DART_PRECOMPILED_RUNTIME)
if ((stack_overflow_flags & Thread::kOsrRequest) != 0) {
@ -2165,9 +2151,7 @@ DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) {
} else {
result = Compiler::CompileFunction(thread, function);
}
if (result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
}
ThrowIfError(result);
}
arguments.SetReturn(function);
#else
@ -2587,7 +2571,8 @@ DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) {
DEFINE_RUNTIME_ENTRY(InitStaticField, 1) {
const Field& field = Field::CheckedHandle(zone, arguments.ArgAt(0));
field.EvaluateInitializer();
const Error& result = Error::Handle(zone, field.EvaluateInitializer());
ThrowIfError(result);
}
// Print the stop message.

View file

@ -1432,7 +1432,12 @@ intptr_t SnapshotWriter::FindVmSnapshotObject(RawObject* rawobj) {
void SnapshotWriter::ThrowException(Exceptions::ExceptionType type,
const char* msg) {
thread()->ClearStickyError();
{
NoSafepointScope no_safepoint;
RawError* error = thread()->StealStickyError();
ASSERT(error == Object::snapshot_writer_error().raw());
}
if (msg != NULL) {
const String& msg_obj = String::Handle(String::New(msg));
const Array& args = Array::Handle(Array::New(1));
@ -1502,12 +1507,18 @@ Message* MessageWriter::WriteMessage(const Object& obj,
// Setup for long jump in case there is an exception while writing
// the message.
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
NoSafepointScope no_safepoint;
WriteObject(obj.raw());
} else {
FreeBuffer();
bool has_exception = false;
{
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
NoSafepointScope no_safepoint;
WriteObject(obj.raw());
} else {
FreeBuffer();
has_exception = true;
}
}
if (has_exception) {
ThrowException(exception_type(), exception_msg());
}

View file

@ -803,6 +803,28 @@ intptr_t Thread::OffsetFromThread(const RuntimeEntry* runtime_entry) {
return -1;
}
#if defined(DEBUG)
bool Thread::TopErrorHandlerIsSetJump() const {
if (long_jump_base_ == nullptr) return false;
if (top_exit_frame_info_ == 0) return true;
#if defined(USING_SIMULATOR) || defined(USING_SAFE_STACK)
return true; // False positives.
#else
return reinterpret_cast<uword>(long_jump_base_) < top_exit_frame_info_;
#endif
}
bool Thread::TopErrorHandlerIsExitFrame() const {
if (top_exit_frame_info_ == 0) return false;
if (long_jump_base_ == nullptr) return true;
#if defined(USING_SIMULATOR) || defined(USING_SAFE_STACK)
return true; // False positives.
#else
return top_exit_frame_info_ < reinterpret_cast<uword>(long_jump_base_);
#endif
}
#endif // defined(DEBUG)
bool Thread::IsValidHandle(Dart_Handle object) const {
return IsValidLocalHandle(object) || IsValidZoneHandle(object) ||
IsValidScopedHandle(object);

View file

@ -558,6 +558,13 @@ class Thread : public BaseThread {
LongJumpScope* long_jump_base() const { return long_jump_base_; }
void set_long_jump_base(LongJumpScope* value) { long_jump_base_ = value; }
#if defined(DEBUG)
// For asserts only. Has false positives when running with a simulator or
// SafeStack.
bool TopErrorHandlerIsSetJump() const;
bool TopErrorHandlerIsExitFrame() const;
#endif
uword vm_tag() const { return vm_tag_; }
void set_vm_tag(uword tag) { vm_tag_ = tag; }
static intptr_t vm_tag_offset() { return OFFSET_OF(Thread, vm_tag_); }