Index: runtime/vm/isolate.cc |
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc |
index 0145636f3c12c64dadc891b2bae2477fdbc50df9..4d6c56c743ae95cd80433efb7132370acfa6ad6e 100644 |
--- a/runtime/vm/isolate.cc |
+++ b/runtime/vm/isolate.cc |
@@ -493,6 +493,15 @@ bool IsolateMessageHandler::HandleMessage(Message* message) { |
} |
} |
delete message; |
+ if (success) { |
+ const Object& result = |
+ Object::Handle(zone, I->InvokePendingServiceExtensionCalls()); |
+ if (result.IsError()) { |
+ success = ProcessUnhandledException(Error::Cast(result)); |
+ } else { |
+ ASSERT(result.IsNull()); |
+ } |
+ } |
return success; |
} |
@@ -504,7 +513,7 @@ void IsolateMessageHandler::NotifyPauseOnStart() { |
HandleScope handle_scope(I); |
ServiceEvent pause_event(isolate(), ServiceEvent::kPauseStart); |
Service::HandleEvent(&pause_event); |
- } else if (FLAG_trace_service) { |
+ } else if (FLAG_trace_service) { |
OS::Print("vm-service: Dropping event of type PauseStart (%s)\n", |
isolate()->name()); |
} |
@@ -518,7 +527,7 @@ void IsolateMessageHandler::NotifyPauseOnExit() { |
HandleScope handle_scope(I); |
ServiceEvent pause_event(isolate(), ServiceEvent::kPauseExit); |
Service::HandleEvent(&pause_event); |
- } else if (FLAG_trace_service) { |
+ } else if (FLAG_trace_service) { |
OS::Print("vm-service: Dropping event of type PauseExit (%s)\n", |
isolate()->name()); |
} |
@@ -704,6 +713,8 @@ Isolate::Isolate(const Dart_IsolateFlags& api_flags) |
default_tag_(UserTag::null()), |
collected_closures_(GrowableObjectArray::null()), |
deoptimized_code_array_(GrowableObjectArray::null()), |
+ pending_service_extension_calls_(GrowableObjectArray::null()), |
+ registered_service_extension_handlers_(GrowableObjectArray::null()), |
metrics_list_head_(NULL), |
compilation_allowed_(true), |
cha_(NULL), |
@@ -1641,6 +1652,14 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor, |
visitor->VisitPointer( |
reinterpret_cast<RawObject**>(&deoptimized_code_array_)); |
+ // Visit the pending service extension calls. |
+ visitor->VisitPointer( |
+ reinterpret_cast<RawObject**>(&pending_service_extension_calls_)); |
+ |
+ // Visit the registered service extension handlers. |
+ visitor->VisitPointer( |
+ reinterpret_cast<RawObject**>(®istered_service_extension_handlers_)); |
+ |
// Visit objects in the debugger. |
debugger()->VisitObjectPointers(visitor); |
@@ -1862,6 +1881,169 @@ void Isolate::TrackDeoptimizedCode(const Code& code) { |
} |
+void Isolate::set_pending_service_extension_calls( |
+ const GrowableObjectArray& value) { |
+ pending_service_extension_calls_ = value.raw(); |
+} |
+ |
+ |
+void Isolate::set_registered_service_extension_handlers( |
+ const GrowableObjectArray& value) { |
+ registered_service_extension_handlers_ = value.raw(); |
+} |
+ |
+ |
+RawObject* Isolate::InvokePendingServiceExtensionCalls() { |
+ GrowableObjectArray& calls = |
+ GrowableObjectArray::Handle(GetAndClearPendingServiceExtensionCalls()); |
+ if (calls.IsNull()) { |
+ return Object::null(); |
+ } |
+ // Grab run function. |
+ const Library& developer_lib = Library::Handle(Library::DeveloperLibrary()); |
+ ASSERT(!developer_lib.IsNull()); |
+ const Function& run_extension = Function::Handle( |
+ developer_lib.LookupLocalFunction(Symbols::_runExtension())); |
+ ASSERT(!run_extension.IsNull()); |
+ |
+ const Array& arguments = |
+ Array::Handle(Array::New(kPendingEntrySize, Heap::kNew)); |
+ Object& result = Object::Handle(); |
+ String& method_name = String::Handle(); |
+ Instance& closure = Instance::Handle(); |
+ Array& parameter_keys = Array::Handle(); |
+ Array& parameter_values = Array::Handle(); |
+ Instance& reply_port = Instance::Handle(); |
+ Instance& id = Instance::Handle(); |
+ for (intptr_t i = 0; i < calls.Length(); i += kPendingEntrySize) { |
+ // Grab arguments for call. |
+ closure ^= calls.At(i + kPendingHandlerIndex); |
+ ASSERT(!closure.IsNull()); |
+ arguments.SetAt(kPendingHandlerIndex, closure); |
+ method_name ^= calls.At(i + kPendingMethodNameIndex); |
+ ASSERT(!method_name.IsNull()); |
+ arguments.SetAt(kPendingMethodNameIndex, method_name); |
+ parameter_keys ^= calls.At(i + kPendingKeysIndex); |
+ ASSERT(!parameter_keys.IsNull()); |
+ arguments.SetAt(kPendingKeysIndex, parameter_keys); |
+ parameter_values ^= calls.At(i + kPendingValuesIndex); |
+ ASSERT(!parameter_values.IsNull()); |
+ arguments.SetAt(kPendingValuesIndex, parameter_values); |
+ reply_port ^= calls.At(i + kPendingReplyPortIndex); |
+ ASSERT(!reply_port.IsNull()); |
+ arguments.SetAt(kPendingReplyPortIndex, reply_port); |
+ id ^= calls.At(i + kPendingIdIndex); |
+ arguments.SetAt(kPendingIdIndex, id); |
+ |
+ result = DartEntry::InvokeFunction(run_extension, arguments); |
+ if (result.IsError()) { |
+ if (result.IsUnwindError()) { |
+ // Propagate the unwind error. Remaining service extension calls |
+ // are dropped. |
+ return result.raw(); |
+ } else { |
+ // Send error back over the protocol. |
+ Service::PostError(method_name, |
+ parameter_keys, |
+ parameter_values, |
+ reply_port, |
+ id, |
+ Error::Cast(result)); |
+ } |
+ } |
+ result = DartLibraryCalls::DrainMicrotaskQueue(); |
+ if (result.IsError()) { |
+ return result.raw(); |
+ } |
+ } |
+ return Object::null(); |
+} |
+ |
+ |
+RawGrowableObjectArray* Isolate::GetAndClearPendingServiceExtensionCalls() { |
+ RawGrowableObjectArray* r = pending_service_extension_calls_; |
+ pending_service_extension_calls_ = GrowableObjectArray::null(); |
+ return r; |
+} |
+ |
+ |
+void Isolate::AppendServiceExtensionCall(const Instance& closure, |
+ const String& method_name, |
+ const Array& parameter_keys, |
+ const Array& parameter_values, |
+ const Instance& reply_port, |
+ const Instance& id) { |
+ GrowableObjectArray& calls = |
+ GrowableObjectArray::Handle(pending_service_extension_calls()); |
+ if (calls.IsNull()) { |
+ calls ^= GrowableObjectArray::New(); |
+ ASSERT(!calls.IsNull()); |
+ set_pending_service_extension_calls(calls); |
+ } |
+ ASSERT(kPendingHandlerIndex == 0); |
+ calls.Add(closure); |
+ ASSERT(kPendingMethodNameIndex == 1); |
+ calls.Add(method_name); |
+ ASSERT(kPendingKeysIndex == 2); |
+ calls.Add(parameter_keys); |
+ ASSERT(kPendingValuesIndex == 3); |
+ calls.Add(parameter_values); |
+ ASSERT(kPendingReplyPortIndex == 4); |
+ calls.Add(reply_port); |
+ ASSERT(kPendingIdIndex == 5); |
+ calls.Add(id); |
+} |
+ |
+ |
+// This function is written in C++ and not Dart because we must do this |
+// operation atomically in the face of random OOB messages. Do not port |
+// to Dart code unless you can ensure that the operations will can be |
+// done atomically. |
+void Isolate::RegisterServiceExtensionHandler(const String& name, |
+ const Instance& closure) { |
+ GrowableObjectArray& handlers = |
+ GrowableObjectArray::Handle(registered_service_extension_handlers()); |
+ if (handlers.IsNull()) { |
+ handlers ^= GrowableObjectArray::New(Heap::kOld); |
+ set_registered_service_extension_handlers(handlers); |
+ } |
+#if defined(DEBUG) |
+ { |
+ // Sanity check. |
+ const Instance& existing_handler = |
+ Instance::Handle(LookupServiceExtensionHandler(name)); |
+ ASSERT(existing_handler.IsNull()); |
+ } |
+#endif |
+ ASSERT(kRegisteredNameIndex == 0); |
+ handlers.Add(name, Heap::kOld); |
+ ASSERT(kRegisteredHandlerIndex == 1); |
+ handlers.Add(closure, Heap::kOld); |
+} |
+ |
+ |
+// This function is written in C++ and not Dart because we must do this |
+// operation atomically in the face of random OOB messages. Do not port |
+// to Dart code unless you can ensure that the operations will can be |
+// done atomically. |
+RawInstance* Isolate::LookupServiceExtensionHandler(const String& name) { |
+ const GrowableObjectArray& handlers = |
+ GrowableObjectArray::Handle(registered_service_extension_handlers()); |
+ if (handlers.IsNull()) { |
+ return Instance::null(); |
+ } |
+ String& handler_name = String::Handle(); |
+ for (intptr_t i = 0; i < handlers.Length(); i += kRegisteredEntrySize) { |
+ handler_name ^= handlers.At(i + kRegisteredNameIndex); |
+ ASSERT(!handler_name.IsNull()); |
+ if (handler_name.Equals(name)) { |
+ return Instance::RawCast(handlers.At(i + kRegisteredHandlerIndex)); |
+ } |
+ } |
+ return Instance::null(); |
+} |
+ |
+ |
void Isolate::WakePauseEventHandler(Dart_Isolate isolate) { |
Isolate* iso = reinterpret_cast<Isolate*>(isolate); |
MonitorLocker ml(iso->pause_loop_monitor_); |