blob: e7c7886e15400da6fe56a422de512ad24e97c000 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
#include "bin/crypto.h"
#include "bin/directory.h"
#include "bin/extensions.h"
#include "bin/file.h"
#include "bin/io_buffer.h"
#include "bin/namespace.h"
#include "bin/platform.h"
#include "bin/utils.h"
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "include/dart_tools_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "platform/memory_sanitizer.h"
#include "platform/utils.h"
// Return the error from the containing function if handle is in error handle.
#define RETURN_IF_ERROR(handle) \
{ \
Dart_Handle __handle = handle; \
if (Dart_IsError((__handle))) { \
return __handle; \
} \
}
namespace dart {
namespace bin {
const char* DartUtils::original_working_directory = NULL;
CommandLineOptions* DartUtils::url_mapping = NULL;
const char* const DartUtils::kDartScheme = "dart:";
const char* const DartUtils::kDartExtensionScheme = "dart-ext:";
const char* const DartUtils::kAsyncLibURL = "dart:async";
const char* const DartUtils::kBuiltinLibURL = "dart:_builtin";
const char* const DartUtils::kCoreLibURL = "dart:core";
const char* const DartUtils::kInternalLibURL = "dart:_internal";
const char* const DartUtils::kIsolateLibURL = "dart:isolate";
const char* const DartUtils::kHttpLibURL = "dart:_http";
const char* const DartUtils::kIOLibURL = "dart:io";
const char* const DartUtils::kIOLibPatchURL = "dart:io-patch";
const char* const DartUtils::kCLILibURL = "dart:cli";
const char* const DartUtils::kCLILibPatchURL = "dart:cli-patch";
const char* const DartUtils::kUriLibURL = "dart:uri";
const char* const DartUtils::kHttpScheme = "http:";
const char* const DartUtils::kVMServiceLibURL = "dart:vmservice";
MagicNumberData appjit_magic_number = {8, {0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0}};
MagicNumberData snapshot_magic_number = {4, {0xf5, 0xf5, 0xdc, 0xdc}};
MagicNumberData kernel_magic_number = {4, {0x90, 0xab, 0xcd, 0xef}};
MagicNumberData gzip_magic_number = {2, {0x1f, 0x8b, 0, 0}};
static bool IsWindowsHost() {
#if defined(HOST_OS_WINDOWS)
return true;
#else // defined(HOST_OS_WINDOWS)
return false;
#endif // defined(HOST_OS_WINDOWS)
}
const char* DartUtils::MapLibraryUrl(const char* url_string) {
ASSERT(url_mapping != NULL);
// We need to check if the passed in url is found in the url_mapping array,
// in that case use the mapped entry.
intptr_t len = strlen(url_string);
for (intptr_t idx = 0; idx < url_mapping->count(); idx++) {
const char* url_name = url_mapping->GetArgument(idx);
if (!strncmp(url_string, url_name, len) && (url_name[len] == ',')) {
const char* url_mapped_name = url_name + len + 1;
if (strlen(url_mapped_name) != 0) {
return url_mapped_name; // Found a mapping for this URL.
}
}
}
return NULL; // Did not find a mapping for this URL.
}
int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) {
int64_t value = 0;
Dart_Handle result = Dart_IntegerToInt64(value_obj, &value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return value;
}
int64_t DartUtils::GetInt64ValueCheckRange(Dart_Handle value_obj,
int64_t lower,
int64_t upper) {
int64_t value = DartUtils::GetIntegerValue(value_obj);
if (value < lower || upper < value) {
Dart_PropagateError(Dart_NewApiError("Value outside expected range"));
}
return value;
}
intptr_t DartUtils::GetIntptrValue(Dart_Handle value_obj) {
int64_t value = 0;
Dart_Handle result = Dart_IntegerToInt64(value_obj, &value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
if (value < kIntptrMin || kIntptrMax < value) {
Dart_PropagateError(Dart_NewApiError("Value outside intptr_t range"));
}
return static_cast<intptr_t>(value);
}
bool DartUtils::GetInt64Value(Dart_Handle value_obj, int64_t* value) {
bool valid = Dart_IsInteger(value_obj);
if (valid) {
Dart_Handle result = Dart_IntegerFitsIntoInt64(value_obj, &valid);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
}
if (!valid) return false;
Dart_Handle result = Dart_IntegerToInt64(value_obj, value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return true;
}
const char* DartUtils::GetStringValue(Dart_Handle str_obj) {
const char* cstring = NULL;
Dart_Handle result = Dart_StringToCString(str_obj, &cstring);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return cstring;
}
bool DartUtils::GetBooleanValue(Dart_Handle bool_obj) {
bool value = false;
Dart_Handle result = Dart_BooleanValue(bool_obj, &value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return value;
}
bool DartUtils::GetNativeBooleanArgument(Dart_NativeArguments args,
intptr_t index) {
bool value = false;
Dart_Handle result = Dart_GetNativeBooleanArgument(args, index, &value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return value;
}
int64_t DartUtils::GetNativeIntegerArgument(Dart_NativeArguments args,
intptr_t index) {
int64_t value = 0;
Dart_Handle result = Dart_GetNativeIntegerArgument(args, index, &value);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
return value;
}
intptr_t DartUtils::GetNativeIntptrArgument(Dart_NativeArguments args,
intptr_t index) {
int64_t value = GetNativeIntegerArgument(args, index);
if (value < kIntptrMin || kIntptrMax < value) {
Dart_PropagateError(Dart_NewApiError("Value outside intptr_t range"));
}
return static_cast<intptr_t>(value);
}
const char* DartUtils::GetNativeStringArgument(Dart_NativeArguments args,
intptr_t index) {
char* tmp = NULL;
Dart_Handle result =
Dart_GetNativeStringArgument(args, index, reinterpret_cast<void**>(&tmp));
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
if (tmp != NULL) {
return tmp;
}
const char* cstring = NULL;
result = Dart_StringToCString(result, &cstring);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
ASSERT(cstring != NULL);
return cstring;
}
Dart_Handle DartUtils::SetIntegerField(Dart_Handle handle,
const char* name,
int64_t val) {
return Dart_SetField(handle, NewString(name), Dart_NewInteger(val));
}
Dart_Handle DartUtils::SetStringField(Dart_Handle handle,
const char* name,
const char* val) {
return Dart_SetField(handle, NewString(name), NewString(val));
}
bool DartUtils::IsDartSchemeURL(const char* url_name) {
static const intptr_t kDartSchemeLen = strlen(kDartScheme);
// If the URL starts with "dart:" then it is considered as a special
// library URL which is handled differently from other URLs.
return (strncmp(url_name, kDartScheme, kDartSchemeLen) == 0);
}
bool DartUtils::IsHttpSchemeURL(const char* url_name) {
static const intptr_t kHttpSchemeLen = strlen(kHttpScheme);
return (strncmp(url_name, kHttpScheme, kHttpSchemeLen) == 0);
}
bool DartUtils::IsDartExtensionSchemeURL(const char* url_name) {
static const intptr_t kDartExtensionSchemeLen = strlen(kDartExtensionScheme);
// If the URL starts with "dartext:" then it is considered as a special
// extension library URL which is handled differently from other URLs.
return (strncmp(url_name, kDartExtensionScheme, kDartExtensionSchemeLen) ==
0);
}
bool DartUtils::IsDartIOLibURL(const char* url_name) {
return (strcmp(url_name, kIOLibURL) == 0);
}
bool DartUtils::IsDartCLILibURL(const char* url_name) {
return (strcmp(url_name, kCLILibURL) == 0);
}
bool DartUtils::IsDartHttpLibURL(const char* url_name) {
return (strcmp(url_name, kHttpLibURL) == 0);
}
bool DartUtils::IsDartBuiltinLibURL(const char* url_name) {
return (strcmp(url_name, kBuiltinLibURL) == 0);
}
const char* DartUtils::RemoveScheme(const char* url) {
const char* colon = strchr(url, ':');
if (colon == NULL) {
return url;
} else {
return colon + 1;
}
}
char* DartUtils::DirName(const char* url) {
const char* slash = strrchr(url, File::PathSeparator()[0]);
if (slash == NULL) {
return strdup(url);
} else {
return Utils::StrNDup(url, slash - url + 1);
}
}
void* DartUtils::OpenFile(const char* name, bool write) {
File* file =
File::Open(NULL, name, write ? File::kWriteTruncate : File::kRead);
return reinterpret_cast<void*>(file);
}
void* DartUtils::OpenFileUri(const char* uri, bool write) {
File* file =
File::OpenUri(NULL, uri, write ? File::kWriteTruncate : File::kRead);
return reinterpret_cast<void*>(file);
}
void DartUtils::ReadFile(uint8_t** data, intptr_t* len, void* stream) {
ASSERT(data != NULL);
ASSERT(len != NULL);
ASSERT(stream != NULL);
File* file_stream = reinterpret_cast<File*>(stream);
int64_t file_len = file_stream->Length();
if ((file_len < 0) || (file_len > kIntptrMax)) {
*data = NULL;
*len = -1; // Indicates read was not successful.
return;
}
*len = static_cast<intptr_t>(file_len);
*data = reinterpret_cast<uint8_t*>(malloc(*len));
if (*data == NULL) {
OUT_OF_MEMORY();
}
if (!file_stream->ReadFully(*data, *len)) {
free(*data);
*data = NULL;
*len = -1; // Indicates read was not successful.
return;
}
}
void DartUtils::WriteFile(const void* buffer,
intptr_t num_bytes,
void* stream) {
ASSERT(stream != NULL);
File* file_stream = reinterpret_cast<File*>(stream);
bool bytes_written = file_stream->WriteFully(buffer, num_bytes);
ASSERT(bytes_written);
}
void DartUtils::CloseFile(void* stream) {
File* file = reinterpret_cast<File*>(stream);
file->Release();
}
bool DartUtils::EntropySource(uint8_t* buffer, intptr_t length) {
return Crypto::GetRandomBytes(length, buffer);
}
static Dart_Handle SingleArgDart_Invoke(Dart_Handle lib,
const char* method,
Dart_Handle arg) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = arg;
return Dart_Invoke(lib, DartUtils::NewString(method), kNumArgs, dart_args);
}
// TODO(iposva): Allocate from the zone instead of leaking error string
// here. On the other hand the binary is about to exit anyway.
#define SET_ERROR_MSG(error_msg, format, ...) \
intptr_t len = snprintf(NULL, 0, format, __VA_ARGS__); \
char* msg = reinterpret_cast<char*>(malloc(len + 1)); \
snprintf(msg, len + 1, format, __VA_ARGS__); \
*error_msg = msg
static uint8_t* ReadFileFully(const char* filename,
intptr_t* file_len,
const char** error_msg) {
*file_len = -1;
void* stream = DartUtils::OpenFile(filename, false);
if (stream == NULL) {
SET_ERROR_MSG(error_msg, "Unable to open file: %s", filename);
return NULL;
}
uint8_t* text_buffer = NULL;
DartUtils::ReadFile(&text_buffer, file_len, stream);
if (text_buffer == NULL || *file_len == -1) {
*error_msg = "Unable to read file contents";
text_buffer = NULL;
}
DartUtils::CloseFile(stream);
return text_buffer;
}
Dart_Handle DartUtils::ReadStringFromFile(const char* filename) {
const char* error_msg = NULL;
intptr_t len;
uint8_t* text_buffer = ReadFileFully(filename, &len, &error_msg);
if (text_buffer == NULL) {
return Dart_NewApiError(error_msg);
}
Dart_Handle str = Dart_NewStringFromUTF8(text_buffer, len);
free(text_buffer);
return str;
}
Dart_Handle DartUtils::MakeUint8Array(const uint8_t* buffer, intptr_t len) {
Dart_Handle array = Dart_NewTypedData(Dart_TypedData_kUint8, len);
RETURN_IF_ERROR(array);
{
Dart_TypedData_Type td_type;
void* td_data;
intptr_t td_len;
Dart_Handle result =
Dart_TypedDataAcquireData(array, &td_type, &td_data, &td_len);
RETURN_IF_ERROR(result);
ASSERT(td_type == Dart_TypedData_kUint8);
ASSERT(td_len == len);
ASSERT(td_data != NULL);
memmove(td_data, buffer, td_len);
result = Dart_TypedDataReleaseData(array);
RETURN_IF_ERROR(result);
}
return array;
}
Dart_Handle DartUtils::SetWorkingDirectory() {
IsolateData* isolate_data =
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
Dart_Handle builtin_lib = isolate_data->builtin_lib();
Dart_Handle directory = NewString(original_working_directory);
return SingleArgDart_Invoke(builtin_lib, "_setWorkingDirectory", directory);
}
Dart_Handle DartUtils::ResolveUriInWorkingDirectory(Dart_Handle script_uri) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = script_uri;
return Dart_Invoke(DartUtils::BuiltinLib(),
NewString("_resolveInWorkingDirectory"), kNumArgs,
dart_args);
}
Dart_Handle DartUtils::LibraryFilePath(Dart_Handle library_uri) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = library_uri;
return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_libraryFilePath"),
kNumArgs, dart_args);
}
Dart_Handle DartUtils::ResolveScript(Dart_Handle url) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = url;
return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_resolveScriptUri"),
kNumArgs, dart_args);
}
static bool CheckMagicNumber(const uint8_t* buffer,
intptr_t buffer_length,
const MagicNumberData& magic_number) {
if ((buffer_length >= magic_number.length)) {
return memcmp(buffer, magic_number.bytes, magic_number.length) == 0;
}
return false;
}
DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const char* filename) {
MagicNumber magic_number = DartUtils::kUnknownMagicNumber;
if (File::GetType(NULL, filename, true) == File::kIsFile) {
File* file = File::Open(NULL, filename, File::kRead);
if (file != NULL) {
RefCntReleaseScope<File> rs(file);
intptr_t max_magic_length = 0;
max_magic_length =
Utils::Maximum(max_magic_length, snapshot_magic_number.length);
max_magic_length =
Utils::Maximum(max_magic_length, appjit_magic_number.length);
max_magic_length =
Utils::Maximum(max_magic_length, kernel_magic_number.length);
max_magic_length =
Utils::Maximum(max_magic_length, gzip_magic_number.length);
ASSERT(max_magic_length <= 8);
uint8_t header[8];
if (file->ReadFully(&header, max_magic_length)) {
magic_number = DartUtils::SniffForMagicNumber(header, sizeof(header));
}
}
}
return magic_number;
}
DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const uint8_t* buffer,
intptr_t buffer_length) {
if (CheckMagicNumber(buffer, buffer_length, snapshot_magic_number)) {
return kSnapshotMagicNumber;
}
if (CheckMagicNumber(buffer, buffer_length, appjit_magic_number)) {
return kAppJITMagicNumber;
}
if (CheckMagicNumber(buffer, buffer_length, kernel_magic_number)) {
return kKernelMagicNumber;
}
if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) {
return kGzipMagicNumber;
}
if (CheckMagicNumber(buffer, buffer_length, gzip_magic_number)) {
return kGzipMagicNumber;
}
return kUnknownMagicNumber;
}
Dart_Handle DartUtils::PrepareBuiltinLibrary(Dart_Handle builtin_lib,
Dart_Handle internal_lib,
bool is_service_isolate,
bool trace_loading) {
// Setup the internal library's 'internalPrint' function.
Dart_Handle print =
Dart_Invoke(builtin_lib, NewString("_getPrintClosure"), 0, NULL);
RETURN_IF_ERROR(print);
Dart_Handle result =
Dart_SetField(internal_lib, NewString("_printClosure"), print);
RETURN_IF_ERROR(result);
if (!is_service_isolate) {
if (IsWindowsHost()) {
result = Dart_SetField(builtin_lib, NewString("_isWindows"), Dart_True());
RETURN_IF_ERROR(result);
}
if (trace_loading) {
result =
Dart_SetField(builtin_lib, NewString("_traceLoading"), Dart_True());
RETURN_IF_ERROR(result);
}
// Set current working directory.
result = SetWorkingDirectory();
RETURN_IF_ERROR(result);
}
return Dart_True();
}
Dart_Handle DartUtils::PrepareCoreLibrary(Dart_Handle core_lib,
Dart_Handle io_lib,
bool is_service_isolate) {
if (!is_service_isolate) {
// Setup the 'Uri.base' getter in dart:core.
Dart_Handle uri_base =
Dart_Invoke(io_lib, NewString("_getUriBaseClosure"), 0, NULL);
RETURN_IF_ERROR(uri_base);
Dart_Handle result =
Dart_SetField(core_lib, NewString("_uriBaseClosure"), uri_base);
RETURN_IF_ERROR(result);
}
return Dart_True();
}
Dart_Handle DartUtils::PrepareAsyncLibrary(Dart_Handle async_lib,
Dart_Handle isolate_lib) {
Dart_Handle schedule_immediate_closure = Dart_Invoke(
isolate_lib, NewString("_getIsolateScheduleImmediateClosure"), 0, NULL);
RETURN_IF_ERROR(schedule_immediate_closure);
Dart_Handle args[1];
args[0] = schedule_immediate_closure;
return Dart_Invoke(async_lib, NewString("_setScheduleImmediateClosure"), 1,
args);
}
Dart_Handle DartUtils::PrepareIOLibrary(Dart_Handle io_lib) {
return Dart_Invoke(io_lib, NewString("_setupHooks"), 0, NULL);
}
Dart_Handle DartUtils::PrepareIsolateLibrary(Dart_Handle isolate_lib) {
return Dart_Invoke(isolate_lib, NewString("_setupHooks"), 0, NULL);
}
Dart_Handle DartUtils::PrepareCLILibrary(Dart_Handle cli_lib) {
Dart_Handle wait_for_event_handle =
Dart_Invoke(cli_lib, NewString("_getWaitForEvent"), 0, NULL);
RETURN_IF_ERROR(wait_for_event_handle);
return Dart_SetField(cli_lib, NewString("_waitForEventClosure"),
wait_for_event_handle);
}
Dart_Handle DartUtils::SetupServiceLoadPort() {
// Wait for the service isolate to initialize the load port.
Dart_Port load_port = Dart_ServiceWaitForLoadPort();
if (load_port == ILLEGAL_PORT) {
return Dart_NewUnhandledExceptionError(
NewDartUnsupportedError("Service did not return load port."));
}
return Builtin::SetLoadPort(load_port);
}
Dart_Handle DartUtils::SetupPackageRoot(const char* package_root,
const char* packages_config) {
Dart_Handle result = Dart_Null();
// Set up package root if specified.
if (package_root != NULL) {
ASSERT(packages_config == NULL);
result = NewString(package_root);
RETURN_IF_ERROR(result);
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = result;
result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackageRoot"),
kNumArgs, dart_args);
} else if (packages_config != NULL) {
result = NewString(packages_config);
RETURN_IF_ERROR(result);
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = result;
result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackagesMap"),
kNumArgs, dart_args);
}
return result;
}
Dart_Handle DartUtils::PrepareForScriptLoading(bool is_service_isolate,
bool trace_loading) {
// First ensure all required libraries are available.
Dart_Handle url = NewString(kCoreLibURL);
RETURN_IF_ERROR(url);
Dart_Handle core_lib = Dart_LookupLibrary(url);
RETURN_IF_ERROR(core_lib);
url = NewString(kAsyncLibURL);
RETURN_IF_ERROR(url);
Dart_Handle async_lib = Dart_LookupLibrary(url);
RETURN_IF_ERROR(async_lib);
url = NewString(kIsolateLibURL);
RETURN_IF_ERROR(url);
Dart_Handle isolate_lib = Dart_LookupLibrary(url);
RETURN_IF_ERROR(isolate_lib);
url = NewString(kInternalLibURL);
RETURN_IF_ERROR(url);
Dart_Handle internal_lib = Dart_LookupLibrary(url);
RETURN_IF_ERROR(internal_lib);
Dart_Handle builtin_lib =
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
RETURN_IF_ERROR(builtin_lib);
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
RETURN_IF_ERROR(io_lib);
Builtin::SetNativeResolver(Builtin::kIOLibrary);
Dart_Handle cli_lib = Builtin::LoadAndCheckLibrary(Builtin::kCLILibrary);
RETURN_IF_ERROR(cli_lib);
Builtin::SetNativeResolver(Builtin::kCLILibrary);
// Setup the builtin library in a persistent handle attached the isolate
// specific data as we seem to lookup and use builtin lib a lot.
IsolateData* isolate_data =
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
ASSERT(isolate_data != NULL);
isolate_data->set_builtin_lib(builtin_lib);
// We need to ensure that all the scripts loaded so far are finalized
// as we are about to invoke some Dart code below to setup closures.
Dart_Handle result = Dart_FinalizeLoading(false);
RETURN_IF_ERROR(result);
result = PrepareBuiltinLibrary(builtin_lib, internal_lib, is_service_isolate,
trace_loading);
RETURN_IF_ERROR(result);
RETURN_IF_ERROR(PrepareAsyncLibrary(async_lib, isolate_lib));
RETURN_IF_ERROR(PrepareCoreLibrary(core_lib, io_lib, is_service_isolate));
RETURN_IF_ERROR(PrepareIsolateLibrary(isolate_lib));
RETURN_IF_ERROR(PrepareIOLibrary(io_lib));
RETURN_IF_ERROR(PrepareCLILibrary(cli_lib));
return result;
}
Dart_Handle DartUtils::SetupIOLibrary(const char* namespc_path,
const char* script_uri,
bool disable_exit) {
Dart_Handle io_lib_url = NewString(kIOLibURL);
RETURN_IF_ERROR(io_lib_url);
Dart_Handle io_lib = Dart_LookupLibrary(io_lib_url);
RETURN_IF_ERROR(io_lib);
if (namespc_path != NULL) {
Dart_Handle namespc_type = GetDartType(DartUtils::kIOLibURL, "_Namespace");
RETURN_IF_ERROR(namespc_type);
Dart_Handle args[1];
args[0] = NewString(namespc_path);
RETURN_IF_ERROR(args[0]);
Dart_Handle result =
Dart_Invoke(namespc_type, NewString("_setupNamespace"), 1, args);
RETURN_IF_ERROR(result);
}
if (disable_exit) {
Dart_Handle embedder_config_type =
GetDartType(DartUtils::kIOLibURL, "_EmbedderConfig");
RETURN_IF_ERROR(embedder_config_type);
Dart_Handle result = Dart_SetField(embedder_config_type,
NewString("_mayExit"), Dart_False());
RETURN_IF_ERROR(result);
}
Dart_Handle platform_type = GetDartType(DartUtils::kIOLibURL, "_Platform");
RETURN_IF_ERROR(platform_type);
Dart_Handle script_name = NewString("_nativeScript");
RETURN_IF_ERROR(script_name);
Dart_Handle dart_script = NewString(script_uri);
RETURN_IF_ERROR(dart_script);
Dart_Handle set_script_name =
Dart_SetField(platform_type, script_name, dart_script);
RETURN_IF_ERROR(set_script_name);
return Dart_Null();
}
bool DartUtils::PostNull(Dart_Port port_id) {
// Post a message with just the null object.
return Dart_PostCObject(port_id, CObject::Null()->AsApiCObject());
}
bool DartUtils::PostInt32(Dart_Port port_id, int32_t value) {
// Post a message with the integer value.
int32_t min = 0xc0000000; // -1073741824
int32_t max = 0x3fffffff; // 1073741823
ASSERT(min <= value && value < max);
Dart_CObject object;
object.type = Dart_CObject_kInt32;
object.value.as_int32 = value;
return Dart_PostCObject(port_id, &object);
}
bool DartUtils::PostInt64(Dart_Port port_id, int64_t value) {
// Post a message with the integer value.
Dart_CObject object;
object.type = Dart_CObject_kInt64;
object.value.as_int64 = value;
return Dart_PostCObject(port_id, &object);
}
Dart_Handle DartUtils::GetDartType(const char* library_url,
const char* class_name) {
return Dart_GetType(Dart_LookupLibrary(NewString(library_url)),
NewString(class_name), 0, NULL);
}
Dart_Handle DartUtils::NewDartOSError() {
// Extract the current OS error.
OSError os_error;
return NewDartOSError(&os_error);
}
Dart_Handle DartUtils::NewDartOSError(OSError* os_error) {
// Create a dart:io OSError object with the information retrieved from the OS.
Dart_Handle type = GetDartType(kIOLibURL, "OSError");
ASSERT(!Dart_IsError(type));
Dart_Handle args[2];
args[0] = NewString(os_error->message());
args[1] = Dart_NewInteger(os_error->code());
return Dart_New(type, Dart_Null(), 2, args);
}
Dart_Handle DartUtils::NewDartExceptionWithOSError(const char* library_url,
const char* exception_name,
const char* message,
Dart_Handle os_error) {
// Create a Dart Exception object with a message and an OSError.
Dart_Handle type = GetDartType(library_url, exception_name);
ASSERT(!Dart_IsError(type));
Dart_Handle args[2];
args[0] = NewString(message);
args[1] = os_error;
return Dart_New(type, Dart_Null(), 2, args);
}
Dart_Handle DartUtils::NewDartExceptionWithMessage(const char* library_url,
const char* exception_name,
const char* message) {
// Create a Dart Exception object with a message.
Dart_Handle type = GetDartType(library_url, exception_name);
ASSERT(!Dart_IsError(type));
if (message != NULL) {
Dart_Handle args[1];
args[0] = NewString(message);
return Dart_New(type, Dart_Null(), 1, args);
} else {
return Dart_New(type, Dart_Null(), 0, NULL);
}
}
Dart_Handle DartUtils::NewDartArgumentError(const char* message) {
return NewDartExceptionWithMessage(kCoreLibURL, "ArgumentError", message);
}
Dart_Handle DartUtils::NewDartUnsupportedError(const char* message) {
return NewDartExceptionWithMessage(kCoreLibURL, "UnsupportedError", message);
}
Dart_Handle DartUtils::NewDartIOException(const char* exception_name,
const char* message,
Dart_Handle os_error) {
// Create a dart:io exception object of the given type.
return NewDartExceptionWithOSError(kIOLibURL, exception_name, message,
os_error);
}
Dart_Handle DartUtils::NewError(const char* format, ...) {
va_list args;
va_start(args, format);
intptr_t len = vsnprintf(NULL, 0, format, args);
va_end(args);
char* buffer = reinterpret_cast<char*>(Dart_ScopeAllocate(len + 1));
MSAN_UNPOISON(buffer, (len + 1));
va_list args2;
va_start(args2, format);
vsnprintf(buffer, (len + 1), format, args2);
va_end(args2);
return Dart_NewApiError(buffer);
}
Dart_Handle DartUtils::NewInternalError(const char* message) {
return NewDartExceptionWithMessage(kCoreLibURL, "_InternalError", message);
}
bool DartUtils::SetOriginalWorkingDirectory() {
original_working_directory = Directory::CurrentNoScope();
return original_working_directory != NULL;
}
Dart_Handle DartUtils::GetCanonicalizableWorkingDirectory() {
const char* str = DartUtils::original_working_directory;
intptr_t len = strlen(str);
if ((str[len] == '/') || (IsWindowsHost() && str[len] == '\\')) {
return Dart_NewStringFromCString(str);
}
char* new_str = reinterpret_cast<char*>(Dart_ScopeAllocate(len + 2));
snprintf(new_str, (len + 2), "%s%s", str, File::PathSeparator());
return Dart_NewStringFromCString(new_str);
}
// Statically allocated Dart_CObject instances for immutable
// objects. As these will be used by different threads the use of
// these depends on the fact that the marking internally in the
// Dart_CObject structure is not marking simple value objects.
Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {0}};
Dart_CObject CObject::api_true_ = {Dart_CObject_kBool, {true}};
Dart_CObject CObject::api_false_ = {Dart_CObject_kBool, {false}};
CObject CObject::null_ = CObject(&api_null_);
CObject CObject::true_ = CObject(&api_true_);
CObject CObject::false_ = CObject(&api_false_);
CObject* CObject::Null() {
return &null_;
}
CObject* CObject::True() {
return &true_;
}
CObject* CObject::False() {
return &false_;
}
CObject* CObject::Bool(bool value) {
return value ? &true_ : &false_;
}
Dart_CObject* CObject::New(Dart_CObject_Type type, int additional_bytes) {
Dart_CObject* cobject = reinterpret_cast<Dart_CObject*>(
Dart_ScopeAllocate(sizeof(Dart_CObject) + additional_bytes));
cobject->type = type;
return cobject;
}
Dart_CObject* CObject::NewInt32(int32_t value) {
Dart_CObject* cobject = New(Dart_CObject_kInt32);
cobject->value.as_int32 = value;
return cobject;
}
Dart_CObject* CObject::NewInt64(int64_t value) {
Dart_CObject* cobject = New(Dart_CObject_kInt64);
cobject->value.as_int64 = value;
return cobject;
}
Dart_CObject* CObject::NewIntptr(intptr_t value) {
// Pointer values passed as intptr_t are always send as int64_t.
Dart_CObject* cobject = New(Dart_CObject_kInt64);
cobject->value.as_int64 = value;
return cobject;
}
Dart_CObject* CObject::NewDouble(double value) {
Dart_CObject* cobject = New(Dart_CObject_kDouble);
cobject->value.as_double = value;
return cobject;
}
Dart_CObject* CObject::NewString(intptr_t length) {
Dart_CObject* cobject = New(Dart_CObject_kString, length + 1);
cobject->value.as_string = reinterpret_cast<char*>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewString(const char* str) {
intptr_t length = strlen(str);
Dart_CObject* cobject = NewString(length);
memmove(cobject->value.as_string, str, length + 1);
return cobject;
}
Dart_CObject* CObject::NewArray(intptr_t length) {
Dart_CObject* cobject =
New(Dart_CObject_kArray, length * sizeof(Dart_CObject*)); // NOLINT
cobject->value.as_array.length = length;
cobject->value.as_array.values =
reinterpret_cast<Dart_CObject**>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewUint8Array(intptr_t length) {
Dart_CObject* cobject = New(Dart_CObject_kTypedData, length);
cobject->value.as_typed_data.type = Dart_TypedData_kUint8;
cobject->value.as_typed_data.length = length;
cobject->value.as_typed_data.values = reinterpret_cast<uint8_t*>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewUint32Array(intptr_t length) {
Dart_CObject* cobject = New(Dart_CObject_kTypedData, 4 * length);
cobject->value.as_typed_data.type = Dart_TypedData_kUint32;
cobject->value.as_typed_data.length = length;
cobject->value.as_typed_data.values = reinterpret_cast<uint8_t*>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewExternalUint8Array(
intptr_t length,
uint8_t* data,
void* peer,
Dart_WeakPersistentHandleFinalizer callback) {
Dart_CObject* cobject = New(Dart_CObject_kExternalTypedData);
cobject->value.as_external_typed_data.type = Dart_TypedData_kUint8;
cobject->value.as_external_typed_data.length = length;
cobject->value.as_external_typed_data.data = data;
cobject->value.as_external_typed_data.peer = peer;
cobject->value.as_external_typed_data.callback = callback;
return cobject;
}
Dart_CObject* CObject::NewIOBuffer(int64_t length) {
// Make sure that we do not have an integer overflow here. Actual check
// against max elements will be done at the time of writing, as the constant
// is not part of the public API.
if ((length < 0) || (length > kIntptrMax)) {
return NULL;
}
uint8_t* data = IOBuffer::Allocate(static_cast<intptr_t>(length));
if (data == NULL) {
return NULL;
}
return NewExternalUint8Array(static_cast<intptr_t>(length), data, data,
IOBuffer::Finalizer);
}
void CObject::FreeIOBufferData(Dart_CObject* cobject) {
ASSERT(cobject->type == Dart_CObject_kExternalTypedData);
cobject->value.as_external_typed_data.callback(
NULL, NULL, cobject->value.as_external_typed_data.peer);
cobject->value.as_external_typed_data.data = NULL;
}
CObject* CObject::IllegalArgumentError() {
CObjectArray* result = new CObjectArray(CObject::NewArray(1));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kArgumentError)));
return result;
}
CObject* CObject::FileClosedError() {
CObjectArray* result = new CObjectArray(CObject::NewArray(1));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kFileClosedError)));
return result;
}
CObject* CObject::NewOSError() {
OSError os_error;
return NewOSError(&os_error);
}
CObject* CObject::NewOSError(OSError* os_error) {
CObject* error_message =
new CObjectString(CObject::NewString(os_error->message()));
CObjectArray* result = new CObjectArray(CObject::NewArray(3));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kOSError)));
result->SetAt(1, new CObjectInt32(CObject::NewInt32(os_error->code())));
result->SetAt(2, error_message);
return result;
}
} // namespace bin
} // namespace dart