Chromium Code Reviews| Index: runtime/vm/isolate.cc |
| diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc |
| index 7af37bfbcff69f3d9213c7ee37e0aa812b6ec5b6..ab18bf47c79630b487f2801f5c4a48b20792beaa 100644 |
| --- a/runtime/vm/isolate.cc |
| +++ b/runtime/vm/isolate.cc |
| @@ -492,6 +492,15 @@ bool IsolateMessageHandler::HandleMessage(Message* message) { |
| } |
| } |
| delete message; |
| + if (success) { |
| + const Object& result = |
| + Object::Handle(zone, I->InvokePendingExtensionCalls()); |
| + if (result.IsError()) { |
| + success = ProcessUnhandledException(Error::Cast(result)); |
| + } else { |
| + ASSERT(result.IsNull()); |
| + } |
| + } |
| return success; |
| } |
| @@ -696,6 +705,8 @@ Isolate::Isolate(const Dart_IsolateFlags& api_flags) |
| default_tag_(UserTag::null()), |
| collected_closures_(GrowableObjectArray::null()), |
| deoptimized_code_array_(GrowableObjectArray::null()), |
| + pending_extension_calls_(GrowableObjectArray::null()), |
| + registered_extension_handlers_(GrowableObjectArray::null()), |
| metrics_list_head_(NULL), |
| compilation_allowed_(true), |
| cha_(NULL), |
| @@ -1624,6 +1635,10 @@ 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_extension_calls_)); |
| + |
| // Visit objects in the debugger. |
| debugger()->VisitObjectPointers(visitor); |
| @@ -1845,6 +1860,160 @@ void Isolate::TrackDeoptimizedCode(const Code& code) { |
| } |
| +void Isolate::set_pending_extension_calls(const GrowableObjectArray& value) { |
| + pending_extension_calls_ = value.raw(); |
| +} |
| + |
| + |
| +void Isolate::set_registered_extension_handlers( |
| + const GrowableObjectArray& value) { |
| + registered_extension_handlers_ = value.raw(); |
| +} |
| + |
| + |
| +RawObject* Isolate::InvokePendingExtensionCalls() { |
| + GrowableObjectArray& calls = |
| + GrowableObjectArray::Handle(GetAndClearPendingExtensionCalls()); |
| + 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::GetAndClearPendingExtensionCalls() { |
| + RawGrowableObjectArray* r = pending_extension_calls_; |
| + pending_extension_calls_ = GrowableObjectArray::null(); |
| + return r; |
| +} |
| + |
| + |
| +void Isolate::AppendExtensionCall(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_extension_calls()); |
| + if (calls.IsNull()) { |
| + calls ^= GrowableObjectArray::New(Heap::kOld); |
|
Ivan Posva
2015/08/27 06:15:29
Why in old space?
Cutch
2015/08/27 13:27:49
Done.
|
| + ASSERT(!calls.IsNull()); |
| + set_pending_extension_calls(calls); |
| + } |
| + ASSERT(kPendingHandlerIndex == 0); |
| + calls.Add(closure, Heap::kOld); |
|
Ivan Posva
2015/08/27 06:15:29
ditto here and below. Why old?
Cutch
2015/08/27 13:27:49
Done.
|
| + ASSERT(kPendingMethodNameIndex == 1); |
| + calls.Add(method_name, Heap::kOld); |
| + ASSERT(kPendingKeysIndex == 2); |
| + calls.Add(parameter_keys, Heap::kOld); |
| + ASSERT(kPendingValuesIndex == 3); |
| + calls.Add(parameter_values, Heap::kOld); |
| + ASSERT(kPendingReplyPortIndex == 4); |
| + calls.Add(reply_port, Heap::kOld); |
| + ASSERT(kPendingIdIndex == 5); |
| + calls.Add(id, Heap::kOld); |
| +} |
| + |
| + |
| +void Isolate::RegisterExtensionHandler(const String& name, |
|
Ivan Posva
2015/08/27 06:15:29
These are really VM service extension handlers, co
Cutch
2015/08/27 13:27:49
Done.
|
| + const Instance& closure) { |
| + GrowableObjectArray& handlers = |
| + GrowableObjectArray::Handle(registered_extension_handlers()); |
| + if (handlers.IsNull()) { |
| + handlers ^= GrowableObjectArray::New(Heap::kOld); |
| + set_registered_extension_handlers(handlers); |
| + } |
| +#if defined(DEBUG) |
| + { |
| + // Sanity check. |
| + const Instance& existing_handler = |
| + Instance::Handle(LookupExtensionHandler(name)); |
| + ASSERT(existing_handler.IsNull()); |
| + } |
| +#endif |
| + ASSERT(kRegisteredNameIndex == 0); |
| + handlers.Add(name, Heap::kOld); |
| + ASSERT(kRegisteredHandlerIndex == 1); |
| + handlers.Add(closure, Heap::kOld); |
| +} |
| + |
| + |
| +RawInstance* Isolate::LookupExtensionHandler(const String& name) { |
|
Ivan Posva
2015/08/27 06:15:29
Why isn't the extension list not maintained in the
Cutch
2015/08/27 13:27:49
Because doing that in Dart code could lead to inco
Ivan Posva
2015/08/27 18:12:26
Many thanks for the explanation. Please add it as
Cutch
2015/08/27 18:23:29
Done.
|
| + const GrowableObjectArray& handlers = |
| + GrowableObjectArray::Handle(registered_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_); |