Chromium Code Reviews| Index: runtime/vm/isolate.cc |
| =================================================================== |
| --- runtime/vm/isolate.cc (revision 44200) |
| +++ runtime/vm/isolate.cc (working copy) |
| @@ -129,6 +129,11 @@ |
| kResumeMsg = 2, |
| kPingMsg = 3, |
| kKillMsg = 4, |
| + kAddExitMsg = 5, |
| + kDelExitMsg = 6, |
| + kAddErrorMsg = 7, |
| + kDelErrorMsg = 8, |
| + kErrorFatalMsg = 9, |
| kImmediateAction = 0, |
| kBeforeNextEventAction = 1, |
| @@ -164,8 +169,8 @@ |
| if (message.Length() < 2) return true; |
| const Object& type = Object::Handle(I, message.At(1)); |
| if (!type.IsSmi()) return true; |
| - const Smi& msg_type = Smi::Cast(type); |
| - switch (msg_type.Value()) { |
| + const intptr_t msg_type = Smi::Cast(type).Value(); |
| + switch (msg_type) { |
| case kPauseMsg: { |
| // [ OOB, kPauseMsg, pause capability, resume capability ] |
| if (message.Length() != 4) return true; |
| @@ -252,6 +257,45 @@ |
| } |
| break; |
| } |
| + case kAddExitMsg: |
| + case kDelExitMsg: |
| + case kAddErrorMsg: |
| + case kDelErrorMsg: { |
| + // [ OOB, msg, listener port ] |
| + if (message.Length() != 3) return true; |
| + Object& obj = Object::Handle(I, message.At(2)); |
|
siva
2015/03/06 23:56:04
const Object& obj = ...;
Ivan Posva
2015/03/07 04:20:39
Done.
|
| + if (!obj.IsSendPort()) return true; |
|
siva
2015/03/06 23:56:04
Did we change the C++ style here, we always used t
Ivan Posva
2015/03/07 04:20:39
There are 2628 places in the project that use the
|
| + const SendPort& listener = SendPort::Cast(obj); |
| + switch (msg_type) { |
| + case kAddExitMsg: |
| + I->AddExitListener(listener); |
| + break; |
| + case kDelExitMsg: |
| + I->RemoveExitListener(listener); |
| + break; |
| + case kAddErrorMsg: |
| + I->AddErrorListener(listener); |
| + break; |
| + case kDelErrorMsg: |
| + I->RemoveErrorListener(listener); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + break; |
| + } |
| + case kErrorFatalMsg: { |
| + // [ OOB, kErrorFatalMsg, terminate capability, val ] |
| + if (message.Length() != 4) return true; |
| + // Check that the terminate capability has been passed correctly. |
| + Object& obj = Object::Handle(I, message.At(2)); |
| + if (!I->VerifyTerminateCapability(obj)) return true; |
| + // Get the value to be set. |
| + obj = message.At(3); |
| + if (!obj.IsBool()) return true; |
| + I->SetErrorsFatal(Bool::Cast(obj).value()); |
| + break; |
| + } |
| #if defined(DEBUG) |
| // Malformed OOB messages are silently ignored in release builds. |
| default: |
| @@ -417,8 +461,35 @@ |
| Dart_ExitScope(); |
| } |
| - I->object_store()->set_sticky_error(result); |
| - return false; |
| + // Generate the error and stacktrace strings for the error message. |
| + String& exc_str = String::Handle(I); |
| + String& stacktrace_str = String::Handle(I); |
| + if (result.IsUnhandledException()) { |
| + const UnhandledException& uhe = UnhandledException::Cast(result); |
| + const Instance& exception = Instance::Handle(I, uhe.exception()); |
| + Object& tmp = Object::Handle(I); |
| + tmp = DartLibraryCalls::ToString(exception); |
| + if (!tmp.IsString()) { |
| + tmp = String::New(exception.ToCString()); |
| + } |
| + exc_str ^= tmp.raw(); |
| + |
| + const Instance& stacktrace = Instance::Handle(I, uhe.stacktrace()); |
| + tmp = DartLibraryCalls::ToString(stacktrace); |
| + if (!tmp.IsString()) { |
| + tmp = String::New(stacktrace.ToCString()); |
| + } |
| + stacktrace_str ^= tmp.raw();; |
| + } else { |
| + exc_str = String::New(result.ToErrorCString()); |
| + } |
| + I->NotifyErrorListeners(exc_str, stacktrace_str); |
| + |
| + if (I->ErrorsFatal()) { |
| + I->object_store()->set_sticky_error(result); |
| + return false; |
| + } |
| + return true; |
| } |
| @@ -449,6 +520,7 @@ |
| origin_id_(0), |
| pause_capability_(0), |
| terminate_capability_(0), |
| + errors_fatal_(true), |
| heap_(NULL), |
| object_store_(NULL), |
| top_exit_frame_info_(0), |
| @@ -514,6 +586,7 @@ |
| main_port_(0), |
| pause_capability_(0), |
| terminate_capability_(0), |
| + errors_fatal_(true), |
| heap_(NULL), |
| object_store_(NULL), |
| top_exit_frame_info_(0), |
| @@ -917,6 +990,144 @@ |
| } |
| +// TODO(iposva): Remove duplicated code and start using some hash based |
| +// structure instead of these linear lookups. |
| +void Isolate::AddExitListener(const SendPort& listener) { |
| + // Ensure a limit for the number of listeners remembered. |
| + static const intptr_t kMaxListeners = kSmiMax / (6*kWordSize); |
|
siva
2015/03/06 23:56:04
spaces 6 * kWOrdSize
Ivan Posva
2015/03/07 04:20:39
Done.
|
| + |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, object_store()->exit_listeners()); |
| + SendPort& current = SendPort::Handle(this); |
| + intptr_t insertion_index = -1; |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + current ^= listeners.At(i); |
| + if (current.IsNull()) { |
| + if (insertion_index < 0) { |
| + insertion_index = i; |
| + } |
| + } else if (current.Id() == listener.Id()) { |
| + return; |
| + } |
| + } |
| + if (insertion_index < 0) { |
| + if (listeners.Length() >= kMaxListeners) { |
| + // Cannot grow the array of listeners beyond its max. Additional |
| + // listeners are ignored. In practice will never happen as we will |
| + // run out of memory beforehand. |
| + return; |
| + } |
| + listeners.Add(listener); |
| + } else { |
| + listeners.SetAt(insertion_index, listener); |
| + } |
| +} |
| + |
| + |
| +void Isolate::RemoveExitListener(const SendPort& listener) { |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, object_store()->exit_listeners()); |
| + SendPort& current = SendPort::Handle(this); |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + current ^= listeners.At(i); |
| + if (!current.IsNull() && (current.Id() == listener.Id())) { |
| + // Remove the matching listener from the list. |
| + current = SendPort::null(); |
| + listeners.SetAt(i, current); |
| + return; |
| + } |
| + } |
| +} |
| + |
| + |
| +void Isolate::NotifyExitListeners() { |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, this->object_store()->exit_listeners()); |
| + SendPort& listener = SendPort::Handle(this); |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + listener ^= listeners.At(i); |
| + if (!listener.IsNull()) { |
| + Dart_Port port_id = listener.Id(); |
| + uint8_t* data = NULL; |
| + intptr_t len = 0; |
| + SerializeObject(Object::null_instance(), &data, &len, false); |
| + Message* msg = new Message(port_id, data, len, Message::kNormalPriority); |
| + PortMap::PostMessage(msg); |
| + } |
| + } |
| +} |
| + |
| + |
| +void Isolate::AddErrorListener(const SendPort& listener) { |
| + // Ensure a limit for the number of listeners remembered. |
| + static const intptr_t kMaxListeners = kSmiMax / (6*kWordSize); |
| + |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, object_store()->error_listeners()); |
| + SendPort& current = SendPort::Handle(this); |
| + intptr_t insertion_index = -1; |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + current ^= listeners.At(i); |
| + if (current.IsNull()) { |
| + if (insertion_index < 0) { |
| + insertion_index = i; |
| + } |
| + } else if (current.Id() == listener.Id()) { |
| + return; |
| + } |
| + } |
| + if (insertion_index < 0) { |
| + if (listeners.Length() >= kMaxListeners) { |
| + // Cannot grow the array of listeners beyond its max. Additional |
| + // listeners are ignored. In practice will never happen as we will |
| + // run out of memory beforehand. |
| + return; |
| + } |
| + listeners.Add(listener); |
| + } else { |
| + listeners.SetAt(insertion_index, listener); |
| + } |
| +} |
| + |
| + |
| +void Isolate::RemoveErrorListener(const SendPort& listener) { |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, object_store()->error_listeners()); |
| + SendPort& current = SendPort::Handle(this); |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + current ^= listeners.At(i); |
| + if (!current.IsNull() && (current.Id() == listener.Id())) { |
| + // Remove the matching listener from the list. |
| + current = SendPort::null(); |
| + listeners.SetAt(i, current); |
| + return; |
| + } |
| + } |
| +} |
| + |
| + |
| +void Isolate::NotifyErrorListeners(const String& msg, |
| + const String& stacktrace) { |
| + const Array& arr = Array::Handle(this, Array::New(2)); |
| + arr.SetAt(0, msg); |
| + arr.SetAt(1, stacktrace); |
| + const GrowableObjectArray& listeners = GrowableObjectArray::Handle( |
| + this, this->object_store()->error_listeners()); |
| + SendPort& listener = SendPort::Handle(this); |
| + for (intptr_t i = 0; i < listeners.Length(); i++) { |
| + listener ^= listeners.At(i); |
| + if (!listener.IsNull()) { |
| + Dart_Port port_id = listener.Id(); |
| + uint8_t* data = NULL; |
| + intptr_t len = 0; |
| + SerializeObject(arr, &data, &len, false); |
| + Message* msg = new Message(port_id, data, len, Message::kNormalPriority); |
| + PortMap::PostMessage(msg); |
| + } |
| + } |
| +} |
| + |
| + |
| static void StoreError(Isolate* isolate, const Object& obj) { |
| ASSERT(obj.IsError()); |
| isolate->object_store()->set_sticky_error(Error::Cast(obj)); |
| @@ -1149,6 +1360,9 @@ |
| StackZone stack_zone(this); |
| HandleScope handle_scope(this); |
| + // Notify exit listeners that this isolate is shutting down. |
| + NotifyExitListeners(); |
| + |
| // Clean up debugger resources. |
| debugger()->Shutdown(); |