Reapply "Create an app snapshot of the Dart front end."

Skip training on Windows, issue #28532.

R=hausner@google.com

Review-Url: https://codereview.chromium.org/2665753002 .
This commit is contained in:
Ryan Macnak 2017-01-31 09:47:51 -08:00
parent b8aca22c6a
commit 9eb216a495
8 changed files with 249 additions and 205 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

@ -811,6 +811,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 newly created Isolate on success, NULL on failure.
static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate,
const char* script_uri,
@ -829,10 +996,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;
}
}
@ -855,6 +1022,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
@ -958,10 +1138,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);
@ -1313,173 +1489,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

@ -74,10 +74,8 @@ class RunKernelTask : public ThreadPool::Task {
isolate = reinterpret_cast<Isolate*>(create_callback(
KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error));
if (isolate == NULL) {
if (FLAG_trace_kernel) {
OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n",
error);
}
OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n",
error);
KernelIsolate::SetKernelIsolate(NULL);
KernelIsolate::FinishedInitializing();
return;
@ -151,10 +149,8 @@ class RunKernelTask : public ThreadPool::Task {
const Library& root_library =
Library::Handle(Z, I->object_store()->root_library());
if (root_library.IsNull()) {
if (FLAG_trace_kernel) {
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not install a script.");
}
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not install a script.");
// Kernel isolate is not supported by embedder.
return false;
}
@ -165,10 +161,8 @@ class RunKernelTask : public ThreadPool::Task {
Z, root_library.LookupFunctionAllowPrivate(entry_name));
if (entry.IsNull()) {
// Kernel isolate is not supported by embedder.
if (FLAG_trace_kernel) {
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not provide a main function.");
}
OS::Print(DART_KERNEL_ISOLATE_NAME
": Embedder did not provide a main function.");
return false;
}
ASSERT(!entry.IsNull());
@ -177,12 +171,10 @@ class RunKernelTask : public ThreadPool::Task {
ASSERT(!result.IsNull());
if (result.IsError()) {
// Kernel isolate did not initialize properly.
if (FLAG_trace_kernel) {
const Error& error = Error::Cast(result);
OS::Print(DART_KERNEL_ISOLATE_NAME
": Calling main resulted in an error: %s",
error.ToErrorCString());
}
const Error& error = Error::Cast(result);
OS::Print(DART_KERNEL_ISOLATE_NAME
": Calling main resulted in an error: %s",
error.ToErrorCString());
return false;
}
ASSERT(result.IsReceivePort());

View file

@ -223,7 +223,7 @@ class NoneCompilerConfiguration extends CompilerConfiguration {
CommandArtifact artifact) {
List<String> args = [];
if (useDFEIsolate) {
args.add('--dfe=runtime/tools/kernel-service.dart');
args.add('--dfe=utils/kernel-service/kernel-service.dart');
}
if (isChecked) {
args.add('--enable_asserts');

View file

@ -2389,7 +2389,7 @@ class BatchDFEProcess {
Future _startProcess() async {
final executable = io.Platform.executable;
final arguments = ['runtime/tools/kernel-service.dart', '--batch'];
final arguments = ['utils/kernel-service/kernel-service.dart', '--batch'];
try {
_port = -1;

View file

@ -0,0 +1,17 @@
# 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 = [
"--train",
"file://" + rebase_path("../../pkg/compiler/lib/src/dart2js.dart"),
]
}

View file

@ -11,12 +11,12 @@ library runtime.tools.kernel_service;
// This is either invoked as the root script of the Kernel isolate when used
// as a part of
//
// dart --dfe=runtime/tools/kernel-service.dart ...
// dart --dfe=utils/kernel-service/kernel-service.dart ...
//
// invocation or it is invoked as a standalone script to perform batch mode
// compilation requested via an HTTP interface
//
// dart runtime/tools/kernel-service.dart --batch
// dart utils/kernel-service/kernel-service.dart --batch
//
// The port for the batch mode worker is controlled by DFE_WORKER_PORT
// environment declarations (set by -DDFE_WORKER_PORT=... command line flag).
@ -312,9 +312,34 @@ void startBatchServer() {
});
}
train(String scriptUri) {
// TODO(28532): Enable on Windows.
if (Platform.isWindows) return;
var tag = 1;
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);
}
main([args]) {
if (args?.length == 1 && args[0] == '--batch') {
startBatchServer();
} else if (args?.length == 2 && args[0] == '--train') {
// This entry point is used when creating an app snapshot. The argument
// provides a script to compile to warm-up generated code.
train(args[1]);
} else {
// Entry point for the Kernel isolate.
return new RawReceivePort()..handler = _processLoadRequest;