OLD | NEW |
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 Loading... |
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(®ister_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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |