mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 21:50:00 -05:00
Rewrite snapshot_creator in Rust
This commit is contained in:
parent
79c3439f26
commit
d641782c82
12 changed files with 98 additions and 240 deletions
|
@ -5,7 +5,7 @@ import("//build_extra/flatbuffers/rust/rust_flatbuffer.gni")
|
||||||
import("//build_extra/rust/rust.gni")
|
import("//build_extra/rust/rust.gni")
|
||||||
import("//third_party/v8/gni/snapshot_toolchain.gni")
|
import("//third_party/v8/gni/snapshot_toolchain.gni")
|
||||||
import("//third_party/v8/gni/v8.gni")
|
import("//third_party/v8/gni/v8.gni")
|
||||||
import("../deno.gni")
|
import("deno.gni")
|
||||||
|
|
||||||
main_extern = [
|
main_extern = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,8 @@ template("bundle") {
|
||||||
]
|
]
|
||||||
depfile = out_dir + out_name + ".d"
|
depfile = out_dir + out_name + ".d"
|
||||||
args = [
|
args = [
|
||||||
rebase_path("//third_party/node_modules/rollup/bin/rollup", root_build_dir),
|
rebase_path("//third_party/node_modules/rollup/bin/rollup",
|
||||||
|
root_build_dir),
|
||||||
"-c",
|
"-c",
|
||||||
rebase_path("//rollup.config.js", root_build_dir),
|
rebase_path("//rollup.config.js", root_build_dir),
|
||||||
"-i",
|
"-i",
|
||||||
|
@ -45,8 +46,7 @@ template("snapshot") {
|
||||||
"testonly",
|
"testonly",
|
||||||
"deps",
|
"deps",
|
||||||
])
|
])
|
||||||
# TODO(ry) Rewrite snapshot_creator in Rust.
|
tool = "//core:snapshot_creator"
|
||||||
tool = "//core/libdeno:snapshot_creator"
|
|
||||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||||
snapshot_out_bin = "$target_gen_dir/$target_name.bin"
|
snapshot_out_bin = "$target_gen_dir/$target_name.bin"
|
||||||
inputs = [
|
inputs = [
|
|
@ -7,6 +7,7 @@ group("default") {
|
||||||
":deno_core_http_bench",
|
":deno_core_http_bench",
|
||||||
":deno_core_http_bench_test",
|
":deno_core_http_bench_test",
|
||||||
":deno_core_test",
|
":deno_core_test",
|
||||||
|
":snapshot_creator",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,3 +78,14 @@ rust_test("deno_core_http_bench_test") {
|
||||||
extern = http_bench_extern
|
extern = http_bench_extern
|
||||||
extern_rlib = http_bench_extern_rlib
|
extern_rlib = http_bench_extern_rlib
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rust_executable("snapshot_creator") {
|
||||||
|
source_root = "snapshot_creator.rs"
|
||||||
|
extern = [
|
||||||
|
{
|
||||||
|
label = ":deno"
|
||||||
|
crate_name = "deno"
|
||||||
|
crate_type = "rlib"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ repository = "https://github.com/denoland/deno"
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "snapshot_creator"
|
||||||
|
path = "snapshot_creator.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1.27"
|
futures = "0.1.27"
|
||||||
lazy_static = "1.3.0"
|
lazy_static = "1.3.0"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
import("//deno.gni")
|
|
||||||
import("//third_party/v8/gni/v8.gni")
|
import("//third_party/v8/gni/v8.gni")
|
||||||
|
|
||||||
config("deno_config") {
|
config("deno_config") {
|
||||||
|
@ -50,8 +49,6 @@ v8_source_set("libdeno") {
|
||||||
"deno.h",
|
"deno.h",
|
||||||
"exceptions.cc",
|
"exceptions.cc",
|
||||||
"exceptions.h",
|
"exceptions.h",
|
||||||
"file_util.cc",
|
|
||||||
"file_util.h",
|
|
||||||
"internal.h",
|
"internal.h",
|
||||||
"modules.cc",
|
"modules.cc",
|
||||||
]
|
]
|
||||||
|
@ -71,39 +68,21 @@ v8_static_library("libdeno_static_lib") {
|
||||||
configs = [ ":deno_config" ]
|
configs = [ ":deno_config" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
v8_executable("snapshot_creator") {
|
|
||||||
sources = [
|
|
||||||
"snapshot_creator.cc",
|
|
||||||
]
|
|
||||||
deps = [
|
|
||||||
":libdeno",
|
|
||||||
]
|
|
||||||
configs = [ ":deno_config" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
v8_executable("libdeno_test") {
|
v8_executable("libdeno_test") {
|
||||||
testonly = true
|
testonly = true
|
||||||
sources = [
|
sources = [
|
||||||
"file_util_test.cc",
|
|
||||||
"libdeno_test.cc",
|
"libdeno_test.cc",
|
||||||
"modules_test.cc",
|
"modules_test.cc",
|
||||||
"test.cc",
|
"test.cc",
|
||||||
]
|
]
|
||||||
deps = [
|
deps = [
|
||||||
":libdeno",
|
":libdeno",
|
||||||
":snapshot_test",
|
|
||||||
"//testing/gtest:gtest",
|
"//testing/gtest:gtest",
|
||||||
]
|
]
|
||||||
data = [
|
data = [
|
||||||
"$target_gen_dir/snapshot_test.bin",
|
"libdeno_test.js",
|
||||||
]
|
]
|
||||||
snapshot_path = rebase_path(data[0], root_build_dir)
|
js_path = rebase_path(data[0])
|
||||||
defines = [ "SNAPSHOT_PATH=\"$snapshot_path\"" ]
|
defines = [ "JS_PATH=\"$js_path\"" ]
|
||||||
configs = [ ":deno_config" ]
|
configs = [ ":deno_config" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generates $target_gen_dir/snapshot_test.bin
|
|
||||||
snapshot("snapshot_test") {
|
|
||||||
testonly = true
|
|
||||||
source_root = "libdeno_test.js"
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
#include "deno.h"
|
#include "deno.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "file_util.h"
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <mach-o/dyld.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "file_util.h"
|
|
||||||
|
|
||||||
namespace deno {
|
|
||||||
|
|
||||||
bool ReadFileToString(const char* fn, std::string* contents) {
|
|
||||||
std::ifstream file(fn, std::ios::binary);
|
|
||||||
if (file.fail()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
contents->assign(std::istreambuf_iterator<char>{file}, {});
|
|
||||||
return !file.fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Basename(std::string const& filename) {
|
|
||||||
for (auto it = filename.rbegin(); it != filename.rend(); ++it) {
|
|
||||||
char ch = *it;
|
|
||||||
if (ch == '\\' || ch == '/') {
|
|
||||||
return std::string(it.base(), filename.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the directory component from a filename. The returned path always
|
|
||||||
// ends with a slash. This function does not understand Windows drive letters.
|
|
||||||
std::string Dirname(std::string const& filename) {
|
|
||||||
for (auto it = filename.rbegin(); it != filename.rend(); ++it) {
|
|
||||||
char ch = *it;
|
|
||||||
if (ch == '\\' || ch == '/') {
|
|
||||||
return std::string(filename.begin(), it.base());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::string("./");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the full path the currently running executable.
|
|
||||||
// This implementation is very basic. Caveats:
|
|
||||||
// * OS X: fails if buffer is too small, does not retry with a bigger buffer.
|
|
||||||
// * Windows: ANSI only, no unicode. Fails if path is longer than 260 chars.
|
|
||||||
bool ExePath(std::string* path) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Windows only.
|
|
||||||
char exe_buf[MAX_PATH];
|
|
||||||
DWORD len = GetModuleFileNameA(NULL, exe_buf, sizeof exe_buf);
|
|
||||||
if (len == 0 || len == sizeof exe_buf) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// OS X only.
|
|
||||||
char link_buf[PATH_MAX * 2]; // Exe may be longer than MAX_PATH, says Apple.
|
|
||||||
uint32_t len = sizeof link_buf;
|
|
||||||
if (_NSGetExecutablePath(link_buf, &len) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Linux only.
|
|
||||||
static const char* link_buf = "/proc/self/exe";
|
|
||||||
#endif
|
|
||||||
// Linux and OS X.
|
|
||||||
char exe_buf[PATH_MAX];
|
|
||||||
char* r = realpath(link_buf, exe_buf);
|
|
||||||
if (r == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// All platforms.
|
|
||||||
path->assign(exe_buf);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace deno
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
|
||||||
#ifndef FILE_UTIL_H_
|
|
||||||
#define FILE_UTIL_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace deno {
|
|
||||||
bool ReadFileToString(const char* fn, std::string* contents);
|
|
||||||
std::string Basename(std::string const& filename);
|
|
||||||
std::string Dirname(std::string const& filename);
|
|
||||||
bool ExePath(std::string* path);
|
|
||||||
} // namespace deno
|
|
||||||
|
|
||||||
#endif // FILE_UTIL_H_
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
|
||||||
|
|
||||||
#include "file_util.h"
|
|
||||||
|
|
||||||
TEST(FileUtilTest, ReadFileToStringFileNotExist) {
|
|
||||||
std::string output;
|
|
||||||
EXPECT_FALSE(deno::ReadFileToString("/should_error_out.txt", &output));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FileUtilTest, Basename) {
|
|
||||||
EXPECT_EQ("foo.txt", deno::Basename("foo.txt"));
|
|
||||||
EXPECT_EQ("foo.txt", deno::Basename("/foo.txt"));
|
|
||||||
EXPECT_EQ("", deno::Basename("/foo/"));
|
|
||||||
EXPECT_EQ("", deno::Basename("foo/"));
|
|
||||||
EXPECT_EQ("", deno::Basename("/"));
|
|
||||||
EXPECT_EQ("foo.txt", deno::Basename(".\\foo.txt"));
|
|
||||||
EXPECT_EQ("foo.txt", deno::Basename("/home/ryan/foo.txt"));
|
|
||||||
EXPECT_EQ("foo.txt", deno::Basename("C:\\home\\ryan\\foo.txt"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FileUtilTest, Dirname) {
|
|
||||||
EXPECT_EQ("home/dank/", deno::Dirname("home/dank/memes.gif"));
|
|
||||||
EXPECT_EQ("/home/dank/", deno::Dirname("/home/dank/memes.gif"));
|
|
||||||
EXPECT_EQ("/home/dank/", deno::Dirname("/home/dank/"));
|
|
||||||
EXPECT_EQ("home/dank/", deno::Dirname("home/dank/memes.gif"));
|
|
||||||
EXPECT_EQ("/", deno::Dirname("/"));
|
|
||||||
EXPECT_EQ(".\\", deno::Dirname(".\\memes.gif"));
|
|
||||||
EXPECT_EQ("c:\\", deno::Dirname("c:\\stuff"));
|
|
||||||
EXPECT_EQ("./", deno::Dirname("nothing"));
|
|
||||||
EXPECT_EQ("./", deno::Dirname(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FileUtilTest, ExePath) {
|
|
||||||
std::string exe_path;
|
|
||||||
EXPECT_TRUE(deno::ExePath(&exe_path));
|
|
||||||
// Path is absolute.
|
|
||||||
EXPECT_TRUE(exe_path.find("/") == 0 || exe_path.find(":\\") == 1);
|
|
||||||
// FIlename is the name of the test binary.
|
|
||||||
std::string exe_filename = deno::Basename(exe_path);
|
|
||||||
EXPECT_EQ(exe_filename.find("libdeno_test"), 0u);
|
|
||||||
// Path exists (also tests ReadFileToString).
|
|
||||||
std::string contents;
|
|
||||||
EXPECT_TRUE(deno::ReadFileToString(exe_path.c_str(), &contents));
|
|
||||||
EXPECT_NE(contents.find("Inception :)"), std::string::npos);
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
|
||||||
// Hint: --trace_serializer is a useful debugging flag.
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include "deno.h"
|
|
||||||
#include "file_util.h"
|
|
||||||
#include "internal.h"
|
|
||||||
#include "third_party/v8/include/v8.h"
|
|
||||||
#include "third_party/v8/src/base/logging.h"
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
const char* snapshot_out_bin = argv[1];
|
|
||||||
const char* js_fn = argv[2];
|
|
||||||
|
|
||||||
deno_set_v8_flags(&argc, argv);
|
|
||||||
|
|
||||||
CHECK_NOT_NULL(js_fn);
|
|
||||||
CHECK_NOT_NULL(snapshot_out_bin);
|
|
||||||
|
|
||||||
std::string js_source;
|
|
||||||
CHECK(deno::ReadFileToString(js_fn, &js_source));
|
|
||||||
|
|
||||||
deno_init();
|
|
||||||
deno_config config = {1, deno::empty_snapshot, deno::empty_buf, nullptr,
|
|
||||||
nullptr};
|
|
||||||
Deno* d = deno_new(config);
|
|
||||||
|
|
||||||
deno_execute(d, nullptr, js_fn, js_source.c_str());
|
|
||||||
if (deno_last_exception(d) != nullptr) {
|
|
||||||
std::cerr << "Snapshot Exception " << std::endl;
|
|
||||||
std::cerr << deno_last_exception(d) << std::endl;
|
|
||||||
deno_delete(d);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto snapshot = deno_snapshot_new(d);
|
|
||||||
|
|
||||||
std::ofstream file_(snapshot_out_bin, std::ios::binary);
|
|
||||||
file_.write(reinterpret_cast<char*>(snapshot.data_ptr), snapshot.data_len);
|
|
||||||
file_.close();
|
|
||||||
|
|
||||||
deno_snapshot_delete(snapshot);
|
|
||||||
deno_delete(d);
|
|
||||||
|
|
||||||
return file_.bad();
|
|
||||||
}
|
|
|
@ -1,28 +1,44 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "file_util.h"
|
#include "internal.h"
|
||||||
|
|
||||||
deno_snapshot snapshot = {nullptr, 0};
|
deno_snapshot snapshot = {nullptr, 0};
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
bool ReadFileToString(const char* fn, std::string* contents) {
|
||||||
// Locate the snapshot.
|
std::ifstream file(fn, std::ios::binary);
|
||||||
std::string exe_path;
|
if (file.fail()) {
|
||||||
if (!deno::ExePath(&exe_path)) {
|
return false;
|
||||||
std::cerr << "deno::ExePath() failed" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
std::string snapshot_path = deno::Dirname(exe_path) + SNAPSHOT_PATH;
|
contents->assign(std::istreambuf_iterator<char>{file}, {});
|
||||||
|
return !file.fail();
|
||||||
|
}
|
||||||
|
|
||||||
// Load the snapshot.
|
int main(int argc, char** argv) {
|
||||||
std::string contents;
|
// All of the JS code in libdeno_test.js is tested after being snapshotted.
|
||||||
if (!deno::ReadFileToString(snapshot_path.c_str(), &contents)) {
|
// We create that snapshot now at runtime, rather than at compile time to
|
||||||
std::cerr << "Failed to read snapshot from " << snapshot_path << std::endl;
|
// simplify the build process. So we load and execute the libdeno_test.js
|
||||||
|
// file, without running any of the tests and store the result in the global
|
||||||
|
// "snapshot" variable, which will be used later in the tests.
|
||||||
|
std::string js_fn = JS_PATH;
|
||||||
|
std::string js_source;
|
||||||
|
CHECK(ReadFileToString(js_fn.c_str(), &js_source));
|
||||||
|
|
||||||
|
deno_init();
|
||||||
|
deno_config config = {1, deno::empty_snapshot, deno::empty_buf, nullptr,
|
||||||
|
nullptr};
|
||||||
|
Deno* d = deno_new(config);
|
||||||
|
|
||||||
|
deno_execute(d, nullptr, js_fn.c_str(), js_source.c_str());
|
||||||
|
if (deno_last_exception(d) != nullptr) {
|
||||||
|
std::cerr << "Snapshot Exception " << std::endl;
|
||||||
|
std::cerr << deno_last_exception(d) << std::endl;
|
||||||
|
deno_delete(d);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
snapshot.data_ptr =
|
|
||||||
reinterpret_cast<uint8_t*>(const_cast<char*>(contents.c_str()));
|
snapshot = deno_snapshot_new(d);
|
||||||
snapshot.data_len = contents.size();
|
|
||||||
|
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
deno_init();
|
deno_init();
|
||||||
|
|
44
core/snapshot_creator.rs
Normal file
44
core/snapshot_creator.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Note: This is a nearly identical rewrite of core/libdeno/snapshot_creator.cc
|
||||||
|
// but in Rust.
|
||||||
|
//
|
||||||
|
// This snapshot program is considered "basic" because the code being
|
||||||
|
// snapshotted cannot call ops.
|
||||||
|
|
||||||
|
extern crate deno;
|
||||||
|
|
||||||
|
use deno::js_check;
|
||||||
|
use deno::Isolate;
|
||||||
|
use deno::StartupData;
|
||||||
|
use std::env;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
// NOTE: `--help` arg will display V8 help and exit
|
||||||
|
let args = deno::v8_set_flags(args);
|
||||||
|
|
||||||
|
let (snapshot_out_bin, js_filename) = if args.len() == 3 {
|
||||||
|
(args[1].clone(), args[2].clone())
|
||||||
|
} else {
|
||||||
|
eprintln!("Usage: snapshot_creator <out_filename> <js_filename>");
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
let js_source =
|
||||||
|
std::fs::read(&js_filename).expect("couldn't read js_filename");
|
||||||
|
let js_source_str = std::str::from_utf8(&js_source).unwrap();
|
||||||
|
|
||||||
|
let will_snapshot = true;
|
||||||
|
let mut isolate = Isolate::new(StartupData::None, will_snapshot);
|
||||||
|
|
||||||
|
js_check(isolate.execute(&js_filename, js_source_str));
|
||||||
|
|
||||||
|
let snapshot = isolate.snapshot().expect("error snapshotting");
|
||||||
|
|
||||||
|
let mut out_file = std::fs::File::create(snapshot_out_bin).unwrap();
|
||||||
|
let snapshot_slice =
|
||||||
|
unsafe { std::slice::from_raw_parts(snapshot.data_ptr, snapshot.data_len) };
|
||||||
|
out_file
|
||||||
|
.write_all(snapshot_slice)
|
||||||
|
.expect("Failed to write snapshot file");
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue