Chromium Code Reviews| Index: runtime/vm/isolate.cc |
| =================================================================== |
| --- runtime/vm/isolate.cc (revision 37860) |
| +++ runtime/vm/isolate.cc (working copy) |
| @@ -83,6 +83,13 @@ |
| const UnhandledException& error); |
| private: |
| + // Keep in sync with isolate_patch.dart. |
| + enum { |
| + kPauseMsg = 1, |
| + kResumeMsg |
| + }; |
| + |
| + void HandleLibMessage(const Array& message); |
| bool ProcessUnhandledException(const Object& message, const Error& result); |
| RawFunction* ResolveCallbackFunction(); |
| Isolate* isolate_; |
| @@ -102,6 +109,46 @@ |
| } |
| +void IsolateMessageHandler::HandleLibMessage(const Array& message) { |
|
siva
2014/07/01 21:42:56
Would be good to document the message formats here
Ivan Posva
2014/07/03 12:51:16
Done.
|
| + if (message.Length() < 2) return; |
| + const Object& type = Object::Handle(I, message.At(1)); |
| + if (!type.IsSmi()) return; |
| + const Smi& msg_type = Smi::Cast(type); |
| + switch (msg_type.Value()) { |
| + case kPauseMsg: { |
| + if (message.Length() != 4) return; |
| + Object& obj = Object::Handle(I, message.At(2)); |
| + if (!obj.IsCapability()) return; |
| + if (!I->VerifyPauseCapability(Capability::Cast(obj))) return; |
| + obj = message.At(3); |
| + if (!obj.IsCapability()) return; |
| + if (I->AddPauseCapability(Capability::Cast(obj))) { |
| + increment_paused(); |
| + } |
| + break; |
| + } |
| + case kResumeMsg: { |
| + if (message.Length() != 4) return; |
| + Object& obj = Object::Handle(I, message.At(2)); |
| + if (!obj.IsCapability()) return; |
| + if (!I->VerifyPauseCapability(Capability::Cast(obj))) return; |
| + obj = message.At(3); |
| + if (!obj.IsCapability()) return; |
| + if (I->RemovePauseCapability(Capability::Cast(obj))) { |
| + decrement_paused(); |
| + } |
| + break; |
| + } |
| +#if DEBUG |
|
siva
2014/07/01 21:42:56
#if defined(DEBUG) to be consistent.
Ivan Posva
2014/07/03 12:51:16
Done.
|
| + // Malformed OOB messages are silently ignored in release builds. |
| + default: |
| + UNREACHABLE(); |
| + break; |
| +#endif // DEBUG |
| + } |
| +} |
| + |
| + |
| void IsolateMessageHandler::MessageNotify(Message::Priority priority) { |
| if (priority >= Message::kOOBPriority) { |
| // Handle out of band messages even if the isolate is busy. |
| @@ -129,6 +176,7 @@ |
| if (!message->IsOOB()) { |
| msg_handler = DartLibraryCalls::LookupHandler(message->dest_port()); |
| if (msg_handler.IsError()) { |
| + delete message; |
| return ProcessUnhandledException(Object::null_instance(), |
| Error::Cast(msg_handler)); |
| } |
| @@ -149,6 +197,7 @@ |
| const Object& msg_obj = Object::Handle(I, reader.ReadObject()); |
| if (msg_obj.IsError()) { |
| // An error occurred while reading the message. |
| + delete message; |
| return ProcessUnhandledException(Object::null_instance(), |
| Error::Cast(msg_obj)); |
| } |
| @@ -166,18 +215,33 @@ |
| bool success = true; |
| if (message->IsOOB()) { |
| - ASSERT(msg.IsArray()); |
| - const Object& oob_tag = Object::Handle(I, Array::Cast(msg).At(0)); |
| - ASSERT(oob_tag.IsSmi()); |
| - switch (Smi::Cast(oob_tag).Value()) { |
| - case Message::kServiceOOBMsg: { |
| - Service::HandleIsolateMessage(I, msg); |
| - break; |
| + // OOB messages are expected to be fixed length arrays where the first |
| + // element is a Smi describing the OOB destination. Messages that do not |
| + // confirm to this layout are silently ignored. |
| + if (msg.IsArray()) { |
| + const Array& oob_msg = Array::Cast(msg); |
| + if (oob_msg.Length() > 0) { |
| + const Object& oob_tag = Object::Handle(I, oob_msg.At(0)); |
| + if (oob_tag.IsSmi()) { |
| + switch (Smi::Cast(oob_tag).Value()) { |
| + case Message::kServiceOOBMsg: { |
| + Service::HandleIsolateMessage(I, oob_msg); |
| + break; |
| + } |
| + case Message::kIsolateLibOOBMsg: { |
| + HandleLibMessage(oob_msg); |
| + break; |
| + } |
| +#if DEBUG |
|
siva
2014/07/01 21:42:56
Ditto.
Ivan Posva
2014/07/03 12:51:16
Done.
|
| + // Malformed OOB messages are silently ignored in release builds. |
| + default: { |
| + UNREACHABLE(); |
| + break; |
| + } |
| +#endif // DEBUG |
| + } |
| + } |
| } |
| - default: { |
| - UNREACHABLE(); |
| - break; |
| - } |
| } |
| } else { |
| const Object& result = Object::Handle(I, |
| @@ -320,6 +384,8 @@ |
| name_(NULL), |
| start_time_(OS::GetCurrentTimeMicros()), |
| main_port_(0), |
| + pause_capability_(0), |
| + terminate_capability_(0), |
| heap_(NULL), |
| object_store_(NULL), |
| top_context_(Context::null()), |
| @@ -463,6 +529,9 @@ |
| // main thread. |
| result->SetStackLimitFromCurrentTOS(reinterpret_cast<uword>(&result)); |
| result->set_main_port(PortMap::CreatePort(result->message_handler())); |
| + result->set_pause_capability(result->random()->NextUInt64()); |
| + result->set_terminate_capability(result->random()->NextUInt64()); |
| + |
| result->BuildName(name_prefix); |
| result->debugger_ = new Debugger(); |
| @@ -593,6 +662,52 @@ |
| } |
| +bool Isolate::VerifyPauseCapability(const Capability& capability) { |
| + return !capability.IsNull() && (pause_capability() == capability.Id()); |
| +} |
| + |
| + |
| +bool Isolate::AddPauseCapability(const Capability& capability) { |
| + const GrowableObjectArray& caps = GrowableObjectArray::Handle( |
| + this, object_store()->pause_capabilities()); |
| + Capability& current = Capability::Handle(this); |
| + intptr_t insertion_index = -1; |
| + for (intptr_t i = 0; i < caps.Length(); i++) { |
| + current ^= caps.At(i); |
| + if (current.IsNull()) { |
| + if (insertion_index < 0) { |
| + insertion_index = i; |
| + } |
| + } else if (current.Id() == capability.Id()) { |
| + return false; |
| + } |
| + } |
| + if (insertion_index < 0) { |
| + caps.Add(capability); |
| + } else { |
| + caps.SetAt(insertion_index, capability); |
| + } |
| + return true; |
| +} |
| + |
| + |
| +bool Isolate::RemovePauseCapability(const Capability& capability) { |
| + const GrowableObjectArray& caps = GrowableObjectArray::Handle( |
| + this, object_store()->pause_capabilities()); |
| + Capability& current = Capability::Handle(this); |
| + for (intptr_t i = 0; i < caps.Length(); i++) { |
| + current ^= caps.At(i); |
| + if (!current.IsNull() && (current.Id() == capability.Id())) { |
| + // Remove the matching capability from the list. |
| + current = Capability::null(); |
| + caps.SetAt(i, current); |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| + |
| static void StoreError(Isolate* isolate, const Object& obj) { |
| ASSERT(obj.IsError()); |
| isolate->object_store()->set_sticky_error(Error::Cast(obj)); |
| @@ -772,7 +887,7 @@ |
| void VisitHandle(uword addr) { |
| FinalizablePersistentHandle* handle = |
| reinterpret_cast<FinalizablePersistentHandle*>(addr); |
| - handle->UpdateUnreachable(isolate()); |
| + handle->UpdateUnreachable(I); |
| } |
| private: |
| @@ -1212,7 +1327,7 @@ |
| return LanguageError::New(msg); |
| } |
| } else { |
| - lib = isolate()->object_store()->root_library(); |
| + lib = I->object_store()->root_library(); |
| } |
| ASSERT(!lib.IsNull()); |
| @@ -1254,7 +1369,7 @@ |
| void IsolateSpawnState::Cleanup() { |
| - SwitchIsolateScope switch_scope(isolate()); |
| + SwitchIsolateScope switch_scope(I); |
| Dart::ShutdownIsolate(); |
| } |