Create an app snapshot of the Dart front end.

R=asiva@google.com, hausner@google.com, zra@google.com

Review-Url: https://codereview.chromium.org/2655173002 .
This commit is contained in:
Ryan Macnak 2017-01-26 16:28:59 -08:00
parent 1e0bf05aaf
commit 8c7111c967
6 changed files with 233 additions and 185 deletions

View file

@ -42,6 +42,9 @@ group("runtime") {
"runtime/bin:sample_extension",
"runtime/bin:test_extension",
"runtime/vm:patched_sdk",
# TODO(rmacnak): Link this into 'dart'
"utils/kernel-service:kernel-service",
]
}
@ -122,9 +125,7 @@ action("create_sdk") {
rebase_path("$root_gen_dir"),
]
if (defined(is_fuchsia) && is_fuchsia_host) {
args += [
"--copy_libs"
]
args += [ "--copy_libs" ]
}
}
@ -173,11 +174,10 @@ group("samples") {
]
}
# The rules below build a qemu Fuchsia OS image that includes the Dart tree
# under /system/test/dart. Building this image is gated by the GN argument
# 'dart_build_fuchsia_test_image' because building the image is slow.
if (defined(is_fuchsia) && (is_fuchsia)) {
if (defined(is_fuchsia) && is_fuchsia) {
declare_args() {
dart_build_fuchsia_test_image = false
}
@ -217,10 +217,10 @@ if (defined(is_fuchsia) && (is_fuchsia)) {
action("generate_dart_test_image") {
testonly = true
deps = [
"runtime/bin:dart",
"runtime/bin:run_vm_tests",
"runtime/bin:process_test",
":generate_dart_test_manifest",
"runtime/bin:dart",
"runtime/bin:process_test",
"runtime/bin:run_vm_tests",
]
input = "$target_gen_dir/dart_test_tree.manifest"

View file

@ -809,6 +809,173 @@ static Dart_Handle EnvironmentCallback(Dart_Handle name) {
static void SnapshotOnExitHook(int64_t exit_code);
static const int64_t kAppSnapshotHeaderSize = 5 * kInt64Size;
static const int64_t kAppSnapshotMagicNumber = 0xf6f6dcdc;
static const int64_t kAppSnapshotPageSize = 4 * KB;
static bool ReadAppSnapshotBlobs(const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
File* file = File::Open(script_name, File::kRead);
if (file == NULL) {
return false;
}
if (file->Length() < kAppSnapshotHeaderSize) {
file->Release();
return false;
}
int64_t header[5];
ASSERT(sizeof(header) == kAppSnapshotHeaderSize);
if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
file->Release();
return false;
}
if (header[0] != kAppSnapshotMagicNumber) {
file->Release();
return false;
}
int64_t vm_data_size = header[1];
int64_t vm_data_position =
Utils::RoundUp(file->Position(), kAppSnapshotPageSize);
int64_t vm_instructions_size = header[2];
int64_t vm_instructions_position = vm_data_position + vm_data_size;
if (vm_instructions_size != 0) {
vm_instructions_position =
Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize);
}
int64_t isolate_data_size = header[3];
int64_t isolate_data_position = Utils::RoundUp(
vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize);
int64_t isolate_instructions_size = header[4];
int64_t isolate_instructions_position =
isolate_data_position + isolate_data_size;
if (isolate_instructions_size != 0) {
isolate_instructions_position =
Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
}
if (vm_data_size != 0) {
*vm_data_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadOnly, vm_data_position, vm_data_size));
if (vm_data_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
if (vm_instructions_size != 0) {
*vm_instructions_buffer = reinterpret_cast<const uint8_t*>(file->Map(
File::kReadExecute, vm_instructions_position, vm_instructions_size));
if (*vm_instructions_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
*isolate_data_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadOnly, isolate_data_position, isolate_data_size));
if (isolate_data_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
if (isolate_instructions_size == 0) {
*isolate_instructions_buffer = NULL;
} else {
*isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadExecute, isolate_instructions_position,
isolate_instructions_size));
if (*isolate_instructions_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
file->Release();
return true;
}
#if defined(DART_PRECOMPILED_RUNTIME)
static bool ReadAppSnapshotDynamicLibrary(
const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
void* library = Extensions::LoadExtensionLibrary(script_name);
if (library == NULL) {
return false;
}
*vm_data_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName));
if (*vm_data_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName);
Platform::Exit(kErrorExitCode);
}
*vm_instructions_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName));
if (*vm_instructions_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kVmSnapshotInstructionsSymbolName);
Platform::Exit(kErrorExitCode);
}
*isolate_data_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName));
if (*isolate_data_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kIsolateSnapshotDataSymbolName);
Platform::Exit(kErrorExitCode);
}
*isolate_instructions_buffer =
reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol(
library, kIsolateSnapshotInstructionsSymbolName));
if (*isolate_instructions_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kIsolateSnapshotInstructionsSymbolName);
Platform::Exit(kErrorExitCode);
}
return true;
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
static bool ReadAppSnapshot(const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
if (File::GetType(script_name, true) != File::kIsFile) {
// If 'script_name' refers to a pipe, don't read to check for an app
// snapshot since we cannot rewind if it isn't (and couldn't mmap it in
// anyway if it was).
return false;
}
if (ReadAppSnapshotBlobs(script_name, vm_data_buffer, vm_instructions_buffer,
isolate_data_buffer, isolate_instructions_buffer)) {
return true;
}
#if defined(DART_PRECOMPILED_RUNTIME)
// For testing AOT with the standalone embedder, we also support loading
// from a dynamic library to simulate what happens on iOS.
return ReadAppSnapshotDynamicLibrary(
script_name, vm_data_buffer, vm_instructions_buffer, isolate_data_buffer,
isolate_instructions_buffer);
#else
return false;
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
// Returns true on success, false on failure.
static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
const char* script_uri,
@ -823,10 +990,10 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
if (!use_dart_frontend) {
*error = strdup("Kernel isolate not supported.");
return NULL;
} else {
if (packages_config == NULL) {
packages_config = commandline_packages_file;
}
}
script_uri = frontend_filename;
if (packages_config == NULL) {
packages_config = commandline_packages_file;
}
}
@ -849,6 +1016,19 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
isolate_run_app_snapshot = true;
isolate_snapshot_data = app_isolate_snapshot_data;
isolate_snapshot_instructions = app_isolate_snapshot_instructions;
} else if (!is_main_isolate) {
const uint8_t* file_vm_snapshot_data = NULL;
const uint8_t* file_vm_snapshot_instructions = NULL;
const uint8_t* file_isolate_snapshot_data = NULL;
const uint8_t* file_isolate_snapshot_instructions = NULL;
if (ReadAppSnapshot(
script_uri, &file_vm_snapshot_data, &file_vm_snapshot_instructions,
&file_isolate_snapshot_data, &file_isolate_snapshot_instructions)) {
// TODO(rmacnak): We are leaking the snapshot when the isolate shuts down.
isolate_run_app_snapshot = true;
isolate_snapshot_data = file_isolate_snapshot_data;
isolate_snapshot_instructions = file_isolate_snapshot_instructions;
}
}
#endif
@ -929,10 +1109,6 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
result = DartUtils::SetupServiceLoadPort();
CHECK_RESULT(result);
if (Dart_IsKernelIsolate(isolate)) {
script_uri = frontend_filename;
}
// Setup package root if specified.
result = DartUtils::SetupPackageRoot(package_root, packages_config);
CHECK_RESULT(result);
@ -1288,173 +1464,6 @@ static void WriteSnapshotFile(const char* filename,
}
static const int64_t kAppSnapshotHeaderSize = 5 * sizeof(int64_t); // NOLINT
static const int64_t kAppSnapshotMagicNumber = 0xf6f6dcdc;
static const int64_t kAppSnapshotPageSize = 4 * KB;
static bool ReadAppSnapshotBlobs(const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
File* file = File::Open(script_name, File::kRead);
if (file == NULL) {
return false;
}
if (file->Length() < kAppSnapshotHeaderSize) {
file->Release();
return false;
}
int64_t header[5];
ASSERT(sizeof(header) == kAppSnapshotHeaderSize);
if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
file->Release();
return false;
}
if (header[0] != kAppSnapshotMagicNumber) {
file->Release();
return false;
}
int64_t vm_data_size = header[1];
int64_t vm_data_position =
Utils::RoundUp(file->Position(), kAppSnapshotPageSize);
int64_t vm_instructions_size = header[2];
int64_t vm_instructions_position = vm_data_position + vm_data_size;
if (vm_instructions_size != 0) {
vm_instructions_position =
Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize);
}
int64_t isolate_data_size = header[3];
int64_t isolate_data_position = Utils::RoundUp(
vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize);
int64_t isolate_instructions_size = header[4];
int64_t isolate_instructions_position =
isolate_data_position + isolate_data_size;
if (isolate_instructions_size != 0) {
isolate_instructions_position =
Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
}
if (vm_data_size != 0) {
*vm_data_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadOnly, vm_data_position, vm_data_size));
if (vm_data_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
if (vm_instructions_size != 0) {
*vm_instructions_buffer = reinterpret_cast<const uint8_t*>(file->Map(
File::kReadExecute, vm_instructions_position, vm_instructions_size));
if (*vm_instructions_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
*isolate_data_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadOnly, isolate_data_position, isolate_data_size));
if (isolate_data_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
if (isolate_instructions_size == 0) {
*isolate_instructions_buffer = NULL;
} else {
*isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
file->Map(File::kReadExecute, isolate_instructions_position,
isolate_instructions_size));
if (*isolate_instructions_buffer == NULL) {
Log::PrintErr("Failed to memory map snapshot\n");
Platform::Exit(kErrorExitCode);
}
}
file->Release();
return true;
}
#if defined(DART_PRECOMPILED_RUNTIME)
static bool ReadAppSnapshotDynamicLibrary(
const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
void* library = Extensions::LoadExtensionLibrary(script_name);
if (library == NULL) {
return false;
}
*vm_data_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName));
if (*vm_data_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName);
Platform::Exit(kErrorExitCode);
}
*vm_instructions_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName));
if (*vm_instructions_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kVmSnapshotInstructionsSymbolName);
Platform::Exit(kErrorExitCode);
}
*isolate_data_buffer = reinterpret_cast<const uint8_t*>(
Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName));
if (*isolate_data_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kIsolateSnapshotDataSymbolName);
Platform::Exit(kErrorExitCode);
}
*isolate_instructions_buffer =
reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol(
library, kIsolateSnapshotInstructionsSymbolName));
if (*isolate_instructions_buffer == NULL) {
Log::PrintErr("Failed to resolve symbol '%s'\n",
kIsolateSnapshotInstructionsSymbolName);
Platform::Exit(kErrorExitCode);
}
return true;
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
static bool ReadAppSnapshot(const char* script_name,
const uint8_t** vm_data_buffer,
const uint8_t** vm_instructions_buffer,
const uint8_t** isolate_data_buffer,
const uint8_t** isolate_instructions_buffer) {
if (File::GetType(script_name, true) != File::kIsFile) {
// If 'script_name' refers to a pipe, don't read to check for an app
// snapshot since we cannot rewind if it isn't (and couldn't mmap it in
// anyway if it was).
return false;
}
if (ReadAppSnapshotBlobs(script_name, vm_data_buffer, vm_instructions_buffer,
isolate_data_buffer, isolate_instructions_buffer)) {
return true;
}
#if defined(DART_PRECOMPILED_RUNTIME)
// For testing AOT with the standalone embedder, we also support loading
// from a dynamic library to simulate what happens on iOS.
return ReadAppSnapshotDynamicLibrary(
script_name, vm_data_buffer, vm_instructions_buffer, isolate_data_buffer,
isolate_instructions_buffer);
#else
return false;
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
static bool WriteInt64(File* file, int64_t size) {
return file->WriteFully(&size, sizeof(size));
}

View file

@ -462,6 +462,7 @@ const int kDoubleSize = sizeof(double); // NOLINT
const int kFloatSize = sizeof(float); // NOLINT
const int kQuadSize = 4 * kFloatSize;
const int kSimd128Size = sizeof(simd128_value_t); // NOLINT
const int kInt64Size = sizeof(int64_t); // NOLINT
const int kInt32Size = sizeof(int32_t); // NOLINT
const int kInt16Size = sizeof(int16_t); // NOLINT
#ifdef ARCH_IS_32_BIT

View file

@ -154,7 +154,7 @@ class RunKernelTask : public ThreadPool::Task {
return false;
}
ASSERT(!root_library.IsNull());
const String& entry_name = String::Handle(Z, String::New("main"));
const String& entry_name = String::Handle(Z, String::New("start"));
ASSERT(!entry_name.IsNull());
const Function& entry = Function::Handle(
Z, root_library.LookupFunctionAllowPrivate(entry_name));

View file

@ -0,0 +1,16 @@
# Copyright (c) 2017, 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.
import("../application_snapshot.gni")
application_snapshot("kernel-service") {
dfe_script = "kernel-service.dart"
deps = [
"../../runtime/vm:patched_sdk($host_toolchain)",
]
main_dart = dfe_script
training_args = [
"file://" + rebase_path("../../pkg/compiler/lib/src/dart2js.dart"),
]
}

View file

@ -92,4 +92,26 @@ Future _processLoadRequest(request) async {
port.send([tag, inputFileUrl, inputFileUrl, null, result]);
}
main() => new RawReceivePort()..handler = _processLoadRequest;
// This entry point is used when running in the kernel isolate.
start() => new RawReceivePort()..handler = _processLoadRequest;
// This entry point is used when creating an app snapshot. The argument provides
// a script to compile to warm-up generated code.
main(args) {
var tag = 1;
var scriptUri = args[0];
var responsePort = new RawReceivePort();
responsePort.handler = (response) {
if (response[0] == tag) {
// Success.
responsePort.close();
} else if (response[0] == -tag) {
// Compilation error.
throw response[4];
} else {
throw "Unexpected response: $response";
}
};
var request = [tag, responsePort.sendPort, scriptUri];
_processLoadRequest(request);
}