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

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
« no previous file with comments | « runtime/vm/service.h ('k') | runtime/vm/service_isolate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs.
44 const char* path_; 44 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
45 const char* resource_; 45 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
46 int length_; 46 uint32_t Service::event_mask_ = 0;
47 }; 47 struct ServiceMethodDescriptor;
48 48 ServiceMethodDescriptor* FindMethod(const char* method_name);
49 extern ResourcesEntry __service_resources_[]; 49
50 50 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
51 class Resources { 51 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
52 return reinterpret_cast<uint8_t*>(new_ptr);
53 }
54
55 static void PrintRequest(const JSONObject& obj, JSONStream* js) {
56 JSONObject jsobj(&obj, "request");
57 jsobj.AddProperty("method", js->method());
58 {
59 JSONArray jsarr(&jsobj, "param_keys");
60 for (intptr_t i = 0; i < js->num_params(); i++) {
61 jsarr.AddValue(js->GetParamKey(i));
62 }
63 }
64 {
65 JSONArray jsarr(&jsobj, "param_values");
66 for (intptr_t i = 0; i < js->num_params(); i++) {
67 jsarr.AddValue(js->GetParamValue(i));
68 }
69 }
70 }
71
72
73 static void PrintError(JSONStream* js,
74 const char* format, ...) {
75 Isolate* isolate = Isolate::Current();
76
77 va_list args;
78 va_start(args, format);
79 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
80 va_end(args);
81
82 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
83 va_list args2;
84 va_start(args2, format);
85 OS::VSNPrint(buffer, (len + 1), format, args2);
86 va_end(args2);
87
88 JSONObject jsobj(js);
89 jsobj.AddProperty("type", "Error");
90 jsobj.AddProperty("message", buffer);
91 PrintRequest(jsobj, js);
92 }
93
94
95 static void PrintMissingParamError(JSONStream* js,
96 const char* param) {
97 PrintError(js, "%s expects the '%s' parameter",
98 js->method(), param);
99 }
100
101
102 static void PrintInvalidParamError(JSONStream* js,
103 const char* param) {
104 PrintError(js, "%s: invalid '%s' parameter: %s",
105 js->method(), param, js->LookupParam(param));
106 }
107
108
109 static void PrintUnrecognizedMethodError(JSONStream* js) {
110 PrintError(js, "unrecognized method: %s", js->method());
111 }
112
113
114 static void PrintErrorWithKind(JSONStream* js,
115 const char* kind,
116 const char* format, ...) {
117 Isolate* isolate = Isolate::Current();
118
119 va_list args;
120 va_start(args, format);
121 intptr_t len = OS::VSNPrint(NULL, 0, format, args);
122 va_end(args);
123
124 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
125 va_list args2;
126 va_start(args2, format);
127 OS::VSNPrint(buffer, (len + 1), format, args2);
128 va_end(args2);
129
130 JSONObject jsobj(js);
131 jsobj.AddProperty("type", "Error");
132 jsobj.AddProperty("id", "");
133 jsobj.AddProperty("kind", kind);
134 jsobj.AddProperty("message", buffer);
135 PrintRequest(jsobj, js);
136 }
137
138
139 static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
140 if ((s == NULL) || (*s == '\0')) {
141 // Empty string.
142 return false;
143 }
144 if (id == NULL) {
145 // No id pointer.
146 return false;
147 }
148 intptr_t r = 0;
149 char* end_ptr = NULL;
150 r = strtol(s, &end_ptr, base);
151 if (end_ptr == s) {
152 // String was not advanced at all, cannot be valid.
153 return false;
154 }
155 *id = r;
156 return true;
157 }
158
159
160 static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
161 if ((s == NULL) || (*s == '\0')) {
162 // Empty string.
163 return false;
164 }
165 if (id == NULL) {
166 // No id pointer.
167 return false;
168 }
169 uintptr_t r = 0;
170 char* end_ptr = NULL;
171 r = strtoul(s, &end_ptr, base);
172 if (end_ptr == s) {
173 // String was not advanced at all, cannot be valid.
174 return false;
175 }
176 *id = r;
177 return true;
178 }
179
180
181 static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
182 if ((s == NULL) || (*s == '\0')) {
183 // Empty string.
184 return false;
185 }
186 if (id == NULL) {
187 // No id pointer.
188 return false;
189 }
190 int64_t r = 0;
191 char* end_ptr = NULL;
192 r = strtoll(s, &end_ptr, base);
193 if (end_ptr == s) {
194 // String was not advanced at all, cannot be valid.
195 return false;
196 }
197 *id = r;
198 return true;
199 }
200
201
202 // Scans the string until the '-' character. Returns pointer to string
203 // at '-' character. Returns NULL if not found.
204 static const char* ScanUntilDash(const char* s) {
205 if ((s == NULL) || (*s == '\0')) {
206 // Empty string.
207 return NULL;
208 }
209 while (*s != '\0') {
210 if (*s == '-') {
211 return s;
212 }
213 s++;
214 }
215 return NULL;
216 }
217
218
219 static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
220 if ((s == NULL) || (*s == '\0')) {
221 // Empty string.
222 return false;
223 }
224 if ((timestamp == NULL) || (address == NULL)) {
225 // Bad arguments.
226 return false;
227 }
228 // Extract the timestamp.
229 if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
230 return false;
231 }
232 s = ScanUntilDash(s);
233 if (s == NULL) {
234 return false;
235 }
236 // Skip the dash.
237 s++;
238 // Extract the PC.
239 if (!GetUnsignedIntegerId(s, address, 16)) {
240 return false;
241 }
242 return true;
243 }
244
245
246 // TODO(johnmccutchan): Split into separate file and write unit tests.
247 class MethodParameter {
52 public: 248 public:
53 static const int kNoSuchInstance = -1; 249 MethodParameter(const char* name, bool required)
54 static int ResourceLookup(const char* path, const char** resource) { 250 : name_(name), required_(required) {
55 ResourcesEntry* table = ResourceTable(); 251 }
56 for (int i = 0; table[i].path_ != NULL; i++) { 252
57 const ResourcesEntry& entry = table[i]; 253 virtual ~MethodParameter() { }
58 if (strcmp(path, entry.path_) == 0) { 254
59 *resource = entry.resource_; 255 virtual bool Validate(const char* value) const {
60 ASSERT(entry.length_ > 0); 256 return true;
61 return entry.length_; 257 }
258
259 const char* name() const {
260 return name_;
261 }
262
263 bool required() const {
264 return required_;
265 }
266
267 private:
268 const char* name_;
269 bool required_;
270 };
271
272
273 class NoSuchParameter : public MethodParameter {
274 public:
275 explicit NoSuchParameter(const char* name)
276 : MethodParameter(name, false) {
277 }
278
279 virtual bool Validate(const char* value) const {
280 return (value == NULL);
281 }
282 };
283
284
285 #define NO_ISOLATE_PARAMETER new NoSuchParameter("isolateId")
286
287
288 class BoolParameter : public MethodParameter {
289 public:
290 BoolParameter(const char* name, bool required)
291 : MethodParameter(name, required) {
292 }
293
294 virtual bool Validate(const char* value) const {
295 if (value == NULL) {
296 return false;
297 }
298 return (strcmp("true", value) == 0) || (strcmp("false", value) == 0);
299 }
300
301 static bool Interpret(const char* value) {
302 return strcmp("true", value) == 0;
303 }
304 };
305
306
307 class IdParameter : public MethodParameter {
308 public:
309 IdParameter(const char* name, bool required)
310 : MethodParameter(name, required) {
311 }
312
313 virtual bool Validate(const char* value) const {
314 return (value != NULL);
315 }
316 };
317
318
319 #define ISOLATE_PARAMETER new IdParameter("isolateId", true)
320
321
322 class EnumParameter : public MethodParameter {
323 public:
324 EnumParameter(const char* name, bool required, const char** enums)
325 : MethodParameter(name, required),
326 enums_(enums) {
327 }
328
329 virtual bool Validate(const char* value) const {
330 if (value == NULL) {
331 return true;
332 }
333 for (intptr_t i = 0; enums_[i] != NULL; i++) {
334 if (strcmp(value, enums_[i]) == 0) {
335 return true;
62 } 336 }
63 } 337 }
64 return kNoSuchInstance; 338 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 } 339 }
95 340
96 private: 341 private:
97 static ResourcesEntry* At(int idx) { 342 const char** enums_;
98 ASSERT(idx >= 0); 343 };
99 ResourcesEntry* table = ResourceTable(); 344
100 for (int i = 0; table[i].path_ != NULL; i++) { 345
101 if (idx == i) { 346 // If the key is not found, this function returns the last element in the
102 return &table[i]; 347 // values array. This can be used to encode the default value.
348 template<typename T>
349 T EnumMapper(const char* value, const char** enums, T* values) {
350 ASSERT(value != NULL);
351 intptr_t i = 0;
352 for (i = 0; enums[i] != NULL; i++) {
353 if (strcmp(value, enums[i]) == 0) {
354 return values[i];
355 }
356 }
357 // Default value.
358 return values[i];
359 }
360
361
362 typedef bool (*ServiceMethodEntry)(Isolate* isolate, JSONStream* js);
363
364
365 struct ServiceMethodDescriptor {
366 const char* name;
367 const ServiceMethodEntry entry;
368 const MethodParameter* const * parameters;
369 };
370
371
372 // TODO(johnmccutchan): Do we reject unexpected parameters?
373 static bool ValidateParameters(const MethodParameter* const* parameters,
374 JSONStream* js) {
375 if (parameters == NULL) {
376 return true;
377 }
378 for (intptr_t i = 0; parameters[i] != NULL; i++) {
379 const MethodParameter* parameter = parameters[i];
380 const char* name = parameter->name();
381 const bool required = parameter->required();
382 const char* value = js->LookupParam(name);
383 const bool has_parameter = (value != NULL);
384 if (required && !has_parameter) {
385 PrintMissingParamError(js, name);
386 return false;
387 }
388 if (!parameter->Validate(value)) {
389 PrintInvalidParamError(js, name);
390 return false;
391 }
392 }
393 return true;
394 }
395
396
397 void Service::InvokeMethod(Isolate* isolate, const Array& msg) {
398 ASSERT(isolate != NULL);
399 ASSERT(!msg.IsNull());
400 ASSERT(msg.Length() == 5);
401
402 {
403 StackZone zone(isolate);
404 HANDLESCOPE(isolate);
405
406 Instance& reply_port = Instance::Handle(isolate);
407 String& method_name = String::Handle(isolate);
408 Array& param_keys = Array::Handle(isolate);
409 Array& param_values = Array::Handle(isolate);
410 reply_port ^= msg.At(1);
411 method_name ^= msg.At(2);
412 param_keys ^= msg.At(3);
413 param_values ^= msg.At(4);
414
415 ASSERT(!method_name.IsNull());
416 ASSERT(!param_keys.IsNull());
417 ASSERT(!param_values.IsNull());
418 ASSERT(param_keys.Length() == param_values.Length());
419
420 if (!reply_port.IsSendPort()) {
421 FATAL("SendPort expected.");
422 }
423
424 JSONStream js;
425 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
426 method_name, param_keys, param_values);
427
428 const char* c_method_name = method_name.ToCString();
429
430 ServiceMethodDescriptor* method = FindMethod(c_method_name);
431 if (method != NULL) {
432 if (!ValidateParameters(method->parameters, &js)) {
433 js.PostReply();
434 return;
103 } 435 }
104 } 436 if (method->entry(isolate, &js)) {
105 return NULL; 437 js.PostReply();
106 } 438 }
107 439 return;
108 static ResourcesEntry* ResourceTable() { 440 }
109 return &__service_resources_[0]; 441
110 } 442 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(c_method_name);
111 443 if (handler == NULL) {
112 DISALLOW_ALLOCATION(); 444 handler = FindRootEmbedderHandler(c_method_name);
113 DISALLOW_IMPLICIT_CONSTRUCTORS(Resources); 445 }
114 }; 446
447 if (handler != NULL) {
448 EmbedderHandleMessage(handler, &js);
449 js.PostReply();
450 return;
451 }
452
453 PrintUnrecognizedMethodError(&js);
454 js.PostReply();
455 return;
456 }
457 }
458
459
460 void Service::HandleRootMessage(const Array& msg_instance) {
461 Isolate* isolate = Isolate::Current();
462 InvokeMethod(isolate, msg_instance);
463 }
464
465
466 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
467 ASSERT(isolate != NULL);
468 InvokeMethod(isolate, msg);
469 }
470
471
472 bool Service::EventMaskHas(uint32_t mask) {
473 return (event_mask_ & mask) != 0;
474 }
475
476
477 bool Service::NeedsDebuggerEvents() {
478 return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyDebugMask);
479 }
480
481
482 bool Service::NeedsGCEvents() {
483 return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyGCMask);
484 }
485
486
487 void Service::SetEventMask(uint32_t mask) {
488 event_mask_ = mask;
489 }
490
491
492 void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
493 if (!ServiceIsolate::IsRunning()) {
494 return;
495 }
496 Isolate* isolate = Isolate::Current();
497 ASSERT(isolate != NULL);
498 HANDLESCOPE(isolate);
499
500 // Construct a list of the form [eventId, eventMessage].
501 const Array& list = Array::Handle(Array::New(2));
502 ASSERT(!list.IsNull());
503 list.SetAt(0, Integer::Handle(Integer::New(eventId)));
504 list.SetAt(1, eventMessage);
505
506 // Push the event to port_.
507 uint8_t* data = NULL;
508 MessageWriter writer(&data, &allocator, false);
509 writer.WriteMessage(list);
510 intptr_t len = writer.BytesWritten();
511 if (FLAG_trace_service) {
512 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
513 eventId, len);
514 }
515 // TODO(turnidge): For now we ignore failure to send an event. Revisit?
516 PortMap::PostMessage(
517 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority));
518 }
519
520
521 void Service::SendEvent(intptr_t eventId,
522 const String& meta,
523 const uint8_t* data,
524 intptr_t size) {
525 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
526 const intptr_t meta_bytes = Utf8::Length(meta);
527 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
528 const TypedData& message = TypedData::Handle(
529 TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
530 intptr_t offset = 0;
531 // TODO(koda): Rename these methods SetHostUint64, etc.
532 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
533 offset += sizeof(uint64_t);
534 {
535 NoGCScope no_gc;
536 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
537 offset += meta_bytes;
538 }
539 // TODO(koda): It would be nice to avoid this copy (requires changes to
540 // MessageWriter code).
541 {
542 NoGCScope no_gc;
543 memmove(message.DataAddr(offset), data, size);
544 offset += size;
545 }
546 ASSERT(offset == total_bytes);
547 SendEvent(eventId, message);
548 }
549
550
551 void Service::HandleGCEvent(GCEvent* event) {
552 JSONStream js;
553 event->PrintJSON(&js);
554 const String& message = String::Handle(String::New(js.ToCString()));
555 SendEvent(kEventFamilyGC, message);
556 }
557
558
559 void Service::HandleDebuggerEvent(DebuggerEvent* event) {
560 JSONStream js;
561 event->PrintJSON(&js);
562 const String& message = String::Handle(String::New(js.ToCString()));
563 SendEvent(kEventFamilyDebug, message);
564 }
115 565
116 566
117 class EmbedderServiceHandler { 567 class EmbedderServiceHandler {
118 public: 568 public:
119 explicit EmbedderServiceHandler(const char* name) : name_(NULL), 569 explicit EmbedderServiceHandler(const char* name) : name_(NULL),
120 callback_(NULL), 570 callback_(NULL),
121 user_data_(NULL), 571 user_data_(NULL),
122 next_(NULL) { 572 next_(NULL) {
123 ASSERT(name != NULL); 573 ASSERT(name != NULL);
124 name_ = strdup(name); 574 name_ = strdup(name);
(...skipping 21 matching lines...) Expand all
146 } 596 }
147 597
148 private: 598 private:
149 char* name_; 599 char* name_;
150 Dart_ServiceRequestCallback callback_; 600 Dart_ServiceRequestCallback callback_;
151 void* user_data_; 601 void* user_data_;
152 EmbedderServiceHandler* next_; 602 EmbedderServiceHandler* next_;
153 }; 603 };
154 604
155 605
156 class LibraryCoverageFilter : public CoverageFilter { 606 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
157 public: 607 JSONStream* js) {
158 explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {} 608 ASSERT(handler != NULL);
159 bool ShouldOutputCoverageFor(const Library& lib, 609 Dart_ServiceRequestCallback callback = handler->callback();
160 const Script& script, 610 ASSERT(callback != NULL);
161 const Class& cls, 611 const char* r = NULL;
162 const Function& func) const { 612 const char* name = js->method();
163 return lib.raw() == lib_.raw(); 613 const char** keys = js->param_keys();
164 } 614 const char** values = js->param_values();
165 private: 615 r = callback(name, keys, values, js->num_params(), handler->user_data());
166 const Library& lib_; 616 ASSERT(r != NULL);
167 }; 617 // TODO(johnmccutchan): Allow for NULL returns?
168 618 TextBuffer* buffer = js->buffer();
169 619 buffer->AddString(r);
170 class ScriptCoverageFilter : public CoverageFilter { 620 free(const_cast<char*>(r));
171 public: 621 }
172 explicit ScriptCoverageFilter(const Script& script) 622
173 : script_(script) {} 623
174 bool ShouldOutputCoverageFor(const Library& lib, 624 void Service::RegisterIsolateEmbedderCallback(
175 const Script& script, 625 const char* name,
176 const Class& cls, 626 Dart_ServiceRequestCallback callback,
177 const Function& func) const { 627 void* user_data) {
178 return script.raw() == script_.raw(); 628 if (name == NULL) {
179 } 629 return;
180 private: 630 }
181 const Script& script_; 631 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
182 }; 632 if (handler != NULL) {
183 633 // Update existing handler entry.
184 634 handler->set_callback(callback);
185 class ClassCoverageFilter : public CoverageFilter { 635 handler->set_user_data(user_data);
186 public: 636 return;
187 explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {} 637 }
188 bool ShouldOutputCoverageFor(const Library& lib, 638 // Create a new handler.
189 const Script& script, 639 handler = new EmbedderServiceHandler(name);
190 const Class& cls, 640 handler->set_callback(callback);
191 const Function& func) const { 641 handler->set_user_data(user_data);
192 return cls.raw() == cls_.raw(); 642
193 } 643 // Insert into isolate_service_handler_head_ list.
194 private: 644 handler->set_next(isolate_service_handler_head_);
195 const Class& cls_; 645 isolate_service_handler_head_ = handler;
196 }; 646 }
197 647
198 648
199 class FunctionCoverageFilter : public CoverageFilter { 649 EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
200 public: 650 const char* name) {
201 explicit FunctionCoverageFilter(const Function& func) : func_(func) {} 651 EmbedderServiceHandler* current = isolate_service_handler_head_;
202 bool ShouldOutputCoverageFor(const Library& lib, 652 while (current != NULL) {
203 const Script& script, 653 if (strcmp(name, current->name()) == 0) {
204 const Class& cls, 654 return current;
205 const Function& func) const { 655 }
206 return func.raw() == func_.raw(); 656 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 } 657 }
500 return NULL; 658 return NULL;
501 } 659 }
502 660
503 const char* Service::kIsolateName = "vm-service"; 661
504 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; 662 void Service::RegisterRootEmbedderCallback(
505 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; 663 const char* name,
506 Isolate* Service::service_isolate_ = NULL; 664 Dart_ServiceRequestCallback callback,
507 Dart_Port Service::service_port_ = ILLEGAL_PORT; 665 void* user_data) {
508 Dart_Port Service::load_port_ = ILLEGAL_PORT; 666 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; 667 return;
635 } 668 }
636 if (HasServiceIsolate()) { 669 EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
637 // Service isolate already exists. 670 if (handler != NULL) {
671 // Update existing handler entry.
672 handler->set_callback(callback);
673 handler->set_user_data(user_data);
638 return; 674 return;
639 } 675 }
640 SetServiceIsolate(isolate); 676 // Create a new handler.
641 677 handler = new EmbedderServiceHandler(name);
642 StackZone zone(isolate); 678 handler->set_callback(callback);
643 HANDLESCOPE(isolate); 679 handler->set_user_data(user_data);
644 680
645 // Register dart:vmservice library. 681 // Insert into root_service_handler_head_ list.
646 const String& url_str = String::Handle(Symbols::DartVMService().raw()); 682 handler->set_next(root_service_handler_head_);
647 const Library& library = Library::Handle(Library::New(url_str)); 683 root_service_handler_head_ = handler;
648 library.Register(); 684 }
649 library.set_native_entry_resolver(VmServiceNativeResolver); 685
650 686
651 // Temporarily install our library tag handler. 687 EmbedderServiceHandler* Service::FindRootEmbedderHandler(
652 isolate->set_library_tag_handler(LibraryTagHandler); 688 const char* name) {
653 689 EmbedderServiceHandler* current = root_service_handler_head_;
654 // Get script source. 690 while (current != NULL) {
655 const char* resource = NULL; 691 if (strcmp(name, current->name()) == 0) {
656 const char* path = "/vmservice.dart"; 692 return current;
657 intptr_t r = Resources::ResourceLookup(path, &resource); 693 }
658 ASSERT(r != Resources::kNoSuchInstance); 694 current = current->next();
659 ASSERT(resource != NULL); 695 }
660 const String& source_str = String::Handle( 696 return NULL;
661 String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r)); 697 }
662 ASSERT(!source_str.IsNull()); 698
663 const Script& script = Script::Handle( 699
664 isolate, Script::New(url_str, source_str, RawScript::kLibraryTag)); 700 static const MethodParameter* get_isolate_params[] = {
665 701 ISOLATE_PARAMETER,
666 // Compile script. 702 NULL,
667 Dart_EnterScope(); // Need to enter scope for tag handler. 703 };
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 704
986 705
987 static bool HandleIsolate(Isolate* isolate, JSONStream* js) { 706 static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
988 isolate->PrintJSON(js, false); 707 isolate->PrintJSON(js, false);
989 return true; 708 return true;
990 } 709 }
991 710
992 711
712 static const MethodParameter* get_stack_params[] = {
713 ISOLATE_PARAMETER,
714 NULL,
715 };
716
717
993 static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) { 718 static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) {
994 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); 719 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
995 JSONObject jsobj(js); 720 JSONObject jsobj(js);
996 jsobj.AddProperty("type", "Stack"); 721 jsobj.AddProperty("type", "Stack");
997 JSONArray jsarr(&jsobj, "frames"); 722 JSONArray jsarr(&jsobj, "frames");
998 intptr_t num_frames = stack->Length(); 723 intptr_t num_frames = stack->Length();
999 for (intptr_t i = 0; i < num_frames; i++) { 724 for (intptr_t i = 0; i < num_frames; i++) {
1000 ActivationFrame* frame = stack->FrameAt(i); 725 ActivationFrame* frame = stack->FrameAt(i);
1001 JSONObject jsobj(&jsarr); 726 JSONObject jsobj(&jsarr);
1002 frame->PrintToJSONObject(&jsobj); 727 frame->PrintToJSONObject(&jsobj);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 return HandleCommonEcho(&jsobj, js); 766 return HandleCommonEcho(&jsobj, js);
1042 } 767 }
1043 768
1044 769
1045 static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) { 770 static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) {
1046 JSONObject jsobj(js); 771 JSONObject jsobj(js);
1047 return HandleCommonEcho(&jsobj, js); 772 return HandleCommonEcho(&jsobj, js);
1048 } 773 }
1049 774
1050 775
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) { 776 static bool ContainsNonInstance(const Object& obj) {
1158 if (obj.IsArray()) { 777 if (obj.IsArray()) {
1159 const Array& array = Array::Cast(obj); 778 const Array& array = Array::Cast(obj);
1160 Object& element = Object::Handle(); 779 Object& element = Object::Handle();
1161 for (intptr_t i = 0; i < array.Length(); ++i) { 780 for (intptr_t i = 0; i < array.Length(); ++i) {
1162 element = array.At(i); 781 element = array.At(i);
1163 if (!(element.IsInstance() || element.IsNull())) { 782 if (!(element.IsInstance() || element.IsNull())) {
1164 return true; 783 return true;
1165 } 784 }
1166 } 785 }
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
1589 // We nil out the array after generating the response to prevent 1208 // We nil out the array after generating the response to prevent
1590 // reporting suprious references when repeatedly looking for the 1209 // reporting suprious references when repeatedly looking for the
1591 // references to an object. 1210 // references to an object.
1592 path.SetAt(i * 2, Object::null_object()); 1211 path.SetAt(i * 2, Object::null_object());
1593 } 1212 }
1594 } 1213 }
1595 return true; 1214 return true;
1596 } 1215 }
1597 1216
1598 1217
1218 static const MethodParameter* get_inbound_references_params[] = {
1219 ISOLATE_PARAMETER,
1220 NULL,
1221 };
1222
1223
1599 static bool HandleIsolateGetInboundReferences(Isolate* isolate, 1224 static bool HandleIsolateGetInboundReferences(Isolate* isolate,
1600 JSONStream* js) { 1225 JSONStream* js) {
1601 const char* target_id = js->LookupParam("targetId"); 1226 const char* target_id = js->LookupParam("targetId");
1602 if (target_id == NULL) { 1227 if (target_id == NULL) {
1603 PrintMissingParamError(js, "targetId"); 1228 PrintMissingParamError(js, "targetId");
1604 return true; 1229 return true;
1605 } 1230 }
1606 const char* limit_cstr = js->LookupParam("limit"); 1231 const char* limit_cstr = js->LookupParam("limit");
1607 if (target_id == NULL) { 1232 if (target_id == NULL) {
1608 PrintMissingParamError(js, "limit"); 1233 PrintMissingParamError(js, "limit");
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1687 // We nil out the array after generating the response to prevent 1312 // We nil out the array after generating the response to prevent
1688 // reporting spurious references when looking for inbound references 1313 // reporting spurious references when looking for inbound references
1689 // after looking for a retaining path. 1314 // after looking for a retaining path.
1690 for (intptr_t i = 0; i < limit; ++i) { 1315 for (intptr_t i = 0; i < limit; ++i) {
1691 path.SetAt(i * 2, Object::null_object()); 1316 path.SetAt(i * 2, Object::null_object());
1692 } 1317 }
1693 1318
1694 return true; 1319 return true;
1695 } 1320 }
1696 1321
1322
1323 static const MethodParameter* get_retaining_path_params[] = {
1324 ISOLATE_PARAMETER,
1325 NULL,
1326 };
1327
1328
1697 static bool HandleIsolateGetRetainingPath(Isolate* isolate, 1329 static bool HandleIsolateGetRetainingPath(Isolate* isolate,
1698 JSONStream* js) { 1330 JSONStream* js) {
1699 const char* target_id = js->LookupParam("targetId"); 1331 const char* target_id = js->LookupParam("targetId");
1700 if (target_id == NULL) { 1332 if (target_id == NULL) {
1701 PrintMissingParamError(js, "targetId"); 1333 PrintMissingParamError(js, "targetId");
1702 return true; 1334 return true;
1703 } 1335 }
1704 const char* limit_cstr = js->LookupParam("limit"); 1336 const char* limit_cstr = js->LookupParam("limit");
1705 if (target_id == NULL) { 1337 if (target_id == NULL) {
1706 PrintMissingParamError(js, "limit"); 1338 PrintMissingParamError(js, "limit");
(...skipping 23 matching lines...) Expand all
1730 "attempt to find a retaining path for an expired object\n"); 1362 "attempt to find a retaining path for an expired object\n");
1731 return true; 1363 return true;
1732 } 1364 }
1733 PrintInvalidParamError(js, "targetId"); 1365 PrintInvalidParamError(js, "targetId");
1734 return true; 1366 return true;
1735 } 1367 }
1736 return PrintRetainingPath(isolate, &obj, limit, js); 1368 return PrintRetainingPath(isolate, &obj, limit, js);
1737 } 1369 }
1738 1370
1739 1371
1372 static const MethodParameter* get_retained_size_params[] = {
1373 ISOLATE_PARAMETER,
1374 NULL,
1375 };
1376
1377
1740 static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) { 1378 static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) {
1741 const char* target_id = js->LookupParam("targetId"); 1379 const char* target_id = js->LookupParam("targetId");
1742 if (target_id == NULL) { 1380 if (target_id == NULL) {
1743 PrintMissingParamError(js, "targetId"); 1381 PrintMissingParamError(js, "targetId");
1744 return true; 1382 return true;
1745 } 1383 }
1746 ObjectIdRing::LookupResult lookup_result; 1384 ObjectIdRing::LookupResult lookup_result;
1747 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, 1385 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id,
1748 &lookup_result)); 1386 &lookup_result));
1749 if (obj.raw() == Object::sentinel().raw()) { 1387 if (obj.raw() == Object::sentinel().raw()) {
(...skipping 27 matching lines...) Expand all
1777 result.PrintJSON(js, true); 1415 result.PrintJSON(js, true);
1778 return true; 1416 return true;
1779 } 1417 }
1780 PrintError(js, "%s: Invalid 'targetId' parameter value: " 1418 PrintError(js, "%s: Invalid 'targetId' parameter value: "
1781 "id '%s' does not correspond to a " 1419 "id '%s' does not correspond to a "
1782 "library, class, or instance", js->method(), target_id); 1420 "library, class, or instance", js->method(), target_id);
1783 return true; 1421 return true;
1784 } 1422 }
1785 1423
1786 1424
1425 static const MethodParameter* eval_params[] = {
1426 ISOLATE_PARAMETER,
1427 NULL,
1428 };
1429
1430
1787 static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) { 1431 static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) {
1788 const char* target_id = js->LookupParam("targetId"); 1432 const char* target_id = js->LookupParam("targetId");
1789 if (target_id == NULL) { 1433 if (target_id == NULL) {
1790 PrintMissingParamError(js, "targetId"); 1434 PrintMissingParamError(js, "targetId");
1791 return true; 1435 return true;
1792 } 1436 }
1793 const char* expr = js->LookupParam("expression"); 1437 const char* expr = js->LookupParam("expression");
1794 if (expr == NULL) { 1438 if (expr == NULL) {
1795 PrintMissingParamError(js, "expression"); 1439 PrintMissingParamError(js, "expression");
1796 return true; 1440 return true;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1869 1513
1870 intptr_t count() const { return count_; } 1514 intptr_t count() const { return count_; }
1871 1515
1872 private: 1516 private:
1873 const Class& cls_; 1517 const Class& cls_;
1874 const Array& storage_; 1518 const Array& storage_;
1875 intptr_t count_; 1519 intptr_t count_;
1876 }; 1520 };
1877 1521
1878 1522
1523 static const MethodParameter* get_instances_params[] = {
1524 ISOLATE_PARAMETER,
1525 NULL,
1526 };
1527
1528
1879 static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) { 1529 static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
1880 const char* target_id = js->LookupParam("classId"); 1530 const char* target_id = js->LookupParam("classId");
1881 if (target_id == NULL) { 1531 if (target_id == NULL) {
1882 PrintMissingParamError(js, "classId"); 1532 PrintMissingParamError(js, "classId");
1883 return true; 1533 return true;
1884 } 1534 }
1885 const char* limit_cstr = js->LookupParam("limit"); 1535 const char* limit_cstr = js->LookupParam("limit");
1886 if (target_id == NULL) { 1536 if (target_id == NULL) {
1887 PrintMissingParamError(js, "limit"); 1537 PrintMissingParamError(js, "limit");
1888 return true; 1538 return true;
(...skipping 26 matching lines...) Expand all
1915 JSONObject jsobj(js); 1565 JSONObject jsobj(js);
1916 jsobj.AddProperty("type", "InstanceSet"); 1566 jsobj.AddProperty("type", "InstanceSet");
1917 jsobj.AddProperty("id", "instance_set"); 1567 jsobj.AddProperty("id", "instance_set");
1918 jsobj.AddProperty("totalCount", count); 1568 jsobj.AddProperty("totalCount", count);
1919 jsobj.AddProperty("sampleCount", storage.Length()); 1569 jsobj.AddProperty("sampleCount", storage.Length());
1920 jsobj.AddProperty("sample", storage); 1570 jsobj.AddProperty("sample", storage);
1921 return true; 1571 return true;
1922 } 1572 }
1923 1573
1924 1574
1575 class LibraryCoverageFilter : public CoverageFilter {
1576 public:
1577 explicit LibraryCoverageFilter(const Library& lib) : lib_(lib) {}
1578 bool ShouldOutputCoverageFor(const Library& lib,
1579 const Script& script,
1580 const Class& cls,
1581 const Function& func) const {
1582 return lib.raw() == lib_.raw();
1583 }
1584 private:
1585 const Library& lib_;
1586 };
1587
1588
1589 class ScriptCoverageFilter : public CoverageFilter {
1590 public:
1591 explicit ScriptCoverageFilter(const Script& script)
1592 : script_(script) {}
1593 bool ShouldOutputCoverageFor(const Library& lib,
1594 const Script& script,
1595 const Class& cls,
1596 const Function& func) const {
1597 return script.raw() == script_.raw();
1598 }
1599 private:
1600 const Script& script_;
1601 };
1602
1603
1604 class ClassCoverageFilter : public CoverageFilter {
1605 public:
1606 explicit ClassCoverageFilter(const Class& cls) : cls_(cls) {}
1607 bool ShouldOutputCoverageFor(const Library& lib,
1608 const Script& script,
1609 const Class& cls,
1610 const Function& func) const {
1611 return cls.raw() == cls_.raw();
1612 }
1613 private:
1614 const Class& cls_;
1615 };
1616
1617
1618 class FunctionCoverageFilter : public CoverageFilter {
1619 public:
1620 explicit FunctionCoverageFilter(const Function& func) : func_(func) {}
1621 bool ShouldOutputCoverageFor(const Library& lib,
1622 const Script& script,
1623 const Class& cls,
1624 const Function& func) const {
1625 return func.raw() == func_.raw();
1626 }
1627 private:
1628 const Function& func_;
1629 };
1630
1631
1632 static const MethodParameter* get_coverage_params[] = {
1633 ISOLATE_PARAMETER,
1634 NULL,
1635 };
1636
1637
1925 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) { 1638 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
1926 if (!js->HasParam("targetId")) { 1639 if (!js->HasParam("targetId")) {
1927 CodeCoverage::PrintJSON(isolate, js, NULL); 1640 CodeCoverage::PrintJSON(isolate, js, NULL);
1928 return true; 1641 return true;
1929 } 1642 }
1930 const char* target_id = js->LookupParam("targetId"); 1643 const char* target_id = js->LookupParam("targetId");
1931 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL)); 1644 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
1932 if (obj.raw() == Object::sentinel().raw()) { 1645 if (obj.raw() == Object::sentinel().raw()) {
1933 PrintInvalidParamError(js, "targetId"); 1646 PrintInvalidParamError(js, "targetId");
1934 return true; 1647 return true;
(...skipping 18 matching lines...) Expand all
1953 CodeCoverage::PrintJSON(isolate, js, &ff); 1666 CodeCoverage::PrintJSON(isolate, js, &ff);
1954 return true; 1667 return true;
1955 } 1668 }
1956 PrintError(js, "%s: Invalid 'targetId' parameter value: " 1669 PrintError(js, "%s: Invalid 'targetId' parameter value: "
1957 "id '%s' does not correspond to a " 1670 "id '%s' does not correspond to a "
1958 "script, library, class, or function", js->method(), target_id); 1671 "script, library, class, or function", js->method(), target_id);
1959 return true; 1672 return true;
1960 } 1673 }
1961 1674
1962 1675
1676 static const MethodParameter* add_breakpoint_params[] = {
1677 ISOLATE_PARAMETER,
1678 NULL,
1679 };
1680
1681
1963 static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) { 1682 static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) {
1964 if (!js->HasParam("line")) { 1683 if (!js->HasParam("line")) {
1965 PrintMissingParamError(js, "line"); 1684 PrintMissingParamError(js, "line");
1966 return true; 1685 return true;
1967 } 1686 }
1968 const char* line_param = js->LookupParam("line"); 1687 const char* line_param = js->LookupParam("line");
1969 intptr_t line = -1; 1688 intptr_t line = -1;
1970 if (!GetIntegerId(line_param, &line)) { 1689 if (!GetIntegerId(line_param, &line)) {
1971 PrintInvalidParamError(js, "line"); 1690 PrintInvalidParamError(js, "line");
1972 return true; 1691 return true;
(...skipping 10 matching lines...) Expand all
1983 isolate->debugger()->SetBreakpointAtLine(script_url, line); 1702 isolate->debugger()->SetBreakpointAtLine(script_url, line);
1984 if (bpt == NULL) { 1703 if (bpt == NULL) {
1985 PrintError(js, "Unable to set breakpoint at line %s", line_param); 1704 PrintError(js, "Unable to set breakpoint at line %s", line_param);
1986 return true; 1705 return true;
1987 } 1706 }
1988 bpt->PrintJSON(js); 1707 bpt->PrintJSON(js);
1989 return true; 1708 return true;
1990 } 1709 }
1991 1710
1992 1711
1712 static const MethodParameter* remove_breakpoint_params[] = {
1713 ISOLATE_PARAMETER,
1714 NULL,
1715 };
1716
1717
1993 static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) { 1718 static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) {
1994 if (!js->HasParam("breakpointId")) { 1719 if (!js->HasParam("breakpointId")) {
1995 PrintMissingParamError(js, "breakpointId"); 1720 PrintMissingParamError(js, "breakpointId");
1996 return true; 1721 return true;
1997 } 1722 }
1998 const char* bpt_id = js->LookupParam("breakpointId"); 1723 const char* bpt_id = js->LookupParam("breakpointId");
1999 SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id); 1724 SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
2000 if (bpt == NULL) { 1725 if (bpt == NULL) {
2001 fprintf(stderr, "ERROR1"); 1726 fprintf(stderr, "ERROR1");
2002 PrintInvalidParamError(js, "breakpointId"); 1727 PrintInvalidParamError(js, "breakpointId");
(...skipping 16 matching lines...) Expand all
2019 const String& metrics_cls_name = 1744 const String& metrics_cls_name =
2020 String::Handle(isolate, String::New("Metrics")); 1745 String::Handle(isolate, String::New("Metrics"));
2021 ASSERT(!metrics_cls_name.IsNull()); 1746 ASSERT(!metrics_cls_name.IsNull());
2022 const Class& metrics_cls = 1747 const Class& metrics_cls =
2023 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name)); 1748 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name));
2024 ASSERT(!metrics_cls.IsNull()); 1749 ASSERT(!metrics_cls.IsNull());
2025 return metrics_cls.raw(); 1750 return metrics_cls.raw();
2026 } 1751 }
2027 1752
2028 1753
1754
2029 static bool HandleNativeMetricsList(Isolate* isolate, JSONStream* js) { 1755 static bool HandleNativeMetricsList(Isolate* isolate, JSONStream* js) {
2030 JSONObject obj(js); 1756 JSONObject obj(js);
2031 obj.AddProperty("type", "MetricList"); 1757 obj.AddProperty("type", "MetricList");
2032 { 1758 {
2033 JSONArray metrics(&obj, "metrics"); 1759 JSONArray metrics(&obj, "metrics");
2034 Metric* current = isolate->metrics_list_head(); 1760 Metric* current = isolate->metrics_list_head();
2035 while (current != NULL) { 1761 while (current != NULL) {
2036 metrics.AddValue(current); 1762 metrics.AddValue(current);
2037 current = current->next(); 1763 current = current->next();
2038 } 1764 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
2099 ASSERT(result.IsString()); 1825 ASSERT(result.IsString());
2100 TextBuffer* buffer = js->buffer(); 1826 TextBuffer* buffer = js->buffer();
2101 buffer->AddString(String::Cast(result).ToCString()); 1827 buffer->AddString(String::Cast(result).ToCString());
2102 return true; 1828 return true;
2103 } 1829 }
2104 PrintError(js, "Dart Metric %s not found\n", id); 1830 PrintError(js, "Dart Metric %s not found\n", id);
2105 return true; 1831 return true;
2106 } 1832 }
2107 1833
2108 1834
1835 static const MethodParameter* get_metric_list_params[] = {
1836 ISOLATE_PARAMETER,
1837 NULL,
1838 };
1839
1840
2109 static bool HandleIsolateGetMetricList(Isolate* isolate, JSONStream* js) { 1841 static bool HandleIsolateGetMetricList(Isolate* isolate, JSONStream* js) {
2110 bool native_metrics = false; 1842 bool native_metrics = false;
2111 if (js->HasParam("type")) { 1843 if (js->HasParam("type")) {
2112 if (js->ParamIs("type", "Native")) { 1844 if (js->ParamIs("type", "Native")) {
2113 native_metrics = true; 1845 native_metrics = true;
2114 } else if (js->ParamIs("type", "Dart")) { 1846 } else if (js->ParamIs("type", "Dart")) {
2115 native_metrics = false; 1847 native_metrics = false;
2116 } else { 1848 } else {
2117 PrintInvalidParamError(js, "type"); 1849 PrintInvalidParamError(js, "type");
2118 return true; 1850 return true;
2119 } 1851 }
2120 } else { 1852 } else {
2121 PrintMissingParamError(js, "type"); 1853 PrintMissingParamError(js, "type");
2122 return true; 1854 return true;
2123 } 1855 }
2124 if (native_metrics) { 1856 if (native_metrics) {
2125 return HandleNativeMetricsList(isolate, js); 1857 return HandleNativeMetricsList(isolate, js);
2126 } 1858 }
2127 return HandleDartMetricsList(isolate, js); 1859 return HandleDartMetricsList(isolate, js);
2128 } 1860 }
2129 1861
2130 1862
1863 static const MethodParameter* get_metric_params[] = {
1864 ISOLATE_PARAMETER,
1865 NULL,
1866 };
1867
1868
2131 static bool HandleIsolateGetMetric(Isolate* isolate, JSONStream* js) { 1869 static bool HandleIsolateGetMetric(Isolate* isolate, JSONStream* js) {
2132 const char* metric_id = js->LookupParam("metricId"); 1870 const char* metric_id = js->LookupParam("metricId");
2133 if (metric_id == NULL) { 1871 if (metric_id == NULL) {
2134 PrintMissingParamError(js, "metricId"); 1872 PrintMissingParamError(js, "metricId");
2135 return true; 1873 return true;
2136 } 1874 }
2137 // Verify id begins with "metrics/". 1875 // Verify id begins with "metrics/".
2138 static const char* kMetricIdPrefix = "metrics/"; 1876 static const char* kMetricIdPrefix = "metrics/";
2139 static intptr_t kMetricIdPrefixLen = strlen(kMetricIdPrefix); 1877 static intptr_t kMetricIdPrefixLen = strlen(kMetricIdPrefix);
2140 if (strncmp(metric_id, kMetricIdPrefix, kMetricIdPrefixLen) != 0) { 1878 if (strncmp(metric_id, kMetricIdPrefix, kMetricIdPrefixLen) != 0) {
2141 PrintError(js, "Metric %s not found\n", metric_id); 1879 PrintError(js, "Metric %s not found\n", metric_id);
2142 } 1880 }
2143 // Check if id begins with "metrics/native/". 1881 // Check if id begins with "metrics/native/".
2144 static const char* kNativeMetricIdPrefix = "metrics/native/"; 1882 static const char* kNativeMetricIdPrefix = "metrics/native/";
2145 static intptr_t kNativeMetricIdPrefixLen = strlen(kNativeMetricIdPrefix); 1883 static intptr_t kNativeMetricIdPrefixLen = strlen(kNativeMetricIdPrefix);
2146 const bool native_metric = 1884 const bool native_metric =
2147 strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0; 1885 strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0;
2148 if (native_metric) { 1886 if (native_metric) {
2149 const char* id = metric_id + kNativeMetricIdPrefixLen; 1887 const char* id = metric_id + kNativeMetricIdPrefixLen;
2150 return HandleNativeMetric(isolate, js, id); 1888 return HandleNativeMetric(isolate, js, id);
2151 } 1889 }
2152 const char* id = metric_id + kMetricIdPrefixLen; 1890 const char* id = metric_id + kMetricIdPrefixLen;
2153 return HandleDartMetric(isolate, js, id); 1891 return HandleDartMetric(isolate, js, id);
2154 } 1892 }
2155 1893
2156 1894
2157 static bool HandleVMGetMetricList(JSONStream* js) { 1895 static const MethodParameter* get_vm_metric_list_params[] = {
1896 NO_ISOLATE_PARAMETER,
1897 NULL,
1898 };
1899
1900
1901 static bool HandleVMGetMetricList(Isolate* isolate, JSONStream* js) {
2158 return false; 1902 return false;
2159 } 1903 }
2160 1904
2161 1905
2162 static bool HandleVMGetMetric(JSONStream* js) { 1906 static const MethodParameter* get_vm_metric_params[] = {
1907 NO_ISOLATE_PARAMETER,
1908 NULL,
1909 };
1910
1911
1912 static bool HandleVMGetMetric(Isolate* isolate, JSONStream* js) {
2163 const char* metric_id = js->LookupParam("metricId"); 1913 const char* metric_id = js->LookupParam("metricId");
2164 if (metric_id == NULL) { 1914 if (metric_id == NULL) {
2165 PrintMissingParamError(js, "metricId"); 1915 PrintMissingParamError(js, "metricId");
2166 } 1916 }
2167 return false; 1917 return false;
2168 } 1918 }
2169 1919
2170 1920
1921 static const MethodParameter* resume_params[] = {
1922 ISOLATE_PARAMETER,
1923 NULL,
1924 };
1925
1926
2171 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) { 1927 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
2172 const char* step_param = js->LookupParam("step"); 1928 const char* step_param = js->LookupParam("step");
2173 if (isolate->message_handler()->paused_on_start()) { 1929 if (isolate->message_handler()->paused_on_start()) {
2174 isolate->message_handler()->set_pause_on_start(false); 1930 isolate->message_handler()->set_pause_on_start(false);
2175 JSONObject jsobj(js); 1931 JSONObject jsobj(js);
2176 jsobj.AddProperty("type", "Success"); 1932 jsobj.AddProperty("type", "Success");
2177 jsobj.AddProperty("id", ""); 1933 jsobj.AddProperty("id", "");
2178 { 1934 {
2179 DebuggerEvent resumeEvent(isolate, DebuggerEvent::kIsolateResumed); 1935 DebuggerEvent resumeEvent(isolate, DebuggerEvent::kIsolateResumed);
2180 Service::HandleDebuggerEvent(&resumeEvent); 1936 Service::HandleDebuggerEvent(&resumeEvent);
(...skipping 26 matching lines...) Expand all
2207 jsobj.AddProperty("type", "Success"); 1963 jsobj.AddProperty("type", "Success");
2208 jsobj.AddProperty("id", ""); 1964 jsobj.AddProperty("id", "");
2209 return true; 1965 return true;
2210 } 1966 }
2211 1967
2212 PrintError(js, "VM was not paused"); 1968 PrintError(js, "VM was not paused");
2213 return true; 1969 return true;
2214 } 1970 }
2215 1971
2216 1972
1973 static const MethodParameter* get_breakpoints_params[] = {
1974 ISOLATE_PARAMETER,
1975 NULL,
1976 };
1977
1978
2217 static bool HandleIsolateGetBreakpoints(Isolate* isolate, JSONStream* js) { 1979 static bool HandleIsolateGetBreakpoints(Isolate* isolate, JSONStream* js) {
2218 JSONObject jsobj(js); 1980 JSONObject jsobj(js);
2219 jsobj.AddProperty("type", "BreakpointList"); 1981 jsobj.AddProperty("type", "BreakpointList");
2220 JSONArray jsarr(&jsobj, "breakpoints"); 1982 JSONArray jsarr(&jsobj, "breakpoints");
2221 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); 1983 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
2222 return true; 1984 return true;
2223 } 1985 }
2224 1986
2225 1987
1988 static const MethodParameter* pause_params[] = {
1989 ISOLATE_PARAMETER,
1990 NULL,
1991 };
1992
1993
2226 static bool HandleIsolatePause(Isolate* isolate, JSONStream* js) { 1994 static bool HandleIsolatePause(Isolate* isolate, JSONStream* js) {
2227 // TODO(turnidge): Don't double-interrupt the isolate here. 1995 // TODO(turnidge): Don't double-interrupt the isolate here.
2228 isolate->ScheduleInterrupts(Isolate::kApiInterrupt); 1996 isolate->ScheduleInterrupts(Isolate::kApiInterrupt);
2229 JSONObject jsobj(js); 1997 JSONObject jsobj(js);
2230 jsobj.AddProperty("type", "Success"); 1998 jsobj.AddProperty("type", "Success");
2231 jsobj.AddProperty("id", ""); 1999 jsobj.AddProperty("id", "");
2232 return true; 2000 return true;
2233 } 2001 }
2234 2002
2235 2003
2004 static const MethodParameter* get_tag_profile_params[] = {
2005 ISOLATE_PARAMETER,
2006 NULL,
2007 };
2008
2009
2236 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) { 2010 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
2237 JSONObject miniProfile(js); 2011 JSONObject miniProfile(js);
2238 miniProfile.AddProperty("type", "TagProfile"); 2012 miniProfile.AddProperty("type", "TagProfile");
2239 miniProfile.AddProperty("id", "profile/tag"); 2013 miniProfile.AddProperty("id", "profile/tag");
2240 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile); 2014 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile);
2241 return true; 2015 return true;
2242 } 2016 }
2243 2017
2018
2019 static const char* tags_enum_names[] = {
2020 "None",
2021 "UserVM",
2022 "UserOnly",
2023 "VMUser",
2024 "VMOnly",
2025 NULL,
2026 };
2027
2028
2029 static ProfilerService::TagOrder tags_enum_values[] = {
2030 ProfilerService::kNoTags,
2031 ProfilerService::kUserVM,
2032 ProfilerService::kUser,
2033 ProfilerService::kVMUser,
2034 ProfilerService::kVM,
2035 ProfilerService::kNoTags, // Default value.
2036 };
2037
2038
2039 static const MethodParameter* get_cpu_profile_params[] = {
2040 ISOLATE_PARAMETER,
2041 new EnumParameter("tags", true, tags_enum_names),
2042 NULL,
2043 };
2044
2045
2244 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) { 2046 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
2245 ProfilerService::TagOrder tag_order = ProfilerService::kUserVM; 2047 ProfilerService::TagOrder tag_order =
2246 if (js->HasParam("tags")) { 2048 EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
2247 if (js->ParamIs("tags", "None")) {
2248 tag_order = ProfilerService::kNoTags;
2249 } else if (js->ParamIs("tags", "UserVM")) {
2250 tag_order = ProfilerService::kUserVM;
2251 } else if (js->ParamIs("tags", "UserOnly")) {
2252 tag_order = ProfilerService::kUser;
2253 } else if (js->ParamIs("tags", "VMUser")) {
2254 tag_order = ProfilerService::kVMUser;
2255 } else if (js->ParamIs("tags", "VMOnly")) {
2256 tag_order = ProfilerService::kVM;
2257 } else {
2258 PrintInvalidParamError(js, "tags");
2259 return true;
2260 }
2261 }
2262 ProfilerService::PrintJSON(js, tag_order); 2049 ProfilerService::PrintJSON(js, tag_order);
2263 return true; 2050 return true;
2264 } 2051 }
2265 2052
2266 2053
2054 static const MethodParameter* get_allocation_profile_params[] = {
2055 ISOLATE_PARAMETER,
2056 NULL,
2057 };
2058
2059
2267 static bool HandleIsolateGetAllocationProfile(Isolate* isolate, 2060 static bool HandleIsolateGetAllocationProfile(Isolate* isolate,
2268 JSONStream* js) { 2061 JSONStream* js) {
2269 bool should_reset_accumulator = false; 2062 bool should_reset_accumulator = false;
2270 bool should_collect = false; 2063 bool should_collect = false;
2271 if (js->HasParam("reset")) { 2064 if (js->HasParam("reset")) {
2272 if (js->ParamIs("reset", "true")) { 2065 if (js->ParamIs("reset", "true")) {
2273 should_reset_accumulator = true; 2066 should_reset_accumulator = true;
2274 } else { 2067 } else {
2275 PrintInvalidParamError(js, "reset"); 2068 PrintInvalidParamError(js, "reset");
2276 return true; 2069 return true;
(...skipping 13 matching lines...) Expand all
2290 } 2083 }
2291 if (should_collect) { 2084 if (should_collect) {
2292 isolate->UpdateLastAllocationProfileGCTimestamp(); 2085 isolate->UpdateLastAllocationProfileGCTimestamp();
2293 isolate->heap()->CollectAllGarbage(); 2086 isolate->heap()->CollectAllGarbage();
2294 } 2087 }
2295 isolate->class_table()->AllocationProfilePrintJSON(js); 2088 isolate->class_table()->AllocationProfilePrintJSON(js);
2296 return true; 2089 return true;
2297 } 2090 }
2298 2091
2299 2092
2093 static const MethodParameter* get_heap_map_params[] = {
2094 ISOLATE_PARAMETER,
2095 NULL,
2096 };
2097
2098
2300 static bool HandleIsolateGetHeapMap(Isolate* isolate, JSONStream* js) { 2099 static bool HandleIsolateGetHeapMap(Isolate* isolate, JSONStream* js) {
2301 isolate->heap()->PrintHeapMapToJSONStream(isolate, js); 2100 isolate->heap()->PrintHeapMapToJSONStream(isolate, js);
2302 return true; 2101 return true;
2303 } 2102 }
2304 2103
2305 2104
2105 static const MethodParameter* request_heap_snapshot_params[] = {
2106 ISOLATE_PARAMETER,
2107 NULL,
2108 };
2109
2110
2306 static bool HandleIsolateRequestHeapSnapshot(Isolate* isolate, JSONStream* js) { 2111 static bool HandleIsolateRequestHeapSnapshot(Isolate* isolate, JSONStream* js) {
2307 Service::SendGraphEvent(isolate); 2112 Service::SendGraphEvent(isolate);
2308 // TODO(koda): Provide some id that ties this request to async response(s). 2113 // TODO(koda): Provide some id that ties this request to async response(s).
2309 JSONObject jsobj(js); 2114 JSONObject jsobj(js);
2310 jsobj.AddProperty("type", "OK"); 2115 jsobj.AddProperty("type", "OK");
2311 jsobj.AddProperty("id", "ok"); 2116 jsobj.AddProperty("id", "ok");
2312 return true; 2117 return true;
2313 } 2118 }
2314 2119
2315 2120
(...skipping 30 matching lines...) Expand all
2346 } 2151 }
2347 uword obj_begin = RawObject::ToAddr(obj); 2152 uword obj_begin = RawObject::ToAddr(obj);
2348 uword obj_end = obj_begin + obj->Size(); 2153 uword obj_end = obj_begin + obj->Size();
2349 return obj_begin <= addr_ && addr_ < obj_end; 2154 return obj_begin <= addr_ && addr_ < obj_end;
2350 } 2155 }
2351 private: 2156 private:
2352 uword addr_; 2157 uword addr_;
2353 }; 2158 };
2354 2159
2355 2160
2161 static const MethodParameter* get_object_by_address_params[] = {
2162 ISOLATE_PARAMETER,
2163 NULL,
2164 };
2165
2166
2356 static bool HandleIsolateGetObjectByAddress(Isolate* isolate, JSONStream* js) { 2167 static bool HandleIsolateGetObjectByAddress(Isolate* isolate, JSONStream* js) {
2357 const char* addr_str = js->LookupParam("address"); 2168 const char* addr_str = js->LookupParam("address");
2358 if (addr_str == NULL) { 2169 if (addr_str == NULL) {
2359 PrintMissingParamError(js, "address"); 2170 PrintMissingParamError(js, "address");
2360 return true; 2171 return true;
2361 } 2172 }
2362 2173
2363 // Handle heap objects. 2174 // Handle heap objects.
2364 uword addr = 0; 2175 uword addr = 0;
2365 if (!GetUnsignedIntegerId(addr_str, &addr, 16)) { 2176 if (!GetUnsignedIntegerId(addr_str, &addr, 16)) {
(...skipping 27 matching lines...) Expand all
2393 2204
2394 2205
2395 static bool HandleIsolateRespondWithMalformedObject(Isolate* isolate, 2206 static bool HandleIsolateRespondWithMalformedObject(Isolate* isolate,
2396 JSONStream* js) { 2207 JSONStream* js) {
2397 JSONObject jsobj(js); 2208 JSONObject jsobj(js);
2398 jsobj.AddProperty("bart", "simpson"); 2209 jsobj.AddProperty("bart", "simpson");
2399 return true; 2210 return true;
2400 } 2211 }
2401 2212
2402 2213
2214 static const MethodParameter* get_object_params[] = {
2215 ISOLATE_PARAMETER,
2216 NULL,
2217 };
2218
2219
2403 static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) { 2220 static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) {
2404 const char* id = js->LookupParam("objectId"); 2221 const char* id = js->LookupParam("objectId");
2405 if (id == NULL) { 2222 if (id == NULL) {
2406 PrintMissingParamError(js, "objectId"); 2223 PrintMissingParamError(js, "objectId");
2407 return true; 2224 return true;
2408 } 2225 }
2409 2226
2410 // Handle heap objects. 2227 // Handle heap objects.
2411 ObjectIdRing::LookupResult lookup_result; 2228 ObjectIdRing::LookupResult lookup_result;
2412 const Object& obj = 2229 const Object& obj =
(...skipping 15 matching lines...) Expand all
2428 if (bpt != NULL) { 2245 if (bpt != NULL) {
2429 bpt->PrintJSON(js); 2246 bpt->PrintJSON(js);
2430 return true; 2247 return true;
2431 } 2248 }
2432 2249
2433 PrintError(js, "Unrecognized object id: %s\n", id); 2250 PrintError(js, "Unrecognized object id: %s\n", id);
2434 return true; 2251 return true;
2435 } 2252 }
2436 2253
2437 2254
2255 static const MethodParameter* get_class_list_params[] = {
2256 ISOLATE_PARAMETER,
2257 NULL,
2258 };
2259
2260
2438 static bool HandleIsolateGetClassList(Isolate* isolate, JSONStream* js) { 2261 static bool HandleIsolateGetClassList(Isolate* isolate, JSONStream* js) {
2439 ClassTable* table = isolate->class_table(); 2262 ClassTable* table = isolate->class_table();
2440 JSONObject jsobj(js); 2263 JSONObject jsobj(js);
2441 table->PrintToJSONObject(&jsobj); 2264 table->PrintToJSONObject(&jsobj);
2442 return true; 2265 return true;
2443 } 2266 }
2444 2267
2445 2268
2269 static const MethodParameter* get_type_arguments_list_params[] = {
2270 ISOLATE_PARAMETER,
2271 NULL,
2272 };
2273
2274
2446 static bool HandleIsolateGetTypeArgumentsList(Isolate* isolate, 2275 static bool HandleIsolateGetTypeArgumentsList(Isolate* isolate,
2447 JSONStream* js) { 2276 JSONStream* js) {
2448 bool only_with_instantiations = false; 2277 bool only_with_instantiations = false;
2449 if (js->ParamIs("onlyWithInstantiations", "true")) { 2278 if (js->ParamIs("onlyWithInstantiations", "true")) {
2450 only_with_instantiations = true; 2279 only_with_instantiations = true;
2451 } 2280 }
2452 ObjectStore* object_store = isolate->object_store(); 2281 ObjectStore* object_store = isolate->object_store();
2453 const Array& table = Array::Handle(object_store->canonical_type_arguments()); 2282 const Array& table = Array::Handle(object_store->canonical_type_arguments());
2454 ASSERT(table.Length() > 0); 2283 ASSERT(table.Length() > 0);
2455 TypeArguments& type_args = TypeArguments::Handle(); 2284 TypeArguments& type_args = TypeArguments::Handle();
2456 const intptr_t table_size = table.Length() - 1; 2285 const intptr_t table_size = table.Length() - 1;
2457 const intptr_t table_used = Smi::Value(Smi::RawCast(table.At(table_size))); 2286 const intptr_t table_used = Smi::Value(Smi::RawCast(table.At(table_size)));
2458 JSONObject jsobj(js); 2287 JSONObject jsobj(js);
2459 jsobj.AddProperty("type", "TypeArgumentsList"); 2288 jsobj.AddProperty("type", "TypeArgumentsList");
2460 jsobj.AddProperty("canonicalTypeArgumentsTableSize", table_size); 2289 jsobj.AddProperty("canonicalTypeArgumentsTableSize", table_size);
2461 jsobj.AddProperty("canonicalTypeArgumentsTableUsed", table_used); 2290 jsobj.AddProperty("canonicalTypeArgumentsTableUsed", table_used);
2462 JSONArray members(&jsobj, "typeArguments"); 2291 JSONArray members(&jsobj, "typeArguments");
2463 for (intptr_t i = 0; i < table_size; i++) { 2292 for (intptr_t i = 0; i < table_size; i++) {
2464 type_args ^= table.At(i); 2293 type_args ^= table.At(i);
2465 if (!type_args.IsNull()) { 2294 if (!type_args.IsNull()) {
2466 if (!only_with_instantiations || type_args.HasInstantiations()) { 2295 if (!only_with_instantiations || type_args.HasInstantiations()) {
2467 members.AddValue(type_args); 2296 members.AddValue(type_args);
2468 } 2297 }
2469 } 2298 }
2470 } 2299 }
2471 return true; 2300 return true;
2472 } 2301 }
2473 2302
2474 2303
2475 static IsolateMessageHandlerEntry isolate_handlers_new[] = {
2476 { "getIsolate", HandleIsolate },
2477 { "getObject", HandleIsolateGetObject },
2478 { "getObjectByAddress", HandleIsolateGetObjectByAddress },
2479 { "getBreakpoints", HandleIsolateGetBreakpoints },
2480 { "pause", HandleIsolatePause },
2481 { "resume", HandleIsolateResume },
2482 { "getStack", HandleIsolateGetStack },
2483 { "getCpuProfile", HandleIsolateGetCpuProfile },
2484 { "getTagProfile", HandleIsolateGetTagProfile },
2485 { "getAllocationProfile", HandleIsolateGetAllocationProfile },
2486 { "getHeapMap", HandleIsolateGetHeapMap },
2487 { "addBreakpoint", HandleIsolateAddBreakpoint },
2488 { "removeBreakpoint", HandleIsolateRemoveBreakpoint },
2489 { "getCoverage", HandleIsolateGetCoverage },
2490 { "eval", HandleIsolateEval },
2491 { "getRetainedSize", HandleIsolateGetRetainedSize },
2492 { "getRetainingPath", HandleIsolateGetRetainingPath },
2493 { "getInboundReferences", HandleIsolateGetInboundReferences },
2494 { "getInstances", HandleIsolateGetInstances },
2495 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot },
2496 { "getClassList", HandleIsolateGetClassList },
2497 { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList },
2498 { "getIsolateMetricList", HandleIsolateGetMetricList },
2499 { "getIsolateMetric", HandleIsolateGetMetric },
2500 { "_echo", HandleIsolateEcho },
2501 { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent },
2502 { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson },
2503 { "_respondWithMalformedObject", HandleIsolateRespondWithMalformedObject },
2504 };
2505
2506
2507 static IsolateMessageHandler FindIsolateMessageHandler(const char* method) {
2508 intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
2509 sizeof(isolate_handlers_new[0]);
2510 for (intptr_t i = 0; i < num_message_handlers; i++) {
2511 const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
2512 if (strcmp(method, entry.method) == 0) {
2513 return entry.handler;
2514 }
2515 }
2516 if (FLAG_trace_service) {
2517 OS::Print("Service has no isolate message handler for <%s>\n", method);
2518 }
2519 return NULL;
2520 }
2521
2522
2523 void Service::HandleRootMessage(const Instance& msg_instance) {
2524 Isolate* isolate = Isolate::Current();
2525 ASSERT(!msg_instance.IsNull());
2526 ASSERT(msg_instance.IsArray());
2527
2528 {
2529 StackZone zone(isolate);
2530 HANDLESCOPE(isolate);
2531
2532 const Array& msg = Array::Cast(msg_instance);
2533 ASSERT(msg.Length() == 5);
2534
2535 Instance& reply_port = Instance::Handle(isolate);
2536 String& method = String::Handle(isolate);
2537 Array& param_keys = Array::Handle(isolate);
2538 Array& param_values = Array::Handle(isolate);
2539 reply_port ^= msg.At(1);
2540 method ^= msg.At(2);
2541 param_keys ^= msg.At(3);
2542 param_values ^= msg.At(4);
2543
2544 ASSERT(!method.IsNull());
2545 ASSERT(!param_keys.IsNull());
2546 ASSERT(!param_values.IsNull());
2547 ASSERT(param_keys.Length() == param_values.Length());
2548
2549 if (!reply_port.IsSendPort()) {
2550 FATAL("SendPort expected.");
2551 }
2552
2553 RootMessageHandler handler =
2554 FindRootMessageHandler(method.ToCString());
2555 {
2556 JSONStream js;
2557 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
2558 method, param_keys, param_values);
2559 if (handler == NULL) {
2560 // Check for an embedder handler.
2561 EmbedderServiceHandler* e_handler =
2562 FindRootEmbedderHandler(method.ToCString());
2563 if (e_handler != NULL) {
2564 EmbedderHandleMessage(e_handler, &js);
2565 } else {
2566 if (FindIsolateMessageHandler(method.ToCString()) != NULL) {
2567 PrintMissingParamError(&js, "isolateId");
2568 } else {
2569 PrintError(&js, "Unrecognized method: %s", method.ToCString());
2570 }
2571 }
2572 js.PostReply();
2573 } else {
2574 if (handler(&js)) {
2575 // Handler returns true if the reply is ready to be posted.
2576 // TODO(johnmccutchan): Support asynchronous replies.
2577 js.PostReply();
2578 }
2579 }
2580 }
2581 }
2582 }
2583
2584
2585 static bool HandleRootEcho(JSONStream* js) {
2586 JSONObject jsobj(js);
2587 return HandleCommonEcho(&jsobj, js);
2588 }
2589
2590
2591 class ServiceIsolateVisitor : public IsolateVisitor { 2304 class ServiceIsolateVisitor : public IsolateVisitor {
2592 public: 2305 public:
2593 explicit ServiceIsolateVisitor(JSONArray* jsarr) 2306 explicit ServiceIsolateVisitor(JSONArray* jsarr)
2594 : jsarr_(jsarr) { 2307 : jsarr_(jsarr) {
2595 } 2308 }
2596 2309
2597 virtual ~ServiceIsolateVisitor() {} 2310 virtual ~ServiceIsolateVisitor() {}
2598 2311
2599 void VisitIsolate(Isolate* isolate) { 2312 void VisitIsolate(Isolate* isolate) {
2600 if (isolate != Dart::vm_isolate() && !Service::IsServiceIsolate(isolate)) { 2313 if ((isolate != Dart::vm_isolate()) &&
2314 !ServiceIsolate::IsServiceIsolate(isolate)) {
2601 jsarr_->AddValue(isolate); 2315 jsarr_->AddValue(isolate);
2602 } 2316 }
2603 } 2317 }
2604 2318
2605 private: 2319 private:
2606 JSONArray* jsarr_; 2320 JSONArray* jsarr_;
2607 }; 2321 };
2608 2322
2609 2323
2610 static bool HandleVM(JSONStream* js) { 2324 static const MethodParameter* get_vm_params[] = {
2611 Isolate* isolate = Isolate::Current(); 2325 NO_ISOLATE_PARAMETER,
2326 NULL,
2327 };
2328
2329
2330 static bool HandleVM(Isolate* isolate, JSONStream* js) {
2612 JSONObject jsobj(js); 2331 JSONObject jsobj(js);
2613 jsobj.AddProperty("type", "VM"); 2332 jsobj.AddProperty("type", "VM");
2614 jsobj.AddProperty("id", "vm"); 2333 jsobj.AddProperty("id", "vm");
2615 jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord)); 2334 jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord));
2616 jsobj.AddProperty("targetCPU", CPU::Id()); 2335 jsobj.AddProperty("targetCPU", CPU::Id());
2617 jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware()); 2336 jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
2618 jsobj.AddPropertyF("date", "%" Pd64 "", OS::GetCurrentTimeMillis()); 2337 jsobj.AddPropertyF("date", "%" Pd64 "", OS::GetCurrentTimeMillis());
2619 jsobj.AddProperty("version", Version::String()); 2338 jsobj.AddProperty("version", Version::String());
2620 // Send pid as a string because it allows us to avoid any issues with 2339 // Send pid as a string because it allows us to avoid any issues with
2621 // pids > 53-bits (when consumed by JavaScript). 2340 // pids > 53-bits (when consumed by JavaScript).
(...skipping 10 matching lines...) Expand all
2632 // Construct the isolate list. 2351 // Construct the isolate list.
2633 { 2352 {
2634 JSONArray jsarr(&jsobj, "isolates"); 2353 JSONArray jsarr(&jsobj, "isolates");
2635 ServiceIsolateVisitor visitor(&jsarr); 2354 ServiceIsolateVisitor visitor(&jsarr);
2636 Isolate::VisitIsolates(&visitor); 2355 Isolate::VisitIsolates(&visitor);
2637 } 2356 }
2638 return true; 2357 return true;
2639 } 2358 }
2640 2359
2641 2360
2642 static bool HandleVMFlagList(JSONStream* js) { 2361 static const MethodParameter* get_flag_list_params[] = {
2362 NO_ISOLATE_PARAMETER,
2363 NULL,
2364 };
2365
2366
2367 static bool HandleVMFlagList(Isolate* isolate, JSONStream* js) {
2643 Flags::PrintJSON(js); 2368 Flags::PrintJSON(js);
2644 return true; 2369 return true;
2645 } 2370 }
2646 2371
2647 2372
2648 static bool HandleVMSetFlag(JSONStream* js) { 2373 static const MethodParameter* set_flags_params[] = {
2374 NO_ISOLATE_PARAMETER,
2375 NULL,
2376 };
2377
2378
2379 static bool HandleVMSetFlag(Isolate* isolate, JSONStream* js) {
2649 const char* flag_name = js->LookupParam("name"); 2380 const char* flag_name = js->LookupParam("name");
2650 if (flag_name == NULL) { 2381 if (flag_name == NULL) {
2651 PrintMissingParamError(js, "name"); 2382 PrintMissingParamError(js, "name");
2652 return true; 2383 return true;
2653 } 2384 }
2654 const char* flag_value = js->LookupParam("value"); 2385 const char* flag_value = js->LookupParam("value");
2655 if (flag_value == NULL) { 2386 if (flag_value == NULL) {
2656 PrintMissingParamError(js, "value"); 2387 PrintMissingParamError(js, "value");
2657 return true; 2388 return true;
2658 } 2389 }
2659 JSONObject jsobj(js); 2390 JSONObject jsobj(js);
2660 const char* error = NULL; 2391 const char* error = NULL;
2661 if (Flags::SetFlag(flag_name, flag_value, &error)) { 2392 if (Flags::SetFlag(flag_name, flag_value, &error)) {
2662 jsobj.AddProperty("type", "Success"); 2393 jsobj.AddProperty("type", "Success");
2663 jsobj.AddProperty("id", ""); 2394 jsobj.AddProperty("id", "");
2664 return true; 2395 return true;
2665 } else { 2396 } else {
2666 jsobj.AddProperty("type", "Failure"); 2397 jsobj.AddProperty("type", "Failure");
2667 jsobj.AddProperty("id", ""); 2398 jsobj.AddProperty("id", "");
2668 jsobj.AddProperty("message", error); 2399 jsobj.AddProperty("message", error);
2669 return true; 2400 return true;
2670 } 2401 }
2671 } 2402 }
2672 2403
2673 2404
2674 static RootMessageHandlerEntry root_handlers_new[] = { 2405 static ServiceMethodDescriptor service_methods_[] = {
2675 { "getVM", HandleVM }, 2406 { "_echo", HandleIsolateEcho,
2676 { "getFlagList", HandleVMFlagList }, 2407 NULL },
2677 { "setFlag", HandleVMSetFlag }, 2408 { "_respondWithMalformedJson", HandleIsolateRespondWithMalformedJson,
2678 { "getVMMetricList", HandleVMGetMetricList }, 2409 NULL },
2679 { "getVMMetric", HandleVMGetMetric }, 2410 { "_respondWithMalformedObject", HandleIsolateRespondWithMalformedObject,
2680 { "_echo", HandleRootEcho }, 2411 NULL },
2412 { "_triggerEchoEvent", HandleIsolateTriggerEchoEvent,
2413 NULL },
2414 { "addBreakpoint", HandleIsolateAddBreakpoint,
2415 add_breakpoint_params },
2416 { "eval", HandleIsolateEval,
2417 eval_params },
2418 { "getAllocationProfile", HandleIsolateGetAllocationProfile,
2419 get_allocation_profile_params },
2420 { "getBreakpoints", HandleIsolateGetBreakpoints,
2421 get_breakpoints_params },
2422 { "getClassList", HandleIsolateGetClassList,
2423 get_class_list_params },
2424 { "getCoverage", HandleIsolateGetCoverage,
2425 get_coverage_params },
2426 { "getCpuProfile", HandleIsolateGetCpuProfile,
2427 get_cpu_profile_params },
2428 { "getFlagList", HandleVMFlagList ,
2429 get_flag_list_params },
2430 { "getHeapMap", HandleIsolateGetHeapMap,
2431 get_heap_map_params },
2432 { "getInboundReferences", HandleIsolateGetInboundReferences,
2433 get_inbound_references_params },
2434 { "getInstances", HandleIsolateGetInstances,
2435 get_instances_params },
2436 { "getIsolate", HandleIsolate,
2437 get_isolate_params },
2438 { "getIsolateMetric", HandleIsolateGetMetric,
2439 get_metric_params },
2440 { "getIsolateMetricList", HandleIsolateGetMetricList,
2441 get_metric_list_params },
2442 { "getObject", HandleIsolateGetObject,
2443 get_object_params },
2444 { "getObjectByAddress", HandleIsolateGetObjectByAddress,
2445 get_object_by_address_params },
2446 { "getRetainedSize", HandleIsolateGetRetainedSize,
2447 get_retained_size_params },
2448 { "getRetainingPath", HandleIsolateGetRetainingPath,
2449 get_retaining_path_params },
2450 { "getStack", HandleIsolateGetStack,
2451 get_stack_params },
2452 { "getTagProfile", HandleIsolateGetTagProfile,
2453 get_tag_profile_params },
2454 { "getTypeArgumentsList", HandleIsolateGetTypeArgumentsList,
2455 get_type_arguments_list_params },
2456 { "getVM", HandleVM ,
2457 get_vm_params },
2458 { "getVMMetric", HandleVMGetMetric,
2459 get_vm_metric_params },
2460 { "getVMMetricList", HandleVMGetMetricList,
2461 get_vm_metric_list_params },
2462 { "pause", HandleIsolatePause,
2463 pause_params },
2464 { "removeBreakpoint", HandleIsolateRemoveBreakpoint,
2465 remove_breakpoint_params },
2466 { "resume", HandleIsolateResume,
2467 resume_params },
2468 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot,
2469 request_heap_snapshot_params },
2470 { "setFlag", HandleVMSetFlag ,
2471 set_flags_params },
2681 }; 2472 };
2682 2473
2683 2474
2684 static RootMessageHandler FindRootMessageHandler(const char* method) { 2475 ServiceMethodDescriptor* FindMethod(const char* method_name) {
2685 intptr_t num_message_handlers = sizeof(root_handlers_new) / 2476 intptr_t num_methods = sizeof(service_methods_) /
2686 sizeof(root_handlers_new[0]); 2477 sizeof(service_methods_[0]);
2687 for (intptr_t i = 0; i < num_message_handlers; i++) { 2478 for (intptr_t i = 0; i < num_methods; i++) {
2688 const RootMessageHandlerEntry& entry = root_handlers_new[i]; 2479 ServiceMethodDescriptor& method = service_methods_[i];
2689 if (strcmp(method, entry.method) == 0) { 2480 if (strcmp(method_name, method.name) == 0) {
2690 return entry.handler; 2481 return &method;
2691 } 2482 }
2692 } 2483 }
2693 if (FLAG_trace_service) {
2694 OS::Print("vm-service: No root message handler for <%s>.\n", method);
2695 }
2696 return NULL; 2484 return NULL;
2697 } 2485 }
2698 2486
2699 2487
2700 void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
2701 if (!IsRunning()) {
2702 return;
2703 }
2704 Isolate* isolate = Isolate::Current();
2705 ASSERT(isolate != NULL);
2706 HANDLESCOPE(isolate);
2707
2708 // Construct a list of the form [eventId, eventMessage].
2709 const Array& list = Array::Handle(Array::New(2));
2710 ASSERT(!list.IsNull());
2711 list.SetAt(0, Integer::Handle(Integer::New(eventId)));
2712 list.SetAt(1, eventMessage);
2713
2714 // Push the event to port_.
2715 uint8_t* data = NULL;
2716 MessageWriter writer(&data, &allocator, false);
2717 writer.WriteMessage(list);
2718 intptr_t len = writer.BytesWritten();
2719 if (FLAG_trace_service) {
2720 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
2721 eventId, len);
2722 }
2723 // TODO(turnidge): For now we ignore failure to send an event. Revisit?
2724 PortMap::PostMessage(
2725 new Message(service_port_, data, len, Message::kNormalPriority));
2726 }
2727
2728
2729 void Service::SendEvent(intptr_t eventId,
2730 const String& meta,
2731 const uint8_t* data,
2732 intptr_t size) {
2733 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
2734 const intptr_t meta_bytes = Utf8::Length(meta);
2735 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
2736 const TypedData& message = TypedData::Handle(
2737 TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
2738 intptr_t offset = 0;
2739 // TODO(koda): Rename these methods SetHostUint64, etc.
2740 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
2741 offset += sizeof(uint64_t);
2742 {
2743 NoGCScope no_gc;
2744 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
2745 offset += meta_bytes;
2746 }
2747 // TODO(koda): It would be nice to avoid this copy (requires changes to
2748 // MessageWriter code).
2749 {
2750 NoGCScope no_gc;
2751 memmove(message.DataAddr(offset), data, size);
2752 offset += size;
2753 }
2754 ASSERT(offset == total_bytes);
2755 SendEvent(eventId, message);
2756 }
2757
2758
2759 void Service::HandleGCEvent(GCEvent* event) {
2760 JSONStream js;
2761 event->PrintJSON(&js);
2762 const String& message = String::Handle(String::New(js.ToCString()));
2763 SendEvent(kEventFamilyGC, message);
2764 }
2765
2766
2767 void Service::HandleDebuggerEvent(DebuggerEvent* event) {
2768 JSONStream js;
2769 event->PrintJSON(&js);
2770 const String& message = String::Handle(String::New(js.ToCString()));
2771 SendEvent(kEventFamilyDebug, message);
2772 }
2773
2774
2775 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
2776 JSONStream* js) {
2777 ASSERT(handler != NULL);
2778 Dart_ServiceRequestCallback callback = handler->callback();
2779 ASSERT(callback != NULL);
2780 const char* r = NULL;
2781 const char* name = js->method();
2782 const char** keys = js->param_keys();
2783 const char** values = js->param_values();
2784 r = callback(name, keys, values, js->num_params(), handler->user_data());
2785 ASSERT(r != NULL);
2786 // TODO(johnmccutchan): Allow for NULL returns?
2787 TextBuffer* buffer = js->buffer();
2788 buffer->AddString(r);
2789 free(const_cast<char*>(r));
2790 }
2791
2792
2793 void Service::RegisterIsolateEmbedderCallback(
2794 const char* name,
2795 Dart_ServiceRequestCallback callback,
2796 void* user_data) {
2797 if (name == NULL) {
2798 return;
2799 }
2800 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
2801 if (handler != NULL) {
2802 // Update existing handler entry.
2803 handler->set_callback(callback);
2804 handler->set_user_data(user_data);
2805 return;
2806 }
2807 // Create a new handler.
2808 handler = new EmbedderServiceHandler(name);
2809 handler->set_callback(callback);
2810 handler->set_user_data(user_data);
2811
2812 // Insert into isolate_service_handler_head_ list.
2813 handler->set_next(isolate_service_handler_head_);
2814 isolate_service_handler_head_ = handler;
2815 }
2816
2817
2818 EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(
2819 const char* name) {
2820 EmbedderServiceHandler* current = isolate_service_handler_head_;
2821 while (current != NULL) {
2822 if (strcmp(name, current->name()) == 0) {
2823 return current;
2824 }
2825 current = current->next();
2826 }
2827 return NULL;
2828 }
2829
2830
2831 void Service::RegisterRootEmbedderCallback(
2832 const char* name,
2833 Dart_ServiceRequestCallback callback,
2834 void* user_data) {
2835 if (name == NULL) {
2836 return;
2837 }
2838 EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
2839 if (handler != NULL) {
2840 // Update existing handler entry.
2841 handler->set_callback(callback);
2842 handler->set_user_data(user_data);
2843 return;
2844 }
2845 // Create a new handler.
2846 handler = new EmbedderServiceHandler(name);
2847 handler->set_callback(callback);
2848 handler->set_user_data(user_data);
2849
2850 // Insert into root_service_handler_head_ list.
2851 handler->set_next(root_service_handler_head_);
2852 root_service_handler_head_ = handler;
2853 }
2854
2855
2856 EmbedderServiceHandler* Service::FindRootEmbedderHandler(
2857 const char* name) {
2858 EmbedderServiceHandler* current = root_service_handler_head_;
2859 while (current != NULL) {
2860 if (strcmp(name, current->name()) == 0) {
2861 return current;
2862 }
2863 current = current->next();
2864 }
2865 return NULL;
2866 }
2867
2868 } // namespace dart 2488 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/service.h ('k') | runtime/vm/service_isolate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698