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); |