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