1 | // Copyright (c) 2012, 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 "bin/dartutils.h" |
6 | |
7 | #include "bin/crypto.h" |
8 | #include "bin/directory.h" |
9 | #include "bin/extensions.h" |
10 | #include "bin/file.h" |
11 | #include "bin/io_buffer.h" |
12 | #include "bin/namespace.h" |
13 | #include "bin/platform.h" |
14 | #include "bin/utils.h" |
15 | #include "include/dart_api.h" |
16 | #include "include/dart_native_api.h" |
17 | #include "include/dart_tools_api.h" |
18 | #include "platform/assert.h" |
19 | #include "platform/globals.h" |
20 | #include "platform/memory_sanitizer.h" |
21 | #include "platform/utils.h" |
22 | |
23 | // Return the error from the containing function if handle is in error handle. |
24 | #define RETURN_IF_ERROR(handle) \ |
25 | { \ |
26 | Dart_Handle __handle = handle; \ |
27 | if (Dart_IsError((__handle))) { \ |
28 | return __handle; \ |
29 | } \ |
30 | } |
31 | |
32 | namespace dart { |
33 | namespace bin { |
34 | |
35 | const char* DartUtils::original_working_directory = NULL; |
36 | const char* const DartUtils::kDartScheme = "dart:" ; |
37 | const char* const DartUtils::kDartExtensionScheme = "dart-ext:" ; |
38 | const char* const DartUtils::kAsyncLibURL = "dart:async" ; |
39 | const char* const DartUtils::kBuiltinLibURL = "dart:_builtin" ; |
40 | const char* const DartUtils::kCoreLibURL = "dart:core" ; |
41 | const char* const DartUtils::kInternalLibURL = "dart:_internal" ; |
42 | const char* const DartUtils::kIsolateLibURL = "dart:isolate" ; |
43 | const char* const DartUtils::kHttpLibURL = "dart:_http" ; |
44 | const char* const DartUtils::kIOLibURL = "dart:io" ; |
45 | const char* const DartUtils::kIOLibPatchURL = "dart:io-patch" ; |
46 | const char* const DartUtils::kCLILibURL = "dart:cli" ; |
47 | const char* const DartUtils::kCLILibPatchURL = "dart:cli-patch" ; |
48 | const char* const DartUtils::kUriLibURL = "dart:uri" ; |
49 | const char* const DartUtils::kHttpScheme = "http:" ; |
50 | const char* const DartUtils::kVMServiceLibURL = "dart:vmservice" ; |
51 | |
52 | dart::SimpleHashMap* DartUtils::environment_ = NULL; |
53 | |
54 | MagicNumberData appjit_magic_number = {8, {0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0}}; |
55 | MagicNumberData kernel_magic_number = {4, {0x90, 0xab, 0xcd, 0xef}}; |
56 | MagicNumberData kernel_list_magic_number = { |
57 | 7, |
58 | {0x23, 0x40, 0x64, 0x69, 0x6c, 0x6c, 0x0a}}; // #@dill\n |
59 | MagicNumberData gzip_magic_number = {2, {0x1f, 0x8b, 0, 0}}; |
60 | |
61 | static bool IsWindowsHost() { |
62 | #if defined(HOST_OS_WINDOWS) |
63 | return true; |
64 | #else // defined(HOST_OS_WINDOWS) |
65 | return false; |
66 | #endif // defined(HOST_OS_WINDOWS) |
67 | } |
68 | |
69 | Dart_Handle CommandLineOptions::CreateRuntimeOptions() { |
70 | Dart_Handle string_type = DartUtils::GetDartType("dart:core" , "String" ); |
71 | if (Dart_IsError(string_type)) { |
72 | return string_type; |
73 | } |
74 | Dart_Handle dart_arguments = |
75 | Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), count_); |
76 | if (Dart_IsError(dart_arguments)) { |
77 | return dart_arguments; |
78 | } |
79 | for (int i = 0; i < count_; i++) { |
80 | Dart_Handle argument_value = DartUtils::NewString(GetArgument(i)); |
81 | if (Dart_IsError(argument_value)) { |
82 | return argument_value; |
83 | } |
84 | Dart_Handle result = Dart_ListSetAt(dart_arguments, i, argument_value); |
85 | if (Dart_IsError(result)) { |
86 | return result; |
87 | } |
88 | } |
89 | return dart_arguments; |
90 | } |
91 | |
92 | int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) { |
93 | int64_t value = 0; |
94 | Dart_Handle result = Dart_IntegerToInt64(value_obj, &value); |
95 | if (Dart_IsError(result)) { |
96 | Dart_PropagateError(result); |
97 | } |
98 | return value; |
99 | } |
100 | |
101 | int64_t DartUtils::GetInt64ValueCheckRange(Dart_Handle value_obj, |
102 | int64_t lower, |
103 | int64_t upper) { |
104 | int64_t value = DartUtils::GetIntegerValue(value_obj); |
105 | if (value < lower || upper < value) { |
106 | Dart_PropagateError(Dart_NewApiError("Value outside expected range" )); |
107 | } |
108 | return value; |
109 | } |
110 | |
111 | intptr_t DartUtils::GetIntptrValue(Dart_Handle value_obj) { |
112 | int64_t value = 0; |
113 | Dart_Handle result = Dart_IntegerToInt64(value_obj, &value); |
114 | if (Dart_IsError(result)) { |
115 | Dart_PropagateError(result); |
116 | } |
117 | if (value < kIntptrMin || kIntptrMax < value) { |
118 | Dart_PropagateError(Dart_NewApiError("Value outside intptr_t range" )); |
119 | } |
120 | return static_cast<intptr_t>(value); |
121 | } |
122 | |
123 | bool DartUtils::GetInt64Value(Dart_Handle value_obj, int64_t* value) { |
124 | bool valid = Dart_IsInteger(value_obj); |
125 | if (valid) { |
126 | Dart_Handle result = Dart_IntegerFitsIntoInt64(value_obj, &valid); |
127 | if (Dart_IsError(result)) { |
128 | Dart_PropagateError(result); |
129 | } |
130 | } |
131 | if (!valid) return false; |
132 | Dart_Handle result = Dart_IntegerToInt64(value_obj, value); |
133 | if (Dart_IsError(result)) { |
134 | Dart_PropagateError(result); |
135 | } |
136 | return true; |
137 | } |
138 | |
139 | const char* DartUtils::GetStringValue(Dart_Handle str_obj) { |
140 | const char* cstring = NULL; |
141 | Dart_Handle result = Dart_StringToCString(str_obj, &cstring); |
142 | if (Dart_IsError(result)) { |
143 | Dart_PropagateError(result); |
144 | } |
145 | return cstring; |
146 | } |
147 | |
148 | bool DartUtils::GetBooleanValue(Dart_Handle bool_obj) { |
149 | bool value = false; |
150 | Dart_Handle result = Dart_BooleanValue(bool_obj, &value); |
151 | if (Dart_IsError(result)) { |
152 | Dart_PropagateError(result); |
153 | } |
154 | return value; |
155 | } |
156 | |
157 | bool DartUtils::GetNativeBooleanArgument(Dart_NativeArguments args, |
158 | intptr_t index) { |
159 | bool value = false; |
160 | Dart_Handle result = Dart_GetNativeBooleanArgument(args, index, &value); |
161 | if (Dart_IsError(result)) { |
162 | Dart_PropagateError(result); |
163 | } |
164 | return value; |
165 | } |
166 | |
167 | int64_t DartUtils::GetNativeIntegerArgument(Dart_NativeArguments args, |
168 | intptr_t index) { |
169 | int64_t value = 0; |
170 | Dart_Handle result = Dart_GetNativeIntegerArgument(args, index, &value); |
171 | if (Dart_IsError(result)) { |
172 | Dart_PropagateError(result); |
173 | } |
174 | return value; |
175 | } |
176 | |
177 | intptr_t DartUtils::GetNativeIntptrArgument(Dart_NativeArguments args, |
178 | intptr_t index) { |
179 | int64_t value = GetNativeIntegerArgument(args, index); |
180 | if (value < kIntptrMin || kIntptrMax < value) { |
181 | Dart_PropagateError(Dart_NewApiError("Value outside intptr_t range" )); |
182 | } |
183 | return static_cast<intptr_t>(value); |
184 | } |
185 | |
186 | const char* DartUtils::GetNativeStringArgument(Dart_NativeArguments args, |
187 | intptr_t index) { |
188 | char* tmp = NULL; |
189 | Dart_Handle result = |
190 | Dart_GetNativeStringArgument(args, index, reinterpret_cast<void**>(&tmp)); |
191 | if (Dart_IsError(result)) { |
192 | Dart_PropagateError(result); |
193 | } |
194 | if (tmp != NULL) { |
195 | return tmp; |
196 | } |
197 | const char* cstring = NULL; |
198 | result = Dart_StringToCString(result, &cstring); |
199 | if (Dart_IsError(result)) { |
200 | Dart_PropagateError(result); |
201 | } |
202 | ASSERT(cstring != NULL); |
203 | return cstring; |
204 | } |
205 | |
206 | Dart_Handle DartUtils::SetIntegerField(Dart_Handle handle, |
207 | const char* name, |
208 | int64_t val) { |
209 | return Dart_SetField(handle, NewString(name), Dart_NewInteger(val)); |
210 | } |
211 | |
212 | Dart_Handle DartUtils::SetStringField(Dart_Handle handle, |
213 | const char* name, |
214 | const char* val) { |
215 | return Dart_SetField(handle, NewString(name), NewString(val)); |
216 | } |
217 | |
218 | bool DartUtils::IsDartSchemeURL(const char* url_name) { |
219 | static const intptr_t kDartSchemeLen = strlen(kDartScheme); |
220 | // If the URL starts with "dart:" then it is considered as a special |
221 | // library URL which is handled differently from other URLs. |
222 | return (strncmp(url_name, kDartScheme, kDartSchemeLen) == 0); |
223 | } |
224 | |
225 | bool DartUtils::IsHttpSchemeURL(const char* url_name) { |
226 | static const intptr_t kHttpSchemeLen = strlen(kHttpScheme); |
227 | return (strncmp(url_name, kHttpScheme, kHttpSchemeLen) == 0); |
228 | } |
229 | |
230 | bool DartUtils::IsDartExtensionSchemeURL(const char* url_name) { |
231 | static const intptr_t kDartExtensionSchemeLen = strlen(kDartExtensionScheme); |
232 | // If the URL starts with "dart-ext:" then it is considered as a special |
233 | // extension library URL which is handled differently from other URLs. |
234 | return (strncmp(url_name, kDartExtensionScheme, kDartExtensionSchemeLen) == |
235 | 0); |
236 | } |
237 | |
238 | bool DartUtils::IsDartIOLibURL(const char* url_name) { |
239 | return (strcmp(url_name, kIOLibURL) == 0); |
240 | } |
241 | |
242 | bool DartUtils::IsDartCLILibURL(const char* url_name) { |
243 | return (strcmp(url_name, kCLILibURL) == 0); |
244 | } |
245 | |
246 | bool DartUtils::IsDartHttpLibURL(const char* url_name) { |
247 | return (strcmp(url_name, kHttpLibURL) == 0); |
248 | } |
249 | |
250 | bool DartUtils::IsDartBuiltinLibURL(const char* url_name) { |
251 | return (strcmp(url_name, kBuiltinLibURL) == 0); |
252 | } |
253 | |
254 | const char* DartUtils::RemoveScheme(const char* url) { |
255 | const char* colon = strchr(url, ':'); |
256 | if (colon == NULL) { |
257 | return url; |
258 | } else { |
259 | return colon + 1; |
260 | } |
261 | } |
262 | |
263 | char* DartUtils::DirName(const char* url) { |
264 | const char* slash = strrchr(url, File::PathSeparator()[0]); |
265 | if (slash == NULL) { |
266 | return Utils::StrDup(url); |
267 | } else { |
268 | return Utils::StrNDup(url, slash - url + 1); |
269 | } |
270 | } |
271 | |
272 | void* DartUtils::OpenFile(const char* name, bool write) { |
273 | File* file = |
274 | File::Open(NULL, name, write ? File::kWriteTruncate : File::kRead); |
275 | return reinterpret_cast<void*>(file); |
276 | } |
277 | |
278 | void* DartUtils::OpenFileUri(const char* uri, bool write) { |
279 | File* file = |
280 | File::OpenUri(NULL, uri, write ? File::kWriteTruncate : File::kRead); |
281 | return reinterpret_cast<void*>(file); |
282 | } |
283 | |
284 | void DartUtils::ReadFile(uint8_t** data, intptr_t* len, void* stream) { |
285 | ASSERT(data != NULL); |
286 | ASSERT(len != NULL); |
287 | ASSERT(stream != NULL); |
288 | File* file_stream = reinterpret_cast<File*>(stream); |
289 | int64_t file_len = file_stream->Length(); |
290 | if ((file_len < 0) || (file_len > kIntptrMax)) { |
291 | *data = NULL; |
292 | *len = -1; // Indicates read was not successful. |
293 | return; |
294 | } |
295 | *len = static_cast<intptr_t>(file_len); |
296 | *data = reinterpret_cast<uint8_t*>(malloc(*len)); |
297 | if (*data == NULL) { |
298 | OUT_OF_MEMORY(); |
299 | } |
300 | if (!file_stream->ReadFully(*data, *len)) { |
301 | free(*data); |
302 | *data = NULL; |
303 | *len = -1; // Indicates read was not successful. |
304 | return; |
305 | } |
306 | } |
307 | |
308 | void DartUtils::WriteFile(const void* buffer, |
309 | intptr_t num_bytes, |
310 | void* stream) { |
311 | ASSERT(stream != NULL); |
312 | File* file_stream = reinterpret_cast<File*>(stream); |
313 | bool bytes_written = file_stream->WriteFully(buffer, num_bytes); |
314 | ASSERT(bytes_written); |
315 | } |
316 | |
317 | void DartUtils::CloseFile(void* stream) { |
318 | File* file = reinterpret_cast<File*>(stream); |
319 | file->Release(); |
320 | } |
321 | |
322 | bool DartUtils::EntropySource(uint8_t* buffer, intptr_t length) { |
323 | return Crypto::GetRandomBytes(length, buffer); |
324 | } |
325 | |
326 | static Dart_Handle SingleArgDart_Invoke(Dart_Handle lib, |
327 | const char* method, |
328 | Dart_Handle arg) { |
329 | const int kNumArgs = 1; |
330 | Dart_Handle dart_args[kNumArgs]; |
331 | dart_args[0] = arg; |
332 | return Dart_Invoke(lib, DartUtils::NewString(method), kNumArgs, dart_args); |
333 | } |
334 | |
335 | // TODO(iposva): Allocate from the zone instead of leaking error string |
336 | // here. On the other hand the binary is about to exit anyway. |
337 | #define SET_ERROR_MSG(error_msg, format, ...) \ |
338 | intptr_t len = snprintf(NULL, 0, format, __VA_ARGS__); \ |
339 | char* msg = reinterpret_cast<char*>(malloc(len + 1)); \ |
340 | snprintf(msg, len + 1, format, __VA_ARGS__); \ |
341 | *error_msg = msg |
342 | |
343 | static uint8_t* ReadFileFully(const char* filename, |
344 | intptr_t* file_len, |
345 | const char** error_msg) { |
346 | *file_len = -1; |
347 | void* stream = DartUtils::OpenFile(filename, false); |
348 | if (stream == NULL) { |
349 | SET_ERROR_MSG(error_msg, "Unable to open file: %s" , filename); |
350 | return NULL; |
351 | } |
352 | uint8_t* text_buffer = NULL; |
353 | DartUtils::ReadFile(&text_buffer, file_len, stream); |
354 | if (text_buffer == NULL || *file_len == -1) { |
355 | *error_msg = "Unable to read file contents" ; |
356 | text_buffer = NULL; |
357 | } |
358 | DartUtils::CloseFile(stream); |
359 | return text_buffer; |
360 | } |
361 | |
362 | Dart_Handle DartUtils::ReadStringFromFile(const char* filename) { |
363 | const char* error_msg = NULL; |
364 | intptr_t len; |
365 | uint8_t* text_buffer = ReadFileFully(filename, &len, &error_msg); |
366 | if (text_buffer == NULL) { |
367 | return Dart_NewApiError(error_msg); |
368 | } |
369 | Dart_Handle str = Dart_NewStringFromUTF8(text_buffer, len); |
370 | free(text_buffer); |
371 | return str; |
372 | } |
373 | |
374 | Dart_Handle DartUtils::MakeUint8Array(const uint8_t* buffer, intptr_t len) { |
375 | Dart_Handle array = Dart_NewTypedData(Dart_TypedData_kUint8, len); |
376 | RETURN_IF_ERROR(array); |
377 | { |
378 | Dart_TypedData_Type td_type; |
379 | void* td_data; |
380 | intptr_t td_len; |
381 | Dart_Handle result = |
382 | Dart_TypedDataAcquireData(array, &td_type, &td_data, &td_len); |
383 | RETURN_IF_ERROR(result); |
384 | ASSERT(td_type == Dart_TypedData_kUint8); |
385 | ASSERT(td_len == len); |
386 | ASSERT(td_data != NULL); |
387 | memmove(td_data, buffer, td_len); |
388 | result = Dart_TypedDataReleaseData(array); |
389 | RETURN_IF_ERROR(result); |
390 | } |
391 | return array; |
392 | } |
393 | |
394 | Dart_Handle DartUtils::SetWorkingDirectory() { |
395 | Dart_Handle directory = NewString(original_working_directory); |
396 | return SingleArgDart_Invoke(LookupBuiltinLib(), "_setWorkingDirectory" , |
397 | directory); |
398 | } |
399 | |
400 | Dart_Handle DartUtils::ResolveScript(Dart_Handle url) { |
401 | const int kNumArgs = 1; |
402 | Dart_Handle dart_args[kNumArgs]; |
403 | dart_args[0] = url; |
404 | return Dart_Invoke(DartUtils::LookupBuiltinLib(), |
405 | NewString("_resolveScriptUri" ), kNumArgs, dart_args); |
406 | } |
407 | |
408 | static bool CheckMagicNumber(const uint8_t* buffer, |
409 | intptr_t buffer_length, |
410 | const MagicNumberData& magic_number) { |
411 | if ((buffer_length >= magic_number.length)) { |
412 | return memcmp(buffer, magic_number.bytes, magic_number.length) == 0; |
413 | } |
414 | return false; |
415 | } |
416 | |
417 | DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const char* filename) { |
418 | MagicNumber magic_number = DartUtils::kUnknownMagicNumber; |
419 | if (File::GetType(NULL, filename, true) == File::kIsFile) { |
420 | File* file = File::Open(NULL, filename, File::kRead); |
421 | if (file != NULL) { |
422 | RefCntReleaseScope<File> rs(file); |
423 | intptr_t max_magic_length = 0; |
424 | max_magic_length = |
425 | Utils::Maximum(max_magic_length, appjit_magic_number.length); |
426 | max_magic_length = |
427 | Utils::Maximum(max_magic_length, kernel_magic_number.length); |
428 | max_magic_length = |
429 | Utils::Maximum(max_magic_length, kernel_list_magic_number.length); |
430 | max_magic_length = |
431 | Utils::Maximum(max_magic_length, gzip_magic_number.length); |
432 | ASSERT(max_magic_length <= 8); |
433 | uint8_t [8]; |
434 | if (file->ReadFully(&header, max_magic_length)) { |
435 | magic_number = DartUtils::SniffForMagicNumber(header, sizeof(header)); |
436 | } |
437 | } |
438 | } |
439 | return magic_number; |
440 | } |
441 | |
442 | DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const uint8_t* buffer, |
443 | intptr_t buffer_length) { |
444 | if (CheckMagicNumber(buffer, buffer_length, appjit_magic_number)) { |
445 | return kAppJITMagicNumber; |
446 | } |
447 | |
448 | if (CheckMagicNumber(buffer, buffer_length, kernel_magic_number)) { |
449 | return kKernelMagicNumber; |
450 | } |
451 | |
452 | if (CheckMagicNumber(buffer, buffer_length, kernel_list_magic_number)) { |
453 | return kKernelListMagicNumber; |
454 | } |
455 | |
456 | if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) { |
457 | return kGzipMagicNumber; |
458 | } |
459 | |
460 | if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) { |
461 | return kGzipMagicNumber; |
462 | } |
463 | |
464 | return kUnknownMagicNumber; |
465 | } |
466 | |
467 | Dart_Handle DartUtils::PrepareBuiltinLibrary(Dart_Handle builtin_lib, |
468 | Dart_Handle internal_lib, |
469 | bool is_service_isolate, |
470 | bool trace_loading) { |
471 | // Setup the internal library's 'internalPrint' function. |
472 | Dart_Handle print = |
473 | Dart_Invoke(builtin_lib, NewString("_getPrintClosure" ), 0, NULL); |
474 | RETURN_IF_ERROR(print); |
475 | Dart_Handle result = |
476 | Dart_SetField(internal_lib, NewString("_printClosure" ), print); |
477 | RETURN_IF_ERROR(result); |
478 | |
479 | if (!is_service_isolate) { |
480 | if (IsWindowsHost()) { |
481 | result = Dart_SetField(builtin_lib, NewString("_isWindows" ), Dart_True()); |
482 | RETURN_IF_ERROR(result); |
483 | } |
484 | if (trace_loading) { |
485 | result = |
486 | Dart_SetField(builtin_lib, NewString("_traceLoading" ), Dart_True()); |
487 | RETURN_IF_ERROR(result); |
488 | } |
489 | // Set current working directory. |
490 | result = SetWorkingDirectory(); |
491 | RETURN_IF_ERROR(result); |
492 | } |
493 | return Dart_True(); |
494 | } |
495 | |
496 | Dart_Handle DartUtils::PrepareCoreLibrary(Dart_Handle core_lib, |
497 | Dart_Handle io_lib, |
498 | bool is_service_isolate) { |
499 | if (!is_service_isolate) { |
500 | // Setup the 'Uri.base' getter in dart:core. |
501 | Dart_Handle uri_base = |
502 | Dart_Invoke(io_lib, NewString("_getUriBaseClosure" ), 0, NULL); |
503 | RETURN_IF_ERROR(uri_base); |
504 | Dart_Handle result = |
505 | Dart_SetField(core_lib, NewString("_uriBaseClosure" ), uri_base); |
506 | RETURN_IF_ERROR(result); |
507 | } |
508 | return Dart_True(); |
509 | } |
510 | |
511 | Dart_Handle DartUtils::PrepareAsyncLibrary(Dart_Handle async_lib, |
512 | Dart_Handle isolate_lib) { |
513 | Dart_Handle schedule_immediate_closure = Dart_Invoke( |
514 | isolate_lib, NewString("_getIsolateScheduleImmediateClosure" ), 0, NULL); |
515 | RETURN_IF_ERROR(schedule_immediate_closure); |
516 | Dart_Handle args[1]; |
517 | args[0] = schedule_immediate_closure; |
518 | return Dart_Invoke(async_lib, NewString("_setScheduleImmediateClosure" ), 1, |
519 | args); |
520 | } |
521 | |
522 | Dart_Handle DartUtils::PrepareIOLibrary(Dart_Handle io_lib) { |
523 | return Dart_Invoke(io_lib, NewString("_setupHooks" ), 0, NULL); |
524 | } |
525 | |
526 | Dart_Handle DartUtils::PrepareIsolateLibrary(Dart_Handle isolate_lib) { |
527 | return Dart_Invoke(isolate_lib, NewString("_setupHooks" ), 0, NULL); |
528 | } |
529 | |
530 | Dart_Handle DartUtils::PrepareCLILibrary(Dart_Handle cli_lib) { |
531 | Dart_Handle wait_for_event_handle = |
532 | Dart_Invoke(cli_lib, NewString("_getWaitForEvent" ), 0, NULL); |
533 | RETURN_IF_ERROR(wait_for_event_handle); |
534 | return Dart_SetField(cli_lib, NewString("_waitForEventClosure" ), |
535 | wait_for_event_handle); |
536 | } |
537 | |
538 | Dart_Handle DartUtils::SetupPackageConfig(const char* packages_config) { |
539 | Dart_Handle result = Dart_Null(); |
540 | |
541 | if (packages_config != NULL) { |
542 | result = NewString(packages_config); |
543 | RETURN_IF_ERROR(result); |
544 | const int kNumArgs = 1; |
545 | Dart_Handle dart_args[kNumArgs]; |
546 | dart_args[0] = result; |
547 | result = Dart_Invoke(DartUtils::LookupBuiltinLib(), |
548 | NewString("_setPackagesMap" ), kNumArgs, dart_args); |
549 | } |
550 | return result; |
551 | } |
552 | |
553 | Dart_Handle DartUtils::PrepareForScriptLoading(bool is_service_isolate, |
554 | bool trace_loading) { |
555 | // First ensure all required libraries are available. |
556 | Dart_Handle url = NewString(kCoreLibURL); |
557 | RETURN_IF_ERROR(url); |
558 | Dart_Handle core_lib = Dart_LookupLibrary(url); |
559 | RETURN_IF_ERROR(core_lib); |
560 | url = NewString(kAsyncLibURL); |
561 | RETURN_IF_ERROR(url); |
562 | Dart_Handle async_lib = Dart_LookupLibrary(url); |
563 | RETURN_IF_ERROR(async_lib); |
564 | url = NewString(kIsolateLibURL); |
565 | RETURN_IF_ERROR(url); |
566 | Dart_Handle isolate_lib = Dart_LookupLibrary(url); |
567 | RETURN_IF_ERROR(isolate_lib); |
568 | url = NewString(kInternalLibURL); |
569 | RETURN_IF_ERROR(url); |
570 | Dart_Handle internal_lib = Dart_LookupLibrary(url); |
571 | RETURN_IF_ERROR(internal_lib); |
572 | Dart_Handle builtin_lib = |
573 | Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary); |
574 | RETURN_IF_ERROR(builtin_lib); |
575 | Builtin::SetNativeResolver(Builtin::kBuiltinLibrary); |
576 | Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary); |
577 | RETURN_IF_ERROR(io_lib); |
578 | Builtin::SetNativeResolver(Builtin::kIOLibrary); |
579 | Dart_Handle cli_lib = Builtin::LoadAndCheckLibrary(Builtin::kCLILibrary); |
580 | RETURN_IF_ERROR(cli_lib); |
581 | Builtin::SetNativeResolver(Builtin::kCLILibrary); |
582 | |
583 | // We need to ensure that all the scripts loaded so far are finalized |
584 | // as we are about to invoke some Dart code below to setup closures. |
585 | Dart_Handle result = Dart_FinalizeLoading(false); |
586 | RETURN_IF_ERROR(result); |
587 | |
588 | result = PrepareBuiltinLibrary(builtin_lib, internal_lib, is_service_isolate, |
589 | trace_loading); |
590 | RETURN_IF_ERROR(result); |
591 | |
592 | RETURN_IF_ERROR(PrepareAsyncLibrary(async_lib, isolate_lib)); |
593 | RETURN_IF_ERROR(PrepareCoreLibrary(core_lib, io_lib, is_service_isolate)); |
594 | RETURN_IF_ERROR(PrepareIsolateLibrary(isolate_lib)); |
595 | RETURN_IF_ERROR(PrepareIOLibrary(io_lib)); |
596 | RETURN_IF_ERROR(PrepareCLILibrary(cli_lib)); |
597 | return result; |
598 | } |
599 | |
600 | Dart_Handle DartUtils::SetupIOLibrary(const char* namespc_path, |
601 | const char* script_uri, |
602 | bool disable_exit) { |
603 | Dart_Handle io_lib_url = NewString(kIOLibURL); |
604 | RETURN_IF_ERROR(io_lib_url); |
605 | Dart_Handle io_lib = Dart_LookupLibrary(io_lib_url); |
606 | RETURN_IF_ERROR(io_lib); |
607 | |
608 | if (namespc_path != NULL) { |
609 | Dart_Handle namespc_type = GetDartType(DartUtils::kIOLibURL, "_Namespace" ); |
610 | RETURN_IF_ERROR(namespc_type); |
611 | Dart_Handle args[1]; |
612 | args[0] = NewString(namespc_path); |
613 | RETURN_IF_ERROR(args[0]); |
614 | Dart_Handle result = |
615 | Dart_Invoke(namespc_type, NewString("_setupNamespace" ), 1, args); |
616 | RETURN_IF_ERROR(result); |
617 | } |
618 | |
619 | if (disable_exit) { |
620 | Dart_Handle embedder_config_type = |
621 | GetDartType(DartUtils::kIOLibURL, "_EmbedderConfig" ); |
622 | RETURN_IF_ERROR(embedder_config_type); |
623 | Dart_Handle result = Dart_SetField(embedder_config_type, |
624 | NewString("_mayExit" ), Dart_False()); |
625 | RETURN_IF_ERROR(result); |
626 | } |
627 | |
628 | Dart_Handle platform_type = GetDartType(DartUtils::kIOLibURL, "_Platform" ); |
629 | RETURN_IF_ERROR(platform_type); |
630 | Dart_Handle script_name = NewString("_nativeScript" ); |
631 | RETURN_IF_ERROR(script_name); |
632 | Dart_Handle dart_script = NewString(script_uri); |
633 | RETURN_IF_ERROR(dart_script); |
634 | Dart_Handle set_script_name = |
635 | Dart_SetField(platform_type, script_name, dart_script); |
636 | RETURN_IF_ERROR(set_script_name); |
637 | |
638 | #if !defined(PRODUCT) |
639 | Dart_Handle network_profiling_type = |
640 | GetDartType(DartUtils::kIOLibURL, "_NetworkProfiling" ); |
641 | RETURN_IF_ERROR(network_profiling_type); |
642 | Dart_Handle result = |
643 | Dart_Invoke(network_profiling_type, |
644 | NewString("_registerServiceExtension" ), 0, nullptr); |
645 | RETURN_IF_ERROR(result); |
646 | #endif // !defined(PRODUCT) |
647 | return Dart_Null(); |
648 | } |
649 | |
650 | bool DartUtils::PostNull(Dart_Port port_id) { |
651 | // Post a message with just the null object. |
652 | return Dart_PostCObject(port_id, CObject::Null()->AsApiCObject()); |
653 | } |
654 | |
655 | bool DartUtils::PostInt32(Dart_Port port_id, int32_t value) { |
656 | // Post a message with the integer value. |
657 | int32_t min = 0xc0000000; // -1073741824 |
658 | int32_t max = 0x3fffffff; // 1073741823 |
659 | ASSERT(min <= value && value < max); |
660 | Dart_CObject object; |
661 | object.type = Dart_CObject_kInt32; |
662 | object.value.as_int32 = value; |
663 | return Dart_PostCObject(port_id, &object); |
664 | } |
665 | |
666 | bool DartUtils::PostInt64(Dart_Port port_id, int64_t value) { |
667 | // Post a message with the integer value. |
668 | Dart_CObject object; |
669 | object.type = Dart_CObject_kInt64; |
670 | object.value.as_int64 = value; |
671 | return Dart_PostCObject(port_id, &object); |
672 | } |
673 | |
674 | Dart_Handle DartUtils::GetDartType(const char* library_url, |
675 | const char* class_name) { |
676 | return Dart_GetNonNullableType(Dart_LookupLibrary(NewString(library_url)), |
677 | NewString(class_name), 0, NULL); |
678 | } |
679 | |
680 | Dart_Handle DartUtils::NewDartOSError() { |
681 | // Extract the current OS error. |
682 | OSError os_error; |
683 | return NewDartOSError(&os_error); |
684 | } |
685 | |
686 | Dart_Handle DartUtils::NewDartOSError(OSError* os_error) { |
687 | // Create a dart:io OSError object with the information retrieved from the OS. |
688 | Dart_Handle type = GetDartType(kIOLibURL, "OSError" ); |
689 | ASSERT(!Dart_IsError(type)); |
690 | Dart_Handle args[2]; |
691 | args[0] = NewString(os_error->message()); |
692 | args[1] = Dart_NewInteger(os_error->code()); |
693 | return Dart_New(type, Dart_Null(), 2, args); |
694 | } |
695 | |
696 | Dart_Handle DartUtils::NewDartExceptionWithOSError(const char* library_url, |
697 | const char* exception_name, |
698 | const char* message, |
699 | Dart_Handle os_error) { |
700 | // Create a Dart Exception object with a message and an OSError. |
701 | Dart_Handle type = GetDartType(library_url, exception_name); |
702 | ASSERT(!Dart_IsError(type)); |
703 | Dart_Handle args[2]; |
704 | args[0] = NewString(message); |
705 | args[1] = os_error; |
706 | return Dart_New(type, Dart_Null(), 2, args); |
707 | } |
708 | |
709 | Dart_Handle DartUtils::NewDartExceptionWithMessage(const char* library_url, |
710 | const char* exception_name, |
711 | const char* message) { |
712 | // Create a Dart Exception object with a message. |
713 | Dart_Handle type = GetDartType(library_url, exception_name); |
714 | ASSERT(!Dart_IsError(type)); |
715 | if (message != NULL) { |
716 | Dart_Handle args[1]; |
717 | args[0] = NewString(message); |
718 | return Dart_New(type, Dart_Null(), 1, args); |
719 | } else { |
720 | return Dart_New(type, Dart_Null(), 0, NULL); |
721 | } |
722 | } |
723 | |
724 | Dart_Handle DartUtils::NewDartArgumentError(const char* message) { |
725 | return NewDartExceptionWithMessage(kCoreLibURL, "ArgumentError" , message); |
726 | } |
727 | |
728 | Dart_Handle DartUtils::NewDartFormatException(const char* message) { |
729 | return NewDartExceptionWithMessage(kCoreLibURL, "FormatException" , message); |
730 | } |
731 | |
732 | Dart_Handle DartUtils::NewDartUnsupportedError(const char* message) { |
733 | return NewDartExceptionWithMessage(kCoreLibURL, "UnsupportedError" , message); |
734 | } |
735 | |
736 | Dart_Handle DartUtils::NewDartIOException(const char* exception_name, |
737 | const char* message, |
738 | Dart_Handle os_error) { |
739 | // Create a dart:io exception object of the given type. |
740 | return NewDartExceptionWithOSError(kIOLibURL, exception_name, message, |
741 | os_error); |
742 | } |
743 | |
744 | Dart_Handle DartUtils::NewError(const char* format, ...) { |
745 | va_list args; |
746 | va_start(args, format); |
747 | intptr_t len = vsnprintf(NULL, 0, format, args); |
748 | va_end(args); |
749 | |
750 | char* buffer = reinterpret_cast<char*>(Dart_ScopeAllocate(len + 1)); |
751 | MSAN_UNPOISON(buffer, (len + 1)); |
752 | va_list args2; |
753 | va_start(args2, format); |
754 | vsnprintf(buffer, (len + 1), format, args2); |
755 | va_end(args2); |
756 | |
757 | return Dart_NewApiError(buffer); |
758 | } |
759 | |
760 | Dart_Handle DartUtils::NewInternalError(const char* message) { |
761 | return NewDartExceptionWithMessage(kCoreLibURL, "_InternalError" , message); |
762 | } |
763 | |
764 | bool DartUtils::SetOriginalWorkingDirectory() { |
765 | // If we happen to re-initialize the Dart VM multiple times, make sure to free |
766 | // the old string (allocated by getcwd()) before setting a new one. |
767 | if (original_working_directory != nullptr) { |
768 | free(const_cast<char*>(original_working_directory)); |
769 | } |
770 | original_working_directory = Directory::CurrentNoScope(); |
771 | return original_working_directory != nullptr; |
772 | } |
773 | |
774 | void DartUtils::SetEnvironment(dart::SimpleHashMap* environment) { |
775 | environment_ = environment; |
776 | } |
777 | |
778 | Dart_Handle DartUtils::EnvironmentCallback(Dart_Handle name) { |
779 | uint8_t* utf8_array; |
780 | intptr_t utf8_len; |
781 | Dart_Handle result = Dart_Null(); |
782 | Dart_Handle handle = Dart_StringToUTF8(name, &utf8_array, &utf8_len); |
783 | if (Dart_IsError(handle)) { |
784 | handle = Dart_ThrowException( |
785 | DartUtils::NewDartArgumentError(Dart_GetError(handle))); |
786 | } else { |
787 | char* name_chars = reinterpret_cast<char*>(malloc(utf8_len + 1)); |
788 | memmove(name_chars, utf8_array, utf8_len); |
789 | name_chars[utf8_len] = '\0'; |
790 | const char* value = NULL; |
791 | if (environment_ != NULL) { |
792 | SimpleHashMap::Entry* entry = |
793 | environment_->Lookup(GetHashmapKeyFromString(name_chars), |
794 | SimpleHashMap::StringHash(name_chars), false); |
795 | if (entry != NULL) { |
796 | value = reinterpret_cast<char*>(entry->value); |
797 | } |
798 | } |
799 | if (value != NULL) { |
800 | result = Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(value), |
801 | strlen(value)); |
802 | if (Dart_IsError(result)) { |
803 | result = Dart_Null(); |
804 | } |
805 | } |
806 | free(name_chars); |
807 | } |
808 | return result; |
809 | } |
810 | |
811 | // Statically allocated Dart_CObject instances for immutable |
812 | // objects. As these will be used by different threads the use of |
813 | // these depends on the fact that the marking internally in the |
814 | // Dart_CObject structure is not marking simple value objects. |
815 | Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {false}}; |
816 | Dart_CObject CObject::api_true_ = {Dart_CObject_kBool, {true}}; |
817 | Dart_CObject CObject::api_false_ = {Dart_CObject_kBool, {false}}; |
818 | CObject CObject::null_(&api_null_); |
819 | CObject CObject::true_(&api_true_); |
820 | CObject CObject::false_(&api_false_); |
821 | |
822 | CObject* CObject::Null() { |
823 | return &null_; |
824 | } |
825 | |
826 | CObject* CObject::True() { |
827 | return &true_; |
828 | } |
829 | |
830 | CObject* CObject::False() { |
831 | return &false_; |
832 | } |
833 | |
834 | CObject* CObject::Bool(bool value) { |
835 | return value ? &true_ : &false_; |
836 | } |
837 | |
838 | Dart_CObject* CObject::New(Dart_CObject_Type type, int additional_bytes) { |
839 | Dart_CObject* cobject = reinterpret_cast<Dart_CObject*>( |
840 | Dart_ScopeAllocate(sizeof(Dart_CObject) + additional_bytes)); |
841 | cobject->type = type; |
842 | return cobject; |
843 | } |
844 | |
845 | Dart_CObject* CObject::NewInt32(int32_t value) { |
846 | Dart_CObject* cobject = New(Dart_CObject_kInt32); |
847 | cobject->value.as_int32 = value; |
848 | return cobject; |
849 | } |
850 | |
851 | Dart_CObject* CObject::NewInt64(int64_t value) { |
852 | Dart_CObject* cobject = New(Dart_CObject_kInt64); |
853 | cobject->value.as_int64 = value; |
854 | return cobject; |
855 | } |
856 | |
857 | Dart_CObject* CObject::NewIntptr(intptr_t value) { |
858 | // Pointer values passed as intptr_t are always send as int64_t. |
859 | Dart_CObject* cobject = New(Dart_CObject_kInt64); |
860 | cobject->value.as_int64 = value; |
861 | return cobject; |
862 | } |
863 | |
864 | Dart_CObject* CObject::NewDouble(double value) { |
865 | Dart_CObject* cobject = New(Dart_CObject_kDouble); |
866 | cobject->value.as_double = value; |
867 | return cobject; |
868 | } |
869 | |
870 | Dart_CObject* CObject::NewString(intptr_t length) { |
871 | Dart_CObject* cobject = New(Dart_CObject_kString, length + 1); |
872 | cobject->value.as_string = reinterpret_cast<char*>(cobject + 1); |
873 | return cobject; |
874 | } |
875 | |
876 | Dart_CObject* CObject::NewString(const char* str) { |
877 | intptr_t length = strlen(str); |
878 | Dart_CObject* cobject = NewString(length); |
879 | memmove(cobject->value.as_string, str, length + 1); |
880 | return cobject; |
881 | } |
882 | |
883 | Dart_CObject* CObject::NewArray(intptr_t length) { |
884 | Dart_CObject* cobject = |
885 | New(Dart_CObject_kArray, length * sizeof(Dart_CObject*)); // NOLINT |
886 | cobject->value.as_array.length = length; |
887 | cobject->value.as_array.values = |
888 | reinterpret_cast<Dart_CObject**>(cobject + 1); |
889 | return cobject; |
890 | } |
891 | |
892 | Dart_CObject* CObject::NewUint8Array(intptr_t length) { |
893 | Dart_CObject* cobject = New(Dart_CObject_kTypedData, length); |
894 | cobject->value.as_typed_data.type = Dart_TypedData_kUint8; |
895 | cobject->value.as_typed_data.length = length; |
896 | cobject->value.as_typed_data.values = reinterpret_cast<uint8_t*>(cobject + 1); |
897 | return cobject; |
898 | } |
899 | |
900 | Dart_CObject* CObject::NewUint32Array(intptr_t length) { |
901 | Dart_CObject* cobject = New(Dart_CObject_kTypedData, 4 * length); |
902 | cobject->value.as_typed_data.type = Dart_TypedData_kUint32; |
903 | cobject->value.as_typed_data.length = length; |
904 | cobject->value.as_typed_data.values = reinterpret_cast<uint8_t*>(cobject + 1); |
905 | return cobject; |
906 | } |
907 | |
908 | Dart_CObject* CObject::NewExternalUint8Array( |
909 | intptr_t length, |
910 | uint8_t* data, |
911 | void* peer, |
912 | Dart_WeakPersistentHandleFinalizer callback) { |
913 | Dart_CObject* cobject = New(Dart_CObject_kExternalTypedData); |
914 | cobject->value.as_external_typed_data.type = Dart_TypedData_kUint8; |
915 | cobject->value.as_external_typed_data.length = length; |
916 | cobject->value.as_external_typed_data.data = data; |
917 | cobject->value.as_external_typed_data.peer = peer; |
918 | cobject->value.as_external_typed_data.callback = callback; |
919 | return cobject; |
920 | } |
921 | |
922 | Dart_CObject* CObject::NewIOBuffer(int64_t length) { |
923 | // Make sure that we do not have an integer overflow here. Actual check |
924 | // against max elements will be done at the time of writing, as the constant |
925 | // is not part of the public API. |
926 | if ((length < 0) || (length > kIntptrMax)) { |
927 | return NULL; |
928 | } |
929 | uint8_t* data = IOBuffer::Allocate(static_cast<intptr_t>(length)); |
930 | if (data == NULL) { |
931 | return NULL; |
932 | } |
933 | return NewExternalUint8Array(static_cast<intptr_t>(length), data, data, |
934 | IOBuffer::Finalizer); |
935 | } |
936 | |
937 | void CObject::FreeIOBufferData(Dart_CObject* cobject) { |
938 | ASSERT(cobject->type == Dart_CObject_kExternalTypedData); |
939 | cobject->value.as_external_typed_data.callback( |
940 | NULL, NULL, cobject->value.as_external_typed_data.peer); |
941 | cobject->value.as_external_typed_data.data = NULL; |
942 | } |
943 | |
944 | CObject* CObject::IllegalArgumentError() { |
945 | CObjectArray* result = new CObjectArray(CObject::NewArray(1)); |
946 | result->SetAt(0, new CObjectInt32(CObject::NewInt32(kArgumentError))); |
947 | return result; |
948 | } |
949 | |
950 | CObject* CObject::FileClosedError() { |
951 | CObjectArray* result = new CObjectArray(CObject::NewArray(1)); |
952 | result->SetAt(0, new CObjectInt32(CObject::NewInt32(kFileClosedError))); |
953 | return result; |
954 | } |
955 | |
956 | CObject* CObject::NewOSError() { |
957 | OSError os_error; |
958 | return NewOSError(&os_error); |
959 | } |
960 | |
961 | CObject* CObject::NewOSError(OSError* os_error) { |
962 | CObject* error_message = |
963 | new CObjectString(CObject::NewString(os_error->message())); |
964 | CObjectArray* result = new CObjectArray(CObject::NewArray(3)); |
965 | result->SetAt(0, new CObjectInt32(CObject::NewInt32(kOSError))); |
966 | result->SetAt(1, new CObjectInt32(CObject::NewInt32(os_error->code()))); |
967 | result->SetAt(2, error_message); |
968 | return result; |
969 | } |
970 | |
971 | } // namespace bin |
972 | } // namespace dart |
973 | |