Flutter Engine
The Flutter Engine
dartdev_isolate.cc
Go to the documentation of this file.
1// Copyright (c) 2020, 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
6
7#if !defined(DART_PRECOMPILED_RUNTIME)
8
9#include <functional>
10#include <memory>
11
12#include "bin/directory.h"
13#include "bin/error_exit.h"
14#include "bin/exe_utils.h"
15#include "bin/file.h"
16#include "bin/lockers.h"
17#include "bin/main_options.h"
18#include "bin/platform.h"
19#include "bin/process.h"
21#include "platform/utils.h"
22
23#define CHECK_RESULT(result) \
24 if (Dart_IsError(result)) { \
25 ProcessError(Dart_GetError(result), kErrorExitCode); \
26 if (send_port_id != ILLEGAL_PORT) { \
27 Dart_CloseNativePort(send_port_id); \
28 } \
29 Dart_ExitScope(); \
30 Dart_ShutdownIsolate(); \
31 return; \
32 }
33
34namespace dart {
35namespace bin {
36
37DartDevIsolate::DartDevRunner DartDevIsolate::runner_ =
38 DartDevIsolate::DartDevRunner();
39bool DartDevIsolate::should_run_dart_dev_ = false;
40bool DartDevIsolate::print_usage_error_ = false;
41Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
42DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
44char** DartDevIsolate::DartDevRunner::script_ = nullptr;
45char** DartDevIsolate::DartDevRunner::package_config_override_ = nullptr;
46std::unique_ptr<char*[], void (*)(char*[])>
47 DartDevIsolate::DartDevRunner::argv_ =
48 std::unique_ptr<char*[], void (*)(char**)>(nullptr, [](char**) {});
49intptr_t DartDevIsolate::DartDevRunner::argc_ = 0;
50
51bool DartDevIsolate::ShouldParseCommand(const char* script_uri) {
52 // If script_uri is a known DartDev command, we should not try to run it.
53 //
54 // Otherwise if script_uri is not a file path or of a known URI scheme, we
55 // assume this is a mistyped DartDev command.
56 //
57 // This should be kept in sync with the commands in
58 // `pkg/dartdev/lib/dartdev.dart`.
59 return (
60 (strcmp(script_uri, "analyze") == 0) ||
61 (strcmp(script_uri, "compilation-server") == 0) ||
62 (strcmp(script_uri, "build") == 0) ||
63 (strcmp(script_uri, "compile") == 0) ||
64 (strcmp(script_uri, "create") == 0) ||
65 (strcmp(script_uri, "development-service") == 0) ||
66 (strcmp(script_uri, "devtools") == 0) ||
67 (strcmp(script_uri, "doc") == 0) || (strcmp(script_uri, "fix") == 0) ||
68 (strcmp(script_uri, "format") == 0) ||
69 (strcmp(script_uri, "info") == 0) || (strcmp(script_uri, "pub") == 0) ||
70 (strcmp(script_uri, "run") == 0) || (strcmp(script_uri, "test") == 0) ||
71 (strcmp(script_uri, "info") == 0) ||
72 (strcmp(script_uri, "language-server") == 0) ||
73 (strcmp(script_uri, "tooling-daemon") == 0) ||
74 (!File::ExistsUri(nullptr, script_uri) &&
75 (strncmp(script_uri, "http://", 7) != 0) &&
76 (strncmp(script_uri, "https://", 8) != 0) &&
77 (strncmp(script_uri, "file://", 7) != 0) &&
78 (strncmp(script_uri, "package:", 8) != 0) &&
79 (strncmp(script_uri, "google3://", 10) != 0)));
80}
81
82CStringUniquePtr DartDevIsolate::TryResolveArtifactPath(const char* filename) {
83 auto try_resolve_path = [&](CStringUniquePtr dir_prefix) {
84 // First assume we're in dart-sdk/bin.
85 char* snapshot_path =
86 Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename);
87 if (File::Exists(nullptr, snapshot_path)) {
88 return CStringUniquePtr(snapshot_path);
89 }
90 free(snapshot_path);
91
92 // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
93 // directories. Try to use a snapshot from a previously built SDK.
94 snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename);
95 if (File::Exists(nullptr, snapshot_path)) {
96 return CStringUniquePtr(snapshot_path);
97 }
98 free(snapshot_path);
99 return CStringUniquePtr(nullptr);
100 };
101
102 // Try to find the artifact using the resolved EXE path first. This can fail
103 // if the Dart SDK file structure is faked using symlinks and the actual
104 // artifacts are spread across directories on the file system (e.g., some
105 // google3 execution environments).
106 auto result =
108 if (result == nullptr) {
109 result =
111 }
112
113 return result;
114}
115
117 return TryResolveArtifactPath("dartdev.dart.snapshot");
118}
119
121 Dart_IsolateGroupCreateCallback create_isolate,
122 char** packages_file,
123 char** script,
124 CommandLineOptions* dart_options) {
125 create_isolate_ = create_isolate;
126 dart_options_ = dart_options;
127 package_config_override_ = packages_file;
128 script_ = script;
129
130 // We've encountered an error during preliminary argument parsing so we'll
131 // output the standard help message and exit with an error code.
132 if (print_usage_error_) {
133 dart_options_->Reset();
134 dart_options_->AddArgument("--help");
135 }
136
137 MonitorLocker locker(monitor_);
138 int result = Thread::Start("DartDev Runner", RunCallback,
139 reinterpret_cast<uword>(this));
140 if (result != 0) {
141 FATAL("Failed to start DartDev thread: %d", result);
142 }
144
145 if (result_ == DartDevIsolate::DartDev_Result_Run) {
146 // Clear the DartDev dart_options and replace them with the processed
147 // options provided by DartDev.
148 dart_options_->Reset();
149 dart_options_->AddArguments(const_cast<const char**>(argv_.get()), argc_);
150 }
151}
152
154 return message->value.as_array.values[index];
155}
156
157void DartDevIsolate::DartDevRunner::DartDevResultCallback(
158 Dart_Port dest_port_id,
160 // These messages are produced in pkg/dartdev/lib/src/vm_interop_handler.dart.
162 int32_t type = GetArrayItem(message, 0)->value.as_int32;
163 switch (type) {
167 auto item2 = GetArrayItem(message, 2);
168
169 ASSERT(item2->type == Dart_CObject_kString ||
170 item2->type == Dart_CObject_kNull);
171
172 auto item3 = GetArrayItem(message, 3);
173
174 ASSERT(item3->type == Dart_CObject_kBool);
175 const bool mark_main_isolate_as_system_isolate = item3->value.as_bool;
176 if (mark_main_isolate_as_system_isolate) {
178 }
179
180 if (*script_ != nullptr) {
181 free(*script_);
182 }
183 if (*package_config_override_ != nullptr) {
184 free(*package_config_override_);
185 *package_config_override_ = nullptr;
186 }
187 *script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
188
189 if (item2->type == Dart_CObject_kString) {
190 *package_config_override_ = Utils::StrDup(item2->value.as_string);
191 }
192
195 argc_ = args->value.as_array.length;
196 Dart_CObject** dart_args = args->value.as_array.values;
197
198 auto deleter = [](char** args) {
199 for (intptr_t i = 0; i < argc_; ++i) {
200 free(args[i]);
201 }
202 delete[] args;
203 };
204 argv_ =
205 std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_], deleter);
206 for (intptr_t i = 0; i < argc_; ++i) {
207 argv_[i] = Utils::StrDup(dart_args[i]->value.as_string);
208 }
209 break;
210 }
213 int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;
214
215 // If we're given a non-zero exit code, DartDev is signaling for us to
216 // shutdown.
217 int32_t exit_code =
218 print_usage_error_ ? kErrorExitCode : dartdev_exit_code;
220
221 // If DartDev hasn't signaled for us to do anything else, we can assume
222 // there's nothing else for the VM to run and that we can exit.
225 }
226
227 // DartDev is done processing the command. Unblock the main thread and
228 // continue the launch procedure.
229 DartDevRunner::monitor_->Notify();
230 break;
231 }
232 default:
233 UNREACHABLE();
234 }
235}
236
237void DartDevIsolate::DartDevRunner::RunCallback(uword args) {
238 MonitorLocker locker_(DartDevRunner::monitor_);
239 DartDevRunner* runner = reinterpret_cast<DartDevRunner*>(args);
240
241 // Hardcode flags to match those used to generate the DartDev snapshot.
244 flags.enable_asserts = false;
245 flags.use_field_guards = true;
246 flags.use_osr = true;
247 flags.is_system_isolate = true;
248 flags.branch_coverage = false;
249 flags.coverage = false;
250
251 char* error = nullptr;
252 Dart_Isolate dartdev_isolate = runner->create_isolate_(
254 runner->packages_file_, &flags, /* callback_data */ nullptr,
255 const_cast<char**>(&error));
256
257 if (dartdev_isolate == nullptr) {
258 ProcessError(error, kErrorExitCode);
259 free(error);
260 return;
261 }
262
263 Dart_EnterIsolate(dartdev_isolate);
265
266 // Retrieve the DartDev entrypoint.
267 Dart_Port send_port_id = ILLEGAL_PORT;
268 Dart_Handle root_lib = Dart_RootLibrary();
269 Dart_Handle main_closure =
270 Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
271 CHECK_RESULT(main_closure);
272
273 if (!Dart_IsClosure(main_closure)) {
274 ProcessError("Unable to find 'main' in root library 'dartdev'",
278 return;
279 }
280
281 // Create a SendPort that DartDev can use to communicate its results over.
282 send_port_id =
283 Dart_NewNativePort(DART_DEV_ISOLATE_NAME, DartDevResultCallback, false);
284 ASSERT(send_port_id != ILLEGAL_PORT);
285 Dart_Handle send_port = Dart_NewSendPort(send_port_id);
286 CHECK_RESULT(send_port);
287
288 const intptr_t kNumIsolateArgs = 4;
289 Dart_Handle isolate_args[kNumIsolateArgs];
290 isolate_args[0] = main_closure; // entryPoint
291 isolate_args[1] = runner->dart_options_->CreateRuntimeOptions(); // args
292 isolate_args[2] = send_port; // message
293 isolate_args[3] = Dart_True(); // isSpawnUri
294
295 Dart_Handle isolate_lib =
298 Dart_Invoke(isolate_lib, Dart_NewStringFromCString("_startIsolate"),
299 kNumIsolateArgs, isolate_args);
302
303 Dart_CloseNativePort(send_port_id);
304
307}
308
309void DartDevIsolate::DartDevRunner::ProcessError(const char* msg,
310 int32_t exit_code) {
311 Syslog::PrintErr("%s.\n", msg);
314 DartDevRunner::monitor_->Notify();
315}
316
318 Dart_IsolateGroupCreateCallback create_isolate,
319 char** packages_file,
320 char** script,
321 CommandLineOptions* dart_options) {
322 runner_.Run(create_isolate, packages_file, script, dart_options);
323 return runner_.result();
324}
325
326} // namespace bin
327} // namespace dart
328
329#endif // if !defined(DART_PRECOMPILED_RUNTIME)
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static char * StrDup(const char *s)
static char * SCreate(const char *format,...) PRINTF_ATTRIBUTE(1
Definition: utils.cc:231
void AddArguments(const char **argv, int argc)
Definition: dartutils.h:77
void AddArgument(const char *argument)
Definition: dartutils.h:68
void Run(Dart_IsolateGroupCreateCallback create_isolate, char **package_config_override_, char **script, CommandLineOptions *dart_options)
static CStringUniquePtr TryResolveDartDevSnapshotPath()
static DartDev_Result RunDartDev(Dart_IsolateGroupCreateCallback create_isolate, char **packages_file, char **script, CommandLineOptions *dart_options)
static bool ShouldParseCommand(const char *script_uri)
static CStringUniquePtr GetDirectoryPrefixFromResolvedExeName()
Definition: exe_utils.cc:68
static CStringUniquePtr GetDirectoryPrefixFromUnresolvedExeName()
Definition: exe_utils.cc:122
static bool Exists(Namespace *namespc, const char *path)
static bool ExistsUri(Namespace *namespc, const char *uri)
static constexpr int64_t kNoTimeout
Definition: thread.h:79
WaitResult WaitMicros(int64_t micros)
static void set_mark_main_isolate_as_system_isolate(bool state)
Definition: main_options.h:155
static void SetGlobalExitCode(int exit_code)
Definition: process.h:129
static int Start(const char *name, ThreadStartFunction function, uword parameters)
Dart_Isolate(* Dart_IsolateGroupCreateCallback)(const char *script_uri, const char *main, const char *package_root, const char *package_config, Dart_IsolateFlags *flags, void *isolate_data, char **error)
Definition: dart_api.h:654
#define ILLEGAL_PORT
Definition: dart_api.h:1535
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition: dart_api.h:88
@ Dart_CObject_kString
@ Dart_CObject_kArray
@ Dart_CObject_kNull
@ Dart_CObject_kInt32
@ Dart_CObject_kBool
#define CHECK_RESULT(result)
#define DART_DEV_ISOLATE_NAME
#define ASSERT(E)
#define FATAL(error)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
Win32Message message
static Dart_CObject * GetArrayItem(Dart_CObject *message, intptr_t index)
constexpr int kErrorExitCode
Definition: error_exit.h:18
Dart_ShutdownIsolate()
Definition: dart_vm.cc:33
DART_EXPORT void Dart_EnterScope()
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
CAllocUniquePtr< char > CStringUniquePtr
Definition: utils.h:31
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_True()
DART_EXPORT Dart_Handle Dart_RootLibrary()
DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags *flags)
DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
uintptr_t uword
Definition: globals.h:501
DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id)
DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id)
DART_EXPORT Dart_Handle Dart_RunLoop()
DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url)
DART_EXPORT Dart_Port Dart_NewNativePort(const char *name, Dart_NativeMessageHandler handler, bool handle_concurrently)
DART_EXPORT bool Dart_IsClosure(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char *str)
union _Dart_CObject::@86 value