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
32namespace dart {
33namespace bin {
34
35const char* DartUtils::original_working_directory = NULL;
36const char* const DartUtils::kDartScheme = "dart:";
37const char* const DartUtils::kDartExtensionScheme = "dart-ext:";
38const char* const DartUtils::kAsyncLibURL = "dart:async";
39const char* const DartUtils::kBuiltinLibURL = "dart:_builtin";
40const char* const DartUtils::kCoreLibURL = "dart:core";
41const char* const DartUtils::kInternalLibURL = "dart:_internal";
42const char* const DartUtils::kIsolateLibURL = "dart:isolate";
43const char* const DartUtils::kHttpLibURL = "dart:_http";
44const char* const DartUtils::kIOLibURL = "dart:io";
45const char* const DartUtils::kIOLibPatchURL = "dart:io-patch";
46const char* const DartUtils::kCLILibURL = "dart:cli";
47const char* const DartUtils::kCLILibPatchURL = "dart:cli-patch";
48const char* const DartUtils::kUriLibURL = "dart:uri";
49const char* const DartUtils::kHttpScheme = "http:";
50const char* const DartUtils::kVMServiceLibURL = "dart:vmservice";
51
52dart::SimpleHashMap* DartUtils::environment_ = NULL;
53
54MagicNumberData appjit_magic_number = {8, {0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0}};
55MagicNumberData kernel_magic_number = {4, {0x90, 0xab, 0xcd, 0xef}};
56MagicNumberData kernel_list_magic_number = {
57 7,
58 {0x23, 0x40, 0x64, 0x69, 0x6c, 0x6c, 0x0a}}; // #@dill\n
59MagicNumberData gzip_magic_number = {2, {0x1f, 0x8b, 0, 0}};
60
61static 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
69Dart_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
92int64_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
101int64_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
111intptr_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
123bool 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
139const 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
148bool 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
157bool 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
167int64_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
177intptr_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
186const 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
206Dart_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
212Dart_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
218bool 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
225bool DartUtils::IsHttpSchemeURL(const char* url_name) {
226 static const intptr_t kHttpSchemeLen = strlen(kHttpScheme);
227 return (strncmp(url_name, kHttpScheme, kHttpSchemeLen) == 0);
228}
229
230bool 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
238bool DartUtils::IsDartIOLibURL(const char* url_name) {
239 return (strcmp(url_name, kIOLibURL) == 0);
240}
241
242bool DartUtils::IsDartCLILibURL(const char* url_name) {
243 return (strcmp(url_name, kCLILibURL) == 0);
244}
245
246bool DartUtils::IsDartHttpLibURL(const char* url_name) {
247 return (strcmp(url_name, kHttpLibURL) == 0);
248}
249
250bool DartUtils::IsDartBuiltinLibURL(const char* url_name) {
251 return (strcmp(url_name, kBuiltinLibURL) == 0);
252}
253
254const 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
263char* 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
272void* 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
278void* 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
284void 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
308void 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
317void DartUtils::CloseFile(void* stream) {
318 File* file = reinterpret_cast<File*>(stream);
319 file->Release();
320}
321
322bool DartUtils::EntropySource(uint8_t* buffer, intptr_t length) {
323 return Crypto::GetRandomBytes(length, buffer);
324}
325
326static 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
343static 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
362Dart_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
374Dart_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
394Dart_Handle DartUtils::SetWorkingDirectory() {
395 Dart_Handle directory = NewString(original_working_directory);
396 return SingleArgDart_Invoke(LookupBuiltinLib(), "_setWorkingDirectory",
397 directory);
398}
399
400Dart_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
408static 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
417DartUtils::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 header[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
442DartUtils::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
467Dart_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
496Dart_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
511Dart_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
522Dart_Handle DartUtils::PrepareIOLibrary(Dart_Handle io_lib) {
523 return Dart_Invoke(io_lib, NewString("_setupHooks"), 0, NULL);
524}
525
526Dart_Handle DartUtils::PrepareIsolateLibrary(Dart_Handle isolate_lib) {
527 return Dart_Invoke(isolate_lib, NewString("_setupHooks"), 0, NULL);
528}
529
530Dart_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
538Dart_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
553Dart_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
600Dart_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
650bool 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
655bool 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
666bool 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
674Dart_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
680Dart_Handle DartUtils::NewDartOSError() {
681 // Extract the current OS error.
682 OSError os_error;
683 return NewDartOSError(&os_error);
684}
685
686Dart_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
696Dart_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
709Dart_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
724Dart_Handle DartUtils::NewDartArgumentError(const char* message) {
725 return NewDartExceptionWithMessage(kCoreLibURL, "ArgumentError", message);
726}
727
728Dart_Handle DartUtils::NewDartFormatException(const char* message) {
729 return NewDartExceptionWithMessage(kCoreLibURL, "FormatException", message);
730}
731
732Dart_Handle DartUtils::NewDartUnsupportedError(const char* message) {
733 return NewDartExceptionWithMessage(kCoreLibURL, "UnsupportedError", message);
734}
735
736Dart_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
744Dart_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
760Dart_Handle DartUtils::NewInternalError(const char* message) {
761 return NewDartExceptionWithMessage(kCoreLibURL, "_InternalError", message);
762}
763
764bool 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
774void DartUtils::SetEnvironment(dart::SimpleHashMap* environment) {
775 environment_ = environment;
776}
777
778Dart_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.
815Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {false}};
816Dart_CObject CObject::api_true_ = {Dart_CObject_kBool, {true}};
817Dart_CObject CObject::api_false_ = {Dart_CObject_kBool, {false}};
818CObject CObject::null_(&api_null_);
819CObject CObject::true_(&api_true_);
820CObject CObject::false_(&api_false_);
821
822CObject* CObject::Null() {
823 return &null_;
824}
825
826CObject* CObject::True() {
827 return &true_;
828}
829
830CObject* CObject::False() {
831 return &false_;
832}
833
834CObject* CObject::Bool(bool value) {
835 return value ? &true_ : &false_;
836}
837
838Dart_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
845Dart_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
851Dart_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
857Dart_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
864Dart_CObject* CObject::NewDouble(double value) {
865 Dart_CObject* cobject = New(Dart_CObject_kDouble);
866 cobject->value.as_double = value;
867 return cobject;
868}
869
870Dart_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
876Dart_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
883Dart_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
892Dart_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
900Dart_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
908Dart_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
922Dart_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
937void 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
944CObject* CObject::IllegalArgumentError() {
945 CObjectArray* result = new CObjectArray(CObject::NewArray(1));
946 result->SetAt(0, new CObjectInt32(CObject::NewInt32(kArgumentError)));
947 return result;
948}
949
950CObject* CObject::FileClosedError() {
951 CObjectArray* result = new CObjectArray(CObject::NewArray(1));
952 result->SetAt(0, new CObjectInt32(CObject::NewInt32(kFileClosedError)));
953 return result;
954}
955
956CObject* CObject::NewOSError() {
957 OSError os_error;
958 return NewOSError(&os_error);
959}
960
961CObject* 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