Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1526)

Unified Diff: runtime/vm/service.cc

Issue 920813003: Refactor service code and service method parameters (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/service.cc
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index cbb169957da257ab2f08d355e08d29c1b4c9282c..0384b8aedc312bf411b8f74b031b5924b5b40824 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -27,6 +27,7 @@
#include "vm/port.h"
#include "vm/profiler_service.h"
#include "vm/reusable_handles.h"
+#include "vm/service_isolate.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/unicode.h"
@@ -34,953 +35,647 @@
namespace dart {
-DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests.");
-DEFINE_FLAG(bool, trace_service_pause_events, false,
- "Trace VM service isolate pause events.");
+DECLARE_FLAG(bool, trace_service);
+DECLARE_FLAG(bool, trace_service_pause_events);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, enable_asserts);
-struct ResourcesEntry {
- const char* path_;
- const char* resource_;
- int length_;
-};
-
-extern ResourcesEntry __service_resources_[];
+EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
+EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
turnidge 2015/02/12 18:08:57 Add a TODO to combine isolate and root service han
Cutch 2015/02/12 18:18:47 Done.
+uint32_t Service::event_mask_ = 0;
+struct ServiceMethodDescriptor;
+ServiceMethodDescriptor* FindMethod(const char* method_name);
-class Resources {
- public:
- static const int kNoSuchInstance = -1;
- static int ResourceLookup(const char* path, const char** resource) {
- ResourcesEntry* table = ResourceTable();
- for (int i = 0; table[i].path_ != NULL; i++) {
- const ResourcesEntry& entry = table[i];
- if (strcmp(path, entry.path_) == 0) {
- *resource = entry.resource_;
- ASSERT(entry.length_ > 0);
- return entry.length_;
- }
- }
- return kNoSuchInstance;
- }
+static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
+ void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
+ return reinterpret_cast<uint8_t*>(new_ptr);
+}
- static const char* Path(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return NULL;
+static void PrintRequest(const JSONObject& obj, JSONStream* js) {
+ JSONObject jsobj(&obj, "request");
+ jsobj.AddProperty("method", js->method());
+ {
+ JSONArray jsarr(&jsobj, "param_keys");
+ for (intptr_t i = 0; i < js->num_params(); i++) {
+ jsarr.AddValue(js->GetParamKey(i));
}
- ASSERT(entry->path_ != NULL);
- return entry->path_;
}
-
- static int Length(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return kNoSuchInstance;
+ {
+ JSONArray jsarr(&jsobj, "param_values");
+ for (intptr_t i = 0; i < js->num_params(); i++) {
+ jsarr.AddValue(js->GetParamValue(i));
}
- ASSERT(entry->path_ != NULL);
- return entry->length_;
}
+}
- static const uint8_t* Resource(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* entry = At(idx);
- if (entry == NULL) {
- return NULL;
- }
- return reinterpret_cast<const uint8_t*>(entry->resource_);
- }
- private:
- static ResourcesEntry* At(int idx) {
- ASSERT(idx >= 0);
- ResourcesEntry* table = ResourceTable();
- for (int i = 0; table[i].path_ != NULL; i++) {
- if (idx == i) {
- return &table[i];
- }
- }
- return NULL;
- }
+static void PrintError(JSONStream* js,
+ const char* format, ...) {
+ Isolate* isolate = Isolate::Current();
- static ResourcesEntry* ResourceTable() {
- return &__service_resources_[0];
- }
+ va_list args;
+ va_start(args, format);
+ intptr_t len = OS::VSNPrint(NULL, 0, format, args);
+ va_end(args);
- DISALLOW_ALLOCATION();
- DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
-};
+ char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ va_list args2;
+ va_start(args2, format);
+ OS::VSNPrint(buffer, (len + 1), format, args2);
+ va_end(args2);
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Error");
+ jsobj.AddProperty("message", buffer);
+ PrintRequest(jsobj, js);
+}
-class EmbedderServiceHandler {
- public:
- explicit EmbedderServiceHandler(const char* name) : name_(NULL),
- callback_(NULL),
- user_data_(NULL),
- next_(NULL) {
- ASSERT(name != NULL);
- name_ = strdup(name);
- }
- ~EmbedderServiceHandler() {
- free(name_);
- }
+static void PrintMissingParamError(JSONStream* js,
+ const char* param) {
+ PrintError(js, "%s expects the '%s' parameter",
+ js->method(), param);
+}
- const char* name() const { return name_; }
- Dart_ServiceRequestCallback callback() const { return callback_; }
- void set_callback(Dart_ServiceRequestCallback callback) {
- callback_ = callback;
- }
+static void PrintInvalidParamError(JSONStream* js,
+ const char* param) {
+ PrintError(js, "%s: invalid '%s' parameter: %s",
+ js->method(), param, js->LookupParam(param));
+}
- void* user_data() const { return user_data_; }
- void set_user_data(void* user_data) {
- user_data_ = user_data;
- }
- EmbedderServiceHandler* next() const { return next_; }
- void set_next(EmbedderServiceHandler* next) {
- next_ = next;
- }
+static void PrintUnrecognizedMethodError(JSONStream* js) {
+ PrintError(js, "unrecognized method: %s", js->method());
+}
- private:
- char* name_;
- Dart_ServiceRequestCallback callback_;
- void* user_data_;
- EmbedderServiceHandler* next_;
-};
+static void PrintErrorWithKind(JSONStream* js,
+ const char* kind,
+ const char* format, ...) {
+ Isolate* isolate = Isolate::Current();
-class LibraryCoverageFilter : public CoverageFilter {
- public:
- explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {}
- bool ShouldOutputCoverageFor(const Library& lib,
- const Script& script,
- const Class& cls,
- const Function& func) const {
- return lib.raw() == lib_.raw();
- }
- private:
- const Library& lib_;
-};
+ va_list args;
+ va_start(args, format);
+ intptr_t len = OS::VSNPrint(NULL, 0, format, args);
+ va_end(args);
+ char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ va_list args2;
+ va_start(args2, format);
+ OS::VSNPrint(buffer, (len + 1), format, args2);
+ va_end(args2);
-class ScriptCoverageFilter : public CoverageFilter {
- public:
- explicit ScriptCoverageFilter(const Script& script)
- : script_(script) {}
- bool ShouldOutputCoverageFor(const Library& lib,
- const Script& script,
- const Class& cls,
- const Function& func) const {
- return script.raw() == script_.raw();
- }
- private:
- const Script& script_;
-};
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Error");
+ jsobj.AddProperty("id", "");
+ jsobj.AddProperty("kind", kind);
+ jsobj.AddProperty("message", buffer);
+ PrintRequest(jsobj, js);
+}
-class ClassCoverageFilter : public CoverageFilter {
- public:
- explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {}
- bool ShouldOutputCoverageFor(const Library& lib,
- const Script& script,
- const Class& cls,
- const Function& func) const {
- return cls.raw() == cls_.raw();
+static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
+ if ((s == NULL) || (*s == '\0')) {
+ // Empty string.
+ return false;
}
- private:
- const Class& cls_;
-};
-
-
-class FunctionCoverageFilter : public CoverageFilter {
- public:
- explicit FunctionCoverageFilter(const Function& func) : func_(func) {}
- bool ShouldOutputCoverageFor(const Library& lib,
- const Script& script,
- const Class& cls,
- const Function& func) const {
- return func.raw() == func_.raw();
+ if (id == NULL) {
+ // No id pointer.
+ return false;
}
- private:
- const Function& func_;
-};
+ intptr_t r = 0;
+ char* end_ptr = NULL;
+ r = strtol(s, &end_ptr, base);
+ if (end_ptr == s) {
+ // String was not advanced at all, cannot be valid.
+ return false;
+ }
+ *id = r;
+ return true;
+}
-static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
- void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
- return reinterpret_cast<uint8_t*>(new_ptr);
+static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
+ if ((s == NULL) || (*s == '\0')) {
+ // Empty string.
+ return false;
+ }
+ if (id == NULL) {
+ // No id pointer.
+ return false;
+ }
+ uintptr_t r = 0;
+ char* end_ptr = NULL;
+ r = strtoul(s, &end_ptr, base);
+ if (end_ptr == s) {
+ // String was not advanced at all, cannot be valid.
+ return false;
+ }
+ *id = r;
+ return true;
}
-static void SendIsolateServiceMessage(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Isolate* isolate = arguments->isolate();
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
-
- // Set the type of the OOB message.
- message.SetAt(0, Smi::Handle(isolate, Smi::New(Message::kServiceOOBMsg)));
+static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
+ if ((s == NULL) || (*s == '\0')) {
+ // Empty string.
+ return false;
+ }
+ if (id == NULL) {
+ // No id pointer.
+ return false;
+ }
+ int64_t r = 0;
+ char* end_ptr = NULL;
+ r = strtoll(s, &end_ptr, base);
+ if (end_ptr == s) {
+ // String was not advanced at all, cannot be valid.
+ return false;
+ }
+ *id = r;
+ return true;
+}
- // Serialize message.
- uint8_t* data = NULL;
- MessageWriter writer(&data, &allocator, false);
- writer.WriteMessage(message);
- // TODO(turnidge): Throw an exception when the return value is false?
- PortMap::PostMessage(new Message(sp.Id(), data, writer.BytesWritten(),
- Message::kOOBPriority));
+// Scans the string until the '-' character. Returns pointer to string
+// at '-' character. Returns NULL if not found.
+static const char* ScanUntilDash(const char* s) {
+ if ((s == NULL) || (*s == '\0')) {
+ // Empty string.
+ return NULL;
+ }
+ while (*s != '\0') {
+ if (*s == '-') {
+ return s;
+ }
+ s++;
+ }
+ return NULL;
}
-static void SendRootServiceMessage(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Isolate* isolate = arguments->isolate();
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(0));
- Service::HandleRootMessage(message);
+static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
+ if ((s == NULL) || (*s == '\0')) {
+ // Empty string.
+ return false;
+ }
+ if ((timestamp == NULL) || (address == NULL)) {
+ // Bad arguments.
+ return false;
+ }
+ // Extract the timestamp.
+ if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
+ return false;
+ }
+ s = ScanUntilDash(s);
+ if (s == NULL) {
+ return false;
+ }
+ // Skip the dash.
+ s++;
+ // Extract the PC.
+ if (!GetUnsignedIntegerId(s, address, 16)) {
+ return false;
+ }
+ return true;
}
-class ScopeStopwatch : public ValueObject {
+class MethodParameter {
turnidge 2015/02/12 18:08:57 Consider adding standalone unit tests for BoolPara
Cutch 2015/02/12 18:18:47 I've added a TODO.
public:
- explicit ScopeStopwatch(const char* name) : name_(name) {
- start_ = OS::GetCurrentTimeMicros();
+ MethodParameter(const char* name, bool required)
+ : name_(name), required_(required) {
+ }
+
+ virtual ~MethodParameter() { }
+
+ virtual bool Validate(const char* value) const {
+ return true;
}
- int64_t GetElapsed() const {
- int64_t end = OS::GetCurrentTimeMicros();
- ASSERT(end >= start_);
- return end - start_;
+ const char* name() const {
+ return name_;
}
- ~ScopeStopwatch() {
- int64_t elapsed = GetElapsed();
- OS::Print("[%" Pd "] %s took %" Pd64 " micros.\n",
- OS::ProcessId(), name_, elapsed);
+ bool required() const {
+ return required_;
}
private:
const char* name_;
- int64_t start_;
+ bool required_;
};
-bool Service::IsRunning() {
- MonitorLocker ml(monitor_);
- return (service_port_ != ILLEGAL_PORT) && (service_isolate_ != NULL);
-}
+class BoolParameter : public MethodParameter {
+ public:
+ BoolParameter(const char* name, bool required)
+ : MethodParameter(name, required) {
+ }
+ virtual bool Validate(const char* value) const {
+ if (value == NULL) {
+ return false;
+ }
+ return (strcmp("true", value) == 0) || (strcmp("false", value) == 0);
+ }
-void Service::SetServicePort(Dart_Port port) {
- MonitorLocker ml(monitor_);
- service_port_ = port;
-}
+ static bool Interpret(const char* value) {
+ return strcmp("true", value) == 0;
+ }
+};
-void Service::SetServiceIsolate(Isolate* isolate) {
- MonitorLocker ml(monitor_);
- service_isolate_ = isolate;
- if (service_isolate_ != NULL) {
- service_isolate_->is_service_isolate_ = true;
+class IdParameter : public MethodParameter {
+ public:
+ IdParameter(const char* name, bool required)
+ : MethodParameter(name, required) {
}
-}
+ virtual bool Validate(const char* value) const {
+ return (value != NULL);
+ }
+};
-bool Service::HasServiceIsolate() {
- MonitorLocker ml(monitor_);
- return service_isolate_ != NULL;
-}
+#define ISOLATE_PARAMETER new IdParameter("isolateId", true)
-bool Service::IsServiceIsolate(Isolate* isolate) {
- MonitorLocker ml(monitor_);
- return isolate == service_isolate_;
-}
-Dart_Port Service::WaitForLoadPort() {
- MonitorLocker ml(monitor_);
+class EnumParameter : public MethodParameter {
+ public:
+ EnumParameter(const char* name, bool required, const char** enums)
+ : MethodParameter(name, required),
+ enums_(enums) {
+ }
- while (initializing_ && (load_port_ == ILLEGAL_PORT)) {
- ml.Wait();
+ virtual bool Validate(const char* value) const {
+ if (value == NULL) {
+ return true;
+ }
+ for (intptr_t i = 0; enums_[i] != NULL; i++) {
+ if (strcmp(value, enums_[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
}
- return load_port_;
-}
+ private:
+ const char** enums_;
+};
-Dart_Port Service::LoadPort() {
- MonitorLocker ml(monitor_);
- return load_port_;
+// If the key is not found, this function returns the last element in the
+// values array. This can be used to encode the default value.
+template<typename T>
+T EnumMapper(const char* value, const char** enums, T* values) {
+ ASSERT(value != NULL);
+ intptr_t i = 0;
+ for (i = 0; enums[i] != NULL; i++) {
+ if (strcmp(value, enums[i]) == 0) {
+ return values[i];
+ }
+ }
+ // Default value.
+ return values[i];
}
-void Service::SetLoadPort(Dart_Port port) {
- MonitorLocker ml(monitor_);
- load_port_ = port;
-}
+typedef bool (*ServiceMethodEntry)(Isolate* isolate, JSONStream* js);
-void Service::SetEventMask(uint32_t mask) {
- event_mask_ = mask;
-}
+struct ServiceMethodDescriptor {
+ const char* name;
+ const ServiceMethodEntry entry;
+ const MethodParameter* const * parameters;
+};
-static void SetEventMask(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Isolate* isolate = arguments->isolate();
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(0));
- Service::SetEventMask(mask.AsTruncatedUint32Value());
+static bool ValidateParameters(const MethodParameter* const* parameters,
+ JSONStream* js) {
+ if (parameters == NULL) {
+ return true;
+ }
+ for (intptr_t i = 0; parameters[i] != NULL; i++) {
+ const MethodParameter* parameter = parameters[i];
+ const char* name = parameter->name();
+ const bool required = parameter->required();
+ const char* value = js->LookupParam(name);
+ const bool has_parameter = (value != NULL);
+ if (required && !has_parameter) {
+ PrintMissingParamError(js, name);
+ return false;
+ }
+ if (!parameter->Validate(value)) {
+ PrintInvalidParamError(js, name);
+ return false;
+ }
+ }
turnidge 2015/02/12 18:08:57 We don't complain about unexpected extra parameter
+ return true;
}
-// These must be kept in sync with service/constants.dart
-#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
-#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
+void Service::InvokeMethod(Isolate* isolate, const Array& msg) {
+ ASSERT(isolate != NULL);
+ ASSERT(!msg.IsNull());
+ ASSERT(msg.Length() == 5);
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+
+ Instance& reply_port = Instance::Handle(isolate);
+ String& method_name = String::Handle(isolate);
+ Array& param_keys = Array::Handle(isolate);
+ Array& param_values = Array::Handle(isolate);
+ reply_port ^= msg.At(1);
+ method_name ^= msg.At(2);
+ param_keys ^= msg.At(3);
+ param_values ^= msg.At(4);
+ ASSERT(!method_name.IsNull());
+ ASSERT(!param_keys.IsNull());
+ ASSERT(!param_values.IsNull());
+ ASSERT(param_keys.Length() == param_values.Length());
-static RawArray* MakeServiceControlMessage(Dart_Port port_id, intptr_t code,
- const String& name) {
- const Array& list = Array::Handle(Array::New(4));
- ASSERT(!list.IsNull());
- const Integer& code_int = Integer::Handle(Integer::New(code));
- const Integer& port_int = Integer::Handle(Integer::New(port_id));
- const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
- list.SetAt(0, code_int);
- list.SetAt(1, port_int);
- list.SetAt(2, send_port);
- list.SetAt(3, name);
- return list.raw();
-}
+ if (!reply_port.IsSendPort()) {
+ FATAL("SendPort expected.");
+ }
+ JSONStream js;
+ js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+ method_name, param_keys, param_values);
-class RegisterRunningIsolatesVisitor : public IsolateVisitor {
- public:
- explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
- : IsolateVisitor(),
- register_function_(Function::Handle(service_isolate)),
- service_isolate_(service_isolate) {
- ASSERT(Service::IsServiceIsolate(Isolate::Current()));
- // Get library.
- const String& library_url = Symbols::DartVMService();
- ASSERT(!library_url.IsNull());
- const Library& library =
- Library::Handle(Library::LookupLibrary(library_url));
- ASSERT(!library.IsNull());
- // Get function.
- const String& function_name =
- String::Handle(String::New("_registerIsolate"));
- ASSERT(!function_name.IsNull());
- register_function_ = library.LookupFunctionAllowPrivate(function_name);
- ASSERT(!register_function_.IsNull());
- }
-
- virtual void VisitIsolate(Isolate* isolate) {
- ASSERT(Service::IsServiceIsolate(Isolate::Current()));
- if (Service::IsServiceIsolate(isolate) ||
- (isolate == Dart::vm_isolate())) {
- // We do not register the service or vm isolate.
+ const char* c_method_name = method_name.ToCString();
+
+ ServiceMethodDescriptor* method = FindMethod(c_method_name);
+ if (method != NULL) {
+ if (!ValidateParameters(method->parameters, &js)) {
+ js.PostReply();
+ return;
+ }
+ if (method->entry(isolate, &js)) {
+ js.PostReply();
+ }
return;
}
- // Setup arguments for call.
- Dart_Port port_id = isolate->main_port();
- const Integer& port_int = Integer::Handle(Integer::New(port_id));
- ASSERT(!port_int.IsNull());
- const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
- const String& name = String::Handle(String::New(isolate->name()));
- ASSERT(!name.IsNull());
- const Array& args = Array::Handle(Array::New(3));
- ASSERT(!args.IsNull());
- args.SetAt(0, port_int);
- args.SetAt(1, send_port);
- args.SetAt(2, name);
- Object& r = Object::Handle(service_isolate_);
- r = DartEntry::InvokeFunction(register_function_, args);
- if (FLAG_trace_service) {
- OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
- name.ToCString(),
- port_id);
- }
- ASSERT(!r.IsError());
- }
- private:
- Function& register_function_;
- Isolate* service_isolate_;
-};
+ EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(c_method_name);
+ if (handler == NULL) {
+ handler = FindRootEmbedderHandler(c_method_name);
+ }
+ if (handler != NULL) {
+ EmbedderHandleMessage(handler, &js);
+ js.PostReply();
+ return;
+ }
-static Dart_Port ExtractPort(Isolate* isolate, Dart_Handle receivePort) {
- const ReceivePort& rp = Api::UnwrapReceivePortHandle(isolate, receivePort);
- if (rp.IsNull()) {
- return ILLEGAL_PORT;
+ PrintUnrecognizedMethodError(&js);
+ js.PostReply();
+ return;
}
- return rp.Id();
}
-static void OnStart(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Isolate* isolate = arguments->isolate();
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- {
- if (FLAG_trace_service) {
- OS::Print("vm-service: Booting dart:vmservice library.\n");
- }
- // Boot the dart:vmservice library.
- Dart_EnterScope();
- Dart_Handle url_str =
- Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId));
- Dart_Handle library = Dart_LookupLibrary(url_str);
- ASSERT(Dart_IsLibrary(library));
- Dart_Handle result =
- Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL);
- ASSERT(!Dart_IsError(result));
- Dart_Port port = ExtractPort(isolate, result);
- ASSERT(port != ILLEGAL_PORT);
- Service::SetServicePort(port);
- Dart_ExitScope();
- }
-
- {
- if (FLAG_trace_service) {
- OS::Print("vm-service: Registering running isolates.\n");
- }
- // Register running isolates with service.
- RegisterRunningIsolatesVisitor register_isolates(isolate);
- Isolate::VisitIsolates(&register_isolates);
- }
+void Service::HandleRootMessage(const Array& msg_instance) {
+ Isolate* isolate = Isolate::Current();
+ InvokeMethod(isolate, msg_instance);
}
-struct VmServiceNativeEntry {
- const char* name;
- int num_arguments;
- Dart_NativeFunction function;
-};
+void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
+ ASSERT(isolate != NULL);
+ InvokeMethod(isolate, msg);
+}
-static VmServiceNativeEntry _VmServiceNativeEntries[] = {
- {"VMService_SendIsolateServiceMessage", 2, SendIsolateServiceMessage},
- {"VMService_SendRootServiceMessage", 1, SendRootServiceMessage},
- {"VMService_SetEventMask", 1, SetEventMask},
- {"VMService_OnStart", 0, OnStart },
-};
+bool Service::EventMaskHas(uint32_t mask) {
+ return (event_mask_ & mask) != 0;
+}
-static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
- int num_arguments,
- bool* auto_setup_scope) {
- const Object& obj = Object::Handle(Api::UnwrapHandle(name));
- if (!obj.IsString()) {
- return NULL;
- }
- const char* function_name = obj.ToCString();
- ASSERT(function_name != NULL);
- ASSERT(auto_setup_scope != NULL);
- *auto_setup_scope = true;
- intptr_t n =
- sizeof(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]);
- for (intptr_t i = 0; i < n; i++) {
- VmServiceNativeEntry entry = _VmServiceNativeEntries[i];
- if ((strcmp(function_name, entry.name) == 0) &&
- (num_arguments == entry.num_arguments)) {
- return entry.function;
- }
- }
- return NULL;
+bool Service::NeedsDebuggerEvents() {
+ return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyDebugMask);
}
-const char* Service::kIsolateName = "vm-service";
-EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
-EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
-Isolate* Service::service_isolate_ = NULL;
-Dart_Port Service::service_port_ = ILLEGAL_PORT;
-Dart_Port Service::load_port_ = ILLEGAL_PORT;
-Dart_IsolateCreateCallback Service::create_callback_ = NULL;
-Monitor* Service::monitor_ = NULL;
-bool Service::initializing_ = true;
-uint32_t Service::event_mask_ = 0;
-
-bool Service::IsServiceIsolateName(const char* name) {
- ASSERT(name != NULL);
- return strcmp(name, kIsolateName) == 0;
+bool Service::NeedsGCEvents() {
+ return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyGCMask);
}
-bool Service::SendIsolateStartupMessage() {
- if (!IsRunning()) {
- return false;
- }
- Isolate* isolate = Isolate::Current();
- if (IsServiceIsolate(isolate)) {
- return false;
- }
- ASSERT(isolate != NULL);
- HANDLESCOPE(isolate);
- const String& name = String::Handle(String::New(isolate->name()));
- ASSERT(!name.IsNull());
- const Array& list = Array::Handle(
- MakeServiceControlMessage(Dart_GetMainPortId(),
- VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID,
- name));
- ASSERT(!list.IsNull());
- uint8_t* data = NULL;
- MessageWriter writer(&data, &allocator, false);
- writer.WriteMessage(list);
- intptr_t len = writer.BytesWritten();
- if (FLAG_trace_service) {
- OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
- name.ToCString(),
- Dart_GetMainPortId());
- }
- return PortMap::PostMessage(
- new Message(service_port_, data, len, Message::kNormalPriority));
+void Service::SetEventMask(uint32_t mask) {
+ event_mask_ = mask;
}
-bool Service::SendIsolateShutdownMessage() {
- if (!IsRunning()) {
- return false;
+void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
+ if (!ServiceIsolate::IsRunning()) {
+ return;
}
Isolate* isolate = Isolate::Current();
- if (IsServiceIsolate(isolate)) {
- return false;
- }
ASSERT(isolate != NULL);
HANDLESCOPE(isolate);
- const String& name = String::Handle(String::New(isolate->name()));
- ASSERT(!name.IsNull());
- const Array& list = Array::Handle(
- MakeServiceControlMessage(Dart_GetMainPortId(),
- VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID,
- name));
+
+ // Construct a list of the form [eventId, eventMessage].
+ const Array& list = Array::Handle(Array::New(2));
ASSERT(!list.IsNull());
+ list.SetAt(0, Integer::Handle(Integer::New(eventId)));
+ list.SetAt(1, eventMessage);
+
+ // Push the event to port_.
uint8_t* data = NULL;
MessageWriter writer(&data, &allocator, false);
writer.WriteMessage(list);
intptr_t len = writer.BytesWritten();
if (FLAG_trace_service) {
- OS::Print("vm-service: Isolate %s %" Pd64 " deregistered.\n",
- name.ToCString(),
- Dart_GetMainPortId());
- }
- return PortMap::PostMessage(
- new Message(service_port_, data, len, Message::kNormalPriority));
-}
-
-
-Dart_Handle Service::GetSource(const char* name) {
- ASSERT(name != NULL);
- int i = 0;
- while (true) {
- const char* path = Resources::Path(i);
- if (path == NULL) {
- break;
- }
- ASSERT(*path != '\0');
- // Skip the '/'.
- path++;
- if (strcmp(name, path) == 0) {
- const uint8_t* str = Resources::Resource(i);
- intptr_t length = Resources::Length(i);
- return Dart_NewStringFromUTF8(str, length);
- }
- i++;
- }
- return Dart_Null();
-}
-
-
-Dart_Handle Service::LibraryTagHandler(Dart_LibraryTag tag,
- Dart_Handle library,
- Dart_Handle url) {
- if (tag == Dart_kCanonicalizeUrl) {
- // url is already canonicalized.
- return url;
- }
- if (tag != Dart_kSourceTag) {
- FATAL("Service::LibraryTagHandler encountered an unexpected tag.");
- }
- ASSERT(tag == Dart_kSourceTag);
- const char* url_string = NULL;
- Dart_Handle result = Dart_StringToCString(url, &url_string);
- if (Dart_IsError(result)) {
- return result;
- }
- Dart_Handle source = GetSource(url_string);
- if (Dart_IsError(source)) {
- return source;
+ OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
+ eventId, len);
}
- return Dart_LoadSource(library, url, source, 0, 0);
+ // TODO(turnidge): For now we ignore failure to send an event. Revisit?
+ PortMap::PostMessage(
+ new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority));
}
-void Service::MaybeInjectVMServiceLibrary(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ASSERT(isolate->name() != NULL);
- if (!Service::IsServiceIsolateName(isolate->name())) {
- // Not service isolate.
- return;
+void Service::SendEvent(intptr_t eventId,
+ const String& meta,
+ const uint8_t* data,
+ intptr_t size) {
+ // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
+ const intptr_t meta_bytes = Utf8::Length(meta);
+ const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
+ const TypedData& message = TypedData::Handle(
+ TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
+ intptr_t offset = 0;
+ // TODO(koda): Rename these methods SetHostUint64, etc.
+ message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
+ offset += sizeof(uint64_t);
+ {
+ NoGCScope no_gc;
+ meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
+ offset += meta_bytes;
}
- if (HasServiceIsolate()) {
- // Service isolate already exists.
- return;
+ // TODO(koda): It would be nice to avoid this copy (requires changes to
+ // MessageWriter code).
+ {
+ NoGCScope no_gc;
+ memmove(message.DataAddr(offset), data, size);
+ offset += size;
}
- SetServiceIsolate(isolate);
-
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
-
- // Register dart:vmservice library.
- const String& url_str = String::Handle(Symbols::DartVMService().raw());
- const Library& library = Library::Handle(Library::New(url_str));
- library.Register();
- library.set_native_entry_resolver(VmServiceNativeResolver);
-
- // Temporarily install our library tag handler.
- isolate->set_library_tag_handler(LibraryTagHandler);
-
- // Get script source.
- const char* resource = NULL;
- const char* path = "/vmservice.dart";
- intptr_t r = Resources::ResourceLookup(path, &resource);
- ASSERT(r != Resources::kNoSuchInstance);
- ASSERT(resource != NULL);
- const String& source_str = String::Handle(
- String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r));
- ASSERT(!source_str.IsNull());
- const Script& script = Script::Handle(
- isolate, Script::New(url_str, source_str, RawScript::kLibraryTag));
-
- // Compile script.
- Dart_EnterScope(); // Need to enter scope for tag handler.
- library.SetLoadInProgress();
- const Error& error = Error::Handle(isolate,
- Compiler::Compile(library, script));
- ASSERT(error.IsNull());
- Dart_Handle result = Dart_FinalizeLoading(false);
- ASSERT(!Dart_IsError(result));
- Dart_ExitScope();
-
- // Uninstall our library tag handler.
- isolate->set_library_tag_handler(NULL);
+ ASSERT(offset == total_bytes);
+ SendEvent(eventId, message);
}
-void Service::FinishedInitializing() {
- MonitorLocker ml(monitor_);
- initializing_ = false;
- ml.NotifyAll();
+void Service::HandleGCEvent(GCEvent* event) {
+ JSONStream js;
+ event->PrintJSON(&js);
+ const String& message = String::Handle(String::New(js.ToCString()));
+ SendEvent(kEventFamilyGC, message);
}
-static void ShutdownIsolate(uword parameter) {
- Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
- ASSERT(Service::IsServiceIsolate(isolate));
- {
- // Print the error if there is one. This may execute dart code to
- // print the exception object, so we need to use a StartIsolateScope.
- StartIsolateScope start_scope(isolate);
- StackZone zone(isolate);
- HandleScope handle_scope(isolate);
- Error& error = Error::Handle();
- error = isolate->object_store()->sticky_error();
- if (!error.IsNull()) {
- OS::PrintErr("vm-service: Error: %s\n", error.ToErrorCString());
- }
- Dart::RunShutdownCallback();
- }
- {
- // Shut the isolate down.
- SwitchIsolateScope switch_scope(isolate);
- Dart::ShutdownIsolate();
- }
- Service::SetServiceIsolate(NULL);
- Service::SetServicePort(ILLEGAL_PORT);
- if (FLAG_trace_service) {
- OS::Print("vm-service: Shutdown.\n");
- }
+void Service::HandleDebuggerEvent(DebuggerEvent* event) {
+ JSONStream js;
+ event->PrintJSON(&js);
+ const String& message = String::Handle(String::New(js.ToCString()));
+ SendEvent(kEventFamilyDebug, message);
}
-class RunServiceTask : public ThreadPool::Task {
+class EmbedderServiceHandler {
public:
- virtual void Run() {
- ASSERT(Isolate::Current() == NULL);
- char* error = NULL;
- Isolate* isolate = NULL;
-
- Dart_IsolateCreateCallback create_callback = Service::create_callback();
- // TODO(johnmccutchan): Support starting up service isolate without embedder
- // provided isolate creation callback.
- if (create_callback == NULL) {
- Service::FinishedInitializing();
- return;
- }
-
- isolate =
- reinterpret_cast<Isolate*>(create_callback(Service::kIsolateName,
- NULL,
- NULL,
- NULL,
- &error));
- if (isolate == NULL) {
- OS::PrintErr("vm-service: Isolate creation error: %s\n", error);
- Service::FinishedInitializing();
- return;
- }
-
- Isolate::SetCurrent(NULL);
+ explicit EmbedderServiceHandler(const char* name) : name_(NULL),
+ callback_(NULL),
+ user_data_(NULL),
+ next_(NULL) {
+ ASSERT(name != NULL);
+ name_ = strdup(name);
+ }
- RunMain(isolate);
+ ~EmbedderServiceHandler() {
+ free(name_);
+ }
- Service::FinishedInitializing();
+ const char* name() const { return name_; }
- isolate->message_handler()->Run(Dart::thread_pool(),
- NULL,
- ShutdownIsolate,
- reinterpret_cast<uword>(isolate));
+ Dart_ServiceRequestCallback callback() const { return callback_; }
+ void set_callback(Dart_ServiceRequestCallback callback) {
+ callback_ = callback;
}
- protected:
- void RunMain(Isolate* isolate) {
- StartIsolateScope iso_scope(isolate);
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
- // Invoke main which will return the loadScriptPort.
- const Library& root_library =
- Library::Handle(isolate, isolate->object_store()->root_library());
- if (root_library.IsNull()) {
- if (FLAG_trace_service) {
- OS::Print("vm-service: Embedder did not install a script.");
- }
- // Service isolate is not supported by embedder.
- return;
- }
- ASSERT(!root_library.IsNull());
- const String& entry_name = String::Handle(isolate, String::New("main"));
- ASSERT(!entry_name.IsNull());
- const Function& entry =
- Function::Handle(isolate,
- root_library.LookupFunctionAllowPrivate(entry_name));
- if (entry.IsNull()) {
- // Service isolate is not supported by embedder.
- if (FLAG_trace_service) {
- OS::Print("vm-service: Embedder did not provide a main function.");
- }
- return;
- }
- ASSERT(!entry.IsNull());
- const Object& result =
- Object::Handle(isolate,
- DartEntry::InvokeFunction(entry,
- Object::empty_array()));
- ASSERT(!result.IsNull());
- if (result.IsError()) {
- // Service isolate did not initialize properly.
- if (FLAG_trace_service) {
- const Error& error = Error::Cast(result);
- OS::Print("vm-service: Calling main resulted in an error: %s",
- error.ToErrorCString());
- }
- return;
- }
- ASSERT(result.IsReceivePort());
- const ReceivePort& rp = ReceivePort::Cast(result);
- Service::SetLoadPort(rp.Id());
+ void* user_data() const { return user_data_; }
+ void set_user_data(void* user_data) {
+ user_data_ = user_data;
}
-};
-
-void Service::RunService() {
- ASSERT(monitor_ == NULL);
- monitor_ = new Monitor();
- ASSERT(monitor_ != NULL);
- // Grab the isolate create callback here to avoid race conditions with tests
- // that change this after Dart_Initialize returns.
- create_callback_ = Isolate::CreateCallback();
- Dart::thread_pool()->Run(new RunServiceTask());
-}
-
-// A handler for a per-isolate request.
-//
-// If a handler returns true, the reply is complete and ready to be
-// posted. If a handler returns false, then it is responsible for
-// posting the reply (this can be used for asynchronous delegation of
-// the response handling).
-typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
+ EmbedderServiceHandler* next() const { return next_; }
+ void set_next(EmbedderServiceHandler* next) {
+ next_ = next;
+ }
-struct IsolateMessageHandlerEntry {
- const char* method;
- IsolateMessageHandler handler;
+ private:
+ char* name_;
+ Dart_ServiceRequestCallback callback_;
+ void* user_data_;
+ EmbedderServiceHandler* next_;
};
-static IsolateMessageHandler FindIsolateMessageHandler(const char* method);
-
-// A handler for a root (vm-global) request.
-//
-// If a handler returns true, the reply is complete and ready to be
-// posted. If a handler returns false, then it is responsible for
-// posting the reply (this can be used for asynchronous delegation of
-// the response handling).
-typedef bool (*RootMessageHandler)(JSONStream* stream);
-
-struct RootMessageHandlerEntry {
- const char* method;
- RootMessageHandler handler;
-};
-
-static RootMessageHandler FindRootMessageHandler(const char* method);
+void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
+ JSONStream* js) {
+ ASSERT(handler != NULL);
+ Dart_ServiceRequestCallback callback = handler->callback();
+ ASSERT(callback != NULL);
+ const char* r = NULL;
+ const char* name = js->method();
+ const char** keys = js->param_keys();
+ const char** values = js->param_values();
+ r = callback(name, keys, values, js->num_params(), handler->user_data());
+ ASSERT(r != NULL);
+ // TODO(johnmccutchan): Allow for NULL returns?
+ TextBuffer* buffer = js->buffer();
+ buffer->AddString(r);
+ free(const_cast<char*>(r));
+}
-static void PrintRequest(const JSONObject& obj, JSONStream* js) {
- JSONObject jsobj(&obj, "request");
- jsobj.AddProperty("method", js->method());
- {
- JSONArray jsarr(&jsobj, "param_keys");
- for (intptr_t i = 0; i < js->num_params(); i++) {
- jsarr.AddValue(js->GetParamKey(i));
- }
+void Service::RegisterIsolateEmbedderCallback(
+ const char* name,
+ Dart_ServiceRequestCallback callback,
+ void* user_data) {
+ if (name == NULL) {
+ return;
}
- {
- JSONArray jsarr(&jsobj, "param_values");
- for (intptr_t i = 0; i < js->num_params(); i++) {
- jsarr.AddValue(js->GetParamValue(i));
- }
+ EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
+ if (handler != NULL) {
+ // Update existing handler entry.
+ handler->set_callback(callback);
+ handler->set_user_data(user_data);
+ return;
}
-}
-
-
-static void PrintError(JSONStream* js,
- const char* format, ...) {
- Isolate* isolate = Isolate::Current();
-
- va_list args;
- va_start(args, format);
- intptr_t len = OS::VSNPrint(NULL, 0, format, args);
- va_end(args);
-
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
- va_list args2;
- va_start(args2, format);
- OS::VSNPrint(buffer, (len + 1), format, args2);
- va_end(args2);
-
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Error");
- jsobj.AddProperty("message", buffer);
- PrintRequest(jsobj, js);
-}
-
+ // Create a new handler.
+ handler = new EmbedderServiceHandler(name);
+ handler->set_callback(callback);
+ handler->set_user_data(user_data);
-static void PrintMissingParamError(JSONStream* js,
- const char* param) {
- PrintError(js, "%s expects the '%s' parameter",
- js->method(), param);
+ // Insert into isolate_service_handler_head_ list.
+ handler->set_next(isolate_service_handler_head_);
+ isolate_service_handler_head_ = handler;
}
-static void PrintInvalidParamError(JSONStream* js,
- const char* param) {
- PrintError(js, "%s: invalid '%s' parameter: %s",
- js->method(), param, js->LookupParam(param));
+EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
+ const char* name) {
+ EmbedderServiceHandler* current = isolate_service_handler_head_;
+ while (current != NULL) {
+ if (strcmp(name, current->name()) == 0) {
+ return current;
+ }
+ current = current->next();
+ }
+ return NULL;
}
-static void PrintErrorWithKind(JSONStream* js,
- const char* kind,
- const char* format, ...) {
- Isolate* isolate = Isolate::Current();
-
- va_list args;
- va_start(args, format);
- intptr_t len = OS::VSNPrint(NULL, 0, format, args);
- va_end(args);
-
- char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
- va_list args2;
- va_start(args2, format);
- OS::VSNPrint(buffer, (len + 1), format, args2);
- va_end(args2);
+void Service::RegisterRootEmbedderCallback(
+ const char* name,
+ Dart_ServiceRequestCallback callback,
+ void* user_data) {
+ if (name == NULL) {
+ return;
+ }
+ EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
+ if (handler != NULL) {
+ // Update existing handler entry.
+ handler->set_callback(callback);
+ handler->set_user_data(user_data);
+ return;
+ }
+ // Create a new handler.
+ handler = new EmbedderServiceHandler(name);
+ handler->set_callback(callback);
+ handler->set_user_data(user_data);
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Error");
- jsobj.AddProperty("id", "");
- jsobj.AddProperty("kind", kind);
- jsobj.AddProperty("message", buffer);
- PrintRequest(jsobj, js);
+ // Insert into root_service_handler_head_ list.
+ handler->set_next(root_service_handler_head_);
+ root_service_handler_head_ = handler;
}
-void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
- ASSERT(isolate != NULL);
- ASSERT(!msg.IsNull());
- ASSERT(msg.Length() == 5);
-
- {
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
-
- Instance& reply_port = Instance::Handle(isolate);
- String& method = String::Handle(isolate);
- Array& param_keys = Array::Handle(isolate);
- Array& param_values = Array::Handle(isolate);
- reply_port ^= msg.At(1);
- method ^= msg.At(2);
- param_keys ^= msg.At(3);
- param_values ^= msg.At(4);
-
- ASSERT(!method.IsNull());
- ASSERT(!param_keys.IsNull());
- ASSERT(!param_values.IsNull());
- ASSERT(param_keys.Length() == param_values.Length());
-
- if (!reply_port.IsSendPort()) {
- FATAL("SendPort expected.");
- }
-
- IsolateMessageHandler handler =
- FindIsolateMessageHandler(method.ToCString());
- {
- JSONStream js;
- js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- method, param_keys, param_values);
- if (handler == NULL) {
- // Check for an embedder handler.
- EmbedderServiceHandler* e_handler =
- FindIsolateEmbedderHandler(method.ToCString());
- if (e_handler != NULL) {
- EmbedderHandleMessage(e_handler, &js);
- } else {
- if (FindRootMessageHandler(method.ToCString()) != NULL) {
- PrintError(&js, "%s does not expect the 'isolateId' parameter",
- method.ToCString());
- } else {
- PrintError(&js, "Unrecognized method: %s", method.ToCString());
- }
- }
- js.PostReply();
- } else {
- if (handler(isolate, &js)) {
- // Handler returns true if the reply is ready to be posted.
- // TODO(johnmccutchan): Support asynchronous replies.
- js.PostReply();
- }
- }
+EmbedderServiceHandler* Service::FindRootEmbedderHandler(
+ const char* name) {
+ EmbedderServiceHandler* current = root_service_handler_head_;
+ while (current != NULL) {
+ if (strcmp(name, current->name()) == 0) {
+ return current;
}
+ current = current->next();
}
+ return NULL;
}
@@ -1048,112 +743,6 @@ static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) {
}
-static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
- if ((s == NULL) || (*s == '\0')) {
- // Empty string.
- return false;
- }
- if (id == NULL) {
- // No id pointer.
- return false;
- }
- intptr_t r = 0;
- char* end_ptr = NULL;
- r = strtol(s, &end_ptr, base);
- if (end_ptr == s) {
- // String was not advanced at all, cannot be valid.
- return false;
- }
- *id = r;
- return true;
-}
-
-
-static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
- if ((s == NULL) || (*s == '\0')) {
- // Empty string.
- return false;
- }
- if (id == NULL) {
- // No id pointer.
- return false;
- }
- uintptr_t r = 0;
- char* end_ptr = NULL;
- r = strtoul(s, &end_ptr, base);
- if (end_ptr == s) {
- // String was not advanced at all, cannot be valid.
- return false;
- }
- *id = r;
- return true;
-}
-
-
-static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
- if ((s == NULL) || (*s == '\0')) {
- // Empty string.
- return false;
- }
- if (id == NULL) {
- // No id pointer.
- return false;
- }
- int64_t r = 0;
- char* end_ptr = NULL;
- r = strtoll(s, &end_ptr, base);
- if (end_ptr == s) {
- // String was not advanced at all, cannot be valid.
- return false;
- }
- *id = r;
- return true;
-}
-
-// Scans the string until the '-' character. Returns pointer to string
-// at '-' character. Returns NULL if not found.
-static const char* ScanUntilDash(const char* s) {
- if ((s == NULL) || (*s == '\0')) {
- // Empty string.
- return NULL;
- }
- while (*s != '\0') {
- if (*s == '-') {
- return s;
- }
- s++;
- }
- return NULL;
-}
-
-
-static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
- if ((s == NULL) || (*s == '\0')) {
- // Empty string.
- return false;
- }
- if ((timestamp == NULL) || (address == NULL)) {
- // Bad arguments.
- return false;
- }
- // Extract the timestamp.
- if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
- return false;
- }
- s = ScanUntilDash(s);
- if (s == NULL) {
- return false;
- }
- // Skip the dash.
- s++;
- // Extract the PC.
- if (!GetUnsignedIntegerId(s, address, 16)) {
- return false;
- }
- return true;
-}
-
-
static bool ContainsNonInstance(const Object& obj) {
if (obj.IsArray()) {
const Array& array = Array::Cast(obj);
@@ -1912,14 +1501,71 @@ static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
wrapper.SetLength(count);
storage = Array::MakeArray(wrapper);
}
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "InstanceSet");
- jsobj.AddProperty("id", "instance_set");
- jsobj.AddProperty("totalCount", count);
- jsobj.AddProperty("sampleCount", storage.Length());
- jsobj.AddProperty("sample", storage);
- return true;
-}
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "InstanceSet");
+ jsobj.AddProperty("id", "instance_set");
+ jsobj.AddProperty("totalCount", count);
+ jsobj.AddProperty("sampleCount", storage.Length());
+ jsobj.AddProperty("sample", storage);
+ return true;
+}
+
+
+class LibraryCoverageFilter : public CoverageFilter {
+ public:
+ explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {}
+ bool ShouldOutputCoverageFor(const Library& lib,
+ const Script& script,
+ const Class& cls,
+ const Function& func) const {
+ return lib.raw() == lib_.raw();
+ }
+ private:
+ const Library& lib_;
+};
+
+
+class ScriptCoverageFilter : public CoverageFilter {
+ public:
+ explicit ScriptCoverageFilter(const Script& script)
+ : script_(script) {}
+ bool ShouldOutputCoverageFor(const Library& lib,
+ const Script& script,
+ const Class& cls,
+ const Function& func) const {
+ return script.raw() == script_.raw();
+ }
+ private:
+ const Script& script_;
+};
+
+
+class ClassCoverageFilter : public CoverageFilter {
+ public:
+ explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {}
+ bool ShouldOutputCoverageFor(const Library& lib,
+ const Script& script,
+ const Class& cls,
+ const Function& func) const {
+ return cls.raw() == cls_.raw();
+ }
+ private:
+ const Class& cls_;
+};
+
+
+class FunctionCoverageFilter : public CoverageFilter {
+ public:
+ explicit FunctionCoverageFilter(const Function& func) : func_(func) {}
+ bool ShouldOutputCoverageFor(const Library& lib,
+ const Script& script,
+ const Class& cls,
+ const Function& func) const {
+ return func.raw() == func_.raw();
+ }
+ private:
+ const Function& func_;
+};
static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
@@ -2155,12 +1801,12 @@ static bool HandleIsolateGetMetric(Isolate* isolate, JSONStream* js) {
}
-static bool HandleVMGetMetricList(JSONStream* js) {
+static bool HandleVMGetMetricList(Isolate* isolate, JSONStream* js) {
return false;
}
-static bool HandleVMGetMetric(JSONStream* js) {
+static bool HandleVMGetMetric(Isolate* isolate, JSONStream* js) {
const char* metric_id = js->LookupParam("metricId");
if (metric_id == NULL) {
PrintMissingParamError(js, "metricId");
@@ -2242,24 +1888,37 @@ static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
return true;
}
+
+static const char* tags_enum_names[] = {
+ "None",
+ "UserVM",
+ "UserOnly",
+ "VMUser",
+ "VMOnly",
+ NULL,
+};
+
+
+static ProfilerService::TagOrder tags_enum_values[] = {
+ ProfilerService::kNoTags,
+ ProfilerService::kUserVM,
+ ProfilerService::kUser,
+ ProfilerService::kVMUser,
+ ProfilerService::kVM,
+ ProfilerService::kNoTags, // Default value.
+};
+
+
+static const MethodParameter* cpu_profile_params[] = {
+ ISOLATE_PARAMETER,
+ new EnumParameter("tags", true, tags_enum_names),
+ NULL,
+};
+
+
static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
- ProfilerService::TagOrder tag_order = ProfilerService::kUserVM;
- if (js->HasParam("tags")) {
- if (js->ParamIs("tags", "None")) {
- tag_order = ProfilerService::kNoTags;
- } else if (js->ParamIs("tags", "UserVM")) {
- tag_order = ProfilerService::kUserVM;
- } else if (js->ParamIs("tags", "UserOnly")) {
- tag_order = ProfilerService::kUser;
- } else if (js->ParamIs("tags", "VMUser")) {
- tag_order = ProfilerService::kVMUser;
- } else if (js->ParamIs("tags", "VMOnly")) {
- tag_order = ProfilerService::kVM;
- } else {
- PrintInvalidParamError(js, "tags");
- return true;
- }
- }
+ ProfilerService::TagOrder tag_order =
+ EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
ProfilerService::PrintJSON(js, tag_order);
return true;
}
@@ -2473,122 +2132,6 @@ static bool HandleIsolateGetTypeArgumentsList(Isolate* isolate,
}
-static IsolateMessageHandlerEntry isolate_handlers_new[] = {
- { "getIsolate", HandleIsolate },
- { "getObject", HandleIsolateGetObject },
- { "getObjectByAddress", HandleIsolateGetObjectByAddress },
- { "getBreakpoints", HandleIsolateGetBreakpoints },
- { "pause", HandleIsolatePause },
- { "resume", HandleIsolateResume },
- { "getStack", HandleIsolateGetStack },
- { "getCpuProfile", HandleIsolateGetCpuProfile },
- { "getTagProfile", HandleIsolateGetTagProfile },
- { "getAllocationProfile", HandleIsolateGetAllocationProfile },
- { "getHeapMap", HandleIsolateGetHeapMap },
- { "addBreakpoint", HandleIsolateAddBreakpoint },
- { "removeBreakpoint", HandleIsolateRemoveBreakpoint },
- { "getCoverage", HandleIsolateGetCoverage },
- { "eval", HandleIsolateEval },
- { "getRetainedSize", HandleIsolateGetRetainedSize },
- { "getRetainingPath", HandleIsolateGetRetainingPath },
- { "getInboundReferences", HandleIsolateGetInboundReferences },
- { "getInstances", HandleIsolateGetInstances },
- { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot },
- { "getClassList", HandleIsolateGetClassList },
- { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList },
- { "getIsolateMetricList", HandleIsolateGetMetricList },
- { "getIsolateMetric", HandleIsolateGetMetric },
- { "_echo", HandleIsolateEcho },
- { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent },
- { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson },
- { "_respondWithMalformedObject", HandleIsolateRespondWithMalformedObject },
-};
-
-
-static IsolateMessageHandler FindIsolateMessageHandler(const char* method) {
- intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
- sizeof(isolate_handlers_new[0]);
- for (intptr_t i = 0; i < num_message_handlers; i++) {
- const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
- if (strcmp(method, entry.method) == 0) {
- return entry.handler;
- }
- }
- if (FLAG_trace_service) {
- OS::Print("Service has no isolate message handler for <%s>\n", method);
- }
- return NULL;
-}
-
-
-void Service::HandleRootMessage(const Instance& msg_instance) {
- Isolate* isolate = Isolate::Current();
- ASSERT(!msg_instance.IsNull());
- ASSERT(msg_instance.IsArray());
-
- {
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
-
- const Array& msg = Array::Cast(msg_instance);
- ASSERT(msg.Length() == 5);
-
- Instance& reply_port = Instance::Handle(isolate);
- String& method = String::Handle(isolate);
- Array& param_keys = Array::Handle(isolate);
- Array& param_values = Array::Handle(isolate);
- reply_port ^= msg.At(1);
- method ^= msg.At(2);
- param_keys ^= msg.At(3);
- param_values ^= msg.At(4);
-
- ASSERT(!method.IsNull());
- ASSERT(!param_keys.IsNull());
- ASSERT(!param_values.IsNull());
- ASSERT(param_keys.Length() == param_values.Length());
-
- if (!reply_port.IsSendPort()) {
- FATAL("SendPort expected.");
- }
-
- RootMessageHandler handler =
- FindRootMessageHandler(method.ToCString());
- {
- JSONStream js;
- js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- method, param_keys, param_values);
- if (handler == NULL) {
- // Check for an embedder handler.
- EmbedderServiceHandler* e_handler =
- FindRootEmbedderHandler(method.ToCString());
- if (e_handler != NULL) {
- EmbedderHandleMessage(e_handler, &js);
- } else {
- if (FindIsolateMessageHandler(method.ToCString()) != NULL) {
- PrintMissingParamError(&js, "isolateId");
- } else {
- PrintError(&js, "Unrecognized method: %s", method.ToCString());
- }
- }
- js.PostReply();
- } else {
- if (handler(&js)) {
- // Handler returns true if the reply is ready to be posted.
- // TODO(johnmccutchan): Support asynchronous replies.
- js.PostReply();
- }
- }
- }
- }
-}
-
-
-static bool HandleRootEcho(JSONStream* js) {
- JSONObject jsobj(js);
- return HandleCommonEcho(&jsobj, js);
-}
-
-
class ServiceIsolateVisitor : public IsolateVisitor {
public:
explicit ServiceIsolateVisitor(JSONArray* jsarr)
@@ -2598,7 +2141,8 @@ class ServiceIsolateVisitor : public IsolateVisitor {
virtual ~ServiceIsolateVisitor() {}
void VisitIsolate(Isolate* isolate) {
- if (isolate != Dart::vm_isolate() && !Service::IsServiceIsolate(isolate)) {
+ if ((isolate != Dart::vm_isolate()) &&
+ !ServiceIsolate::IsServiceIsolate(isolate)) {
jsarr_->AddValue(isolate);
}
}
@@ -2608,8 +2152,7 @@ class ServiceIsolateVisitor : public IsolateVisitor {
};
-static bool HandleVM(JSONStream* js) {
- Isolate* isolate = Isolate::Current();
+static bool HandleVM(Isolate* isolate, JSONStream* js) {
JSONObject jsobj(js);
jsobj.AddProperty("type", "VM");
jsobj.AddProperty("id", "vm");
@@ -2640,13 +2183,13 @@ static bool HandleVM(JSONStream* js) {
}
-static bool HandleVMFlagList(JSONStream* js) {
+static bool HandleVMFlagList(Isolate* isolate, JSONStream* js) {
Flags::PrintJSON(js);
return true;
}
-static bool HandleVMSetFlag(JSONStream* js) {
+static bool HandleVMSetFlag(Isolate* isolate, JSONStream* js) {
const char* flag_name = js->LookupParam("name");
if (flag_name == NULL) {
PrintMissingParamError(js, "name");
@@ -2672,198 +2215,55 @@ static bool HandleVMSetFlag(JSONStream* js) {
}
-static RootMessageHandlerEntry root_handlers_new[] = {
- { "getVM", HandleVM },
- { "getFlagList", HandleVMFlagList },
- { "setFlag", HandleVMSetFlag },
- { "getVMMetricList", HandleVMGetMetricList },
- { "getVMMetric", HandleVMGetMetric },
- { "_echo", HandleRootEcho },
+static ServiceMethodDescriptor service_methods_[] = {
+ { "_echo", HandleIsolateEcho, NULL },
+ { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson, NULL },
+ { "_respondWithMalformedObject",
+ HandleIsolateRespondWithMalformedObject, NULL },
+ { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent, NULL },
+ { "addBreakpoint", HandleIsolateAddBreakpoint, NULL },
+ { "eval", HandleIsolateEval, NULL },
+ { "getAllocationProfile", HandleIsolateGetAllocationProfile, NULL },
+ { "getBreakpoints", HandleIsolateGetBreakpoints, NULL },
+ { "getClassList", HandleIsolateGetClassList, NULL },
+ { "getCoverage", HandleIsolateGetCoverage, NULL },
+ { "getCpuProfile", HandleIsolateGetCpuProfile, cpu_profile_params, },
turnidge 2015/02/12 18:08:57 Would be nice to add validators for everything as
Cutch 2015/02/12 18:18:47 Partially done. Only the isolate parameter is list
+ { "getFlagList", HandleVMFlagList , NULL},
+ { "getHeapMap", HandleIsolateGetHeapMap, NULL },
+ { "getInboundReferences", HandleIsolateGetInboundReferences, NULL },
+ { "getInstances", HandleIsolateGetInstances, NULL },
+ { "getIsolate", HandleIsolate, NULL },
+ { "getIsolateMetric", HandleIsolateGetMetric, NULL },
+ { "getIsolateMetricList", HandleIsolateGetMetricList, NULL },
+ { "getObject", HandleIsolateGetObject, NULL },
+ { "getObjectByAddress", HandleIsolateGetObjectByAddress, NULL },
+ { "getRetainedSize", HandleIsolateGetRetainedSize, NULL },
+ { "getRetainingPath", HandleIsolateGetRetainingPath, NULL },
+ { "getStack", HandleIsolateGetStack, NULL },
+ { "getTagProfile", HandleIsolateGetTagProfile, NULL },
+ { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList, NULL },
+ { "getVM", HandleVM , NULL},
+ { "getVMMetric", HandleVMGetMetric , NULL},
+ { "getVMMetricList", HandleVMGetMetricList , NULL},
+ { "pause", HandleIsolatePause, NULL },
+ { "removeBreakpoint", HandleIsolateRemoveBreakpoint, NULL },
+ { "resume", HandleIsolateResume, NULL },
+ { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot, NULL },
+ { "setFlag", HandleVMSetFlag , NULL},
};
-static RootMessageHandler FindRootMessageHandler(const char* method) {
- intptr_t num_message_handlers = sizeof(root_handlers_new) /
- sizeof(root_handlers_new[0]);
- for (intptr_t i = 0; i < num_message_handlers; i++) {
- const RootMessageHandlerEntry& entry = root_handlers_new[i];
- if (strcmp(method, entry.method) == 0) {
- return entry.handler;
- }
- }
- if (FLAG_trace_service) {
- OS::Print("vm-service: No root message handler for <%s>.\n", method);
- }
- return NULL;
-}
-
-
-void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
- if (!IsRunning()) {
- return;
- }
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- HANDLESCOPE(isolate);
-
- // Construct a list of the form [eventId, eventMessage].
- const Array& list = Array::Handle(Array::New(2));
- ASSERT(!list.IsNull());
- list.SetAt(0, Integer::Handle(Integer::New(eventId)));
- list.SetAt(1, eventMessage);
-
- // Push the event to port_.
- uint8_t* data = NULL;
- MessageWriter writer(&data, &allocator, false);
- writer.WriteMessage(list);
- intptr_t len = writer.BytesWritten();
- if (FLAG_trace_service) {
- OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
- eventId, len);
- }
- // TODO(turnidge): For now we ignore failure to send an event. Revisit?
- PortMap::PostMessage(
- new Message(service_port_, data, len, Message::kNormalPriority));
-}
-
-
-void Service::SendEvent(intptr_t eventId,
- const String& meta,
- const uint8_t* data,
- intptr_t size) {
- // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
- const intptr_t meta_bytes = Utf8::Length(meta);
- const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
- const TypedData& message = TypedData::Handle(
- TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
- intptr_t offset = 0;
- // TODO(koda): Rename these methods SetHostUint64, etc.
- message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
- offset += sizeof(uint64_t);
- {
- NoGCScope no_gc;
- meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
- offset += meta_bytes;
- }
- // TODO(koda): It would be nice to avoid this copy (requires changes to
- // MessageWriter code).
- {
- NoGCScope no_gc;
- memmove(message.DataAddr(offset), data, size);
- offset += size;
- }
- ASSERT(offset == total_bytes);
- SendEvent(eventId, message);
-}
-
-
-void Service::HandleGCEvent(GCEvent* event) {
- JSONStream js;
- event->PrintJSON(&js);
- const String& message = String::Handle(String::New(js.ToCString()));
- SendEvent(kEventFamilyGC, message);
-}
-
-
-void Service::HandleDebuggerEvent(DebuggerEvent* event) {
- JSONStream js;
- event->PrintJSON(&js);
- const String& message = String::Handle(String::New(js.ToCString()));
- SendEvent(kEventFamilyDebug, message);
-}
-
-
-void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
- JSONStream* js) {
- ASSERT(handler != NULL);
- Dart_ServiceRequestCallback callback = handler->callback();
- ASSERT(callback != NULL);
- const char* r = NULL;
- const char* name = js->method();
- const char** keys = js->param_keys();
- const char** values = js->param_values();
- r = callback(name, keys, values, js->num_params(), handler->user_data());
- ASSERT(r != NULL);
- // TODO(johnmccutchan): Allow for NULL returns?
- TextBuffer* buffer = js->buffer();
- buffer->AddString(r);
- free(const_cast<char*>(r));
-}
-
-
-void Service::RegisterIsolateEmbedderCallback(
- const char* name,
- Dart_ServiceRequestCallback callback,
- void* user_data) {
- if (name == NULL) {
- return;
- }
- EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
- if (handler != NULL) {
- // Update existing handler entry.
- handler->set_callback(callback);
- handler->set_user_data(user_data);
- return;
- }
- // Create a new handler.
- handler = new EmbedderServiceHandler(name);
- handler->set_callback(callback);
- handler->set_user_data(user_data);
-
- // Insert into isolate_service_handler_head_ list.
- handler->set_next(isolate_service_handler_head_);
- isolate_service_handler_head_ = handler;
-}
-
-
-EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
- const char* name) {
- EmbedderServiceHandler* current = isolate_service_handler_head_;
- while (current != NULL) {
- if (strcmp(name, current->name()) == 0) {
- return current;
+ServiceMethodDescriptor* FindMethod(const char* method_name) {
+ intptr_t num_methods = sizeof(service_methods_) /
+ sizeof(service_methods_[0]);
+ for (intptr_t i = 0; i < num_methods; i++) {
+ ServiceMethodDescriptor& method = service_methods_[i];
+ if (strcmp(method_name, method.name) == 0) {
+ return &method;
}
- current = current->next();
}
return NULL;
}
-void Service::RegisterRootEmbedderCallback(
- const char* name,
- Dart_ServiceRequestCallback callback,
- void* user_data) {
- if (name == NULL) {
- return;
- }
- EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
- if (handler != NULL) {
- // Update existing handler entry.
- handler->set_callback(callback);
- handler->set_user_data(user_data);
- return;
- }
- // Create a new handler.
- handler = new EmbedderServiceHandler(name);
- handler->set_callback(callback);
- handler->set_user_data(user_data);
-
- // Insert into root_service_handler_head_ list.
- handler->set_next(root_service_handler_head_);
- root_service_handler_head_ = handler;
-}
-
-
-EmbedderServiceHandler* Service::FindRootEmbedderHandler(
- const char* name) {
- EmbedderServiceHandler* current = root_service_handler_head_;
- while (current != NULL) {
- if (strcmp(name, current->name()) == 0) {
- return current;
- }
- current = current->next();
- }
- return NULL;
-}
-
} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698