Remove legacy restart code

Also fixes #29092 by threading Error objects back to the message handler.

BUG=
R=asiva@google.com, rmacnak@google.com

Review-Url: https://codereview.chromium.org/2759533002 .
This commit is contained in:
John McCutchan 2017-03-20 08:47:39 -07:00
parent ee7fe44941
commit a4adbffb50
21 changed files with 71 additions and 162 deletions

View file

@ -16,8 +16,6 @@ static const int kApiErrorExitCode = 253;
static const int kCompilationErrorExitCode = 254;
// Exit code indicating an unhandled error that is not a compilation error.
static const int kErrorExitCode = 255;
// Exit code indicating a vm restart request. Never returned to the user.
static const int kRestartRequestExitCode = 1000;
void ErrorExit(int exit_code, const char* format, ...);

View file

@ -37,8 +37,6 @@ static const int kApiErrorExitCode = 253;
static const int kCompilationErrorExitCode = 254;
// Exit code indicating an unhandled error that is not a compilation error.
static const int kErrorExitCode = 255;
// Exit code indicating a vm restart request. Never returned to the user.
static const int kRestartRequestExitCode = 1000;
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
@ -48,8 +46,6 @@ static const int kRestartRequestExitCode = 1000;
exit_code = kCompilationErrorExitCode; \
} else if (Dart_IsApiError(result)) { \
exit_code = kApiErrorExitCode; \
} else if (Dart_IsVMRestartRequest(result)) { \
exit_code = kRestartRequestExitCode; \
} else { \
exit_code = kErrorExitCode; \
} \

View file

@ -761,8 +761,6 @@ static Dart_Handle EnvironmentCallback(Dart_Handle name) {
*exit_code = kCompilationErrorExitCode; \
} else if (Dart_IsApiError(result)) { \
*exit_code = kApiErrorExitCode; \
} else if (Dart_IsVMRestartRequest(result)) { \
*exit_code = kRestartRequestExitCode; \
} else { \
*exit_code = kErrorExitCode; \
} \
@ -1215,11 +1213,6 @@ static void GenerateAppAOTSnapshot() {
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
if (Dart_IsVMRestartRequest(result)) { \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
return true; \
} \
const int exit_code = Dart_IsCompilationError(result) \
? kCompilationErrorExitCode \
: kErrorExitCode; \
@ -1253,10 +1246,6 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
commandline_packages_file, NULL, &error, &exit_code);
if (isolate == NULL) {
delete[] isolate_name;
if (exit_code == kRestartRequestExitCode) {
free(error);
return true;
}
Log::PrintErr("%s\n", error);
free(error);
error = NULL;
@ -1411,8 +1400,7 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
result = Dart_RunLoop();
// Generate an app snapshot after execution if specified.
if (gen_snapshot_kind == kAppJIT) {
if (!Dart_IsCompilationError(result) &&
!Dart_IsVMRestartRequest(result)) {
if (!Dart_IsCompilationError(result)) {
Snapshot::GenerateAppJIT(snapshot_filename);
}
}

View file

@ -132,10 +132,7 @@ typedef struct _Dart_Isolate* Dart_Isolate;
* occur in any function which triggers the execution of Dart code.
*
* - Fatal error handles are produced when the system wants to shut
* down the current isolate. Sometimes a fatal error may be a
* restart request (see Dart_IsRestartRequest). If the embedder does
* not support restarting the VM, then this should be treated as a
* normal fatal error.
* down the current isolate.
*
* --- Propagating errors ---
*
@ -311,17 +308,6 @@ DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle);
*/
DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
/**
* Is this error a request to restart the VM?
*
* If an embedder chooses to support restarting the VM from tools
* (such as a debugger), then this function is used to distinguish
* restart requests from other fatal errors.
*
* Requires there to be a current isolate.
*/
DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle);
/**
* Gets the error message from an error handle.
*

View file

@ -122,7 +122,7 @@ DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 2) {
DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
Service::HandleRootMessage(message);
return Service::HandleRootMessage(message);
}
return Object::null();
}
@ -131,7 +131,7 @@ DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
Service::HandleObjectRootMessage(message);
return Service::HandleObjectRootMessage(message);
}
return Object::null();
}

View file

@ -1242,39 +1242,12 @@ class VmNameCommand extends DebuggerCommand {
'Syntax: vm name <name>\n';
}
class VmRestartCommand extends DebuggerCommand {
VmRestartCommand(Debugger debugger) : super(debugger, 'restart', []);
Future handleModalInput(String line) async {
if (line == 'yes') {
debugger.console.printRed('Restarting VM...');
await debugger.vm.restart();
debugger.input.exitMode();
} else if (line == 'no') {
debugger.console.printRed('VM restart canceled.');
debugger.input.exitMode();
} else {
debugger.console.printRed("Please type 'yes' or 'no'");
}
}
Future run(List<String> args) async {
debugger.input.enterMode('Restart vm? (yes/no)', handleModalInput);
}
String helpShort = 'Restart a Dart virtual machine';
String helpLong = 'Restart a Dart virtual machine.\n'
'\n'
'Syntax: vm restart\n';
}
class VmCommand extends DebuggerCommand {
VmCommand(Debugger debugger)
: super(debugger, 'vm', [
new VmListCommand(debugger),
new VmNameCommand(debugger),
new VmRestartCommand(debugger),
]);
Future run(List<String> args) async {

View file

@ -853,10 +853,6 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
}
}
Future restart() {
return invokeRpc('_restartVM', {});
}
Future<Map> _fetchDirect({int count: kDefaultFieldLimit}) async {
if (!loaded) {
// The vm service relies on these events to keep the VM and

View file

@ -27,9 +27,6 @@ evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
debugger_location_second_test: Pass, Slow
debugger_location_test: Pass, Slow
# Can be slow in debug mode, as well.
vm_restart_test: Pass, Slow
# These tests are slow on simulators.
[ $arch == simarm || $arch == simmips || $arch == simarm64 ]
*: Pass, Slow
@ -64,7 +61,6 @@ evaluate_activation_test/scope: RuntimeError # Issue 27806
get_object_rpc_test: RuntimeError # Issue 27806
get_source_report_test: RuntimeError # Issue 27806
set_name_rpc_test: RuntimeError # Issue 27806
vm_restart_test: CompileTimeError # Issue 27806
debugger_location_second_test: Skip # Issue 28180

View file

@ -20,7 +20,6 @@ library_dependency_test: RuntimeError # There are no imports and exports in kern
# 'VMServiceIO_Shutdown' (0 arguments) cannot be found
# because of '--compile_all'
capture_stdio_test: CompileTimeError
vm_restart_test: CompileTimeError
address_mapper_test: CompileTimeError
###

View file

@ -809,13 +809,6 @@ DART_EXPORT bool Dart_IsFatalError(Dart_Handle object) {
}
DART_EXPORT bool Dart_IsVMRestartRequest(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
return (obj.IsUnwindError() && UnwindError::Cast(obj).is_vm_restart());
}
DART_EXPORT const char* Dart_GetError(Dart_Handle handle) {
API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());

View file

@ -314,8 +314,7 @@ RawError* IsolateMessageHandler::HandleLibMessage(const Array& message) {
break;
}
case Isolate::kKillMsg:
case Isolate::kInternalKillMsg:
case Isolate::kVMRestartMsg: {
case Isolate::kInternalKillMsg: {
// [ OOB, kKillMsg, terminate capability, priority ]
if (message.Length() != 4) return Error::null();
Object& obj = Object::Handle(zone, message.At(3));
@ -336,16 +335,6 @@ RawError* IsolateMessageHandler::HandleLibMessage(const Array& message) {
const String& msg =
String::Handle(String::New("isolate terminated by vm"));
return UnwindError::New(msg);
} else if (msg_type == Isolate::kVMRestartMsg) {
// If this is the main isolate, this request to restart
// will be caught and handled in the embedder. Otherwise
// this unwind error will cause the isolate to exit.
const String& msg = String::Handle(
String::New("isolate terminated for vm restart"));
const UnwindError& error =
UnwindError::Handle(UnwindError::New(msg));
error.set_is_vm_restart(true);
return error.raw();
} else {
UNREACHABLE();
}
@ -531,7 +520,11 @@ MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
switch (Smi::Cast(oob_tag).Value()) {
case Message::kServiceOOBMsg: {
if (FLAG_support_service) {
Service::HandleIsolateMessage(I, oob_msg);
const Error& error =
Error::Handle(Service::HandleIsolateMessage(I, oob_msg));
if (!error.IsNull()) {
status = ProcessUnhandledException(error);
}
} else {
UNREACHABLE();
}
@ -650,11 +643,7 @@ static MessageHandler::MessageStatus StoreError(Thread* thread,
if (error.IsUnwindError()) {
const UnwindError& unwind = UnwindError::Cast(error);
if (!unwind.is_user_initiated()) {
if (unwind.is_vm_restart()) {
return MessageHandler::kRestart;
} else {
return MessageHandler::kShutdown;
}
return MessageHandler::kShutdown;
}
}
return MessageHandler::kError;
@ -1033,18 +1022,24 @@ bool Isolate::IsPaused() const {
}
void Isolate::PausePostRequest() {
RawError* Isolate::PausePostRequest() {
if (!FLAG_support_debugger) {
return;
return Error::null();
}
if (debugger_ == NULL) {
return;
return Error::null();
}
ASSERT(!IsPaused());
const Error& error = Error::Handle(debugger_->PausePostRequest());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
if (Thread::Current()->top_exit_frame_info() == 0) {
return error.raw();
} else {
Exceptions::PropagateError(error);
UNREACHABLE();
}
}
return Error::null();
}

View file

@ -163,7 +163,6 @@ class Isolate : public BaseIsolate {
// Internal message ids.
kInterruptMsg = 10, // Break in the debugger.
kInternalKillMsg = 11, // Like kill, but does not run exit listeners, etc.
kVMRestartMsg = 12, // Sent to isolates when vm is restarting.
};
// The different Isolate API message priorities for ping and kill messages.
enum LibMsgPriority {
@ -530,7 +529,7 @@ class Isolate : public BaseIsolate {
should_pause_post_service_request_ = should_pause_post_service_request;
}
void PausePostRequest();
RawError* PausePostRequest();
uword user_tag() const { return user_tag_; }
static intptr_t user_tag_offset() { return OFFSET_OF(Isolate, user_tag_); }

View file

@ -635,17 +635,18 @@ void IsolateReloadContext::Reload(bool force_reload,
TIR_Print("---- EXITED TAG HANDLER\n");
if (result.IsUnwindError()) {
// We can only propagate errors when there are Dart frames on the stack.
// TODO(johnmccutchan): Fix dartbug.com/29092.
if (thread->top_exit_frame_info() == 0) {
FATAL(
"Got an Unwind Error in the middle of a reload. "
"http://dartbug.com/29092");
// We can only propagate errors when there are Dart frames on the stack.
// In this case there are no Dart frames on the stack and we set the
// thread's sticky error. This error will be returned to the message
// handler.
thread->set_sticky_error(Error::Cast(result));
} else {
// If the tag handler returns with an UnwindError error, propagate it and
// give up.
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
// If the tag handler returns with an UnwindError error, propagate it and
// give up.
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
// Other errors (e.g. a parse error) are captured by the reload system.

View file

@ -15406,7 +15406,6 @@ RawUnwindError* UnwindError::New(const String& message, Heap::Space space) {
}
result.set_message(message);
result.set_is_user_initiated(false);
result.set_is_vm_restart(false);
return result.raw();
}
@ -15421,11 +15420,6 @@ void UnwindError::set_is_user_initiated(bool value) const {
}
void UnwindError::set_is_vm_restart(bool value) const {
StoreNonPointer(&raw_ptr()->is_vm_restart_, value);
}
const char* UnwindError::ToErrorCString() const {
const String& msg_str = String::Handle(message());
return msg_str.ToCString();

View file

@ -5421,9 +5421,6 @@ class UnwindError : public Error {
bool is_user_initiated() const { return raw_ptr()->is_user_initiated_; }
void set_is_user_initiated(bool value) const;
bool is_vm_restart() const { return raw_ptr()->is_vm_restart_; }
void set_is_vm_restart(bool value) const;
RawString* message() const { return raw_ptr()->message_; }
static intptr_t InstanceSize() {

View file

@ -997,7 +997,6 @@ void UnwindError::PrintJSONImpl(JSONStream* stream, bool ref) const {
jsobj.AddServiceId(*this);
jsobj.AddProperty("message", ToErrorCString());
jsobj.AddProperty("_is_user_initiated", is_user_initiated());
jsobj.AddProperty("_is_vm_restart", is_vm_restart());
}

View file

@ -1629,7 +1629,6 @@ class RawUnwindError : public RawError {
RawString* message_;
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->message_); }
bool is_user_initiated_;
bool is_vm_restart_;
};

View file

@ -813,9 +813,9 @@ void Service::PostError(const String& method_name,
}
void Service::InvokeMethod(Isolate* I,
const Array& msg,
bool parameters_are_dart_objects) {
RawError* Service::InvokeMethod(Isolate* I,
const Array& msg,
bool parameters_are_dart_objects) {
Thread* T = Thread::Current();
ASSERT(I == T->isolate());
ASSERT(I != NULL);
@ -877,7 +877,7 @@ void Service::InvokeMethod(Isolate* I,
// For now, always return an error.
PrintInvalidParamError(&js, "_idZone");
js.PostReply();
return;
return T->get_and_clear_sticky_error();
}
}
const char* c_method_name = method_name.ToCString();
@ -886,7 +886,7 @@ void Service::InvokeMethod(Isolate* I,
if (method != NULL) {
if (!ValidateParameters(method->parameters, &js)) {
js.PostReply();
return;
return T->get_and_clear_sticky_error();
}
if (method->entry(T, &js)) {
js.PostReply();
@ -895,7 +895,7 @@ void Service::InvokeMethod(Isolate* I,
// so this case shouldn't be reached, at present.
UNIMPLEMENTED();
}
return;
return T->get_and_clear_sticky_error();
}
EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(c_method_name);
@ -905,7 +905,7 @@ void Service::InvokeMethod(Isolate* I,
if (handler != NULL) {
EmbedderHandleMessage(handler, &js);
return;
return T->get_and_clear_sticky_error();
}
const Instance& extension_handler =
@ -915,32 +915,32 @@ void Service::InvokeMethod(Isolate* I,
param_values, reply_port, seq);
// Schedule was successful. Extension code will post a reply
// asynchronously.
return;
return T->get_and_clear_sticky_error();
}
PrintUnrecognizedMethodError(&js);
js.PostReply();
return;
return T->get_and_clear_sticky_error();
}
}
void Service::HandleRootMessage(const Array& msg_instance) {
RawError* Service::HandleRootMessage(const Array& msg_instance) {
Isolate* isolate = Isolate::Current();
InvokeMethod(isolate, msg_instance);
return InvokeMethod(isolate, msg_instance);
}
void Service::HandleObjectRootMessage(const Array& msg_instance) {
RawError* Service::HandleObjectRootMessage(const Array& msg_instance) {
Isolate* isolate = Isolate::Current();
InvokeMethod(isolate, msg_instance, true);
return InvokeMethod(isolate, msg_instance, true);
}
void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
RawError* Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
ASSERT(isolate != NULL);
InvokeMethod(isolate, msg);
MaybePause(isolate);
const Error& error = Error::Handle(InvokeMethod(isolate, msg));
return MaybePause(isolate, error);
}
@ -2538,14 +2538,18 @@ void Service::CheckForPause(Isolate* isolate, JSONStream* stream) {
}
void Service::MaybePause(Isolate* isolate) {
RawError* Service::MaybePause(Isolate* isolate, const Error& error) {
// Don't pause twice.
if (!isolate->IsPaused()) {
if (isolate->should_pause_post_service_request()) {
isolate->set_should_pause_post_service_request(false);
isolate->PausePostRequest();
// Before pausing, restore the sticky error. The debugger will return it
// from PausePostRequest.
Thread::Current()->set_sticky_error(error);
return isolate->PausePostRequest();
}
}
return error.raw();
}
@ -3861,18 +3865,6 @@ static bool GetVM(Thread* thread, JSONStream* js) {
}
static const MethodParameter* restart_vm_params[] = {
NO_ISOLATE_PARAMETER, NULL,
};
static bool RestartVM(Thread* thread, JSONStream* js) {
Isolate::KillAllIsolates(Isolate::kVMRestartMsg);
PrintSuccess(js);
return true;
}
static const char* exception_pause_mode_names[] = {
"All", "None", "Unhandled", NULL,
};
@ -4142,8 +4134,6 @@ static const ServiceMethodDescriptor service_methods_[] = {
pause_params },
{ "removeBreakpoint", RemoveBreakpoint,
remove_breakpoint_params },
{ "_restartVM", RestartVM,
restart_vm_params },
{ "reloadSources", ReloadSources,
reload_sources_params },
{ "_reloadSources", ReloadSources,

View file

@ -27,6 +27,7 @@ class Isolate;
class JSONStream;
class Object;
class RawInstance;
class RawError;
class ServiceEvent;
class String;
@ -81,14 +82,14 @@ class StreamInfo {
class Service : public AllStatic {
public:
// Handles a message which is not directed to an isolate.
static void HandleRootMessage(const Array& message);
static RawError* HandleRootMessage(const Array& message);
// Handles a message which is not directed to an isolate and also
// expects the parameter keys and values to be actual dart objects.
static void HandleObjectRootMessage(const Array& message);
static RawError* HandleObjectRootMessage(const Array& message);
// Handles a message which is directed to a particular isolate.
static void HandleIsolateMessage(Isolate* isolate, const Array& message);
static RawError* HandleIsolateMessage(Isolate* isolate, const Array& message);
static void HandleEvent(ServiceEvent* event);
@ -169,9 +170,9 @@ class Service : public AllStatic {
static void CheckForPause(Isolate* isolate, JSONStream* stream);
private:
static void InvokeMethod(Isolate* isolate,
const Array& message,
bool parameters_are_dart_objects = false);
static RawError* InvokeMethod(Isolate* isolate,
const Array& message,
bool parameters_are_dart_objects = false);
static void EmbedderHandleMessage(EmbedderServiceHandler* handler,
JSONStream* js);
@ -203,7 +204,7 @@ class Service : public AllStatic {
const char* kind,
JSONStream* event);
static void MaybePause(Isolate* isolate);
static RawError* MaybePause(Isolate* isolate, const Error& error);
static EmbedderServiceHandler* isolate_service_handler_head_;
static EmbedderServiceHandler* root_service_handler_head_;

View file

@ -274,6 +274,14 @@ void Thread::clear_sticky_error() {
}
RawError* Thread::get_and_clear_sticky_error() {
NoSafepointScope nss;
RawError* return_value = sticky_error_;
sticky_error_ = Error::null();
return return_value;
}
const char* Thread::TaskKindToCString(TaskKind kind) {
switch (kind) {
case kUnknownTask:

View file

@ -506,6 +506,7 @@ class Thread : public BaseThread {
RawError* sticky_error() const;
void set_sticky_error(const Error& value);
void clear_sticky_error();
RawError* get_and_clear_sticky_error();
RawStackTrace* async_stack_trace() const;
void set_async_stack_trace(const StackTrace& stack_trace);