| Index: runtime/vm/isolate.cc
|
| diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
|
| index abc53430c65a03e0faae1b40e68434716954a2ec..cb5da450520ef9ccb71c6308e2ced03dde74962b 100644
|
| --- a/runtime/vm/isolate.cc
|
| +++ b/runtime/vm/isolate.cc
|
| @@ -202,18 +202,22 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
| break;
|
| }
|
| case kPingMsg: {
|
| - // [ OOB, kPingMsg, responsePort, priority ]
|
| - if (message.Length() != 4) return true;
|
| + // [ OOB, kPingMsg, responsePort, priority, response ]
|
| + if (message.Length() != 5) return true;
|
| const Object& obj2 = Object::Handle(I, message.At(2));
|
| if (!obj2.IsSendPort()) return true;
|
| const SendPort& send_port = SendPort::Cast(obj2);
|
| const Object& obj3 = Object::Handle(I, message.At(3));
|
| if (!obj3.IsSmi()) return true;
|
| const intptr_t priority = Smi::Cast(obj3).Value();
|
| + const Object& obj4 = Object::Handle(I, message.At(4));
|
| + if (!obj4.IsInstance() && !obj4.IsNull()) return true;
|
| + const Instance& response =
|
| + obj4.IsNull() ? Instance::null_instance() : Instance::Cast(obj4);
|
| if (priority == kImmediateAction) {
|
| uint8_t* data = NULL;
|
| intptr_t len = 0;
|
| - SerializeObject(Object::null_instance(), &data, &len, false);
|
| + SerializeObject(response, &data, &len, false);
|
| PortMap::PostMessage(new Message(send_port.Id(),
|
| data, len,
|
| Message::kNormalPriority));
|
| @@ -268,21 +272,31 @@ bool IsolateMessageHandler::HandleLibMessage(const Array& message) {
|
| case kAddErrorMsg:
|
| case kDelErrorMsg: {
|
| // [ OOB, msg, listener port ]
|
| - if (message.Length() != 3) return true;
|
| + if (message.Length() < 3) return true;
|
| const Object& obj = Object::Handle(I, message.At(2));
|
| if (!obj.IsSendPort()) return true;
|
| const SendPort& listener = SendPort::Cast(obj);
|
| switch (msg_type) {
|
| - case kAddExitMsg:
|
| - I->AddExitListener(listener);
|
| + case kAddExitMsg: {
|
| + if (message.Length() != 4) return true;
|
| + // [ OOB, msg, listener port, response object ]
|
| + const Object& response = Object::Handle(I, message.At(3));
|
| + if (!response.IsInstance() && !response.IsNull()) return true;
|
| + I->AddExitListener(listener,
|
| + response.IsNull() ? Instance::null_instance()
|
| + : Instance::Cast(response));
|
| break;
|
| + }
|
| case kDelExitMsg:
|
| + if (message.Length() != 3) return true;
|
| I->RemoveExitListener(listener);
|
| break;
|
| case kAddErrorMsg:
|
| + if (message.Length() != 3) return true;
|
| I->AddErrorListener(listener);
|
| break;
|
| case kDelErrorMsg:
|
| + if (message.Length() != 3) return true;
|
| I->RemoveErrorListener(listener);
|
| break;
|
| default:
|
| @@ -1002,21 +1016,23 @@ bool Isolate::RemoveResumeCapability(const Capability& capability) {
|
|
|
| // TODO(iposva): Remove duplicated code and start using some hash based
|
| // structure instead of these linear lookups.
|
| -void Isolate::AddExitListener(const SendPort& listener) {
|
| +void Isolate::AddExitListener(const SendPort& listener,
|
| + const Instance& response) {
|
| // Ensure a limit for the number of listeners remembered.
|
| - static const intptr_t kMaxListeners = kSmiMax / (6 * kWordSize);
|
| + static const intptr_t kMaxListeners = kSmiMax / (12 * kWordSize);
|
|
|
| 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++) {
|
| + for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
| current ^= listeners.At(i);
|
| if (current.IsNull()) {
|
| if (insertion_index < 0) {
|
| insertion_index = i;
|
| }
|
| } else if (current.Id() == listener.Id()) {
|
| + listeners.SetAt(i + 1, response);
|
| return;
|
| }
|
| }
|
| @@ -1028,8 +1044,10 @@ void Isolate::AddExitListener(const SendPort& listener) {
|
| return;
|
| }
|
| listeners.Add(listener);
|
| + listeners.Add(response);
|
| } else {
|
| listeners.SetAt(insertion_index, listener);
|
| + listeners.SetAt(insertion_index + 1, response);
|
| }
|
| }
|
|
|
| @@ -1038,12 +1056,13 @@ 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++) {
|
| + for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
| 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);
|
| + listeners.SetAt(i + 1, Object::null_instance());
|
| return;
|
| }
|
| }
|
| @@ -1056,13 +1075,15 @@ void Isolate::NotifyExitListeners() {
|
| if (listeners.IsNull()) return;
|
|
|
| SendPort& listener = SendPort::Handle(this);
|
| - for (intptr_t i = 0; i < listeners.Length(); i++) {
|
| + Instance& response = Instance::Handle(this);
|
| + for (intptr_t i = 0; i < listeners.Length(); i += 2) {
|
| 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);
|
| + response ^= listeners.At(i + 1);
|
| + SerializeObject(response, &data, &len, false);
|
| Message* msg = new Message(port_id, data, len, Message::kNormalPriority);
|
| PortMap::PostMessage(msg);
|
| }
|
|
|