diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2019-06-04 19:35:51 +0200 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-07-08 18:18:28 -0400 |
commit | d641782c823317a2d2f64d646a0d5b8b6c22b771 (patch) | |
tree | a03beb0939a46333636d0de68eee052978103cfe | |
parent | 79c3439f269f1e0e24003518e363988fa4f1da33 (diff) |
Rewrite snapshot_creator in Rust
-rw-r--r-- | cli/BUILD.gn | 2 | ||||
-rw-r--r-- | cli/deno.gni (renamed from deno.gni) | 6 | ||||
-rw-r--r-- | core/BUILD.gn | 12 | ||||
-rw-r--r-- | core/Cargo.toml | 4 | ||||
-rw-r--r-- | core/libdeno/BUILD.gn | 27 | ||||
-rw-r--r-- | core/libdeno/api.cc | 1 | ||||
-rw-r--r-- | core/libdeno/file_util.cc | 90 | ||||
-rw-r--r-- | core/libdeno/file_util.h | 14 | ||||
-rw-r--r-- | core/libdeno/file_util_test.cc | 46 | ||||
-rw-r--r-- | core/libdeno/snapshot_creator.cc | 46 | ||||
-rw-r--r-- | core/libdeno/test.cc | 46 | ||||
-rw-r--r-- | core/snapshot_creator.rs | 44 |
12 files changed, 98 insertions, 240 deletions
diff --git a/cli/BUILD.gn b/cli/BUILD.gn index 20a5b2dee..7f19f8b95 100644 --- a/cli/BUILD.gn +++ b/cli/BUILD.gn @@ -5,7 +5,7 @@ import("//build_extra/flatbuffers/rust/rust_flatbuffer.gni") import("//build_extra/rust/rust.gni") import("//third_party/v8/gni/snapshot_toolchain.gni") import("//third_party/v8/gni/v8.gni") -import("../deno.gni") +import("deno.gni") main_extern = [ { diff --git a/deno.gni b/cli/deno.gni index a260edd11..dabcd43ca 100644 --- a/deno.gni +++ b/cli/deno.gni @@ -16,7 +16,8 @@ template("bundle") { ] depfile = out_dir + out_name + ".d" 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", rebase_path("//rollup.config.js", root_build_dir), "-i", @@ -45,8 +46,7 @@ template("snapshot") { "testonly", "deps", ]) - # TODO(ry) Rewrite snapshot_creator in Rust. - tool = "//core/libdeno:snapshot_creator" + tool = "//core:snapshot_creator" visibility = [ ":*" ] # Only targets in this file can depend on this. snapshot_out_bin = "$target_gen_dir/$target_name.bin" inputs = [ diff --git a/core/BUILD.gn b/core/BUILD.gn index bf9d910c0..0f1eba8ca 100644 --- a/core/BUILD.gn +++ b/core/BUILD.gn @@ -7,6 +7,7 @@ group("default") { ":deno_core_http_bench", ":deno_core_http_bench_test", ":deno_core_test", + ":snapshot_creator", ] } @@ -77,3 +78,14 @@ rust_test("deno_core_http_bench_test") { extern = http_bench_extern extern_rlib = http_bench_extern_rlib } + +rust_executable("snapshot_creator") { + source_root = "snapshot_creator.rs" + extern = [ + { + label = ":deno" + crate_name = "deno" + crate_type = "rlib" + }, + ] +} diff --git a/core/Cargo.toml b/core/Cargo.toml index b22bf7fe9..c41863da0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,6 +13,10 @@ repository = "https://github.com/denoland/deno" [lib] path = "lib.rs" +[[bin]] +name = "snapshot_creator" +path = "snapshot_creator.rs" + [dependencies] futures = "0.1.27" lazy_static = "1.3.0" diff --git a/core/libdeno/BUILD.gn b/core/libdeno/BUILD.gn index 31a5be640..10ec4bf91 100644 --- a/core/libdeno/BUILD.gn +++ b/core/libdeno/BUILD.gn @@ -1,5 +1,4 @@ # Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import("//deno.gni") import("//third_party/v8/gni/v8.gni") config("deno_config") { @@ -50,8 +49,6 @@ v8_source_set("libdeno") { "deno.h", "exceptions.cc", "exceptions.h", - "file_util.cc", - "file_util.h", "internal.h", "modules.cc", ] @@ -71,39 +68,21 @@ v8_static_library("libdeno_static_lib") { configs = [ ":deno_config" ] } -v8_executable("snapshot_creator") { - sources = [ - "snapshot_creator.cc", - ] - deps = [ - ":libdeno", - ] - configs = [ ":deno_config" ] -} - v8_executable("libdeno_test") { testonly = true sources = [ - "file_util_test.cc", "libdeno_test.cc", "modules_test.cc", "test.cc", ] deps = [ ":libdeno", - ":snapshot_test", "//testing/gtest:gtest", ] data = [ - "$target_gen_dir/snapshot_test.bin", + "libdeno_test.js", ] - snapshot_path = rebase_path(data[0], root_build_dir) - defines = [ "SNAPSHOT_PATH=\"$snapshot_path\"" ] + js_path = rebase_path(data[0]) + defines = [ "JS_PATH=\"$js_path\"" ] configs = [ ":deno_config" ] } - -# Generates $target_gen_dir/snapshot_test.bin -snapshot("snapshot_test") { - testonly = true - source_root = "libdeno_test.js" -} diff --git a/core/libdeno/api.cc b/core/libdeno/api.cc index 13057aeae..1515bca51 100644 --- a/core/libdeno/api.cc +++ b/core/libdeno/api.cc @@ -11,7 +11,6 @@ #include "deno.h" #include "exceptions.h" -#include "file_util.h" #include "internal.h" extern "C" { diff --git a/core/libdeno/file_util.cc b/core/libdeno/file_util.cc deleted file mode 100644 index 256f4f257..000000000 --- a/core/libdeno/file_util.cc +++ /dev/null @@ -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 diff --git a/core/libdeno/file_util.h b/core/libdeno/file_util.h deleted file mode 100644 index 0177f2c94..000000000 --- a/core/libdeno/file_util.h +++ /dev/null @@ -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_ diff --git a/core/libdeno/file_util_test.cc b/core/libdeno/file_util_test.cc deleted file mode 100644 index 863a31d48..000000000 --- a/core/libdeno/file_util_test.cc +++ /dev/null @@ -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); -} diff --git a/core/libdeno/snapshot_creator.cc b/core/libdeno/snapshot_creator.cc deleted file mode 100644 index bd3c8081d..000000000 --- a/core/libdeno/snapshot_creator.cc +++ /dev/null @@ -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(); -} diff --git a/core/libdeno/test.cc b/core/libdeno/test.cc index 3d022c904..0bfe374ef 100644 --- a/core/libdeno/test.cc +++ b/core/libdeno/test.cc @@ -1,28 +1,44 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. #include "test.h" +#include <fstream> #include <string> -#include "file_util.h" +#include "internal.h" deno_snapshot snapshot = {nullptr, 0}; -int main(int argc, char** argv) { - // Locate the snapshot. - std::string exe_path; - if (!deno::ExePath(&exe_path)) { - std::cerr << "deno::ExePath() failed" << std::endl; - return 1; +bool ReadFileToString(const char* fn, std::string* contents) { + std::ifstream file(fn, std::ios::binary); + if (file.fail()) { + return false; } - std::string snapshot_path = deno::Dirname(exe_path) + SNAPSHOT_PATH; + contents->assign(std::istreambuf_iterator<char>{file}, {}); + return !file.fail(); +} + +int main(int argc, char** argv) { + // All of the JS code in libdeno_test.js is tested after being snapshotted. + // We create that snapshot now at runtime, rather than at compile time to + // 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); - // Load the snapshot. - std::string contents; - if (!deno::ReadFileToString(snapshot_path.c_str(), &contents)) { - std::cerr << "Failed to read snapshot from " << snapshot_path << std::endl; + 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; } - snapshot.data_ptr = - reinterpret_cast<uint8_t*>(const_cast<char*>(contents.c_str())); - snapshot.data_len = contents.size(); + + snapshot = deno_snapshot_new(d); testing::InitGoogleTest(&argc, argv); deno_init(); diff --git a/core/snapshot_creator.rs b/core/snapshot_creator.rs new file mode 100644 index 000000000..1d43b9174 --- /dev/null +++ b/core/snapshot_creator.rs @@ -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"); +} |