Flutter Engine
The Flutter Engine
service.cc
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/service.h"
6
7#include <memory>
8#include <utility>
9
10#include "include/dart_api.h"
12#include "platform/globals.h"
13
14#include "platform/unicode.h"
15#include "platform/utils.h"
16#include "vm/base64.h"
17#include "vm/canonical_tables.h"
20#include "vm/cpu.h"
21#include "vm/dart_api_impl.h"
22#include "vm/dart_api_message.h"
23#include "vm/dart_api_state.h"
24#include "vm/dart_entry.h"
25#include "vm/debugger.h"
26#include "vm/heap/safepoint.h"
27#include "vm/isolate.h"
28#include "vm/kernel_isolate.h"
29#include "vm/lockers.h"
30#include "vm/message.h"
31#include "vm/message_handler.h"
32#include "vm/message_snapshot.h"
33#include "vm/native_arguments.h"
34#include "vm/native_entry.h"
35#include "vm/native_symbol.h"
36#include "vm/object.h"
37#include "vm/object_graph.h"
38#include "vm/object_id_ring.h"
39#include "vm/object_store.h"
40#include "vm/parser.h"
41#include "vm/port.h"
42#include "vm/profiler.h"
43#include "vm/profiler_service.h"
45#include "vm/resolver.h"
46#include "vm/reusable_handles.h"
47#include "vm/service_event.h"
48#include "vm/service_isolate.h"
49#include "vm/source_report.h"
50#include "vm/stack_frame.h"
51#include "vm/symbols.h"
52#include "vm/timeline.h"
53#include "vm/version.h"
54
55#if defined(SUPPORT_PERFETTO)
56#include "vm/perfetto_utils.h"
57#endif // defined(SUPPORT_PERFETTO)
58
59namespace dart {
60
61#define Z (T->zone())
62
63DECLARE_FLAG(bool, trace_service);
64DECLARE_FLAG(bool, trace_service_pause_events);
65DECLARE_FLAG(bool, profile_vm);
67 vm_name,
68 "vm",
69 "The default name of this vm as reported by the VM service "
70 "protocol");
71
73 warn_on_pause_with_no_debugger,
74 false,
75 "Print a message when an isolate is paused but there is no "
76 "debugger attached.");
77
79 charp,
80 log_service_response_sizes,
81 nullptr,
82 "Log sizes of service responses and events to a file in CSV format.");
83
84void* Service::service_response_size_log_file_ = nullptr;
85
86void Service::LogResponseSize(const char* method, JSONStream* js) {
87 if (service_response_size_log_file_ == nullptr) {
88 return;
89 }
91 char* entry =
92 OS::SCreate(nullptr, "%s, %" Pd "\n", method, js->buffer()->length());
93 (*file_write)(entry, strlen(entry), service_response_size_log_file_);
94 free(entry);
95}
96
98 if (FLAG_log_service_response_sizes == nullptr) {
99 return;
100 }
104 if ((file_open == nullptr) || (file_write == nullptr) ||
105 (file_close == nullptr)) {
106 OS::PrintErr("Error: Could not access file callbacks.");
107 UNREACHABLE();
108 }
109 ASSERT(service_response_size_log_file_ == nullptr);
110 service_response_size_log_file_ =
111 (*file_open)(FLAG_log_service_response_sizes, true);
112 if (service_response_size_log_file_ == nullptr) {
113 OS::PrintErr("Warning: Failed to open service response size log file: %s\n",
114 FLAG_log_service_response_sizes);
115 return;
116 }
117}
118
120 if (service_response_size_log_file_ == nullptr) {
121 return;
122 }
124 (*file_close)(service_response_size_log_file_);
125 service_response_size_log_file_ = nullptr;
126}
127
128static void PrintInvalidParamError(JSONStream* js, const char* param) {
129#if !defined(PRODUCT)
130 js->PrintError(kInvalidParams, "%s: invalid '%s' parameter: %s", js->method(),
131 param, js->LookupParam(param));
132#endif
133}
134
135// TODO(johnmccutchan): Split into separate file and write unit tests.
137 public:
138 MethodParameter(const char* name, bool required)
139 : name_(name), required_(required) {}
140
141 virtual ~MethodParameter() {}
142
143 virtual bool Validate(const char* value) const { return true; }
144
145 virtual bool ValidateObject(const Object& value) const { return true; }
146
147 const char* name() const { return name_; }
148
149 bool required() const { return required_; }
150
151 virtual void PrintError(const char* name,
152 const char* value,
153 JSONStream* js) const {
155 }
156
157 virtual void PrintErrorObject(const char* name,
158 const Object& value,
159 JSONStream* js) const {
161 }
162
163 private:
164 const char* name_;
165 bool required_;
166};
167
169 public:
170 explicit NoSuchParameter(const char* name) : MethodParameter(name, false) {}
171
172 virtual bool Validate(const char* value) const { return (value == nullptr); }
173
174 virtual bool ValidateObject(const Object& value) const {
175 return value.IsNull();
176 }
177};
178
179#define ISOLATE_PARAMETER new IdParameter("isolateId", true)
180#define ISOLATE_GROUP_PARAMETER new IdParameter("isolateGroupId", true)
181#define NO_ISOLATE_PARAMETER new NoSuchParameter("isolateId")
182#define RUNNABLE_ISOLATE_PARAMETER new RunnableIsolateParameter("isolateId")
183#define OBJECT_PARAMETER new IdParameter("objectId", true)
184
186 public:
187 EnumListParameter(const char* name, bool required, const char* const* enums)
188 : MethodParameter(name, required), enums_(enums) {}
189
190 virtual bool Validate(const char* value) const {
191 return ElementCount(value) >= 0;
192 }
193
194 const char** Parse(char* value) const {
195 const char* kJsonChars = " \t\r\n[,]";
196
197 // Make a writeable copy of the value.
198 intptr_t element_count = ElementCount(value);
199 if (element_count < 0) {
200 return nullptr;
201 }
202 intptr_t element_pos = 0;
203
204 // Allocate our element array. +1 for nullptr terminator.
205 // The caller is responsible for deleting this memory.
206 char** elements = new char*[element_count + 1];
207 elements[element_count] = nullptr;
208
209 // Parse the string destructively. Build the list of elements.
210 while (element_pos < element_count) {
211 // Skip to the next element.
212 value += strspn(value, kJsonChars);
213
214 intptr_t len = strcspn(value, kJsonChars);
215 ASSERT(len > 0); // We rely on the parameter being validated already.
216 value[len] = '\0';
217 elements[element_pos++] = value;
218
219 // Advance. +1 for null terminator.
220 value += (len + 1);
221 }
222 return const_cast<const char**>(elements);
223 }
224
225 private:
226 // For now observatory enums are ascii letters plus underscore.
227 static bool IsEnumChar(char c) {
228 return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ||
229 (c == '_'));
230 }
231
232 // Returns number of elements in the list. -1 on parse error.
233 intptr_t ElementCount(const char* value) const {
234 const char* kJsonWhitespaceChars = " \t\r\n";
235 if (value == nullptr) {
236 return -1;
237 }
238 const char* cp = value;
239 cp += strspn(cp, kJsonWhitespaceChars);
240 if (*cp++ != '[') {
241 // Missing initial [.
242 return -1;
243 }
244 bool closed = false;
245 bool element_allowed = true;
246 intptr_t element_count = 0;
247 while (true) {
248 // Skip json whitespace.
249 cp += strspn(cp, kJsonWhitespaceChars);
250 switch (*cp) {
251 case '\0':
252 return closed ? element_count : -1;
253 case ']':
254 closed = true;
255 cp++;
256 break;
257 case ',':
258 if (element_allowed) {
259 return -1;
260 }
261 element_allowed = true;
262 cp++;
263 break;
264 default:
265 if (!element_allowed) {
266 return -1;
267 }
268 bool valid_enum = false;
269 const char* id_start = cp;
270 while (IsEnumChar(*cp)) {
271 cp++;
272 }
273 if (cp == id_start) {
274 // Empty identifier, something like this [,].
275 return -1;
276 }
277 intptr_t id_len = cp - id_start;
278 if (enums_ != nullptr) {
279 for (intptr_t i = 0; enums_[i] != nullptr; i++) {
280 intptr_t len = strlen(enums_[i]);
281 if (len == id_len && strncmp(id_start, enums_[i], len) == 0) {
282 element_count++;
283 valid_enum = true;
284 element_allowed = false; // we need a comma first.
285 break;
286 }
287 }
288 }
289 if (!valid_enum) {
290 return -1;
291 }
292 break;
293 }
294 }
295 }
296
297 const char* const* enums_;
298};
299
300#if defined(SUPPORT_TIMELINE)
301static const char* const timeline_streams_enum_names[] = {
302 "all",
303#define DEFINE_NAME(name, ...) #name,
304 TIMELINE_STREAM_LIST(DEFINE_NAME)
305#undef DEFINE_NAME
306 nullptr};
307
308static const MethodParameter* const set_vm_timeline_flags_params[] = {
310 new EnumListParameter("recordedStreams",
311 false,
312 timeline_streams_enum_names),
313 nullptr,
314};
315
316static bool HasStream(const char** recorded_streams, const char* stream) {
317 while (*recorded_streams != nullptr) {
318 if ((strstr(*recorded_streams, "all") != nullptr) ||
319 (strstr(*recorded_streams, stream) != nullptr)) {
320 return true;
321 }
322 recorded_streams++;
323 }
324 return false;
325}
326
327bool Service::EnableTimelineStreams(char* categories_list) {
328 const EnumListParameter* recorded_streams_param =
329 static_cast<const EnumListParameter*>(set_vm_timeline_flags_params[1]);
330 const char** streams = recorded_streams_param->Parse(categories_list);
331 if (streams == nullptr) {
332 return false;
333 }
334
335#define SET_ENABLE_STREAM(name, ...) \
336 Timeline::SetStream##name##Enabled(HasStream(streams, #name));
337 TIMELINE_STREAM_LIST(SET_ENABLE_STREAM);
338#undef SET_ENABLE_STREAM
339
340 delete[] streams;
341
342#if !defined(PRODUCT)
343 // Notify clients that the set of subscribed streams has been updated.
344 if (Service::timeline_stream.enabled()) {
347 }
348#endif
349
350 return true;
351}
352#endif // defined(SUPPORT_TIMELINE)
353
354#ifndef PRODUCT
355// The name of this of this vm as reported by the VM service protocol.
356static char* vm_name = nullptr;
357
358static const char* GetVMName() {
359 if (vm_name == nullptr) {
360 return FLAG_vm_name;
361 }
362 return vm_name;
363}
364
366
368
370 : ring_(nullptr), policy_(ObjectIdRing::kAllocateId) {}
371
373
376 ring_ = ring;
377 policy_ = policy;
378}
379
381 ASSERT(ring_ != nullptr);
382 Thread* thread = Thread::Current();
383 Zone* zone = thread->zone();
384 ASSERT(zone != nullptr);
385 const intptr_t id = ring_->GetIdForObject(obj.ptr(), policy_);
386 return zone->PrintToString("objects/%" Pd "", id);
387}
388
389// TODO(johnmccutchan): Unify embedder service handler lists and their APIs.
390EmbedderServiceHandler* Service::isolate_service_handler_head_ = nullptr;
391EmbedderServiceHandler* Service::root_service_handler_head_ = nullptr;
393const ServiceMethodDescriptor* FindMethod(const char* method_name);
394
395// Support for streams defined in embedders.
396Dart_ServiceStreamListenCallback Service::stream_listen_callback_ = nullptr;
397Dart_ServiceStreamCancelCallback Service::stream_cancel_callback_ = nullptr;
398Dart_GetVMServiceAssetsArchive Service::get_service_assets_callback_ = nullptr;
399Dart_EmbedderInformationCallback Service::embedder_information_callback_ =
400 nullptr;
401
402// These are the set of streams known to the core VM.
413
414const uint8_t* Service::dart_library_kernel_ = nullptr;
415intptr_t Service::dart_library_kernel_len_ = 0;
416
417// Keep streams_ in sync with the protected streams in
418// lib/developer/extension.dart
419static StreamInfo* const streams_[] = {
425};
426
427bool Service::ListenStream(const char* stream_id,
428 bool include_private_members) {
429 if (FLAG_trace_service) {
430 OS::PrintErr("vm-service: starting stream '%s'\n", stream_id);
431 }
432 intptr_t num_streams = sizeof(streams_) / sizeof(streams_[0]);
433 for (intptr_t i = 0; i < num_streams; i++) {
434 if (strcmp(stream_id, streams_[i]->id()) == 0) {
435 streams_[i]->set_enabled(true);
436 streams_[i]->set_include_private_members(include_private_members);
437 return true;
438 }
439 }
440 if (stream_listen_callback_ != nullptr) {
442 TransitionVMToNative transition(T);
443 return (*stream_listen_callback_)(stream_id);
444 }
445 return false;
446}
447
448void Service::CancelStream(const char* stream_id) {
449 if (FLAG_trace_service) {
450 OS::PrintErr("vm-service: stopping stream '%s'\n", stream_id);
451 }
452 intptr_t num_streams = sizeof(streams_) / sizeof(streams_[0]);
453 for (intptr_t i = 0; i < num_streams; i++) {
454 if (strcmp(stream_id, streams_[i]->id()) == 0) {
455 streams_[i]->set_enabled(false);
456 return;
457 }
458 }
459 if (stream_cancel_callback_ != nullptr) {
461 TransitionVMToNative transition(T);
462 return (*stream_cancel_callback_)(stream_id);
463 }
464}
465
468 Object& object = Object::Handle();
469 {
470 Api::Scope api_scope(T);
471 Dart_Handle handle;
472 {
473 TransitionVMToNative transition(T);
474 if (get_service_assets_callback_ == nullptr) {
475 return Object::null();
476 }
477 handle = get_service_assets_callback_();
478 if (Dart_IsError(handle)) {
479 Dart_PropagateError(handle);
480 }
481 }
482 object = Api::UnwrapHandle(handle);
483 }
484 if (object.IsNull()) {
485 return Object::null();
486 }
487 if (!object.IsTypedData()) {
488 const String& error_message = String::Handle(
489 String::New("An implementation of Dart_GetVMServiceAssetsArchive "
490 "should return a Uint8Array or null."));
491 const Error& error = Error::Handle(ApiError::New(error_message));
493 return Object::null();
494 }
495 const TypedData& typed_data = TypedData::Cast(object);
496 if (typed_data.ElementSizeInBytes() != 1) {
497 const String& error_message = String::Handle(
498 String::New("An implementation of Dart_GetVMServiceAssetsArchive "
499 "should return a Uint8Array or null."));
500 const Error& error = Error::Handle(ApiError::New(error_message));
502 return Object::null();
503 }
504 return object.ptr();
505}
506
508 JSONObject jsobj(js);
509 jsobj.AddProperty("type", "Success");
510}
511
513#if defined(DART_PRECOMPILED_RUNTIME)
514 js->PrintError(kFeatureDisabled, "Debugger is disabled in AOT mode.");
515 return true;
516#else
517 if (thread->isolate()->debugger() == nullptr) {
518 js->PrintError(kFeatureDisabled, "Debugger is disabled.");
519 return true;
520 }
521 return false;
522#endif
523}
524
526 if (!FLAG_profiler) {
527 js->PrintError(kFeatureDisabled, "Profiler is disabled.");
528 return true;
529 }
530 return false;
531}
532
533static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
534 if ((s == nullptr) || (*s == '\0')) {
535 // Empty string.
536 return false;
537 }
538 if (id == nullptr) {
539 // No id pointer.
540 return false;
541 }
542 intptr_t r = 0;
543 char* end_ptr = nullptr;
544#if defined(ARCH_IS_32_BIT)
545 r = strtol(s, &end_ptr, base);
546#else
547 r = strtoll(s, &end_ptr, base);
548#endif
549 if (end_ptr == s) {
550 // String was not advanced at all, cannot be valid.
551 return false;
552 }
553 *id = r;
554 return true;
555}
556
557static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
558 if ((s == nullptr) || (*s == '\0')) {
559 // Empty string.
560 return false;
561 }
562 if (id == nullptr) {
563 // No id pointer.
564 return false;
565 }
566 uintptr_t r = 0;
567 char* end_ptr = nullptr;
568#if defined(ARCH_IS_32_BIT)
569 r = strtoul(s, &end_ptr, base);
570#else
571 r = strtoull(s, &end_ptr, base);
572#endif
573 if (end_ptr == s) {
574 // String was not advanced at all, cannot be valid.
575 return false;
576 }
577 *id = r;
578 return true;
579}
580
581static bool GetInteger64Id(const char* s, int64_t* id, int base = 10) {
582 if ((s == nullptr) || (*s == '\0')) {
583 // Empty string.
584 return false;
585 }
586 if (id == nullptr) {
587 // No id pointer.
588 return false;
589 }
590 int64_t r = 0;
591 char* end_ptr = nullptr;
592 r = strtoll(s, &end_ptr, base);
593 if (end_ptr == s) {
594 // String was not advanced at all, cannot be valid.
595 return false;
596 }
597 *id = r;
598 return true;
599}
600
601// Scans the string until the '-' character. Returns pointer to string
602// at '-' character. Returns nullptr if not found.
603static const char* ScanUntilDash(const char* s) {
604 if ((s == nullptr) || (*s == '\0')) {
605 // Empty string.
606 return nullptr;
607 }
608 while (*s != '\0') {
609 if (*s == '-') {
610 return s;
611 }
612 s++;
613 }
614 return nullptr;
615}
616
617static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
618 if ((s == nullptr) || (*s == '\0')) {
619 // Empty string.
620 return false;
621 }
622 if ((timestamp == nullptr) || (address == nullptr)) {
623 // Bad arguments.
624 return false;
625 }
626 // Extract the timestamp.
627 if (!GetInteger64Id(s, timestamp, 16) || (*timestamp < 0)) {
628 return false;
629 }
630 s = ScanUntilDash(s);
631 if (s == nullptr) {
632 return false;
633 }
634 // Skip the dash.
635 s++;
636 // Extract the PC.
637 if (!GetUnsignedIntegerId(s, address, 16)) {
638 return false;
639 }
640 return true;
641}
642
643// Verifies that |s| begins with |prefix| and then calls |GetIntegerId| on
644// the remainder of |s|.
645static bool GetPrefixedIntegerId(const char* s,
646 const char* prefix,
647 intptr_t* service_id) {
648 if (s == nullptr) {
649 return false;
650 }
651 ASSERT(prefix != nullptr);
652 const intptr_t kInputLen = strlen(s);
653 const intptr_t kPrefixLen = strlen(prefix);
654 ASSERT(kPrefixLen > 0);
655 if (kInputLen <= kPrefixLen) {
656 return false;
657 }
658 if (strncmp(s, prefix, kPrefixLen) != 0) {
659 return false;
660 }
661 // Prefix satisfied. Move forward.
662 s += kPrefixLen;
663 // Attempt to read integer id.
664 return GetIntegerId(s, service_id);
665}
666
667static bool IsValidClassId(Isolate* isolate, intptr_t cid) {
668 ASSERT(isolate != nullptr);
669 ClassTable* class_table = isolate->group()->class_table();
670 ASSERT(class_table != nullptr);
671 return class_table->IsValidIndex(cid) && class_table->HasValidClassAt(cid);
672}
673
674static ClassPtr GetClassForId(Isolate* isolate, intptr_t cid) {
675 ASSERT(isolate == Isolate::Current());
676 ASSERT(isolate != nullptr);
677 ClassTable* class_table = isolate->group()->class_table();
678 ASSERT(class_table != nullptr);
679 return class_table->At(cid);
680}
681
683 public:
686
687 virtual bool ValidateObject(const Object& value) const {
688 return value.IsString();
689 }
690};
691
693 public:
694 DartListParameter(const char* name, bool required)
696
697 virtual bool ValidateObject(const Object& value) const {
698 return value.IsArray() || value.IsGrowableObjectArray();
699 }
700};
701
703 public:
704 BoolParameter(const char* name, bool required)
706
707 virtual bool Validate(const char* value) const {
708 if (value == nullptr) {
709 return false;
710 }
711 return (strcmp("true", value) == 0) || (strcmp("false", value) == 0);
712 }
713
714 static bool Parse(const char* value, bool default_value = false) {
715 if (value == nullptr) {
716 return default_value;
717 }
718 return strcmp("true", value) == 0;
719 }
720};
721
723 public:
724 UIntParameter(const char* name, bool required)
726
727 virtual bool Validate(const char* value) const {
728 if (value == nullptr) {
729 return false;
730 }
731 for (const char* cp = value; *cp != '\0'; cp++) {
732 if (*cp < '0' || *cp > '9') {
733 return false;
734 }
735 }
736 return true;
737 }
738
739 static uintptr_t Parse(const char* value) {
740 if (value == nullptr) {
741 return -1;
742 }
743 char* end_ptr = nullptr;
744 uintptr_t result = strtoul(value, &end_ptr, 10);
745 ASSERT(*end_ptr == '\0'); // Parsed full string
746 return result;
747 }
748};
749
751 public:
752 Int64Parameter(const char* name, bool required)
754
755 virtual bool Validate(const char* value) const {
756 if (value == nullptr) {
757 return false;
758 }
759 for (const char* cp = value; *cp != '\0'; cp++) {
760 if ((*cp < '0' || *cp > '9') && (*cp != '-')) {
761 return false;
762 }
763 }
764 return true;
765 }
766
767 static int64_t Parse(const char* value, int64_t default_value = -1) {
768 if ((value == nullptr) || (*value == '\0')) {
769 return default_value;
770 }
771 char* end_ptr = nullptr;
772 int64_t result = strtoll(value, &end_ptr, 10);
773 ASSERT(*end_ptr == '\0'); // Parsed full string
774 return result;
775 }
776};
777
779 public:
780 UInt64Parameter(const char* name, bool required)
782
783 virtual bool Validate(const char* value) const {
784 if (value == nullptr) {
785 return false;
786 }
787 for (const char* cp = value; *cp != '\0'; cp++) {
788 if ((*cp < '0' || *cp > '9') && (*cp != '-')) {
789 return false;
790 }
791 }
792 return true;
793 }
794
795 static uint64_t Parse(const char* value, uint64_t default_value = 0) {
796 if ((value == nullptr) || (*value == '\0')) {
797 return default_value;
798 }
799 char* end_ptr = nullptr;
800 uint64_t result = strtoull(value, &end_ptr, 10);
801 ASSERT(*end_ptr == '\0'); // Parsed full string
802 return result;
803 }
804};
805
807 public:
808 IdParameter(const char* name, bool required)
810
811 virtual bool Validate(const char* value) const { return (value != nullptr); }
812};
813
815 public:
816 StringParameter(const char* name, bool required)
818
819 virtual bool Validate(const char* value) const { return (value != nullptr); }
820};
821
823 public:
824 explicit RunnableIsolateParameter(const char* name)
826
827 virtual bool Validate(const char* value) const {
828 Isolate* isolate = Isolate::Current();
829 return (value != nullptr) && (isolate != nullptr) &&
830 (isolate->is_runnable());
831 }
832
833 virtual void PrintError(const char* name,
834 const char* value,
835 JSONStream* js) const {
836 js->PrintError(kIsolateMustBeRunnable,
837 "Isolate must be runnable before this request is made.");
838 }
839};
840
842 public:
843 EnumParameter(const char* name, bool required, const char* const* enums)
844 : MethodParameter(name, required), enums_(enums) {}
845
846 virtual bool Validate(const char* value) const {
847 if (value == nullptr) {
848 return true;
849 }
850 for (intptr_t i = 0; enums_[i] != nullptr; i++) {
851 if (strcmp(value, enums_[i]) == 0) {
852 return true;
853 }
854 }
855 return false;
856 }
857
858 private:
859 const char* const* enums_;
860};
861
862// If the key is not found, this function returns the last element in the
863// values array. This can be used to encode the default value.
864template <typename T>
865T EnumMapper(const char* value, const char* const* enums, T* values) {
866 ASSERT(value != nullptr);
867 intptr_t i = 0;
868 for (i = 0; enums[i] != nullptr; i++) {
869 if (strcmp(value, enums[i]) == 0) {
870 return values[i];
871 }
872 }
873 // Default value.
874 return values[i];
875}
876
877typedef void (*ServiceMethodEntry)(Thread* thread, JSONStream* js);
878
880 const char* name;
883};
884
885static void PrintMissingParamError(JSONStream* js, const char* param) {
886 js->PrintError(kInvalidParams, "%s expects the '%s' parameter", js->method(),
887 param);
888}
889
891 js->PrintError(kMethodNotFound, nullptr);
892}
893
894// TODO(johnmccutchan): Do we reject unexpected parameters?
895static bool ValidateParameters(const MethodParameter* const* parameters,
896 JSONStream* js) {
897 if (parameters == nullptr) {
898 return true;
899 }
900 if (js->NumObjectParameters() > 0) {
902 for (intptr_t i = 0; parameters[i] != nullptr; i++) {
903 const MethodParameter* parameter = parameters[i];
904 const char* name = parameter->name();
905 const bool required = parameter->required();
906 value = js->LookupObjectParam(name);
907 const bool has_parameter = !value.IsNull();
908 if (required && !has_parameter) {
910 return false;
911 }
912 if (has_parameter && !parameter->ValidateObject(value)) {
913 parameter->PrintErrorObject(name, value, js);
914 return false;
915 }
916 }
917 } else {
918 for (intptr_t i = 0; parameters[i] != nullptr; i++) {
919 const MethodParameter* parameter = parameters[i];
920 const char* name = parameter->name();
921 const bool required = parameter->required();
922 const char* value = js->LookupParam(name);
923 const bool has_parameter = (value != nullptr);
924 if (required && !has_parameter) {
926 return false;
927 }
928 if (has_parameter && !parameter->Validate(value)) {
929 parameter->PrintError(name, value, js);
930 return false;
931 }
932 }
933 }
934 return true;
935}
936
937void Service::PostError(const String& method_name,
938 const Array& parameter_keys,
939 const Array& parameter_values,
940 const Instance& reply_port,
941 const Instance& id,
942 const Error& error) {
944 StackZone zone(T);
946 js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(), id, method_name,
947 parameter_keys, parameter_values);
948 js.PrintError(kExtensionError, "Error in extension `%s`: %s", js.method(),
949 error.ToErrorCString());
950 js.PostReply();
951}
952
953ErrorPtr Service::InvokeMethod(Isolate* I,
954 const Array& msg,
955 bool parameters_are_dart_objects) {
957 ASSERT(I == T->isolate());
958 ASSERT(I != nullptr);
959 ASSERT(T->execution_state() == Thread::kThreadInVM);
960 ASSERT(!msg.IsNull());
961 ASSERT(msg.Length() == 6);
962
963 {
964 StackZone zone(T);
965
966 Instance& reply_port = Instance::Handle(Z);
967 Instance& seq = String::Handle(Z);
968 String& method_name = String::Handle(Z);
969 Array& param_keys = Array::Handle(Z);
970 Array& param_values = Array::Handle(Z);
971 reply_port ^= msg.At(1);
972 seq ^= msg.At(2);
973 method_name ^= msg.At(3);
974 param_keys ^= msg.At(4);
975 param_values ^= msg.At(5);
976
977 ASSERT(!method_name.IsNull());
978 ASSERT(seq.IsNull() || seq.IsString() || seq.IsNumber());
979 ASSERT(!param_keys.IsNull());
980 ASSERT(!param_values.IsNull());
981 ASSERT(param_keys.Length() == param_values.Length());
982
983 // We expect a reply port unless there is a null sequence id,
984 // which indicates that no reply should be sent. We use this in
985 // tests.
986 if (!seq.IsNull() && !reply_port.IsSendPort()) {
987 FATAL("SendPort expected.");
988 }
989
990 JSONStream js;
991 Dart_Port reply_port_id =
992 (reply_port.IsNull() ? ILLEGAL_PORT : SendPort::Cast(reply_port).Id());
993 js.Setup(zone.GetZone(), reply_port_id, seq, method_name, param_keys,
994 param_values, parameters_are_dart_objects);
995
996 // RPC came in with a custom service id zone.
997 const char* id_zone_param = js.LookupParam("_idZone");
998
999 if (id_zone_param != nullptr) {
1000 // Override id zone.
1001 if (strcmp("default", id_zone_param) == 0) {
1002 // Ring with eager id allocation. This is the default ring and default
1003 // policy.
1004 // Nothing to do.
1005 } else if (strcmp("default.reuse", id_zone_param) == 0) {
1006 // Change the default ring's policy.
1007 RingServiceIdZone* zone =
1008 reinterpret_cast<RingServiceIdZone*>(js.id_zone());
1009 zone->set_policy(ObjectIdRing::kReuseId);
1010 } else {
1011 // TODO(johnmccutchan): Support creating, deleting, and selecting
1012 // custom service id zones.
1013 // For now, always return an error.
1014 PrintInvalidParamError(&js, "_idZone");
1015 js.PostReply();
1016 return T->StealStickyError();
1017 }
1018 }
1019 const char* c_method_name = method_name.ToCString();
1020
1021 const ServiceMethodDescriptor* method = FindMethod(c_method_name);
1022 if (method != nullptr) {
1023 if (!ValidateParameters(method->parameters, &js)) {
1024 js.PostReply();
1025 return T->StealStickyError();
1026 }
1027 method->entry(T, &js);
1028 Service::LogResponseSize(c_method_name, &js);
1029 js.PostReply();
1030 return T->StealStickyError();
1031 }
1032
1033 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(c_method_name);
1034 if (handler == nullptr) {
1035 handler = FindRootEmbedderHandler(c_method_name);
1036 }
1037
1038 if (handler != nullptr) {
1039 EmbedderHandleMessage(handler, &js);
1040 return T->StealStickyError();
1041 }
1042
1043 const Instance& extension_handler =
1044 Instance::Handle(Z, I->LookupServiceExtensionHandler(method_name));
1045 if (!extension_handler.IsNull()) {
1046 ScheduleExtensionHandler(extension_handler, method_name, param_keys,
1047 param_values, reply_port, seq);
1048 // Schedule was successful. Extension code will post a reply
1049 // asynchronously.
1050 return T->StealStickyError();
1051 }
1052
1054 js.PostReply();
1055 return T->StealStickyError();
1056 }
1057}
1058
1059ErrorPtr Service::HandleRootMessage(const Array& msg_instance) {
1060 Isolate* isolate = Isolate::Current();
1061 return InvokeMethod(isolate, msg_instance);
1062}
1063
1064ErrorPtr Service::HandleObjectRootMessage(const Array& msg_instance) {
1065 Isolate* isolate = Isolate::Current();
1066 return InvokeMethod(isolate, msg_instance, true);
1067}
1068
1069ErrorPtr Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
1070 ASSERT(isolate != nullptr);
1071 const Error& error = Error::Handle(InvokeMethod(isolate, msg));
1072 return MaybePause(isolate, error);
1073}
1074
1075static void Finalizer(void* isolate_callback_data, void* buffer) {
1076 free(buffer);
1077}
1078
1079void Service::SendEvent(const char* stream_id,
1080 const char* event_type,
1081 uint8_t* bytes,
1082 intptr_t bytes_length) {
1083 Thread* thread = Thread::Current();
1084 Isolate* isolate = thread->isolate();
1085 ASSERT(isolate != nullptr);
1086
1087 if (FLAG_trace_service) {
1089 "vm-service: Pushing ServiceEvent(isolate='%s', "
1091 "', kind='%s',"
1092 " len=%" Pd ") to stream %s\n",
1093 isolate->name(), static_cast<int64_t>(isolate->main_port()), event_type,
1094 bytes_length, stream_id);
1095 }
1096
1097 bool result;
1098 {
1099 Dart_CObject cbytes;
1102 cbytes.value.as_external_typed_data.length = bytes_length;
1103 cbytes.value.as_external_typed_data.data = bytes;
1104 cbytes.value.as_external_typed_data.peer = bytes;
1106
1107 Dart_CObject cstream_id;
1108 cstream_id.type = Dart_CObject_kString;
1109 cstream_id.value.as_string = const_cast<char*>(stream_id);
1110
1111 Dart_CObject* elements[2];
1112 elements[0] = &cstream_id;
1113 elements[1] = &cbytes;
1116 message.value.as_array.length = 2;
1117 message.value.as_array.values = elements;
1118
1119 std::unique_ptr<Message> msg =
1120 WriteApiMessage(thread->zone(), &message, ServiceIsolate::Port(),
1122 if (msg == nullptr) {
1123 result = false;
1124 } else {
1125 result = PortMap::PostMessage(std::move(msg));
1126 }
1127 }
1128
1129 if (!result) {
1130 free(bytes);
1131 }
1132}
1133
1134void Service::SendEventWithData(const char* stream_id,
1135 const char* event_type,
1136 intptr_t reservation,
1137 const char* metadata,
1138 intptr_t metadata_size,
1139 uint8_t* data,
1140 intptr_t data_size) {
1141 ASSERT(kInt32Size + metadata_size <= reservation);
1142 // Using a SPACE creates valid JSON. Our goal here is to prevent the memory
1143 // overhead of copying to concatenate metadata and payload together by
1144 // over-allocating to underlying buffer before we know how long the metadata
1145 // will be.
1146 memset(data, ' ', reservation);
1147 reinterpret_cast<uint32_t*>(data)[0] = reservation;
1148 memmove(&(reinterpret_cast<uint32_t*>(data)[1]), metadata, metadata_size);
1149 Service::SendEvent(stream_id, event_type, data, data_size);
1150}
1151
1153 const char* name = event->isolate()->name();
1154 const int64_t main_port = static_cast<int64_t>(event->isolate()->main_port());
1155 switch (event->kind()) {
1157 OS::PrintErr("vm-service: isolate(%" Pd64
1158 ") '%s' has no debugger attached and is paused at start.",
1159 main_port, name);
1160 break;
1162 OS::PrintErr("vm-service: isolate(%" Pd64
1163 ") '%s' has no debugger attached and is paused at exit.",
1164 main_port, name);
1165 break;
1168 "vm-service: isolate (%" Pd64
1169 ") '%s' has no debugger attached and is paused due to exception.",
1170 main_port, name);
1171 break;
1174 "vm-service: isolate (%" Pd64
1175 ") '%s' has no debugger attached and is paused due to interrupt.",
1176 main_port, name);
1177 break;
1179 OS::PrintErr("vm-service: isolate (%" Pd64
1180 ") '%s' has no debugger attached and is paused.",
1181 main_port, name);
1182 break;
1184 OS::PrintErr("vm-service: isolate (%" Pd64
1185 ") '%s' has no debugger attached and is paused post reload.",
1186 main_port, name);
1187 break;
1188 default:
1189 UNREACHABLE();
1190 break;
1191 }
1193 OS::PrintErr(" Start the vm-service to debug.\n");
1194 } else if (ServiceIsolate::server_address() == nullptr) {
1195 OS::PrintErr(" Connect to the Dart VM service to debug.\n");
1196 } else {
1197 OS::PrintErr(" Connect to the Dart VM service at %s to debug.\n",
1199 }
1200 const Error& err = Error::Handle(Thread::Current()->sticky_error());
1201 if (!err.IsNull()) {
1202 OS::PrintErr("%s\n", err.ToErrorCString());
1203 }
1204}
1205
1206void Service::HandleEvent(ServiceEvent* event, bool enter_safepoint) {
1207 if (event->stream_info() != nullptr && !event->stream_info()->enabled()) {
1208 if (FLAG_warn_on_pause_with_no_debugger && event->IsPause()) {
1209 // If we are about to pause a running program which has no
1210 // debugger connected, tell the user about it.
1212 }
1213 // Ignore events when no one is listening to the event stream.
1214 return;
1215 } else if (event->stream_info() != nullptr &&
1216 FLAG_warn_on_pause_with_no_debugger && event->IsPause()) {
1218 }
1220 return;
1221 }
1222 JSONStream js;
1223 if (event->stream_info() != nullptr) {
1224 js.set_include_private_members(
1225 event->stream_info()->include_private_members());
1226 }
1227 const char* stream_id = event->stream_id();
1228 ASSERT(stream_id != nullptr);
1229 {
1230 JSONObject jsobj(&js);
1231 jsobj.AddProperty("jsonrpc", "2.0");
1232 jsobj.AddProperty("method", "streamNotify");
1233 JSONObject params(&jsobj, "params");
1234 params.AddProperty("streamId", stream_id);
1235 params.AddProperty("event", event);
1236 }
1237 PostEvent(event->isolate_group(), event->isolate(), stream_id,
1238 event->KindAsCString(), &js, enter_safepoint);
1239}
1240
1241void Service::PostEvent(IsolateGroup* isolate_group,
1242 Isolate* isolate,
1243 const char* stream_id,
1244 const char* kind,
1246 bool enter_safepoint) {
1247 if (enter_safepoint) {
1248 // Enter a safepoint so we don't block the mutator while processing
1249 // large events.
1250 TransitionToNative transition(Thread::Current());
1251 PostEventImpl(isolate_group, isolate, stream_id, kind, event);
1252 return;
1253 }
1254 PostEventImpl(isolate_group, isolate, stream_id, kind, event);
1255}
1256
1257void Service::PostEventImpl(IsolateGroup* isolate_group,
1258 Isolate* isolate,
1259 const char* stream_id,
1260 const char* kind,
1261 JSONStream* event) {
1262 ASSERT(stream_id != nullptr);
1263 ASSERT(kind != nullptr);
1264 ASSERT(event != nullptr);
1265
1266 if (FLAG_trace_service) {
1267 if (isolate != nullptr) {
1268 ASSERT(isolate_group != nullptr);
1270 "vm-service: Pushing "
1271 "ServiceEvent(isolateGroupId='" ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING
1272 "', isolate='%s', isolateId='" ISOLATE_SERVICE_ID_FORMAT_STRING
1273 "', kind='%s') to stream %s\n",
1274 isolate_group->id(), isolate->name(),
1275 static_cast<int64_t>(isolate->main_port()), kind, stream_id);
1276 } else if (isolate_group != nullptr) {
1278 "vm-service: Pushing "
1279 "ServiceEvent(isolateGroupId='" ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING
1280 "', kind='%s') to stream %s\n",
1281 isolate_group->id(), kind, stream_id);
1282 } else {
1284 "vm-service: Pushing ServiceEvent(isolate='<no current isolate>', "
1285 "kind='%s') to stream %s\n",
1286 kind, stream_id);
1287 }
1288 }
1289
1291
1292 // Message is of the format [<stream id>, <json string>].
1293 //
1294 // Build the event message in the C heap to avoid dart heap
1295 // allocation. This method can be called while we have acquired a
1296 // direct pointer to typed data, so we can't allocate here.
1297 Dart_CObject list_cobj;
1298 Dart_CObject* list_values[2];
1299 list_cobj.type = Dart_CObject_kArray;
1300 list_cobj.value.as_array.length = 2;
1301 list_cobj.value.as_array.values = list_values;
1302
1303 Dart_CObject stream_id_cobj;
1304 stream_id_cobj.type = Dart_CObject_kString;
1305 stream_id_cobj.value.as_string = const_cast<char*>(stream_id);
1306 list_values[0] = &stream_id_cobj;
1307
1308 Dart_CObject json_cobj;
1309 json_cobj.type = Dart_CObject_kString;
1310 json_cobj.value.as_string = const_cast<char*>(event->ToCString());
1311 list_values[1] = &json_cobj;
1312
1313 AllocOnlyStackZone zone;
1314 std::unique_ptr<Message> msg =
1315 WriteApiMessage(zone.GetZone(), &list_cobj, ServiceIsolate::Port(),
1317 if (msg != nullptr) {
1318 PortMap::PostMessage(std::move(msg));
1319 }
1320}
1321
1323 public:
1324 explicit EmbedderServiceHandler(const char* name)
1325 : name_(nullptr),
1326 callback_(nullptr),
1327 user_data_(nullptr),
1328 next_(nullptr) {
1329 ASSERT(name != nullptr);
1330 name_ = Utils::StrDup(name);
1331 }
1332
1333 ~EmbedderServiceHandler() { free(name_); }
1334
1335 const char* name() const { return name_; }
1336
1337 Dart_ServiceRequestCallback callback() const { return callback_; }
1339 callback_ = callback;
1340 }
1341
1342 void* user_data() const { return user_data_; }
1343 void set_user_data(void* user_data) { user_data_ = user_data; }
1344
1345 EmbedderServiceHandler* next() const { return next_; }
1347
1348 private:
1349 char* name_;
1351 void* user_data_;
1353};
1354
1355void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler,
1356 JSONStream* js) {
1357 ASSERT(handler != nullptr);
1358 Dart_ServiceRequestCallback callback = handler->callback();
1359 ASSERT(callback != nullptr);
1360 const char* response = nullptr;
1361 bool success;
1362 {
1363 TransitionVMToNative transition(Thread::Current());
1364 success = callback(js->method(), js->param_keys(), js->param_values(),
1365 js->num_params(), handler->user_data(), &response);
1366 }
1367 ASSERT(response != nullptr);
1368 if (!success) {
1369 js->SetupError();
1370 }
1371 js->buffer()->AddString(response);
1372 js->PostReply();
1373 free(const_cast<char*>(response));
1374}
1375
1377 const char* name,
1379 void* user_data) {
1380 if (name == nullptr) {
1381 return;
1382 }
1383 EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name);
1384 if (handler != nullptr) {
1385 // Update existing handler entry.
1386 handler->set_callback(callback);
1387 handler->set_user_data(user_data);
1388 return;
1389 }
1390 // Create a new handler.
1391 handler = new EmbedderServiceHandler(name);
1392 handler->set_callback(callback);
1393 handler->set_user_data(user_data);
1394
1395 // Insert into isolate_service_handler_head_ list.
1396 handler->set_next(isolate_service_handler_head_);
1397 isolate_service_handler_head_ = handler;
1398}
1399
1400EmbedderServiceHandler* Service::FindIsolateEmbedderHandler(const char* name) {
1401 EmbedderServiceHandler* current = isolate_service_handler_head_;
1402 while (current != nullptr) {
1403 if (strcmp(name, current->name()) == 0) {
1404 return current;
1405 }
1406 current = current->next();
1407 }
1408 return nullptr;
1409}
1410
1413 void* user_data) {
1414 if (name == nullptr) {
1415 return;
1416 }
1417 EmbedderServiceHandler* handler = FindRootEmbedderHandler(name);
1418 if (handler != nullptr) {
1419 // Update existing handler entry.
1420 handler->set_callback(callback);
1421 handler->set_user_data(user_data);
1422 return;
1423 }
1424 // Create a new handler.
1425 handler = new EmbedderServiceHandler(name);
1426 handler->set_callback(callback);
1427 handler->set_user_data(user_data);
1428
1429 // Insert into root_service_handler_head_ list.
1430 handler->set_next(root_service_handler_head_);
1431 root_service_handler_head_ = handler;
1432}
1433
1435 Dart_ServiceStreamListenCallback listen_callback,
1436 Dart_ServiceStreamCancelCallback cancel_callback) {
1437 stream_listen_callback_ = listen_callback;
1438 stream_cancel_callback_ = cancel_callback;
1439}
1440
1442 Dart_GetVMServiceAssetsArchive get_service_assets) {
1443 get_service_assets_callback_ = get_service_assets;
1444}
1445
1448 embedder_information_callback_ = callback;
1449}
1450
1452 if (embedder_information_callback_ == nullptr) {
1453 return -1;
1454 }
1456 0, // version
1457 nullptr, // name
1458 0, // max_rss
1459 0 // current_rss
1460 };
1461 embedder_information_callback_(&info);
1463 return info.current_rss;
1464}
1465
1467 if (embedder_information_callback_ == nullptr) {
1468 return -1;
1469 }
1471 0, // version
1472 nullptr, // name
1473 0, // max_rss
1474 0 // current_rss
1475 };
1476 embedder_information_callback_(&info);
1478 return info.max_rss;
1479}
1480
1481void Service::SetDartLibraryKernelForSources(const uint8_t* kernel_bytes,
1482 intptr_t kernel_length) {
1483 dart_library_kernel_ = kernel_bytes;
1484 dart_library_kernel_len_ = kernel_length;
1485}
1486
1487EmbedderServiceHandler* Service::FindRootEmbedderHandler(const char* name) {
1488 EmbedderServiceHandler* current = root_service_handler_head_;
1489 while (current != nullptr) {
1490 if (strcmp(name, current->name()) == 0) {
1491 return current;
1492 }
1493 current = current->next();
1494 }
1495 return nullptr;
1496}
1497
1498void Service::ScheduleExtensionHandler(const Instance& handler,
1499 const String& method_name,
1500 const Array& parameter_keys,
1501 const Array& parameter_values,
1502 const Instance& reply_port,
1503 const Instance& id) {
1504 ASSERT(!handler.IsNull());
1505 ASSERT(!method_name.IsNull());
1506 ASSERT(!parameter_keys.IsNull());
1507 ASSERT(!parameter_values.IsNull());
1508 ASSERT(!reply_port.IsNull());
1509 Isolate* isolate = Isolate::Current();
1510 ASSERT(isolate != nullptr);
1511 isolate->AppendServiceExtensionCall(handler, method_name, parameter_keys,
1512 parameter_values, reply_port, id);
1513}
1514
1515static const MethodParameter* const get_isolate_params[] = {
1517 nullptr,
1518};
1519
1520static void GetIsolate(Thread* thread, JSONStream* js) {
1521 thread->isolate()->PrintJSON(js, false);
1522}
1523
1526 nullptr,
1527};
1528
1533};
1534
1535static void PrintSentinel(JSONStream* js, SentinelType sentinel_type) {
1536 JSONObject jsobj(js);
1537 jsobj.AddProperty("type", "Sentinel");
1538 switch (sentinel_type) {
1539 case kCollectedSentinel:
1540 jsobj.AddProperty("kind", "Collected");
1541 jsobj.AddProperty("valueAsString", "<collected>");
1542 break;
1543 case kExpiredSentinel:
1544 jsobj.AddProperty("kind", "Expired");
1545 jsobj.AddProperty("valueAsString", "<expired>");
1546 break;
1547 case kFreeSentinel:
1548 jsobj.AddProperty("kind", "Free");
1549 jsobj.AddProperty("valueAsString", "<free>");
1550 break;
1551 default:
1552 UNIMPLEMENTED();
1553 break;
1554 }
1555}
1556
1557static const MethodParameter* const
1560 new BoolParameter("includePrivateMembers", true),
1561 nullptr,
1562};
1563
1565 const char* stream_id = js->LookupParam("streamId");
1566 if (stream_id == nullptr) {
1567 PrintMissingParamError(js, "streamId");
1568 return;
1569 }
1570 bool include_private_members =
1571 BoolParameter::Parse(js->LookupParam("includePrivateMembers"), false);
1572 intptr_t num_streams = sizeof(streams_) / sizeof(streams_[0]);
1573 for (intptr_t i = 0; i < num_streams; i++) {
1574 if (strcmp(stream_id, streams_[i]->id()) == 0) {
1575 streams_[i]->set_include_private_members(include_private_members);
1576 break;
1577 }
1578 }
1580}
1581
1583 std::function<void(IsolateGroup*)> visitor) {
1584 const String& prefix =
1586
1587 const String& s =
1588 String::Handle(String::New(js->LookupParam("isolateGroupId")));
1589 if (!s.StartsWith(prefix)) {
1590 PrintInvalidParamError(js, "isolateGroupId");
1591 return;
1592 }
1593 uint64_t isolate_group_id = UInt64Parameter::Parse(
1596 isolate_group_id,
1597 [&visitor](IsolateGroup* isolate_group) { visitor(isolate_group); },
1598 /*if_not_found=*/[&js]() { PrintSentinel(js, kExpiredSentinel); });
1599}
1600
1601static void GetIsolateGroup(Thread* thread, JSONStream* js) {
1602 ActOnIsolateGroup(js, [&](IsolateGroup* isolate_group) {
1603 isolate_group->PrintJSON(js, false);
1604 });
1605}
1606
1609 nullptr,
1610};
1611
1612static void GetMemoryUsage(Thread* thread, JSONStream* js) {
1613 thread->isolate()->PrintMemoryUsageJSON(js);
1614}
1615
1618 nullptr,
1619};
1620
1622 ActOnIsolateGroup(js, [&](IsolateGroup* isolate_group) {
1623 isolate_group->PrintMemoryUsageJSON(js);
1624 });
1625}
1626
1629 nullptr,
1630};
1631
1633 thread->isolate()->PrintPauseEventJSON(js);
1634}
1635
1636static const MethodParameter* const get_scripts_params[] = {
1638 nullptr,
1639};
1640
1641static void GetScripts(Thread* thread, JSONStream* js) {
1642 auto object_store = thread->isolate_group()->object_store();
1643 Zone* zone = thread->zone();
1644
1645 const auto& libs =
1646 GrowableObjectArray::Handle(zone, object_store->libraries());
1647 intptr_t num_libs = libs.Length();
1648
1649 Library& lib = Library::Handle(zone);
1650 Array& scripts = Array::Handle(zone);
1651 Script& script = Script::Handle(zone);
1652
1653 JSONObject jsobj(js);
1654 {
1655 jsobj.AddProperty("type", "ScriptList");
1656 JSONArray script_array(&jsobj, "scripts");
1657 for (intptr_t i = 0; i < num_libs; i++) {
1658 lib ^= libs.At(i);
1659 ASSERT(!lib.IsNull());
1660 scripts = lib.LoadedScripts();
1661 for (intptr_t j = 0; j < scripts.Length(); j++) {
1662 script ^= scripts.At(j);
1663 ASSERT(!script.IsNull());
1664 script_array.AddValue(script);
1665 }
1666 }
1667 }
1668}
1669
1670static const MethodParameter* const get_stack_params[] = {
1672 new UIntParameter("limit", false),
1673 nullptr,
1674};
1675
1676static void GetStack(Thread* thread, JSONStream* js) {
1677 if (CheckDebuggerDisabled(thread, js)) {
1678 return;
1679 }
1680 intptr_t limit = 0;
1681 bool has_limit = js->HasParam("limit");
1682 if (has_limit) {
1683 limit = UIntParameter::Parse(js->LookupParam("limit"));
1684 if (limit < 0) {
1685 PrintInvalidParamError(js, "limit");
1686 return;
1687 }
1688 }
1689 Isolate* isolate = thread->isolate();
1690 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
1691 DebuggerStackTrace* async_awaiter_stack =
1692 isolate->debugger()->AsyncAwaiterStackTrace();
1693
1694 // Do we want the complete script object and complete local variable objects?
1695 // This is true for dump requests.
1696 JSONObject jsobj(js);
1697 jsobj.AddProperty("type", "Stack");
1698 {
1699 JSONArray jsarr(&jsobj, "frames");
1700
1701 intptr_t num_frames =
1702 has_limit ? Utils::Minimum(stack->Length(), limit) : stack->Length();
1703
1704 for (intptr_t i = 0; i < num_frames; i++) {
1705 ActivationFrame* frame = stack->FrameAt(i);
1706 JSONObject jsobj(&jsarr);
1707 frame->PrintToJSONObject(&jsobj);
1708 jsobj.AddProperty("index", i);
1709 }
1710 }
1711
1712 if (async_awaiter_stack != nullptr) {
1713 JSONArray jsarr(&jsobj, "asyncCausalFrames");
1714 intptr_t num_frames =
1715 has_limit ? Utils::Minimum(async_awaiter_stack->Length(), limit)
1716 : async_awaiter_stack->Length();
1717 for (intptr_t i = 0; i < num_frames; i++) {
1718 ActivationFrame* frame = async_awaiter_stack->FrameAt(i);
1719 JSONObject jsobj(&jsarr);
1720 frame->PrintToJSONObject(&jsobj);
1721 jsobj.AddProperty("index", i);
1722 }
1723 }
1724
1725 const bool truncated =
1726 (has_limit &&
1727 (limit < stack->Length() || (async_awaiter_stack != nullptr &&
1728 limit < async_awaiter_stack->Length())));
1729 jsobj.AddProperty("truncated", truncated);
1730
1731 {
1733 jsobj.AddProperty("messages", aq.queue());
1734 }
1735}
1736
1738 jsobj->AddProperty("type", "_EchoResponse");
1739 if (js->HasParam("text")) {
1740 jsobj->AddProperty("text", js->LookupParam("text"));
1741 }
1742}
1743
1744void Service::SendEchoEvent(Isolate* isolate, const char* text) {
1745 JSONStream js;
1746 {
1747 JSONObject jsobj(&js);
1748 jsobj.AddProperty("jsonrpc", "2.0");
1749 jsobj.AddProperty("method", "streamNotify");
1750 {
1751 JSONObject params(&jsobj, "params");
1752 params.AddProperty("streamId", echo_stream.id());
1753 {
1754 JSONObject event(&params, "event");
1755 event.AddProperty("type", "Event");
1756 event.AddProperty("kind", "_Echo");
1757 event.AddProperty("isolate", isolate);
1758 if (text != nullptr) {
1759 event.AddProperty("text", text);
1760 }
1761 event.AddPropertyTimeMillis("timestamp", OS::GetCurrentTimeMillis());
1762 }
1763 }
1764 }
1765
1766 intptr_t reservation = js.buffer()->length() + sizeof(int32_t);
1767 intptr_t data_size = reservation + 3;
1768 uint8_t* data = reinterpret_cast<uint8_t*>(malloc(data_size));
1769 data[reservation + 0] = 0;
1770 data[reservation + 1] = 128;
1771 data[reservation + 2] = 255;
1772 SendEventWithData(echo_stream.id(), "_Echo", reservation,
1773 js.buffer()->buffer(), js.buffer()->length(), data,
1774 data_size);
1775}
1776
1777static void TriggerEchoEvent(Thread* thread, JSONStream* js) {
1778 if (Service::echo_stream.enabled()) {
1779 Service::SendEchoEvent(thread->isolate(), js->LookupParam("text"));
1780 }
1781 JSONObject jsobj(js);
1782 HandleCommonEcho(&jsobj, js);
1783}
1784
1785static void Echo(Thread* thread, JSONStream* js) {
1786 JSONObject jsobj(js);
1787 HandleCommonEcho(&jsobj, js);
1788}
1789
1790static bool ContainsNonInstance(const Object& obj) {
1791 if (obj.IsArray()) {
1792 const Array& array = Array::Cast(obj);
1793 Object& element = Object::Handle();
1794 for (intptr_t i = 0; i < array.Length(); ++i) {
1795 element = array.At(i);
1796 if (!(element.IsInstance() || element.IsNull())) {
1797 return true;
1798 }
1799 }
1800 return false;
1801 } else if (obj.IsGrowableObjectArray()) {
1802 const GrowableObjectArray& array = GrowableObjectArray::Cast(obj);
1803 Object& element = Object::Handle();
1804 for (intptr_t i = 0; i < array.Length(); ++i) {
1805 element = array.At(i);
1806 if (!(element.IsInstance() || element.IsNull())) {
1807 return true;
1808 }
1809 }
1810 return false;
1811 } else {
1812 return !(obj.IsInstance() || obj.IsNull());
1813 }
1814}
1815
1817 const char* arg,
1819 *kind = ObjectIdRing::kValid;
1820 if (strncmp(arg, "int-", 4) == 0) {
1821 arg += 4;
1822 int64_t value = 0;
1823 if (!OS::StringToInt64(arg, &value) || !Smi::IsValid(value)) {
1824 *kind = ObjectIdRing::kInvalid;
1825 return Object::null();
1826 }
1827 const Integer& obj =
1828 Integer::Handle(thread->zone(), Smi::New(static_cast<intptr_t>(value)));
1829 return obj.ptr();
1830 } else if (strcmp(arg, "bool-true") == 0) {
1831 return Bool::True().ptr();
1832 } else if (strcmp(arg, "bool-false") == 0) {
1833 return Bool::False().ptr();
1834 } else if (strcmp(arg, "null") == 0) {
1835 return Object::null();
1836 }
1837
1838 ObjectIdRing* ring = thread->isolate()->EnsureObjectIdRing();
1839 intptr_t id = -1;
1840 if (!GetIntegerId(arg, &id)) {
1841 *kind = ObjectIdRing::kInvalid;
1842 return Object::null();
1843 }
1844 return ring->GetObjectForId(id, kind);
1845}
1846
1848 const Class& klass,
1849 char** parts,
1850 int num_parts) {
1851 auto zone = thread->zone();
1852
1853 if (num_parts != 4) {
1854 return Object::sentinel().ptr();
1855 }
1856
1857 const char* encoded_id = parts[3];
1858 auto& id = String::Handle(String::New(encoded_id));
1859 id = String::DecodeIRI(id);
1860 if (id.IsNull()) {
1861 return Object::sentinel().ptr();
1862 }
1863
1864 if (strcmp(parts[2], "fields") == 0) {
1865 // Field ids look like: "classes/17/fields/name"
1866 const auto& field = Field::Handle(klass.LookupField(id));
1867 if (field.IsNull()) {
1868 return Object::sentinel().ptr();
1869 }
1870 return field.ptr();
1871 }
1872 if (strcmp(parts[2], "field_inits") == 0) {
1873 // Field initializer ids look like: "classes/17/field_inits/name"
1874 const auto& field = Field::Handle(klass.LookupField(id));
1875 if (field.IsNull() || (field.is_late() && !field.has_initializer())) {
1876 return Object::sentinel().ptr();
1877 }
1878 const auto& function = Function::Handle(field.EnsureInitializerFunction());
1879 if (function.IsNull()) {
1880 return Object::sentinel().ptr();
1881 }
1882 return function.ptr();
1883 }
1884 if (strcmp(parts[2], "functions") == 0) {
1885 // Function ids look like: "classes/17/functions/name"
1886
1887 const auto& function =
1889 if (function.IsNull()) {
1890 return Object::sentinel().ptr();
1891 }
1892 return function.ptr();
1893 }
1894 if (strcmp(parts[2], "implicit_closures") == 0) {
1895 // Function ids look like: "classes/17/implicit_closures/11"
1896 intptr_t id;
1897 if (!GetIntegerId(parts[3], &id)) {
1898 return Object::sentinel().ptr();
1899 }
1900 const auto& func =
1902 if (func.IsNull()) {
1903 return Object::sentinel().ptr();
1904 }
1905 return func.ptr();
1906 }
1907 if (strcmp(parts[2], "dispatchers") == 0) {
1908 // Dispatcher Function ids look like: "classes/17/dispatchers/11"
1909 intptr_t id;
1910 if (!GetIntegerId(parts[3], &id)) {
1911 return Object::sentinel().ptr();
1912 }
1913 const auto& func =
1915 if (func.IsNull()) {
1916 return Object::sentinel().ptr();
1917 }
1918 return func.ptr();
1919 }
1920 if (strcmp(parts[2], "closures") == 0) {
1921 // Closure ids look like: "classes/17/closures/11"
1922 intptr_t id;
1923 if (!GetIntegerId(parts[3], &id)) {
1924 return Object::sentinel().ptr();
1925 }
1926 Function& func = Function::Handle(zone);
1928 if (func.IsNull()) {
1929 return Object::sentinel().ptr();
1930 }
1931 return func.ptr();
1932 }
1933
1934 UNREACHABLE();
1935 return Object::sentinel().ptr();
1936}
1937
1939 char** parts,
1940 int num_parts) {
1941 // Library ids look like "libraries/35"
1942 if (num_parts < 2) {
1943 return Object::sentinel().ptr();
1944 }
1945 const auto& libs =
1946 GrowableObjectArray::Handle(isolate_group->object_store()->libraries());
1947 ASSERT(!libs.IsNull());
1948 const String& id = String::Handle(String::New(parts[1]));
1949 // Scan for private key.
1950 String& private_key = String::Handle();
1951 Library& lib = Library::Handle();
1952 bool lib_found = false;
1953 for (intptr_t i = 0; i < libs.Length(); i++) {
1954 lib ^= libs.At(i);
1955 ASSERT(!lib.IsNull());
1956 private_key = lib.private_key();
1957 if (private_key.Equals(id)) {
1958 lib_found = true;
1959 break;
1960 }
1961 }
1962 if (!lib_found) {
1963 return Object::sentinel().ptr();
1964 }
1965
1966 const auto& klass = Class::Handle(lib.toplevel_class());
1967 ASSERT(!klass.IsNull());
1968
1969 if (num_parts == 2) {
1970 return lib.ptr();
1971 }
1972 if (strcmp(parts[2], "fields") == 0) {
1973 // Library field ids look like: "libraries/17/fields/name"
1974 return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
1975 }
1976 if (strcmp(parts[2], "field_inits") == 0) {
1977 // Library field ids look like: "libraries/17/field_inits/name"
1978 return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
1979 }
1980 if (strcmp(parts[2], "functions") == 0) {
1981 // Library function ids look like: "libraries/17/functions/name"
1982 return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
1983 }
1984 if (strcmp(parts[2], "closures") == 0) {
1985 // Library function ids look like: "libraries/17/closures/name"
1986 return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
1987 }
1988 if (strcmp(parts[2], "implicit_closures") == 0) {
1989 // Library function ids look like: "libraries/17/implicit_closures/name"
1990 return LookupClassMembers(Thread::Current(), klass, parts, num_parts);
1991 }
1992
1993 if (strcmp(parts[2], "scripts") == 0) {
1994 // Script ids look like "libraries/35/scripts/library%2Furl.dart/12345"
1995 if (num_parts != 5) {
1996 return Object::sentinel().ptr();
1997 }
1998 const String& id = String::Handle(String::New(parts[3]));
1999 ASSERT(!id.IsNull());
2000 // The id is the url of the script % encoded, decode it.
2001 const String& requested_url = String::Handle(String::DecodeIRI(id));
2002
2003 // Each script id is tagged with a load time.
2004 int64_t timestamp;
2005 if (!GetInteger64Id(parts[4], &timestamp, 16) || (timestamp < 0)) {
2006 return Object::sentinel().ptr();
2007 }
2008
2010 String& script_url = String::Handle();
2011 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
2012 ASSERT(!loaded_scripts.IsNull());
2013 intptr_t i;
2014 for (i = 0; i < loaded_scripts.Length(); i++) {
2015 script ^= loaded_scripts.At(i);
2016 ASSERT(!script.IsNull());
2017 script_url = script.url();
2018 if (script_url.Equals(requested_url) &&
2019 (timestamp == script.load_timestamp())) {
2020 return script.ptr();
2021 }
2022 }
2023 }
2024
2025 // Not found.
2026 return Object::sentinel().ptr();
2027}
2028
2030 char** parts,
2031 int num_parts) {
2032 // Class ids look like: "classes/17"
2033 if (num_parts < 2) {
2034 return Object::sentinel().ptr();
2035 }
2036 Zone* zone = thread->zone();
2037 auto table = thread->isolate_group()->class_table();
2038 intptr_t id;
2039 if (!GetIntegerId(parts[1], &id) || !table->IsValidIndex(id)) {
2040 return Object::sentinel().ptr();
2041 }
2042 Class& cls = Class::Handle(zone, table->At(id));
2043 if (num_parts == 2) {
2044 return cls.ptr();
2045 }
2046 if (strcmp(parts[2], "closures") == 0) {
2047 // Closure ids look like: "classes/17/closures/11"
2048 return LookupClassMembers(thread, cls, parts, num_parts);
2049 } else if (strcmp(parts[2], "field_inits") == 0) {
2050 // Field initializer ids look like: "classes/17/field_inits/name"
2051 return LookupClassMembers(thread, cls, parts, num_parts);
2052 } else if (strcmp(parts[2], "fields") == 0) {
2053 // Field ids look like: "classes/17/fields/name"
2054 return LookupClassMembers(thread, cls, parts, num_parts);
2055 } else if (strcmp(parts[2], "functions") == 0) {
2056 // Function ids look like: "classes/17/functions/name"
2057 return LookupClassMembers(thread, cls, parts, num_parts);
2058 } else if (strcmp(parts[2], "implicit_closures") == 0) {
2059 // Function ids look like: "classes/17/implicit_closures/11"
2060 return LookupClassMembers(thread, cls, parts, num_parts);
2061 } else if (strcmp(parts[2], "dispatchers") == 0) {
2062 // Dispatcher Function ids look like: "classes/17/dispatchers/11"
2063 return LookupClassMembers(thread, cls, parts, num_parts);
2064 } else if (strcmp(parts[2], "types") == 0) {
2065 // Type ids look like: "classes/17/types/11"
2066 if (num_parts != 4) {
2067 return Object::sentinel().ptr();
2068 }
2069 intptr_t id;
2070 if (!GetIntegerId(parts[3], &id)) {
2071 return Object::sentinel().ptr();
2072 }
2073 if (id != 0) {
2074 return Object::sentinel().ptr();
2075 }
2076 const Type& type = Type::Handle(zone, cls.DeclarationType());
2077 if (!type.IsNull()) {
2078 return type.ptr();
2079 }
2080 }
2081
2082 // Not found.
2083 return Object::sentinel().ptr();
2084}
2085
2087 char** parts,
2088 int num_parts) {
2089 // TypeArguments ids look like: "typearguments/17"
2090 if (num_parts < 2) {
2091 return Object::sentinel().ptr();
2092 }
2093 intptr_t id;
2094 if (!GetIntegerId(parts[1], &id)) {
2095 return Object::sentinel().ptr();
2096 }
2097 ObjectStore* object_store = thread->isolate_group()->object_store();
2098 const Array& table =
2099 Array::Handle(thread->zone(), object_store->canonical_type_arguments());
2100 ASSERT(table.Length() > 0);
2101 const intptr_t table_size = table.Length() - 1;
2102 if ((id < 0) || (id >= table_size) || (table.At(id) == Object::null())) {
2103 return Object::sentinel().ptr();
2104 }
2105 return table.At(id);
2106}
2107
2108static ObjectPtr LookupHeapObjectCode(char** parts, int num_parts) {
2109 if (num_parts != 2) {
2110 return Object::sentinel().ptr();
2111 }
2112 uword pc;
2113 const char* const kCollectedPrefix = "collected-";
2114 const intptr_t kCollectedPrefixLen = strlen(kCollectedPrefix);
2115 const char* const kNativePrefix = "native-";
2116 const intptr_t kNativePrefixLen = strlen(kNativePrefix);
2117 const char* const kReusedPrefix = "reused-";
2118 const intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
2119 const char* id = parts[1];
2120 if (strncmp(kCollectedPrefix, id, kCollectedPrefixLen) == 0) {
2121 if (!GetUnsignedIntegerId(&id[kCollectedPrefixLen], &pc, 16)) {
2122 return Object::sentinel().ptr();
2123 }
2124 // TODO(turnidge): Return "collected" instead.
2125 return Object::null();
2126 }
2127 if (strncmp(kNativePrefix, id, kNativePrefixLen) == 0) {
2128 if (!GetUnsignedIntegerId(&id[kNativePrefixLen], &pc, 16)) {
2129 return Object::sentinel().ptr();
2130 }
2131 // TODO(johnmccutchan): Support native Code.
2132 return Object::null();
2133 }
2134 if (strncmp(kReusedPrefix, id, kReusedPrefixLen) == 0) {
2135 if (!GetUnsignedIntegerId(&id[kReusedPrefixLen], &pc, 16)) {
2136 return Object::sentinel().ptr();
2137 }
2138 // TODO(turnidge): Return "expired" instead.
2139 return Object::null();
2140 }
2141 int64_t timestamp = 0;
2142 if (!GetCodeId(id, &timestamp, &pc) || (timestamp < 0)) {
2143 return Object::sentinel().ptr();
2144 }
2145 Code& code = Code::Handle(Code::FindCode(pc, timestamp));
2146 if (!code.IsNull()) {
2147 return code.ptr();
2148 }
2149
2150 // Not found.
2151 return Object::sentinel().ptr();
2152}
2153
2155 char** parts,
2156 int num_parts) {
2157 if (num_parts != 2) {
2158 return Object::sentinel().ptr();
2159 }
2160 uword message_id = 0;
2161 if (!GetUnsignedIntegerId(parts[1], &message_id, 16)) {
2162 return Object::sentinel().ptr();
2163 }
2165 Message* message = aq.queue()->FindMessageById(message_id);
2166 if (message == nullptr) {
2167 // The user may try to load an expired message.
2168 return Object::sentinel().ptr();
2169 }
2170 if (message->IsRaw()) {
2171 return message->raw_obj();
2172 } else {
2173 return ReadMessage(thread, message);
2174 }
2175}
2176
2178 const char* id_original,
2180 char* id = thread->zone()->MakeCopyOfString(id_original);
2181
2182 // Parse the id by splitting at each '/'.
2183 const int MAX_PARTS = 8;
2184 char* parts[MAX_PARTS];
2185 int num_parts = 0;
2186 int i = 0;
2187 int start_pos = 0;
2188 while (id[i] != '\0') {
2189 if (id[i] == '/') {
2190 id[i++] = '\0';
2191 parts[num_parts++] = &id[start_pos];
2192 if (num_parts == MAX_PARTS) {
2193 break;
2194 }
2195 start_pos = i;
2196 } else {
2197 i++;
2198 }
2199 }
2200 if (num_parts < MAX_PARTS) {
2201 parts[num_parts++] = &id[start_pos];
2202 }
2203
2204 if (result != nullptr) {
2206 }
2207
2208 Isolate* isolate = thread->isolate();
2209 if (strcmp(parts[0], "objects") == 0) {
2210 // Object ids look like "objects/1123"
2211 Object& obj = Object::Handle(thread->zone());
2212 ObjectIdRing::LookupResult lookup_result;
2213 obj = LookupObjectId(thread, parts[1], &lookup_result);
2214 if (lookup_result != ObjectIdRing::kValid) {
2215 if (result != nullptr) {
2216 *result = lookup_result;
2217 }
2218 return Object::sentinel().ptr();
2219 }
2220 return obj.ptr();
2221
2222 } else if (strcmp(parts[0], "libraries") == 0) {
2223 return LookupHeapObjectLibraries(isolate->group(), parts, num_parts);
2224 } else if (strcmp(parts[0], "classes") == 0) {
2225 return LookupHeapObjectClasses(thread, parts, num_parts);
2226 } else if (strcmp(parts[0], "typearguments") == 0) {
2227 return LookupHeapObjectTypeArguments(thread, parts, num_parts);
2228 } else if (strcmp(parts[0], "code") == 0) {
2229 return LookupHeapObjectCode(parts, num_parts);
2230 } else if (strcmp(parts[0], "messages") == 0) {
2231 return LookupHeapObjectMessage(thread, parts, num_parts);
2232 }
2233
2234 // Not found.
2235 return Object::sentinel().ptr();
2236}
2237
2239 const char* id,
2242 size_t end_pos = strcspn(id, "/");
2243 if (end_pos == strlen(id)) {
2244 return nullptr;
2245 }
2246 const char* rest = id + end_pos + 1; // +1 for '/'.
2247 if (strncmp("breakpoints", id, end_pos) == 0) {
2248 intptr_t bpt_id = 0;
2249 Breakpoint* bpt = nullptr;
2250 if (GetIntegerId(rest, &bpt_id)) {
2251 bpt = isolate->debugger()->GetBreakpointById(bpt_id);
2252 if (bpt != nullptr) {
2254 return bpt;
2255 }
2256 if (bpt_id < isolate->debugger()->limitBreakpointId()) {
2258 return nullptr;
2259 }
2260 }
2261 }
2262 return nullptr;
2263}
2264
2266 Thread* thread,
2267 Array* field_names_handle,
2268 String* name_handle,
2269 const JSONObject& jsresponse,
2270 const Record& record,
2271 const intptr_t field_slot_offset) {
2272 *field_names_handle = record.GetFieldNames(thread);
2273 const intptr_t num_positional_fields =
2274 record.num_fields() - field_names_handle->Length();
2275 const intptr_t field_index =
2276 (field_slot_offset - Record::field_offset(0)) / Record::kBytesPerElement;
2277 if (field_index < num_positional_fields) {
2278 jsresponse.AddProperty("parentField", field_index);
2279 } else {
2280 *name_handle ^= field_names_handle->At(field_index - num_positional_fields);
2281 jsresponse.AddProperty("parentField", name_handle->ToCString());
2282 }
2283}
2284
2285static void PrintInboundReferences(Thread* thread,
2286 Object* target,
2287 intptr_t limit,
2288 JSONStream* js) {
2289 ObjectGraph graph(thread);
2290 Array& path = Array::Handle(Array::New(limit * 2));
2291 intptr_t length = graph.InboundReferences(target, path);
2292 OffsetsTable offsets_table(thread->zone());
2293 JSONObject jsobj(js);
2294 jsobj.AddProperty("type", "InboundReferences");
2295 {
2296 JSONArray elements(&jsobj, "references");
2298 Smi& slot_offset = Smi::Handle();
2299 Array& field_names = Array::Handle();
2301 Class& source_class = Class::Handle();
2302 Field& field = Field::Handle();
2303 Array& parent_field_map = Array::Handle();
2304 limit = Utils::Minimum(limit, length);
2305 for (intptr_t i = 0; i < limit; ++i) {
2306 JSONObject jselement(&elements);
2307 source = path.At(i * 2);
2308 slot_offset ^= path.At((i * 2) + 1);
2309
2310 jselement.AddProperty("source", source);
2311 if (source.IsArray()) {
2312 intptr_t element_index =
2313 (slot_offset.Value() - Array::element_offset(0)) /
2315 jselement.AddProperty("parentListIndex", element_index);
2316 jselement.AddProperty("parentField", element_index);
2317 } else if (source.IsRecord()) {
2318 AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name,
2319 jselement, Record::Cast(source),
2320 slot_offset.Value());
2321 } else {
2322 if (source.IsInstance()) {
2323 source_class = source.clazz();
2324 parent_field_map = source_class.OffsetToFieldMap();
2325 intptr_t index = slot_offset.Value() >> kCompressedWordSizeLog2;
2326 if (index > 0 && index < parent_field_map.Length()) {
2327 field ^= parent_field_map.At(index);
2328 if (!field.IsNull()) {
2329 jselement.AddProperty("parentField", field);
2330 continue;
2331 }
2332 }
2333 }
2334 const char* field_name = offsets_table.FieldNameForOffset(
2335 source.GetClassId(), slot_offset.Value());
2336 if (field_name != nullptr) {
2337 jselement.AddProperty("_parentWordOffset", slot_offset.Value());
2338 // TODO(vm-service): Adjust RPC type to allow returning a field name
2339 // without a field object, or reify the fields described by
2340 // raw_object_fields.cc
2341 // jselement.AddProperty("_parentFieldName", field_name);
2342 } else if (source.IsContext()) {
2343 intptr_t element_index =
2344 (slot_offset.Value() - Context::variable_offset(0)) /
2346 jselement.AddProperty("parentListIndex", element_index);
2347 jselement.AddProperty("parentField", element_index);
2348 } else {
2349 jselement.AddProperty("_parentWordOffset", slot_offset.Value());
2350 }
2351 }
2352 }
2353 }
2354
2355 // We nil out the array after generating the response to prevent
2356 // reporting spurious references when repeatedly looking for the
2357 // references to an object.
2358 for (intptr_t i = 0; i < path.Length(); i++) {
2359 path.SetAt(i, Object::null_object());
2360 }
2361}
2362
2365 nullptr,
2366};
2367
2369 const char* target_id = js->LookupParam("targetId");
2370 if (target_id == nullptr) {
2371 PrintMissingParamError(js, "targetId");
2372 return;
2373 }
2374 const char* limit_cstr = js->LookupParam("limit");
2375 if (limit_cstr == nullptr) {
2376 PrintMissingParamError(js, "limit");
2377 return;
2378 }
2379 intptr_t limit;
2380 if (!GetIntegerId(limit_cstr, &limit)) {
2381 PrintInvalidParamError(js, "limit");
2382 return;
2383 }
2384
2385 Object& obj = Object::Handle(thread->zone());
2386 ObjectIdRing::LookupResult lookup_result;
2387 {
2388 HANDLESCOPE(thread);
2389 obj = LookupHeapObject(thread, target_id, &lookup_result);
2390 }
2391 if (obj.ptr() == Object::sentinel().ptr()) {
2392 if (lookup_result == ObjectIdRing::kCollected) {
2394 } else if (lookup_result == ObjectIdRing::kExpired) {
2396 } else {
2397 PrintInvalidParamError(js, "targetId");
2398 }
2399 return;
2400 }
2401 PrintInboundReferences(thread, &obj, limit, js);
2402}
2403
2404static void PrintRetainingPath(Thread* thread,
2405 Object* obj,
2406 intptr_t limit,
2407 JSONStream* js) {
2408 ObjectGraph graph(thread);
2409 Array& path = Array::Handle(Array::New(limit * 2));
2410 auto result = graph.RetainingPath(obj, path);
2411 intptr_t length = result.length;
2412 JSONObject jsobj(js);
2413 jsobj.AddProperty("type", "RetainingPath");
2414 jsobj.AddProperty("length", length);
2415 jsobj.AddProperty("gcRootType", result.gc_root_type);
2416 JSONArray elements(&jsobj, "elements");
2417 Object& element = Object::Handle();
2418 Smi& slot_offset = Smi::Handle();
2419 Array& field_names = Array::Handle();
2421 Class& element_class = Class::Handle();
2422 Array& element_field_map = Array::Handle();
2423 Map& map = Map::Handle();
2424 Array& map_data = Array::Handle();
2425 Field& field = Field::Handle();
2427 limit = Utils::Minimum(limit, length);
2428 OffsetsTable offsets_table(thread->zone());
2429 for (intptr_t i = 0; i < limit; ++i) {
2430 JSONObject jselement(&elements);
2431 element = path.At(i * 2);
2432 jselement.AddProperty("value", element);
2433 // Interpret the word offset from parent as list index, map key,
2434 // weak property, or instance field.
2435 if (i > 0) {
2436 slot_offset ^= path.At((i * 2) - 1);
2437 if (element.IsArray() || element.IsGrowableObjectArray()) {
2438 intptr_t element_index =
2439 (slot_offset.Value() - Array::element_offset(0)) /
2441 jselement.AddProperty("parentListIndex", element_index);
2442 jselement.AddProperty("parentField", element_index);
2443 } else if (element.IsRecord()) {
2444 AddParentFieldToResponseBasedOnRecord(thread, &field_names, &name,
2445 jselement, Record::Cast(element),
2446 slot_offset.Value());
2447 } else if (element.IsMap()) {
2448 map = static_cast<MapPtr>(path.At(i * 2));
2449 map_data = map.data();
2450 intptr_t element_index =
2451 (slot_offset.Value() - Array::element_offset(0)) /
2453 Map::Iterator iterator(map);
2454 while (iterator.MoveNext()) {
2455 if (iterator.CurrentKey() == map_data.At(element_index) ||
2456 iterator.CurrentValue() == map_data.At(element_index)) {
2457 element = iterator.CurrentKey();
2458 jselement.AddProperty("parentMapKey", element);
2459 break;
2460 }
2461 }
2462 } else if (element.IsWeakProperty()) {
2463 wp ^= static_cast<WeakPropertyPtr>(element.ptr());
2464 element = wp.key();
2465 jselement.AddProperty("parentMapKey", element);
2466 } else {
2467 if (element.IsInstance()) {
2468 element_class = element.clazz();
2469 element_field_map = element_class.OffsetToFieldMap();
2470 intptr_t index = slot_offset.Value() >> kCompressedWordSizeLog2;
2471 if ((index > 0) && (index < element_field_map.Length())) {
2472 field ^= element_field_map.At(index);
2473 if (!field.IsNull()) {
2474 name ^= field.name();
2475 jselement.AddProperty("parentField", name.ToCString());
2476 continue;
2477 }
2478 }
2479 }
2480 const char* field_name = offsets_table.FieldNameForOffset(
2481 element.GetClassId(), slot_offset.Value());
2482 if (field_name != nullptr) {
2483 jselement.AddProperty("parentField", field_name);
2484 } else if (element.IsContext()) {
2485 intptr_t element_index =
2486 (slot_offset.Value() - Context::variable_offset(0)) /
2488 jselement.AddProperty("parentListIndex", element_index);
2489 jselement.AddProperty("parentField", element_index);
2490 } else {
2491 jselement.AddProperty("_parentWordOffset", slot_offset.Value());
2492 }
2493 }
2494 }
2495 }
2496
2497 // We nil out the array after generating the response to prevent
2498 // reporting spurious references when looking for inbound references
2499 // after looking for a retaining path.
2500 for (intptr_t i = 0; i < path.Length(); i++) {
2501 path.SetAt(i, Object::null_object());
2502 }
2503}
2504
2507 nullptr,
2508};
2509
2510static void GetRetainingPath(Thread* thread, JSONStream* js) {
2511 const char* target_id = js->LookupParam("targetId");
2512 if (target_id == nullptr) {
2513 PrintMissingParamError(js, "targetId");
2514 return;
2515 }
2516 const char* limit_cstr = js->LookupParam("limit");
2517 if (limit_cstr == nullptr) {
2518 PrintMissingParamError(js, "limit");
2519 return;
2520 }
2521 intptr_t limit;
2522 if (!GetIntegerId(limit_cstr, &limit)) {
2523 PrintInvalidParamError(js, "limit");
2524 return;
2525 }
2526
2527 Object& obj = Object::Handle(thread->zone());
2528 ObjectIdRing::LookupResult lookup_result;
2529 {
2530 HANDLESCOPE(thread);
2531 obj = LookupHeapObject(thread, target_id, &lookup_result);
2532 }
2533 if (obj.ptr() == Object::sentinel().ptr()) {
2534 if (lookup_result == ObjectIdRing::kCollected) {
2536 } else if (lookup_result == ObjectIdRing::kExpired) {
2538 } else {
2539 PrintInvalidParamError(js, "targetId");
2540 }
2541 return;
2542 }
2543 PrintRetainingPath(thread, &obj, limit, js);
2544}
2545
2548 new IdParameter("targetId", true),
2549 nullptr,
2550};
2551
2552static void GetRetainedSize(Thread* thread, JSONStream* js) {
2553 const char* target_id = js->LookupParam("targetId");
2554 ASSERT(target_id != nullptr);
2555 ObjectIdRing::LookupResult lookup_result;
2556 Object& obj =
2557 Object::Handle(LookupHeapObject(thread, target_id, &lookup_result));
2558 if (obj.ptr() == Object::sentinel().ptr()) {
2559 if (lookup_result == ObjectIdRing::kCollected) {
2561 } else if (lookup_result == ObjectIdRing::kExpired) {
2563 } else {
2564 PrintInvalidParamError(js, "targetId");
2565 }
2566 return;
2567 }
2568 // TODO(rmacnak): There is no way to get the size retained by a class object.
2569 // SizeRetainedByClass should be a separate RPC.
2570 if (obj.IsClass()) {
2571 const Class& cls = Class::Cast(obj);
2572 ObjectGraph graph(thread);
2573 intptr_t retained_size = graph.SizeRetainedByClass(cls.id());
2574 const Object& result = Object::Handle(Integer::New(retained_size));
2575 result.PrintJSON(js, true);
2576 return;
2577 }
2578
2579 ObjectGraph graph(thread);
2580 intptr_t retained_size = graph.SizeRetainedByInstance(obj);
2581 const Object& result = Object::Handle(Integer::New(retained_size));
2582 result.PrintJSON(js, true);
2583}
2584
2587 new IdParameter("targetId", true),
2588 nullptr,
2589};
2590
2591static void GetReachableSize(Thread* thread, JSONStream* js) {
2592 const char* target_id = js->LookupParam("targetId");
2593 ASSERT(target_id != nullptr);
2594 ObjectIdRing::LookupResult lookup_result;
2595 Object& obj =
2596 Object::Handle(LookupHeapObject(thread, target_id, &lookup_result));
2597 if (obj.ptr() == Object::sentinel().ptr()) {
2598 if (lookup_result == ObjectIdRing::kCollected) {
2600 } else if (lookup_result == ObjectIdRing::kExpired) {
2602 } else {
2603 PrintInvalidParamError(js, "targetId");
2604 }
2605 return;
2606 }
2607 // TODO(rmacnak): There is no way to get the size retained by a class object.
2608 // SizeRetainedByClass should be a separate RPC.
2609 if (obj.IsClass()) {
2610 const Class& cls = Class::Cast(obj);
2611 ObjectGraph graph(thread);
2612 intptr_t retained_size = graph.SizeReachableByClass(cls.id());
2613 const Object& result = Object::Handle(Integer::New(retained_size));
2614 result.PrintJSON(js, true);
2615 return;
2616 }
2617
2618 ObjectGraph graph(thread);
2619 intptr_t retained_size = graph.SizeReachableByInstance(obj);
2620 const Object& result = Object::Handle(Integer::New(retained_size));
2621 result.PrintJSON(js, true);
2622}
2623
2624static const MethodParameter* const invoke_params[] = {
2626 nullptr,
2627};
2628
2629static void Invoke(Thread* thread, JSONStream* js) {
2630 const char* receiver_id = js->LookupParam("targetId");
2631 if (receiver_id == nullptr) {
2632 PrintMissingParamError(js, "targetId");
2633 return;
2634 }
2635 const char* selector_cstr = js->LookupParam("selector");
2636 if (selector_cstr == nullptr) {
2637 PrintMissingParamError(js, "selector");
2638 return;
2639 }
2640 const char* argument_ids = js->LookupParam("argumentIds");
2641 if (argument_ids == nullptr) {
2642 PrintMissingParamError(js, "argumentIds");
2643 return;
2644 }
2645
2646#if !defined(DART_PRECOMPILED_RUNTIME)
2647 bool disable_breakpoints =
2648 BoolParameter::Parse(js->LookupParam("disableBreakpoints"), false);
2650 disable_breakpoints);
2651#endif
2652
2653 Zone* zone = thread->zone();
2654 ObjectIdRing::LookupResult lookup_result;
2655 Object& receiver = Object::Handle(
2656 zone, LookupHeapObject(thread, receiver_id, &lookup_result));
2657 if (receiver.ptr() == Object::sentinel().ptr()) {
2658 if (lookup_result == ObjectIdRing::kCollected) {
2660 } else if (lookup_result == ObjectIdRing::kExpired) {
2662 } else {
2663 PrintInvalidParamError(js, "targetId");
2664 }
2665 return;
2666 }
2667
2668 const GrowableObjectArray& growable_args =
2670
2671 bool is_instance = (receiver.IsInstance() || receiver.IsNull()) &&
2672 !ContainsNonInstance(receiver);
2673 if (is_instance) {
2674 growable_args.Add(receiver);
2675 }
2676
2677 intptr_t n = strlen(argument_ids);
2678 if ((n < 2) || (argument_ids[0] != '[') || (argument_ids[n - 1] != ']')) {
2679 PrintInvalidParamError(js, "argumentIds");
2680 return;
2681 }
2682 if (n > 2) {
2683 intptr_t start = 1;
2684 while (start < n) {
2685 intptr_t end = start;
2686 while ((argument_ids[end + 1] != ',') && (argument_ids[end + 1] != ']')) {
2687 end++;
2688 }
2689 if (end == start) {
2690 // Empty element.
2691 PrintInvalidParamError(js, "argumentIds");
2692 return;
2693 }
2694
2695 const char* argument_id =
2696 zone->MakeCopyOfStringN(&argument_ids[start], end - start + 1);
2697
2698 ObjectIdRing::LookupResult lookup_result;
2699 Object& argument = Object::Handle(
2700 zone, LookupHeapObject(thread, argument_id, &lookup_result));
2701 // Invoke only accepts Instance arguments.
2702 if (!(argument.IsInstance() || argument.IsNull()) ||
2703 ContainsNonInstance(argument)) {
2704 PrintInvalidParamError(js, "argumentIds");
2705 return;
2706 }
2707 if (argument.ptr() == Object::sentinel().ptr()) {
2708 if (lookup_result == ObjectIdRing::kCollected) {
2710 } else if (lookup_result == ObjectIdRing::kExpired) {
2712 } else {
2713 PrintInvalidParamError(js, "argumentIds");
2714 }
2715 return;
2716 }
2717 growable_args.Add(argument);
2718
2719 start = end + 3;
2720 }
2721 }
2722
2723 const String& selector = String::Handle(zone, String::New(selector_cstr));
2724 const Array& args =
2725 Array::Handle(zone, Array::MakeFixedLength(growable_args));
2726 const Array& arg_names = Object::empty_array();
2727
2728 if (receiver.IsLibrary()) {
2729 const Library& lib = Library::Cast(receiver);
2730 const Object& result =
2731 Object::Handle(zone, lib.Invoke(selector, args, arg_names));
2732 result.PrintJSON(js, true);
2733 return;
2734 }
2735 if (receiver.IsClass()) {
2736 const Class& cls = Class::Cast(receiver);
2737 const Object& result =
2738 Object::Handle(zone, cls.Invoke(selector, args, arg_names));
2739 result.PrintJSON(js, true);
2740 return;
2741 }
2742 if (is_instance) {
2743 // We don't use Instance::Cast here because it doesn't allow null.
2745 instance ^= receiver.ptr();
2746 const Object& result =
2747 Object::Handle(zone, instance.Invoke(selector, args, arg_names));
2748 result.PrintJSON(js, true);
2749 return;
2750 }
2751 js->PrintError(kInvalidParams,
2752 "%s: invalid 'targetId' parameter: "
2753 "Cannot invoke against a VM-internal object",
2754 js->method());
2755}
2756
2757static const MethodParameter* const evaluate_params[] = {
2759 nullptr,
2760};
2761
2762static bool IsAlpha(char c) {
2763 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
2764}
2765static bool IsAlphaOrDollar(char c) {
2766 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '$');
2767}
2768static bool IsAlphaNum(char c) {
2769 return (c >= '0' && c <= '9') || IsAlpha(c);
2770}
2771static bool IsAlphaNumOrDollar(char c) {
2772 return (c >= '0' && c <= '9') || IsAlphaOrDollar(c);
2773}
2774static bool IsWhitespace(char c) {
2775 return c <= ' ';
2776}
2777static bool IsObjectIdChar(char c) {
2778 return IsAlphaNum(c) || c == '/' || c == '-' || c == '@' || c == '%';
2779}
2780
2781// TODO(vm-service): Consider whether we should pass structured objects in
2782// service messages instead of always flattening them to C strings.
2783static bool ParseScope(const char* scope,
2786 Zone* zone = Thread::Current()->zone();
2787 const char* c = scope;
2788 if (*c++ != '{') return false;
2789
2790 for (;;) {
2791 while (IsWhitespace(*c)) {
2792 c++;
2793 }
2794
2795 if (*c == '}') return true;
2796
2797 const char* name = c;
2798 if (!IsAlphaOrDollar(*c)) return false;
2799 while (IsAlphaNumOrDollar(*c)) {
2800 c++;
2801 }
2802 names->Add(zone->MakeCopyOfStringN(name, c - name));
2803
2804 while (IsWhitespace(*c)) {
2805 c++;
2806 }
2807
2808 if (*c++ != ':') return false;
2809
2810 while (IsWhitespace(*c)) {
2811 c++;
2812 }
2813
2814 const char* id = c;
2815 if (!IsObjectIdChar(*c)) return false;
2816 while (IsObjectIdChar(*c)) {
2817 c++;
2818 }
2819 ids->Add(zone->MakeCopyOfStringN(id, c - id));
2820
2821 while (IsWhitespace(*c)) {
2822 c++;
2823 }
2824 if (*c == ',') c++;
2825 }
2826
2827 return false;
2828}
2829
2830static bool BuildScope(Thread* thread,
2831 JSONStream* js,
2833 const GrowableObjectArray& values) {
2834 const char* scope = js->LookupParam("scope");
2837 if (scope != nullptr) {
2838 if (!ParseScope(scope, &cnames, &cids)) {
2839 PrintInvalidParamError(js, "scope");
2840 return true;
2841 }
2843 Object& obj = Object::Handle();
2844 for (intptr_t i = 0; i < cids.length(); i++) {
2845 ObjectIdRing::LookupResult lookup_result;
2846 obj = LookupHeapObject(thread, cids[i], &lookup_result);
2847 if (obj.ptr() == Object::sentinel().ptr()) {
2848 if (lookup_result == ObjectIdRing::kCollected) {
2850 } else if (lookup_result == ObjectIdRing::kExpired) {
2852 } else {
2853 PrintInvalidParamError(js, "targetId");
2854 }
2855 return true;
2856 }
2857 if ((!obj.IsInstance() && !obj.IsNull()) || ContainsNonInstance(obj)) {
2858 js->PrintError(kInvalidParams,
2859 "%s: invalid scope 'targetId' parameter: "
2860 "Cannot evaluate against a VM-internal object",
2861 js->method());
2862 return true;
2863 }
2864 name = String::New(cnames[i]);
2865 names.Add(name);
2866 values.Add(obj);
2867 }
2868 }
2869 return false;
2870}
2871
2872static void Evaluate(Thread* thread, JSONStream* js) {
2873 // If a compilation service is available, this RPC invocation will have been
2874 // intercepted by RunningIsolates.routeRequest.
2875 js->PrintError(
2877 "%s: No compilation service available; cannot evaluate from source.",
2878 js->method());
2879}
2880
2882 {
2884 new IdParameter("frameIndex", false),
2885 new IdParameter("targetId", false),
2886 nullptr,
2887};
2888
2889static void CollectStringifiedType(Thread* thread,
2890 Zone* zone,
2891 const AbstractType& type,
2892 const GrowableObjectArray& output) {
2894 if (type.IsFunctionType()) {
2895 // The closure class
2896 // (IsolateGroup::Current()->object_store()->closure_class())
2897 // is statically typed weird (the call method redirects to itself)
2898 // and the type is therefore not useful for the CFE. We use null instead.
2899 output.Add(instance);
2900 return;
2901 }
2902 if (type.IsRecordType()) {
2903 // _Record class is not useful for the CFE. We use null instead.
2904 output.Add(instance);
2905 return;
2906 }
2907 if (type.IsDynamicType()) {
2908 // Dynamic is weird in that it seems to have a class with no name and a
2909 // library called something like '7189777121420'. We use null instead.
2910 output.Add(instance);
2911 return;
2912 }
2913 if (type.IsTypeParameter()) {
2914 // Calling type_class on a type parameter will crash the VM.
2915 // We use null instead.
2916 output.Add(instance);
2917 return;
2918 }
2919 ASSERT(type.IsType());
2920
2921 const Class& cls = Class::Handle(type.type_class());
2922 const Library& lib = Library::Handle(zone, cls.library());
2923
2924 instance ^= lib.url();
2925 output.Add(instance);
2926
2927 instance ^= cls.ScrubbedName();
2928 output.Add(instance);
2929
2930 instance ^= Smi::New((intptr_t)type.nullability());
2931 output.Add(instance);
2932
2933 const TypeArguments& type_arguments =
2934 TypeArguments::Handle(Type::Cast(type).arguments());
2935 if (!type_arguments.IsNull()) {
2936 instance ^= Smi::New(type_arguments.Length());
2937 output.Add(instance);
2938 AbstractType& src_type = AbstractType::Handle();
2939 for (intptr_t i = 0; i < type_arguments.Length(); i++) {
2940 src_type = type_arguments.TypeAt(i);
2941 CollectStringifiedType(thread, zone, src_type, output);
2942 }
2943 } else {
2944 const intptr_t num_type_parameters = cls.NumTypeParameters(thread);
2945 instance ^= Smi::New(num_type_parameters);
2946 output.Add(instance);
2947 const AbstractType& dynamic_type =
2949 for (intptr_t i = 0; i < num_type_parameters; i++) {
2950 CollectStringifiedType(thread, zone, dynamic_type, output);
2951 }
2952 }
2953}
2954
2956 if (CheckDebuggerDisabled(thread, js)) {
2957 return;
2958 }
2959
2960 Isolate* isolate = thread->isolate();
2961 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
2962 intptr_t framePos = UIntParameter::Parse(js->LookupParam("frameIndex"));
2963 if (framePos >= stack->Length()) {
2964 PrintInvalidParamError(js, "frameIndex");
2965 return;
2966 }
2967
2968 Zone* zone = thread->zone();
2969 const GrowableObjectArray& param_names =
2971 const GrowableObjectArray& param_values =
2973 const GrowableObjectArray& type_params_names =
2975 const GrowableObjectArray& type_params_bounds =
2977 const GrowableObjectArray& type_params_defaults =
2979 String& klass_name = String::Handle(zone);
2980 String& method_name = String::Handle(zone);
2981 String& library_uri = String::Handle(zone);
2982 bool isStatic = false;
2983 String& script_uri = String::Handle(zone);
2984 TokenPosition token_pos = TokenPosition::kNoSource;
2985
2986 if (BuildScope(thread, js, param_names, param_values)) {
2987 return;
2988 }
2989
2990 if (js->HasParam("frameIndex")) {
2991 // building scope in the context of a given frame
2992 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
2993 intptr_t framePos = UIntParameter::Parse(js->LookupParam("frameIndex"));
2994 if (framePos >= stack->Length()) {
2995 PrintInvalidParamError(js, "frameIndex");
2996 return;
2997 }
2998
2999 ActivationFrame* frame = stack->FrameAt(framePos);
3000 script_uri = frame->SourceUrl();
3001 token_pos = frame->TokenPos();
3002 frame->BuildParameters(param_names, param_values, type_params_names,
3003 type_params_bounds, type_params_defaults);
3004
3005 if (frame->function().is_static()) {
3006 const Class& cls = Class::Handle(zone, frame->function().Owner());
3007 if (!cls.IsTopLevel()) {
3008 klass_name = cls.UserVisibleName();
3009 }
3010 library_uri = Library::Handle(zone, cls.library()).url();
3011 method_name = frame->function().UserVisibleName();
3012 isStatic = true;
3013 } else {
3014 Class& method_cls = Class::Handle(zone, frame->function().Owner());
3015 method_cls = method_cls.Mixin();
3016 library_uri = Library::Handle(zone, method_cls.library()).url();
3017 klass_name = method_cls.UserVisibleName();
3018 method_name = frame->function().UserVisibleName();
3019 isStatic = false;
3020 }
3021 } else {
3022 // building scope in the context of a given object
3023 if (!js->HasParam("targetId")) {
3024 js->PrintError(kInvalidParams,
3025 "Either targetId or frameIndex has to be provided.");
3026 return;
3027 }
3028 const char* target_id = js->LookupParam("targetId");
3029
3030 ObjectIdRing::LookupResult lookup_result;
3031 Object& obj = Object::Handle(
3032 zone, LookupHeapObject(thread, target_id, &lookup_result));
3033 if (obj.ptr() == Object::sentinel().ptr()) {
3034 PrintInvalidParamError(js, "targetId");
3035 return;
3036 }
3037 if (obj.IsLibrary()) {
3038 const Library& lib = Library::Cast(obj);
3039 library_uri = lib.url();
3040 isStatic = true;
3041 } else if (obj.IsClass() || ((obj.IsInstance() || obj.IsNull()) &&
3042 !ContainsNonInstance(obj))) {
3043 Class& cls = Class::Handle(zone);
3044 if (obj.IsClass()) {
3045 cls ^= obj.ptr();
3046 isStatic = true;
3047 } else {
3049 instance ^= obj.ptr();
3050 cls = instance.clazz();
3051 cls = cls.Mixin();
3052 isStatic = false;
3053 }
3054 if (!cls.IsTopLevel() &&
3055 (IsInternalOnlyClassId(cls.id()) || cls.id() == kTypeArgumentsCid)) {
3056 js->PrintError(
3058 "Expressions can be evaluated only with regular Dart instances");
3059 return;
3060 }
3061
3062 if (!cls.IsTopLevel()) {
3063 klass_name = cls.UserVisibleName();
3064 }
3065 library_uri = Library::Handle(zone, cls.library()).url();
3066 } else {
3067 js->PrintError(kInvalidParams,
3068 "%s: invalid 'targetId' parameter: "
3069 "Cannot evaluate against a VM-internal object",
3070 js->method());
3071 return;
3072 }
3073 }
3074
3075 JSONObject report(js);
3076 {
3077 JSONArray jsonParamNames(&report, "param_names");
3078
3079 String& param_name = String::Handle(zone);
3080 for (intptr_t i = 0; i < param_names.Length(); i++) {
3081 param_name ^= param_names.At(i);
3082 jsonParamNames.AddValue(param_name.ToCString());
3083 }
3084 }
3085 {
3086 const JSONArray jsonParamTypes(&report, "param_types");
3087 Object& obj = Object::Handle();
3089 const GrowableObjectArray& param_types =
3092 for (intptr_t i = 0; i < param_names.Length(); i++) {
3093 obj = param_values.At(i);
3094 if (obj.IsNull()) {
3095 param_types.Add(obj);
3096 } else if (obj.IsInstance()) {
3097 instance ^= param_values.At(i);
3098 type = instance.GetType(Heap::kNew);
3099 CollectStringifiedType(thread, zone, type, param_types);
3100 }
3101 }
3102 for (intptr_t i = 0; i < param_types.Length(); i++) {
3103 instance ^= param_types.At(i);
3104 jsonParamTypes.AddValue(instance.ToCString());
3105 }
3106 }
3107
3108 {
3109 JSONArray jsonTypeParamsNames(&report, "type_params_names");
3110 String& type_param_name = String::Handle(zone);
3111 for (intptr_t i = 0; i < type_params_names.Length(); i++) {
3112 type_param_name ^= type_params_names.At(i);
3113 jsonTypeParamsNames.AddValue(type_param_name.ToCString());
3114 }
3115 }
3116 {
3117 const JSONArray jsonParamTypes(&report, "type_params_bounds");
3118 const GrowableObjectArray& type_params_bounds_strings =
3121 for (intptr_t i = 0; i < type_params_bounds.Length(); i++) {
3122 type ^= type_params_bounds.At(i);
3123 CollectStringifiedType(thread, zone, type, type_params_bounds_strings);
3124 }
3126 for (intptr_t i = 0; i < type_params_bounds_strings.Length(); i++) {
3127 instance ^= type_params_bounds_strings.At(i);
3128 jsonParamTypes.AddValue(instance.ToCString());
3129 }
3130 }
3131 {
3132 const JSONArray jsonParamTypes(&report, "type_params_defaults");
3133 const GrowableObjectArray& type_params_defaults_strings =
3136 for (intptr_t i = 0; i < type_params_defaults.Length(); i++) {
3137 type ^= type_params_defaults.At(i);
3138 CollectStringifiedType(thread, zone, type, type_params_defaults_strings);
3139 }
3141 for (intptr_t i = 0; i < type_params_defaults_strings.Length(); i++) {
3142 instance ^= type_params_defaults_strings.At(i);
3143 jsonParamTypes.AddValue(instance.ToCString());
3144 }
3145 }
3146 report.AddProperty("libraryUri", library_uri.ToCString());
3147 if (!klass_name.IsNull()) {
3148 report.AddProperty("klass", klass_name.ToCString());
3149 }
3150 if (!method_name.IsNull()) {
3151 report.AddProperty("method", method_name.ToCString());
3152 }
3153 report.AddProperty("tokenPos", token_pos);
3154 if (!script_uri.IsNull()) {
3155 report.AddProperty("scriptUri", script_uri.ToCString());
3156 }
3157 report.AddProperty("isStatic", isStatic);
3158}
3159
3160#if !defined(DART_PRECOMPILED_RUNTIME)
3161// Parse comma-separated list of values, put them into values
3162static bool ParseCSVList(const char* csv_list,
3163 const GrowableObjectArray& values) {
3164 Zone* zone = Thread::Current()->zone();
3165 String& s = String::Handle(zone);
3166 const char* c = csv_list;
3167 if (*c++ != '[') return false;
3168 while (IsWhitespace(*c) && *c != '\0') {
3169 c++;
3170 }
3171 while (*c != '\0') {
3172 const char* value = c;
3173 while (*c != '\0' && *c != ']' && *c != ',' && !IsWhitespace(*c)) {
3174 c++;
3175 }
3176 if (c > value) {
3177 s = String::New(zone->MakeCopyOfStringN(value, c - value));
3178 values.Add(s);
3179 }
3180 switch (*c) {
3181 case '\0':
3182 return false;
3183 case ',':
3184 c++;
3185 break;
3186 case ']':
3187 return true;
3188 }
3189 while (IsWhitespace(*c) && *c != '\0') {
3190 c++;
3191 }
3192 }
3193 return false;
3194}
3195#endif
3196
3199 new StringParameter("expression", true),
3200 new StringParameter("definitions", false),
3201 new StringParameter("definitionTypes", false),
3202 new StringParameter("typeDefinitions", false),
3203 new StringParameter("typeBounds", false),
3204 new StringParameter("typeDefaults", false),
3205 new StringParameter("libraryUri", true),
3206 new StringParameter("klass", false),
3207 new BoolParameter("isStatic", false),
3208 new StringParameter("method", false),
3209 new Int64Parameter("tokenPos", false),
3210 // TODO(jensj): Uncomment this line when DDS has rolled into flutter
3211 // (https://dart-review.googlesource.com/c/sdk/+/329322).
3212 // new StringParameter("scriptUri", false),
3213 nullptr,
3214};
3215
3216static void CompileExpression(Thread* thread, JSONStream* js) {
3217#if defined(DART_PRECOMPILED_RUNTIME)
3218 js->PrintError(kFeatureDisabled, "Debugger is disabled in AOT mode.");
3219#else
3220 if (CheckDebuggerDisabled(thread, js)) {
3221 return;
3222 }
3223
3225 js->PrintError(
3227 "%s: No compilation service available; cannot evaluate from source.",
3228 js->method());
3229 return;
3230 }
3231
3232 const char* klass = js->LookupParam("klass");
3233 bool is_static =
3234 BoolParameter::Parse(js->LookupParam("isStatic"), (klass == nullptr));
3235 int64_t token_pos = Int64Parameter::Parse(js->LookupParam("tokenPos"));
3236
3239 if (!ParseCSVList(js->LookupParam("definitions"), params)) {
3240 PrintInvalidParamError(js, "definitions");
3241 return;
3242 }
3243 const GrowableObjectArray& param_types =
3245 if (!ParseCSVList(js->LookupParam("definitionTypes"), param_types)) {
3246 PrintInvalidParamError(js, "definitionTypes");
3247 return;
3248 }
3249
3250 const GrowableObjectArray& type_params =
3252 if (!ParseCSVList(js->LookupParam("typeDefinitions"), type_params)) {
3253 PrintInvalidParamError(js, "typedDefinitions");
3254 return;
3255 }
3256 const GrowableObjectArray& type_bounds =
3258 if (!ParseCSVList(js->LookupParam("typeBounds"), type_bounds)) {
3259 PrintInvalidParamError(js, "typeBounds");
3260 return;
3261 }
3262 const GrowableObjectArray& type_defaults =
3264 if (!ParseCSVList(js->LookupParam("typeDefaults"), type_defaults)) {
3265 PrintInvalidParamError(js, "typeDefaults");
3266 return;
3267 }
3268
3269 const uint8_t* kernel_buffer = Service::dart_library_kernel();
3270 const intptr_t kernel_buffer_len = Service::dart_library_kernel_length();
3271
3272 Dart_KernelCompilationResult compilation_result =
3274 kernel_buffer, kernel_buffer_len, js->LookupParam("expression"),
3279 Array::Handle(Array::MakeFixedLength(type_defaults)),
3280 js->LookupParam("libraryUri"), js->LookupParam("klass"),
3281 js->LookupParam("method"), TokenPosition::Deserialize(token_pos),
3282 js->LookupParam("scriptUri"), is_static);
3283
3284 if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
3285 js->PrintError(kExpressionCompilationError, "%s", compilation_result.error);
3286 free(compilation_result.error);
3287 return;
3288 }
3289
3290 const uint8_t* kernel_bytes = compilation_result.kernel;
3291 intptr_t kernel_length = compilation_result.kernel_size;
3292 ASSERT(kernel_bytes != nullptr);
3293
3294 JSONObject report(js);
3295 report.AddPropertyBase64("kernelBytes", kernel_bytes, kernel_length);
3296#endif
3297}
3298
3301 new UIntParameter("frameIndex", false),
3302 new IdParameter("targetId", false),
3303 new StringParameter("kernelBytes", true),
3304 nullptr,
3305};
3306
3307ExternalTypedDataPtr DecodeKernelBuffer(const char* kernel_buffer_base64) {
3308 intptr_t kernel_length;
3309 uint8_t* kernel_buffer = DecodeBase64(kernel_buffer_base64, &kernel_length);
3310 return ExternalTypedData::NewFinalizeWithFree(kernel_buffer, kernel_length);
3311}
3312
3314 if (CheckDebuggerDisabled(thread, js)) {
3315 return;
3316 }
3317
3318 Isolate* isolate = thread->isolate();
3319
3320 bool disable_breakpoints =
3321 BoolParameter::Parse(js->LookupParam("disableBreakpoints"), false);
3322 DisableBreakpointsScope db(isolate->debugger(), disable_breakpoints);
3323
3324 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
3325 intptr_t frame_pos = UIntParameter::Parse(js->LookupParam("frameIndex"));
3326 if (frame_pos >= stack->Length()) {
3327 PrintInvalidParamError(js, "frameIndex");
3328 return;
3329 }
3330 Zone* zone = thread->zone();
3331 const GrowableObjectArray& param_names =
3333 const GrowableObjectArray& param_values =
3335 if (BuildScope(thread, js, param_names, param_values)) {
3336 return;
3337 }
3338 const GrowableObjectArray& type_params_names =
3340 const GrowableObjectArray& type_params_bounds =
3342 const GrowableObjectArray& type_params_defaults =
3344
3345 const ExternalTypedData& kernel_data = ExternalTypedData::Handle(
3346 zone, DecodeKernelBuffer(js->LookupParam("kernelBytes")));
3347
3348 if (js->HasParam("frameIndex")) {
3349 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
3350 intptr_t frame_pos = UIntParameter::Parse(js->LookupParam("frameIndex"));
3351 if (frame_pos >= stack->Length()) {
3352 PrintInvalidParamError(js, "frameIndex");
3353 return;
3354 }
3355
3356 ActivationFrame* frame = stack->FrameAt(frame_pos);
3357 TypeArguments& type_arguments = TypeArguments::Handle(
3358 zone,
3359 frame->BuildParameters(param_names, param_values, type_params_names,
3360 type_params_bounds, type_params_defaults));
3361
3362 const Object& result = Object::Handle(
3363 zone,
3364 frame->EvaluateCompiledExpression(
3365 kernel_data,
3366 Array::Handle(zone, Array::MakeFixedLength(type_params_names)),
3367 Array::Handle(zone, Array::MakeFixedLength(param_values)),
3368 type_arguments));
3369 result.PrintJSON(js, true);
3370 } else {
3371 // evaluating expression in the context of a given object
3372 if (!js->HasParam("targetId")) {
3373 js->PrintError(kInvalidParams,
3374 "Either targetId or frameIndex has to be provided.");
3375 return;
3376 }
3377 const char* target_id = js->LookupParam("targetId");
3378 ObjectIdRing::LookupResult lookup_result;
3379 Object& obj = Object::Handle(
3380 zone, LookupHeapObject(thread, target_id, &lookup_result));
3381 if (obj.ptr() == Object::sentinel().ptr()) {
3382 if (lookup_result == ObjectIdRing::kCollected) {
3384 } else if (lookup_result == ObjectIdRing::kExpired) {
3386 } else {
3387 PrintInvalidParamError(js, "targetId");
3388 }
3389 return;
3390 }
3391 const auto& type_params_names_fixed =
3392 Array::Handle(zone, Array::MakeFixedLength(type_params_names));
3393 const auto& param_values_fixed =
3394 Array::Handle(zone, Array::MakeFixedLength(param_values));
3395
3396 TypeArguments& type_arguments = TypeArguments::Handle(zone);
3397 if (obj.IsLibrary()) {
3398 const auto& lib = Library::Cast(obj);
3399 const auto& result = Object::Handle(
3400 zone,
3401 lib.EvaluateCompiledExpression(kernel_data, type_params_names_fixed,
3402 param_values_fixed, type_arguments));
3403 result.PrintJSON(js, true);
3404 return;
3405 }
3406 if (obj.IsClass()) {
3407 const auto& cls = Class::Cast(obj);
3408 const auto& result = Object::Handle(
3409 zone,
3410 cls.EvaluateCompiledExpression(kernel_data, type_params_names_fixed,
3411 param_values_fixed, type_arguments));
3412 result.PrintJSON(js, true);
3413 return;
3414 }
3415 if ((obj.IsInstance() || obj.IsNull()) && !ContainsNonInstance(obj)) {
3416 const auto& instance =
3418 const auto& receiver_cls = Class::Handle(zone, instance.clazz());
3419 const auto& result = Object::Handle(
3420 zone, instance.EvaluateCompiledExpression(
3421 receiver_cls, kernel_data, type_params_names_fixed,
3422 param_values_fixed, type_arguments));
3423 result.PrintJSON(js, true);
3424 return;
3425 }
3426 js->PrintError(kInvalidParams,
3427 "%s: invalid 'targetId' parameter: "
3428 "Cannot evaluate against a VM-internal object",
3429 js->method());
3430 }
3431}
3432
3435 new UIntParameter("frameIndex", true),
3436 new MethodParameter("expression", true),
3437 nullptr,
3438};
3439
3440static void EvaluateInFrame(Thread* thread, JSONStream* js) {
3441 // If a compilation service is available, this RPC invocation will have been
3442 // intercepted by RunningIsolates.routeRequest.
3443 js->PrintError(
3445 "%s: No compilation service available; cannot evaluate from source.",
3446 js->method());
3447}
3448
3449static void MarkClasses(const Class& root,
3450 bool include_subclasses,
3451 bool include_implementors) {
3452 Thread* thread = Thread::Current();
3453 HANDLESCOPE(thread);
3454 ClassTable* table = thread->isolate()->group()->class_table();
3456 table->SetCollectInstancesFor(root.id(), true);
3457 worklist.Add(&root);
3460 while (!worklist.is_empty()) {
3461 const Class& cls = *worklist.RemoveLast();
3462 // All subclasses are implementors, but they are not included in
3463 // `direct_implementors`.
3464 if (include_subclasses || include_implementors) {
3465 subclasses = cls.direct_subclasses_unsafe();
3466 if (!subclasses.IsNull()) {
3467 for (intptr_t j = 0; j < subclasses.Length(); j++) {
3468 Class& subclass = Class::Handle();
3469 subclass ^= subclasses.At(j);
3470 if (!table->CollectInstancesFor(subclass.id())) {
3471 table->SetCollectInstancesFor(subclass.id(), true);
3472 worklist.Add(&subclass);
3473 }
3474 }
3475 }
3476 }
3477 if (include_implementors) {
3478 implementors = cls.direct_implementors_unsafe();
3479 if (!implementors.IsNull()) {
3480 for (intptr_t j = 0; j < implementors.Length(); j++) {
3481 Class& implementor = Class::Handle();
3482 implementor ^= implementors.At(j);
3483 if (!table->CollectInstancesFor(implementor.id())) {
3484 table->SetCollectInstancesFor(implementor.id(), true);
3485 worklist.Add(&implementor);
3486 }
3487 }
3488 }
3489 }
3490 }
3491}
3492
3493static void UnmarkClasses() {
3495 for (intptr_t i = 1; i < table->NumCids(); i++) {
3496 table->SetCollectInstancesFor(i, false);
3497 }
3498}
3499
3501 public:
3503 intptr_t limit)
3504 : table_(IsolateGroup::Current()->class_table()),
3505 storage_(storage),
3506 limit_(limit),
3507 count_(0) {}
3508
3509 virtual Direction VisitObject(ObjectGraph::StackIterator* it) {
3510 ObjectPtr raw_obj = it->Get();
3511 if (raw_obj->IsPseudoObject()) {
3512 return kProceed;
3513 }
3514 if (table_->CollectInstancesFor(raw_obj->GetClassId())) {
3515 if (count_ < limit_) {
3516 storage_->Add(Object::Handle(raw_obj));
3517 }
3518 ++count_;
3519 }
3520 return kProceed;
3521 }
3522
3523 intptr_t count() const { return count_; }
3524
3525 private:
3526 ClassTable* const table_;
3528 const intptr_t limit_;
3529 intptr_t count_;
3530};
3531
3532static const MethodParameter* const get_instances_params[] = {
3534 new IdParameter("objectId", /*required=*/true),
3535 new UIntParameter("limit", /*required=*/true),
3536 new BoolParameter("includeSubclasses", /*required=*/false),
3537 new BoolParameter("includeImplementers", /*required=*/false),
3538 nullptr,
3539};
3540
3541static void GetInstances(Thread* thread, JSONStream* js) {
3542 const char* object_id = js->LookupParam("objectId");
3543 const intptr_t limit = UIntParameter::Parse(js->LookupParam("limit"));
3544 const bool include_subclasses =
3545 BoolParameter::Parse(js->LookupParam("includeSubclasses"), false);
3546 const bool include_implementers =
3547 BoolParameter::Parse(js->LookupParam("includeImplementers"), false);
3548
3549 const Object& obj =
3550 Object::Handle(LookupHeapObject(thread, object_id, nullptr));
3551 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsClass()) {
3552 PrintInvalidParamError(js, "objectId");
3553 return;
3554 }
3555 const Class& cls = Class::Cast(obj);
3556
3557 // Ensure the array and handles created below are promptly destroyed.
3558 StackZone zone(thread);
3559
3560 ZoneGrowableHandlePtrArray<Object> storage(thread->zone(), limit);
3561 GetInstancesVisitor visitor(&storage, limit);
3562 {
3563 ObjectGraph graph(thread);
3564 HeapIterationScope iteration_scope(Thread::Current(), true);
3565 MarkClasses(cls, include_subclasses, include_implementers);
3566 graph.IterateObjects(&visitor);
3567 UnmarkClasses();
3568 }
3569 intptr_t count = visitor.count();
3570 JSONObject jsobj(js);
3571 jsobj.AddProperty("type", "InstanceSet");
3572 jsobj.AddProperty("totalCount", count);
3573 {
3574 JSONArray samples(&jsobj, "instances");
3575 for (int i = 0; (i < limit) && (i < count); i++) {
3576 samples.AddValue(storage.At(i));
3577 }
3578 }
3579}
3580
3583 new IdParameter("objectId", /*required=*/true),
3584 new BoolParameter("includeSubclasses", /*required=*/false),
3585 new BoolParameter("includeImplementers", /*required=*/false),
3586 nullptr,
3587};
3588
3589static void GetInstancesAsList(Thread* thread, JSONStream* js) {
3590 const char* object_id = js->LookupParam("objectId");
3591 bool include_subclasses =
3592 BoolParameter::Parse(js->LookupParam("includeSubclasses"), false);
3593 bool include_implementers =
3594 BoolParameter::Parse(js->LookupParam("includeImplementers"), false);
3595
3596 const Object& obj =
3597 Object::Handle(LookupHeapObject(thread, object_id, nullptr));
3598 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsClass()) {
3599 PrintInvalidParamError(js, "objectId");
3600 return;
3601 }
3602 const Class& cls = Class::Cast(obj);
3603
3604 Array& instances = Array::Handle();
3605 {
3606 // Ensure the |ZoneGrowableHandlePtrArray| and handles created below are
3607 // promptly destroyed.
3608 StackZone zone(thread);
3609
3610 ZoneGrowableHandlePtrArray<Object> storage(thread->zone(), 1024);
3611 GetInstancesVisitor visitor(&storage, kSmiMax);
3612 {
3613 ObjectGraph graph(thread);
3614 HeapIterationScope iteration_scope(Thread::Current(), true);
3615 MarkClasses(cls, include_subclasses, include_implementers);
3616 graph.IterateObjects(&visitor);
3617 UnmarkClasses();
3618 }
3619 intptr_t count = visitor.count();
3620 instances = Array::New(count);
3621 for (intptr_t i = 0; i < count; i++) {
3622 instances.SetAt(i, storage.At(i));
3623 }
3624 }
3625 instances.PrintJSON(js, /*ref=*/true);
3626}
3627
3628template <typename Adder>
3629static intptr_t ParseJSONCollection(Thread* thread,
3630 const char* str,
3631 const Adder& add) {
3632 ASSERT(str != nullptr);
3633 ASSERT(thread != nullptr);
3634 intptr_t n = strlen(str);
3635 if (n < 2) {
3636 return -1;
3637 } else if (n == 2) {
3638 return 0;
3639 }
3640 // The JSON string array looks like [abc, def]. There are no quotes around the
3641 // strings, but there is a space after the comma. start points to the first
3642 // character of the element. end points to the separator after the element
3643 // (']' or ',').
3644 intptr_t start = 1;
3645 while (start < n) {
3646 intptr_t end = start;
3647 while (end < n) {
3648 const char c = str[end];
3649 if (c == ',' || c == ']') {
3650 break;
3651 }
3652 ++end;
3653 }
3654 add(&str[start], end - start);
3655 start = end + 2;
3656 }
3657 return 0;
3658}
3659
3660intptr_t ParseJSONArray(Thread* thread,
3661 const char* str,
3662 const GrowableObjectArray& elements) {
3663 Zone* zone = thread->zone();
3664 return ParseJSONCollection(
3665 thread, str, [zone, &elements](const char* start, intptr_t length) {
3666 String& element = String::Handle(
3667 zone,
3668 String::FromUTF8(reinterpret_cast<const uint8_t*>(start), length));
3669 elements.Add(element);
3670 });
3671}
3672
3673#if !defined(DART_PRECOMPILED_RUNTIME)
3674static intptr_t ParseJSONSet(Thread* thread,
3675 const char* str,
3676 ZoneCStringSet* elements) {
3677 Zone* zone = thread->zone();
3678 return ParseJSONCollection(
3679 thread, str, [zone, elements](const char* start, intptr_t length) {
3680 elements->Insert(zone->MakeCopyOfStringN(start, length));
3681 });
3682}
3683#endif
3684
3685static const MethodParameter* const get_ports_params[] = {
3687 nullptr,
3688};
3689
3690static void GetPorts(Thread* thread, JSONStream* js) {
3691 // Ensure the array and handles created below are promptly destroyed.
3692 StackZone zone(thread);
3695 JSONObject jsobj(js);
3696 jsobj.AddProperty("type", "PortList");
3697 {
3699 JSONArray arr(&jsobj, "ports");
3700 for (int i = 0; i < ports.Length(); ++i) {
3701 port ^= ports.At(i);
3702 ASSERT(port.is_open());
3703 if (port.keep_isolate_alive()) {
3704 arr.AddValue(port);
3705 }
3706 }
3707 }
3708}
3709
3710#if !defined(DART_PRECOMPILED_RUNTIME)
3711static const char* const report_enum_names[] = {
3715};
3716#endif
3717
3719#if !defined(DART_PRECOMPILED_RUNTIME)
3721 new EnumListParameter("reports", true, report_enum_names),
3722 new IdParameter("scriptId", false),
3723 new UIntParameter("tokenPos", false),
3724 new UIntParameter("endTokenPos", false),
3725 new BoolParameter("forceCompile", false),
3726#endif
3727 nullptr,
3728};
3729
3730static void GetSourceReport(Thread* thread, JSONStream* js) {
3731#if defined(DART_PRECOMPILED_RUNTIME)
3732 js->PrintError(kFeatureDisabled, "disabled in AOT mode and PRODUCT.");
3733#else
3734 char* reports_str = Utils::StrDup(js->LookupParam("reports"));
3735 const EnumListParameter* reports_parameter =
3736 static_cast<const EnumListParameter*>(get_source_report_params[1]);
3737 const char** reports = reports_parameter->Parse(reports_str);
3738 const char** riter = reports;
3739 intptr_t report_set = 0;
3740 while (*riter != nullptr) {
3741 if (strcmp(*riter, SourceReport::kCallSitesStr) == 0) {
3742 report_set |= SourceReport::kCallSites;
3743 } else if (strcmp(*riter, SourceReport::kCoverageStr) == 0) {
3744 report_set |= SourceReport::kCoverage;
3745 } else if (strcmp(*riter, SourceReport::kPossibleBreakpointsStr) == 0) {
3747 } else if (strcmp(*riter, SourceReport::kProfileStr) == 0) {
3748 report_set |= SourceReport::kProfile;
3749 } else if (strcmp(*riter, SourceReport::kBranchCoverageStr) == 0) {
3750 report_set |= SourceReport::kBranchCoverage;
3751 }
3752 riter++;
3753 }
3754 if (reports != nullptr) {
3755 delete[] reports;
3756 }
3757 free(reports_str);
3758
3760 if (BoolParameter::Parse(js->LookupParam("forceCompile"), false)) {
3761 compile_mode = SourceReport::kForceCompile;
3762 }
3763
3764 bool report_lines =
3765 BoolParameter::Parse(js->LookupParam("reportLines"), false);
3766
3768 intptr_t start_pos = UIntParameter::Parse(js->LookupParam("tokenPos"));
3769 intptr_t end_pos = UIntParameter::Parse(js->LookupParam("endTokenPos"));
3770
3771 if (js->HasParam("scriptId")) {
3772 // Get the target script.
3773 const char* script_id_param = js->LookupParam("scriptId");
3774 const Object& obj =
3775 Object::Handle(LookupHeapObject(thread, script_id_param, nullptr));
3776 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsScript()) {
3777 PrintInvalidParamError(js, "scriptId");
3778 return;
3779 }
3780 script ^= obj.ptr();
3781 } else {
3782 if (js->HasParam("tokenPos")) {
3783 js->PrintError(
3785 "%s: the 'tokenPos' parameter requires the 'scriptId' parameter",
3786 js->method());
3787 return;
3788 }
3789 if (js->HasParam("endTokenPos")) {
3790 js->PrintError(
3792 "%s: the 'endTokenPos' parameter requires the 'scriptId' parameter",
3793 js->method());
3794 return;
3795 }
3796 }
3797
3798 const char* library_filters_param = js->LookupParam("libraryFilters");
3800 if (library_filters_param != nullptr) {
3801 library_filters = GrowableObjectArray::New();
3802 intptr_t library_filters_length =
3803 ParseJSONArray(thread, library_filters_param, library_filters);
3804 if (library_filters_length < 0) {
3805 PrintInvalidParamError(js, "library_filters");
3806 return;
3807 }
3808 }
3809
3810 const char* libraries_already_compiled_param =
3811 js->LookupParam("librariesAlreadyCompiled");
3812 Zone* zone = thread->zone();
3813 ZoneCStringSet* libraries_already_compiled = nullptr;
3814 if (libraries_already_compiled_param != nullptr) {
3815 libraries_already_compiled = new (zone) ZoneCStringSet(zone);
3816 intptr_t libraries_already_compiled_length = ParseJSONSet(
3817 thread, libraries_already_compiled_param, libraries_already_compiled);
3818 if (libraries_already_compiled_length < 0) {
3819 PrintInvalidParamError(js, "libraries_already_compiled");
3820 return;
3821 }
3822 }
3823
3824 SourceReport report(report_set, library_filters, libraries_already_compiled,
3825 compile_mode, report_lines);
3826 report.PrintJSON(js, script, TokenPosition::Deserialize(start_pos),
3828#endif // !DART_PRECOMPILED_RUNTIME
3829}
3830
3833 new BoolParameter("force", false),
3834 new BoolParameter("pause", false),
3835 new StringParameter("rootLibUri", false),
3836 new StringParameter("packagesUri", false),
3837 nullptr,
3838};
3839
3840static void ReloadSources(Thread* thread, JSONStream* js) {
3841#if defined(DART_PRECOMPILED_RUNTIME)
3842 js->PrintError(kFeatureDisabled, "Compiler is disabled in AOT mode.");
3843#else
3844 IsolateGroup* isolate_group = thread->isolate_group();
3845 if (isolate_group->library_tag_handler() == nullptr) {
3846 js->PrintError(kFeatureDisabled,
3847 "A library tag handler must be installed.");
3848 return;
3849 }
3850 // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
3851 // call to accept an isolate group instead of an isolate.
3852 Isolate* isolate = thread->isolate();
3853 if ((isolate->sticky_error() != Error::null()) ||
3855 js->PrintError(kIsolateReloadBarred,
3856 "This isolate cannot reload sources anymore because there "
3857 "was an unhandled exception error. Restart the isolate.");
3858 return;
3859 }
3860 if (isolate_group->IsReloading()) {
3861 js->PrintError(kIsolateIsReloading, "This isolate is being reloaded.");
3862 return;
3863 }
3864 if (!isolate_group->CanReload()) {
3865 js->PrintError(kFeatureDisabled,
3866 "This isolate cannot reload sources right now.");
3867 return;
3868 }
3869 const bool force_reload =
3870 BoolParameter::Parse(js->LookupParam("force"), false);
3871
3872 isolate_group->ReloadSources(js, force_reload, js->LookupParam("rootLibUri"),
3873 js->LookupParam("packagesUri"));
3874
3875 Service::CheckForPause(isolate, js);
3876
3877#endif
3878}
3879
3881 // Should we pause?
3883 BoolParameter::Parse(stream->LookupParam("pause"), false));
3884}
3885
3886ErrorPtr Service::MaybePause(Isolate* isolate, const Error& error) {
3887 // Don't pause twice.
3888 if (!isolate->IsPaused()) {
3889 if (isolate->should_pause_post_service_request()) {
3891 if (!error.IsNull()) {
3892 // Before pausing, restore the sticky error. The debugger will return it
3893 // from PausePostRequest.
3895 }
3896 return isolate->PausePostRequest();
3897 }
3898 }
3899 return error.ptr();
3900}
3901
3902static void AddBreakpointCommon(Thread* thread,
3903 JSONStream* js,
3904 const String& script_uri) {
3905 if (CheckDebuggerDisabled(thread, js)) {
3906 return;
3907 }
3908
3909 const char* line_param = js->LookupParam("line");
3910 intptr_t line = UIntParameter::Parse(line_param);
3911 const char* col_param = js->LookupParam("column");
3912 intptr_t col = -1;
3913 if (col_param != nullptr) {
3914 col = UIntParameter::Parse(col_param);
3915 if (col == 0) {
3916 // Column number is 1-based.
3917 PrintInvalidParamError(js, "column");
3918 return;
3919 }
3920 }
3921 ASSERT(!script_uri.IsNull());
3922 Breakpoint* bpt = nullptr;
3923 bpt = thread->isolate()->debugger()->SetBreakpointAtLineCol(script_uri, line,
3924 col);
3925 if (bpt == nullptr) {
3926 js->PrintError(kCannotAddBreakpoint,
3927 "%s: Cannot add breakpoint at line '%s'", js->method(),
3928 line_param);
3929 return;
3930 }
3931 bpt->PrintJSON(js);
3932}
3933
3936 new IdParameter("scriptId", true),
3937 new UIntParameter("line", true),
3938 new UIntParameter("column", false),
3939 nullptr,
3940};
3941
3942static void AddBreakpoint(Thread* thread, JSONStream* js) {
3943 if (CheckDebuggerDisabled(thread, js)) {
3944 return;
3945 }
3946
3947 const char* script_id_param = js->LookupParam("scriptId");
3948 Object& obj =
3949 Object::Handle(LookupHeapObject(thread, script_id_param, nullptr));
3950 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsScript()) {
3951 PrintInvalidParamError(js, "scriptId");
3952 return;
3953 }
3954 const Script& script = Script::Cast(obj);
3955 const String& script_uri = String::Handle(script.url());
3956 ASSERT(!script_uri.IsNull());
3957 AddBreakpointCommon(thread, js, script_uri);
3958}
3959
3962 new IdParameter("scriptUri", true),
3963 new UIntParameter("line", true),
3964 new UIntParameter("column", false),
3965 nullptr,
3966};
3967
3969 if (CheckDebuggerDisabled(thread, js)) {
3970 return;
3971 }
3972
3973 const char* script_uri_param = js->LookupParam("scriptUri");
3974 const String& script_uri = String::Handle(String::New(script_uri_param));
3975 AddBreakpointCommon(thread, js, script_uri);
3976}
3977
3980 new IdParameter("functionId", true),
3981 nullptr,
3982};
3983
3985 if (CheckDebuggerDisabled(thread, js)) {
3986 return;
3987 }
3988
3989 const char* function_id = js->LookupParam("functionId");
3990 Object& obj = Object::Handle(LookupHeapObject(thread, function_id, nullptr));
3991 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsFunction()) {
3992 PrintInvalidParamError(js, "functionId");
3993 return;
3994 }
3995 const Function& function = Function::Cast(obj);
3996 Breakpoint* bpt =
3997 thread->isolate()->debugger()->SetBreakpointAtEntry(function, false);
3998 if (bpt == nullptr) {
3999 js->PrintError(kCannotAddBreakpoint,
4000 "%s: Cannot add breakpoint at function '%s'", js->method(),
4001 function.ToCString());
4002 return;
4003 }
4004 bpt->PrintJSON(js);
4005}
4006
4009 new IdParameter("objectId", true),
4010 nullptr,
4011};
4012
4014 if (CheckDebuggerDisabled(thread, js)) {
4015 return;
4016 }
4017
4018 const char* object_id = js->LookupParam("objectId");
4019 Object& obj = Object::Handle(LookupHeapObject(thread, object_id, nullptr));
4020 if (obj.ptr() == Object::sentinel().ptr() || !obj.IsInstance()) {
4021 PrintInvalidParamError(js, "objectId");
4022 return;
4023 }
4024 const Instance& closure = Instance::Cast(obj);
4026 closure, /*single_shot=*/false);
4027 if (bpt == nullptr) {
4028 js->PrintError(kCannotAddBreakpoint,
4029 "%s: Cannot add breakpoint at activation", js->method());
4030 return;
4031 }
4032 bpt->PrintJSON(js);
4033}
4034
4037 nullptr,
4038};
4039
4040static void RemoveBreakpoint(Thread* thread, JSONStream* js) {
4041 if (CheckDebuggerDisabled(thread, js)) {
4042 return;
4043 }
4044
4045 if (!js->HasParam("breakpointId")) {
4046 PrintMissingParamError(js, "breakpointId");
4047 return;
4048 }
4049 const char* bpt_id = js->LookupParam("breakpointId");
4050 ObjectIdRing::LookupResult lookup_result;
4051 Isolate* isolate = thread->isolate();
4052 Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id, &lookup_result);
4053 // TODO(turnidge): Should we return a different error for bpts which
4054 // have been already removed?
4055 if (bpt == nullptr) {
4056 PrintInvalidParamError(js, "breakpointId");
4057 return;
4058 }
4059 isolate->debugger()->RemoveBreakpoint(bpt->id());
4061}
4062
4064 JSONObject obj(js);
4065 obj.AddProperty("type", "MetricList");
4066 {
4067 JSONArray metrics(&obj, "metrics");
4068
4069 auto isolate = thread->isolate();
4070#define ADD_METRIC(type, variable, name, unit) \
4071 metrics.AddValue(isolate->Get##variable##Metric());
4073#undef ADD_METRIC
4074
4075 auto isolate_group = thread->isolate_group();
4076#define ADD_METRIC(type, variable, name, unit) \
4077 metrics.AddValue(isolate_group->Get##variable##Metric());
4079#undef ADD_METRIC
4080 }
4081}
4082
4083static void HandleNativeMetric(Thread* thread, JSONStream* js, const char* id) {
4084 auto isolate = thread->isolate();
4085#define ADD_METRIC(type, variable, name, unit) \
4086 if (strcmp(id, name) == 0) { \
4087 isolate->Get##variable##Metric()->PrintJSON(js); \
4088 return; \
4089 }
4091#undef ADD_METRIC
4092
4093 auto isolate_group = thread->isolate_group();
4094#define ADD_METRIC(type, variable, name, unit) \
4095 if (strcmp(id, name) == 0) { \
4096 isolate_group->Get##variable##Metric()->PrintJSON(js); \
4097 return; \
4098 }
4100#undef ADD_METRIC
4101
4102 PrintInvalidParamError(js, "metricId");
4103}
4104
4107 nullptr,
4108};
4109
4111 if (js->HasParam("type")) {
4112 if (!js->ParamIs("type", "Native")) {
4113 PrintInvalidParamError(js, "type");
4114 return;
4115 }
4116 } else {
4117 PrintMissingParamError(js, "type");
4118 return;
4119 }
4120 HandleNativeMetricsList(thread, js);
4121}
4122
4125 nullptr,
4126};
4127
4128static void GetIsolateMetric(Thread* thread, JSONStream* js) {
4129 const char* metric_id = js->LookupParam("metricId");
4130 if (metric_id == nullptr) {
4131 PrintMissingParamError(js, "metricId");
4132 return;
4133 }
4134 // Verify id begins with "metrics/native/".
4135 static const char* const kNativeMetricIdPrefix = "metrics/native/";
4136 static intptr_t kNativeMetricIdPrefixLen = strlen(kNativeMetricIdPrefix);
4137 if (strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) !=
4138 0) {
4139 PrintInvalidParamError(js, "metricId");
4140 return;
4141 }
4142 const char* id = metric_id + kNativeMetricIdPrefixLen;
4143 HandleNativeMetric(thread, js, id);
4144}
4145
4146enum TimelineOrSamplesResponseFormat : bool { JSON = false, Perfetto = true };
4147
4149 Thread* thread,
4150 JSONStream* js) {
4151 const int64_t time_origin_micros =
4152 Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
4153 const int64_t time_extent_micros =
4154 Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
4155 const bool include_code_samples =
4156 BoolParameter::Parse(js->LookupParam("_code"), false);
4157 if (CheckProfilerDisabled(thread, js)) {
4158 return;
4159 }
4160
4162 ProfilerService::PrintJSON(js, time_origin_micros, time_extent_micros,
4163 include_code_samples);
4165#if defined(SUPPORT_PERFETTO)
4166 // This branch will never be reached when SUPPORT_PERFETTO is not defined,
4167 // because |GetPerfettoCpuSamples| is not defined when SUPPORT_PERFETTO is
4168 // not defined.
4169 ProfilerService::PrintPerfetto(js, time_origin_micros, time_extent_micros);
4170#else
4171 UNREACHABLE();
4172#endif // defined(SUPPORT_PERFETTO)
4173 }
4174}
4175
4177 Thread* thread,
4178 JSONStream* js) {
4179 Isolate* isolate = thread->isolate();
4180 ASSERT(isolate != nullptr);
4181 StackZone zone(thread);
4182 TimelineEventRecorder* timeline_recorder = Timeline::recorder();
4183 ASSERT(timeline_recorder != nullptr);
4184 const char* name = timeline_recorder->name();
4185 if (strcmp(name, CALLBACK_RECORDER_NAME) == 0) {
4186 js->PrintError(kInvalidTimelineRequest,
4187 "A recorder of type \"%s\" is currently in use. As a "
4188 "result, timeline events are handled by the embedder rather "
4189 "than the VM.",
4190 timeline_recorder->name());
4191 return;
4192 } else if (strcmp(name, FUCHSIA_RECORDER_NAME) == 0 ||
4193 strcmp(name, SYSTRACE_RECORDER_NAME) == 0 ||
4194 strcmp(name, MACOS_RECORDER_NAME) == 0) {
4195 js->PrintError(
4197 "A recorder of type \"%s\" is currently in use. As a result, timeline "
4198 "events are handled by the OS rather than the VM. See the VM service "
4199 "documentation for more details on where timeline events can be found "
4200 "for this recorder type.",
4201 timeline_recorder->name());
4202 return;
4203 } else if (strcmp(name, FILE_RECORDER_NAME) == 0 ||
4204 strcmp(name, PERFETTO_FILE_RECORDER_NAME) == 0) {
4205 js->PrintError(kInvalidTimelineRequest,
4206 "A recorder of type \"%s\" is currently in use. As a "
4207 "result, timeline events are written directly to a file and "
4208 "thus cannot be retrieved through the VM Service.",
4209 timeline_recorder->name());
4210 return;
4211 }
4212 int64_t time_origin_micros =
4213 Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
4214 int64_t time_extent_micros =
4215 Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
4216 TimelineEventFilter filter(time_origin_micros, time_extent_micros);
4218 timeline_recorder->PrintJSON(js, &filter);
4220#if defined(SUPPORT_PERFETTO)
4221 // This branch will never be reached when SUPPORT_PERFETTO is not defined,
4222 // because |GetPerfettoVMTimeline| is not defined when SUPPORT_PERFETTO is
4223 // not defined.
4224 timeline_recorder->PrintPerfettoTimeline(js, filter);
4225#else
4226 UNREACHABLE();
4227#endif // defined(SUPPORT_PERFETTO)
4228 }
4229}
4230
4231#if defined(SUPPORT_PERFETTO)
4232static void GetPerfettoCpuSamples(Thread* thread, JSONStream* js) {
4234}
4235
4236static void GetPerfettoVMTimeline(Thread* thread, JSONStream* js) {
4238}
4239#endif // defined(SUPPORT_PERFETTO)
4240
4241static void SetVMTimelineFlags(Thread* thread, JSONStream* js) {
4242#if !defined(SUPPORT_TIMELINE)
4244#else
4245 Isolate* isolate = thread->isolate();
4246 ASSERT(isolate != nullptr);
4247 StackZone zone(thread);
4248
4249 char* recorded_streams = Utils::StrDup(js->LookupParam("recordedStreams"));
4250 Service::EnableTimelineStreams(recorded_streams);
4251 free(recorded_streams);
4252
4254#endif
4255}
4256
4259 nullptr,
4260};
4261
4262static void GetVMTimelineFlags(Thread* thread, JSONStream* js) {
4263#if !defined(SUPPORT_TIMELINE)
4264 JSONObject obj(js);
4265 obj.AddProperty("type", "TimelineFlags");
4266#else
4267 Isolate* isolate = thread->isolate();
4268 ASSERT(isolate != nullptr);
4269 StackZone zone(thread);
4270 Timeline::PrintFlagsToJSON(js);
4271#endif
4272}
4273
4276 nullptr,
4277};
4278
4279static void GetVMTimelineMicros(Thread* thread, JSONStream* js) {
4280 JSONObject obj(js);
4281 obj.AddProperty("type", "Timestamp");
4283}
4284
4287 nullptr,
4288};
4289
4290static void ClearVMTimeline(Thread* thread, JSONStream* js) {
4291 Isolate* isolate = thread->isolate();
4292 ASSERT(isolate != nullptr);
4293 StackZone zone(thread);
4294
4295 Timeline::Clear();
4296
4298}
4299
4302 new Int64Parameter("timeOriginMicros", /*required=*/false),
4303 new Int64Parameter("timeExtentMicros", /*required=*/false),
4304 nullptr,
4305};
4306
4307static void GetVMTimeline(Thread* thread, JSONStream* js) {
4309}
4310
4311static const char* const step_enum_names[] = {
4312 "None", "Into", "Over", "Out", "Rewind", "OverAsyncSuspension", nullptr,
4313};
4314
4319 Debugger::kContinue, // Default value
4320};
4321
4322static const MethodParameter* const resume_params[] = {
4324 new EnumParameter("step", false, step_enum_names),
4325 new UIntParameter("frameIndex", false),
4326 nullptr,
4327};
4328
4329static void Resume(Thread* thread, JSONStream* js) {
4330 const char* step_param = js->LookupParam("step");
4332 if (step_param != nullptr) {
4334 }
4335 intptr_t frame_index = 1;
4336 const char* frame_index_param = js->LookupParam("frameIndex");
4337 if (frame_index_param != nullptr) {
4338 if (step != Debugger::kStepRewind) {
4339 // Only rewind supports the frameIndex parameter.
4340 js->PrintError(
4342 "%s: the 'frameIndex' parameter can only be used when rewinding",
4343 js->method());
4344 return;
4345 }
4346 frame_index = UIntParameter::Parse(js->LookupParam("frameIndex"));
4347 }
4348 Isolate* isolate = thread->isolate();
4349 if (isolate->message_handler()->is_paused_on_start()) {
4350 // If the user is issuing a 'Over' or an 'Out' step, that is the
4351 // same as a regular resume request.
4352 if (step == Debugger::kStepInto) {
4353 isolate->debugger()->EnterSingleStepMode();
4354 }
4355 isolate->message_handler()->set_should_pause_on_start(false);
4356 isolate->SetResumeRequest();
4357 if (Service::debug_stream.enabled()) {
4360 }
4362 return;
4363 }
4364 if (isolate->message_handler()->should_pause_on_start()) {
4365 isolate->message_handler()->set_should_pause_on_start(false);
4366 isolate->SetResumeRequest();
4367 if (Service::debug_stream.enabled()) {
4370 }
4372 return;
4373 }
4374 if (isolate->message_handler()->is_paused_on_exit()) {
4375 isolate->message_handler()->set_should_pause_on_exit(false);
4376 isolate->SetResumeRequest();
4377 // We don't send a resume event because we will be exiting.
4379 return;
4380 }
4381 if (isolate->debugger()->PauseEvent() == nullptr) {
4382 js->PrintError(kIsolateMustBePaused, nullptr);
4383 return;
4384 }
4385
4386 const char* error = nullptr;
4387 if (!isolate->debugger()->SetResumeAction(step, frame_index, &error)) {
4388 js->PrintError(kCannotResume, "%s", error);
4389 return;
4390 }
4391 isolate->SetResumeRequest();
4393}
4394
4395static const MethodParameter* const kill_params[] = {
4397 nullptr,
4398};
4399
4400static void Kill(Thread* thread, JSONStream* js) {
4401 const String& msg =
4402 String::Handle(String::New("isolate terminated by Kill service request"));
4404 error.set_is_user_initiated(true);
4407}
4408
4409static const MethodParameter* const pause_params[] = {
4411 nullptr,
4412};
4413
4414static void Pause(Thread* thread, JSONStream* js) {
4415 // TODO(turnidge): This interrupt message could have been sent from
4416 // the service isolate directly, but would require some special case
4417 // code. That would prevent this isolate getting double-interrupted
4418 // with OOB messages.
4419 Isolate* isolate = thread->isolate();
4421 isolate->pause_capability());
4423}
4424
4426 nullptr,
4427};
4428
4429static void EnableProfiler(Thread* thread, JSONStream* js) {
4430 if (!FLAG_profiler) {
4431 FLAG_profiler = true;
4433 }
4435}
4436
4439 nullptr,
4440};
4441
4442static void GetTagProfile(Thread* thread, JSONStream* js) {
4443 JSONObject miniProfile(js);
4444 miniProfile.AddProperty("type", "TagProfile");
4445 thread->isolate()->vm_tag_counters()->PrintToJSONObject(&miniProfile);
4446}
4447
4450 new Int64Parameter("timeOriginMicros", /*required=*/false),
4451 new Int64Parameter("timeExtentMicros", /*required=*/false),
4452 nullptr,
4453};
4454
4455static void GetCpuSamples(Thread* thread, JSONStream* js) {
4457}
4458
4461 new IdParameter("classId", false),
4462 new Int64Parameter("timeOriginMicros", false),
4463 new Int64Parameter("timeExtentMicros", false),
4464 nullptr,
4465};
4466
4467static void GetAllocationTraces(Thread* thread, JSONStream* js) {
4468 int64_t time_origin_micros =
4469 Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
4470 int64_t time_extent_micros =
4471 Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
4472 Isolate* isolate = thread->isolate();
4473
4474 // Return only allocations for objects with classId.
4475 if (js->HasParam("classId")) {
4476 const char* class_id = js->LookupParam("classId");
4477 intptr_t cid = -1;
4478 GetPrefixedIntegerId(class_id, "classes/", &cid);
4479 if (IsValidClassId(isolate, cid)) {
4480 if (CheckProfilerDisabled(thread, js)) {
4481 return;
4482 }
4483 const Class& cls = Class::Handle(GetClassForId(isolate, cid));
4484 ProfilerService::PrintAllocationJSON(js, cls, time_origin_micros,
4485 time_extent_micros);
4486 } else {
4487 PrintInvalidParamError(js, "classId");
4488 }
4489 } else {
4490 // Otherwise, return allocations for all traced class IDs.
4491 if (CheckProfilerDisabled(thread, js)) {
4492 return;
4493 }
4494 ProfilerService::PrintAllocationJSON(js, time_origin_micros,
4495 time_extent_micros);
4496 }
4497}
4498
4501 nullptr,
4502};
4503
4504static void ClearCpuSamples(Thread* thread, JSONStream* js) {
4507}
4508
4510 JSONStream* js,
4511 bool internal) {
4512 bool should_reset_accumulator = false;
4513 bool should_collect = false;
4514 if (js->HasParam("reset")) {
4515 if (js->ParamIs("reset", "true")) {
4516 should_reset_accumulator = true;
4517 } else {
4518 PrintInvalidParamError(js, "reset");
4519 return;
4520 }
4521 }
4522 if (js->HasParam("gc")) {
4523 if (js->ParamIs("gc", "true")) {
4524 should_collect = true;
4525 } else {
4527 return;
4528 }
4529 }
4530 auto isolate_group = thread->isolate_group();
4531 if (should_reset_accumulator) {
4533 }
4534 if (should_collect) {
4535 isolate_group->UpdateLastAllocationProfileGCTimestamp();
4536 isolate_group->heap()->CollectAllGarbage(GCReason::kDebugging);
4537 }
4538 isolate_group->class_table()->AllocationProfilePrintJSON(js, internal);
4539}
4540
4543 nullptr,
4544};
4545
4547 GetAllocationProfileImpl(thread, js, false);
4548}
4549
4551 GetAllocationProfileImpl(thread, js, true);
4552}
4553
4556 nullptr,
4557};
4558
4559static void CollectAllGarbage(Thread* thread, JSONStream* js) {
4560 auto heap = thread->isolate_group()->heap();
4563}
4564
4565static const MethodParameter* const get_heap_map_params[] = {
4567 nullptr,
4568};
4569
4570static void GetHeapMap(Thread* thread, JSONStream* js) {
4571 auto isolate_group = thread->isolate_group();
4572 if (js->HasParam("gc")) {
4573 if (js->ParamIs("gc", "scavenge")) {
4574 isolate_group->heap()->CollectGarbage(thread, GCType::kScavenge,
4576 } else if (js->ParamIs("gc", "mark-sweep")) {
4577 isolate_group->heap()->CollectGarbage(thread, GCType::kMarkSweep,
4579 } else if (js->ParamIs("gc", "mark-compact")) {
4580 isolate_group->heap()->CollectGarbage(thread, GCType::kMarkCompact,
4582 } else {
4584 return;
4585 }
4586 }
4587 isolate_group->heap()->PrintHeapMapToJSONStream(isolate_group, js);
4588}
4589
4592 nullptr,
4593};
4594
4595static void RequestHeapSnapshot(Thread* thread, JSONStream* js) {
4596 if (Service::heapsnapshot_stream.enabled()) {
4597 VmServiceHeapSnapshotChunkedWriter vmservice_writer(thread);
4598 HeapSnapshotWriter writer(thread, &vmservice_writer);
4599 writer.Write();
4600 }
4601 // TODO(koda): Provide some id that ties this request to async response(s).
4603}
4604
4605#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
4606struct VMMapping {
4607 char path[256];
4608 size_t size;
4609};
4610
4611static void AddVMMappings(JSONArray* rss_children) {
4612 FILE* fp = fopen("/proc/self/smaps", "r");
4613 if (fp == nullptr) {
4614 return;
4615 }
4616
4617 MallocGrowableArray<VMMapping> mappings(10);
4618 char* line = nullptr;
4619 size_t line_buffer_size = 0;
4620 char path[256];
4621 char property[32];
4622 size_t start, end, size;
4623 while (getline(&line, &line_buffer_size, fp) > 0) {
4624 if (sscanf(line, "%zx-%zx", &start, &end) == 2) {
4625 // Each line has the following format:
4626 //
4627 // start-end flags offset dev inode path
4628 //
4629 // We want to skip 4 fields and get to the last one (path).
4630 // Note that we can't scan backwards because path might contain white
4631 // space.
4632 const intptr_t kPathFieldIndex = 5;
4633
4634 char* path_start = line;
4635 intptr_t current_field = 0;
4636 while (*path_start != '\0') {
4637 // Field separator.
4638 if (*path_start == ' ') {
4639 // Skip to the first non-space.
4640 while (*path_start == ' ') {
4641 path_start++;
4642 }
4643 current_field++;
4644 if (current_field == kPathFieldIndex) {
4645 break;
4646 }
4647 continue;
4648 }
4649 path_start++;
4650 }
4651 if (current_field != kPathFieldIndex) {
4652 continue; // Malformed input.
4653 }
4654
4655 strncpy(path, path_start, sizeof(path) - 1);
4656 int len = strlen(path);
4657 if ((len > 0) && path[len - 1] == '\n') {
4658 path[len - 1] = 0;
4659 }
4660 } else if (sscanf(line, "%s%zd", property, &size) == 2) {
4661 // Property line.
4662 // Skipping a few paths to avoid double counting:
4663 // (deleted) - memfd dual mapping in Dart heap
4664 // [heap] - sbrk area, should already included with malloc
4665 // <empty> - anonymous mappings, mostly in Dart heap (Linux)
4666 // [anon:dart-*] - as labelled (Android)
4667 if ((strcmp(property, "Rss:") == 0) && (size != 0) &&
4668 (strcmp(path, "(deleted)") != 0) && (strcmp(path, "[heap]") != 0) &&
4669 (strcmp(path, "") != 0) && (strcmp(path, "[anon:dart-heap]") != 0) &&
4670 (strcmp(path, "[anon:dart-code]") != 0) &&
4671 (strcmp(path, "[anon:dart-profiler]") != 0) &&
4672 (strcmp(path, "[anon:dart-timeline]") != 0) &&
4673 (strcmp(path, "[anon:dart-zone]") != 0)) {
4674 bool updated = false;
4675 for (intptr_t i = 0; i < mappings.length(); i++) {
4676 if (strcmp(mappings[i].path, path) == 0) {
4677 mappings[i].size += size;
4678 updated = true;
4679 break;
4680 }
4681 }
4682 if (!updated) {
4683 VMMapping mapping;
4684 strncpy(mapping.path, path, sizeof(mapping.path));
4685 mapping.size = size;
4686 mappings.Add(mapping);
4687 }
4688 }
4689 }
4690 }
4691 fclose(fp);
4692 free(line); // Free buffer allocated by getline.
4693
4694 for (intptr_t i = 0; i < mappings.length(); i++) {
4695 JSONObject mapping(rss_children);
4696 mapping.AddProperty("name", mappings[i].path);
4697 mapping.AddProperty("description",
4698 "Mapped file / shared library / executable");
4699 mapping.AddProperty64("size", mappings[i].size * KB);
4700 JSONArray(&mapping, "children");
4701 }
4702}
4703#endif
4704
4706 JSONObject response(js);
4707 response.AddProperty("type", "ProcessMemoryUsage");
4708
4709 JSONObject rss(&response, "root");
4710 rss.AddPropertyF("name", "Process %" Pd "", OS::ProcessId());
4711 rss.AddProperty("description", "Resident set size");
4712 rss.AddProperty64("size", Service::CurrentRSS());
4713 JSONArray rss_children(&rss, "children");
4714
4715 intptr_t vm_size = 0;
4716 {
4717 JSONObject vm(&rss_children);
4718 {
4719 JSONArray vm_children(&vm, "children");
4720
4721 {
4722 JSONObject profiler(&vm_children);
4723 profiler.AddProperty("name", "Profiler");
4724 profiler.AddProperty("description",
4725 "Samples from the Dart VM's profiler");
4726 intptr_t size = Profiler::Size();
4727 vm_size += size;
4728 profiler.AddProperty64("size", size);
4729 JSONArray(&profiler, "children");
4730 }
4731
4732 {
4733 JSONObject timeline(&vm_children);
4734 timeline.AddProperty("name", "Timeline");
4735 timeline.AddProperty(
4736 "description",
4737 "Timeline events from dart:developer and Dart_RecordTimelineEvent");
4738 intptr_t size = Timeline::recorder()->Size();
4739 vm_size += size;
4740 timeline.AddProperty64("size", size);
4741 JSONArray(&timeline, "children");
4742 }
4743
4744 {
4745 JSONObject zone(&vm_children);
4746 zone.AddProperty("name", "Zone");
4747 zone.AddProperty("description", "Arena allocation in the Dart VM");
4748 intptr_t size = Zone::Size();
4749 vm_size += size;
4750 zone.AddProperty64("size", size);
4751 JSONArray(&zone, "children");
4752 }
4753
4754 {
4755 JSONObject semi(&vm_children);
4756 semi.AddProperty("name", "Page Cache");
4757 semi.AddProperty("description", "Cached heap regions");
4758 intptr_t size = Page::CachedSize();
4759 vm_size += size;
4760 semi.AddProperty64("size", size);
4761 JSONArray(&semi, "children");
4762 }
4763
4764 IsolateGroup::ForEach([&vm_children,
4765 &vm_size](IsolateGroup* isolate_group) {
4766 int64_t capacity =
4767 (isolate_group->heap()->new_space()->CapacityInWords() +
4768 isolate_group->heap()->old_space()->CapacityInWords()) *
4769 kWordSize;
4770 // The more precise UsedInWords for new-space iterates pages and
4771 // potentially accesses Thread::top_/end_, which is not thread-safe
4772 // here. CapacityInWords is similar enough for purposes of service stats
4773 // for new-space, differing only up to the as-yet-unused portion of
4774 // active TLABs, unlike old-space where it can differ greatly in a
4775 // highly fragmented heap.
4776 int64_t used = (isolate_group->heap()->new_space()->CapacityInWords() +
4777 isolate_group->heap()->old_space()->UsedInWords()) *
4778 kWordSize;
4779
4780 int64_t free = capacity - used;
4781
4782 JSONObject group(&vm_children);
4783 group.AddPropertyF("name", "IsolateGroup %s",
4784 isolate_group->source()->name);
4785 group.AddProperty("description", "Dart heap capacity");
4786 vm_size += capacity;
4787 group.AddProperty64("size", capacity);
4788 JSONArray group_children(&group, "children");
4789
4790 {
4791 JSONObject jsused(&group_children);
4792 jsused.AddProperty("name", "Used");
4793 jsused.AddProperty("description", "");
4794 jsused.AddProperty64("size", used);
4795 JSONArray(&jsused, "children");
4796 }
4797
4798 {
4799 JSONObject jsfree(&group_children);
4800 jsfree.AddProperty("name", "Free");
4801 jsfree.AddProperty("description", "");
4802 jsfree.AddProperty64("size", free);
4803 JSONArray(&jsfree, "children");
4804 }
4805 });
4806 } // vm_children
4807
4808 vm.AddProperty("name", "Dart VM");
4809 vm.AddProperty("description", "");
4810 vm.AddProperty64("size", vm_size);
4811 }
4812
4813#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
4814 AddVMMappings(&rss_children);
4815#endif
4816 // TODO(46166): Implement for other operating systems.
4817
4818 return vm_size;
4819}
4820
4822 nullptr,
4823};
4824
4827}
4828
4829void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) {
4830 if (!Service::debug_stream.enabled()) {
4831 return;
4832 }
4834 event.set_inspectee(&inspectee);
4836}
4837
4839 const char* stream_id,
4840 const char* event_kind,
4841 const uint8_t* bytes,
4842 intptr_t bytes_len) {
4844 event.set_embedder_kind(event_kind);
4845 event.set_embedder_stream_id(stream_id);
4846 event.set_bytes(bytes, bytes_len);
4847 Service::HandleEvent(&event, /*enter_safepoint=*/false);
4848}
4849
4851 int64_t sequence_number,
4852 int64_t timestamp,
4853 intptr_t level,
4854 const String& name,
4855 const String& message,
4856 const Instance& zone,
4857 const Object& error,
4858 const Instance& stack_trace) {
4859 if (!Service::logging_stream.enabled()) {
4860 return;
4861 }
4862 ServiceEvent::LogRecord log_record;
4863 log_record.sequence_number = sequence_number;
4864 log_record.timestamp = timestamp;
4865 log_record.level = level;
4866 log_record.name = &name;
4867 log_record.message = &message;
4868 log_record.zone = &zone;
4869 log_record.error = &error;
4870 log_record.stack_trace = &stack_trace;
4872 event.set_log_record(log_record);
4874}
4875
4877 const String& event_kind,
4878 const String& event_data) {
4879 if (!Service::extension_stream.enabled()) {
4880 return;
4881 }
4882 ServiceEvent::ExtensionEvent extension_event;
4883 extension_event.event_kind = &event_kind;
4884 extension_event.event_data = &event_data;
4886 event.set_extension_event(extension_event);
4888}
4889
4892 nullptr,
4893};
4894
4895template <typename T>
4897 public:
4899 : HandleVisitor(thread), handles_(handles) {
4900 ASSERT(handles_ != nullptr);
4901 }
4902
4903 void Append(PersistentHandle* persistent_handle) {
4904 JSONObject obj(handles_);
4905 obj.AddProperty("type", "_PersistentHandle");
4906 const Object& object = Object::Handle(persistent_handle->ptr());
4907 obj.AddProperty("object", object);
4908 }
4909
4910 void Append(FinalizablePersistentHandle* weak_persistent_handle) {
4911 if (!weak_persistent_handle->ptr()->IsHeapObject()) {
4912 return; // Free handle.
4913 }
4914
4915 JSONObject obj(handles_);
4916 obj.AddProperty("type", "_WeakPersistentHandle");
4917 const Object& object = Object::Handle(weak_persistent_handle->ptr());
4918 obj.AddProperty("object", object);
4919 obj.AddPropertyF(
4920 "peer", "0x%" Px "",
4921 reinterpret_cast<uintptr_t>(weak_persistent_handle->peer()));
4922 obj.AddPropertyF(
4923 "callbackAddress", "0x%" Px "",
4924 reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()));
4925 // Attempt to include a native symbol name.
4927 reinterpret_cast<uword>(weak_persistent_handle->callback()), nullptr);
4928 obj.AddProperty("callbackSymbolName", (name == nullptr) ? "" : name);
4929 if (name != nullptr) {
4931 }
4932 obj.AddPropertyF("externalSize", "%" Pd "",
4933 weak_persistent_handle->external_size());
4934 }
4935
4936 protected:
4937 void VisitHandle(uword addr) override {
4938 T* handle = reinterpret_cast<T*>(addr);
4939 Append(handle);
4940 }
4941
4943};
4944
4946 Isolate* isolate = thread->isolate();
4947 ASSERT(isolate != nullptr);
4948
4949 ApiState* api_state = isolate->group()->api_state();
4950 ASSERT(api_state != nullptr);
4951
4952 {
4953 JSONObject obj(js);
4954 obj.AddProperty("type", "_PersistentHandles");
4955 // Persistent handles.
4956 {
4957 JSONArray persistent_handles(&obj, "persistentHandles");
4959 [&](PersistentHandles& handles) {
4961 thread, &persistent_handles);
4962 handles.Visit(&visitor);
4963 });
4964 }
4965 // Weak persistent handles.
4966 {
4967 JSONArray weak_persistent_handles(&obj, "weakPersistentHandles");
4969 [&](FinalizablePersistentHandles& handles) {
4971 thread, &weak_persistent_handles);
4972 handles.VisitHandles(&visitor);
4973 });
4974 }
4975 }
4976}
4977
4980 nullptr,
4981};
4982
4983static void GetPortsPrivate(Thread* thread, JSONStream* js) {
4984 MessageHandler* message_handler = thread->isolate()->message_handler();
4985 PortMap::PrintPortsForMessageHandler(message_handler, js);
4986}
4987
4989 JSONObject jsobj(js);
4990 jsobj.AddProperty("a", "a");
4991 JSONObject jsobj1(js);
4992 jsobj1.AddProperty("a", "a");
4993 JSONObject jsobj2(js);
4994 jsobj2.AddProperty("a", "a");
4995 JSONObject jsobj3(js);
4996 jsobj3.AddProperty("a", "a");
4997}
4998
5000 JSONObject jsobj(js);
5001 jsobj.AddProperty("bart", "simpson");
5002}
5003
5004// Returns |true| if a heap object with the specified ID was successfully found,
5005// and |false| otherwise. If an object was found, it will be stored at address
5006// |obj|.
5007// This function should be used to handle shared logic between |GetObject| and
5008// |GetImplementationFields|.
5009static bool GetHeapObjectCommon(Thread* thread,
5010 JSONStream* js,
5011 const char* id,
5012 Object* obj,
5013 ObjectIdRing::LookupResult* lookup_result) {
5014 *obj = LookupHeapObject(thread, id, lookup_result);
5015 ASSERT(obj != nullptr);
5016 ASSERT(lookup_result != nullptr);
5017 if (obj->ptr() != Object::sentinel().ptr()) {
5018#if !defined(DART_PRECOMPILED_RUNTIME)
5019 // If obj is a script from dart:* and doesn't have source loaded, try and
5020 // load the source before sending the response.
5021 if (obj->IsScript()) {
5022 const Script& script = Script::Cast(*obj);
5023 if (!script.HasSource() && script.IsPartOfDartColonLibrary() &&
5025 const uint8_t* kernel_buffer = Service::dart_library_kernel();
5026 const intptr_t kernel_buffer_len =
5028 script.LoadSourceFromKernel(kernel_buffer, kernel_buffer_len);
5029 }
5030 }
5031#endif // !defined(DART_PRECOMPILED_RUNTIME)
5032 // We found a heap object for this id.
5033 return true;
5034 }
5035
5036 return false;
5037}
5038
5039static const MethodParameter* const get_object_params[] = {
5041 new UIntParameter("offset", false),
5042 new UIntParameter("count", false),
5043 nullptr,
5044};
5045
5046static void GetObject(Thread* thread, JSONStream* js) {
5047 const char* id = js->LookupParam("objectId");
5048 if (id == nullptr) {
5049 PrintMissingParamError(js, "objectId");
5050 return;
5051 }
5052 if (js->HasParam("offset")) {
5053 intptr_t value = UIntParameter::Parse(js->LookupParam("offset"));
5054 if (value < 0) {
5055 PrintInvalidParamError(js, "offset");
5056 return;
5057 }
5058 js->set_offset(value);
5059 }
5060 if (js->HasParam("count")) {
5061 intptr_t value = UIntParameter::Parse(js->LookupParam("count"));
5062 if (value < 0) {
5063 PrintInvalidParamError(js, "count");
5064 return;
5065 }
5066 js->set_count(value);
5067 }
5068
5069 // Handle heap objects.
5070 Object& obj = Object::Handle();
5071 ObjectIdRing::LookupResult lookup_result;
5072 if (GetHeapObjectCommon(thread, js, id, &obj, &lookup_result)) {
5073 obj.PrintJSON(js, false);
5074 return;
5075 } else if (lookup_result == ObjectIdRing::kCollected) {
5077 return;
5078 } else if (lookup_result == ObjectIdRing::kExpired) {
5080 return;
5081 }
5082
5083 // Handle non-heap objects.
5084 Breakpoint* bpt = LookupBreakpoint(thread->isolate(), id, &lookup_result);
5085 if (bpt != nullptr) {
5086 bpt->PrintJSON(js);
5087 return;
5088 } else if (lookup_result == ObjectIdRing::kCollected) {
5090 return;
5091 }
5092
5093 PrintInvalidParamError(js, "objectId");
5094}
5095
5099 nullptr,
5100};
5101
5103 const char* id = js->LookupParam("objectId");
5104
5105 // Handle heap objects.
5106 Object& obj = Object::Handle();
5107 ObjectIdRing::LookupResult lookup_result;
5108 if (GetHeapObjectCommon(thread, js, id, &obj, &lookup_result)) {
5110 return;
5111 } else if (lookup_result == ObjectIdRing::kCollected) {
5113 return;
5114 } else if (lookup_result == ObjectIdRing::kExpired) {
5116 return;
5117 }
5118
5119 // Handle non-heap objects.
5120 Breakpoint* bpt = LookupBreakpoint(thread->isolate(), id, &lookup_result);
5121 if (bpt != nullptr) {
5122 const JSONObject jsobj(js);
5123 jsobj.AddProperty("type", "ImplementationFields");
5124 JSONArray jsarr_fields(&jsobj, "fields");
5125 return;
5126 } else if (lookup_result == ObjectIdRing::kCollected) {
5128 return;
5129 }
5130
5131 PrintInvalidParamError(js, "objectId");
5132}
5133
5136 nullptr,
5137};
5138
5139static void GetObjectStore(Thread* thread, JSONStream* js) {
5140 JSONObject jsobj(js);
5141 thread->isolate_group()->object_store()->PrintToJSONObject(&jsobj);
5142}
5143
5146 nullptr,
5147};
5148
5150 JSONObject jsobj(js);
5151 thread->isolate()->isolate_object_store()->PrintToJSONObject(&jsobj);
5152}
5153
5156 nullptr,
5157};
5158
5159static void GetClassList(Thread* thread, JSONStream* js) {
5160 ClassTable* table = thread->isolate_group()->class_table();
5161 JSONObject jsobj(js);
5162 table->PrintToJSONObject(&jsobj);
5163}
5164
5167 nullptr,
5168};
5169
5171 bool only_with_instantiations = false;
5172 if (js->ParamIs("onlyWithInstantiations", "true")) {
5173 only_with_instantiations = true;
5174 }
5175 Zone* zone = thread->zone();
5176 ObjectStore* object_store = thread->isolate_group()->object_store();
5177 CanonicalTypeArgumentsSet typeargs_table(
5178 zone, object_store->canonical_type_arguments());
5179 const intptr_t table_size = typeargs_table.NumEntries();
5180 const intptr_t table_used = typeargs_table.NumOccupied();
5181 const Array& typeargs_array =
5182 Array::Handle(zone, HashTables::ToArray(typeargs_table, false));
5183 ASSERT(typeargs_array.Length() == table_used);
5184 TypeArguments& typeargs = TypeArguments::Handle(zone);
5185 JSONObject jsobj(js);
5186 jsobj.AddProperty("type", "TypeArgumentsList");
5187 jsobj.AddProperty("canonicalTypeArgumentsTableSize", table_size);
5188 jsobj.AddProperty("canonicalTypeArgumentsTableUsed", table_used);
5189 JSONArray members(&jsobj, "typeArguments");
5190 for (intptr_t i = 0; i < table_used; i++) {
5191 typeargs ^= typeargs_array.At(i);
5192 if (!typeargs.IsNull()) {
5193 if (!only_with_instantiations || typeargs.HasInstantiations()) {
5194 members.AddValue(typeargs);
5195 }
5196 }
5197 }
5198 typeargs_table.Release();
5199}
5200
5201static const MethodParameter* const get_version_params[] = {
5203 nullptr,
5204};
5205
5206static void GetVersion(Thread* thread, JSONStream* js) {
5207 JSONObject jsobj(js);
5208 jsobj.AddProperty("type", "Version");
5209 jsobj.AddProperty("major",
5210 static_cast<intptr_t>(SERVICE_PROTOCOL_MAJOR_VERSION));
5211 jsobj.AddProperty("minor",
5212 static_cast<intptr_t>(SERVICE_PROTOCOL_MINOR_VERSION));
5213 jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
5214 jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
5215}
5216
5218 public:
5219 explicit ServiceIsolateVisitor(JSONArray* jsarr) : jsarr_(jsarr) {}
5221
5222 void VisitIsolate(Isolate* isolate) {
5223 if (!IsSystemIsolate(isolate) && isolate->is_service_registered()) {
5224 jsarr_->AddValue(isolate);
5225 }
5226 }
5227
5228 private:
5229 JSONArray* jsarr_;
5230};
5231
5233 public:
5234 explicit SystemServiceIsolateVisitor(JSONArray* jsarr) : jsarr_(jsarr) {}
5236
5237 void VisitIsolate(Isolate* isolate) {
5238 if (IsSystemIsolate(isolate) && !isolate->is_vm_isolate()) {
5239 jsarr_->AddValue(isolate);
5240 }
5241 }
5242
5243 private:
5244 JSONArray* jsarr_;
5245};
5246
5247static const MethodParameter* const get_vm_params[] = {
5249 nullptr,
5250};
5251
5253 if (embedder_information_callback_ != nullptr) {
5255 0, // version
5256 nullptr, // name
5257 -1, // max_rss
5258 -1 // current_rss
5259 };
5260 embedder_information_callback_(&info);
5262 if (info.name != nullptr) {
5263 jsobj->AddProperty("_embedder", info.name);
5264 }
5265 if (info.max_rss >= 0) {
5266 jsobj->AddProperty64("_maxRSS", info.max_rss);
5267 }
5268 if (info.current_rss >= 0) {
5269 jsobj->AddProperty64("_currentRSS", info.current_rss);
5270 }
5271 }
5272}
5273
5275 JSONObject jsobj(js);
5276 jsobj.AddProperty("type", (ref ? "@VM" : "VM"));
5277 jsobj.AddProperty("name", GetVMName());
5278 if (ref) {
5279 return;
5280 }
5281 jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord));
5282 jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
5283 jsobj.AddProperty("operatingSystem", OS::Name());
5284 jsobj.AddProperty("targetCPU", CPU::Id());
5285 jsobj.AddProperty("version", Version::String());
5286#if defined(DART_PRECOMPILED_RUNTIME)
5288#else
5290#endif
5291 char* features_string = Dart::FeaturesString(nullptr, true, kind);
5292 jsobj.AddProperty("_features", features_string);
5293 free(features_string);
5294 jsobj.AddProperty("_profilerMode", FLAG_profile_vm ? "VM" : "Dart");
5295 jsobj.AddProperty64("pid", OS::ProcessId());
5297 "startTime", OS::GetCurrentTimeMillis() - Dart::UptimeMillis());
5299 // Construct the isolate and isolate_groups list.
5300 {
5301 JSONArray jsarr(&jsobj, "isolates");
5302 ServiceIsolateVisitor visitor(&jsarr);
5303 Isolate::VisitIsolates(&visitor);
5304 }
5305 {
5306 JSONArray jsarr(&jsobj, "systemIsolates");
5307 SystemServiceIsolateVisitor visitor(&jsarr);
5308 Isolate::VisitIsolates(&visitor);
5309 }
5310 {
5311 JSONArray jsarr_isolate_groups(&jsobj, "isolateGroups");
5312 IsolateGroup::ForEach([&jsarr_isolate_groups](IsolateGroup* isolate_group) {
5313 if (!isolate_group->is_system_isolate_group()) {
5314 jsarr_isolate_groups.AddValue(isolate_group);
5315 }
5316 });
5317 }
5318 {
5319 JSONArray jsarr_isolate_groups(&jsobj, "systemIsolateGroups");
5320 IsolateGroup::ForEach([&jsarr_isolate_groups](IsolateGroup* isolate_group) {
5321 // Don't surface the vm-isolate since it's not a "real" isolate.
5322 if (isolate_group->is_vm_isolate()) {
5323 return;
5324 }
5325 if (isolate_group->is_system_isolate_group()) {
5326 jsarr_isolate_groups.AddValue(isolate_group);
5327 }
5328 });
5329 }
5330 {
5331 JSONStream discard_js;
5332 intptr_t vm_memory = GetProcessMemoryUsageHelper(&discard_js);
5333 jsobj.AddProperty("_currentMemory", vm_memory);
5334 }
5335}
5336
5337static void GetVM(Thread* thread, JSONStream* js) {
5339}
5340
5342 public:
5343 static const char* Name() { return "UriMappingTraits"; }
5344 static bool ReportStats() { return false; }
5345
5346 static bool IsMatch(const Object& a, const Object& b) {
5347 const String& a_str = String::Cast(a);
5348 const String& b_str = String::Cast(b);
5349
5350 ASSERT(a_str.HasHash() && b_str.HasHash());
5351 return a_str.Equals(b_str);
5352 }
5353
5354 static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
5355
5356 static ObjectPtr NewKey(const String& str) { return str.ptr(); }
5357};
5358
5360
5361static void PopulateUriMappings(Thread* thread) {
5362 Zone* zone = thread->zone();
5363 auto object_store = thread->isolate_group()->object_store();
5364 UriMapping uri_to_resolved_uri(HashTables::New<UriMapping>(16, Heap::kOld));
5365 UriMapping resolved_uri_to_uri(HashTables::New<UriMapping>(16, Heap::kOld));
5366
5367 const auto& libs =
5368 GrowableObjectArray::Handle(zone, object_store->libraries());
5369 intptr_t num_libs = libs.Length();
5370
5371 Library& lib = Library::Handle(zone);
5372 Script& script = Script::Handle(zone);
5373 Array& scripts = Array::Handle(zone);
5374 String& uri = String::Handle(zone);
5375 String& resolved_uri = String::Handle(zone);
5376#if defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_MACOS)
5377 String& tmp = thread->StringHandle();
5378#endif
5379 for (intptr_t i = 0; i < num_libs; ++i) {
5380 lib ^= libs.At(i);
5381 scripts ^= lib.LoadedScripts();
5382 intptr_t num_scripts = scripts.Length();
5383 for (intptr_t j = 0; j < num_scripts; ++j) {
5384 script ^= scripts.At(j);
5385 uri ^= script.url();
5386 resolved_uri ^= script.resolved_url();
5387 uri_to_resolved_uri.UpdateOrInsert(uri, resolved_uri);
5388 resolved_uri_to_uri.UpdateOrInsert(resolved_uri, uri);
5389
5390#if defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_MACOS)
5391 // Allow for case insensitive matching on platforms that might allow for
5392 // case insensitive paths.
5393 tmp = String::ToLowerCase(uri);
5394 uri_to_resolved_uri.UpdateOrInsert(tmp, resolved_uri);
5395 tmp = String::ToLowerCase(resolved_uri);
5396 resolved_uri_to_uri.UpdateOrInsert(tmp, uri);
5397#endif
5398 }
5399 }
5400
5401 object_store->set_uri_to_resolved_uri_map(uri_to_resolved_uri.Release());
5402 object_store->set_resolved_uri_to_uri_map(resolved_uri_to_uri.Release());
5403 Smi& count = Smi::Handle(zone, Smi::New(num_libs));
5404 object_store->set_last_libraries_count(count);
5405}
5406
5407static void LookupScriptUrisImpl(Thread* thread,
5408 JSONStream* js,
5409 bool lookup_resolved) {
5410 Zone* zone = thread->zone();
5411 auto object_store = thread->isolate_group()->object_store();
5412
5413 const auto& libs =
5414 GrowableObjectArray::Handle(zone, object_store->libraries());
5415 Smi& last_libraries_count =
5416 Smi::Handle(zone, object_store->last_libraries_count());
5417 if ((object_store->uri_to_resolved_uri_map() == Array::null()) ||
5418 (object_store->resolved_uri_to_uri_map() == Array::null()) ||
5419 (last_libraries_count.Value() != libs.Length())) {
5420 PopulateUriMappings(thread);
5421 }
5422 const char* uris_arg = js->LookupParam("uris");
5423 if (uris_arg == nullptr) {
5424 PrintMissingParamError(js, "uris");
5425 return;
5426 }
5427
5428 const GrowableObjectArray& uris =
5430 intptr_t uris_length = ParseJSONArray(thread, uris_arg, uris);
5431 if (uris_length < 0) {
5432 PrintInvalidParamError(js, "uris");
5433 return;
5434 }
5435
5436 UriMapping map(lookup_resolved ? object_store->uri_to_resolved_uri_map()
5437 : object_store->resolved_uri_to_uri_map());
5438 JSONObject jsobj(js);
5439 jsobj.AddProperty("type", "UriList");
5440
5441 {
5442 JSONArray uris_array(&jsobj, "uris");
5443 String& uri = String::Handle(zone);
5444 String& res = String::Handle(zone);
5445 for (intptr_t i = 0; i < uris.Length(); ++i) {
5446 uri ^= uris.At(i);
5447 res ^= map.GetOrNull(uri);
5448#if defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_MACOS)
5449 // Windows and MacOS paths can be case insensitive, so we should allow for
5450 // case insensitive URI mappings on Windows and MacOS.
5451 if (res.IsNull()) {
5452 String& lower_case_uri = thread->StringHandle();
5453 lower_case_uri = String::ToLowerCase(uri);
5454 res ^= map.GetOrNull(lower_case_uri);
5455 }
5456#endif // defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_MACOS)
5457 if (res.IsNull()) {
5458 uris_array.AddValueNull();
5459 } else {
5460 uris_array.AddValue(res.ToCString());
5461 }
5462 }
5463 }
5464 map.Release();
5465}
5466
5469 nullptr,
5470};
5471
5473 LookupScriptUrisImpl(thread, js, true);
5474}
5475
5478 nullptr,
5479};
5480
5481static void LookupPackageUris(Thread* thread, JSONStream* js) {
5482 LookupScriptUrisImpl(thread, js, false);
5483}
5484
5485static const char* const exception_pause_mode_names[] = {
5486 "All",
5487 "None",
5488 "Unhandled",
5489 nullptr,
5490};
5491
5497};
5498
5501 new EnumParameter("mode", true, exception_pause_mode_names),
5502 nullptr,
5503};
5504
5506 const char* mode = js->LookupParam("mode");
5507 if (mode == nullptr) {
5508 PrintMissingParamError(js, "mode");
5509 return;
5510 }
5514 PrintInvalidParamError(js, "mode");
5515 return;
5516 }
5517 Isolate* isolate = thread->isolate();
5518 isolate->debugger()->SetExceptionPauseInfo(info);
5519 if (Service::debug_stream.enabled()) {
5522 }
5524}
5525
5528 new EnumParameter("exceptionPauseMode", false, exception_pause_mode_names),
5529 new BoolParameter("shouldPauseOnExit", false),
5530 nullptr,
5531};
5532
5533static void SetIsolatePauseMode(Thread* thread, JSONStream* js) {
5534 bool state_changed = false;
5535 const char* exception_pause_mode = js->LookupParam("exceptionPauseMode");
5536 if (exception_pause_mode != nullptr) {
5538 EnumMapper(exception_pause_mode, exception_pause_mode_names,
5541 PrintInvalidParamError(js, "exceptionPauseMode");
5542 return;
5543 }
5544 Isolate* isolate = thread->isolate();
5545 isolate->debugger()->SetExceptionPauseInfo(info);
5546 state_changed = true;
5547 }
5548
5549 const char* pause_isolate_on_exit = js->LookupParam("shouldPauseOnExit");
5550 if (pause_isolate_on_exit != nullptr) {
5551 bool enable = BoolParameter::Parse(pause_isolate_on_exit, false);
5552 thread->isolate()->message_handler()->set_should_pause_on_exit(enable);
5553 state_changed = true;
5554 }
5555
5556 if (state_changed && Service::debug_stream.enabled()) {
5557 ServiceEvent event(thread->isolate(),
5560 }
5562}
5563
5566 new IdParameter("breakpointId", true),
5567 new BoolParameter("enable", true),
5568 nullptr,
5569};
5570
5571static void SetBreakpointState(Thread* thread, JSONStream* js) {
5572 Isolate* isolate = thread->isolate();
5573 const char* bpt_id = js->LookupParam("breakpointId");
5574 bool enable = BoolParameter::Parse(js->LookupParam("enable"), true);
5575 ObjectIdRing::LookupResult lookup_result;
5576 Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id, &lookup_result);
5577 // TODO(bkonyi): Should we return a different error for bpts which
5578 // have been already removed?
5579 if (bpt == nullptr) {
5580 PrintInvalidParamError(js, "breakpointId");
5581 return;
5582 }
5583 if (isolate->debugger()->SetBreakpointState(bpt, enable)) {
5584 if (Service::debug_stream.enabled()) {
5586 event.set_breakpoint(bpt);
5588 }
5589 }
5590 bpt->PrintJSON(js);
5591}
5592
5593static const MethodParameter* const get_flag_list_params[] = {
5595 nullptr,
5596};
5597
5598static void GetFlagList(Thread* thread, JSONStream* js) {
5600}
5601
5602static const MethodParameter* const set_flags_params[] = {
5604 nullptr,
5605};
5606
5607static void SetFlag(Thread* thread, JSONStream* js) {
5608 const char* flag_name = js->LookupParam("name");
5609 if (flag_name == nullptr) {
5610 PrintMissingParamError(js, "name");
5611 return;
5612 }
5613 const char* flag_value = js->LookupParam("value");
5614 if (flag_value == nullptr) {
5615 PrintMissingParamError(js, "value");
5616 return;
5617 }
5618
5619 if (Flags::Lookup(flag_name) == nullptr) {
5620 JSONObject jsobj(js);
5621 jsobj.AddProperty("type", "Error");
5622 jsobj.AddProperty("message", "Cannot set flag: flag not found");
5623 return;
5624 }
5625
5626 // Changing most flags at runtime is dangerous because e.g., it may leave the
5627 // behavior generated code and the runtime out of sync.
5628 const uintptr_t kProfilePeriodIndex = 3;
5629 const uintptr_t kProfilerIndex = 4;
5630 const char* kAllowedFlags[] = {
5631 "pause_isolates_on_start",
5632 "pause_isolates_on_exit",
5633 "pause_isolates_on_unhandled_exceptions",
5634 "profile_period",
5635 "profiler",
5636 };
5637
5638 bool allowed = false;
5639 bool profile_period = false;
5640 bool profiler = false;
5641 for (size_t i = 0; i < ARRAY_SIZE(kAllowedFlags); i++) {
5642 if (strcmp(flag_name, kAllowedFlags[i]) == 0) {
5643 allowed = true;
5644 profile_period = (i == kProfilePeriodIndex);
5645 profiler = (i == kProfilerIndex);
5646 break;
5647 }
5648 }
5649
5650 if (!allowed) {
5651 JSONObject jsobj(js);
5652 jsobj.AddProperty("type", "Error");
5653 jsobj.AddProperty("message", "Cannot set flag: cannot change at runtime");
5654 return;
5655 }
5656
5657 const char* error = nullptr;
5658 if (Flags::SetFlag(flag_name, flag_value, &error)) {
5660 if (profile_period) {
5661 // FLAG_profile_period has already been set to the new value. Now we need
5662 // to notify the ThreadInterrupter to pick up the change.
5664 } else if (profiler) {
5665 // FLAG_profiler has already been set to the new value.
5667 }
5668 if (Service::vm_stream.enabled()) {
5670 event.set_flag_name(flag_name);
5671 event.set_flag_new_value(flag_value);
5673 }
5674 } else {
5675 JSONObject jsobj(js);
5676 jsobj.AddProperty("type", "Error");
5677 jsobj.AddProperty("message", error);
5678 }
5679}
5680
5683 new IdParameter("libraryId", true),
5684 new BoolParameter("isDebuggable", true),
5685 nullptr,
5686};
5687
5689 const char* lib_id = js->LookupParam("libraryId");
5690 ObjectIdRing::LookupResult lookup_result;
5691 Object& obj =
5692 Object::Handle(LookupHeapObject(thread, lib_id, &lookup_result));
5693 const bool is_debuggable =
5694 BoolParameter::Parse(js->LookupParam("isDebuggable"), false);
5695 if (obj.IsLibrary()) {
5696 const Library& lib = Library::Cast(obj);
5697 lib.set_debuggable(is_debuggable);
5699 return;
5700 }
5701 PrintInvalidParamError(js, "libraryId");
5702}
5703
5704static const MethodParameter* const set_name_params[] = {
5706 new MethodParameter("name", true),
5707 nullptr,
5708};
5709
5710static void SetName(Thread* thread, JSONStream* js) {
5711 Isolate* isolate = thread->isolate();
5712 isolate->set_name(js->LookupParam("name"));
5713 if (Service::isolate_stream.enabled()) {
5716 }
5718 return;
5719}
5720
5721static const MethodParameter* const set_vm_name_params[] = {
5723 new MethodParameter("name", true),
5724 nullptr,
5725};
5726
5727static void SetVMName(Thread* thread, JSONStream* js) {
5728 const char* name_param = js->LookupParam("name");
5729 free(vm_name);
5730 vm_name = Utils::StrDup(name_param);
5731 if (Service::vm_stream.enabled()) {
5734 }
5736 return;
5737}
5738
5741 new IdParameter("classId", true),
5742 new BoolParameter("enable", true),
5743 nullptr,
5744};
5745
5747 const char* class_id = js->LookupParam("classId");
5748 const bool enable = BoolParameter::Parse(js->LookupParam("enable"));
5749 intptr_t cid = -1;
5750 GetPrefixedIntegerId(class_id, "classes/", &cid);
5751 Isolate* isolate = thread->isolate();
5752 if (!IsValidClassId(isolate, cid)) {
5753 PrintInvalidParamError(js, "classId");
5754 return;
5755 }
5756 const Class& cls = Class::Handle(GetClassForId(isolate, cid));
5757 ASSERT(!cls.IsNull());
5758 cls.SetTraceAllocation(enable);
5760}
5761
5764 nullptr,
5765};
5766
5768 JSONObject jsobj(js);
5769 jsobj.AddProperty("type", "ClassesAliasesMap");
5770
5771 JSONObject map(&jsobj, "map");
5772
5773#define DEFINE_ADD_VALUE_F(id) \
5774 internals.AddValueF("classes/%" Pd, static_cast<intptr_t>(id));
5775#define DEFINE_ADD_VALUE_F_CID(clazz) DEFINE_ADD_VALUE_F(k##clazz##Cid)
5776 {
5777 JSONArray internals(&map, "<VM Internals>");
5778 for (intptr_t id = kFirstInternalOnlyCid; id <= kLastInternalOnlyCid;
5779 ++id) {
5781 }
5783 }
5784 {
5785 JSONArray internals(&map, "Type");
5786 for (intptr_t id = kAbstractTypeCid; id <= kTypeParameterCid; ++id) {
5788 }
5789 }
5790 {
5791 JSONArray internals(&map, "Object");
5793 }
5794 {
5795 JSONArray internals(&map, "Closure");
5798 }
5799 {
5800 JSONArray internals(&map, "Int");
5801 for (intptr_t id = kIntegerCid; id <= kMintCid; ++id) {
5803 }
5804 }
5805 {
5806 JSONArray internals(&map, "Double");
5808 }
5809 {
5810 JSONArray internals(&map, "String");
5812 }
5813 {
5814 JSONArray internals(&map, "List");
5817 }
5818 {
5819 JSONArray internals(&map, "Map");
5821 }
5822
5823 {
5824 JSONArray internals(&map, "Set");
5826 }
5827#define DEFINE_ADD_MAP_KEY(clazz) \
5828 {JSONArray internals(&map, #clazz); \
5829 DEFINE_ADD_VALUE_F_CID(TypedData##clazz) \
5830 DEFINE_ADD_VALUE_F_CID(TypedData##clazz##View) \
5831 DEFINE_ADD_VALUE_F_CID(ExternalTypedData##clazz) \
5832 DEFINE_ADD_VALUE_F_CID(UnmodifiableTypedData##clazz##View) \
5833 }
5835#undef DEFINE_ADD_MAP_KEY
5836#define DEFINE_ADD_MAP_KEY(clazz) \
5837 {JSONArray internals(&map, #clazz); \
5838 DEFINE_ADD_VALUE_F_CID(Ffi##clazz) \
5839 }
5841#undef DEFINE_ADD_MAP_KEY
5842#undef DEFINE_ADD_VALUE_F_CID
5843#undef DEFINE_ADD_VALUE_F
5844}
5845
5846// clang-format off
5848 { "_echo", Echo,
5849 nullptr },
5850 { "_respondWithMalformedJson", RespondWithMalformedJson,
5851 nullptr },
5852 { "_respondWithMalformedObject", RespondWithMalformedObject,
5853 nullptr },
5854 { "_triggerEchoEvent", TriggerEchoEvent,
5855 nullptr },
5856 { "addBreakpoint", AddBreakpoint,
5858 { "addBreakpointWithScriptUri", AddBreakpointWithScriptUri,
5860 { "addBreakpointAtEntry", AddBreakpointAtEntry,
5862 { "_addBreakpointAtActivation", AddBreakpointAtActivation,
5864 { "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope,
5866 { "clearCpuSamples", ClearCpuSamples,
5868 { "clearVMTimeline", ClearVMTimeline,
5870 { "_compileExpression", CompileExpression, compile_expression_params },
5871 { "_enableProfiler", EnableProfiler,
5873 { "evaluate", Evaluate,
5875 { "evaluateInFrame", EvaluateInFrame,
5877 { "_getAllocationProfile", GetAllocationProfile,
5879 { "getAllocationProfile", GetAllocationProfilePublic,
5881 { "getAllocationTraces", GetAllocationTraces,
5883 { "getClassList", GetClassList,
5885 { "getCpuSamples", GetCpuSamples,
5887 { "getFlagList", GetFlagList,
5889 { "_getHeapMap", GetHeapMap,
5891 { "_getImplementationFields", GetImplementationFields,
5893 { "getInboundReferences", GetInboundReferences,
5895 { "getInstances", GetInstances,
5897 { "getInstancesAsList", GetInstancesAsList,
5899#if defined(SUPPORT_PERFETTO)
5900 { "getPerfettoCpuSamples", GetPerfettoCpuSamples,
5902 { "getPerfettoVMTimeline", GetPerfettoVMTimeline,
5904#endif // defined(SUPPORT_PERFETTO)
5905 { "getPorts", GetPorts,
5907 { "getIsolate", GetIsolate,
5909 { "_getIsolateObjectStore", GetIsolateObjectStore,
5911 { "getIsolateGroup", GetIsolateGroup,
5913 { "getMemoryUsage", GetMemoryUsage,
5915 { "getIsolateGroupMemoryUsage", GetIsolateGroupMemoryUsage,
5917 { "_getIsolateMetric", GetIsolateMetric,
5919 { "_getIsolateMetricList", GetIsolateMetricList,
5921 { "getIsolatePauseEvent", GetIsolatePauseEvent,
5923 { "getObject", GetObject,
5925 { "_getObjectStore", GetObjectStore,
5927 { "_getPersistentHandles", GetPersistentHandles,
5929 { "_getPorts", GetPortsPrivate,
5931 { "getProcessMemoryUsage", GetProcessMemoryUsage,
5933 { "_getReachableSize", GetReachableSize,
5935 { "_getRetainedSize", GetRetainedSize,
5937 { "lookupResolvedPackageUris", LookupResolvedPackageUris,
5939 { "lookupPackageUris", LookupPackageUris,
5941 { "getRetainingPath", GetRetainingPath,
5943 { "getScripts", GetScripts,
5945 { "getSourceReport", GetSourceReport,
5947 { "getStack", GetStack,
5949 { "_getTagProfile", GetTagProfile,
5951 { "_getTypeArgumentsList", GetTypeArgumentsList,
5953 { "getVersion", GetVersion,
5955 { "getVM", GetVM,
5956 get_vm_params },
5957 { "getVMTimeline", GetVMTimeline,
5959 { "getVMTimelineFlags", GetVMTimelineFlags,
5961 { "getVMTimelineMicros", GetVMTimelineMicros,
5963 { "invoke", Invoke, invoke_params },
5964 { "kill", Kill, kill_params },
5965 { "pause", Pause,
5966 pause_params },
5967 { "removeBreakpoint", RemoveBreakpoint,
5969 { "reloadSources", ReloadSources,
5971 { "_reloadSources", ReloadSources,
5973 { "resume", Resume,
5974 resume_params },
5975 { "requestHeapSnapshot", RequestHeapSnapshot,
5977 { "_evaluateCompiledExpression", EvaluateCompiledExpression,
5979 { "setBreakpointState", SetBreakpointState,
5981 { "setExceptionPauseMode", SetExceptionPauseMode,
5983 { "setIsolatePauseMode", SetIsolatePauseMode,
5985 { "setFlag", SetFlag,
5987 { "setLibraryDebuggable", SetLibraryDebuggable,
5989 { "setName", SetName,
5991 { "_setStreamIncludePrivateMembers", SetStreamIncludePrivateMembers,
5993 { "setTraceClassAllocation", SetTraceClassAllocation,
5995 { "setVMName", SetVMName,
5997 { "setVMTimelineFlags", SetVMTimelineFlags,
5998 set_vm_timeline_flags_params },
5999 { "_collectAllGarbage", CollectAllGarbage,
6001 { "_getDefaultClassesAliases", GetDefaultClassesAliases,
6003};
6004// clang-format on
6005
6006const ServiceMethodDescriptor* FindMethod(const char* method_name) {
6007 intptr_t num_methods = sizeof(service_methods_) / sizeof(service_methods_[0]);
6008 for (intptr_t i = 0; i < num_methods; i++) {
6010 if (strcmp(method_name, method.name) == 0) {
6011 return &method;
6012 }
6013 }
6014 return nullptr;
6015}
6016
6017#endif // !PRODUCT
6018
6019} // namespace dart
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
SI F table(const skcms_Curve *curve, F v)
ax::mojom::Event event_type
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
#define CLASS_LIST_MAPS(V)
Definition: class_id.h:116
#define CLASS_LIST_STRINGS(V)
Definition: class_id.h:132
#define CLASS_LIST_ARRAYS(V)
Definition: class_id.h:128
#define CLASS_LIST_SETS(V)
Definition: class_id.h:120
#define CLASS_LIST_FFI(V)
Definition: class_id.h:171
#define CLASS_LIST_TYPED_DATA(V)
Definition: class_id.h:137
void RunWithLockedWeakPersistentHandles(std::function< void(FinalizablePersistentHandles &)> fun)
void RunWithLockedPersistentHandles(std::function< void(PersistentHandles &)> fun)
static ObjectPtr UnwrapHandle(Dart_Handle object)
static intptr_t element_offset(intptr_t index)
Definition: object.h:10838
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.h:10959
static constexpr intptr_t kBytesPerElement
Definition: object.h:10923
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition: object.cc:24935
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:10880
void Insert(typename KeyValueTrait::Pair kv)
Definition: hash_map.h:230
void Add(const T &value)
intptr_t length() const
const T & At(intptr_t index) const
BoolParameter(const char *name, bool required)
Definition: service.cc:704
static bool Parse(const char *value, bool default_value=false)
Definition: service.cc:714
virtual bool Validate(const char *value) const
Definition: service.cc:707
static const Bool & False()
Definition: object.h:10799
static const Bool & True()
Definition: object.h:10797
intptr_t id() const
Definition: debugger.h:60
void PrintJSON(JSONStream *stream)
Definition: debugger.cc:191
static const char * Id()
ClassPtr At(intptr_t cid) const
Definition: class_table.h:362
bool IsValidIndex(intptr_t cid) const
Definition: class_table.h:379
bool CollectInstancesFor(intptr_t cid)
Definition: class_table.h:418
bool HasValidClassAt(intptr_t cid) const
Definition: class_table.h:386
LibraryPtr library() const
Definition: object.h:1333
FunctionPtr InvocationDispatcherFunctionFromIndex(intptr_t idx) const
Definition: object.cc:3419
ObjectPtr Invoke(const String &selector, const Array &arguments, const Array &argument_names, bool respect_reflectable=true, bool check_is_entrypoint=false) const
Definition: object.cc:4684
StringPtr ScrubbedName() const
Definition: object.cc:2981
GrowableObjectArrayPtr direct_implementors_unsafe() const
Definition: object.h:1525
intptr_t id() const
Definition: object.h:1233
void SetTraceAllocation(bool trace_allocation) const
Definition: object.cc:4443
ArrayPtr OffsetToFieldMap(ClassTable *class_table=nullptr) const
Definition: object.cc:3183
TypePtr DeclarationType() const
Definition: object.cc:5827
GrowableObjectArrayPtr direct_subclasses_unsafe() const
Definition: object.h:1542
FieldPtr LookupField(const String &name) const
Definition: object.cc:6352
StringPtr UserVisibleName() const
Definition: object.cc:2989
bool IsTopLevel() const
Definition: object.cc:6121
FunctionPtr ImplicitClosureFunctionFromIndex(intptr_t idx) const
Definition: object.cc:3354
intptr_t NumTypeParameters(Thread *thread) const
Definition: object.cc:3555
ClassPtr Mixin() const
Definition: object.cc:3020
static FunctionPtr ClosureFunctionFromIndex(intptr_t idx)
static CodePtr FindCode(uword pc, int64_t timestamp)
Definition: object.cc:18188
static intptr_t variable_offset(intptr_t context_index)
Definition: object.h:7439
static constexpr intptr_t kBytesPerElement
Definition: object.h:7431
static ObjectPtr LookupOpenPorts()
Definition: dart_entry.cc:679
virtual bool ValidateObject(const Object &value) const
Definition: service.cc:697
DartListParameter(const char *name, bool required)
Definition: service.cc:694
DartStringParameter(const char *name, bool required)
Definition: service.cc:684
virtual bool ValidateObject(const Object &value) const
Definition: service.cc:687
static Dart_FileWriteCallback file_write_callback()
Definition: dart.h:125
static Dart_FileOpenCallback file_open_callback()
Definition: dart.h:119
static int64_t UptimeMillis()
Definition: dart.h:76
static char * FeaturesString(IsolateGroup *isolate_group, bool is_vm_snapshot, Snapshot::Kind kind)
Definition: dart.cc:1004
static Dart_FileCloseCallback file_close_callback()
Definition: dart.h:128
intptr_t Length() const
Definition: debugger.h:465
ActivationFrame * FrameAt(int i) const
Definition: debugger.h:467
Breakpoint * SetBreakpointAtEntry(const Function &target_function, bool single_shot)
Definition: debugger.cc:2722
bool SetBreakpointState(Breakpoint *bpt, bool enable)
Definition: debugger.cc:3950
Breakpoint * SetBreakpointAtActivation(const Instance &closure, bool single_shot)
Definition: debugger.cc:2743
bool SetResumeAction(ResumeAction action, intptr_t frame_index=1, const char **error=nullptr)
Definition: debugger.cc:1486
void RemoveBreakpoint(intptr_t bp_id)
Definition: debugger.cc:3967
DebuggerStackTrace * StackTrace()
Definition: debugger.cc:1797
DebuggerStackTrace * AsyncAwaiterStackTrace()
Definition: debugger.cc:1802
const ServiceEvent * PauseEvent() const
Definition: debugger.h:733
void SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info)
Definition: debugger.cc:1860
Breakpoint * GetBreakpointById(intptr_t id)
Definition: debugger.cc:4141
@ kStepOverAsyncSuspension
Definition: debugger.h:667
Breakpoint * SetBreakpointAtLineCol(const String &script_url, intptr_t line_number, intptr_t column_number)
Definition: debugger.cc:2824
void EnterSingleStepMode()
Definition: debugger.cc:3102
void * user_data() const
Definition: service.cc:1342
void set_callback(Dart_ServiceRequestCallback callback)
Definition: service.cc:1338
const char * name() const
Definition: service.cc:1335
EmbedderServiceHandler(const char *name)
Definition: service.cc:1324
Dart_ServiceRequestCallback callback() const
Definition: service.cc:1337
void set_next(EmbedderServiceHandler *next)
Definition: service.cc:1346
EmbedderServiceHandler * next() const
Definition: service.cc:1345
void set_user_data(void *user_data)
Definition: service.cc:1343
EnumListParameter(const char *name, bool required, const char *const *enums)
Definition: service.cc:187
virtual bool Validate(const char *value) const
Definition: service.cc:190
const char ** Parse(char *value) const
Definition: service.cc:194
EnumParameter(const char *name, bool required, const char *const *enums)
Definition: service.cc:843
virtual bool Validate(const char *value) const
Definition: service.cc:846
virtual const char * ToErrorCString() const
Definition: object.cc:19780
static DART_NORETURN void PropagateError(const Error &error)
Definition: exceptions.cc:1003
static ExternalTypedDataPtr NewFinalizeWithFree(uint8_t *data, intptr_t len)
Definition: object.cc:25649
StringPtr name() const
Definition: object.h:4430
Dart_HandleFinalizer callback() const
void VisitHandles(HandleVisitor *visitor)
static bool SetFlag(const char *name, const char *value, const char **error)
static void PrintJSON(JSONStream *js)
static Flag * Lookup(const char *name)
virtual Direction VisitObject(ObjectGraph::StackIterator *it)
Definition: service.cc:3509
GetInstancesVisitor(ZoneGrowableHandlePtrArray< Object > *storage, intptr_t limit)
Definition: service.cc:3502
intptr_t count() const
Definition: service.cc:3523
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition: object.cc:24991
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
intptr_t Length() const
Definition: object.h:11072
ObjectPtr At(intptr_t index) const
Definition: object.h:11085
Thread * thread() const
bool UpdateOrInsert(const Object &key, const Object &value) const
Definition: hash_table.h:713
StorageTraits::ArrayHandle & Release()
Definition: hash_table.h:195
intptr_t NumOccupied() const
Definition: hash_table.h:380
intptr_t NumEntries() const
Definition: hash_table.h:374
static ArrayPtr ToArray(const Table &table, bool include_payload)
Definition: hash_table.h:653
@ kNew
Definition: heap.h:38
@ kOld
Definition: heap.h:39
Scavenger * new_space()
Definition: heap.h:62
PageSpace * old_space()
Definition: heap.h:63
void CollectAllGarbage(GCReason reason=GCReason::kFull, bool compact=false)
Definition: heap.cc:573
void CollectGarbage(Thread *thread, GCType type, GCReason reason)
Definition: heap.cc:558
static const char * hardware()
Definition: cpu_arm.h:30
virtual bool Validate(const char *value) const
Definition: service.cc:811
IdParameter(const char *name, bool required)
Definition: service.cc:808
static int64_t Parse(const char *value, int64_t default_value=-1)
Definition: service.cc:767
virtual bool Validate(const char *value) const
Definition: service.cc:755
Int64Parameter(const char *name, bool required)
Definition: service.cc:752
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:22984
Heap * heap() const
Definition: isolate.h:296
ObjectStore * object_store() const
Definition: isolate.h:510
static IsolateGroup * Current()
Definition: isolate.h:539
Dart_LibraryTagHandler library_tag_handler() const
Definition: isolate.h:555
ClassTable * class_table() const
Definition: isolate.h:496
bool is_system_isolate_group() const
Definition: isolate.h:413
ApiState * api_state() const
Definition: isolate.h:700
IsolateGroupSource * source() const
Definition: isolate.h:286
bool ReloadSources(JSONStream *js, bool force_reload, const char *root_script_url=nullptr, const char *packages_url=nullptr, bool dont_delete_reload_context=false)
Definition: isolate.cc:2073
void PrintJSON(JSONStream *stream, bool ref=true)
Definition: isolate.cc:643
static void RunWithIsolateGroup(uint64_t id, std::function< void(IsolateGroup *)> action, std::function< void()> not_found)
Definition: isolate.cc:690
bool IsReloading() const
Definition: isolate.h:669
void UpdateLastAllocationProfileAccumulatorResetTimestamp()
Definition: isolate.h:346
bool is_vm_isolate() const
Definition: isolate.h:290
static void ForEach(std::function< void(IsolateGroup *)> action)
Definition: isolate.cc:683
void PrintMemoryUsageJSON(JSONStream *stream)
Definition: isolate.cc:668
void PrintToJSONObject(JSONObject *jsobj)
Definition: object_store.cc:33
bool IsSystemIsolate(Isolate *isolate) const
Definition: isolate.cc:752
void set_should_pause_post_service_request(bool value)
Definition: isolate.h:1320
ErrorPtr sticky_error() const
Definition: isolate.h:1357
void SetResumeRequest()
Definition: isolate.h:1150
static Isolate * Current()
Definition: isolate.h:986
IsolateObjectStore * isolate_object_store() const
Definition: isolate.h:1007
VMTagCounters * vm_tag_counters()
Definition: isolate.h:1311
static void VisitIsolates(IsolateVisitor *visitor)
Definition: isolate.cc:3531
Debugger * debugger() const
Definition: isolate.h:1108
void PrintJSON(JSONStream *stream, bool ref=true)
Definition: isolate.cc:3084
MessageHandler * message_handler() const
Definition: isolate.cc:2416
void PrintPauseEventJSON(JSONStream *stream)
Definition: isolate.cc:3212
bool is_vm_isolate() const
Definition: isolate.h:1380
void PrintMemoryUsageJSON(JSONStream *stream)
Definition: isolate.cc:3208
void SendInternalLibMessage(LibMsgId msg_id, uint64_t capability)
Definition: isolate.cc:1033
ObjectIdRing * EnsureObjectIdRing()
Definition: isolate.cc:3014
ErrorPtr PausePostRequest()
Definition: isolate.cc:2013
bool should_pause_post_service_request() const
Definition: isolate.h:1317
IsolateGroup * group() const
Definition: isolate.h:1037
bool is_service_registered() const
Definition: isolate.h:1385
void set_name(const char *name)
Definition: isolate.cc:1977
uint64_t pause_capability() const
Definition: isolate.h:1056
bool IsPaused() const
Definition: isolate.cc:2005
bool is_runnable() const
Definition: isolate.h:1095
void AddValueNull() const
Definition: json_stream.h:493
void AddValue(bool b) const
Definition: json_stream.h:494
void AddProperty64(const char *name, int64_t i) const
Definition: json_stream.h:401
void AddProperty(const char *name, bool b) const
Definition: json_stream.h:395
void AddPropertyBase64(const char *name, const uint8_t *bytes, intptr_t length) const
Definition: json_stream.h:413
void AddPropertyTimeMicros(const char *name, int64_t micros) const
Definition: json_stream.h:407
void AddPropertyTimeMillis(const char *name, int64_t millis) const
Definition: json_stream.h:404
void AddPropertyF(const char *name, const char *format,...) const PRINTF_ATTRIBUTE(3
Definition: json_stream.cc:589
static bool IsRunning()
static Dart_KernelCompilationResult CompileExpressionToKernel(const uint8_t *platform_kernel, intptr_t platform_kernel_size, const char *expression, const Array &definitions, const Array &definition_types, const Array &type_definitions, const Array &type_bounds, const Array &type_defaults, const char *library_url, const char *klass, const char *method, TokenPosition token_pos, char const *script_uri, bool is_static)
ArrayPtr LoadedScripts() const
Definition: object.cc:13940
ObjectPtr Invoke(const String &selector, const Array &arguments, const Array &argument_names, bool respect_reflectable=true, bool check_is_entrypoint=false) const
Definition: object.cc:14473
ClassPtr toplevel_class() const
Definition: object.h:5208
void set_debuggable(bool value) const
Definition: object.h:5284
StringPtr private_key() const
Definition: object.h:5099
StringPtr url() const
Definition: object.h:5097
ObjectPtr CurrentValue() const
Definition: object.h:12155
ObjectPtr CurrentKey() const
Definition: object.h:12153
bool is_paused_on_start() const
void set_should_pause_on_start(bool should_pause_on_start)
void set_should_pause_on_exit(bool should_pause_on_exit)
bool is_paused_on_exit() const
bool should_pause_on_start() const
Message * FindMessageById(intptr_t id)
Definition: message.cc:201
@ kNormalPriority
Definition: message.h:28
const char * name() const
Definition: service.cc:147
virtual bool ValidateObject(const Object &value) const
Definition: service.cc:145
virtual bool Validate(const char *value) const
Definition: service.cc:143
virtual void PrintError(const char *name, const char *value, JSONStream *js) const
Definition: service.cc:151
MethodParameter(const char *name, bool required)
Definition: service.cc:138
bool required() const
Definition: service.cc:149
virtual void PrintErrorObject(const char *name, const Object &value, JSONStream *js) const
Definition: service.cc:157
virtual ~MethodParameter()
Definition: service.cc:141
static const char * LookupSymbolName(uword pc, uword *start)
static void FreeSymbolName(const char *name)
virtual bool ValidateObject(const Object &value) const
Definition: service.cc:174
virtual bool Validate(const char *value) const
Definition: service.cc:172
NoSuchParameter(const char *name)
Definition: service.cc:170
static const char * Name()
Definition: os.h:22
static int64_t GetCurrentTimeMillis()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static intptr_t ProcessId()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
ObjectPtr GetObjectForId(int32_t id, LookupResult *kind)
int32_t GetIdForObject(ObjectPtr raw_obj, IdPolicy policy=kAllocateId)
intptr_t GetClassId() const
Definition: raw_object.h:885
bool IsPseudoObject() const
void PrintToJSONObject(JSONObject *jsobj)
void PrintJSON(JSONStream *stream, bool ref=true) const
static ObjectPtr null()
Definition: object.h:433
intptr_t GetClassId() const
Definition: object.h:341
ObjectPtr ptr() const
Definition: object.h:332
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
void PrintImplementationFields(JSONStream *stream) const
ClassPtr clazz() const
Definition: object.h:13218
const char * FieldNameForOffset(intptr_t cid, intptr_t offset)
intptr_t UsedInWords() const
Definition: pages.h:194
intptr_t CapacityInWords() const
Definition: pages.h:195
static intptr_t CachedSize()
Definition: page.cc:51
void VisitHandle(uword addr) override
Definition: service.cc:4937
PersistentHandleVisitor(Thread *thread, JSONArray *handles)
Definition: service.cc:4898
void Append(FinalizablePersistentHandle *weak_persistent_handle)
Definition: service.cc:4910
void Append(PersistentHandle *persistent_handle)
Definition: service.cc:4903
ObjectPtr ptr() const
void Visit(HandleVisitor *visitor)
static bool PostMessage(std::unique_ptr< Message > message, bool before_events=false)
Definition: port.cc:152
static void PrintPortsForMessageHandler(MessageHandler *handler, JSONStream *stream)
Definition: port.cc:280
static void PrintAllocationJSON(JSONStream *stream, const Class &cls, int64_t time_origin_micros, int64_t time_extent_micros)
static void PrintJSON(JSONStream *stream, int64_t time_origin_micros, int64_t time_extent_micros, bool include_code_samples)
static intptr_t Size()
Definition: profiler.h:787
static void UpdateRunningState()
Definition: profiler.cc:617
static void Init()
Definition: profiler.cc:573
static void UpdateSamplePeriod()
Definition: profiler.cc:666
ArrayPtr GetFieldNames(Thread *thread) const
Definition: object.h:11493
static constexpr intptr_t kBytesPerElement
Definition: object.h:11440
intptr_t num_fields() const
Definition: object.h:11425
static intptr_t field_offset(intptr_t index)
Definition: object.h:11448
static FunctionPtr ResolveFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition: resolver.cc:167
virtual ~RingServiceIdZone()
Definition: service.cc:372
ObjectIdRing::IdPolicy policy() const
Definition: service.h:65
void Init(ObjectIdRing *ring, ObjectIdRing::IdPolicy policy)
Definition: service.cc:374
virtual char * GetServiceId(const Object &obj)
Definition: service.cc:380
RunnableIsolateParameter(const char *name)
Definition: service.cc:824
virtual bool Validate(const char *value) const
Definition: service.cc:827
virtual void PrintError(const char *name, const char *value, JSONStream *js) const
Definition: service.cc:833
intptr_t CapacityInWords() const
Definition: scavenger.h:164
@ kTimelineStreamSubscriptionsUpdate
Definition: service_event.h:62
virtual ~ServiceIdZone()
Definition: service.cc:367
ServiceIsolateVisitor(JSONArray *jsarr)
Definition: service.cc:5219
void VisitIsolate(Isolate *isolate)
Definition: service.cc:5222
virtual ~ServiceIsolateVisitor()
Definition: service.cc:5220
static Dart_Port Port()
static const char * server_address()
static StreamInfo isolate_stream
Definition: service.h:180
static void SendEmbedderEvent(Isolate *isolate, const char *stream_id, const char *event_kind, const uint8_t *bytes, intptr_t bytes_len)
Definition: service.cc:4838
static void LogResponseSize(const char *method, JSONStream *js)
Definition: service.cc:86
static ErrorPtr HandleRootMessage(const Array &message)
Definition: service.cc:1059
static StreamInfo timeline_stream
Definition: service.h:187
static void CancelStream(const char *stream_id)
Definition: service.cc:448
static void HandleEvent(ServiceEvent *event, bool enter_safepoint=true)
Definition: service.cc:1206
static bool ListenStream(const char *stream_id, bool include_privates)
Definition: service.cc:427
static StreamInfo debug_stream
Definition: service.h:181
static void SendEchoEvent(Isolate *isolate, const char *text)
Definition: service.cc:1744
static const uint8_t * dart_library_kernel()
Definition: service.h:216
static void SetGetServiceAssetsCallback(Dart_GetVMServiceAssetsArchive get_service_assets)
Definition: service.cc:1441
static bool HasDartLibraryKernelForSources()
Definition: service.h:212
static void SetDartLibraryKernelForSources(const uint8_t *kernel_bytes, intptr_t kernel_length)
Definition: service.cc:1481
static void SendExtensionEvent(Isolate *isolate, const String &event_kind, const String &event_data)
Definition: service.cc:4876
static void SetEmbedderStreamCallbacks(Dart_ServiceStreamListenCallback listen_callback, Dart_ServiceStreamCancelCallback cancel_callback)
Definition: service.cc:1434
static ErrorPtr HandleIsolateMessage(Isolate *isolate, const Array &message)
Definition: service.cc:1069
static ObjectPtr RequestAssets()
Definition: service.cc:466
static void RegisterRootEmbedderCallback(const char *name, Dart_ServiceRequestCallback callback, void *user_data)
Definition: service.cc:1411
static void SendInspectEvent(Isolate *isolate, const Object &inspectee)
Definition: service.cc:4829
static StreamInfo vm_stream
Definition: service.h:179
static void Init()
Definition: service.cc:97
static void RegisterIsolateEmbedderCallback(const char *name, Dart_ServiceRequestCallback callback, void *user_data)
Definition: service.cc:1376
static void PostError(const String &method_name, const Array &parameter_keys, const Array &parameter_values, const Instance &reply_port, const Instance &id, const Error &error)
Definition: service.cc:937
static StreamInfo echo_stream
Definition: service.h:183
static StreamInfo logging_stream
Definition: service.h:185
static ErrorPtr HandleObjectRootMessage(const Array &message)
Definition: service.cc:1064
static int64_t CurrentRSS()
Definition: service.cc:1451
static StreamInfo profiler_stream
Definition: service.h:188
static void SendLogEvent(Isolate *isolate, int64_t sequence_number, int64_t timestamp, intptr_t level, const String &name, const String &message, const Instance &zone, const Object &error, const Instance &stack_trace)
Definition: service.cc:4850
static void CheckForPause(Isolate *isolate, JSONStream *stream)
Definition: service.cc:3880
static StreamInfo gc_stream
Definition: service.h:182
static void SendEventWithData(const char *stream_id, const char *event_type, intptr_t reservation, const char *metadata, intptr_t metadata_size, uint8_t *data, intptr_t data_size)
Definition: service.cc:1134
static void PrintJSONForEmbedderInformation(JSONObject *jsobj)
Definition: service.cc:5252
static StreamInfo extension_stream
Definition: service.h:186
static void SetEmbedderInformationCallback(Dart_EmbedderInformationCallback callback)
Definition: service.cc:1446
static int64_t MaxRSS()
Definition: service.cc:1466
static bool EnableTimelineStreams(char *categories_list)
static StreamInfo heapsnapshot_stream
Definition: service.h:184
static void Cleanup()
Definition: service.cc:119
static intptr_t dart_library_kernel_length()
Definition: service.h:218
static void PrintJSONForVM(JSONStream *js, bool ref)
Definition: service.cc:5274
static SmiPtr New(intptr_t value)
Definition: object.h:10006
intptr_t Value() const
Definition: object.h:9990
static bool IsValid(int64_t value)
Definition: object.h:10026
void PrintJSON(JSONStream *js, const Script &script, TokenPosition start_pos=TokenPosition::kMinSource, TokenPosition end_pos=TokenPosition::kMaxSource)
static const char * kPossibleBreakpointsStr
Definition: source_report.h:35
static const char * kCallSitesStr
Definition: source_report.h:33
static const char * kCoverageStr
Definition: source_report.h:34
static const char * kBranchCoverageStr
Definition: source_report.h:37
static const char * kProfileStr
Definition: source_report.h:36
Zone * GetZone()
Definition: zone.h:213
void set_enabled(bool value)
Definition: service.h:79
const char * id() const
Definition: service.h:77
void set_include_private_members(bool value)
Definition: service.h:82
virtual bool Validate(const char *value) const
Definition: service.cc:819
StringParameter(const char *name, bool required)
Definition: service.cc:816
static StringPtr ToLowerCase(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:24202
bool HasHash() const
Definition: object.h:10229
bool Equals(const String &str) const
Definition: object.h:13337
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static StringPtr SubString(const String &str, intptr_t begin_index, Heap::Space space=Heap::kNew)
Definition: object.cc:24080
static StringPtr DecodeIRI(const String &str)
Definition: object.cc:23948
static const char * ToCString(Thread *thread, StringPtr ptr)
Definition: object.cc:24126
static StringPtr FromUTF8(const uint8_t *utf8_array, intptr_t array_len, Heap::Space space=Heap::kNew)
Definition: object.cc:23705
SystemServiceIsolateVisitor(JSONArray *jsarr)
Definition: service.cc:5234
void VisitIsolate(Isolate *isolate)
Definition: service.cc:5237
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
void set_sticky_error(const Error &value)
Definition: thread.cc:236
Isolate * isolate() const
Definition: thread.h:534
IsolateGroup * isolate_group() const
Definition: thread.h:541
ErrorPtr sticky_error() const
Definition: thread.cc:232
static TokenPosition Deserialize(int32_t value)
intptr_t Length() const
Definition: object.cc:7294
bool HasInstantiations() const
Definition: object.cc:7269
AbstractTypePtr TypeAt(intptr_t index) const
Definition: object.cc:7308
static TypePtr DynamicType()
intptr_t ElementSizeInBytes() const
Definition: object.h:11531
UInt64Parameter(const char *name, bool required)
Definition: service.cc:780
virtual bool Validate(const char *value) const
Definition: service.cc:783
static uint64_t Parse(const char *value, uint64_t default_value=0)
Definition: service.cc:795
virtual bool Validate(const char *value) const
Definition: service.cc:727
static uintptr_t Parse(const char *value)
Definition: service.cc:739
UIntParameter(const char *name, bool required)
Definition: service.cc:724
static UnwindErrorPtr New(const String &message, Heap::Space space=Heap::kNew)
Definition: object.cc:20005
static bool ReportStats()
Definition: service.cc:5344
static uword Hash(const Object &key)
Definition: service.cc:5354
static const char * Name()
Definition: service.cc:5343
static ObjectPtr NewKey(const String &str)
Definition: service.cc:5356
static bool IsMatch(const Object &a, const Object &b)
Definition: service.cc:5346
static char * StrDup(const char *s)
static T Minimum(T x, T y)
Definition: utils.h:36
void PrintToJSONObject(JSONObject *obj)
Definition: tags.cc:123
static const char * String()
ObjectPtr key() const
Definition: object.h:12920
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition: zone.cc:313
static intptr_t Size()
Definition: zone.h:94
char * MakeCopyOfStringN(const char *str, intptr_t len)
Definition: zone.cc:277
char * MakeCopyOfString(const char *str)
Definition: zone.cc:270
#define DEFINE_NAME(Name)
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
Definition: dart_api.h:807
@ Dart_KernelCompilationStatus_Ok
Definition: dart_api.h:3785
#define ILLEGAL_PORT
Definition: dart_api.h:1535
void(* Dart_FileCloseCallback)(void *stream)
Definition: dart_api.h:820
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
@ Dart_TypedData_kUint8
Definition: dart_api.h:2615
void *(* Dart_FileOpenCallback)(const char *name, bool write)
Definition: dart_api.h:776
Dart_Handle(* Dart_GetVMServiceAssetsArchive)(void)
Definition: dart_api.h:834
@ Dart_CObject_kString
@ Dart_CObject_kArray
@ Dart_CObject_kExternalTypedData
bool(* Dart_ServiceStreamListenCallback)(const char *stream_id)
#define DART_EMBEDDER_INFORMATION_CURRENT_VERSION
bool(* Dart_ServiceRequestCallback)(const char *method, const char **param_keys, const char **param_values, intptr_t num_params, void *user_data, const char **json_object)
void(* Dart_ServiceStreamCancelCallback)(const char *stream_id)
void(* Dart_EmbedderInformationCallback)(Dart_EmbedderInformation *info)
#define UNIMPLEMENTED
const EmbeddedViewParams * params
#define ASSERT(E)
VkInstance instance
Definition: main.cc:48
SkBitmap source
Definition: examples.cpp:28
double frame
Definition: examples.cpp:31
static bool b
struct MyStruct s
struct MyStruct a[10]
#define FATAL(error)
if(end==-1)
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
uint32_t * target
const char * charp
Definition: flags.h:12
Dart_NativeFunction function
Definition: fuchsia.cc:51
#define HANDLESCOPE(thread)
Definition: handles.h:321
size_t length
std::u16string text
Win32Message message
#define ISOLATE_METRIC_LIST(V)
Definition: metrics.h:49
#define ISOLATE_GROUP_METRIC_LIST(V)
Definition: metrics.h:37
Visitor(Ts...) -> Visitor< Ts... >
Definition: dart_vm.cc:33
static const MethodParameter *const get_allocation_profile_params[]
Definition: service.cc:4541
static void ActOnIsolateGroup(JSONStream *js, std::function< void(IsolateGroup *)> visitor)
Definition: service.cc:1582
static const MethodParameter *const get_ports_private_params[]
Definition: service.cc:4978
static const MethodParameter *const set_trace_class_allocation_params[]
Definition: service.cc:5739
static void TriggerEchoEvent(Thread *thread, JSONStream *js)
Definition: service.cc:1777
static void GetIsolateMetricList(Thread *thread, JSONStream *js)
Definition: service.cc:4110
static void LookupResolvedPackageUris(Thread *thread, JSONStream *js)
Definition: service.cc:5472
const ServiceMethodDescriptor * FindMethod(const char *method_name)
Definition: service.cc:6006
ObjectPtr ReadMessage(Thread *thread, Message *message)
static const MethodParameter *const get_source_report_params[]
Definition: service.cc:3718
static const char *const names[]
Definition: symbols.cc:24
static void AddBreakpointWithScriptUri(Thread *thread, JSONStream *js)
Definition: service.cc:3968
static bool BuildScope(Thread *thread, JSONStream *js, const GrowableObjectArray &names, const GrowableObjectArray &values)
Definition: service.cc:2830
static void GetSourceReport(Thread *thread, JSONStream *js)
Definition: service.cc:3730
const char *const name
static void GetIsolateObjectStore(Thread *thread, JSONStream *js)
Definition: service.cc:5149
static const MethodParameter *const get_object_store_params[]
Definition: service.cc:5134
static constexpr intptr_t kCompressedWordSizeLog2
Definition: globals.h:43
static void Evaluate(Thread *thread, JSONStream *js)
Definition: service.cc:2872
static const MethodParameter *const clear_vm_timeline_params[]
Definition: service.cc:4285
static const MethodParameter *const get_type_arguments_list_params[]
Definition: service.cc:5165
static void SetBreakpointState(Thread *thread, JSONStream *js)
Definition: service.cc:5571
const intptr_t kSmiMax
Definition: globals.h:28
static const MethodParameter *const get_isolate_metric_params[]
Definition: service.cc:4123
static void HandleNativeMetric(Thread *thread, JSONStream *js, const char *id)
Definition: service.cc:4083
constexpr intptr_t kBitsPerWord
Definition: globals.h:514
static void GetTypeArgumentsList(Thread *thread, JSONStream *js)
Definition: service.cc:5170
static void RespondWithMalformedObject(Thread *thread, JSONStream *js)
Definition: service.cc:4999
static const MethodParameter *const pause_params[]
Definition: service.cc:4409
static void SetLibraryDebuggable(Thread *thread, JSONStream *js)
Definition: service.cc:5688
static StreamInfo *const streams_[]
Definition: service.cc:419
static void ReloadSources(Thread *thread, JSONStream *js)
Definition: service.cc:3840
static void HandleNativeMetricsList(Thread *thread, JSONStream *js)
Definition: service.cc:4063
static const MethodParameter *const set_library_debuggable_params[]
Definition: service.cc:5681
static void LookupPackageUris(Thread *thread, JSONStream *js)
Definition: service.cc:5481
static void GetImplementationFields(Thread *thread, JSONStream *js)
Definition: service.cc:5102
static const MethodParameter *const get_implementation_fields_params[]
Definition: service.cc:5096
static const MethodParameter *const get_vm_timeline_params[]
Definition: service.cc:4300
static void GetObjectStore(Thread *thread, JSONStream *js)
Definition: service.cc:5139
static void PrintSentinel(JSONStream *js, SentinelType sentinel_type)
Definition: service.cc:1535
static bool CheckProfilerDisabled(Thread *thread, JSONStream *js)
Definition: service.cc:525
static void GetClassList(Thread *thread, JSONStream *js)
Definition: service.cc:5159
static const MethodParameter *const add_breakpoint_at_entry_params[]
Definition: service.cc:3978
static void GetIsolateGroupMemoryUsage(Thread *thread, JSONStream *js)
Definition: service.cc:1621
static const MethodParameter *const get_scripts_params[]
Definition: service.cc:1636
static bool GetUnsignedIntegerId(const char *s, uintptr_t *id, int base=10)
Definition: service.cc:557
static const MethodParameter *const lookup_resolved_package_uris_params[]
Definition: service.cc:5467
DART_EXPORT bool IsNull(Dart_Handle object)
static void SetStreamIncludePrivateMembers(Thread *thread, JSONStream *js)
Definition: service.cc:1564
static const MethodParameter *const add_breakpoint_at_activation_params[]
Definition: service.cc:4007
static const MethodParameter *const build_expression_evaluation_scope_params[]
Definition: service.cc:2881
static const MethodParameter *const compile_expression_params[]
Definition: service.cc:3197
static const MethodParameter *const get_isolate_object_store_params[]
Definition: service.cc:5144
static const MethodParameter *const collect_all_garbage_params[]
Definition: service.cc:4554
void * malloc(size_t size)
Definition: allocation.cc:19
static const MethodParameter *const get_stack_params[]
Definition: service.cc:1670
T EnumMapper(const char *value, const char *const *enums, T *values)
Definition: service.cc:865
static void GetIsolate(Thread *thread, JSONStream *js)
Definition: service.cc:1520
static const MethodParameter *const get_retaining_path_params[]
Definition: service.cc:2505
static const MethodParameter *const get_instances_as_list_params[]
Definition: service.cc:3581
static void GetMemoryUsage(Thread *thread, JSONStream *js)
Definition: service.cc:1612
static void RemoveBreakpoint(Thread *thread, JSONStream *js)
Definition: service.cc:4040
static void ClearCpuSamples(Thread *thread, JSONStream *js)
Definition: service.cc:4504
static ObjectPtr LookupHeapObjectMessage(Thread *thread, char **parts, int num_parts)
Definition: service.cc:2154
DART_EXPORT void Dart_PropagateError(Dart_Handle handle)
static const MethodParameter *const get_flag_list_params[]
Definition: service.cc:5593
static const MethodParameter *const invoke_params[]
Definition: service.cc:2624
static const MethodParameter *const get_tag_profile_params[]
Definition: service.cc:4437
static void PrintInboundReferences(Thread *thread, Object *target, intptr_t limit, JSONStream *js)
Definition: service.cc:2285
static void GetHeapMap(Thread *thread, JSONStream *js)
Definition: service.cc:4570
static void AddBreakpoint(Thread *thread, JSONStream *js)
Definition: service.cc:3942
static const MethodParameter *const enable_profiler_params[]
Definition: service.cc:4425
void(* ServiceMethodEntry)(Thread *thread, JSONStream *js)
Definition: service.cc:877
ObjectPtr Invoke(const Library &lib, const char *name)
static void GetStack(Thread *thread, JSONStream *js)
Definition: service.cc:1676
static bool GetInteger64Id(const char *s, int64_t *id, int base=10)
Definition: service.cc:581
static void SetTraceClassAllocation(Thread *thread, JSONStream *js)
Definition: service.cc:5746
static bool ParseCSVList(const char *csv_list, const GrowableObjectArray &values)
Definition: service.cc:3162
static const MethodParameter *const get_isolate_pause_event_params[]
Definition: service.cc:1627
static void GetInboundReferences(Thread *thread, JSONStream *js)
Definition: service.cc:2368
static intptr_t ParseJSONSet(Thread *thread, const char *str, ZoneCStringSet *elements)
Definition: service.cc:3674
static ObjectPtr LookupHeapObjectCode(char **parts, int num_parts)
Definition: service.cc:2108
static void GetIsolatePauseEvent(Thread *thread, JSONStream *js)
Definition: service.cc:1632
static void SetVMName(Thread *thread, JSONStream *js)
Definition: service.cc:5727
static ObjectPtr LookupHeapObjectLibraries(IsolateGroup *isolate_group, char **parts, int num_parts)
Definition: service.cc:1938
constexpr intptr_t KB
Definition: globals.h:528
static Dart_ExceptionPauseInfo exception_pause_mode_values[]
Definition: service.cc:5492
static intptr_t GetProcessMemoryUsageHelper(JSONStream *js)
Definition: service.cc:4705
uintptr_t uword
Definition: globals.h:501
static const MethodParameter *const get_inbound_references_params[]
Definition: service.cc:2363
static const MethodParameter *const clear_cpu_samples_params[]
Definition: service.cc:4499
static bool GetCodeId(const char *s, int64_t *timestamp, uword *address)
Definition: service.cc:617
static const MethodParameter *const evaluate_in_frame_params[]
Definition: service.cc:3433
static const MethodParameter *const get_process_memory_usage_params[]
Definition: service.cc:4821
static void GetVersion(Thread *thread, JSONStream *js)
Definition: service.cc:5206
static const MethodParameter *const get_class_list_params[]
Definition: service.cc:5154
static const MethodParameter *const get_vm_params[]
Definition: service.cc:5247
static intptr_t ParseJSONCollection(Thread *thread, const char *str, const Adder &add)
Definition: service.cc:3629
static void HandleCommonEcho(JSONObject *jsobj, JSONStream *js)
Definition: service.cc:1737
static bool ValidateParameters(const MethodParameter *const *parameters, JSONStream *js)
Definition: service.cc:895
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
static const MethodParameter *const set_flags_params[]
Definition: service.cc:5602
const uint32_t fp
static const Debugger::ResumeAction step_enum_values[]
Definition: service.cc:4315
static const ServiceMethodDescriptor service_methods_[]
Definition: service.cc:5847
static bool GetHeapObjectCommon(Thread *thread, JSONStream *js, const char *id, Object *obj, ObjectIdRing::LookupResult *lookup_result)
Definition: service.cc:5009
static void ReportPauseOnConsole(ServiceEvent *event)
Definition: service.cc:1152
static void CompileExpression(Thread *thread, JSONStream *js)
Definition: service.cc:3216
static const MethodParameter *const reload_sources_params[]
Definition: service.cc:3831
static const MethodParameter *const request_heap_snapshot_params[]
Definition: service.cc:4590
static void PopulateUriMappings(Thread *thread)
Definition: service.cc:5361
static void BuildExpressionEvaluationScope(Thread *thread, JSONStream *js)
Definition: service.cc:2955
static const MethodParameter *const evaluate_params[]
Definition: service.cc:2757
TimelineOrSamplesResponseFormat
Definition: service.cc:4146
@ JSON
Definition: service.cc:4146
@ Perfetto
Definition: service.cc:4146
static const MethodParameter *const get_persistent_handles_params[]
Definition: service.cc:4890
static void GetTagProfile(Thread *thread, JSONStream *js)
Definition: service.cc:4442
static void Pause(Thread *thread, JSONStream *js)
Definition: service.cc:4414
static const MethodParameter *const get_isolate_group_memory_usage_params[]
Definition: service.cc:1616
static void PrintMissingParamError(JSONStream *js, const char *param)
Definition: service.cc:885
void GetVMTimelineCommon(TimelineOrSamplesResponseFormat format, Thread *thread, JSONStream *js)
Definition: service.cc:4176
UnorderedHashMap< UriMappingTraits > UriMapping
Definition: service.cc:5359
static const MethodParameter *const get_ports_params[]
Definition: service.cc:3685
static const MethodParameter *const set_exception_pause_mode_params[]
Definition: service.cc:5499
static bool IsAlpha(char c)
Definition: service.cc:2762
static void EvaluateInFrame(Thread *thread, JSONStream *js)
Definition: service.cc:3440
static ObjectPtr LookupHeapObject(Thread *thread, const char *id_original, ObjectIdRing::LookupResult *result)
Definition: service.cc:2177
static void AddParentFieldToResponseBasedOnRecord(Thread *thread, Array *field_names_handle, String *name_handle, const JSONObject &jsresponse, const Record &record, const intptr_t field_slot_offset)
Definition: service.cc:2265
static char * vm_name
Definition: service.cc:356
static const MethodParameter *const evaluate_compiled_expression_params[]
Definition: service.cc:3299
static bool ParseScope(const char *scope, GrowableArray< const char * > *names, GrowableArray< const char * > *ids)
Definition: service.cc:2783
static void GetVMTimelineMicros(Thread *thread, JSONStream *js)
Definition: service.cc:4279
static void EvaluateCompiledExpression(Thread *thread, JSONStream *js)
Definition: service.cc:3313
static const MethodParameter *const get_memory_usage_params[]
Definition: service.cc:1607
constexpr intptr_t kInt32Size
Definition: globals.h:450
static void Finalizer(void *isolate_callback_data, void *buffer)
Definition: json_stream.cc:192
static const MethodParameter *const get_version_params[]
Definition: service.cc:5201
static const MethodParameter *const set_breakpoint_state_params[]
Definition: service.cc:5564
static ObjectPtr LookupClassMembers(Thread *thread, const Class &klass, char **parts, int num_parts)
Definition: service.cc:1847
static const MethodParameter *const get_heap_map_params[]
Definition: service.cc:4565
constexpr intptr_t kFirstInternalOnlyCid
Definition: class_id.h:288
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
static void GetPortsPrivate(Thread *thread, JSONStream *js)
Definition: service.cc:4983
static void EnableProfiler()
static void GetAllocationProfilePublic(Thread *thread, JSONStream *js)
Definition: service.cc:4546
const intptr_t cid
static void GetDefaultClassesAliases(Thread *thread, JSONStream *js)
Definition: service.cc:5767
static void RespondWithMalformedJson(Thread *thread, JSONStream *js)
Definition: service.cc:4988
static bool IsWhitespace(char c)
Definition: service.cc:2774
static const MethodParameter *const kill_params[]
Definition: service.cc:4395
static void PrintInvalidParamError(JSONStream *js, const char *param)
Definition: service.cc:128
static void Kill(Thread *thread, JSONStream *js)
Definition: service.cc:4400
static bool IsAlphaOrDollar(char c)
Definition: service.cc:2765
static const MethodParameter *const add_breakpoint_params[]
Definition: service.cc:3934
static void Echo(Thread *thread, JSONStream *js)
Definition: service.cc:1785
ExternalTypedDataPtr DecodeKernelBuffer(const char *kernel_buffer_base64)
Definition: service.cc:3307
static const char *const exception_pause_mode_names[]
Definition: service.cc:5485
static void GetReachableSize(Thread *thread, JSONStream *js)
Definition: service.cc:2591
static const char * ScanUntilDash(const char *s)
Definition: service.cc:603
static const MethodParameter *const get_allocation_traces_params[]
Definition: service.cc:4459
static void LookupScriptUrisImpl(Thread *thread, JSONStream *js, bool lookup_resolved)
Definition: service.cc:5407
static void GetIsolateMetric(Thread *thread, JSONStream *js)
Definition: service.cc:4128
static const char * GetVMName()
Definition: service.cc:358
static void AddBreakpointCommon(Thread *thread, JSONStream *js, const String &script_uri)
Definition: service.cc:3902
static void AddBreakpointAtEntry(Thread *thread, JSONStream *js)
Definition: service.cc:3984
static const MethodParameter *const set_stream_include_private_members_params[]
Definition: service.cc:1558
static bool IsValidClassId(Isolate *isolate, intptr_t cid)
Definition: service.cc:667
static const MethodParameter *const get_vm_timeline_micros_params[]
Definition: service.cc:4274
SentinelType
Definition: service.cc:1529
@ kExpiredSentinel
Definition: service.cc:1531
@ kFreeSentinel
Definition: service.cc:1532
@ kCollectedSentinel
Definition: service.cc:1530
constexpr intptr_t kWordSize
Definition: globals.h:509
static void UnmarkClasses()
Definition: service.cc:3493
static void SetIsolatePauseMode(Thread *thread, JSONStream *js)
Definition: service.cc:5533
static void GetCpuSamples(Thread *thread, JSONStream *js)
Definition: service.cc:4455
static const MethodParameter *const get_reachable_size_params[]
Definition: service.cc:2585
static void GetRetainingPath(Thread *thread, JSONStream *js)
Definition: service.cc:2510
static void Resume(Thread *thread, JSONStream *js)
Definition: service.cc:4329
static void SetFlag(Thread *thread, JSONStream *js)
Definition: service.cc:5607
static const MethodParameter *const resume_params[]
Definition: service.cc:4322
std::unique_ptr< Message > WriteApiMessage(Zone *zone, Dart_CObject *obj, Dart_Port dest_port, Message::Priority priority)
static void GetInstancesAsList(Thread *thread, JSONStream *js)
Definition: service.cc:3589
static void GetProcessMemoryUsage(Thread *thread, JSONStream *js)
Definition: service.cc:4825
static void GetVM(Thread *thread, JSONStream *js)
Definition: service.cc:5337
static ClassPtr GetClassForId(Isolate *isolate, intptr_t cid)
Definition: service.cc:674
static void PrintRetainingPath(Thread *thread, Object *obj, intptr_t limit, JSONStream *js)
Definition: service.cc:2404
static ObjectPtr LookupObjectId(Thread *thread, const char *arg, ObjectIdRing::LookupResult *kind)
Definition: service.cc:1816
static void CollectAllGarbage(Thread *thread, JSONStream *js)
Definition: service.cc:4559
static const MethodParameter *const get_instances_params[]
Definition: service.cc:3532
static void GetRetainedSize(Thread *thread, JSONStream *js)
Definition: service.cc:2552
static const MethodParameter *const get_default_classes_aliases_params[]
Definition: service.cc:5762
static void GetVMTimeline(Thread *thread, JSONStream *js)
Definition: service.cc:4307
static void GetPorts(Thread *thread, JSONStream *js)
Definition: service.cc:3690
static bool IsAlphaNumOrDollar(char c)
Definition: service.cc:2771
static void SetExceptionPauseMode(Thread *thread, JSONStream *js)
Definition: service.cc:5505
static bool IsAlphaNum(char c)
Definition: service.cc:2768
static const MethodParameter *const set_name_params[]
Definition: service.cc:5704
static void MarkClasses(const Class &root, bool include_subclasses, bool include_implementors)
Definition: service.cc:3449
static void CollectStringifiedType(Thread *thread, Zone *zone, const AbstractType &type, const GrowableObjectArray &output)
Definition: service.cc:2889
static bool IsObjectIdChar(char c)
Definition: service.cc:2777
static void GetObject(Thread *thread, JSONStream *js)
Definition: service.cc:5046
static void GetAllocationProfileImpl(Thread *thread, JSONStream *js, bool internal)
Definition: service.cc:4509
static const MethodParameter *const get_isolate_params[]
Definition: service.cc:1515
static void GetPersistentHandles(Thread *thread, JSONStream *js)
Definition: service.cc:4945
static const MethodParameter *const lookup_package_uris_params[]
Definition: service.cc:5476
static const MethodParameter *const get_cpu_samples_params[]
Definition: service.cc:4448
static const MethodParameter *const get_vm_timeline_flags_params[]
Definition: service.cc:4257
static const MethodParameter *const remove_breakpoint_params[]
Definition: service.cc:4035
bool IsInternalOnlyClassId(intptr_t index)
Definition: class_id.h:299
static bool ContainsNonInstance(const Object &obj)
Definition: service.cc:1790
static bool GetPrefixedIntegerId(const char *s, const char *prefix, intptr_t *service_id)
Definition: service.cc:645
static int8_t data[kExtLength]
static void GetScripts(Thread *thread, JSONStream *js)
Definition: service.cc:1641
static const MethodParameter *const get_retained_size_params[]
Definition: service.cc:2546
static void GetFlagList(Thread *thread, JSONStream *js)
Definition: service.cc:5598
static bool GetIntegerId(const char *s, intptr_t *id, int base=10)
Definition: service.cc:533
static const MethodParameter *const set_isolate_pause_mode_params[]
Definition: service.cc:5526
static void RequestHeapSnapshot(Thread *thread, JSONStream *js)
Definition: service.cc:4595
static const MethodParameter *const get_isolate_metric_list_params[]
Definition: service.cc:4105
static void GetCpuSamplesCommon(TimelineOrSamplesResponseFormat format, Thread *thread, JSONStream *js)
Definition: service.cc:4148
static void PrintSuccess(JSONStream *js)
Definition: service.cc:507
static void SetVMTimelineFlags(Thread *thread, JSONStream *js)
Definition: service.cc:4241
static const char *const step_enum_names[]
Definition: service.cc:4311
intptr_t ParseJSONArray(Thread *thread, const char *str, const GrowableObjectArray &elements)
Definition: service.cc:3660
static Breakpoint * LookupBreakpoint(Isolate *isolate, const char *id, ObjectIdRing::LookupResult *result)
Definition: service.cc:2238
static void GetVMTimelineFlags(Thread *thread, JSONStream *js)
Definition: service.cc:4262
static const MethodParameter *const get_object_params[]
Definition: service.cc:5039
static const MethodParameter *const get_isolate_group_params[]
Definition: service.cc:1524
uint8_t * DecodeBase64(const char *str, intptr_t *out_decoded_len)
Definition: base64.cc:39
static void GetAllocationProfile(Thread *thread, JSONStream *js)
Definition: service.cc:4550
static const MethodParameter *const add_breakpoint_with_script_uri_params[]
Definition: service.cc:3960
static void AddBreakpointAtActivation(Thread *thread, JSONStream *js)
Definition: service.cc:4013
Dart_ExceptionPauseInfo
Definition: debugger.h:504
@ kInvalidExceptionPauseInfo
Definition: debugger.h:508
@ kPauseOnUnhandledExceptions
Definition: debugger.h:506
@ kNoPauseOnExceptions
Definition: debugger.h:505
@ kPauseOnAllExceptions
Definition: debugger.h:507
static void GetIsolateGroup(Thread *thread, JSONStream *js)
Definition: service.cc:1601
constexpr intptr_t kLastInternalOnlyCid
Definition: class_id.h:289
static void PrintUnrecognizedMethodError(JSONStream *js)
Definition: service.cc:890
static void GetAllocationTraces(Thread *thread, JSONStream *js)
Definition: service.cc:4467
static void ClearVMTimeline(Thread *thread, JSONStream *js)
Definition: service.cc:4290
static const MethodParameter *const set_vm_name_params[]
Definition: service.cc:5721
static ObjectPtr LookupHeapObjectTypeArguments(Thread *thread, char **parts, int num_parts)
Definition: service.cc:2086
static ObjectPtr LookupHeapObjectClasses(Thread *thread, char **parts, int num_parts)
Definition: service.cc:2029
static const char *const report_enum_names[]
Definition: service.cc:3711
DECLARE_FLAG(bool, show_invisible_frames)
static void SetName(Thread *thread, JSONStream *js)
Definition: service.cc:5710
static bool CheckDebuggerDisabled(Thread *thread, JSONStream *js)
Definition: service.cc:512
@ kExpressionCompilationError
Definition: json_stream.h:65
@ kCannotAddBreakpoint
Definition: json_stream.h:54
@ kExtensionError
Definition: json_stream.h:51
@ kCannotResume
Definition: json_stream.h:59
@ kMethodNotFound
Definition: json_stream.h:47
@ kFeatureDisabled
Definition: json_stream.h:53
@ kIsolateIsReloading
Definition: json_stream.h:60
@ kIsolateMustBePaused
Definition: json_stream.h:58
@ kIsolateMustBeRunnable
Definition: json_stream.h:57
@ kInvalidTimelineRequest
Definition: json_stream.h:66
@ kInvalidParams
Definition: json_stream.h:48
@ kIsolateReloadBarred
Definition: json_stream.h:61
static void GetInstances(Thread *thread, JSONStream *js)
Definition: service.cc:3541
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
std::function< void()> closure
Definition: closure.h:14
string root
Definition: scale_cpu.py:20
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
#define Px
Definition: globals.h:410
#define Pd64
Definition: globals.h:416
#define Pd
Definition: globals.h:408
#define T
Definition: precompiler.cc:65
#define DEFINE_ADD_MAP_KEY(clazz)
#define OBJECT_PARAMETER
Definition: service.cc:183
#define RUNNABLE_ISOLATE_PARAMETER
Definition: service.cc:182
#define DEFINE_ADD_VALUE_F(id)
#define DEFINE_ADD_VALUE_F_CID(clazz)
#define ISOLATE_GROUP_PARAMETER
Definition: service.cc:180
#define Z
Definition: service.cc:61
#define NO_ISOLATE_PARAMETER
Definition: service.cc:181
#define ADD_METRIC(type, variable, name, unit)
#define ISOLATE_PARAMETER
Definition: service.cc:179
#define ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING
Definition: service.h:50
#define SERVICE_PROTOCOL_MAJOR_VERSION
Definition: service.h:20
#define ISOLATE_SERVICE_ID_FORMAT_STRING
Definition: service.h:48
#define SERVICE_PROTOCOL_MINOR_VERSION
Definition: service.h:21
#define ISOLATE_GROUP_SERVICE_ID_PREFIX
Definition: service.h:49
Dart_KernelCompilationStatus status
Definition: dart_api.h:3792
Definition: SkMD5.cpp:134
Dart_HandleFinalizer callback
union _Dart_CObject::@86 value
Dart_CObject_Type type
uint8_t * data
const char * as_string
struct _Dart_CObject::@86::@91 as_external_typed_data
struct _Dart_CObject::@86::@89 as_array
struct _Dart_CObject ** values
const Instance * stack_trace
Definition: service_event.h:79
const MethodParameter *const * parameters
Definition: service.cc:882
const ServiceMethodEntry entry
Definition: service.cc:881
void * user_data
const uintptr_t id
#define ARRAY_SIZE(array)
Definition: globals.h:72