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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/service.h" 5 #include "vm/service.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 #include "platform/globals.h" 8 #include "platform/globals.h"
9 9
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
11 #include "vm/coverage.h" 11 #include "vm/coverage.h"
12 #include "vm/cpu.h" 12 #include "vm/cpu.h"
13 #include "vm/dart_api_impl.h" 13 #include "vm/dart_api_impl.h"
14 #include "vm/dart_entry.h" 14 #include "vm/dart_entry.h"
15 #include "vm/debugger.h" 15 #include "vm/debugger.h"
16 #include "vm/isolate.h" 16 #include "vm/isolate.h"
17 #include "vm/lockers.h" 17 #include "vm/lockers.h"
18 #include "vm/message.h" 18 #include "vm/message.h"
19 #include "vm/message_handler.h" 19 #include "vm/message_handler.h"
20 #include "vm/native_entry.h" 20 #include "vm/native_entry.h"
21 #include "vm/native_arguments.h" 21 #include "vm/native_arguments.h"
22 #include "vm/object.h" 22 #include "vm/object.h"
23 #include "vm/object_graph.h" 23 #include "vm/object_graph.h"
24 #include "vm/object_id_ring.h" 24 #include "vm/object_id_ring.h"
25 #include "vm/object_store.h" 25 #include "vm/object_store.h"
26 #include "vm/parser.h" 26 #include "vm/parser.h"
27 #include "vm/port.h" 27 #include "vm/port.h"
28 #include "vm/profiler_service.h" 28 #include "vm/profiler_service.h"
29 #include "vm/reusable_handles.h" 29 #include "vm/reusable_handles.h"
30 #include "vm/service_isolate.h"
30 #include "vm/stack_frame.h" 31 #include "vm/stack_frame.h"
31 #include "vm/symbols.h" 32 #include "vm/symbols.h"
32 #include "vm/unicode.h" 33 #include "vm/unicode.h"
33 #include "vm/version.h" 34 #include "vm/version.h"
34 35
35 namespace dart { 36 namespace dart {
36 37
37 DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests."); 38 DECLARE_FLAG(bool, trace_service);
38 DEFINE_FLAG(bool, trace_service_pause_events, false, 39 DECLARE_FLAG(bool, trace_service_pause_events);
39 "Trace VM service isolate pause events.");
40 DECLARE_FLAG(bool, enable_type_checks); 40 DECLARE_FLAG(bool, enable_type_checks);
41 DECLARE_FLAG(bool, enable_asserts); 41 DECLARE_FLAG(bool, enable_asserts);
42 42
43 struct ResourcesEntry { 43 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
44 const char* path_; 44 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.
45 const char* resource_; 45 uint32_t Service::event_mask_ = 0;
46 int length_; 46 struct ServiceMethodDescriptor;
47 ServiceMethodDescriptor* FindMethod(const char* method_name);
48
49 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
50 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
51 return reinterpret_cast<uint8_t*>(new_ptr);
52 }
53
54 static void PrintRequest(const JSONObject& obj, JSONStream* js) {
55 JSONObject jsobj(&obj, "request");
56 jsobj.AddProperty("method", js->method());
57 {
58 JSONArray jsarr(&jsobj, "param_keys");
59 for (intptr_t i = 0; i < js->num_params(); i++) {
60 jsarr.AddValue(js->GetParamKey(i));
61 }
62 }
63 {
64 JSONArray jsarr(&jsobj, "param_values");
65 for (intptr_t i = 0; i < js->num_params(); i++) {
66 jsarr.AddValue(js->GetParamValue(i));
67 }
68 }
69 }
70
71
72 static void PrintError(JSONStream* js,
73 const char* format, ...) {
74 Isolate* isolate = Isolate::Current();
75
76 va_list args;
77 va_start(args, format);
78 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
79 va_end(args);
80
81 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
82 va_list args2;
83 va_start(args2, format);
84 OS::VSNPrint(buffer, (len + 1), format, args2);
85 va_end(args2);
86
87 JSONObject jsobj(js);
88 jsobj.AddProperty("type", "Error");
89 jsobj.AddProperty("message", buffer);
90 PrintRequest(jsobj, js);
91 }
92
93
94 static void PrintMissingParamError(JSONStream* js,
95 const char* param) {
96 PrintError(js, "%s expects the '%s' parameter",
97 js->method(), param);
98 }
99
100
101 static void PrintInvalidParamError(JSONStream* js,
102 const char* param) {
103 PrintError(js, "%s: invalid '%s' parameter: %s",
104 js->method(), param, js->LookupParam(param));
105 }
106
107
108 static void PrintUnrecognizedMethodError(JSONStream* js) {
109 PrintError(js, "unrecognized method: %s", js->method());
110 }
111
112
113 static void PrintErrorWithKind(JSONStream* js,
114 const char* kind,
115 const char* format, ...) {
116 Isolate* isolate = Isolate::Current();
117
118 va_list args;
119 va_start(args, format);
120 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
121 va_end(args);
122
123 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
124 va_list args2;
125 va_start(args2, format);
126 OS::VSNPrint(buffer, (len + 1), format, args2);
127 va_end(args2);
128
129 JSONObject jsobj(js);
130 jsobj.AddProperty("type", "Error");
131 jsobj.AddProperty("id", "");
132 jsobj.AddProperty("kind", kind);
133 jsobj.AddProperty("message", buffer);
134 PrintRequest(jsobj, js);
135 }
136
137
138 static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
139 if ((s == NULL) || (*s == '\0')) {
140 // Empty string.
141 return false;
142 }
143 if (id == NULL) {
144 // No id pointer.
145 return false;
146 }
147 intptr_t r = 0;
148 char* end_ptr = NULL;
149 r = strtol(s, &end_ptr, base);
150 if (end_ptr == s) {
151 // String was not advanced at all, cannot be valid.
152 return false;
153 }
154 *id = r;
155 return true;
156 }
157
158
159 static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
160 if ((s == NULL) || (*s == '\0')) {
161 // Empty string.
162 return false;
163 }
164 if (id == NULL) {
165 // No id pointer.
166 return false;
167 }
168 uintptr_t r = 0;
169 char* end_ptr = NULL;
170 r = strtoul(s, &end_ptr, base);
171 if (end_ptr == s) {
172 // String was not advanced at all, cannot be valid.
173 return false;
174 }
175 *id = r;
176 return true;
177 }
178
179
180 static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
181 if ((s == NULL) || (*s == '\0')) {
182 // Empty string.
183 return false;
184 }
185 if (id == NULL) {
186 // No id pointer.
187 return false;
188 }
189 int64_t r = 0;
190 char* end_ptr = NULL;
191 r = strtoll(s, &end_ptr, base);
192 if (end_ptr == s) {
193 // String was not advanced at all, cannot be valid.
194 return false;
195 }
196 *id = r;
197 return true;
198 }
199
200
201 // Scans the string until the '-' character. Returns pointer to string
202 // at '-' character. Returns NULL if not found.
203 static const char* ScanUntilDash(const char* s) {
204 if ((s == NULL) || (*s == '\0')) {
205 // Empty string.
206 return NULL;
207 }
208 while (*s != '\0') {
209 if (*s == '-') {
210 return s;
211 }
212 s++;
213 }
214 return NULL;
215 }
216
217
218 static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
219 if ((s == NULL) || (*s == '\0')) {
220 // Empty string.
221 return false;
222 }
223 if ((timestamp == NULL) || (address == NULL)) {
224 // Bad arguments.
225 return false;
226 }
227 // Extract the timestamp.
228 if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
229 return false;
230 }
231 s = ScanUntilDash(s);
232 if (s == NULL) {
233 return false;
234 }
235 // Skip the dash.
236 s++;
237 // Extract the PC.
238 if (!GetUnsignedIntegerId(s, address, 16)) {
239 return false;
240 }
241 return true;
242 }
243
244
245 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.
246 public:
247 MethodParameter(const char* name, bool required)
248 : name_(name), required_(required) {
249 }
250
251 virtual ~MethodParameter() { }
252
253 virtual bool Validate(const char* value) const {
254 return true;
255 }
256
257 const char* name() const {
258 return name_;
259 }
260
261 bool required() const {
262 return required_;
263 }
264
265 private:
266 const char* name_;
267 bool required_;
47 }; 268 };
48 269
49 extern ResourcesEntry __service_resources_[]; 270
50 271 class BoolParameter : public MethodParameter {
51 class Resources {
52 public: 272 public:
53 static const int kNoSuchInstance = -1; 273 BoolParameter(const char* name, bool required)
54 static int ResourceLookup(const char* path, const char** resource) { 274 : MethodParameter(name, required) {
55 ResourcesEntry* table = ResourceTable(); 275 }
56 for (int i = 0; table[i].path_ != NULL; i++) { 276
57 const ResourcesEntry& entry = table[i]; 277 virtual bool Validate(const char* value) const {
58 if (strcmp(path, entry.path_) == 0) { 278 if (value == NULL) {
59 *resource = entry.resource_; 279 return false;
60 ASSERT(entry.length_ > 0); 280 }
61 return entry.length_; 281 return (strcmp("true", value) == 0) || (strcmp("false", value) == 0);
282 }
283
284 static bool Interpret(const char* value) {
285 return strcmp("true", value) == 0;
286 }
287 };
288
289
290 class IdParameter : public MethodParameter {
291 public:
292 IdParameter(const char* name, bool required)
293 : MethodParameter(name, required) {
294 }
295
296 virtual bool Validate(const char* value) const {
297 return (value != NULL);
298 }
299 };
300
301
302 #define ISOLATE_PARAMETER new IdParameter("isolateId", true)
303
304
305 class EnumParameter : public MethodParameter {
306 public:
307 EnumParameter(const char* name, bool required, const char** enums)
308 : MethodParameter(name, required),
309 enums_(enums) {
310 }
311
312 virtual bool Validate(const char* value) const {
313 if (value == NULL) {
314 return true;
315 }
316 for (intptr_t i = 0; enums_[i] != NULL; i++) {
317 if (strcmp(value, enums_[i]) == 0) {
318 return true;
62 } 319 }
63 } 320 }
64 return kNoSuchInstance; 321 return false;
65 }
66
67 static const char* Path(int idx) {
68 ASSERT(idx >= 0);
69 ResourcesEntry* entry = At(idx);
70 if (entry == NULL) {
71 return NULL;
72 }
73 ASSERT(entry->path_ != NULL);
74 return entry->path_;
75 }
76
77 static int Length(int idx) {
78 ASSERT(idx >= 0);
79 ResourcesEntry* entry = At(idx);
80 if (entry == NULL) {
81 return kNoSuchInstance;
82 }
83 ASSERT(entry->path_ != NULL);
84 return entry->length_;
85 }
86
87 static const uint8_t* Resource(int idx) {
88 ASSERT(idx >= 0);
89 ResourcesEntry* entry = At(idx);
90 if (entry == NULL) {
91 return NULL;
92 }
93 return reinterpret_cast<const uint8_t*>(entry->resource_);
94 } 322 }
95 323
96 private: 324 private:
97 static ResourcesEntry* At(int idx) { 325 const char** enums_;
98 ASSERT(idx >= 0); 326 };
99 ResourcesEntry* table = ResourceTable(); 327
100 for (int i = 0; table[i].path_ != NULL; i++) { 328
101 if (idx == i) { 329 // If the key is not found, this function returns the last element in the
102 return &table[i]; 330 // values array. This can be used to encode the default value.
331 template<typename T>
332 T EnumMapper(const char* value, const char** enums, T* values) {
333 ASSERT(value != NULL);
334 intptr_t i = 0;
335 for (i = 0; enums[i] != NULL; i++) {
336 if (strcmp(value, enums[i]) == 0) {
337 return values[i];
338 }
339 }
340 // Default value.
341 return values[i];
342 }
343
344
345 typedef bool (*ServiceMethodEntry)(Isolate* isolate, JSONStream* js);
346
347
348 struct ServiceMethodDescriptor {
349 const char* name;
350 const ServiceMethodEntry entry;
351 const MethodParameter* const * parameters;
352 };
353
354
355 static bool ValidateParameters(const MethodParameter* const* parameters,
356 JSONStream* js) {
357 if (parameters == NULL) {
358 return true;
359 }
360 for (intptr_t i = 0; parameters[i] != NULL; i++) {
361 const MethodParameter* parameter = parameters[i];
362 const char* name = parameter->name();
363 const bool required = parameter->required();
364 const char* value = js->LookupParam(name);
365 const bool has_parameter = (value != NULL);
366 if (required && !has_parameter) {
367 PrintMissingParamError(js, name);
368 return false;
369 }
370 if (!parameter->Validate(value)) {
371 PrintInvalidParamError(js, name);
372 return false;
373 }
374 }
turnidge 2015/02/12 18:08:57 We don't complain about unexpected extra parameter
375 return true;
376 }
377
378
379 void Service::InvokeMethod(Isolate* isolate, const Array& msg) {
380 ASSERT(isolate != NULL);
381 ASSERT(!msg.IsNull());
382 ASSERT(msg.Length() == 5);
383
384 {
385 StackZone zone(isolate);
386 HANDLESCOPE(isolate);
387
388 Instance& reply_port = Instance::Handle(isolate);
389 String& method_name = String::Handle(isolate);
390 Array& param_keys = Array::Handle(isolate);
391 Array& param_values = Array::Handle(isolate);
392 reply_port ^= msg.At(1);
393 method_name ^= msg.At(2);
394 param_keys ^= msg.At(3);
395 param_values ^= msg.At(4);
396
397 ASSERT(!method_name.IsNull());
398 ASSERT(!param_keys.IsNull());
399 ASSERT(!param_values.IsNull());
400 ASSERT(param_keys.Length() == param_values.Length());
401
402 if (!reply_port.IsSendPort()) {
403 FATAL("SendPort expected.");
404 }
405
406 JSONStream js;
407 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
408 method_name, param_keys, param_values);
409
410 const char* c_method_name = method_name.ToCString();
411
412 ServiceMethodDescriptor* method = FindMethod(c_method_name);
413 if (method != NULL) {
414 if (!ValidateParameters(method->parameters, &js)) {
415 js.PostReply();
416 return;
103 } 417 }
104 } 418 if (method->entry(isolate, &js)) {
105 return NULL; 419 js.PostReply();
106 } 420 }
107 421 return;
108 static ResourcesEntry* ResourceTable() { 422 }
109 return &__service_resources_[0]; 423
110 } 424 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(c_method_name);
111 425 if (handler == NULL) {
112 DISALLOW_ALLOCATION(); 426 handler = FindRootEmbedderHandler(c_method_name);
113 DISALLOW_IMPLICIT_CONSTRUCTORS(Resources); 427 }
114 }; 428
429 if (handler != NULL) {
430 EmbedderHandleMessage(handler, &js);
431 js.PostReply();
432 return;
433 }
434
435 PrintUnrecognizedMethodError(&js);
436 js.PostReply();
437 return;
438 }
439 }
440
441
442 void Service::HandleRootMessage(const Array& msg_instance) {
443 Isolate* isolate = Isolate::Current();
444 InvokeMethod(isolate, msg_instance);
445 }
446
447
448 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
449 ASSERT(isolate != NULL);
450 InvokeMethod(isolate, msg);
451 }
452
453
454 bool Service::EventMaskHas(uint32_t mask) {
455 return (event_mask_ & mask) != 0;
456 }
457
458
459 bool Service::NeedsDebuggerEvents() {
460 return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyDebugMask);
461 }
462
463
464 bool Service::NeedsGCEvents() {
465 return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyGCMask);
466 }
467
468
469 void Service::SetEventMask(uint32_t mask) {
470 event_mask_ = mask;
471 }
472
473
474 void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
475 if (!ServiceIsolate::IsRunning()) {
476 return;
477 }
478 Isolate* isolate = Isolate::Current();
479 ASSERT(isolate != NULL);
480 HANDLESCOPE(isolate);
481
482 // Construct a list of the form [eventId, eventMessage].
483 const Array& list = Array::Handle(Array::New(2));
484 ASSERT(!list.IsNull());
485 list.SetAt(0, Integer::Handle(Integer::New(eventId)));
486 list.SetAt(1, eventMessage);
487
488 // Push the event to port_.
489 uint8_t* data = NULL;
490 MessageWriter writer(&data, &allocator, false);
491 writer.WriteMessage(list);
492 intptr_t len = writer.BytesWritten();
493 if (FLAG_trace_service) {
494 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
495 eventId, len);
496 }
497 // TODO(turnidge): For now we ignore failure to send an event. Revisit?
498 PortMap::PostMessage(
499 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority));
500 }
501
502
503 void Service::SendEvent(intptr_t eventId,
504 const String& meta,
505 const uint8_t* data,
506 intptr_t size) {
507 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
508 const intptr_t meta_bytes = Utf8::Length(meta);
509 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
510 const TypedData& message = TypedData::Handle(
511 TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
512 intptr_t offset = 0;
513 // TODO(koda): Rename these methods SetHostUint64, etc.
514 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
515 offset += sizeof(uint64_t);
516 {
517 NoGCScope no_gc;
518 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
519 offset += meta_bytes;
520 }
521 // TODO(koda): It would be nice to avoid this copy (requires changes to
522 // MessageWriter code).
523 {
524 NoGCScope no_gc;
525 memmove(message.DataAddr(offset), data, size);
526 offset += size;
527 }
528 ASSERT(offset == total_bytes);
529 SendEvent(eventId, message);
530 }
531
532
533 void Service::HandleGCEvent(GCEvent* event) {
534 JSONStream js;
535 event->PrintJSON(&js);
536 const String& message = String::Handle(String::New(js.ToCString()));
537 SendEvent(kEventFamilyGC, message);
538 }
539
540
541 void Service::HandleDebuggerEvent(DebuggerEvent* event) {
542 JSONStream js;
543 event->PrintJSON(&js);
544 const String& message = String::Handle(String::New(js.ToCString()));
545 SendEvent(kEventFamilyDebug, message);
546 }
115 547
116 548
117 class EmbedderServiceHandler { 549 class EmbedderServiceHandler {
118 public: 550 public:
119 explicit EmbedderServiceHandler(const char* name) : name_(NULL), 551 explicit EmbedderServiceHandler(const char* name) : name_(NULL),
120 callback_(NULL), 552 callback_(NULL),
121 user_data_(NULL), 553 user_data_(NULL),
122 next_(NULL) { 554 next_(NULL) {
123 ASSERT(name != NULL); 555 ASSERT(name != NULL);
124 name_ = strdup(name); 556 name_ = strdup(name);
(...skipping 21 matching lines...) Expand all
146 } 578 }
147 579
148 private: 580 private:
149 char* name_; 581 char* name_;
150 Dart_ServiceRequestCallback callback_; 582 Dart_ServiceRequestCallback callback_;
151 void* user_data_; 583 void* user_data_;
152 EmbedderServiceHandler* next_; 584 EmbedderServiceHandler* next_;
153 }; 585 };
154 586
155 587
156 class LibraryCoverageFilter : public CoverageFilter { 588 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
157 public: 589 JSONStream* js) {
158 explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {} 590 ASSERT(handler != NULL);
159 bool ShouldOutputCoverageFor(const Library& lib, 591 Dart_ServiceRequestCallback callback = handler->callback();
160 const Script& script, 592 ASSERT(callback != NULL);
161 const Class& cls, 593 const char* r = NULL;
162 const Function& func) const { 594 const char* name = js->method();
163 return lib.raw() == lib_.raw(); 595 const char** keys = js->param_keys();
164 } 596 const char** values = js->param_values();
165 private: 597 r = callback(name, keys, values, js->num_params(), handler->user_data());
166 const Library& lib_; 598 ASSERT(r != NULL);
167 }; 599 // TODO(johnmccutchan): Allow for NULL returns?
168 600 TextBuffer* buffer = js->buffer();
169 601 buffer->AddString(r);
170 class ScriptCoverageFilter : public CoverageFilter { 602 free(const_cast<char*>(r));
171 public: 603 }
172 explicit ScriptCoverageFilter(const Script& script) 604
173 : script_(script) {} 605
174 bool ShouldOutputCoverageFor(const Library& lib, 606 void Service::RegisterIsolateEmbedderCallback(
175 const Script& script, 607 const char* name,
176 const Class& cls, 608 Dart_ServiceRequestCallback callback,
177 const Function& func) const { 609 void* user_data) {
178 return script.raw() == script_.raw(); 610 if (name == NULL) {
179 } 611 return;
180 private: 612 }
181 const Script& script_; 613 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
182 }; 614 if (handler != NULL) {
183 615 // Update existing handler entry.
184 616 handler->set_callback(callback);
185 class ClassCoverageFilter : public CoverageFilter { 617 handler->set_user_data(user_data);
186 public: 618 return;
187 explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {} 619 }
188 bool ShouldOutputCoverageFor(const Library& lib, 620 // Create a new handler.
189 const Script& script, 621 handler = new EmbedderServiceHandler(name);
190 const Class& cls, 622 handler->set_callback(callback);
191 const Function& func) const { 623 handler->set_user_data(user_data);
192 return cls.raw() == cls_.raw(); 624
193 } 625 // Insert into isolate_service_handler_head_ list.
194 private: 626 handler->set_next(isolate_service_handler_head_);
195 const Class& cls_; 627 isolate_service_handler_head_ = handler;
196 }; 628 }
197 629
198 630
199 class FunctionCoverageFilter : public CoverageFilter { 631 EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
200 public: 632 const char* name) {
201 explicit FunctionCoverageFilter(const Function& func) : func_(func) {} 633 EmbedderServiceHandler* current = isolate_service_handler_head_;
202 bool ShouldOutputCoverageFor(const Library& lib, 634 while (current != NULL) {
203 const Script& script, 635 if (strcmp(name, current->name()) == 0) {
204 const Class& cls, 636 return current;
205 const Function& func) const { 637 }
206 return func.raw() == func_.raw(); 638 current = current->next();
207 }
208 private:
209 const Function& func_;
210 };
211
212
213 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
214 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
215 return reinterpret_cast<uint8_t*>(new_ptr);
216 }
217
218
219 static void SendIsolateServiceMessage(Dart_NativeArguments args) {
220 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
221 Isolate* isolate = arguments->isolate();
222 StackZone zone(isolate);
223 HANDLESCOPE(isolate);
224 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
225 GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
226
227 // Set the type of the OOB message.
228 message.SetAt(0, Smi::Handle(isolate, Smi::New(Message::kServiceOOBMsg)));
229
230 // Serialize message.
231 uint8_t* data = NULL;
232 MessageWriter writer(&data, &allocator, false);
233 writer.WriteMessage(message);
234
235 // TODO(turnidge): Throw an exception when the return value is false?
236 PortMap::PostMessage(new Message(sp.Id(), data, writer.BytesWritten(),
237 Message::kOOBPriority));
238 }
239
240
241 static void SendRootServiceMessage(Dart_NativeArguments args) {
242 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
243 Isolate* isolate = arguments->isolate();
244 StackZone zone(isolate);
245 HANDLESCOPE(isolate);
246 GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(0));
247 Service::HandleRootMessage(message);
248 }
249
250
251 class ScopeStopwatch : public ValueObject {
252 public:
253 explicit ScopeStopwatch(const char* name) : name_(name) {
254 start_ = OS::GetCurrentTimeMicros();
255 }
256
257 int64_t GetElapsed() const {
258 int64_t end = OS::GetCurrentTimeMicros();
259 ASSERT(end >= start_);
260 return end - start_;
261 }
262
263 ~ScopeStopwatch() {
264 int64_t elapsed = GetElapsed();
265 OS::Print("[%" Pd "] %s took %" Pd64 " micros.\n",
266 OS::ProcessId(), name_, elapsed);
267 }
268
269 private:
270 const char* name_;
271 int64_t start_;
272 };
273
274
275 bool Service::IsRunning() {
276 MonitorLocker ml(monitor_);
277 return (service_port_ != ILLEGAL_PORT) && (service_isolate_ != NULL);
278 }
279
280
281 void Service::SetServicePort(Dart_Port port) {
282 MonitorLocker ml(monitor_);
283 service_port_ = port;
284 }
285
286
287 void Service::SetServiceIsolate(Isolate* isolate) {
288 MonitorLocker ml(monitor_);
289 service_isolate_ = isolate;
290 if (service_isolate_ != NULL) {
291 service_isolate_->is_service_isolate_ = true;
292 }
293 }
294
295
296 bool Service::HasServiceIsolate() {
297 MonitorLocker ml(monitor_);
298 return service_isolate_ != NULL;
299 }
300
301
302 bool Service::IsServiceIsolate(Isolate* isolate) {
303 MonitorLocker ml(monitor_);
304 return isolate == service_isolate_;
305 }
306
307 Dart_Port Service::WaitForLoadPort() {
308 MonitorLocker ml(monitor_);
309
310 while (initializing_ && (load_port_ == ILLEGAL_PORT)) {
311 ml.Wait();
312 }
313
314 return load_port_;
315 }
316
317
318 Dart_Port Service::LoadPort() {
319 MonitorLocker ml(monitor_);
320 return load_port_;
321 }
322
323
324 void Service::SetLoadPort(Dart_Port port) {
325 MonitorLocker ml(monitor_);
326 load_port_ = port;
327 }
328
329
330 void Service::SetEventMask(uint32_t mask) {
331 event_mask_ = mask;
332 }
333
334
335 static void SetEventMask(Dart_NativeArguments args) {
336 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
337 Isolate* isolate = arguments->isolate();
338 StackZone zone(isolate);
339 HANDLESCOPE(isolate);
340 GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(0));
341 Service::SetEventMask(mask.AsTruncatedUint32Value());
342 }
343
344
345 // These must be kept in sync with service/constants.dart
346 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
347 #define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
348
349
350 static RawArray* MakeServiceControlMessage(Dart_Port port_id, intptr_t code,
351 const String& name) {
352 const Array& list = Array::Handle(Array::New(4));
353 ASSERT(!list.IsNull());
354 const Integer& code_int = Integer::Handle(Integer::New(code));
355 const Integer& port_int = Integer::Handle(Integer::New(port_id));
356 const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
357 list.SetAt(0, code_int);
358 list.SetAt(1, port_int);
359 list.SetAt(2, send_port);
360 list.SetAt(3, name);
361 return list.raw();
362 }
363
364
365 class RegisterRunningIsolatesVisitor : public IsolateVisitor {
366 public:
367 explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
368 : IsolateVisitor(),
369 register_function_(Function::Handle(service_isolate)),
370 service_isolate_(service_isolate) {
371 ASSERT(Service::IsServiceIsolate(Isolate::Current()));
372 // Get library.
373 const String& library_url = Symbols::DartVMService();
374 ASSERT(!library_url.IsNull());
375 const Library& library =
376 Library::Handle(Library::LookupLibrary(library_url));
377 ASSERT(!library.IsNull());
378 // Get function.
379 const String& function_name =
380 String::Handle(String::New("_registerIsolate"));
381 ASSERT(!function_name.IsNull());
382 register_function_ = library.LookupFunctionAllowPrivate(function_name);
383 ASSERT(!register_function_.IsNull());
384 }
385
386 virtual void VisitIsolate(Isolate* isolate) {
387 ASSERT(Service::IsServiceIsolate(Isolate::Current()));
388 if (Service::IsServiceIsolate(isolate) ||
389 (isolate == Dart::vm_isolate())) {
390 // We do not register the service or vm isolate.
391 return;
392 }
393 // Setup arguments for call.
394 Dart_Port port_id = isolate->main_port();
395 const Integer& port_int = Integer::Handle(Integer::New(port_id));
396 ASSERT(!port_int.IsNull());
397 const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
398 const String& name = String::Handle(String::New(isolate->name()));
399 ASSERT(!name.IsNull());
400 const Array& args = Array::Handle(Array::New(3));
401 ASSERT(!args.IsNull());
402 args.SetAt(0, port_int);
403 args.SetAt(1, send_port);
404 args.SetAt(2, name);
405 Object& r = Object::Handle(service_isolate_);
406 r = DartEntry::InvokeFunction(register_function_, args);
407 if (FLAG_trace_service) {
408 OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
409 name.ToCString(),
410 port_id);
411 }
412 ASSERT(!r.IsError());
413 }
414
415 private:
416 Function& register_function_;
417 Isolate* service_isolate_;
418 };
419
420
421 static Dart_Port ExtractPort(Isolate* isolate, Dart_Handle receivePort) {
422 const ReceivePort& rp = Api::UnwrapReceivePortHandle(isolate, receivePort);
423 if (rp.IsNull()) {
424 return ILLEGAL_PORT;
425 }
426 return rp.Id();
427 }
428
429
430 static void OnStart(Dart_NativeArguments args) {
431 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
432 Isolate* isolate = arguments->isolate();
433 StackZone zone(isolate);
434 HANDLESCOPE(isolate);
435 {
436 if (FLAG_trace_service) {
437 OS::Print("vm-service: Booting dart:vmservice library.\n");
438 }
439 // Boot the dart:vmservice library.
440 Dart_EnterScope();
441 Dart_Handle url_str =
442 Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId));
443 Dart_Handle library = Dart_LookupLibrary(url_str);
444 ASSERT(Dart_IsLibrary(library));
445 Dart_Handle result =
446 Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL);
447 ASSERT(!Dart_IsError(result));
448 Dart_Port port = ExtractPort(isolate, result);
449 ASSERT(port != ILLEGAL_PORT);
450 Service::SetServicePort(port);
451 Dart_ExitScope();
452 }
453
454 {
455 if (FLAG_trace_service) {
456 OS::Print("vm-service: Registering running isolates.\n");
457 }
458 // Register running isolates with service.
459 RegisterRunningIsolatesVisitor register_isolates(isolate);
460 Isolate::VisitIsolates(&register_isolates);
461 }
462 }
463
464
465 struct VmServiceNativeEntry {
466 const char* name;
467 int num_arguments;
468 Dart_NativeFunction function;
469 };
470
471
472 static VmServiceNativeEntry _VmServiceNativeEntries[] = {
473 {"VMService_SendIsolateServiceMessage", 2, SendIsolateServiceMessage},
474 {"VMService_SendRootServiceMessage", 1, SendRootServiceMessage},
475 {"VMService_SetEventMask", 1, SetEventMask},
476 {"VMService_OnStart", 0, OnStart },
477 };
478
479
480 static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
481 int num_arguments,
482 bool* auto_setup_scope) {
483 const Object& obj = Object::Handle(Api::UnwrapHandle(name));
484 if (!obj.IsString()) {
485 return NULL;
486 }
487 const char* function_name = obj.ToCString();
488 ASSERT(function_name != NULL);
489 ASSERT(auto_setup_scope != NULL);
490 *auto_setup_scope = true;
491 intptr_t n =
492 sizeof(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]);
493 for (intptr_t i = 0; i < n; i++) {
494 VmServiceNativeEntry entry = _VmServiceNativeEntries[i];
495 if ((strcmp(function_name, entry.name) == 0) &&
496 (num_arguments == entry.num_arguments)) {
497 return entry.function;
498 }
499 } 639 }
500 return NULL; 640 return NULL;
501 } 641 }
502 642
503 const char* Service::kIsolateName = "vm-service"; 643
504 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; 644 void Service::RegisterRootEmbedderCallback(
505 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; 645 const char* name,
506 Isolate* Service::service_isolate_ = NULL; 646 Dart_ServiceRequestCallback callback,
507 Dart_Port Service::service_port_ = ILLEGAL_PORT; 647 void* user_data) {
508 Dart_Port Service::load_port_ = ILLEGAL_PORT; 648 if (name == NULL) {
509 Dart_IsolateCreateCallback Service::create_callback_ = NULL;
510 Monitor* Service::monitor_ = NULL;
511 bool Service::initializing_ = true;
512 uint32_t Service::event_mask_ = 0;
513
514
515 bool Service::IsServiceIsolateName(const char* name) {
516 ASSERT(name != NULL);
517 return strcmp(name, kIsolateName) == 0;
518 }
519
520
521 bool Service::SendIsolateStartupMessage() {
522 if (!IsRunning()) {
523 return false;
524 }
525 Isolate* isolate = Isolate::Current();
526 if (IsServiceIsolate(isolate)) {
527 return false;
528 }
529 ASSERT(isolate != NULL);
530 HANDLESCOPE(isolate);
531 const String& name = String::Handle(String::New(isolate->name()));
532 ASSERT(!name.IsNull());
533 const Array& list = Array::Handle(
534 MakeServiceControlMessage(Dart_GetMainPortId(),
535 VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID,
536 name));
537 ASSERT(!list.IsNull());
538 uint8_t* data = NULL;
539 MessageWriter writer(&data, &allocator, false);
540 writer.WriteMessage(list);
541 intptr_t len = writer.BytesWritten();
542 if (FLAG_trace_service) {
543 OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
544 name.ToCString(),
545 Dart_GetMainPortId());
546 }
547 return PortMap::PostMessage(
548 new Message(service_port_, data, len, Message::kNormalPriority));
549 }
550
551
552 bool Service::SendIsolateShutdownMessage() {
553 if (!IsRunning()) {
554 return false;
555 }
556 Isolate* isolate = Isolate::Current();
557 if (IsServiceIsolate(isolate)) {
558 return false;
559 }
560 ASSERT(isolate != NULL);
561 HANDLESCOPE(isolate);
562 const String& name = String::Handle(String::New(isolate->name()));
563 ASSERT(!name.IsNull());
564 const Array& list = Array::Handle(
565 MakeServiceControlMessage(Dart_GetMainPortId(),
566 VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID,
567 name));
568 ASSERT(!list.IsNull());
569 uint8_t* data = NULL;
570 MessageWriter writer(&data, &allocator, false);
571 writer.WriteMessage(list);
572 intptr_t len = writer.BytesWritten();
573 if (FLAG_trace_service) {
574 OS::Print("vm-service: Isolate %s %" Pd64 " deregistered.\n",
575 name.ToCString(),
576 Dart_GetMainPortId());
577 }
578 return PortMap::PostMessage(
579 new Message(service_port_, data, len, Message::kNormalPriority));
580 }
581
582
583 Dart_Handle Service::GetSource(const char* name) {
584 ASSERT(name != NULL);
585 int i = 0;
586 while (true) {
587 const char* path = Resources::Path(i);
588 if (path == NULL) {
589 break;
590 }
591 ASSERT(*path != '\0');
592 // Skip the '/'.
593 path++;
594 if (strcmp(name, path) == 0) {
595 const uint8_t* str = Resources::Resource(i);
596 intptr_t length = Resources::Length(i);
597 return Dart_NewStringFromUTF8(str, length);
598 }
599 i++;
600 }
601 return Dart_Null();
602 }
603
604
605 Dart_Handle Service::LibraryTagHandler(Dart_LibraryTag tag,
606 Dart_Handle library,
607 Dart_Handle url) {
608 if (tag == Dart_kCanonicalizeUrl) {
609 // url is already canonicalized.
610 return url;
611 }
612 if (tag != Dart_kSourceTag) {
613 FATAL("Service::LibraryTagHandler encountered an unexpected tag.");
614 }
615 ASSERT(tag == Dart_kSourceTag);
616 const char* url_string = NULL;
617 Dart_Handle result = Dart_StringToCString(url, &url_string);
618 if (Dart_IsError(result)) {
619 return result;
620 }
621 Dart_Handle source = GetSource(url_string);
622 if (Dart_IsError(source)) {
623 return source;
624 }
625 return Dart_LoadSource(library, url, source, 0, 0);
626 }
627
628
629 void Service::MaybeInjectVMServiceLibrary(Isolate* isolate) {
630 ASSERT(isolate != NULL);
631 ASSERT(isolate->name() != NULL);
632 if (!Service::IsServiceIsolateName(isolate->name())) {
633 // Not service isolate.
634 return; 649 return;
635 } 650 }
636 if (HasServiceIsolate()) { 651 EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
637 // Service isolate already exists. 652 if (handler != NULL) {
653 // Update existing handler entry.
654 handler->set_callback(callback);
655 handler->set_user_data(user_data);
638 return; 656 return;
639 } 657 }
640 SetServiceIsolate(isolate); 658 // Create a new handler.
641 659 handler = new EmbedderServiceHandler(name);
642 StackZone zone(isolate); 660 handler->set_callback(callback);
643 HANDLESCOPE(isolate); 661 handler->set_user_data(user_data);
644 662
645 // Register dart:vmservice library. 663 // Insert into root_service_handler_head_ list.
646 const String& url_str = String::Handle(Symbols::DartVMService().raw()); 664 handler->set_next(root_service_handler_head_);
647 const Library& library = Library::Handle(Library::New(url_str)); 665 root_service_handler_head_ = handler;
648 library.Register(); 666 }
649 library.set_native_entry_resolver(VmServiceNativeResolver); 667
650 668
651 // Temporarily install our library tag handler. 669 EmbedderServiceHandler* Service::FindRootEmbedderHandler(
652 isolate->set_library_tag_handler(LibraryTagHandler); 670 const char* name) {
653 671 EmbedderServiceHandler* current = root_service_handler_head_;
654 // Get script source. 672 while (current != NULL) {
655 const char* resource = NULL; 673 if (strcmp(name, current->name()) == 0) {
656 const char* path = "/vmservice.dart"; 674 return current;
657 intptr_t r = Resources::ResourceLookup(path, &resource); 675 }
658 ASSERT(r != Resources::kNoSuchInstance); 676 current = current->next();
659 ASSERT(resource != NULL); 677 }
660 const String& source_str = String::Handle( 678 return NULL;
661 String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r)); 679 }
662 ASSERT(!source_str.IsNull()); 680
663 const Script& script = Script::Handle( 681
664 isolate, Script::New(url_str, source_str, RawScript::kLibraryTag));
665
666 // Compile script.
667 Dart_EnterScope(); // Need to enter scope for tag handler.
668 library.SetLoadInProgress();
669 const Error& error = Error::Handle(isolate,
670 Compiler::Compile(library, script));
671 ASSERT(error.IsNull());
672 Dart_Handle result = Dart_FinalizeLoading(false);
673 ASSERT(!Dart_IsError(result));
674 Dart_ExitScope();
675
676 // Uninstall our library tag handler.
677 isolate->set_library_tag_handler(NULL);
678 }
679
680
681 void Service::FinishedInitializing() {
682 MonitorLocker ml(monitor_);
683 initializing_ = false;
684 ml.NotifyAll();
685 }
686
687
688 static void ShutdownIsolate(uword parameter) {
689 Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
690 ASSERT(Service::IsServiceIsolate(isolate));
691 {
692 // Print the error if there is one. This may execute dart code to
693 // print the exception object, so we need to use a StartIsolateScope.
694 StartIsolateScope start_scope(isolate);
695 StackZone zone(isolate);
696 HandleScope handle_scope(isolate);
697 Error& error = Error::Handle();
698 error = isolate->object_store()->sticky_error();
699 if (!error.IsNull()) {
700 OS::PrintErr("vm-service: Error: %s\n", error.ToErrorCString());
701 }
702 Dart::RunShutdownCallback();
703 }
704 {
705 // Shut the isolate down.
706 SwitchIsolateScope switch_scope(isolate);
707 Dart::ShutdownIsolate();
708 }
709 Service::SetServiceIsolate(NULL);
710 Service::SetServicePort(ILLEGAL_PORT);
711 if (FLAG_trace_service) {
712 OS::Print("vm-service: Shutdown.\n");
713 }
714 }
715
716
717 class RunServiceTask : public ThreadPool::Task {
718 public:
719 virtual void Run() {
720 ASSERT(Isolate::Current() == NULL);
721 char* error = NULL;
722 Isolate* isolate = NULL;
723
724 Dart_IsolateCreateCallback create_callback = Service::create_callback();
725 // TODO(johnmccutchan): Support starting up service isolate without embedder
726 // provided isolate creation callback.
727 if (create_callback == NULL) {
728 Service::FinishedInitializing();
729 return;
730 }
731
732 isolate =
733 reinterpret_cast<Isolate*>(create_callback(Service::kIsolateName,
734 NULL,
735 NULL,
736 NULL,
737 &error));
738 if (isolate == NULL) {
739 OS::PrintErr("vm-service: Isolate creation error: %s\n", error);
740 Service::FinishedInitializing();
741 return;
742 }
743
744 Isolate::SetCurrent(NULL);
745
746 RunMain(isolate);
747
748 Service::FinishedInitializing();
749
750 isolate->message_handler()->Run(Dart::thread_pool(),
751 NULL,
752 ShutdownIsolate,
753 reinterpret_cast<uword>(isolate));
754 }
755
756 protected:
757 void RunMain(Isolate* isolate) {
758 StartIsolateScope iso_scope(isolate);
759 StackZone zone(isolate);
760 HANDLESCOPE(isolate);
761 // Invoke main which will return the loadScriptPort.
762 const Library& root_library =
763 Library::Handle(isolate, isolate->object_store()->root_library());
764 if (root_library.IsNull()) {
765 if (FLAG_trace_service) {
766 OS::Print("vm-service: Embedder did not install a script.");
767 }
768 // Service isolate is not supported by embedder.
769 return;
770 }
771 ASSERT(!root_library.IsNull());
772 const String& entry_name = String::Handle(isolate, String::New("main"));
773 ASSERT(!entry_name.IsNull());
774 const Function& entry =
775 Function::Handle(isolate,
776 root_library.LookupFunctionAllowPrivate(entry_name));
777 if (entry.IsNull()) {
778 // Service isolate is not supported by embedder.
779 if (FLAG_trace_service) {
780 OS::Print("vm-service: Embedder did not provide a main function.");
781 }
782 return;
783 }
784 ASSERT(!entry.IsNull());
785 const Object& result =
786 Object::Handle(isolate,
787 DartEntry::InvokeFunction(entry,
788 Object::empty_array()));
789 ASSERT(!result.IsNull());
790 if (result.IsError()) {
791 // Service isolate did not initialize properly.
792 if (FLAG_trace_service) {
793 const Error& error = Error::Cast(result);
794 OS::Print("vm-service: Calling main resulted in an error: %s",
795 error.ToErrorCString());
796 }
797 return;
798 }
799 ASSERT(result.IsReceivePort());
800 const ReceivePort& rp = ReceivePort::Cast(result);
801 Service::SetLoadPort(rp.Id());
802 }
803 };
804
805
806 void Service::RunService() {
807 ASSERT(monitor_ == NULL);
808 monitor_ = new Monitor();
809 ASSERT(monitor_ != NULL);
810 // Grab the isolate create callback here to avoid race conditions with tests
811 // that change this after Dart_Initialize returns.
812 create_callback_ = Isolate::CreateCallback();
813 Dart::thread_pool()->Run(new RunServiceTask());
814 }
815
816 // A handler for a per-isolate request.
817 //
818 // If a handler returns true, the reply is complete and ready to be
819 // posted. If a handler returns false, then it is responsible for
820 // posting the reply (this can be used for asynchronous delegation of
821 // the response handling).
822 typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
823
824 struct IsolateMessageHandlerEntry {
825 const char* method;
826 IsolateMessageHandler handler;
827 };
828
829 static IsolateMessageHandler FindIsolateMessageHandler(const char* method);
830
831
832 // A handler for a root (vm-global) request.
833 //
834 // If a handler returns true, the reply is complete and ready to be
835 // posted. If a handler returns false, then it is responsible for
836 // posting the reply (this can be used for asynchronous delegation of
837 // the response handling).
838 typedef bool (*RootMessageHandler)(JSONStream* stream);
839
840 struct RootMessageHandlerEntry {
841 const char* method;
842 RootMessageHandler handler;
843 };
844
845 static RootMessageHandler FindRootMessageHandler(const char* method);
846
847
848 static void PrintRequest(const JSONObject& obj, JSONStream* js) {
849 JSONObject jsobj(&obj, "request");
850 jsobj.AddProperty("method", js->method());
851 {
852 JSONArray jsarr(&jsobj, "param_keys");
853 for (intptr_t i = 0; i < js->num_params(); i++) {
854 jsarr.AddValue(js->GetParamKey(i));
855 }
856 }
857 {
858 JSONArray jsarr(&jsobj, "param_values");
859 for (intptr_t i = 0; i < js->num_params(); i++) {
860 jsarr.AddValue(js->GetParamValue(i));
861 }
862 }
863 }
864
865
866 static void PrintError(JSONStream* js,
867 const char* format, ...) {
868 Isolate* isolate = Isolate::Current();
869
870 va_list args;
871 va_start(args, format);
872 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
873 va_end(args);
874
875 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
876 va_list args2;
877 va_start(args2, format);
878 OS::VSNPrint(buffer, (len + 1), format, args2);
879 va_end(args2);
880
881 JSONObject jsobj(js);
882 jsobj.AddProperty("type", "Error");
883 jsobj.AddProperty("message", buffer);
884 PrintRequest(jsobj, js);
885 }
886
887
888 static void PrintMissingParamError(JSONStream* js,
889 const char* param) {
890 PrintError(js, "%s expects the '%s' parameter",
891 js->method(), param);
892 }
893
894
895 static void PrintInvalidParamError(JSONStream* js,
896 const char* param) {
897 PrintError(js, "%s: invalid '%s' parameter: %s",
898 js->method(), param, js->LookupParam(param));
899 }
900
901
902 static void PrintErrorWithKind(JSONStream* js,
903 const char* kind,
904 const char* format, ...) {
905 Isolate* isolate = Isolate::Current();
906
907 va_list args;
908 va_start(args, format);
909 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
910 va_end(args);
911
912 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
913 va_list args2;
914 va_start(args2, format);
915 OS::VSNPrint(buffer, (len + 1), format, args2);
916 va_end(args2);
917
918 JSONObject jsobj(js);
919 jsobj.AddProperty("type", "Error");
920 jsobj.AddProperty("id", "");
921 jsobj.AddProperty("kind", kind);
922 jsobj.AddProperty("message", buffer);
923 PrintRequest(jsobj, js);
924 }
925
926
927 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
928 ASSERT(isolate != NULL);
929 ASSERT(!msg.IsNull());
930 ASSERT(msg.Length() == 5);
931
932 {
933 StackZone zone(isolate);
934 HANDLESCOPE(isolate);
935
936 Instance& reply_port = Instance::Handle(isolate);
937 String& method = String::Handle(isolate);
938 Array& param_keys = Array::Handle(isolate);
939 Array& param_values = Array::Handle(isolate);
940 reply_port ^= msg.At(1);
941 method ^= msg.At(2);
942 param_keys ^= msg.At(3);
943 param_values ^= msg.At(4);
944
945 ASSERT(!method.IsNull());
946 ASSERT(!param_keys.IsNull());
947 ASSERT(!param_values.IsNull());
948 ASSERT(param_keys.Length() == param_values.Length());
949
950 if (!reply_port.IsSendPort()) {
951 FATAL("SendPort expected.");
952 }
953
954 IsolateMessageHandler handler =
955 FindIsolateMessageHandler(method.ToCString());
956 {
957 JSONStream js;
958 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
959 method, param_keys, param_values);
960 if (handler == NULL) {
961 // Check for an embedder handler.
962 EmbedderServiceHandler* e_handler =
963 FindIsolateEmbedderHandler(method.ToCString());
964 if (e_handler != NULL) {
965 EmbedderHandleMessage(e_handler, &js);
966 } else {
967 if (FindRootMessageHandler(method.ToCString()) != NULL) {
968 PrintError(&js, "%s does not expect the 'isolateId' parameter",
969 method.ToCString());
970 } else {
971 PrintError(&js, "Unrecognized method: %s", method.ToCString());
972 }
973 }
974 js.PostReply();
975 } else {
976 if (handler(isolate, &js)) {
977 // Handler returns true if the reply is ready to be posted.
978 // TODO(johnmccutchan): Support asynchronous replies.
979 js.PostReply();
980 }
981 }
982 }
983 }
984 }
985
986
987 static bool HandleIsolate(Isolate* isolate, JSONStream* js) { 682 static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
988 isolate->PrintJSON(js, false); 683 isolate->PrintJSON(js, false);
989 return true; 684 return true;
990 } 685 }
991 686
992 687
993 static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) { 688 static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) {
994 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); 689 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
995 JSONObject jsobj(js); 690 JSONObject jsobj(js);
996 jsobj.AddProperty("type", "Stack"); 691 jsobj.AddProperty("type", "Stack");
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 return HandleCommonEcho(&jsobj, js); 736 return HandleCommonEcho(&jsobj, js);
1042 } 737 }
1043 738
1044 739
1045 static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) { 740 static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) {
1046 JSONObject jsobj(js); 741 JSONObject jsobj(js);
1047 return HandleCommonEcho(&jsobj, js); 742 return HandleCommonEcho(&jsobj, js);
1048 } 743 }
1049 744
1050 745
1051 static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
1052 if ((s == NULL) || (*s == '\0')) {
1053 // Empty string.
1054 return false;
1055 }
1056 if (id == NULL) {
1057 // No id pointer.
1058 return false;
1059 }
1060 intptr_t r = 0;
1061 char* end_ptr = NULL;
1062 r = strtol(s, &end_ptr, base);
1063 if (end_ptr == s) {
1064 // String was not advanced at all, cannot be valid.
1065 return false;
1066 }
1067 *id = r;
1068 return true;
1069 }
1070
1071
1072 static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
1073 if ((s == NULL) || (*s == '\0')) {
1074 // Empty string.
1075 return false;
1076 }
1077 if (id == NULL) {
1078 // No id pointer.
1079 return false;
1080 }
1081 uintptr_t r = 0;
1082 char* end_ptr = NULL;
1083 r = strtoul(s, &end_ptr, base);
1084 if (end_ptr == s) {
1085 // String was not advanced at all, cannot be valid.
1086 return false;
1087 }
1088 *id = r;
1089 return true;
1090 }
1091
1092
1093 static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
1094 if ((s == NULL) || (*s == '\0')) {
1095 // Empty string.
1096 return false;
1097 }
1098 if (id == NULL) {
1099 // No id pointer.
1100 return false;
1101 }
1102 int64_t r = 0;
1103 char* end_ptr = NULL;
1104 r = strtoll(s, &end_ptr, base);
1105 if (end_ptr == s) {
1106 // String was not advanced at all, cannot be valid.
1107 return false;
1108 }
1109 *id = r;
1110 return true;
1111 }
1112
1113 // Scans the string until the '-' character. Returns pointer to string
1114 // at '-' character. Returns NULL if not found.
1115 static const char* ScanUntilDash(const char* s) {
1116 if ((s == NULL) || (*s == '\0')) {
1117 // Empty string.
1118 return NULL;
1119 }
1120 while (*s != '\0') {
1121 if (*s == '-') {
1122 return s;
1123 }
1124 s++;
1125 }
1126 return NULL;
1127 }
1128
1129
1130 static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
1131 if ((s == NULL) || (*s == '\0')) {
1132 // Empty string.
1133 return false;
1134 }
1135 if ((timestamp == NULL) || (address == NULL)) {
1136 // Bad arguments.
1137 return false;
1138 }
1139 // Extract the timestamp.
1140 if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
1141 return false;
1142 }
1143 s = ScanUntilDash(s);
1144 if (s == NULL) {
1145 return false;
1146 }
1147 // Skip the dash.
1148 s++;
1149 // Extract the PC.
1150 if (!GetUnsignedIntegerId(s, address, 16)) {
1151 return false;
1152 }
1153 return true;
1154 }
1155
1156
1157 static bool ContainsNonInstance(const Object& obj) { 746 static bool ContainsNonInstance(const Object& obj) {
1158 if (obj.IsArray()) { 747 if (obj.IsArray()) {
1159 const Array& array = Array::Cast(obj); 748 const Array& array = Array::Cast(obj);
1160 Object& element = Object::Handle(); 749 Object& element = Object::Handle();
1161 for (intptr_t i = 0; i < array.Length(); ++i) { 750 for (intptr_t i = 0; i < array.Length(); ++i) {
1162 element = array.At(i); 751 element = array.At(i);
1163 if (!(element.IsInstance() || element.IsNull())) { 752 if (!(element.IsInstance() || element.IsNull())) {
1164 return true; 753 return true;
1165 } 754 }
1166 } 755 }
(...skipping 748 matching lines...) Expand 10 before | Expand all | Expand 10 after
1915 JSONObject jsobj(js); 1504 JSONObject jsobj(js);
1916 jsobj.AddProperty("type", "InstanceSet"); 1505 jsobj.AddProperty("type", "InstanceSet");
1917 jsobj.AddProperty("id", "instance_set"); 1506 jsobj.AddProperty("id", "instance_set");
1918 jsobj.AddProperty("totalCount", count); 1507 jsobj.AddProperty("totalCount", count);
1919 jsobj.AddProperty("sampleCount", storage.Length()); 1508 jsobj.AddProperty("sampleCount", storage.Length());
1920 jsobj.AddProperty("sample", storage); 1509 jsobj.AddProperty("sample", storage);
1921 return true; 1510 return true;
1922 } 1511 }
1923 1512
1924 1513
1514 class LibraryCoverageFilter : public CoverageFilter {
1515 public:
1516 explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {}
1517 bool ShouldOutputCoverageFor(const Library& lib,
1518 const Script& script,
1519 const Class& cls,
1520 const Function& func) const {
1521 return lib.raw() == lib_.raw();
1522 }
1523 private:
1524 const Library& lib_;
1525 };
1526
1527
1528 class ScriptCoverageFilter : public CoverageFilter {
1529 public:
1530 explicit ScriptCoverageFilter(const Script& script)
1531 : script_(script) {}
1532 bool ShouldOutputCoverageFor(const Library& lib,
1533 const Script& script,
1534 const Class& cls,
1535 const Function& func) const {
1536 return script.raw() == script_.raw();
1537 }
1538 private:
1539 const Script& script_;
1540 };
1541
1542
1543 class ClassCoverageFilter : public CoverageFilter {
1544 public:
1545 explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {}
1546 bool ShouldOutputCoverageFor(const Library& lib,
1547 const Script& script,
1548 const Class& cls,
1549 const Function& func) const {
1550 return cls.raw() == cls_.raw();
1551 }
1552 private:
1553 const Class& cls_;
1554 };
1555
1556
1557 class FunctionCoverageFilter : public CoverageFilter {
1558 public:
1559 explicit FunctionCoverageFilter(const Function& func) : func_(func) {}
1560 bool ShouldOutputCoverageFor(const Library& lib,
1561 const Script& script,
1562 const Class& cls,
1563 const Function& func) const {
1564 return func.raw() == func_.raw();
1565 }
1566 private:
1567 const Function& func_;
1568 };
1569
1570
1925 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) { 1571 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
1926 if (!js->HasParam("targetId")) { 1572 if (!js->HasParam("targetId")) {
1927 CodeCoverage::PrintJSON(isolate, js, NULL); 1573 CodeCoverage::PrintJSON(isolate, js, NULL);
1928 return true; 1574 return true;
1929 } 1575 }
1930 const char* target_id = js->LookupParam("targetId"); 1576 const char* target_id = js->LookupParam("targetId");
1931 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL)); 1577 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
1932 if (obj.raw() == Object::sentinel().raw()) { 1578 if (obj.raw() == Object::sentinel().raw()) {
1933 PrintInvalidParamError(js, "targetId"); 1579 PrintInvalidParamError(js, "targetId");
1934 return true; 1580 return true;
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
2148 strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0; 1794 strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0;
2149 if (native_metric) { 1795 if (native_metric) {
2150 const char* id = metric_id + kNativeMetricIdPrefixLen; 1796 const char* id = metric_id + kNativeMetricIdPrefixLen;
2151 return HandleNativeMetric(isolate, js, id); 1797 return HandleNativeMetric(isolate, js, id);
2152 } 1798 }
2153 const char* id = metric_id + kMetricIdPrefixLen; 1799 const char* id = metric_id + kMetricIdPrefixLen;
2154 return HandleDartMetric(isolate, js, id); 1800 return HandleDartMetric(isolate, js, id);
2155 } 1801 }
2156 1802
2157 1803
2158 static bool HandleVMGetMetricList(JSONStream* js) { 1804 static bool HandleVMGetMetricList(Isolate* isolate, JSONStream* js) {
2159 return false; 1805 return false;
2160 } 1806 }
2161 1807
2162 1808
2163 static bool HandleVMGetMetric(JSONStream* js) { 1809 static bool HandleVMGetMetric(Isolate* isolate, JSONStream* js) {
2164 const char* metric_id = js->LookupParam("metricId"); 1810 const char* metric_id = js->LookupParam("metricId");
2165 if (metric_id == NULL) { 1811 if (metric_id == NULL) {
2166 PrintMissingParamError(js, "metricId"); 1812 PrintMissingParamError(js, "metricId");
2167 } 1813 }
2168 return false; 1814 return false;
2169 } 1815 }
2170 1816
2171 1817
2172 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) { 1818 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
2173 const char* step_param = js->LookupParam("step"); 1819 const char* step_param = js->LookupParam("step");
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
2235 1881
2236 1882
2237 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) { 1883 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
2238 JSONObject miniProfile(js); 1884 JSONObject miniProfile(js);
2239 miniProfile.AddProperty("type", "TagProfile"); 1885 miniProfile.AddProperty("type", "TagProfile");
2240 miniProfile.AddProperty("id", "profile/tag"); 1886 miniProfile.AddProperty("id", "profile/tag");
2241 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile); 1887 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile);
2242 return true; 1888 return true;
2243 } 1889 }
2244 1890
1891
1892 static const char* tags_enum_names[] = {
1893 "None",
1894 "UserVM",
1895 "UserOnly",
1896 "VMUser",
1897 "VMOnly",
1898 NULL,
1899 };
1900
1901
1902 static ProfilerService::TagOrder tags_enum_values[] = {
1903 ProfilerService::kNoTags,
1904 ProfilerService::kUserVM,
1905 ProfilerService::kUser,
1906 ProfilerService::kVMUser,
1907 ProfilerService::kVM,
1908 ProfilerService::kNoTags, // Default value.
1909 };
1910
1911
1912 static const MethodParameter* cpu_profile_params[] = {
1913 ISOLATE_PARAMETER,
1914 new EnumParameter("tags", true, tags_enum_names),
1915 NULL,
1916 };
1917
1918
2245 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) { 1919 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
2246 ProfilerService::TagOrder tag_order = ProfilerService::kUserVM; 1920 ProfilerService::TagOrder tag_order =
2247 if (js->HasParam("tags")) { 1921 EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
2248 if (js->ParamIs("tags", "None")) {
2249 tag_order = ProfilerService::kNoTags;
2250 } else if (js->ParamIs("tags", "UserVM")) {
2251 tag_order = ProfilerService::kUserVM;
2252 } else if (js->ParamIs("tags", "UserOnly")) {
2253 tag_order = ProfilerService::kUser;
2254 } else if (js->ParamIs("tags", "VMUser")) {
2255 tag_order = ProfilerService::kVMUser;
2256 } else if (js->ParamIs("tags", "VMOnly")) {
2257 tag_order = ProfilerService::kVM;
2258 } else {
2259 PrintInvalidParamError(js, "tags");
2260 return true;
2261 }
2262 }
2263 ProfilerService::PrintJSON(js, tag_order); 1922 ProfilerService::PrintJSON(js, tag_order);
2264 return true; 1923 return true;
2265 } 1924 }
2266 1925
2267 1926
2268 static bool HandleIsolateGetAllocationProfile(Isolate* isolate, 1927 static bool HandleIsolateGetAllocationProfile(Isolate* isolate,
2269 JSONStream* js) { 1928 JSONStream* js) {
2270 bool should_reset_accumulator = false; 1929 bool should_reset_accumulator = false;
2271 bool should_collect = false; 1930 bool should_collect = false;
2272 if (js->HasParam("reset")) { 1931 if (js->HasParam("reset")) {
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
2466 if (!type_args.IsNull()) { 2125 if (!type_args.IsNull()) {
2467 if (!only_with_instantiations || type_args.HasInstantiations()) { 2126 if (!only_with_instantiations || type_args.HasInstantiations()) {
2468 members.AddValue(type_args); 2127 members.AddValue(type_args);
2469 } 2128 }
2470 } 2129 }
2471 } 2130 }
2472 return true; 2131 return true;
2473 } 2132 }
2474 2133
2475 2134
2476 static IsolateMessageHandlerEntry isolate_handlers_new[] = {
2477 { "getIsolate", HandleIsolate },
2478 { "getObject", HandleIsolateGetObject },
2479 { "getObjectByAddress", HandleIsolateGetObjectByAddress },
2480 { "getBreakpoints", HandleIsolateGetBreakpoints },
2481 { "pause", HandleIsolatePause },
2482 { "resume", HandleIsolateResume },
2483 { "getStack", HandleIsolateGetStack },
2484 { "getCpuProfile", HandleIsolateGetCpuProfile },
2485 { "getTagProfile", HandleIsolateGetTagProfile },
2486 { "getAllocationProfile", HandleIsolateGetAllocationProfile },
2487 { "getHeapMap", HandleIsolateGetHeapMap },
2488 { "addBreakpoint", HandleIsolateAddBreakpoint },
2489 { "removeBreakpoint", HandleIsolateRemoveBreakpoint },
2490 { "getCoverage", HandleIsolateGetCoverage },
2491 { "eval", HandleIsolateEval },
2492 { "getRetainedSize", HandleIsolateGetRetainedSize },
2493 { "getRetainingPath", HandleIsolateGetRetainingPath },
2494 { "getInboundReferences", HandleIsolateGetInboundReferences },
2495 { "getInstances", HandleIsolateGetInstances },
2496 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot },
2497 { "getClassList", HandleIsolateGetClassList },
2498 { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList },
2499 { "getIsolateMetricList", HandleIsolateGetMetricList },
2500 { "getIsolateMetric", HandleIsolateGetMetric },
2501 { "_echo", HandleIsolateEcho },
2502 { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent },
2503 { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson },
2504 { "_respondWithMalformedObject", HandleIsolateRespondWithMalformedObject },
2505 };
2506
2507
2508 static IsolateMessageHandler FindIsolateMessageHandler(const char* method) {
2509 intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
2510 sizeof(isolate_handlers_new[0]);
2511 for (intptr_t i = 0; i < num_message_handlers; i++) {
2512 const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
2513 if (strcmp(method, entry.method) == 0) {
2514 return entry.handler;
2515 }
2516 }
2517 if (FLAG_trace_service) {
2518 OS::Print("Service has no isolate message handler for <%s>\n", method);
2519 }
2520 return NULL;
2521 }
2522
2523
2524 void Service::HandleRootMessage(const Instance& msg_instance) {
2525 Isolate* isolate = Isolate::Current();
2526 ASSERT(!msg_instance.IsNull());
2527 ASSERT(msg_instance.IsArray());
2528
2529 {
2530 StackZone zone(isolate);
2531 HANDLESCOPE(isolate);
2532
2533 const Array& msg = Array::Cast(msg_instance);
2534 ASSERT(msg.Length() == 5);
2535
2536 Instance& reply_port = Instance::Handle(isolate);
2537 String& method = String::Handle(isolate);
2538 Array& param_keys = Array::Handle(isolate);
2539 Array& param_values = Array::Handle(isolate);
2540 reply_port ^= msg.At(1);
2541 method ^= msg.At(2);
2542 param_keys ^= msg.At(3);
2543 param_values ^= msg.At(4);
2544
2545 ASSERT(!method.IsNull());
2546 ASSERT(!param_keys.IsNull());
2547 ASSERT(!param_values.IsNull());
2548 ASSERT(param_keys.Length() == param_values.Length());
2549
2550 if (!reply_port.IsSendPort()) {
2551 FATAL("SendPort expected.");
2552 }
2553
2554 RootMessageHandler handler =
2555 FindRootMessageHandler(method.ToCString());
2556 {
2557 JSONStream js;
2558 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
2559 method, param_keys, param_values);
2560 if (handler == NULL) {
2561 // Check for an embedder handler.
2562 EmbedderServiceHandler* e_handler =
2563 FindRootEmbedderHandler(method.ToCString());
2564 if (e_handler != NULL) {
2565 EmbedderHandleMessage(e_handler, &js);
2566 } else {
2567 if (FindIsolateMessageHandler(method.ToCString()) != NULL) {
2568 PrintMissingParamError(&js, "isolateId");
2569 } else {
2570 PrintError(&js, "Unrecognized method: %s", method.ToCString());
2571 }
2572 }
2573 js.PostReply();
2574 } else {
2575 if (handler(&js)) {
2576 // Handler returns true if the reply is ready to be posted.
2577 // TODO(johnmccutchan): Support asynchronous replies.
2578 js.PostReply();
2579 }
2580 }
2581 }
2582 }
2583 }
2584
2585
2586 static bool HandleRootEcho(JSONStream* js) {
2587 JSONObject jsobj(js);
2588 return HandleCommonEcho(&jsobj, js);
2589 }
2590
2591
2592 class ServiceIsolateVisitor : public IsolateVisitor { 2135 class ServiceIsolateVisitor : public IsolateVisitor {
2593 public: 2136 public:
2594 explicit ServiceIsolateVisitor(JSONArray* jsarr) 2137 explicit ServiceIsolateVisitor(JSONArray* jsarr)
2595 : jsarr_(jsarr) { 2138 : jsarr_(jsarr) {
2596 } 2139 }
2597 2140
2598 virtual ~ServiceIsolateVisitor() {} 2141 virtual ~ServiceIsolateVisitor() {}
2599 2142
2600 void VisitIsolate(Isolate* isolate) { 2143 void VisitIsolate(Isolate* isolate) {
2601 if (isolate != Dart::vm_isolate() && !Service::IsServiceIsolate(isolate)) { 2144 if ((isolate != Dart::vm_isolate()) &&
2145 !ServiceIsolate::IsServiceIsolate(isolate)) {
2602 jsarr_->AddValue(isolate); 2146 jsarr_->AddValue(isolate);
2603 } 2147 }
2604 } 2148 }
2605 2149
2606 private: 2150 private:
2607 JSONArray* jsarr_; 2151 JSONArray* jsarr_;
2608 }; 2152 };
2609 2153
2610 2154
2611 static bool HandleVM(JSONStream* js) { 2155 static bool HandleVM(Isolate* isolate, JSONStream* js) {
2612 Isolate* isolate = Isolate::Current();
2613 JSONObject jsobj(js); 2156 JSONObject jsobj(js);
2614 jsobj.AddProperty("type", "VM"); 2157 jsobj.AddProperty("type", "VM");
2615 jsobj.AddProperty("id", "vm"); 2158 jsobj.AddProperty("id", "vm");
2616 jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord)); 2159 jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord));
2617 jsobj.AddProperty("targetCPU", CPU::Id()); 2160 jsobj.AddProperty("targetCPU", CPU::Id());
2618 jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware()); 2161 jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
2619 jsobj.AddPropertyF("date", "%" Pd64 "", OS::GetCurrentTimeMillis()); 2162 jsobj.AddPropertyF("date", "%" Pd64 "", OS::GetCurrentTimeMillis());
2620 jsobj.AddProperty("version", Version::String()); 2163 jsobj.AddProperty("version", Version::String());
2621 // Send pid as a string because it allows us to avoid any issues with 2164 // Send pid as a string because it allows us to avoid any issues with
2622 // pids > 53-bits (when consumed by JavaScript). 2165 // pids > 53-bits (when consumed by JavaScript).
(...skipping 10 matching lines...) Expand all
2633 // Construct the isolate list. 2176 // Construct the isolate list.
2634 { 2177 {
2635 JSONArray jsarr(&jsobj, "isolates"); 2178 JSONArray jsarr(&jsobj, "isolates");
2636 ServiceIsolateVisitor visitor(&jsarr); 2179 ServiceIsolateVisitor visitor(&jsarr);
2637 Isolate::VisitIsolates(&visitor); 2180 Isolate::VisitIsolates(&visitor);
2638 } 2181 }
2639 return true; 2182 return true;
2640 } 2183 }
2641 2184
2642 2185
2643 static bool HandleVMFlagList(JSONStream* js) { 2186 static bool HandleVMFlagList(Isolate* isolate, JSONStream* js) {
2644 Flags::PrintJSON(js); 2187 Flags::PrintJSON(js);
2645 return true; 2188 return true;
2646 } 2189 }
2647 2190
2648 2191
2649 static bool HandleVMSetFlag(JSONStream* js) { 2192 static bool HandleVMSetFlag(Isolate* isolate, JSONStream* js) {
2650 const char* flag_name = js->LookupParam("name"); 2193 const char* flag_name = js->LookupParam("name");
2651 if (flag_name == NULL) { 2194 if (flag_name == NULL) {
2652 PrintMissingParamError(js, "name"); 2195 PrintMissingParamError(js, "name");
2653 return true; 2196 return true;
2654 } 2197 }
2655 const char* flag_value = js->LookupParam("value"); 2198 const char* flag_value = js->LookupParam("value");
2656 if (flag_value == NULL) { 2199 if (flag_value == NULL) {
2657 PrintMissingParamError(js, "value"); 2200 PrintMissingParamError(js, "value");
2658 return true; 2201 return true;
2659 } 2202 }
2660 JSONObject jsobj(js); 2203 JSONObject jsobj(js);
2661 const char* error = NULL; 2204 const char* error = NULL;
2662 if (Flags::SetFlag(flag_name, flag_value, &error)) { 2205 if (Flags::SetFlag(flag_name, flag_value, &error)) {
2663 jsobj.AddProperty("type", "Success"); 2206 jsobj.AddProperty("type", "Success");
2664 jsobj.AddProperty("id", ""); 2207 jsobj.AddProperty("id", "");
2665 return true; 2208 return true;
2666 } else { 2209 } else {
2667 jsobj.AddProperty("type", "Failure"); 2210 jsobj.AddProperty("type", "Failure");
2668 jsobj.AddProperty("id", ""); 2211 jsobj.AddProperty("id", "");
2669 jsobj.AddProperty("message", error); 2212 jsobj.AddProperty("message", error);
2670 return true; 2213 return true;
2671 } 2214 }
2672 } 2215 }
2673 2216
2674 2217
2675 static RootMessageHandlerEntry root_handlers_new[] = { 2218 static ServiceMethodDescriptor service_methods_[] = {
2676 { "getVM", HandleVM }, 2219 { "_echo", HandleIsolateEcho, NULL },
2677 { "getFlagList", HandleVMFlagList }, 2220 { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson, NULL },
2678 { "setFlag", HandleVMSetFlag }, 2221 { "_respondWithMalformedObject",
2679 { "getVMMetricList", HandleVMGetMetricList }, 2222 HandleIsolateRespondWithMalformedObject, NULL },
2680 { "getVMMetric", HandleVMGetMetric }, 2223 { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent, NULL },
2681 { "_echo", HandleRootEcho }, 2224 { "addBreakpoint", HandleIsolateAddBreakpoint, NULL },
2225 { "eval", HandleIsolateEval, NULL },
2226 { "getAllocationProfile", HandleIsolateGetAllocationProfile, NULL },
2227 { "getBreakpoints", HandleIsolateGetBreakpoints, NULL },
2228 { "getClassList", HandleIsolateGetClassList, NULL },
2229 { "getCoverage", HandleIsolateGetCoverage, NULL },
2230 { "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
2231 { "getFlagList", HandleVMFlagList , NULL},
2232 { "getHeapMap", HandleIsolateGetHeapMap, NULL },
2233 { "getInboundReferences", HandleIsolateGetInboundReferences, NULL },
2234 { "getInstances", HandleIsolateGetInstances, NULL },
2235 { "getIsolate", HandleIsolate, NULL },
2236 { "getIsolateMetric", HandleIsolateGetMetric, NULL },
2237 { "getIsolateMetricList", HandleIsolateGetMetricList, NULL },
2238 { "getObject", HandleIsolateGetObject, NULL },
2239 { "getObjectByAddress", HandleIsolateGetObjectByAddress, NULL },
2240 { "getRetainedSize", HandleIsolateGetRetainedSize, NULL },
2241 { "getRetainingPath", HandleIsolateGetRetainingPath, NULL },
2242 { "getStack", HandleIsolateGetStack, NULL },
2243 { "getTagProfile", HandleIsolateGetTagProfile, NULL },
2244 { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList, NULL },
2245 { "getVM", HandleVM , NULL},
2246 { "getVMMetric", HandleVMGetMetric , NULL},
2247 { "getVMMetricList", HandleVMGetMetricList , NULL},
2248 { "pause", HandleIsolatePause, NULL },
2249 { "removeBreakpoint", HandleIsolateRemoveBreakpoint, NULL },
2250 { "resume", HandleIsolateResume, NULL },
2251 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot, NULL },
2252 { "setFlag", HandleVMSetFlag , NULL},
2682 }; 2253 };
2683 2254
2684 2255
2685 static RootMessageHandler FindRootMessageHandler(const char* method) { 2256 ServiceMethodDescriptor* FindMethod(const char* method_name) {
2686 intptr_t num_message_handlers = sizeof(root_handlers_new) / 2257 intptr_t num_methods = sizeof(service_methods_) /
2687 sizeof(root_handlers_new[0]); 2258 sizeof(service_methods_[0]);
2688 for (intptr_t i = 0; i < num_message_handlers; i++) { 2259 for (intptr_t i = 0; i < num_methods; i++) {
2689 const RootMessageHandlerEntry& entry = root_handlers_new[i]; 2260 ServiceMethodDescriptor& method = service_methods_[i];
2690 if (strcmp(method, entry.method) == 0) { 2261 if (strcmp(method_name, method.name) == 0) {
2691 return entry.handler; 2262 return &method;
2692 } 2263 }
2693 } 2264 }
2694 if (FLAG_trace_service) {
2695 OS::Print("vm-service: No root message handler for <%s>.\n", method);
2696 }
2697 return NULL; 2265 return NULL;
2698 } 2266 }
2699 2267
2700 2268
2701 void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
2702 if (!IsRunning()) {
2703 return;
2704 }
2705 Isolate* isolate = Isolate::Current();
2706 ASSERT(isolate != NULL);
2707 HANDLESCOPE(isolate);
2708
2709 // Construct a list of the form [eventId, eventMessage].
2710 const Array& list = Array::Handle(Array::New(2));
2711 ASSERT(!list.IsNull());
2712 list.SetAt(0, Integer::Handle(Integer::New(eventId)));
2713 list.SetAt(1, eventMessage);
2714
2715 // Push the event to port_.
2716 uint8_t* data = NULL;
2717 MessageWriter writer(&data, &allocator, false);
2718 writer.WriteMessage(list);
2719 intptr_t len = writer.BytesWritten();
2720 if (FLAG_trace_service) {
2721 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
2722 eventId, len);
2723 }
2724 // TODO(turnidge): For now we ignore failure to send an event. Revisit?
2725 PortMap::PostMessage(
2726 new Message(service_port_, data, len, Message::kNormalPriority));
2727 }
2728
2729
2730 void Service::SendEvent(intptr_t eventId,
2731 const String& meta,
2732 const uint8_t* data,
2733 intptr_t size) {
2734 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
2735 const intptr_t meta_bytes = Utf8::Length(meta);
2736 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
2737 const TypedData& message = TypedData::Handle(
2738 TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
2739 intptr_t offset = 0;
2740 // TODO(koda): Rename these methods SetHostUint64, etc.
2741 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
2742 offset += sizeof(uint64_t);
2743 {
2744 NoGCScope no_gc;
2745 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
2746 offset += meta_bytes;
2747 }
2748 // TODO(koda): It would be nice to avoid this copy (requires changes to
2749 // MessageWriter code).
2750 {
2751 NoGCScope no_gc;
2752 memmove(message.DataAddr(offset), data, size);
2753 offset += size;
2754 }
2755 ASSERT(offset == total_bytes);
2756 SendEvent(eventId, message);
2757 }
2758
2759
2760 void Service::HandleGCEvent(GCEvent* event) {
2761 JSONStream js;
2762 event->PrintJSON(&js);
2763 const String& message = String::Handle(String::New(js.ToCString()));
2764 SendEvent(kEventFamilyGC, message);
2765 }
2766
2767
2768 void Service::HandleDebuggerEvent(DebuggerEvent* event) {
2769 JSONStream js;
2770 event->PrintJSON(&js);
2771 const String& message = String::Handle(String::New(js.ToCString()));
2772 SendEvent(kEventFamilyDebug, message);
2773 }
2774
2775
2776 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
2777 JSONStream* js) {
2778 ASSERT(handler != NULL);
2779 Dart_ServiceRequestCallback callback = handler->callback();
2780 ASSERT(callback != NULL);
2781 const char* r = NULL;
2782 const char* name = js->method();
2783 const char** keys = js->param_keys();
2784 const char** values = js->param_values();
2785 r = callback(name, keys, values, js->num_params(), handler->user_data());
2786 ASSERT(r != NULL);
2787 // TODO(johnmccutchan): Allow for NULL returns?
2788 TextBuffer* buffer = js->buffer();
2789 buffer->AddString(r);
2790 free(const_cast<char*>(r));
2791 }
2792
2793
2794 void Service::RegisterIsolateEmbedderCallback(
2795 const char* name,
2796 Dart_ServiceRequestCallback callback,
2797 void* user_data) {
2798 if (name == NULL) {
2799 return;
2800 }
2801 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
2802 if (handler != NULL) {
2803 // Update existing handler entry.
2804 handler->set_callback(callback);
2805 handler->set_user_data(user_data);
2806 return;
2807 }
2808 // Create a new handler.
2809 handler = new EmbedderServiceHandler(name);
2810 handler->set_callback(callback);
2811 handler->set_user_data(user_data);
2812
2813 // Insert into isolate_service_handler_head_ list.
2814 handler->set_next(isolate_service_handler_head_);
2815 isolate_service_handler_head_ = handler;
2816 }
2817
2818
2819 EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
2820 const char* name) {
2821 EmbedderServiceHandler* current = isolate_service_handler_head_;
2822 while (current != NULL) {
2823 if (strcmp(name, current->name()) == 0) {
2824 return current;
2825 }
2826 current = current->next();
2827 }
2828 return NULL;
2829 }
2830
2831
2832 void Service::RegisterRootEmbedderCallback(
2833 const char* name,
2834 Dart_ServiceRequestCallback callback,
2835 void* user_data) {
2836 if (name == NULL) {
2837 return;
2838 }
2839 EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
2840 if (handler != NULL) {
2841 // Update existing handler entry.
2842 handler->set_callback(callback);
2843 handler->set_user_data(user_data);
2844 return;
2845 }
2846 // Create a new handler.
2847 handler = new EmbedderServiceHandler(name);
2848 handler->set_callback(callback);
2849 handler->set_user_data(user_data);
2850
2851 // Insert into root_service_handler_head_ list.
2852 handler->set_next(root_service_handler_head_);
2853 root_service_handler_head_ = handler;
2854 }
2855
2856
2857 EmbedderServiceHandler* Service::FindRootEmbedderHandler(
2858 const char* name) {
2859 EmbedderServiceHandler* current = root_service_handler_head_;
2860 while (current != NULL) {
2861 if (strcmp(name, current->name()) == 0) {
2862 return current;
2863 }
2864 current = current->next();
2865 }
2866 return NULL;
2867 }
2868
2869 } // namespace dart 2269 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698