Index: runtime/vm/isolate.cc |
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc |
index 685e457309e103c72e593b692c8b3003ee86495b..7d74fb682cfc934c5fe997723aebe1de3de57c4e 100644 |
--- a/runtime/vm/isolate.cc |
+++ b/runtime/vm/isolate.cc |
@@ -149,6 +149,27 @@ void Isolate::ValidateClassTable() { |
} |
+void Isolate::SendInternalLibMessage(LibMsgId msg_id, uint64_t capability) { |
+ const Array& msg = Array::Handle(Array::New(3)); |
+ Object& element = Object::Handle(); |
+ |
+ element = Smi::New(Message::kIsolateLibOOBMsg); |
+ msg.SetAt(0, element); |
+ element = Smi::New(msg_id); |
+ msg.SetAt(1, element); |
+ element = Capability::New(capability); |
+ msg.SetAt(2, element); |
+ |
+ uint8_t* data = NULL; |
+ MessageWriter writer(&data, &allocator, false); |
+ writer.WriteMessage(msg); |
+ |
+ PortMap::PostMessage(new Message(main_port(), |
+ data, writer.BytesWritten(), |
+ Message::kOOBPriority)); |
+} |
+ |
+ |
class IsolateMessageHandler : public MessageHandler { |
public: |
explicit IsolateMessageHandler(Isolate* isolate); |
@@ -167,30 +188,10 @@ class IsolateMessageHandler : public MessageHandler { |
bool IsCurrentIsolate() const; |
virtual Isolate* isolate() const { return isolate_; } |
- // Keep both these enums in sync with isolate_patch.dart. |
- // The different Isolate API message types. |
- enum { |
- kPauseMsg = 1, |
- kResumeMsg = 2, |
- kPingMsg = 3, |
- kKillMsg = 4, |
- kAddExitMsg = 5, |
- kDelExitMsg = 6, |
- kAddErrorMsg = 7, |
- kDelErrorMsg = 8, |
- kErrorFatalMsg = 9, |
- }; |
- // The different Isolate API message priorities for ping and kill messages. |
- enum { |
- kImmediateAction = 0, |
- kBeforeNextEventAction = 1, |
- kAsEventAction = 2 |
- }; |
- |
private: |
// A result of false indicates that the isolate should terminate the |
// processing of further events. |
- bool HandleLibMessage(const Array& message); |
+ RawError* HandleLibMessage(const Array& message); |
bool ProcessUnhandledException(const Error& result); |
Isolate* isolate_; |
@@ -213,50 +214,50 @@ const char* IsolateMessageHandler::name() const { |
// Isolate library OOB messages are fixed sized arrays which have the |
// following format: |
// [ OOB dispatch, Isolate library dispatch, <message specific data> ] |
-bool IsolateMessageHandler::HandleLibMessage(const Array& message) { |
- if (message.Length() < 2) return true; |
+RawError* IsolateMessageHandler::HandleLibMessage(const Array& message) { |
+ if (message.Length() < 2) return Error::null(); |
const Object& type = Object::Handle(I, message.At(1)); |
- if (!type.IsSmi()) return true; |
+ if (!type.IsSmi()) return Error::null(); |
const intptr_t msg_type = Smi::Cast(type).Value(); |
switch (msg_type) { |
- case kPauseMsg: { |
+ case Isolate::kPauseMsg: { |
// [ OOB, kPauseMsg, pause capability, resume capability ] |
- if (message.Length() != 4) return true; |
+ if (message.Length() != 4) return Error::null(); |
Object& obj = Object::Handle(I, message.At(2)); |
- if (!I->VerifyPauseCapability(obj)) return true; |
+ if (!I->VerifyPauseCapability(obj)) return Error::null(); |
obj = message.At(3); |
- if (!obj.IsCapability()) return true; |
+ if (!obj.IsCapability()) return Error::null(); |
if (I->AddResumeCapability(Capability::Cast(obj))) { |
increment_paused(); |
} |
break; |
} |
- case kResumeMsg: { |
+ case Isolate::kResumeMsg: { |
// [ OOB, kResumeMsg, pause capability, resume capability ] |
- if (message.Length() != 4) return true; |
+ if (message.Length() != 4) return Error::null(); |
Object& obj = Object::Handle(I, message.At(2)); |
- if (!I->VerifyPauseCapability(obj)) return true; |
+ if (!I->VerifyPauseCapability(obj)) return Error::null(); |
obj = message.At(3); |
- if (!obj.IsCapability()) return true; |
+ if (!obj.IsCapability()) return Error::null(); |
if (I->RemoveResumeCapability(Capability::Cast(obj))) { |
decrement_paused(); |
} |
break; |
} |
- case kPingMsg: { |
+ case Isolate::kPingMsg: { |
// [ OOB, kPingMsg, responsePort, priority, response ] |
- if (message.Length() != 5) return true; |
+ if (message.Length() != 5) return Error::null(); |
const Object& obj2 = Object::Handle(I, message.At(2)); |
- if (!obj2.IsSendPort()) return true; |
+ if (!obj2.IsSendPort()) return Error::null(); |
const SendPort& send_port = SendPort::Cast(obj2); |
const Object& obj3 = Object::Handle(I, message.At(3)); |
- if (!obj3.IsSmi()) return true; |
+ if (!obj3.IsSmi()) return Error::null(); |
const intptr_t priority = Smi::Cast(obj3).Value(); |
const Object& obj4 = Object::Handle(I, message.At(4)); |
- if (!obj4.IsInstance() && !obj4.IsNull()) return true; |
+ if (!obj4.IsInstance() && !obj4.IsNull()) return Error::null(); |
const Instance& response = |
obj4.IsNull() ? Instance::null_instance() : Instance::Cast(obj4); |
- if (priority == kImmediateAction) { |
+ if (priority == Isolate::kImmediateAction) { |
uint8_t* data = NULL; |
intptr_t len = 0; |
SerializeObject(response, &data, &len, false); |
@@ -264,81 +265,104 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) { |
data, len, |
Message::kNormalPriority)); |
} else { |
- ASSERT((priority == kBeforeNextEventAction) || |
- (priority == kAsEventAction)); |
+ ASSERT((priority == Isolate::kBeforeNextEventAction) || |
+ (priority == Isolate::kAsEventAction)); |
// Update the message so that it will be handled immediately when it |
// is picked up from the message queue the next time. |
message.SetAt( |
0, Smi::Handle(I, Smi::New(Message::kDelayedIsolateLibOOBMsg))); |
- message.SetAt(3, Smi::Handle(I, Smi::New(kImmediateAction))); |
+ message.SetAt(3, Smi::Handle(I, Smi::New(Isolate::kImmediateAction))); |
uint8_t* data = NULL; |
intptr_t len = 0; |
SerializeObject(message, &data, &len, false); |
- this->PostMessage(new Message(Message::kIllegalPort, |
- data, len, |
- Message::kNormalPriority), |
- priority == kBeforeNextEventAction /* at_head */); |
+ this->PostMessage( |
+ new Message(Message::kIllegalPort, |
+ data, len, |
+ Message::kNormalPriority), |
+ priority == Isolate::kBeforeNextEventAction /* at_head */); |
} |
break; |
} |
- case kKillMsg: { |
+ case Isolate::kKillMsg: { |
// [ OOB, kKillMsg, terminate capability, priority ] |
- if (message.Length() != 4) return true; |
+ if (message.Length() != 4) return Error::null(); |
Object& obj = Object::Handle(I, message.At(3)); |
- if (!obj.IsSmi()) return true; |
+ if (!obj.IsSmi()) return Error::null(); |
const intptr_t priority = Smi::Cast(obj).Value(); |
- if (priority == kImmediateAction) { |
+ if (priority == Isolate::kImmediateAction) { |
obj = message.At(2); |
// Signal that the isolate should stop execution. |
- return !I->VerifyTerminateCapability(obj); |
+ if (I->VerifyTerminateCapability(obj)) { |
+ const String& msg = String::Handle(String::New( |
+ "isolate terminated by Isolate.kill")); |
+ return UnwindError::New(msg); |
+ } else { |
+ return Error::null(); |
+ } |
} else { |
- ASSERT((priority == kBeforeNextEventAction) || |
- (priority == kAsEventAction)); |
+ ASSERT((priority == Isolate::kBeforeNextEventAction) || |
+ (priority == Isolate::kAsEventAction)); |
// Update the message so that it will be handled immediately when it |
// is picked up from the message queue the next time. |
message.SetAt( |
0, Smi::Handle(I, Smi::New(Message::kDelayedIsolateLibOOBMsg))); |
- message.SetAt(3, Smi::Handle(I, Smi::New(kImmediateAction))); |
+ message.SetAt(3, Smi::Handle(I, Smi::New(Isolate::kImmediateAction))); |
uint8_t* data = NULL; |
intptr_t len = 0; |
SerializeObject(message, &data, &len, false); |
- this->PostMessage(new Message(Message::kIllegalPort, |
- data, len, |
- Message::kNormalPriority), |
- priority == kBeforeNextEventAction /* at_head */); |
+ this->PostMessage( |
+ new Message(Message::kIllegalPort, |
+ data, len, |
+ Message::kNormalPriority), |
+ priority == Isolate::kBeforeNextEventAction /* at_head */); |
} |
break; |
} |
- case kAddExitMsg: |
- case kDelExitMsg: |
- case kAddErrorMsg: |
- case kDelErrorMsg: { |
+ case Isolate::kInterruptMsg: { |
+ // [ OOB, kInterruptMsg, pause capability ] |
+ if (message.Length() != 3) return Error::null(); |
+ Object& obj = Object::Handle(I, message.At(2)); |
+ if (!I->VerifyPauseCapability(obj)) return Error::null(); |
+ |
+ // If we are already paused, don't pause again. |
+ if (I->debugger()->PauseEvent() == NULL) { |
+ return I->debugger()->SignalIsolateInterrupted(); |
+ } |
+ break; |
+ } |
+ |
+ case Isolate::kAddExitMsg: |
+ case Isolate::kDelExitMsg: |
+ case Isolate::kAddErrorMsg: |
+ case Isolate::kDelErrorMsg: { |
// [ OOB, msg, listener port ] |
- if (message.Length() < 3) return true; |
+ if (message.Length() < 3) return Error::null(); |
const Object& obj = Object::Handle(I, message.At(2)); |
- if (!obj.IsSendPort()) return true; |
+ if (!obj.IsSendPort()) return Error::null(); |
const SendPort& listener = SendPort::Cast(obj); |
switch (msg_type) { |
- case kAddExitMsg: { |
- if (message.Length() != 4) return true; |
+ case Isolate::kAddExitMsg: { |
+ if (message.Length() != 4) return Error::null(); |
// [ OOB, msg, listener port, response object ] |
const Object& response = Object::Handle(I, message.At(3)); |
- if (!response.IsInstance() && !response.IsNull()) return true; |
+ if (!response.IsInstance() && !response.IsNull()) { |
+ return Error::null(); |
+ } |
I->AddExitListener(listener, |
response.IsNull() ? Instance::null_instance() |
: Instance::Cast(response)); |
break; |
} |
- case kDelExitMsg: |
- if (message.Length() != 3) return true; |
+ case Isolate::kDelExitMsg: |
+ if (message.Length() != 3) return Error::null(); |
I->RemoveExitListener(listener); |
break; |
- case kAddErrorMsg: |
- if (message.Length() != 3) return true; |
+ case Isolate::kAddErrorMsg: |
+ if (message.Length() != 3) return Error::null(); |
I->AddErrorListener(listener); |
break; |
- case kDelErrorMsg: |
- if (message.Length() != 3) return true; |
+ case Isolate::kDelErrorMsg: |
+ if (message.Length() != 3) return Error::null(); |
I->RemoveErrorListener(listener); |
break; |
default: |
@@ -346,15 +370,15 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) { |
} |
break; |
} |
- case kErrorFatalMsg: { |
+ case Isolate::kErrorFatalMsg: { |
// [ OOB, kErrorFatalMsg, terminate capability, val ] |
- if (message.Length() != 4) return true; |
+ if (message.Length() != 4) return Error::null(); |
// Check that the terminate capability has been passed correctly. |
Object& obj = Object::Handle(I, message.At(2)); |
- if (!I->VerifyTerminateCapability(obj)) return true; |
+ if (!I->VerifyTerminateCapability(obj)) return Error::null(); |
// Get the value to be set. |
obj = message.At(3); |
- if (!obj.IsBool()) return true; |
+ if (!obj.IsBool()) return Error::null(); |
I->SetErrorsFatal(Bool::Cast(obj).value()); |
break; |
} |
@@ -365,7 +389,7 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) { |
break; |
#endif // defined(DEBUG) |
} |
- return true; |
+ return Error::null(); |
} |
@@ -455,7 +479,10 @@ bool IsolateMessageHandler::HandleMessage(Message* message) { |
break; |
} |
case Message::kIsolateLibOOBMsg: { |
- success = HandleLibMessage(oob_msg); |
+ const Error& error = Error::Handle(HandleLibMessage(oob_msg)); |
+ if (!error.IsNull()) { |
+ success = ProcessUnhandledException(error); |
+ } |
break; |
} |
#if defined(DEBUG) |
@@ -479,7 +506,10 @@ bool IsolateMessageHandler::HandleMessage(Message* message) { |
const Object& oob_tag = Object::Handle(zone, msg_arr.At(0)); |
if (oob_tag.IsSmi() && |
(Smi::Cast(oob_tag).Value() == Message::kDelayedIsolateLibOOBMsg)) { |
- success = HandleLibMessage(Array::Cast(msg_arr)); |
+ const Error& error = Error::Handle(HandleLibMessage(msg_arr)); |
+ if (!error.IsNull()) { |
+ success = ProcessUnhandledException(error); |
+ } |
} |
} |
} |
@@ -589,15 +619,20 @@ bool IsolateMessageHandler::ProcessUnhandledException(const Error& result) { |
} else { |
exc_str = String::New(result.ToErrorCString()); |
} |
- bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str); |
- |
- if (I->ErrorsFatal()) { |
- if (has_listener) { |
- I->object_store()->clear_sticky_error(); |
- } else { |
- I->object_store()->set_sticky_error(result); |
- } |
+ if (result.IsUnwindError()) { |
+ // Unwind errors are always fatal and don't notify listeners. |
+ I->object_store()->set_sticky_error(result); |
return false; |
+ } else { |
+ bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str); |
+ if (I->ErrorsFatal()) { |
+ if (has_listener) { |
+ I->object_store()->clear_sticky_error(); |
+ } else { |
+ I->object_store()->set_sticky_error(result); |
+ } |
+ return false; |
+ } |
} |
return true; |
} |
@@ -1413,6 +1448,39 @@ uword Isolate::GetAndClearInterrupts() { |
} |
+RawError* Isolate::HandleInterrupts() { |
+ uword interrupt_bits = GetAndClearInterrupts(); |
+ if ((interrupt_bits & kVMInterrupt) != 0) { |
+ thread_registry()->CheckSafepoint(); |
+ if (store_buffer()->Overflowed()) { |
+ if (FLAG_verbose_gc) { |
+ OS::PrintErr("Scavenge scheduled by store buffer overflow.\n"); |
+ } |
+ heap()->CollectGarbage(Heap::kNew); |
+ } |
+ } |
+ if ((interrupt_bits & kMessageInterrupt) != 0) { |
+ bool ok = message_handler()->HandleOOBMessages(); |
+ if (!ok) { |
+ // False result from HandleOOBMessages signals that the isolate should |
+ // be terminating. |
+ if (FLAG_trace_isolates) { |
+ OS::Print("[!] Terminating isolate due to OOB message:\n" |
+ "\tisolate: %s\n", name()); |
+ } |
+ // TODO(turnidge): If the isolate is being killed by |
+ // Isolate.kill, then we probably want to respect pause_on_exit. |
+ // If the isolate is being killed due to vm restart we don't. |
+ message_handler()->set_pause_on_start(false); |
+ message_handler()->set_pause_on_exit(false); |
+ const String& msg = String::Handle(String::New("isolate terminated")); |
+ return UnwindError::New(msg); |
+ } |
+ } |
+ return Error::null(); |
+} |
+ |
+ |
uword Isolate::GetAndClearStackOverflowFlags() { |
uword stack_overflow_flags = stack_overflow_flags_; |
stack_overflow_flags_ = 0; |
@@ -1499,6 +1567,9 @@ void Isolate::LowLevelShutdown() { |
// Notify exit listeners that this isolate is shutting down. |
if (object_store() != NULL) { |
+ // TODO(turnidge): If the isolate is being killed by Isolate.kill, |
+ // then we want to notify event listeners. If the isolate is |
+ // being killed due to vm restart we probably don't. |
NotifyExitListeners(); |
} |
@@ -2226,7 +2297,7 @@ void Isolate::KillLocked() { |
Dart_CObject kill; |
kill.type = Dart_CObject_kInt32; |
- kill.value.as_int32 = IsolateMessageHandler::kKillMsg; |
+ kill.value.as_int32 = Isolate::kKillMsg; |
list_values[1] = &kill; |
Dart_CObject cap; |
@@ -2236,7 +2307,7 @@ void Isolate::KillLocked() { |
Dart_CObject imm; |
imm.type = Dart_CObject_kInt32; |
- imm.value.as_int32 = IsolateMessageHandler::kImmediateAction; |
+ imm.value.as_int32 = Isolate::kImmediateAction; |
list_values[3] = &imm; |
{ |