| Index: runtime/bin/gen_snapshot.cc
|
| diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
|
| index f543f09498c1e13415797cfaf4256097a05d2ef2..9dee908222e2c9d239a1a60f0b87fad2232a2d8b 100644
|
| --- a/runtime/bin/gen_snapshot.cc
|
| +++ b/runtime/bin/gen_snapshot.cc
|
| @@ -34,6 +34,122 @@ namespace bin {
|
|
|
| DFE dfe;
|
|
|
| +// Option processing helpers.
|
| +// TODO(dartbug.com/30534) share option processing between main.cc and
|
| +// gen_snapshot.cc
|
| +
|
| +static const char* ProcessOption(const char* option, const char* name) {
|
| + const intptr_t length = strlen(name);
|
| + for (intptr_t i = 0; i < length; i++) {
|
| + if (option[i] != name[i]) {
|
| + if (name[i] == '_' && option[i] == '-') {
|
| + continue;
|
| + }
|
| + return NULL;
|
| + }
|
| + }
|
| + return option + length;
|
| +}
|
| +
|
| +typedef bool (*OptionProcessorCallback)(const char* arg);
|
| +
|
| +class OptionProcessor {
|
| + public:
|
| + OptionProcessor() : next_(first_) { first_ = this; }
|
| +
|
| + virtual ~OptionProcessor() {}
|
| +
|
| + virtual bool Process(const char* option) = 0;
|
| +
|
| + static bool TryProcess(const char* option) {
|
| + for (OptionProcessor* p = first_; p != NULL; p = p->next_) {
|
| + if (p->Process(option)) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + private:
|
| + static OptionProcessor* first_;
|
| + OptionProcessor* next_;
|
| +};
|
| +
|
| +class CallbackOptionProcessor : public OptionProcessor {
|
| + public:
|
| + explicit CallbackOptionProcessor(OptionProcessorCallback cb) : cb_(cb) {}
|
| + virtual bool Process(const char* option) { return cb_(option); }
|
| +
|
| + private:
|
| + OptionProcessorCallback cb_;
|
| +};
|
| +
|
| +OptionProcessor* OptionProcessor::first_ = NULL;
|
| +
|
| +#define DEFINE_CB_OPTION(callback) \
|
| + static CallbackOptionProcessor option_##callback(&callback);
|
| +
|
| +#define DEFINE_STRING_OPTION_CB(name, callback) \
|
| + class OptionProcessor_##name : public OptionProcessor { \
|
| + public: \
|
| + virtual bool Process(const char* option) { \
|
| + const char* value = ProcessOption(option, "--" #name "="); \
|
| + if (value == NULL) { \
|
| + return false; \
|
| + } \
|
| + if (*value == '\0') { \
|
| + Log::PrintErr("Empty value for option " #name "\n"); \
|
| + return false; \
|
| + } \
|
| + callback; \
|
| + return true; \
|
| + } \
|
| + }; \
|
| + static OptionProcessor_##name option_##name;
|
| +
|
| +#define DEFINE_ENUM_OPTION(name, enum_name, variable) \
|
| + DEFINE_STRING_OPTION_CB(name, { \
|
| + const char** kNames = k##enum_name##Names; \
|
| + for (intptr_t i = 0; kNames[i] != NULL; i++) { \
|
| + if (strcmp(value, kNames[i]) == 0) { \
|
| + variable = static_cast<enum_name>(i); \
|
| + return true; \
|
| + } \
|
| + } \
|
| + Log::PrintErr( \
|
| + "Unrecognized value for " #name ": '%s'\nValid values are: ", value); \
|
| + for (intptr_t i = 0; kNames[i] != NULL; i++) { \
|
| + Log::PrintErr("%s%s", i > 0 ? ", " : "", kNames[i]); \
|
| + } \
|
| + Log::PrintErr("\n"); \
|
| + })
|
| +
|
| +#define DEFINE_STRING_OPTION(name, variable) \
|
| + static const char* variable = NULL; \
|
| + DEFINE_STRING_OPTION_CB(name, { variable = value; })
|
| +
|
| +#define DEFINE_BOOL_OPTION(name, variable) \
|
| + static bool variable = false; \
|
| + class OptionProcessor_##name : public OptionProcessor { \
|
| + public: \
|
| + virtual bool Process(const char* option) { \
|
| + const char* value = ProcessOption(option, "--" #name); \
|
| + if (value == NULL) { \
|
| + return false; \
|
| + } \
|
| + if (*value == '=') { \
|
| + Log::PrintErr("Non-empty value for option " #name "\n"); \
|
| + return false; \
|
| + } \
|
| + if (*value != '\0') { \
|
| + return false; \
|
| + } \
|
| + variable = true; \
|
| + return true; \
|
| + } \
|
| + }; \
|
| + static OptionProcessor_##name option_##name;
|
| +
|
| // Exit code indicating an API error.
|
| static const int kApiErrorExitCode = 253;
|
| // Exit code indicating a compilation error.
|
| @@ -72,30 +188,6 @@ enum SnapshotKind {
|
| kAppAOTAssembly,
|
| };
|
| static SnapshotKind snapshot_kind = kCore;
|
| -static const char* vm_snapshot_data_filename = NULL;
|
| -static const char* vm_snapshot_instructions_filename = NULL;
|
| -static const char* isolate_snapshot_data_filename = NULL;
|
| -static const char* isolate_snapshot_instructions_filename = NULL;
|
| -static const char* assembly_filename = NULL;
|
| -static const char* script_snapshot_filename = NULL;
|
| -static bool dependencies_only = false;
|
| -static bool print_dependencies = false;
|
| -static const char* dependencies_filename = NULL;
|
| -
|
| -// Value of the --load-compilation-trace flag.
|
| -// (This pointer points into an argv buffer and does not need to be
|
| -// free'd.)
|
| -static const char* load_compilation_trace_filename = NULL;
|
| -
|
| -// Value of the --package-root flag.
|
| -// (This pointer points into an argv buffer and does not need to be
|
| -// free'd.)
|
| -static const char* commandline_package_root = NULL;
|
| -
|
| -// Value of the --packages flag.
|
| -// (This pointer points into an argv buffer and does not need to be
|
| -// free'd.)
|
| -static const char* commandline_packages_file = NULL;
|
|
|
| // Global state which contains a pointer to the script name for which
|
| // a snapshot needs to be created (NULL would result in the creation
|
| @@ -196,203 +288,32 @@ static Dart_Handle EnvironmentCallback(Dart_Handle name) {
|
| return result;
|
| }
|
|
|
| -static const char* ProcessOption(const char* option, const char* name) {
|
| - const intptr_t length = strlen(name);
|
| - if (strncmp(option, name, length) == 0) {
|
| - return (option + length);
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -static bool ProcessSnapshotKindOption(const char* option) {
|
| - const char* kind = ProcessOption(option, "--snapshot_kind=");
|
| - if (kind == NULL) {
|
| - kind = ProcessOption(option, "--snapshot-kind=");
|
| - }
|
| - if (kind == NULL) {
|
| - return false;
|
| - }
|
| - if (strcmp(kind, "core-jit") == 0) {
|
| - snapshot_kind = kCoreJIT;
|
| - return true;
|
| - } else if (strcmp(kind, "core") == 0) {
|
| - snapshot_kind = kCore;
|
| - return true;
|
| - } else if (strcmp(kind, "script") == 0) {
|
| - snapshot_kind = kScript;
|
| - return true;
|
| - } else if (strcmp(kind, "app-aot-blobs") == 0) {
|
| - snapshot_kind = kAppAOTBlobs;
|
| - return true;
|
| - } else if (strcmp(kind, "app-aot-assembly") == 0) {
|
| - snapshot_kind = kAppAOTAssembly;
|
| - return true;
|
| - }
|
| - Log::PrintErr(
|
| - "Unrecognized snapshot kind: '%s'\nValid kinds are: "
|
| - "core, script, app-aot-blobs, app-aot-assembly\n",
|
| - kind);
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessVmSnapshotDataOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--vm_snapshot_data=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--vm-snapshot-data=");
|
| - }
|
| - if (name != NULL) {
|
| - vm_snapshot_data_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessVmSnapshotInstructionsOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--vm_snapshot_instructions=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--vm-snapshot-instructions=");
|
| - }
|
| - if (name != NULL) {
|
| - vm_snapshot_instructions_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessIsolateSnapshotDataOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--isolate_snapshot_data=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--isolate-snapshot-data=");
|
| - }
|
| - if (name != NULL) {
|
| - isolate_snapshot_data_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessIsolateSnapshotInstructionsOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--isolate_snapshot_instructions=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--isolate-snapshot-instructions=");
|
| - }
|
| - if (name != NULL) {
|
| - isolate_snapshot_instructions_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessAssemblyOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--assembly=");
|
| - if (name != NULL) {
|
| - assembly_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessScriptSnapshotOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--script_snapshot=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--script-snapshot=");
|
| - }
|
| - if (name != NULL) {
|
| - script_snapshot_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessDependenciesOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--dependencies=");
|
| - if (name != NULL) {
|
| - dependencies_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessDependenciesOnlyOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--dependencies_only");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--dependencies-only");
|
| - }
|
| - if (name != NULL) {
|
| - dependencies_only = true;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessPrintDependenciesOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--print_dependencies");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--print-dependencies");
|
| - }
|
| - if (name != NULL) {
|
| - print_dependencies = true;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessEmbedderEntryPointsManifestOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--embedder_entry_points_manifest=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--embedder-entry-points-manifest=");
|
| - }
|
| - if (name != NULL) {
|
| - entry_points_files->AddArgument(name);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessLoadCompilationTraceOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--load_compilation_trace=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--load-compilation-trace=");
|
| - }
|
| - if (name != NULL) {
|
| - load_compilation_trace_filename = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessPackageRootOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--package_root=");
|
| - if (name == NULL) {
|
| - name = ProcessOption(option, "--package-root=");
|
| - }
|
| - if (name != NULL) {
|
| - commandline_package_root = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| +static const char* kSnapshotKindNames[] = {
|
| + "core", "core-jit", "script", "app-aot-blobs", "app-aot-assembly", NULL,
|
| +};
|
|
|
| -static bool ProcessPackagesOption(const char* option) {
|
| - const char* name = ProcessOption(option, "--packages=");
|
| - if (name != NULL) {
|
| - commandline_packages_file = name;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static bool ProcessURLmappingOption(const char* option) {
|
| - const char* mapping = ProcessOption(option, "--url_mapping=");
|
| - if (mapping == NULL) {
|
| - mapping = ProcessOption(option, "--url-mapping=");
|
| - }
|
| - if (mapping != NULL) {
|
| - DartUtils::url_mapping->AddArgument(mapping);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| +DEFINE_ENUM_OPTION(snapshot_kind, SnapshotKind, snapshot_kind);
|
| +DEFINE_STRING_OPTION(vm_snapshot_data, vm_snapshot_data_filename);
|
| +DEFINE_STRING_OPTION(vm_snapshot_instructions,
|
| + vm_snapshot_instructions_filename);
|
| +DEFINE_STRING_OPTION(isolate_snapshot_data, isolate_snapshot_data_filename);
|
| +DEFINE_STRING_OPTION(isolate_snapshot_instructions,
|
| + isolate_snapshot_instructions_filename);
|
| +DEFINE_STRING_OPTION(assembly, assembly_filename);
|
| +DEFINE_STRING_OPTION(script_snapshot, script_snapshot_filename);
|
| +DEFINE_STRING_OPTION(dependencies, dependencies_filename);
|
| +DEFINE_BOOL_OPTION(dependencies_only, dependencies_only);
|
| +DEFINE_BOOL_OPTION(print_dependencies, print_dependencies);
|
| +DEFINE_STRING_OPTION_CB(embedder_entry_points_manifest,
|
| + { entry_points_files->AddArgument(value); });
|
| +DEFINE_STRING_OPTION(load_compilation_trace, load_compilation_trace_filename);
|
| +DEFINE_STRING_OPTION(package_root, commandline_package_root);
|
| +DEFINE_STRING_OPTION(packages, commandline_packages_file);
|
| +DEFINE_STRING_OPTION_CB(url_mapping,
|
| + { DartUtils::url_mapping->AddArgument(value); });
|
| +DEFINE_CB_OPTION(ProcessEnvironmentOption);
|
| +DEFINE_BOOL_OPTION(obfuscate, obfuscate);
|
| +DEFINE_STRING_OPTION(save_obfuscation_map, obfuscation_map_filename);
|
|
|
| static bool IsSnapshottingForPrecompilation() {
|
| return (snapshot_kind == kAppAOTBlobs) || (snapshot_kind == kAppAOTAssembly);
|
| @@ -412,21 +333,7 @@ static int ParseArguments(int argc,
|
|
|
| // Parse out the vm options.
|
| while ((i < argc) && IsValidFlag(argv[i], kPrefix, kPrefixLen)) {
|
| - if (ProcessSnapshotKindOption(argv[i]) ||
|
| - ProcessVmSnapshotDataOption(argv[i]) ||
|
| - ProcessVmSnapshotInstructionsOption(argv[i]) ||
|
| - ProcessIsolateSnapshotDataOption(argv[i]) ||
|
| - ProcessIsolateSnapshotInstructionsOption(argv[i]) ||
|
| - ProcessAssemblyOption(argv[i]) ||
|
| - ProcessScriptSnapshotOption(argv[i]) ||
|
| - ProcessDependenciesOption(argv[i]) ||
|
| - ProcessDependenciesOnlyOption(argv[i]) ||
|
| - ProcessPrintDependenciesOption(argv[i]) ||
|
| - ProcessEmbedderEntryPointsManifestOption(argv[i]) ||
|
| - ProcessURLmappingOption(argv[i]) ||
|
| - ProcessLoadCompilationTraceOption(argv[i]) ||
|
| - ProcessPackageRootOption(argv[i]) || ProcessPackagesOption(argv[i]) ||
|
| - ProcessEnvironmentOption(argv[i])) {
|
| + if (OptionProcessor::TryProcess(argv[i])) {
|
| i += 1;
|
| continue;
|
| }
|
| @@ -520,6 +427,19 @@ static int ParseArguments(int argc,
|
| return -1;
|
| }
|
|
|
| + if (!obfuscate && obfuscation_map_filename != NULL) {
|
| + Log::PrintErr(
|
| + "--obfuscation_map=<...> should only be specified when obfuscation is "
|
| + "enabled by --obfuscate flag.\n\n");
|
| + return -1;
|
| + }
|
| +
|
| + if (obfuscate && !IsSnapshottingForPrecompilation()) {
|
| + Log::PrintErr(
|
| + "Obfuscation can only be enabled when building AOT snapshot.\n\n");
|
| + return -1;
|
| + }
|
| +
|
| return 0;
|
| }
|
|
|
| @@ -970,6 +890,8 @@ static void PrintUsage() {
|
| " --isolate_snapshot_data=<output-file> \n"
|
| " --isolate_snapshot_instructions=<output-file> \n"
|
| " {--embedder_entry_points_manifest=<input-file>} \n"
|
| +" [--obfuscate] \n"
|
| +" [--save-obfuscation-map=<map-filename>] \n"
|
| " <dart-script-file> \n"
|
| " \n"
|
| " To create an AOT application snapshot as assembly suitable for compilation \n"
|
| @@ -978,6 +900,8 @@ static void PrintUsage() {
|
| " --snapshot_kind=app-aot-blobs \n"
|
| " --assembly=<output-file> \n"
|
| " {--embedder_entry_points_manifest=<input-file>} \n"
|
| +" [--obfuscate] \n"
|
| +" [--save-obfuscation-map=<map-filename>] \n"
|
| " <dart-script-file> \n"
|
| " \n"
|
| " AOT snapshots require entry points manifest files, which list the places \n"
|
| @@ -990,6 +914,13 @@ static void PrintUsage() {
|
| " \n"
|
| " Example: \n"
|
| " dart:something,SomeClass,doSomething \n"
|
| +" \n"
|
| +" AOT snapshots can be obfuscated: that is all identifiers will be renamed \n"
|
| +" during compilation. This mode is enabled with --obfuscate flag. Mapping \n"
|
| +" between original and obfuscated names can be serialized as a JSON array \n"
|
| +" using --save-obfuscation-map=<filename> option. See dartbug.com/30524 \n"
|
| +" for implementation details and limitations of the obfuscation pass. \n"
|
| +" \n"
|
| "\n");
|
| }
|
| // clang-format on
|
| @@ -1467,6 +1398,16 @@ static void CreateAndWritePrecompiledSnapshot(
|
| isolate_snapshot_instructions_buffer,
|
| isolate_snapshot_instructions_size);
|
| }
|
| +
|
| + // Serialize obfuscation map if requested.
|
| + if (obfuscation_map_filename != NULL) {
|
| + ASSERT(obfuscate);
|
| + uint8_t* buffer = NULL;
|
| + intptr_t size = 0;
|
| + result = Dart_GetObfuscationMap(&buffer, &size);
|
| + CHECK_RESULT(result);
|
| + WriteFile(obfuscation_map_filename, buffer, size);
|
| + }
|
| }
|
|
|
| static void SetupForUriResolution() {
|
| @@ -1664,6 +1605,12 @@ int main(int argc, char** argv) {
|
| return kErrorExitCode;
|
| }
|
|
|
| + Dart_IsolateFlags flags;
|
| + Dart_IsolateFlagsInitialize(&flags);
|
| +
|
| + Dart_QualifiedFunctionName* entry_points =
|
| + ParseEntryPointsManifestIfPresent();
|
| +
|
| IsolateData* isolate_data = new IsolateData(NULL, commandline_package_root,
|
| commandline_packages_file, NULL);
|
| Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data,
|
| @@ -1718,6 +1665,11 @@ int main(int argc, char** argv) {
|
| isolate_data->set_dependencies(new MallocGrowableArray<char*>());
|
| }
|
|
|
| + if (IsSnapshottingForPrecompilation()) {
|
| + flags.obfuscate = obfuscate;
|
| + flags.entry_points = entry_points;
|
| + }
|
| +
|
| Dart_Isolate isolate = NULL;
|
| void* kernel_program = dfe.ReadScript(app_script_name);
|
| if (kernel_program != NULL) {
|
| @@ -1725,7 +1677,7 @@ int main(int argc, char** argv) {
|
| isolate_data, &error);
|
| } else {
|
| isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data,
|
| - isolate_snapshot_instructions, NULL,
|
| + isolate_snapshot_instructions, &flags,
|
| isolate_data, &error);
|
| }
|
| if (isolate == NULL) {
|
| @@ -1746,9 +1698,6 @@ int main(int argc, char** argv) {
|
| AddDependency(commandline_packages_file);
|
| }
|
|
|
| - Dart_QualifiedFunctionName* entry_points =
|
| - ParseEntryPointsManifestIfPresent();
|
| -
|
| if (kernel_program != NULL) {
|
| Dart_Handle resolved_uri = ResolveUriInWorkingDirectory(app_script_name);
|
| CHECK_RESULT(resolved_uri);
|
|
|