Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
dart_vm.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <sys/stat.h>
8
9#include <sstream>
10#include <vector>
11
14#include "flutter/fml/logging.h"
15#include "flutter/fml/mapping.h"
22#include "third_party/dart/runtime/bin/platform.h"
23#include "third_party/dart/runtime/include/bin/dart_io_api.h"
24#include "third_party/skia/include/core/SkExecutor.h"
31
32namespace flutter {
33
34// Arguments passed to the Dart VM in all configurations.
35static const char* kDartAllConfigsArgs[] = {
36 // clang-format off
37 "--enable_mirrors=false",
38 "--background_compilation",
39 // 'mark_when_idle' appears to cause a regression, turning off for now.
40 // "--mark_when_idle",
41 // clang-format on
42};
43
44static const char* kDartPrecompilationArgs[] = {"--precompilation"};
45
46static const char* kSerialGCArgs[] = {
47 // clang-format off
48 "--concurrent_mark=false",
49 "--concurrent_sweep=false",
50 "--compactor_tasks=1",
51 "--scavenger_tasks=0",
52 "--marker_tasks=0",
53 // clang-format on
54};
55
56[[maybe_unused]]
57static const char* kDartWriteProtectCodeArgs[] = {
58 "--no_write_protect_code",
59};
60
61[[maybe_unused]]
62static const char* kDartDisableIntegerDivisionArgs[] = {
63 "--no_use_integer_division",
64};
65
66static const char* kDartAssertArgs[] = {
67 // clang-format off
68 "--enable_asserts",
69 // clang-format on
70};
71
72static const char* kDartStartPausedArgs[]{
73 "--pause_isolates_on_start",
74};
75
76static const char* kDartEndlessTraceBufferArgs[]{
77 "--timeline_recorder=endless",
78};
79
80static const char* kDartSystraceTraceBufferArgs[] = {
81 "--timeline_recorder=systrace",
82};
83
84static std::string DartFileRecorderArgs(const std::string& path) {
85 std::ostringstream oss;
86 oss << "--timeline_recorder=perfettofile:" << path;
87 return oss.str();
88}
89
90// "Microtask" is included in all argument strings below, but "Microtask" stream
91// events will only be recorded by the VM's timeline recorders when
92// |Switch::ProfileMicrotasks| is set.
93
94[[maybe_unused]]
95static const char* kDartDefaultTraceStreamsArgs[]{
96 "--timeline_streams=Dart,Embedder,GC,Microtask",
97};
98
99static const char* kDartStartupTraceStreamsArgs[]{
100 "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,Microtask,"
101 "VM,API",
102};
103
104static const char* kDartSystraceTraceStreamsArgs[] = {
105 "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,Microtask,"
106 "VM,API",
107};
108
109static const char* kDartProfileMicrotasksArgs[]{
110 "--profile_microtasks",
111};
112
113static std::string DartOldGenHeapSizeArgs(uint64_t heap_size) {
114 std::ostringstream oss;
115 oss << "--old_gen_heap_size=" << heap_size;
116 return oss.str();
117}
118
119constexpr char kFileUriPrefix[] = "file://";
120constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1;
121
122bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) {
123 if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) {
124 // Assume modified.
125 return true;
126 }
127
128 const char* path = source_url + kFileUriPrefixLength;
129 struct stat info;
130 if (stat(path, &info) < 0) {
131 return true;
132 }
133
134 // If st_mtime is zero, it's more likely that the file system doesn't support
135 // mtime than that the file was actually modified in the 1970s.
136 if (!info.st_mtime) {
137 return true;
138 }
139
140 // It's very unclear what time bases we're with here. The Dart API doesn't
141 // document the time base for since_ms. Reading the code, the value varies by
142 // platform, with a typical source being something like gettimeofday.
143 //
144 // We add one to st_mtime because st_mtime has less precision than since_ms
145 // and we want to treat the file as modified if the since time is between
146 // ticks of the mtime.
147 fml::TimeDelta mtime = fml::TimeDelta::FromSeconds(info.st_mtime + 1);
149
150 return mtime > since;
151}
152
154
155static const char kStdoutStreamId[] = "Stdout";
156static const char kStderrStreamId[] = "Stderr";
157
158static bool ServiceStreamListenCallback(const char* stream_id) {
159 if (strcmp(stream_id, kStdoutStreamId) == 0) {
160 dart::bin::SetCaptureStdout(true);
161 return true;
162 } else if (strcmp(stream_id, kStderrStreamId) == 0) {
163 dart::bin::SetCaptureStderr(true);
164 return true;
165 }
166 return false;
167}
168
169static void ServiceStreamCancelCallback(const char* stream_id) {
170 if (strcmp(stream_id, kStdoutStreamId) == 0) {
171 dart::bin::SetCaptureStdout(false);
172 } else if (strcmp(stream_id, kStderrStreamId) == 0) {
173 dart::bin::SetCaptureStderr(false);
174 }
175}
176
178 return Dart_IsPrecompiledRuntime();
179}
180
181static std::vector<const char*> ProfilingFlags(bool enable_profiling,
182 bool profile_startup) {
183// Disable Dart's built in profiler when building a debug build. This
184// works around a race condition that would sometimes stop a crash's
185// stack trace from being printed on Android.
186#ifndef NDEBUG
187 enable_profiling = false;
188#endif
189
190 // We want to disable profiling by default because it overwhelms LLDB. But
191 // the VM enables the same by default. In either case, we have some profiling
192 // flags.
193 if (enable_profiling) {
194 std::vector<const char*> flags = {
195 // This is the default. But just be explicit.
196 "--profiler",
197 // This instructs the profiler to walk C++ frames, and to include
198 // them in the profile.
199 "--profile-vm",
200#if FML_OS_IOS && FML_ARCH_CPU_ARM_FAMILY && FML_ARCH_CPU_ARMEL
201 // Set the profiler interrupt period to 500Hz instead of the
202 // default 1000Hz on 32-bit iOS devices to reduce average and worst
203 // case frame build times.
204 //
205 // Note: profile_period is time in microseconds between sampling
206 // events, not frequency. Frequency is calculated 1/period (or
207 // 1,000,000 / 2,000 -> 500Hz in this case).
208 "--profile_period=2000",
209#else
210 "--profile_period=1000",
211#endif // FML_OS_IOS && FML_ARCH_CPU_ARM_FAMILY && FML_ARCH_CPU_ARMEL
212 };
213
214 if (profile_startup) {
215 // This instructs the profiler to discard new samples once the profiler
216 // sample buffer is full. When this flag is not set, the profiler sample
217 // buffer is used as a ring buffer, meaning that once it is full, new
218 // samples start overwriting the oldest ones."
219 flags.push_back("--profile_startup");
220 }
221
222 return flags;
223 } else {
224 return {"--no-profiler"};
225 }
226}
227
228void PushBackAll(std::vector<const char*>* args,
229 const char** argv,
230 size_t argc) {
231 for (size_t i = 0; i < argc; ++i) {
232 args->push_back(argv[i]);
233 }
234}
235
236static void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
237 info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION;
238 dart::bin::GetIOEmbedderInformation(info);
239 info->name = "Flutter";
240}
241
242std::shared_ptr<DartVM> DartVM::Create(
243 const Settings& settings,
245 fml::RefPtr<const DartSnapshot> isolate_snapshot,
246 std::shared_ptr<IsolateNameServer> isolate_name_server) {
247 auto vm_data = DartVMData::Create(settings, //
248 std::move(vm_snapshot), //
249 std::move(isolate_snapshot) //
250 );
251
252 if (!vm_data) {
253 FML_LOG(ERROR) << "Could not set up VM data to bootstrap the VM from.";
254 return {};
255 }
256
257 // Note: std::make_shared unviable due to hidden constructor.
258 return std::shared_ptr<DartVM>(
259 new DartVM(vm_data, std::move(isolate_name_server)));
260}
261
262static std::atomic_size_t gVMLaunchCount;
263
265 return gVMLaunchCount;
266}
267
268// Minimum and maximum number of worker threads.
269static constexpr size_t kMinCount = 2;
270static constexpr size_t kMaxCount = 4;
271
272DartVM::DartVM(const std::shared_ptr<const DartVMData>& vm_data,
273 std::shared_ptr<IsolateNameServer> isolate_name_server)
274 : settings_(vm_data->GetSettings()),
275 concurrent_message_loop_(fml::ConcurrentMessageLoop::Create(
276 std::clamp(fml::EfficiencyCoreCount().value_or(
277 std::thread::hardware_concurrency()) /
278 2,
279 kMinCount,
280 kMaxCount))),
281 skia_concurrent_executor_(
282 [runner = concurrent_message_loop_->GetTaskRunner()](
283 const fml::closure& work) { runner->PostTask(work); }),
284 vm_data_(vm_data),
285 isolate_name_server_(std::move(isolate_name_server)),
286 service_protocol_(std::make_shared<ServiceProtocol>()) {
287 TRACE_EVENT0("flutter", "DartVMInitializer");
288
289 gVMLaunchCount++;
290
291 // Setting the executor is not thread safe but Dart VM initialization is. So
292 // this call is thread-safe.
293 SkExecutor::SetDefault(&skia_concurrent_executor_);
294
295 FML_DCHECK(vm_data_);
296 FML_DCHECK(isolate_name_server_);
297 FML_DCHECK(service_protocol_);
298
299 if (!dart::bin::Platform::Initialize(false)) {
300 FML_LOG(FATAL) << "Dart platform-specific initialization failed";
301 }
302
303 {
304 TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo");
305 dart::bin::BootstrapDartIo();
306
307 if (!settings_.temp_directory_path.empty()) {
308 dart::bin::SetSystemTempDirectory(settings_.temp_directory_path.c_str());
309 }
310 }
311
312 std::vector<const char*> args;
313
314 // Instruct the VM to ignore unrecognized flags.
315 // There is a lot of diversity in a lot of combinations when it
316 // comes to the arguments the VM supports. And, if the VM comes across a flag
317 // it does not recognize, it exits immediately.
318 args.push_back("--ignore-unrecognized-flags");
319
320 for (auto* const profiler_flag : ProfilingFlags(
321 settings_.enable_dart_profiling, settings_.profile_startup)) {
322 args.push_back(profiler_flag);
323 }
324
325 PushBackAll(&args, kDartAllConfigsArgs, std::size(kDartAllConfigsArgs));
326
327 if (IsRunningPrecompiledCode()) {
328 PushBackAll(&args, kDartPrecompilationArgs,
329 std::size(kDartPrecompilationArgs));
330 }
331
332 // Enable Dart assertions if we are not running precompiled code. We run non-
333 // precompiled code only in the debug product mode.
334 bool enable_asserts = !settings_.disable_dart_asserts;
335
336#if !OS_FUCHSIA
337 if (IsRunningPrecompiledCode()) {
338 enable_asserts = false;
339 }
340#endif // !OS_FUCHSIA
341
342#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG)
343#if !FML_OS_IOS && !FML_OS_MACOSX
344 // Debug mode uses the JIT, disable code page write protection to avoid
345 // memory page protection changes before and after every compilation.
346 PushBackAll(&args, kDartWriteProtectCodeArgs,
347 std::size(kDartWriteProtectCodeArgs));
348#else
349 const bool tracing_result = EnableTracingIfNecessary(settings_);
350 // This check should only trip if the embedding made no attempts to enable
351 // tracing. At this point, it is too late display user visible messages. Just
352 // log and die.
353 FML_CHECK(tracing_result)
354 << "Tracing not enabled before attempting to run JIT mode VM.";
355#if TARGET_CPU_ARM
356 // Tell Dart in JIT mode to not use integer division on armv7
357 // Ideally, this would be detected at runtime by Dart.
358 // TODO(dnfield): Remove this code
359 // https://github.com/dart-lang/sdk/issues/24743
360 PushBackAll(&args, kDartDisableIntegerDivisionArgs,
361 std::size(kDartDisableIntegerDivisionArgs));
362#endif // TARGET_CPU_ARM
363#endif // !FML_OS_IOS && !FML_OS_MACOSX
364#endif // (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG)
365
366 if (enable_asserts) {
367 PushBackAll(&args, kDartAssertArgs, std::size(kDartAssertArgs));
368 }
369
370 // On low power devices with lesser number of cores, using concurrent
371 // marking or sweeping causes contention for the UI thread leading to
372 // Jank, this option can be used to turn off all concurrent GC activities.
373 if (settings_.enable_serial_gc) {
374 PushBackAll(&args, kSerialGCArgs, std::size(kSerialGCArgs));
375 }
376
377 if (settings_.start_paused) {
378 PushBackAll(&args, kDartStartPausedArgs, std::size(kDartStartPausedArgs));
379 }
380
381 if (settings_.endless_trace_buffer || settings_.trace_startup) {
382 // If we are tracing startup, make sure the trace buffer is endless so we
383 // don't lose early traces.
384 PushBackAll(&args, kDartEndlessTraceBufferArgs,
385 std::size(kDartEndlessTraceBufferArgs));
386 }
387
388 if (settings_.trace_systrace) {
389 PushBackAll(&args, kDartSystraceTraceBufferArgs,
390 std::size(kDartSystraceTraceBufferArgs));
391 PushBackAll(&args, kDartSystraceTraceStreamsArgs,
392 std::size(kDartSystraceTraceStreamsArgs));
393 }
394
395 std::string file_recorder_args;
396 if (!settings_.trace_to_file.empty()) {
397 file_recorder_args = DartFileRecorderArgs(settings_.trace_to_file);
398 args.push_back(file_recorder_args.c_str());
399 PushBackAll(&args, kDartSystraceTraceStreamsArgs,
400 std::size(kDartSystraceTraceStreamsArgs));
401 }
402
403 if (settings_.trace_startup) {
404 PushBackAll(&args, kDartStartupTraceStreamsArgs,
405 std::size(kDartStartupTraceStreamsArgs));
406 }
407
408#if defined(OS_FUCHSIA)
409 PushBackAll(&args, kDartSystraceTraceBufferArgs,
410 std::size(kDartSystraceTraceBufferArgs));
411 PushBackAll(&args, kDartSystraceTraceStreamsArgs,
412 std::size(kDartSystraceTraceStreamsArgs));
413#else
414 if (!settings_.trace_systrace && !settings_.trace_startup) {
415 PushBackAll(&args, kDartDefaultTraceStreamsArgs,
416 std::size(kDartDefaultTraceStreamsArgs));
417 }
418#endif // defined(OS_FUCHSIA)
419
420 if (settings_.profile_microtasks) {
421 PushBackAll(&args, kDartProfileMicrotasksArgs,
422 std::size(kDartProfileMicrotasksArgs));
423 }
424
425 std::string old_gen_heap_size_args;
426 if (settings_.old_gen_heap_size >= 0) {
427 old_gen_heap_size_args =
428 DartOldGenHeapSizeArgs(settings_.old_gen_heap_size);
429 args.push_back(old_gen_heap_size_args.c_str());
430 }
431
432 for (size_t i = 0; i < settings_.dart_flags.size(); i++) {
433 args.push_back(settings_.dart_flags[i].c_str());
434 }
435
436 char* flags_error = Dart_SetVMFlags(args.size(), args.data());
437 if (flags_error) {
438 FML_LOG(FATAL) << "Error while setting Dart VM flags: " << flags_error;
439 ::free(flags_error);
440 }
441
442 dart::bin::SetExecutableName(settings_.executable_name.c_str());
443
444 {
445 TRACE_EVENT0("flutter", "Dart_Initialize");
446 Dart_InitializeParams params = {};
447 params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
448 params.vm_snapshot_data = vm_data_->GetVMSnapshot().GetDataMapping();
449 params.vm_snapshot_instructions =
450 vm_data_->GetVMSnapshot().GetInstructionsMapping();
451 params.create_group = reinterpret_cast<decltype(params.create_group)>(
452 DartIsolate::DartIsolateGroupCreateCallback);
453 params.initialize_isolate =
454 reinterpret_cast<decltype(params.initialize_isolate)>(
455 DartIsolate::DartIsolateInitializeCallback);
456 params.shutdown_isolate =
457 reinterpret_cast<decltype(params.shutdown_isolate)>(
458 DartIsolate::DartIsolateShutdownCallback);
459 params.cleanup_isolate = reinterpret_cast<decltype(params.cleanup_isolate)>(
460 DartIsolate::DartIsolateCleanupCallback);
461 params.cleanup_group = reinterpret_cast<decltype(params.cleanup_group)>(
462 DartIsolate::DartIsolateGroupCleanupCallback);
463 params.thread_exit = ThreadExitCallback;
464 params.file_open = dart::bin::OpenFile;
465 params.file_read = dart::bin::ReadFile;
466 params.file_write = dart::bin::WriteFile;
467 params.file_close = dart::bin::CloseFile;
468 params.entropy_source = dart::bin::GetEntropy;
470 settings_.enable_timeline_event_handler,
471 settings_.trace_systrace);
472 // Send the earliest available timestamp in the application lifecycle to
473 // timeline. The difference between this timestamp and the time we render
474 // the very first frame gives us a good idea about Flutter's startup time.
475 // Use an instant event because the call to Dart_TimelineGetMicros
476 // may behave differently before and after the Dart VM is initialized.
477 // As this call is immediately after initialization of the Dart VM,
478 // we are interested in only one timestamp.
479 int64_t micros = Dart_TimelineGetMicros();
480 Dart_RecordTimelineEvent("FlutterEngineMainEnter", // label
481 micros, // timestamp0
482 micros, // timestamp1_or_async_id
483 0, // flow_id_count
484 nullptr, // flow_ids
485 Dart_Timeline_Event_Instant, // event type
486 0, // argument_count
487 nullptr, // argument_names
488 nullptr // argument_values
489 );
490 }
491
492 Dart_SetFileModifiedCallback(&DartFileModifiedCallback);
493
494 // Allow streaming of stdout and stderr by the Dart vm.
495 Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
496 &ServiceStreamCancelCallback);
497
498 Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback);
499
500 if (settings_.dart_library_sources_kernel != nullptr) {
501 std::unique_ptr<fml::Mapping> dart_library_sources =
502 settings_.dart_library_sources_kernel();
503 // Set sources for dart:* libraries for debugging.
504 Dart_SetDartLibrarySourcesKernel(dart_library_sources->GetMapping(),
505 dart_library_sources->GetSize());
506 }
507
508 // Update thread names now that the Dart VM is initialized.
509 concurrent_message_loop_->PostTaskToAllWorkers(
510 [] { Dart_SetThreadName("FlutterConcurrentMessageLoopWorker"); });
511}
512
513DartVM::~DartVM() {
514 // Setting the executor is not thread safe but Dart VM shutdown is. So
515 // this call is thread-safe.
516 SkExecutor::SetDefault(nullptr);
517
518 if (Dart_CurrentIsolate() != nullptr) {
519 Dart_ExitIsolate();
520 }
521
523
524 dart::bin::CleanupDartIo();
525}
526
527std::shared_ptr<const DartVMData> DartVM::GetVMData() const {
528 return vm_data_;
529}
530
531const Settings& DartVM::GetSettings() const {
532 return settings_;
533}
534
535std::shared_ptr<ServiceProtocol> DartVM::GetServiceProtocol() const {
536 return service_protocol_;
537}
538
539std::shared_ptr<IsolateNameServer> DartVM::GetIsolateNameServer() const {
540 return isolate_name_server_;
541}
542
543std::shared_ptr<fml::ConcurrentTaskRunner>
544DartVM::GetConcurrentWorkerTaskRunner() const {
545 return concurrent_message_loop_->GetTaskRunner();
546}
547
548std::shared_ptr<fml::ConcurrentMessageLoop> DartVM::GetConcurrentMessageLoop() {
549 return concurrent_message_loop_;
550}
551
552} // namespace flutter
static void Initialize(Dart_InitializeParams *params, bool enable_timeline_event_handler, bool trace_systrace)
static std::shared_ptr< const DartVMData > Create(const Settings &settings, fml::RefPtr< const DartSnapshot > vm_snapshot, fml::RefPtr< const DartSnapshot > isolate_snapshot)
Creates a new instance of DartVMData. Both the VM and isolate snapshot members are optional and may b...
static size_t GetVMLaunchCount()
The number of times the VM has been launched in the process. This call is inherently racy because the...
Definition dart_vm.cc:264
static bool IsRunningPrecompiledCode()
Checks if VM instances in the process can run precompiled code. This call can be made at any time and...
Definition dart_vm.cc:177
static constexpr TimeDelta FromSeconds(int64_t seconds)
Definition time_delta.h:49
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
const EmbeddedViewParams * params
Settings settings_
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
char ** argv
Definition library.h:9
void ThreadExitCallback()
Definition dart_vm.cc:153
static const char kStderrStreamId[]
Definition dart_vm.cc:156
static constexpr size_t kMaxCount
Definition dart_vm.cc:270
static const char * kDartPrecompilationArgs[]
Definition dart_vm.cc:44
static const char * kSerialGCArgs[]
Definition dart_vm.cc:46
static std::string DartFileRecorderArgs(const std::string &path)
Definition dart_vm.cc:84
static const char * kDartDisableIntegerDivisionArgs[]
Definition dart_vm.cc:62
constexpr size_t kFileUriPrefixLength
Definition dart_vm.cc:120
void PushBackAll(std::vector< const char * > *args, const char **argv, size_t argc)
Definition dart_vm.cc:228
static std::string DartOldGenHeapSizeArgs(uint64_t heap_size)
Definition dart_vm.cc:113
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 switch_defs.h:52
static const char * kDartAllConfigsArgs[]
Definition dart_vm.cc:35
static const char * kDartStartPausedArgs[]
Definition dart_vm.cc:72
static void EmbedderInformationCallback(Dart_EmbedderInformation *info)
Definition dart_vm.cc:236
static const char * kDartStartupTraceStreamsArgs[]
Definition dart_vm.cc:99
static void ServiceStreamCancelCallback(const char *stream_id)
Definition dart_vm.cc:169
static constexpr size_t kMinCount
Definition dart_vm.cc:269
constexpr char kFileUriPrefix[]
Definition dart_vm.cc:119
static const char * kDartEndlessTraceBufferArgs[]
Definition dart_vm.cc:76
static const char * kDartAssertArgs[]
Definition dart_vm.cc:66
bool EnableTracingIfNecessary(const Settings &vm_settings)
Enables tracing in the process so that JIT mode VMs may be launched. Explicitly enabling tracing is n...
static const char * kDartSystraceTraceBufferArgs[]
Definition dart_vm.cc:80
static std::atomic_size_t gVMLaunchCount
Definition dart_vm.cc:262
static const char kStdoutStreamId[]
Definition dart_vm.cc:155
static const char * kDartWriteProtectCodeArgs[]
Definition dart_vm.cc:57
static const char * kDartDefaultTraceStreamsArgs[]
Definition dart_vm.cc:95
static const char * kDartSystraceTraceStreamsArgs[]
Definition dart_vm.cc:104
bool DartFileModifiedCallback(const char *source_url, int64_t since_ms)
Definition dart_vm.cc:122
static bool ServiceStreamListenCallback(const char *stream_id)
Definition dart_vm.cc:158
static std::vector< const char * > ProfilingFlags(bool enable_profiling, bool profile_startup)
Definition dart_vm.cc:181
static const char * kDartProfileMicrotasksArgs[]
Definition dart_vm.cc:109
Definition ref_ptr.h:261
#define TRACE_EVENT0(category_group, name)