| Index: runtime/bin/gen_snapshot.cc
|
| diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
|
| index 448fd28cbddf8c0d8ffb0e6d37521bf239697703..44b09a65ef1278d1c0416dbe081e40d82927d3af 100644
|
| --- a/runtime/bin/gen_snapshot.cc
|
| +++ b/runtime/bin/gen_snapshot.cc
|
| @@ -22,18 +22,38 @@
|
|
|
| #include "include/dart_api.h"
|
|
|
| +#include "platform/hashmap.h"
|
| #include "platform/globals.h"
|
|
|
| namespace dart {
|
| namespace bin {
|
|
|
| +// Exit code indicating an API error.
|
| +static const int kApiErrorExitCode = 253;
|
| +// Exit code indicating a compilation error.
|
| +static const int kCompilationErrorExitCode = 254;
|
| +// Exit code indicating an unhandled error that is not a compilation error.
|
| +static const int kErrorExitCode = 255;
|
| +// Exit code indicating a vm restart request. Never returned to the user.
|
| +static const int kRestartRequestExitCode = 1000;
|
| +
|
| #define CHECK_RESULT(result) \
|
| if (Dart_IsError(result)) { \
|
| + intptr_t exit_code = 0; \
|
| Log::PrintErr("Error: %s", Dart_GetError(result)); \
|
| + if (Dart_IsCompilationError(result)) { \
|
| + exit_code = kCompilationErrorExitCode; \
|
| + } else if (Dart_IsApiError(result)) { \
|
| + exit_code = kApiErrorExitCode; \
|
| + } else if (Dart_IsVMRestartRequest(result)) { \
|
| + exit_code = kRestartRequestExitCode; \
|
| + } else { \
|
| + exit_code = kErrorExitCode; \
|
| + } \
|
| Dart_ExitScope(); \
|
| Dart_ShutdownIsolate(); \
|
| - exit(255); \
|
| - } \
|
| + exit(exit_code); \
|
| + }
|
|
|
|
|
| // Global state that indicates whether a snapshot is to be created and
|
| @@ -41,7 +61,6 @@ namespace bin {
|
| static const char* vm_isolate_snapshot_filename = NULL;
|
| static const char* isolate_snapshot_filename = NULL;
|
| static const char* instructions_snapshot_filename = NULL;
|
| -static const char* embedder_entry_points_manifest = NULL;
|
| static const char* package_root = NULL;
|
|
|
|
|
| @@ -54,6 +73,10 @@ static char* app_script_name = NULL;
|
| // Global state that captures the URL mappings specified on the command line.
|
| static CommandLineOptions* url_mapping = NULL;
|
|
|
| +// Global state that captures the entry point manifest files specified on the
|
| +// command line.
|
| +static CommandLineOptions* entry_points_files = NULL;
|
| +
|
| static bool IsValidFlag(const char* name,
|
| const char* prefix,
|
| intptr_t prefix_length) {
|
| @@ -63,6 +86,93 @@ static bool IsValidFlag(const char* name,
|
| }
|
|
|
|
|
| +// The environment provided through the command line using -D options.
|
| +static dart::HashMap* environment = NULL;
|
| +
|
| +static void* GetHashmapKeyFromString(char* key) {
|
| + return reinterpret_cast<void*>(key);
|
| +}
|
| +
|
| +static bool ProcessEnvironmentOption(const char* arg) {
|
| + ASSERT(arg != NULL);
|
| + if (*arg == '\0') {
|
| + return false;
|
| + }
|
| + if (*arg != '-') {
|
| + return false;
|
| + }
|
| + if (*(arg + 1) != 'D') {
|
| + return false;
|
| + }
|
| + arg = arg + 2;
|
| + if (*arg == '\0') {
|
| + return true;
|
| + }
|
| + if (environment == NULL) {
|
| + environment = new HashMap(&HashMap::SameStringValue, 4);
|
| + }
|
| + // Split the name=value part of the -Dname=value argument.
|
| + char* name;
|
| + char* value = NULL;
|
| + const char* equals_pos = strchr(arg, '=');
|
| + if (equals_pos == NULL) {
|
| + // No equal sign (name without value) currently not supported.
|
| + Log::PrintErr("No value given to -D option\n");
|
| + return false;
|
| + } else {
|
| + int name_len = equals_pos - arg;
|
| + if (name_len == 0) {
|
| + Log::PrintErr("No name given to -D option\n");
|
| + return false;
|
| + }
|
| + // Split name=value into name and value.
|
| + name = reinterpret_cast<char*>(malloc(name_len + 1));
|
| + strncpy(name, arg, name_len);
|
| + name[name_len] = '\0';
|
| + value = strdup(equals_pos + 1);
|
| + }
|
| + HashMap::Entry* entry = environment->Lookup(
|
| + GetHashmapKeyFromString(name), HashMap::StringHash(name), true);
|
| + ASSERT(entry != NULL); // Lookup adds an entry if key not found.
|
| + entry->value = value;
|
| + return true;
|
| +}
|
| +
|
| +
|
| +static Dart_Handle EnvironmentCallback(Dart_Handle name) {
|
| + uint8_t* utf8_array;
|
| + intptr_t utf8_len;
|
| + Dart_Handle result = Dart_Null();
|
| + Dart_Handle handle = Dart_StringToUTF8(name, &utf8_array, &utf8_len);
|
| + if (Dart_IsError(handle)) {
|
| + handle = Dart_ThrowException(
|
| + DartUtils::NewDartArgumentError(Dart_GetError(handle)));
|
| + } else {
|
| + char* name_chars = reinterpret_cast<char*>(malloc(utf8_len + 1));
|
| + memmove(name_chars, utf8_array, utf8_len);
|
| + name_chars[utf8_len] = '\0';
|
| + const char* value = NULL;
|
| + printf("Looking for %s\n", name_chars);
|
| + if (environment != NULL) {
|
| + HashMap::Entry* entry = environment->Lookup(
|
| + GetHashmapKeyFromString(name_chars),
|
| + HashMap::StringHash(name_chars),
|
| + false);
|
| + if (entry != NULL) {
|
| + value = reinterpret_cast<char*>(entry->value);
|
| + }
|
| + }
|
| + if (value != NULL) {
|
| + result = Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(value),
|
| + strlen(value));
|
| + }
|
| + free(name_chars);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +
|
| static const char* ProcessOption(const char* option, const char* name) {
|
| const intptr_t length = strlen(name);
|
| if (strncmp(option, name, length) == 0) {
|
| @@ -105,7 +215,7 @@ static bool ProcessInstructionsSnapshotOption(const char* option) {
|
| static bool ProcessEmbedderEntryPointsManifestOption(const char* option) {
|
| const char* name = ProcessOption(option, "--embedder_entry_points_manifest=");
|
| if (name != NULL) {
|
| - embedder_entry_points_manifest = name;
|
| + entry_points_files->AddArgument(name);
|
| return true;
|
| }
|
| return false;
|
| @@ -114,6 +224,9 @@ static bool ProcessEmbedderEntryPointsManifestOption(const char* option) {
|
|
|
| static bool ProcessPackageRootOption(const char* option) {
|
| const char* name = ProcessOption(option, "--package_root=");
|
| + if (name == NULL) {
|
| + name = ProcessOption(option, "--package-root=");
|
| + }
|
| if (name != NULL) {
|
| package_root = name;
|
| return true;
|
| @@ -141,7 +254,7 @@ static int ParseArguments(int argc,
|
| char** argv,
|
| CommandLineOptions* vm_options,
|
| char** script_name) {
|
| - const char* kPrefix = "--";
|
| + const char* kPrefix = "-";
|
| const intptr_t kPrefixLen = strlen(kPrefix);
|
|
|
| // Skip the binary name.
|
| @@ -154,7 +267,8 @@ static int ParseArguments(int argc,
|
| ProcessInstructionsSnapshotOption(argv[i]) ||
|
| ProcessEmbedderEntryPointsManifestOption(argv[i]) ||
|
| ProcessURLmappingOption(argv[i]) ||
|
| - ProcessPackageRootOption(argv[i])) {
|
| + ProcessPackageRootOption(argv[i]) ||
|
| + ProcessEnvironmentOption(argv[i])) {
|
| i += 1;
|
| continue;
|
| }
|
| @@ -181,14 +295,14 @@ static int ParseArguments(int argc,
|
| }
|
|
|
| if ((instructions_snapshot_filename != NULL) &&
|
| - (embedder_entry_points_manifest == NULL)) {
|
| + (entry_points_files->count() == 0)) {
|
| Log::PrintErr(
|
| "Specifying an instructions snapshot filename indicates precompilation"
|
| ". But no embedder entry points manifest was specified.\n\n");
|
| return -1;
|
| }
|
|
|
| - if ((embedder_entry_points_manifest != NULL) &&
|
| + if ((entry_points_files->count() > 0) &&
|
| (instructions_snapshot_filename == NULL)) {
|
| Log::PrintErr(
|
| "Specifying the embedder entry points manifest indicates "
|
| @@ -201,8 +315,8 @@ static int ParseArguments(int argc,
|
|
|
|
|
| static bool IsSnapshottingForPrecompilation(void) {
|
| - return embedder_entry_points_manifest != NULL &&
|
| - instructions_snapshot_filename != NULL;
|
| + return (entry_points_files->count() > 0) &&
|
| + (instructions_snapshot_filename != NULL);
|
| }
|
|
|
|
|
| @@ -510,9 +624,7 @@ static void VerifyLoaded(Dart_Handle library) {
|
| if (Dart_IsError(library)) {
|
| const char* err_msg = Dart_GetError(library);
|
| Log::PrintErr("Errors encountered while loading: %s\n", err_msg);
|
| - Dart_ExitScope();
|
| - Dart_ShutdownIsolate();
|
| - exit(255);
|
| + CHECK_RESULT(library);
|
| }
|
| ASSERT(Dart_IsLibrary(library));
|
| }
|
| @@ -781,31 +893,34 @@ int64_t ParseEntryPointsManifestLines(FILE* file,
|
| }
|
|
|
|
|
| -static Dart_QualifiedFunctionName* ParseEntryPointsManifestFile(
|
| - const char* path) {
|
| - if (path == NULL) {
|
| - return NULL;
|
| - }
|
| +static Dart_QualifiedFunctionName* ParseEntryPointsManifestFiles() {
|
| + // Total number of entries across all manifest files.
|
| + int64_t entry_count = 0;
|
|
|
| - FILE* file = fopen(path, "r");
|
| + // Parse the files once but don't store the results. This is done to first
|
| + // determine the number of entries in the manifest
|
| + for (intptr_t i = 0; i < entry_points_files->count(); i++) {
|
| + const char* path = entry_points_files->GetArgument(i);
|
|
|
| - if (file == NULL) {
|
| - Log::PrintErr("Could not open entry points manifest file\n");
|
| - return NULL;
|
| - }
|
| + FILE* file = fopen(path, "r");
|
|
|
| - // Parse the file once but don't store the results. This is done to first
|
| - // determine the number of entries in the manifest
|
| - int64_t entry_count = ParseEntryPointsManifestLines(file, NULL);
|
| + if (file == NULL) {
|
| + Log::PrintErr("Could not open entry points manifest file `%s`\n", path);
|
| + return NULL;
|
| + }
|
|
|
| - if (entry_count <= 0) {
|
| - Log::PrintErr(
|
| - "Manifest file specified is invalid or contained no entries\n");
|
| + int64_t entries = ParseEntryPointsManifestLines(file, NULL);
|
| fclose(file);
|
| - return NULL;
|
| - }
|
|
|
| - rewind(file);
|
| + if (entries <= 0) {
|
| + Log::PrintErr(
|
| + "Manifest file `%s` specified is invalid or contained no entries\n",
|
| + path);
|
| + return NULL;
|
| + }
|
| +
|
| + entry_count += entries;
|
| + }
|
|
|
| // Allocate enough storage for the entries in the file plus a termination
|
| // sentinel and parse it again to populate the allocation
|
| @@ -813,10 +928,16 @@ static Dart_QualifiedFunctionName* ParseEntryPointsManifestFile(
|
| reinterpret_cast<Dart_QualifiedFunctionName*>(
|
| calloc(entry_count + 1, sizeof(Dart_QualifiedFunctionName)));
|
|
|
| - int64_t parsed_entry_count = ParseEntryPointsManifestLines(file, entries);
|
| - ASSERT(parsed_entry_count == entry_count);
|
| + int64_t parsed_entry_count = 0;
|
| + for (intptr_t i = 0; i < entry_points_files->count(); i++) {
|
| + const char* path = entry_points_files->GetArgument(i);
|
| + FILE* file = fopen(path, "r");
|
| + parsed_entry_count +=
|
| + ParseEntryPointsManifestLines(file, &entries[parsed_entry_count]);
|
| + fclose(file);
|
| + }
|
|
|
| - fclose(file);
|
| + ASSERT(parsed_entry_count == entry_count);
|
|
|
| // The entries allocation must be explicitly cleaned up via
|
| // |CleanupEntryPointsCollection|
|
| @@ -825,8 +946,7 @@ static Dart_QualifiedFunctionName* ParseEntryPointsManifestFile(
|
|
|
|
|
| static Dart_QualifiedFunctionName* ParseEntryPointsManifestIfPresent() {
|
| - Dart_QualifiedFunctionName* entries =
|
| - ParseEntryPointsManifestFile(embedder_entry_points_manifest);
|
| + Dart_QualifiedFunctionName* entries = ParseEntryPointsManifestFiles();
|
| if ((entries == NULL) && IsSnapshottingForPrecompilation()) {
|
| Log::PrintErr(
|
| "Could not find native embedder entry points during precompilation\n");
|
| @@ -998,6 +1118,10 @@ int main(int argc, char** argv) {
|
| CommandLineOptions url_mapping_array(argc);
|
| url_mapping = &url_mapping_array;
|
|
|
| + // Initialize the entrypoints array.
|
| + CommandLineOptions entry_points_files_array(argc);
|
| + entry_points_files = &entry_points_files_array;
|
| +
|
| // Parse command line arguments.
|
| if (ParseArguments(argc,
|
| argv,
|
| @@ -1067,6 +1191,9 @@ int main(int argc, char** argv) {
|
| Dart_Handle library;
|
| Dart_EnterScope();
|
|
|
| + result = Dart_SetEnvironmentCallback(EnvironmentCallback);
|
| + CHECK_RESULT(result);
|
| +
|
| ASSERT(vm_isolate_snapshot_filename != NULL);
|
| ASSERT(isolate_snapshot_filename != NULL);
|
| // Load up the script before a snapshot is created.
|
| @@ -1108,6 +1235,8 @@ int main(int argc, char** argv) {
|
| exit(255);
|
| }
|
| Dart_EnterScope();
|
| + result = Dart_SetEnvironmentCallback(EnvironmentCallback);
|
| + CHECK_RESULT(result);
|
|
|
| // Set up the library tag handler in such a manner that it will use the
|
| // URL mapping specified on the command line to load the libraries.
|
| @@ -1129,8 +1258,7 @@ int main(int argc, char** argv) {
|
| result = Dart_FinalizeLoading(false);
|
| CHECK_RESULT(result);
|
|
|
| - if (entry_points == NULL) {
|
| - ASSERT(!IsSnapshottingForPrecompilation());
|
| + if (!IsSnapshottingForPrecompilation()) {
|
| CreateAndWriteSnapshot();
|
| } else {
|
| CreateAndWritePrecompiledSnapshot(entry_points);
|
|
|