mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:39:48 +00:00
[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:
parent
679a1a7867
commit
07f43510a2
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_); }
|
||||
|
|
Loading…
Reference in a new issue