1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 16:49:18 -05:00

Replace libdeno with rusty_v8 (#3556)

This commit is contained in:
Ry Dahl 2020-01-05 09:19:29 -05:00 committed by GitHub
parent c41280a057
commit 5f1df038fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 2292 additions and 7304 deletions

View file

@ -103,9 +103,6 @@ jobs:
rustc --version rustc --version
cargo --version cargo --version
- name: Run setup.py
run: python ./tools/setup.py
- name: Start sccache - name: Start sccache
env: env:
AWS_ACCESS_KEY_ID: AKIAIVRN52PLDBP55LBQ AWS_ACCESS_KEY_ID: AKIAIVRN52PLDBP55LBQ

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "chromium_build"]
path = core/libdeno/build
url = https://github.com/denoland/chromium_build.git
[submodule "deno_third_party"] [submodule "deno_third_party"]
path = third_party path = third_party
url = https://github.com/denoland/deno_third_party.git url = https://github.com/denoland/deno_third_party.git

38
Cargo.lock generated
View file

@ -26,7 +26,7 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.25" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -139,6 +139,11 @@ dependencies = [
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "cargo_gn"
version = "0.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.48" version = "1.0.48"
@ -257,6 +262,7 @@ dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rusty_v8 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1284,6 +1290,18 @@ dependencies = [
"security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rusty_v8"
version = "0.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_gn 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rustyline" name = "rustyline"
version = "5.0.5" version = "5.0.5"
@ -1959,7 +1977,7 @@ name = "wasm-bindgen-webidl"
version = "0.2.56" version = "0.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1974,7 +1992,7 @@ name = "web-sys"
version = "0.3.33" version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)",
"sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2006,6 +2024,15 @@ dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "which"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.8" version = "0.2.8"
@ -2073,7 +2100,7 @@ dependencies = [
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" "checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" "checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" "checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
@ -2090,6 +2117,7 @@ dependencies = [
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10004c15deb332055f7a4a208190aed362cf9a7c2f6ab70a305fba50e1105f38" "checksum bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10004c15deb332055f7a4a208190aed362cf9a7c2f6ab70a305fba50e1105f38"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
"checksum cargo_gn 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba7d7f7b201dfcbc314b14f2176c92f8ba521dab538b40e426ffed25ed7cd80"
"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
@ -2205,6 +2233,7 @@ dependencies = [
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" "checksum rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e"
"checksum rustls-native-certs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51ffebdbb48c14f84eba0b715197d673aff1dd22cc1007ca647e28483bbcc307" "checksum rustls-native-certs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51ffebdbb48c14f84eba0b715197d673aff1dd22cc1007ca647e28483bbcc307"
"checksum rusty_v8 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "43577801363788a510ec79184ee734f2de7c237ee6cceb5f0dc15dbc9bb74137"
"checksum rustyline 5.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae156e2a68be20a3ae95574089b65c188d86291cd5421cc647222b8d1864ffb" "checksum rustyline 5.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae156e2a68be20a3ae95574089b65c188d86291cd5421cc647222b8d1864ffb"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" "checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
@ -2284,6 +2313,7 @@ dependencies = [
"checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4" "checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4"
"checksum webpki-roots 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b" "checksum webpki-roots 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b"
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" "checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
"checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View file

@ -248,9 +248,8 @@ testPerm({ env: true }, function getDir(): void {
for (const r of s.runtime) { for (const r of s.runtime) {
if (Deno.build.os !== r.os) continue; if (Deno.build.os !== r.os) continue;
if (r.shouldHaveValue) { if (r.shouldHaveValue) {
assertNotEquals(Deno.dir(s.kind), ""); const d = Deno.dir(s.kind);
} else { assert(d.length > 0);
assertEquals(Deno.dir(s.kind), null);
} }
} }
} }

View file

@ -102,11 +102,6 @@ fn repl_test() {
util::run_python_script("tools/repl_test.py") util::run_python_script("tools/repl_test.py")
} }
#[test]
fn setup_test() {
util::run_python_script("tools/setup_test.py")
}
#[test] #[test]
fn target_test() { fn target_test() {
util::run_python_script("tools/target_test.py") util::run_python_script("tools/target_test.py")

View file

@ -22,6 +22,9 @@ log = "0.4.8"
serde_json = "1.0.41" serde_json = "1.0.41"
url = "2.1" url = "2.1"
rusty_v8 = "0.0.23"
# rusty_v8 = { path = "../../rusty_v8" }
[[example]] [[example]]
name = "deno_core_http_bench" name = "deno_core_http_bench"
path = "examples/http_bench.rs" path = "examples/http_bench.rs"

View file

@ -1,148 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Run "cargo build -vv" if you want to see gn output.
fn main() {
let build = gn::Build::setup();
println!("cargo:rustc-link-search=native={}/obj", build.gn_out_dir);
build.run("default");
}
mod gn {
use std::env;
use std::path::{self, Path, PathBuf};
use std::process::Command;
pub struct Build {
gn_mode: String,
root: PathBuf,
pub gn_out_dir: String,
pub gn_out_path: PathBuf,
pub check_only: bool,
}
impl Build {
pub fn setup() -> Build {
let gn_mode = if cfg!(target_os = "windows") {
// On Windows, we need to link with a release build of libdeno, because
// rust always uses the release CRT.
// TODO(piscisaureus): make linking with debug libdeno possible.
String::from("release")
} else {
// Cargo sets PROFILE to either "debug" or "release", which conveniently
// matches the build modes we support.
env::var("PROFILE").unwrap()
};
// cd into workspace root.
assert!(env::set_current_dir("..").is_ok());
let root = env::current_dir().unwrap();
// If not using host default target the output folder will change
// target/release will become target/$TARGET/release
// Gn should also be using this output directory as well
// most things will work with gn using the default
// output directory but some tests depend on artifacts
// being in a specific directory relative to the main build output
let gn_out_path = root.join(format!("target/{}", gn_mode.clone()));
let gn_out_dir = normalize_path(&gn_out_path);
// Tell Cargo when to re-run this file. We do this first, so these directives
// can take effect even if something goes wrong later in the build process.
println!("cargo:rerun-if-env-changed=DENO_BUILD_PATH");
// This helps Rust source files locate the snapshot, source map etc.
println!("cargo:rustc-env=GN_OUT_DIR={}", gn_out_dir);
// Detect if we're being invoked by the rust language server (RLS).
// Unfortunately we can't detect whether we're being run by `cargo check`.
let check_only = env::var_os("CARGO")
.map(PathBuf::from)
.as_ref()
.and_then(|p| p.file_stem())
.and_then(|f| f.to_str())
.map(|s| s.starts_with("rls"))
.unwrap_or(false);
if check_only {
// Enable the 'check_only' feature, which enables some workarounds in the
// rust source code to compile successfully without a bundle and snapshot
println!("cargo:rustc-cfg=feature=\"check-only\"");
}
Build {
gn_out_dir,
gn_out_path,
check_only,
gn_mode,
root,
}
}
pub fn run(&self, gn_target: &str) {
if !self.gn_out_path.join("build.ninja").exists() {
let mut cmd = Command::new("python");
cmd.env("DENO_BUILD_PATH", &self.gn_out_dir);
cmd.env("DENO_BUILD_MODE", &self.gn_mode);
cmd.env("DEPOT_TOOLS_WIN_TOOLCHAIN", "0");
cmd.arg("./tools/setup.py");
if env::var_os("DENO_NO_BINARY_DOWNLOAD").is_some() {
cmd.arg("--no-binary-download");
}
let status = cmd.status().expect("setup.py failed");
assert!(status.success());
}
let mut ninja = Command::new("third_party/depot_tools/ninja");
let ninja = if !cfg!(target_os = "windows") {
&mut ninja
} else {
// Windows needs special configuration. This is similar to the function of
// python_env() in //tools/util.py.
let python_path: Vec<String> = vec![
"third_party/python_packages",
"third_party/python_packages/win32",
"third_party/python_packages/win32/lib",
"third_party/python_packages/Pythonwin",
]
.into_iter()
.map(|p| self.root.join(p).into_os_string().into_string().unwrap())
.collect();
let orig_path = String::from(";")
+ &env::var_os("PATH").unwrap().into_string().unwrap();
let path = self
.root
.join("third_party/python_packages/pywin32_system32")
.into_os_string()
.into_string()
.unwrap();
ninja
.env("PYTHONPATH", python_path.join(";"))
.env("PATH", path + &orig_path)
.env("DEPOT_TOOLS_WIN_TOOLCHAIN", "0")
};
let status = ninja
.arg(gn_target)
.arg("-C")
.arg(&self.gn_out_dir)
.status()
.expect("ninja failed");
assert!(status.success());
}
}
// Utility function to make a path absolute, normalizing it to use forward
// slashes only. The returned value is an owned String, otherwise panics.
fn normalize_path<T: AsRef<Path>>(path: T) -> String {
path
.as_ref()
.to_str()
.unwrap()
.to_owned()
.chars()
.map(|c| if path::is_separator(c) { '/' } else { c })
.collect()
}
}

View file

@ -1,44 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
//! This module wraps libdeno::deno_set_v8_flags use rusty_v8 as v8;
use crate::libdeno::deno_set_v8_flags;
use libc::c_char;
use libc::c_int;
use std::ffi::CStr;
use std::ffi::CString;
use std::vec::Vec;
/// Pass the command line arguments to v8. /// Pass the command line arguments to v8.
/// Returns a vector of command line arguments that V8 did not understand. /// Returns a vector of command line arguments that V8 did not understand.
pub fn v8_set_flags(args: Vec<String>) -> Vec<String> { pub fn v8_set_flags(args: Vec<String>) -> Vec<String> {
// deno_set_v8_flags(int* argc, char** argv) mutates argc and argv to remove v8::V8::set_flags_from_command_line(args)
// flags that v8 understands.
// Make a new array, that can be modified by V8::SetFlagsFromCommandLine(),
// containing mutable raw pointers to the individual command line args.
let mut raw_argv = args
.iter()
.map(|arg| CString::new(arg.as_str()).unwrap().into_bytes_with_nul())
.collect::<Vec<_>>();
let mut c_argv = raw_argv
.iter_mut()
.map(|arg| arg.as_mut_ptr() as *mut c_char)
.collect::<Vec<_>>();
// Store the length of the c_argv array in a local variable. We'll pass
// a pointer to this local variable to deno_set_v8_flags(), which then
// updates its value.
let mut c_argv_len = c_argv.len() as c_int;
// Let v8 parse the arguments it recognizes and remove them from c_argv.
unsafe { deno_set_v8_flags(&mut c_argv_len, c_argv.as_mut_ptr()) };
// If c_argv_len was updated we have to change the length of c_argv to match.
c_argv.truncate(c_argv_len as usize);
// Copy the modified arguments list into a proper rust vec and return it.
c_argv
.iter()
.map(|ptr| unsafe {
let cstr = CStr::from_ptr(*ptr as *const c_char);
let slice = cstr.to_str().unwrap();
slice.to_string()
})
.collect()
} }

View file

@ -12,10 +12,8 @@ use crate::libdeno;
use crate::libdeno::deno_buf; use crate::libdeno::deno_buf;
use crate::libdeno::deno_dyn_import_id; use crate::libdeno::deno_dyn_import_id;
use crate::libdeno::deno_mod; use crate::libdeno::deno_mod;
use crate::libdeno::deno_pinned_buf;
use crate::libdeno::PinnedBuf; use crate::libdeno::PinnedBuf;
use crate::libdeno::Snapshot1; use crate::libdeno::Snapshot1;
use crate::libdeno::Snapshot2;
use crate::ops::*; use crate::ops::*;
use crate::shared_queue::SharedQueue; use crate::shared_queue::SharedQueue;
use crate::shared_queue::RECOMMENDED_SIZE; use crate::shared_queue::RECOMMENDED_SIZE;
@ -29,15 +27,11 @@ use futures::stream::StreamFuture;
use futures::stream::TryStream; use futures::stream::TryStream;
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use futures::task::AtomicWaker; use futures::task::AtomicWaker;
use libc::c_char;
use libc::c_void; use libc::c_void;
use libc::strdup;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString;
use std::fmt; use std::fmt;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::ptr::null;
use std::sync::{Arc, Mutex, Once}; use std::sync::{Arc, Mutex, Once};
use std::task::Context; use std::task::Context;
use std::task::Poll; use std::task::Poll;
@ -153,8 +147,8 @@ impl From<Script<'_>> for OwnedScript {
/// in the form of the StartupScript struct. /// in the form of the StartupScript struct.
pub enum StartupData<'a> { pub enum StartupData<'a> {
Script(Script<'a>), Script(Script<'a>),
Snapshot(&'a [u8]), Snapshot(&'static [u8]),
LibdenoSnapshot(Snapshot1<'a>), LibdenoSnapshot(Snapshot1),
None, None,
} }
@ -170,8 +164,8 @@ type IsolateErrorHandleFn = dyn FnMut(ErrBox) -> Result<(), ErrBox>;
/// by implementing dispatcher function that takes control buffer and optional zero copy buffer /// by implementing dispatcher function that takes control buffer and optional zero copy buffer
/// as arguments. An async Op corresponds exactly to a Promise in JavaScript. /// as arguments. An async Op corresponds exactly to a Promise in JavaScript.
pub struct Isolate { pub struct Isolate {
libdeno_isolate: *const libdeno::isolate, libdeno_isolate: *mut libdeno::isolate,
shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>, shared_libdeno_isolate: Arc<Mutex<Option<*mut libdeno::isolate>>>,
dyn_import: Option<Arc<DynImportFn>>, dyn_import: Option<Arc<DynImportFn>>,
js_error_create: Arc<JSErrorCreateFn>, js_error_create: Arc<JSErrorCreateFn>,
needs_init: bool, needs_init: bool,
@ -212,7 +206,7 @@ impl Isolate {
let mut libdeno_config = libdeno::deno_config { let mut libdeno_config = libdeno::deno_config {
will_snapshot: will_snapshot.into(), will_snapshot: will_snapshot.into(),
load_snapshot: Snapshot2::empty(), load_snapshot: None,
shared: shared.as_deno_buf(), shared: shared.as_deno_buf(),
recv_cb: Self::pre_dispatch, recv_cb: Self::pre_dispatch,
dyn_import_cb: Self::dyn_import, dyn_import_cb: Self::dyn_import,
@ -226,10 +220,10 @@ impl Isolate {
startup_script = Some(d.into()); startup_script = Some(d.into());
} }
StartupData::Snapshot(d) => { StartupData::Snapshot(d) => {
libdeno_config.load_snapshot = d.into(); libdeno_config.load_snapshot = Some(d.into());
} }
StartupData::LibdenoSnapshot(d) => { StartupData::LibdenoSnapshot(d) => {
libdeno_config.load_snapshot = d; libdeno_config.load_snapshot = Some(d.into());
} }
StartupData::None => {} StartupData::None => {}
}; };
@ -310,16 +304,14 @@ impl Isolate {
} }
} }
extern "C" fn dyn_import( fn dyn_import(
user_data: *mut c_void, user_data: *mut c_void,
specifier: *const c_char, specifier: &str,
referrer: *const c_char, referrer: &str,
id: deno_dyn_import_id, id: deno_dyn_import_id,
) { ) {
assert_ne!(user_data, std::ptr::null_mut()); assert_ne!(user_data, std::ptr::null_mut());
let isolate = unsafe { Isolate::from_raw_ptr(user_data) }; let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
let specifier = unsafe { CStr::from_ptr(specifier).to_str().unwrap() };
let referrer = unsafe { CStr::from_ptr(referrer).to_str().unwrap() };
debug!("dyn_import specifier {} referrer {} ", specifier, referrer); debug!("dyn_import specifier {} referrer {} ", specifier, referrer);
if let Some(ref f) = isolate.dyn_import { if let Some(ref f) = isolate.dyn_import {
@ -334,19 +326,18 @@ impl Isolate {
} }
} }
extern "C" fn pre_dispatch( fn pre_dispatch(
user_data: *mut c_void, user_data: *mut c_void,
op_id: OpId, op_id: OpId,
control_buf: deno_buf, control_buf: deno_buf,
zero_copy_buf: deno_pinned_buf, zero_copy_buf: Option<PinnedBuf>,
) { ) {
let isolate = unsafe { Isolate::from_raw_ptr(user_data) }; let isolate = unsafe { Isolate::from_raw_ptr(user_data) };
let maybe_op = isolate.op_registry.call( let maybe_op =
op_id, isolate
control_buf.as_ref(), .op_registry
PinnedBuf::new(zero_copy_buf), .call(op_id, control_buf.as_ref(), zero_copy_buf);
);
let op = match maybe_op { let op = match maybe_op {
Some(op) => op, Some(op) => op,
@ -397,45 +388,39 @@ impl Isolate {
js_source: &str, js_source: &str,
) -> Result<(), ErrBox> { ) -> Result<(), ErrBox> {
self.shared_init(); self.shared_init();
let filename = CString::new(js_filename).unwrap();
let source = CString::new(js_source).unwrap();
unsafe { unsafe {
libdeno::deno_execute( libdeno::deno_execute(
self.libdeno_isolate, self.libdeno_isolate,
self.as_raw_ptr(), self as *mut _ as *mut c_void,
filename.as_ptr(), js_filename,
source.as_ptr(), js_source,
) )
}; };
self.check_last_exception() self.check_last_exception()
} }
fn check_last_exception(&mut self) -> Result<(), ErrBox> { fn check_last_exception(&mut self) -> Result<(), ErrBox> {
let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) }; let maybe_err =
if ptr.is_null() { unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
Ok(()) match maybe_err {
} else { None => Ok(()),
Some(json_str) => {
let js_error_create = &*self.js_error_create; let js_error_create = &*self.js_error_create;
let cstr = unsafe { CStr::from_ptr(ptr) };
if self.error_handler.is_some() { if self.error_handler.is_some() {
// We duplicate the string and assert ownership.
// This is due to we want the user to safely clone the error.
let cstring = unsafe { CString::from_raw(strdup(ptr)) };
// We need to clear last exception to avoid double handling. // We need to clear last exception to avoid double handling.
unsafe { libdeno::deno_clear_last_exception(self.libdeno_isolate) }; unsafe { libdeno::deno_clear_last_exception(self.libdeno_isolate) };
let json_string = cstring.into_string().unwrap(); let v8_exception = V8Exception::from_json(&json_str).unwrap();
let v8_exception = V8Exception::from_json(&json_string).unwrap();
let js_error = js_error_create(v8_exception); let js_error = js_error_create(v8_exception);
let handler = self.error_handler.as_mut().unwrap(); let handler = self.error_handler.as_mut().unwrap();
handler(js_error) handler(js_error)
} else { } else {
let json_str = cstr.to_str().unwrap(); let v8_exception = V8Exception::from_json(&json_str).unwrap();
let v8_exception = V8Exception::from_json(json_str).unwrap();
let js_error = js_error_create(v8_exception); let js_error = js_error_create(v8_exception);
Err(js_error) Err(js_error)
} }
} }
} }
}
fn check_promise_errors(&self) { fn check_promise_errors(&self) {
unsafe { unsafe {
@ -444,9 +429,8 @@ impl Isolate {
} }
fn throw_exception(&mut self, exception_text: &str) { fn throw_exception(&mut self, exception_text: &str) {
let text = CString::new(exception_text).unwrap();
unsafe { unsafe {
libdeno::deno_throw_exception(self.libdeno_isolate, text.as_ptr()) libdeno::deno_throw_exception(self.libdeno_isolate, exception_text)
} }
} }
@ -471,14 +455,8 @@ impl Isolate {
name: &str, name: &str,
source: &str, source: &str,
) -> Result<deno_mod, ErrBox> { ) -> Result<deno_mod, ErrBox> {
let name_ = CString::new(name.to_string()).unwrap();
let name_ptr = name_.as_ptr() as *const libc::c_char;
let source_ = CString::new(source.to_string()).unwrap();
let source_ptr = source_.as_ptr() as *const libc::c_char;
let id = unsafe { let id = unsafe {
libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr) libdeno::deno_mod_new(self.libdeno_isolate, main, name, source)
}; };
self.check_last_exception().map(|_| id) self.check_last_exception().map(|_| id)
@ -489,12 +467,10 @@ impl Isolate {
unsafe { libdeno::deno_mod_imports_len(self.libdeno_isolate, id) }; unsafe { libdeno::deno_mod_imports_len(self.libdeno_isolate, id) };
let mut out = Vec::new(); let mut out = Vec::new();
for i in 0..len { for i in 0..len {
let specifier_ptr = let specifier =
unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) }; unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) }
let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) }; .unwrap();
let specifier: &str = specifier_c.to_str().unwrap(); out.push(specifier);
out.push(specifier.to_string());
} }
out out
} }
@ -505,15 +481,11 @@ impl Isolate {
/// ErrBox can be downcast to a type that exposes additional information about /// ErrBox can be downcast to a type that exposes additional information about
/// the V8 exception. By default this type is CoreJSError, however it may be a /// the V8 exception. By default this type is CoreJSError, however it may be a
/// different type if Isolate::set_js_error_create() has been used. /// different type if Isolate::set_js_error_create() has been used.
pub fn snapshot(&mut self) -> Result<Snapshot1<'static>, ErrBox> { pub fn snapshot(&mut self) -> Result<Snapshot1, ErrBox> {
let snapshot = unsafe { libdeno::deno_snapshot_new(self.libdeno_isolate) }; let snapshot = libdeno::deno_snapshot_new(self.libdeno_isolate);
match self.check_last_exception() { match self.check_last_exception() {
Ok(..) => Ok(snapshot), Ok(..) => Ok(snapshot),
Err(err) => { Err(err) => Err(err),
assert_eq!(snapshot.data_ptr, null());
assert_eq!(snapshot.data_len, 0);
Err(err)
}
} }
} }
@ -526,11 +498,7 @@ impl Isolate {
let (mod_id, maybe_err_str) = match result { let (mod_id, maybe_err_str) = match result {
Ok(mod_id) => (mod_id, None), Ok(mod_id) => (mod_id, None),
Err(None) => (0, None), Err(None) => (0, None),
Err(Some(err_str)) => (0, Some(CString::new(err_str).unwrap())), Err(Some(err_str)) => (0, Some(err_str)),
};
let err_str_ptr = match maybe_err_str {
Some(ref err_str) => err_str.as_ptr(),
None => std::ptr::null(),
}; };
unsafe { unsafe {
libdeno::deno_dyn_import_done( libdeno::deno_dyn_import_done(
@ -538,7 +506,7 @@ impl Isolate {
self.as_raw_ptr(), self.as_raw_ptr(),
id, id,
mod_id, mod_id,
err_str_ptr, maybe_err_str,
) )
}; };
self.check_last_exception() self.check_last_exception()
@ -662,11 +630,11 @@ impl Isolate {
} }
struct LockerScope { struct LockerScope {
libdeno_isolate: *const libdeno::isolate, libdeno_isolate: *mut libdeno::isolate,
} }
impl LockerScope { impl LockerScope {
fn new(libdeno_isolate: *const libdeno::isolate) -> LockerScope { fn new(libdeno_isolate: *mut libdeno::isolate) -> LockerScope {
unsafe { libdeno::deno_lock(libdeno_isolate) } unsafe { libdeno::deno_lock(libdeno_isolate) }
LockerScope { libdeno_isolate } LockerScope { libdeno_isolate }
} }
@ -752,7 +720,7 @@ impl Future for Isolate {
/// IsolateHandle is a thread safe handle on an Isolate. It exposed thread safe V8 functions. /// IsolateHandle is a thread safe handle on an Isolate. It exposed thread safe V8 functions.
#[derive(Clone)] #[derive(Clone)]
pub struct IsolateHandle { pub struct IsolateHandle {
shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>, shared_libdeno_isolate: Arc<Mutex<Option<*mut libdeno::isolate>>>,
} }
unsafe impl Send for IsolateHandle {} unsafe impl Send for IsolateHandle {}

View file

@ -123,7 +123,8 @@ impl V8Exception {
/// Creates a new V8Exception by parsing the raw exception JSON string from V8. /// Creates a new V8Exception by parsing the raw exception JSON string from V8.
pub fn from_json(json_str: &str) -> Option<Self> { pub fn from_json(json_str: &str) -> Option<Self> {
let v = serde_json::from_str::<serde_json::Value>(json_str); let v = serde_json::from_str::<serde_json::Value>(json_str);
if v.is_err() { if let Err(err) = v {
eprintln!("V8Exception::from_json got problem {}", err);
return None; return None;
} }
let v = v.unwrap(); let v = v.unwrap();

View file

@ -5,6 +5,9 @@ extern crate futures;
extern crate libc; extern crate libc;
#[macro_use] #[macro_use]
extern crate downcast_rs; extern crate downcast_rs;
extern crate rusty_v8;
#[macro_use]
extern crate lazy_static;
mod any_error; mod any_error;
mod flags; mod flags;
@ -18,6 +21,8 @@ mod plugins;
mod resources; mod resources;
mod shared_queue; mod shared_queue;
use rusty_v8 as v8;
pub use crate::any_error::*; pub use crate::any_error::*;
pub use crate::flags::v8_set_flags; pub use crate::flags::v8_set_flags;
pub use crate::isolate::*; pub use crate::isolate::*;
@ -32,10 +37,7 @@ pub use crate::plugins::*;
pub use crate::resources::*; pub use crate::resources::*;
pub fn v8_version() -> &'static str { pub fn v8_version() -> &'static str {
use std::ffi::CStr; v8::V8::get_version()
let version = unsafe { libdeno::deno_v8_version() };
let c_str = unsafe { CStr::from_ptr(version) };
c_str.to_str().unwrap()
} }
#[test] #[test]

File diff suppressed because it is too large Load diff

View file

@ -1,60 +0,0 @@
# This file is used by the GN meta build system to find the root of the source
# tree and to set startup options. For documentation on the values set in this
# file, run "gn help dotfile" at the command line.
# The location of the build configuration file.
buildconfig = "//build/config/BUILDCONFIG.gn"
# These are the targets to check headers for by default. The files in targets
# matching these patterns (see "gn help label_pattern" for format) will have
# their includes checked for proper dependencies when you run either
# "gn check" or "gn gen --check".
check_targets = []
default_args = {
# Various global chrome args that are unrelated to deno.
proprietary_codecs = false
safe_browsing_mode = 0
toolkit_views = false
use_aura = false
use_dbus = false
use_gio = false
use_glib = false
use_ozone = false
use_udev = false
# To disable "use_atk" and other features that we don't need.
is_desktop_linux = false
# TODO(ry) We may want to turn on CFI at some point. Disabling for simplicity
# for now. See http://clang.llvm.org/docs/ControlFlowIntegrity.html
is_cfi = false
# TODO(ry) Remove this so debug builds can link faster. Currently removing
# this breaks cargo build in debug mode in OSX.
is_component_build = false
# Enable Jumbo build for a faster build.
# https://chromium.googlesource.com/chromium/src/+/master/docs/jumbo.md
use_jumbo_build = true
symbol_level = 1
treat_warnings_as_errors = true
# https://cs.chromium.org/chromium/src/docs/ccache_mac.md
clang_use_chrome_plugins = false
v8_enable_gdbjit = false
v8_enable_i18n_support = false
v8_enable_shared_ro_heap = false # See #2624
v8_imminent_deprecation_warnings = false
v8_monolithic = false
v8_untrusted_code_mitigations = false
v8_use_external_startup_data = false
v8_use_snapshot = true
v8_postmortem_support = true # for https://github.com/nodejs/llnode/
# We don't want to require downloading the binary executable
# tools/clang/dsymutil.
enable_dsyms = false
}

View file

@ -1,98 +0,0 @@
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import("//v8/gni/v8.gni")
group("default") {
testonly = true
deps = [
":libdeno_static_lib",
":libdeno_test",
":v8",
]
}
config("deno_config") {
include_dirs = [ "//v8" ] # This allows us to v8/src/base/ libraries.
configs = [ "//v8:external_config" ]
cflags = []
if (is_debug) {
defines = [ "DEBUG" ]
}
if (is_clang) {
cflags += [
"-fcolor-diagnostics",
"-fansi-escape-codes",
]
}
if (is_debug && is_clang && !is_win) {
cflags += [ "-glldb" ]
}
if (is_win) {
# The `/Zl` ("omit default library name") flag makes the compiler produce
# object files that can link with both the static and dynamic CRT.
cflags += [ "/Zl" ]
}
}
v8_source_set("v8") {
deps = [
"//v8:v8",
"//v8:v8_libbase",
"//v8:v8_libplatform",
"//v8:v8_libsampler",
]
configs = [ ":deno_config" ]
}
# Only functionality needed for libdeno_test and snapshot_creator
# In particular no assets, no rust, no msg handlers.
# Because snapshots are slow, it's important that snapshot_creator's
# dependencies are minimal.
v8_source_set("libdeno") {
sources = [
"api.cc",
"binding.cc",
"buffer.h",
"deno.h",
"exceptions.cc",
"exceptions.h",
"internal.h",
"modules.cc",
]
deps = [
":v8",
]
configs = [ ":deno_config" ]
}
# The cargo-driven build links with libdeno to pull in all non-rust code.
v8_static_library("libdeno_static_lib") {
output_name = "libdeno"
deps = [
":libdeno",
"//build/config:shared_library_deps",
]
configs = [ ":deno_config" ]
}
v8_executable("libdeno_test") {
testonly = true
sources = [
"libdeno_test.cc",
"modules_test.cc",
"test.cc",
]
deps = [
":libdeno",
"//testing/gtest:gtest",
]
data = [
"libdeno_test.js",
]
js_path = rebase_path(data[0])
defines = [ "JS_PATH=\"$js_path\"" ]
configs = [ ":deno_config" ]
}

View file

@ -1,254 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <string>
#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8.h"
#include "v8/src/base/logging.h"
#include "deno.h"
#include "exceptions.h"
#include "internal.h"
extern "C" {
Deno* deno_new_snapshotter(deno_config config) {
CHECK(config.will_snapshot);
// TODO(ry) Support loading snapshots before snapshotting.
CHECK_NULL(config.load_snapshot.data_ptr);
auto* creator = new v8::SnapshotCreator(deno::external_references);
auto* isolate = creator->GetIsolate();
auto* d = new deno::DenoIsolate(config);
d->snapshot_creator_ = creator;
d->AddIsolate(isolate);
{
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
d->context_.Reset(isolate, context);
creator->SetDefaultContext(context,
v8::SerializeInternalFieldsCallback(
deno::SerializeInternalFields, nullptr));
deno::InitializeContext(isolate, context);
}
return reinterpret_cast<Deno*>(d);
}
Deno* deno_new(deno_config config) {
if (config.will_snapshot) {
return deno_new_snapshotter(config);
}
deno::DenoIsolate* d = new deno::DenoIsolate(config);
v8::Isolate::CreateParams params;
params.array_buffer_allocator = &deno::ArrayBufferAllocator::global();
params.external_references = deno::external_references;
if (config.load_snapshot.data_ptr) {
params.snapshot_blob = &d->snapshot_;
}
v8::Isolate* isolate = v8::Isolate::New(params);
d->AddIsolate(isolate);
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
{
v8::HandleScope handle_scope(isolate);
auto context =
v8::Context::New(isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
v8::MaybeLocal<v8::Value>(),
v8::DeserializeInternalFieldsCallback(
deno::DeserializeInternalFields, nullptr));
if (!config.load_snapshot.data_ptr) {
// If no snapshot is provided, we initialize the context with empty
// main source code and source maps.
deno::InitializeContext(isolate, context);
}
d->context_.Reset(isolate, context);
}
return reinterpret_cast<Deno*>(d);
}
void deno_lock(Deno* d_) {
auto* d = deno::unwrap(d_);
CHECK_NULL(d->locker_);
d->locker_ = new v8::Locker(d->isolate_);
}
void deno_unlock(Deno* d_) {
auto* d = deno::unwrap(d_);
CHECK_NOT_NULL(d->locker_);
delete d->locker_;
d->locker_ = nullptr;
}
deno_snapshot deno_snapshot_new(Deno* d_) {
auto* d = deno::unwrap(d_);
CHECK_NOT_NULL(d->snapshot_creator_);
d->ClearModules();
d->context_.Reset();
auto blob = d->snapshot_creator_->CreateBlob(
v8::SnapshotCreator::FunctionCodeHandling::kKeep);
d->has_snapshotted_ = true;
return {reinterpret_cast<uint8_t*>(const_cast<char*>(blob.data)),
blob.raw_size};
}
void deno_snapshot_delete(deno_snapshot snapshot) {
delete[] snapshot.data_ptr;
}
static std::unique_ptr<v8::Platform> platform;
void deno_init() {
if (platform.get() == nullptr) {
platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// TODO(ry) This makes WASM compile synchronously. Eventually we should
// remove this to make it work asynchronously too. But that requires getting
// PumpMessageLoop and RunMicrotasks setup correctly.
// See https://github.com/denoland/deno/issues/2544
const char* argv[3] = {"", "--no-wasm-async-compilation",
"--harmony-top-level-await"};
int argc = 3;
v8::V8::SetFlagsFromCommandLine(&argc, const_cast<char**>(argv), false);
}
}
const char* deno_v8_version() { return v8::V8::GetVersion(); }
void deno_set_v8_flags(int* argc, char** argv) {
v8::V8::SetFlagsFromCommandLine(argc, argv, true);
}
const char* deno_last_exception(Deno* d_) {
auto* d = deno::unwrap(d_);
if (d->last_exception_.length() > 0) {
return d->last_exception_.c_str();
} else {
return nullptr;
}
}
void deno_clear_last_exception(Deno* d_) {
auto* d = deno::unwrap(d_);
d->last_exception_.clear();
d->last_exception_handle_.Reset();
}
void deno_execute(Deno* d_, void* user_data, const char* js_filename,
const char* js_source) {
auto* d = deno::unwrap(d_);
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
CHECK(!context.IsEmpty());
deno::Execute(context, js_filename, js_source);
}
void deno_pinned_buf_delete(deno_pinned_buf* buf) {
// The PinnedBuf destructor implicitly releases the ArrayBuffer reference.
auto _ = deno::PinnedBuf(buf);
}
void deno_throw_exception(Deno* d_, const char* text) {
auto* d = deno::unwrap(d_);
auto* isolate = d->isolate_;
isolate->ThrowException(deno::v8_str(text));
}
void deno_respond(Deno* d_, void* user_data, deno_op_id op_id, deno_buf buf) {
auto* d = deno::unwrap(d_);
if (d->current_args_ != nullptr) {
// Synchronous response.
// Note op_id is not passed back in the case of synchronous response.
if (buf.data_ptr != nullptr && buf.data_len > 0) {
auto ab = deno::ImportBuf(d, buf);
d->current_args_->GetReturnValue().Set(ab);
}
d->current_args_ = nullptr;
return;
}
// Asynchronous response.
deno::UserDataScope user_data_scope(d, user_data);
v8::Isolate::Scope isolate_scope(d->isolate_);
v8::HandleScope handle_scope(d->isolate_);
auto context = d->context_.Get(d->isolate_);
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(d->isolate_);
auto recv_ = d->recv_.Get(d->isolate_);
if (recv_.IsEmpty()) {
d->last_exception_ = "Deno.core.recv has not been called.";
return;
}
v8::Local<v8::Value> args[2];
int argc = 0;
if (buf.data_ptr != nullptr) {
args[0] = v8::Integer::New(d->isolate_, op_id);
args[1] = deno::ImportBuf(d, buf);
argc = 2;
}
auto v = recv_->Call(context, context->Global(), argc, args);
if (try_catch.HasCaught()) {
CHECK(v.IsEmpty());
deno::HandleException(context, try_catch.Exception());
}
}
void deno_check_promise_errors(Deno* d_) {
auto* d = deno::unwrap(d_);
if (d->pending_promise_map_.size() > 0) {
auto* isolate = d->isolate_;
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
v8::Context::Scope context_scope(context);
auto it = d->pending_promise_map_.begin();
while (it != d->pending_promise_map_.end()) {
auto error = it->second.Get(isolate);
deno::HandleException(context, error);
it = d->pending_promise_map_.erase(it);
}
}
}
void deno_delete(Deno* d_) {
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
delete d;
}
void deno_terminate_execution(Deno* d_) {
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
d->isolate_->TerminateExecution();
}
void deno_run_microtasks(Deno* d_, void* user_data) {
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
deno::UserDataScope user_data_scope(d, user_data);
v8::Locker locker(d->isolate_);
v8::Isolate::Scope isolate_scope(d->isolate_);
d->isolate_->RunMicrotasks();
}
}

View file

@ -1,597 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h>
#include <windows.h>
#endif // _WIN32
#include "v8/include/v8.h"
#include "v8/src/base/logging.h"
#include "deno.h"
#include "exceptions.h"
#include "internal.h"
#define GLOBAL_IMPORT_BUF_SIZE 1024
namespace deno {
std::vector<InternalFieldData*> deserialized_data;
void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
v8::StartupData payload, void* data) {
DCHECK_NULL(data);
if (payload.raw_size == 0) {
holder->SetAlignedPointerInInternalField(index, nullptr);
return;
}
InternalFieldData* embedder_field = new InternalFieldData{0};
memcpy(embedder_field, payload.data, payload.raw_size);
holder->SetAlignedPointerInInternalField(index, embedder_field);
deserialized_data.push_back(embedder_field);
}
v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
void* data) {
DCHECK_NULL(data);
InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
holder->GetAlignedPointerFromInternalField(index));
if (embedder_field == nullptr) return {nullptr, 0};
int size = sizeof(*embedder_field);
char* payload = new char[size];
// We simply use memcpy to serialize the content.
memcpy(payload, embedder_field, size);
return {payload, size};
}
// Extracts a C string from a v8::V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
void PromiseRejectCallback(v8::PromiseRejectMessage promise_reject_message) {
auto* isolate = v8::Isolate::GetCurrent();
DenoIsolate* d = static_cast<DenoIsolate*>(isolate->GetData(0));
DCHECK_EQ(d->isolate_, isolate);
v8::HandleScope handle_scope(d->isolate_);
auto error = promise_reject_message.GetValue();
auto context = d->context_.Get(d->isolate_);
auto promise = promise_reject_message.GetPromise();
v8::Context::Scope context_scope(context);
int promise_id = promise->GetIdentityHash();
switch (promise_reject_message.GetEvent()) {
case v8::kPromiseRejectWithNoHandler:
// Insert the error into the pending_promise_map_ using the promise's id
// as the key.
d->pending_promise_map_.emplace(std::piecewise_construct,
std::make_tuple(promise_id),
std::make_tuple(d->isolate_, error));
break;
case v8::kPromiseHandlerAddedAfterReject:
d->pending_promise_map_.erase(promise_id);
break;
case v8::kPromiseRejectAfterResolved:
break;
case v8::kPromiseResolveAfterResolved:
// Should not warn. See #1272
break;
default:
CHECK(false && "unreachable");
}
}
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto* isolate = args.GetIsolate();
int argsLen = args.Length();
if (argsLen < 1 || argsLen > 2) {
ThrowInvalidArgument(isolate);
}
v8::HandleScope handle_scope(isolate);
bool is_err = args.Length() >= 2 ? args[1]->BooleanValue(isolate) : false;
FILE* file = is_err ? stderr : stdout;
#ifdef _WIN32
int fd = _fileno(file);
if (fd < 0) return;
HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
if (h == INVALID_HANDLE_VALUE) return;
DWORD mode;
if (GetConsoleMode(h, &mode)) {
// Print to Windows console. Since the Windows API generally doesn't support
// UTF-8 encoded text, we have to use `WriteConsoleW()` which uses UTF-16.
v8::String::Value str(isolate, args[0]);
auto str_len = static_cast<size_t>(str.length());
auto str_wchars = reinterpret_cast<WCHAR*>(*str);
// WriteConsoleW has some limit to how many characters can be written at
// once, which is unspecified but low enough to be encountered in practice.
// Therefore we break up the write into chunks of 8kb if necessary.
size_t chunk_start = 0;
while (chunk_start < str_len) {
size_t chunk_end = std::min(chunk_start + 8192, str_len);
// Do not break in the middle of a surrogate pair. Note that `chunk_end`
// points to the start of the next chunk, so we check whether it contains
// the second half of a surrogate pair (a.k.a. "low surrogate").
if (chunk_end < str_len && str_wchars[chunk_end] >= 0xdc00 &&
str_wchars[chunk_end] <= 0xdfff) {
--chunk_end;
}
// Write to the console.
DWORD chunk_len = static_cast<DWORD>(chunk_end - chunk_start);
DWORD _;
WriteConsoleW(h, &str_wchars[chunk_start], chunk_len, &_, nullptr);
chunk_start = chunk_end;
}
return;
}
#endif // _WIN32
v8::String::Utf8Value str(isolate, args[0]);
fwrite(*str, sizeof(**str), str.length(), file);
fflush(file);
}
void ErrorToJSON(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK_EQ(args.Length(), 1);
auto* isolate = args.GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
auto context = d->context_.Get(d->isolate_);
v8::HandleScope handle_scope(isolate);
auto json_string = EncodeExceptionAsJSON(context, args[0]);
args.GetReturnValue().Set(v8_str(json_string.c_str()));
}
v8::Local<v8::Uint8Array> ImportBuf(DenoIsolate* d, deno_buf buf) {
if (buf.data_ptr == nullptr) {
return v8::Local<v8::Uint8Array>();
}
// To avoid excessively allocating new ArrayBuffers, we try to reuse a single
// global ArrayBuffer. The caveat is that users must extract data from it
// before the next tick. We only do this for ArrayBuffers less than 1024
// bytes.
v8::Local<v8::ArrayBuffer> ab;
void* data;
if (buf.data_len > GLOBAL_IMPORT_BUF_SIZE) {
// Simple case. We allocate a new ArrayBuffer for this.
ab = v8::ArrayBuffer::New(d->isolate_, buf.data_len);
data = ab->GetBackingStore()->Data();
} else {
// Fast case. We reuse the global ArrayBuffer.
if (d->global_import_buf_.IsEmpty()) {
// Lazily initialize it.
DCHECK_NULL(d->global_import_buf_ptr_);
ab = v8::ArrayBuffer::New(d->isolate_, GLOBAL_IMPORT_BUF_SIZE);
d->global_import_buf_.Reset(d->isolate_, ab);
d->global_import_buf_ptr_ = ab->GetBackingStore()->Data();
} else {
DCHECK(d->global_import_buf_ptr_);
ab = d->global_import_buf_.Get(d->isolate_);
}
data = d->global_import_buf_ptr_;
}
memcpy(data, buf.data_ptr, buf.data_len);
auto view = v8::Uint8Array::New(ab, 0, buf.data_len);
return view;
}
// Sets the recv_ callback.
void Recv(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
DCHECK_EQ(d->isolate_, isolate);
v8::HandleScope handle_scope(isolate);
if (!d->recv_.IsEmpty()) {
isolate->ThrowException(v8_str("Deno.core.recv already called."));
return;
}
v8::Local<v8::Value> v = args[0];
CHECK(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(v);
d->recv_.Reset(isolate, func);
}
void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
DCHECK_EQ(d->isolate_, isolate);
v8::HandleScope handle_scope(isolate);
deno_buf control = {nullptr, 0};
int32_t op_id = 0;
if (args[0]->IsInt32()) {
auto context = d->context_.Get(isolate);
op_id = args[0]->Int32Value(context).FromJust();
}
if (args[1]->IsArrayBufferView()) {
auto view = v8::Local<v8::ArrayBufferView>::Cast(args[1]);
auto data =
reinterpret_cast<uint8_t*>(view->Buffer()->GetBackingStore()->Data());
control = {data + view->ByteOffset(), view->ByteLength()};
}
PinnedBuf zero_copy =
args[2]->IsArrayBufferView()
? PinnedBuf(v8::Local<v8::ArrayBufferView>::Cast(args[2]))
: PinnedBuf();
DCHECK_NULL(d->current_args_);
d->current_args_ = &args;
d->recv_cb_(d->user_data_, op_id, control, zero_copy.IntoRaw());
if (d->current_args_ == nullptr) {
// This indicates that deno_repond() was called already.
} else {
// Asynchronous.
d->current_args_ = nullptr;
}
}
v8::ScriptOrigin ModuleOrigin(v8::Isolate* isolate,
v8::Local<v8::Value> resource_name) {
return v8::ScriptOrigin(resource_name, v8::Local<v8::Integer>(),
v8::Local<v8::Integer>(), v8::Local<v8::Boolean>(),
v8::Local<v8::Integer>(), v8::Local<v8::Value>(),
v8::Local<v8::Boolean>(), v8::Local<v8::Boolean>(),
v8::True(isolate));
}
deno_mod DenoIsolate::RegisterModule(bool main, const char* name,
const char* source) {
v8::Isolate::Scope isolate_scope(isolate_);
v8::Locker locker(isolate_);
v8::HandleScope handle_scope(isolate_);
auto context = context_.Get(isolate_);
v8::Context::Scope context_scope(context);
v8::Local<v8::String> name_str = v8_str(name);
v8::Local<v8::String> source_str = v8_str(source);
auto origin = ModuleOrigin(isolate_, name_str);
v8::ScriptCompiler::Source source_(source_str, origin);
v8::TryCatch try_catch(isolate_);
auto maybe_module = v8::ScriptCompiler::CompileModule(isolate_, &source_);
if (try_catch.HasCaught()) {
CHECK(maybe_module.IsEmpty());
HandleException(context, try_catch.Exception());
return 0;
}
auto module = maybe_module.ToLocalChecked();
int id = module->GetIdentityHash();
std::vector<std::string> import_specifiers;
for (int i = 0; i < module->GetModuleRequestsLength(); ++i) {
v8::Local<v8::String> specifier = module->GetModuleRequest(i);
v8::String::Utf8Value specifier_utf8(isolate_, specifier);
import_specifiers.push_back(*specifier_utf8);
}
mods_.emplace(
std::piecewise_construct, std::make_tuple(id),
std::make_tuple(isolate_, module, main, name, import_specifiers));
mods_by_name_[name] = id;
return id;
}
void Shared(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
DCHECK_EQ(d->isolate_, isolate);
v8::Locker locker(d->isolate_);
v8::EscapableHandleScope handle_scope(isolate);
if (d->shared_.data_ptr == nullptr) {
return;
}
v8::Local<v8::SharedArrayBuffer> ab;
if (d->shared_ab_.IsEmpty()) {
// Lazily initialize the persistent external ArrayBuffer.
ab = v8::SharedArrayBuffer::New(isolate, d->shared_.data_ptr,
d->shared_.data_len,
v8::ArrayBufferCreationMode::kExternalized);
d->shared_ab_.Reset(isolate, ab);
}
auto shared_ab = d->shared_ab_.Get(isolate);
info.GetReturnValue().Set(shared_ab);
}
void DenoIsolate::ClearModules() {
for (auto it = mods_.begin(); it != mods_.end(); it++) {
it->second.handle.Reset();
}
mods_.clear();
mods_by_name_.clear();
}
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source) {
auto* isolate = context->GetIsolate();
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto source = v8_str(js_source);
auto name = v8_str(js_filename);
v8::TryCatch try_catch(isolate);
v8::ScriptOrigin origin(name);
auto script = v8::Script::Compile(context, source, &origin);
if (script.IsEmpty()) {
DCHECK(try_catch.HasCaught());
HandleException(context, try_catch.Exception());
return false;
}
auto result = script.ToLocalChecked()->Run(context);
if (result.IsEmpty()) {
DCHECK(try_catch.HasCaught());
HandleException(context, try_catch.Exception());
return false;
}
return true;
}
static inline v8::Local<v8::Boolean> v8_bool(bool v) {
return v8::Boolean::New(v8::Isolate::GetCurrent(), v);
}
void EvalContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
v8::EscapableHandleScope handleScope(isolate);
auto context = d->context_.Get(isolate);
v8::Context::Scope context_scope(context);
if (!(args[0]->IsString())) {
ThrowInvalidArgument(isolate);
return;
}
auto source = args[0].As<v8::String>();
auto output = v8::Array::New(isolate, 2);
/**
* output[0] = result
* output[1] = ErrorInfo | null
* ErrorInfo = {
* thrown: Error | any,
* isNativeError: boolean,
* isCompileError: boolean,
* }
*/
v8::TryCatch try_catch(isolate);
auto name = v8_str("<unknown>");
v8::ScriptOrigin origin(name);
auto script = v8::Script::Compile(context, source, &origin);
if (script.IsEmpty()) {
CHECK(try_catch.HasCaught());
auto exception = try_catch.Exception();
CHECK(output->Set(context, 0, v8::Null(isolate)).FromJust());
auto errinfo_obj = v8::Object::New(isolate);
CHECK(errinfo_obj->Set(context, v8_str("isCompileError"), v8_bool(true))
.FromJust());
CHECK(errinfo_obj
->Set(context, v8_str("isNativeError"),
v8_bool(exception->IsNativeError()))
.FromJust());
CHECK(errinfo_obj->Set(context, v8_str("thrown"), exception).FromJust());
CHECK(output->Set(context, 1, errinfo_obj).FromJust());
args.GetReturnValue().Set(output);
return;
}
auto result = script.ToLocalChecked()->Run(context);
if (result.IsEmpty()) {
CHECK(try_catch.HasCaught());
auto exception = try_catch.Exception();
CHECK(output->Set(context, 0, v8::Null(isolate)).FromJust());
auto errinfo_obj = v8::Object::New(isolate);
CHECK(errinfo_obj->Set(context, v8_str("isCompileError"), v8_bool(false))
.FromJust());
CHECK(errinfo_obj
->Set(context, v8_str("isNativeError"),
v8_bool(exception->IsNativeError()))
.FromJust());
CHECK(errinfo_obj->Set(context, v8_str("thrown"), exception).FromJust());
CHECK(output->Set(context, 1, errinfo_obj).FromJust());
args.GetReturnValue().Set(output);
return;
}
CHECK(output->Set(context, 0, result.ToLocalChecked()).FromJust());
CHECK(output->Set(context, 1, v8::Null(isolate)).FromJust());
args.GetReturnValue().Set(output);
}
void QueueMicrotask(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
if (!(args[0]->IsFunction())) {
ThrowInvalidArgument(isolate);
return;
}
isolate->EnqueueMicrotask(args[0].As<v8::Function>());
}
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context) {
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto global = context->Global();
auto deno_val = v8::Object::New(isolate);
CHECK(global->Set(context, deno::v8_str("Deno"), deno_val).FromJust());
auto core_val = v8::Object::New(isolate);
CHECK(deno_val->Set(context, deno::v8_str("core"), core_val).FromJust());
auto print_tmpl = v8::FunctionTemplate::New(isolate, Print);
auto print_val = print_tmpl->GetFunction(context).ToLocalChecked();
CHECK(core_val->Set(context, deno::v8_str("print"), print_val).FromJust());
auto recv_tmpl = v8::FunctionTemplate::New(isolate, Recv);
auto recv_val = recv_tmpl->GetFunction(context).ToLocalChecked();
CHECK(core_val->Set(context, deno::v8_str("recv"), recv_val).FromJust());
auto send_tmpl = v8::FunctionTemplate::New(isolate, Send);
auto send_val = send_tmpl->GetFunction(context).ToLocalChecked();
CHECK(core_val->Set(context, deno::v8_str("send"), send_val).FromJust());
auto eval_context_tmpl = v8::FunctionTemplate::New(isolate, EvalContext);
auto eval_context_val =
eval_context_tmpl->GetFunction(context).ToLocalChecked();
CHECK(core_val->Set(context, deno::v8_str("evalContext"), eval_context_val)
.FromJust());
auto error_to_json_tmpl = v8::FunctionTemplate::New(isolate, ErrorToJSON);
auto error_to_json_val =
error_to_json_tmpl->GetFunction(context).ToLocalChecked();
CHECK(core_val->Set(context, deno::v8_str("errorToJSON"), error_to_json_val)
.FromJust());
CHECK(core_val->SetAccessor(context, deno::v8_str("shared"), Shared)
.FromJust());
// Direct bindings on `window`.
auto queue_microtask_tmpl =
v8::FunctionTemplate::New(isolate, QueueMicrotask);
auto queue_microtask_val =
queue_microtask_tmpl->GetFunction(context).ToLocalChecked();
CHECK(
global->Set(context, deno::v8_str("queueMicrotask"), queue_microtask_val)
.FromJust());
}
void MessageCallback(v8::Local<v8::Message> message,
v8::Local<v8::Value> data) {
auto* isolate = message->GetIsolate();
DenoIsolate* d = static_cast<DenoIsolate*>(isolate->GetData(0));
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(isolate);
HandleExceptionMessage(context, message);
}
void HostInitializeImportMetaObjectCallback(v8::Local<v8::Context> context,
v8::Local<v8::Module> module,
v8::Local<v8::Object> meta) {
auto* isolate = context->GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
v8::Isolate::Scope isolate_scope(isolate);
CHECK(!module.IsEmpty());
deno_mod id = module->GetIdentityHash();
CHECK_NE(id, 0);
auto* info = d->GetModuleInfo(id);
const char* url = info->name.c_str();
const bool main = info->main;
meta->CreateDataProperty(context, v8_str("url"), v8_str(url)).ToChecked();
meta->CreateDataProperty(context, v8_str("main"), v8_bool(main)).ToChecked();
}
v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback(
v8::Local<v8::Context> context, v8::Local<v8::ScriptOrModule> referrer,
v8::Local<v8::String> specifier) {
auto* isolate = context->GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::Context::Scope context_scope(context);
v8::EscapableHandleScope handle_scope(isolate);
v8::String::Utf8Value specifier_str(isolate, specifier);
auto referrer_name = referrer->GetResourceName();
v8::String::Utf8Value referrer_name_str(isolate, referrer_name);
// TODO(ry) I'm not sure what HostDefinedOptions is for or if we're ever going
// to use it. For now we check that it is not used. This check may need to be
// changed in the future.
auto host_defined_options = referrer->GetHostDefinedOptions();
CHECK_EQ(host_defined_options->Length(), 0);
v8::Local<v8::Promise::Resolver> resolver =
v8::Promise::Resolver::New(context).ToLocalChecked();
deno_dyn_import_id import_id = d->next_dyn_import_id_++;
d->dyn_import_map_.emplace(std::piecewise_construct,
std::make_tuple(import_id),
std::make_tuple(d->isolate_, resolver));
d->dyn_import_cb_(d->user_data_, *specifier_str, *referrer_name_str,
import_id);
auto promise = resolver->GetPromise();
return handle_scope.Escape(promise);
}
void DenoIsolate::AddIsolate(v8::Isolate* isolate) {
isolate_ = isolate;
isolate_->SetCaptureStackTraceForUncaughtExceptions(
true, 10, v8::StackTrace::kDetailed);
isolate_->SetPromiseRejectCallback(deno::PromiseRejectCallback);
isolate_->SetData(0, this);
isolate_->AddMessageListener(MessageCallback);
isolate->SetHostInitializeImportMetaObjectCallback(
HostInitializeImportMetaObjectCallback);
isolate->SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback);
}
} // namespace deno

View file

@ -1,140 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#ifndef BUFFER_H_
#define BUFFER_H_
// Cpplint bans the use of <mutex> because it duplicates functionality in
// chromium //base. However Deno doensn't use that, so suppress that lint.
#include <memory>
#include <mutex> // NOLINT
#include <string>
#include <unordered_map>
#include <utility>
#include "v8/include/v8.h"
#include "v8/src/base/logging.h"
namespace deno {
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
static ArrayBufferAllocator& global() {
static ArrayBufferAllocator global_instance;
return global_instance;
}
void* Allocate(size_t length) override { return new uint8_t[length](); }
void* AllocateUninitialized(size_t length) override {
return new uint8_t[length];
}
void Free(void* data, size_t length) override { Unref(data); }
private:
friend class PinnedBuf;
void Ref(void* data) {
std::lock_guard<std::mutex> lock(ref_count_map_mutex_);
// Note:
// - `unordered_map::insert(make_pair(key, value))` returns the existing
// item if the key, already exists in the map, otherwise it creates an
// new entry with `value`.
// - Buffers not in the map have an implicit reference count of one.
auto entry = ref_count_map_.insert(std::make_pair(data, 1)).first;
++entry->second;
}
void Unref(void* data) {
{
std::lock_guard<std::mutex> lock(ref_count_map_mutex_);
auto entry = ref_count_map_.find(data);
if (entry == ref_count_map_.end()) {
// Buffers not in the map have an implicit ref count of one. After
// dereferencing there are no references left, so we delete the buffer.
} else if (--entry->second == 0) {
// The reference count went to zero, so erase the map entry and free the
// buffer.
ref_count_map_.erase(entry);
} else {
// After decreasing the reference count the buffer still has references
// left, so we leave the pin in place.
return;
}
delete[] reinterpret_cast<uint8_t*>(data);
}
}
private:
ArrayBufferAllocator() {}
~ArrayBufferAllocator() {
// TODO(pisciaureus): Enable this check. It currently fails sometimes
// because the compiler worker isolate never actually exits, so when the
// process exits this isolate still holds on to some buffers.
// CHECK(ref_count_map_.empty());
}
std::unordered_map<void*, size_t> ref_count_map_;
std::mutex ref_count_map_mutex_;
};
class PinnedBuf {
struct Unref {
// This callback gets called from the Pin destructor.
void operator()(void* ptr) { ArrayBufferAllocator::global().Unref(ptr); }
};
// The Pin is a unique (non-copyable) smart pointer which automatically
// unrefs the referenced ArrayBuffer in its destructor.
using Pin = std::unique_ptr<void, Unref>;
uint8_t* data_ptr_;
size_t data_len_;
Pin pin_;
public:
// PinnedBuf::Raw is a POD struct with the same memory layout as the PinBuf
// itself. It is used to move a PinnedBuf between C and Rust.
struct Raw {
uint8_t* data_ptr;
size_t data_len;
void* pin;
};
PinnedBuf() : data_ptr_(nullptr), data_len_(0), pin_() {}
explicit PinnedBuf(v8::Local<v8::ArrayBufferView> view) {
auto buf = view->Buffer()->GetBackingStore()->Data();
ArrayBufferAllocator::global().Ref(buf);
data_ptr_ = reinterpret_cast<uint8_t*>(buf) + view->ByteOffset();
data_len_ = view->ByteLength();
pin_ = Pin(buf);
}
// This constructor recreates a PinnedBuf that has previously been converted
// to a PinnedBuf::Raw using the IntoRaw() method. This is a move operation;
// the Raw struct is emptied in the process.
explicit PinnedBuf(Raw* raw)
: data_ptr_(raw->data_ptr), data_len_(raw->data_len), pin_(raw->pin) {
raw->data_ptr = nullptr;
raw->data_len = 0;
raw->pin = nullptr;
}
// The IntoRaw() method converts the PinnedBuf to a PinnedBuf::Raw so it's
// ownership can be moved to Rust. The source PinnedBuf is emptied in the
// process, but the pinned ArrayBuffer is not dereferenced. In order to not
// leak it, the raw struct must eventually be turned back into a PinnedBuf
// using the constructor above.
Raw IntoRaw() {
Raw raw{
.data_ptr = data_ptr_, .data_len = data_len_, .pin = pin_.release()};
data_ptr_ = nullptr;
data_len_ = 0;
return raw;
}
};
} // namespace deno
#endif // BUFFER_H_

@ -1 +0,0 @@
Subproject commit 6af664c48ed657b89e99a9a8692dc15d7f7a6d9c

View file

@ -1 +0,0 @@
v8/build_overrides

View file

@ -1 +0,0 @@
v8/buildtools

View file

@ -1,165 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#ifndef DENO_H_
#define DENO_H_
#include <stddef.h>
#include <stdint.h>
#include "buffer.h"
// Neither Rust nor Go support calling directly into C++ functions, therefore
// the public interface to libdeno is done in C.
#ifdef __cplusplus
extern "C" {
#endif
typedef deno::PinnedBuf::Raw deno_pinned_buf;
// Data that gets transmitted.
typedef struct {
uint8_t* data_ptr;
size_t data_len;
} deno_buf;
typedef struct {
uint8_t* data_ptr;
size_t data_len;
} deno_snapshot;
typedef struct deno_s Deno;
typedef uint32_t deno_op_id;
// A callback to receive a message from a Deno.core.send() javascript call.
// control_buf is valid for only for the lifetime of this callback.
// data_buf is valid until deno_respond() is called.
//
// op_id corresponds to the first argument of Deno.core.send().
// op_id is an extra user-defined integer valued which is not interpreted by
// libdeno.
//
// control_buf corresponds to the second argument of Deno.core.send().
//
// zero_copy_buf corresponds to the third argument of Deno.core.send().
// The user must call deno_pinned_buf_delete on each zero_copy_buf received.
typedef void (*deno_recv_cb)(void* user_data, deno_op_id op_id,
deno_buf control_buf,
deno_pinned_buf zero_copy_buf);
typedef int deno_dyn_import_id;
// Called when dynamic import is called in JS: import('foo')
// Embedder must call deno_dyn_import_done() with the specified id and
// the module.
typedef void (*deno_dyn_import_cb)(void* user_data, const char* specifier,
const char* referrer, deno_dyn_import_id id);
void deno_init();
const char* deno_v8_version();
void deno_set_v8_flags(int* argc, char** argv);
typedef struct {
int will_snapshot; // Default 0. If calling deno_snapshot_new 1.
deno_snapshot load_snapshot; // A startup snapshot to use.
deno_buf shared; // Shared buffer to be mapped to libdeno.shared
deno_recv_cb recv_cb; // Maps to Deno.core.send() calls.
deno_dyn_import_cb dyn_import_cb;
} deno_config;
// Create a new deno isolate.
// Warning: If config.will_snapshot is set, deno_snapshot_new() must be called
// or an error will result.
Deno* deno_new(deno_config config);
void deno_delete(Deno* d);
// Generate a snapshot. The resulting buf can be used in as the load_snapshot
// member in deno_confg.
// When calling this function, the caller must have created the isolate "d" with
// "will_snapshot" set to 1.
// The caller must free the returned data with deno_snapshot_delete().
deno_snapshot deno_snapshot_new(Deno* d);
// Only for use with data returned from deno_snapshot_new.
void deno_snapshot_delete(deno_snapshot);
void deno_lock(Deno* d);
void deno_unlock(Deno* d);
// Compile and execute a traditional JavaScript script that does not use
// module import statements.
// If it succeeded deno_last_exception() will return NULL.
void deno_execute(Deno* d, void* user_data, const char* js_filename,
const char* js_source);
// deno_respond sends one message back for every deno_recv_cb made.
//
// If this is called during deno_recv_cb, the issuing Deno.core.send() in
// javascript will synchronously return the specified buf as an ArrayBuffer (or
// null if buf is empty).
//
// If this is called after deno_recv_cb has returned, the deno_respond
// will call into the JS callback specified by Deno.core.recv().
//
// (Ideally, but not currently: After calling deno_respond(), the caller no
// longer owns `buf` and must not use it; deno_respond() is responsible for
// releasing its memory.)
//
// op_id is an extra user-defined integer valued which is not currently
// interpreted by libdeno. But it should probably correspond to the op_id in
// deno_recv_cb.
//
// If a JS exception was encountered, deno_last_exception() will be non-NULL.
void deno_respond(Deno* d, void* user_data, deno_op_id op_id, deno_buf buf);
void deno_throw_exception(Deno* d, const char* text);
// consumes zero_copy
void deno_pinned_buf_delete(deno_pinned_buf* buf);
void deno_check_promise_errors(Deno* d);
// Returns a cstring pointer to the exception.
// Rust side must NOT assert ownership.
const char* deno_last_exception(Deno* d);
// Clears last exception.
// Rust side must NOT hold pointer to exception string when called.
void deno_clear_last_exception(Deno* d_);
void deno_terminate_execution(Deno* d);
void deno_run_microtasks(Deno* d, void* user_data);
// Module API
typedef int deno_mod;
// Returns zero on error - check deno_last_exception().
deno_mod deno_mod_new(Deno* d, bool main, const char* name, const char* source);
size_t deno_mod_imports_len(Deno* d, deno_mod id);
// Returned pointer is valid for the lifetime of the Deno isolate "d".
const char* deno_mod_imports_get(Deno* d, deno_mod id, size_t index);
typedef deno_mod (*deno_resolve_cb)(void* user_data, const char* specifier,
deno_mod referrer);
// If it succeeded deno_last_exception() will return NULL.
void deno_mod_instantiate(Deno* d, void* user_data, deno_mod id,
deno_resolve_cb cb);
// If it succeeded deno_last_exception() will return NULL.
void deno_mod_evaluate(Deno* d, void* user_data, deno_mod id);
// Call exactly once for every deno_dyn_import_cb.
// Note this call will execute JS.
// Either mod_id is zero and error_str is not null OR mod_id is valid and
// error_str is null.
// TODO(ry) The errors arising from dynamic import are not exactly the same as
// those arising from ops in Deno.
void deno_dyn_import_done(Deno* d, void* user_data, deno_dyn_import_id id,
deno_mod mod_id, const char* error_str);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // DENO_H_

View file

@ -1,236 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include "exceptions.h"
#include <string>
#include "internal.h"
namespace deno {
v8::Local<v8::Object> EncodeMessageAsObject(v8::Local<v8::Context> context,
v8::Local<v8::Message> message) {
auto* isolate = context->GetIsolate();
v8::EscapableHandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto stack_trace = message->GetStackTrace();
// Encode the exception into a JS object, which we will then turn into JSON.
auto json_obj = v8::Object::New(isolate);
auto exception_str = message->Get();
CHECK(json_obj->Set(context, v8_str("message"), exception_str).FromJust());
auto maybe_source_line = message->GetSourceLine(context);
if (!maybe_source_line.IsEmpty()) {
CHECK(json_obj
->Set(context, v8_str("sourceLine"),
maybe_source_line.ToLocalChecked())
.FromJust());
}
CHECK(json_obj
->Set(context, v8_str("scriptResourceName"),
message->GetScriptResourceName())
.FromJust());
auto maybe_line_number = message->GetLineNumber(context);
if (maybe_line_number.IsJust()) {
CHECK(json_obj
->Set(context, v8_str("lineNumber"),
v8::Integer::New(isolate, maybe_line_number.FromJust()))
.FromJust());
}
CHECK(json_obj
->Set(context, v8_str("startPosition"),
v8::Integer::New(isolate, message->GetStartPosition()))
.FromJust());
CHECK(json_obj
->Set(context, v8_str("endPosition"),
v8::Integer::New(isolate, message->GetEndPosition()))
.FromJust());
CHECK(json_obj
->Set(context, v8_str("errorLevel"),
v8::Integer::New(isolate, message->ErrorLevel()))
.FromJust());
auto maybe_start_column = message->GetStartColumn(context);
if (maybe_start_column.IsJust()) {
auto start_column =
v8::Integer::New(isolate, maybe_start_column.FromJust());
CHECK(
json_obj->Set(context, v8_str("startColumn"), start_column).FromJust());
}
auto maybe_end_column = message->GetEndColumn(context);
if (maybe_end_column.IsJust()) {
auto end_column = v8::Integer::New(isolate, maybe_end_column.FromJust());
CHECK(json_obj->Set(context, v8_str("endColumn"), end_column).FromJust());
}
CHECK(json_obj
->Set(context, v8_str("isSharedCrossOrigin"),
v8::Boolean::New(isolate, message->IsSharedCrossOrigin()))
.FromJust());
CHECK(json_obj
->Set(context, v8_str("isOpaque"),
v8::Boolean::New(isolate, message->IsOpaque()))
.FromJust());
v8::Local<v8::Array> frames;
if (!stack_trace.IsEmpty()) {
uint32_t count = static_cast<uint32_t>(stack_trace->GetFrameCount());
frames = v8::Array::New(isolate, count);
for (uint32_t i = 0; i < count; ++i) {
auto frame = stack_trace->GetFrame(isolate, i);
auto frame_obj = v8::Object::New(isolate);
CHECK(frames->Set(context, i, frame_obj).FromJust());
auto line = v8::Integer::New(isolate, frame->GetLineNumber());
auto column = v8::Integer::New(isolate, frame->GetColumn());
CHECK(frame_obj->Set(context, v8_str("line"), line).FromJust());
CHECK(frame_obj->Set(context, v8_str("column"), column).FromJust());
auto function_name = frame->GetFunctionName();
if (!function_name.IsEmpty()) {
CHECK(frame_obj->Set(context, v8_str("functionName"), function_name)
.FromJust());
}
// scriptName can be empty in special conditions e.g. eval
auto scriptName = frame->GetScriptNameOrSourceURL();
if (scriptName.IsEmpty()) {
scriptName = v8_str("<unknown>");
}
CHECK(
frame_obj->Set(context, v8_str("scriptName"), scriptName).FromJust());
CHECK(frame_obj
->Set(context, v8_str("isEval"),
v8::Boolean::New(isolate, frame->IsEval()))
.FromJust());
CHECK(frame_obj
->Set(context, v8_str("isConstructor"),
v8::Boolean::New(isolate, frame->IsConstructor()))
.FromJust());
CHECK(frame_obj
->Set(context, v8_str("isWasm"),
v8::Boolean::New(isolate, frame->IsWasm()))
.FromJust());
}
} else {
// No stack trace. We only have one stack frame of info..
frames = v8::Array::New(isolate, 1);
auto frame_obj = v8::Object::New(isolate);
CHECK(frames->Set(context, 0, frame_obj).FromJust());
auto line =
v8::Integer::New(isolate, message->GetLineNumber(context).FromJust());
auto column =
v8::Integer::New(isolate, message->GetStartColumn(context).FromJust());
CHECK(frame_obj->Set(context, v8_str("line"), line).FromJust());
CHECK(frame_obj->Set(context, v8_str("column"), column).FromJust());
CHECK(frame_obj
->Set(context, v8_str("scriptName"),
message->GetScriptResourceName())
.FromJust());
}
CHECK(json_obj->Set(context, v8_str("frames"), frames).FromJust());
json_obj = handle_scope.Escape(json_obj);
return json_obj;
}
std::string EncodeMessageAsJSON(v8::Local<v8::Context> context,
v8::Local<v8::Message> message) {
auto* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto json_obj = EncodeMessageAsObject(context, message);
auto json_string = v8::JSON::Stringify(context, json_obj).ToLocalChecked();
v8::String::Utf8Value json_string_(isolate, json_string);
return std::string(ToCString(json_string_));
}
v8::Local<v8::Object> EncodeExceptionAsObject(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception) {
auto* isolate = context->GetIsolate();
v8::EscapableHandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto message = v8::Exception::CreateMessage(isolate, exception);
auto json_obj = EncodeMessageAsObject(context, message);
json_obj = handle_scope.Escape(json_obj);
return json_obj;
}
std::string EncodeExceptionAsJSON(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception) {
auto* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
auto message = v8::Exception::CreateMessage(isolate, exception);
return EncodeMessageAsJSON(context, message);
}
void HandleException(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception) {
v8::Isolate* isolate = context->GetIsolate();
// TerminateExecution was called
if (isolate->IsExecutionTerminating()) {
// cancel exception termination so that the exception can be created
isolate->CancelTerminateExecution();
// maybe make a new exception object
if (exception->IsNullOrUndefined()) {
exception = v8::Exception::Error(v8_str("execution terminated"));
}
// handle the exception as if it is a regular exception
HandleException(context, exception);
// re-enable exception termination
isolate->TerminateExecution();
return;
}
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
std::string json_str = EncodeExceptionAsJSON(context, exception);
CHECK_NOT_NULL(d);
d->last_exception_ = json_str;
d->last_exception_handle_.Reset(isolate, exception);
}
void HandleExceptionMessage(v8::Local<v8::Context> context,
v8::Local<v8::Message> message) {
v8::Isolate* isolate = context->GetIsolate();
// TerminateExecution was called
if (isolate->IsExecutionTerminating()) {
HandleException(context, v8::Undefined(isolate));
return;
}
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
std::string json_str = EncodeMessageAsJSON(context, message);
CHECK_NOT_NULL(d);
d->last_exception_ = json_str;
}
void ClearException(v8::Local<v8::Context> context) {
v8::Isolate* isolate = context->GetIsolate();
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
CHECK_NOT_NULL(d);
d->last_exception_.clear();
d->last_exception_handle_.Reset();
}
void ThrowInvalidArgument(v8::Isolate* isolate) {
isolate->ThrowException(v8::Exception::TypeError(v8_str("Invalid Argument")));
}
} // namespace deno

View file

@ -1,27 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#ifndef EXCEPTIONS_H_
#define EXCEPTIONS_H_
#include <string>
#include "v8/include/v8.h"
namespace deno {
v8::Local<v8::Object> EncodeExceptionAsObject(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception);
std::string EncodeExceptionAsJSON(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception);
void HandleException(v8::Local<v8::Context> context,
v8::Local<v8::Value> exception);
void HandleExceptionMessage(v8::Local<v8::Context> context,
v8::Local<v8::Message> message);
void ClearException(v8::Local<v8::Context> context);
void ThrowInvalidArgument(v8::Isolate* isolate);
} // namespace deno
#endif // EXCEPTIONS_H_

View file

@ -1,206 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#ifndef INTERNAL_H_
#define INTERNAL_H_
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "buffer.h"
#include "deno.h"
#include "v8/include/v8.h"
#include "v8/src/base/logging.h"
namespace deno {
struct ModuleInfo {
bool main;
std::string name;
v8::Persistent<v8::Module> handle;
std::vector<std::string> import_specifiers;
ModuleInfo(v8::Isolate* isolate, v8::Local<v8::Module> module, bool main_,
const char* name_, std::vector<std::string> import_specifiers_)
: main(main_), name(name_), import_specifiers(import_specifiers_) {
handle.Reset(isolate, module);
}
};
// deno_s = Wrapped Isolate.
class DenoIsolate {
public:
explicit DenoIsolate(deno_config config)
: isolate_(nullptr),
locker_(nullptr),
shared_(config.shared),
current_args_(nullptr),
snapshot_creator_(nullptr),
global_import_buf_ptr_(nullptr),
recv_cb_(config.recv_cb),
user_data_(nullptr),
resolve_cb_(nullptr),
next_dyn_import_id_(0),
dyn_import_cb_(config.dyn_import_cb),
has_snapshotted_(false) {
if (config.load_snapshot.data_ptr) {
snapshot_.data =
reinterpret_cast<const char*>(config.load_snapshot.data_ptr);
snapshot_.raw_size = static_cast<int>(config.load_snapshot.data_len);
}
}
~DenoIsolate() {
last_exception_handle_.Reset();
shared_ab_.Reset();
if (locker_) {
delete locker_;
}
if (snapshot_creator_) {
// TODO(ry) V8 has a strange assert which prevents a SnapshotCreator from
// being deallocated if it hasn't created a snapshot yet.
// https://github.com/v8/v8/blob/73212783fbd534fac76cc4b66aac899c13f71fc8/src/api.cc#L603
// If that assert is removed, this if guard could be removed.
// WARNING: There may be false positive LSAN errors here.
if (has_snapshotted_) {
delete snapshot_creator_;
}
} else {
isolate_->Dispose();
}
}
static inline DenoIsolate* FromIsolate(v8::Isolate* isolate) {
return static_cast<DenoIsolate*>(isolate->GetData(0));
}
void AddIsolate(v8::Isolate* isolate);
deno_mod RegisterModule(bool main, const char* name, const char* source);
void ClearModules();
ModuleInfo* GetModuleInfo(deno_mod id) {
if (id == 0) {
return nullptr;
}
auto it = mods_.find(id);
if (it != mods_.end()) {
return &it->second;
} else {
return nullptr;
}
}
v8::Isolate* isolate_;
v8::Locker* locker_;
deno_buf shared_;
const v8::FunctionCallbackInfo<v8::Value>* current_args_;
v8::SnapshotCreator* snapshot_creator_;
void* global_import_buf_ptr_;
deno_recv_cb recv_cb_;
void* user_data_;
std::map<deno_mod, ModuleInfo> mods_;
std::map<std::string, deno_mod> mods_by_name_;
deno_resolve_cb resolve_cb_;
deno_dyn_import_id next_dyn_import_id_;
deno_dyn_import_cb dyn_import_cb_;
std::map<deno_dyn_import_id, v8::Persistent<v8::Promise::Resolver>>
dyn_import_map_;
v8::Persistent<v8::Context> context_;
std::map<int, v8::Persistent<v8::Value>> pending_promise_map_;
std::string last_exception_;
v8::Persistent<v8::Value> last_exception_handle_;
v8::Persistent<v8::Function> recv_;
v8::StartupData snapshot_;
v8::Persistent<v8::ArrayBuffer> global_import_buf_;
v8::Persistent<v8::SharedArrayBuffer> shared_ab_;
bool has_snapshotted_;
};
class UserDataScope {
DenoIsolate* deno_;
void* prev_data_;
void* data_; // Not necessary; only for sanity checking.
public:
UserDataScope(DenoIsolate* deno, void* data) : deno_(deno), data_(data) {
CHECK(deno->user_data_ == nullptr || deno->user_data_ == data_);
prev_data_ = deno->user_data_;
deno->user_data_ = data;
}
~UserDataScope() {
CHECK(deno_->user_data_ == data_);
deno_->user_data_ = prev_data_;
}
};
struct InternalFieldData {
uint32_t data;
};
static inline v8::Local<v8::String> v8_str(const char* x) {
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
v8::NewStringType::kNormal)
.ToLocalChecked();
}
static inline DenoIsolate* unwrap(Deno* d_) {
return reinterpret_cast<deno::DenoIsolate*>(d_);
}
const char* ToCString(const v8::String::Utf8Value& value);
void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
void Recv(const v8::FunctionCallbackInfo<v8::Value>& args);
void Send(const v8::FunctionCallbackInfo<v8::Value>& args);
void EvalContext(const v8::FunctionCallbackInfo<v8::Value>& args);
void ErrorToJSON(const v8::FunctionCallbackInfo<v8::Value>& args);
void Shared(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
void MessageCallback(v8::Local<v8::Message> message, v8::Local<v8::Value> data);
void QueueMicrotask(const v8::FunctionCallbackInfo<v8::Value>& args);
static intptr_t external_references[] = {
reinterpret_cast<intptr_t>(Print),
reinterpret_cast<intptr_t>(Recv),
reinterpret_cast<intptr_t>(Send),
reinterpret_cast<intptr_t>(EvalContext),
reinterpret_cast<intptr_t>(ErrorToJSON),
reinterpret_cast<intptr_t>(Shared),
reinterpret_cast<intptr_t>(MessageCallback),
reinterpret_cast<intptr_t>(QueueMicrotask),
0};
static const deno_buf empty_buf = {nullptr, 0};
static const deno_snapshot empty_snapshot = {nullptr, 0};
Deno* NewFromSnapshot(void* user_data, deno_recv_cb cb);
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context);
void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
v8::StartupData payload, void* data);
v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
void* data);
v8::Local<v8::Uint8Array> ImportBuf(DenoIsolate* d, deno_buf buf);
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source);
bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source, bool resolve_only);
} // namespace deno
extern "C" {
// This is just to workaround the linker.
struct deno_s {
deno::DenoIsolate isolate;
};
}
#endif // INTERNAL_H_

View file

@ -1,322 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include "test.h"
TEST(LibDenoTest, InitializesCorrectly) {
EXPECT_NE(snapshot.data_ptr, nullptr);
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "1 + 2");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, Snapshotter) {
Deno* d1 = deno_new(deno_config{1, empty_snapshot, empty, nullptr, nullptr});
deno_execute(d1, nullptr, "a.js", "a = 1 + 2");
EXPECT_EQ(nullptr, deno_last_exception(d1));
deno_snapshot test_snapshot = deno_snapshot_new(d1);
deno_delete(d1);
Deno* d2 = deno_new(deno_config{0, test_snapshot, empty, nullptr, nullptr});
deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');");
EXPECT_EQ(nullptr, deno_last_exception(d2));
deno_delete(d2);
deno_snapshot_delete(test_snapshot);
}
TEST(LibDenoTest, CanCallFunction) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_lock(d);
deno_execute(d, nullptr, "a.js",
"if (CanCallFunction() != 'foo') throw Error();");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_unlock(d);
deno_delete(d);
}
TEST(LibDenoTest, ErrorsCorrectly) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "throw Error()");
EXPECT_NE(nullptr, deno_last_exception(d));
deno_delete(d);
}
void assert_null(deno_pinned_buf b) {
EXPECT_EQ(b.data_ptr, nullptr);
EXPECT_EQ(b.data_len, 0u);
EXPECT_EQ(b.pin, nullptr);
}
TEST(LibDenoTest, RecvReturnEmpty) {
static int count = 0;
auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) {
EXPECT_EQ(op_id, 42u);
assert_null(zero_copy_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 2);
deno_delete(d);
}
TEST(LibDenoTest, BasicRecv) {
static int count = 0;
auto recv_cb = [](auto user_data, deno_op_id op_id, auto buf,
auto zero_copy_buf) {
EXPECT_EQ(op_id, 42u);
// auto d = reinterpret_cast<Deno*>(user_data);
assert_null(zero_copy_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 1);
EXPECT_EQ(buf.data_ptr[1], 2);
EXPECT_EQ(buf.data_ptr[2], 3);
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
deno_execute(d, d, "a.js", "BasicRecv()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 1);
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
{
deno_lock(d);
uint8_t response[] = {'b', 'a', 'r'};
deno_respond(d, nullptr, 43, {response, sizeof response});
deno_unlock(d);
}
EXPECT_EQ(count, 2);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_delete(d);
}
TEST(LibDenoTest, RecvReturnBar) {
static int count = 0;
auto recv_cb = [](auto user_data, deno_op_id op_id, auto buf,
auto zero_copy_buf) {
EXPECT_EQ(op_id, 42u);
auto d = reinterpret_cast<Deno*>(user_data);
assert_null(zero_copy_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
uint8_t response[] = {'b', 'a', 'r'};
deno_respond(d, user_data, op_id, {response, sizeof response});
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
deno_execute(d, d, "a.js", "RecvReturnBar()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 1);
deno_delete(d);
}
TEST(LibDenoTest, DoubleRecvFails) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "DoubleRecvFails()");
EXPECT_NE(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, TypedArraySnapshots) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, SnapshotBug) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "SnapshotBug()");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, GlobalErrorHandling) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()");
std::string expected =
"{\"message\":\"Uncaught ReferenceError: notdefined is not defined\","
"\"sourceLine\":\" "
"notdefined()\",\"scriptResourceName\":\"helloworld.js\","
"\"lineNumber\":3,\"startPosition\":3,\"endPosition\":4,\"errorLevel\":8,"
"\"startColumn\":1,\"endColumn\":2,\"isSharedCrossOrigin\":false,"
"\"isOpaque\":false,\"frames\":[{\"line\":3,\"column\":2,"
"\"functionName\":\"eval\",\"scriptName\":\"helloworld.js\",\"isEval\":"
"true,"
"\"isConstructor\":false,\"isWasm\":false},";
std::string actual(deno_last_exception(d), 0, expected.length());
EXPECT_STREQ(expected.c_str(), actual.c_str());
deno_delete(d);
}
TEST(LibDenoTest, ZeroCopyBuf) {
static int count = 0;
static deno_pinned_buf zero_copy_buf2;
auto recv_cb = [](auto user_data, deno_op_id op_id, deno_buf buf,
deno_pinned_buf zero_copy_buf) {
EXPECT_EQ(op_id, 42u);
count++;
EXPECT_NE(zero_copy_buf.pin, nullptr);
zero_copy_buf.data_ptr[0] = 4;
zero_copy_buf.data_ptr[1] = 2;
zero_copy_buf2 = zero_copy_buf;
EXPECT_EQ(2u, buf.data_len);
EXPECT_EQ(2u, zero_copy_buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 1);
EXPECT_EQ(buf.data_ptr[1], 2);
// Note zero_copy_buf won't actually be freed here because in
// libdeno_test.js zeroCopyBuf is a rooted global. We just want to exercise
// the API here.
deno_pinned_buf_delete(&zero_copy_buf);
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
deno_execute(d, d, "a.js", "ZeroCopyBuf()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 1);
// zero_copy_buf was subsequently changed in JS, let's check that our copy
// reflects that.
EXPECT_EQ(zero_copy_buf2.data_ptr[0], 9);
EXPECT_EQ(zero_copy_buf2.data_ptr[1], 8);
deno_delete(d);
}
TEST(LibDenoTest, CheckPromiseErrors) {
static int count = 0;
auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) {
count++;
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_execute(d, nullptr, "a.js", "CheckPromiseErrors()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 1);
// We caught the exception. So still no errors after calling
// deno_check_promise_errors().
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_delete(d);
}
TEST(LibDenoTest, LastException) {
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, nullptr, nullptr});
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_execute(d, nullptr, "a.js", "\n\nthrow Error('boo');\n\n");
EXPECT_STREQ(deno_last_exception(d),
"{\"message\":\"Uncaught Error: boo\",\"sourceLine\":\"throw "
"Error('boo');\",\"scriptResourceName\":\"a.js\",\"lineNumber\":"
"3,\"startPosition\":8,\"endPosition\":9,\"errorLevel\":8,"
"\"startColumn\":6,\"endColumn\":7,\"isSharedCrossOrigin\":"
"false,\"isOpaque\":false,\"frames\":[{\"line\":3,\"column\":7,"
"\"scriptName\":\"a.js\",\"isEval\":false,"
"\"isConstructor\":false,\"isWasm\":false}]}");
deno_delete(d);
}
TEST(LibDenoTest, EncodeErrorBug) {
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, nullptr, nullptr});
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_execute(d, nullptr, "a.js", "eval('a')");
EXPECT_STREQ(
deno_last_exception(d),
"{\"message\":\"Uncaught ReferenceError: a is not "
"defined\",\"sourceLine\":\"a\",\"lineNumber\":1,\"startPosition\":0,"
"\"endPosition\":1,\"errorLevel\":8,\"startColumn\":0,\"endColumn\":1,"
"\"isSharedCrossOrigin\":false,\"isOpaque\":false,\"frames\":[{\"line\":"
"1,\"column\":1,\"functionName\":\"eval\",\"scriptName\":\"<unknown>\","
"\"isEval\":true,\"isConstructor\":false,\"isWasm\":false},{\"line\":1,"
"\"column\":1,\"scriptName\":\"a.js\",\"isEval\":"
"false,\"isConstructor\":false,\"isWasm\":false}]}");
deno_delete(d);
}
TEST(LibDenoTest, Shared) {
uint8_t s[] = {0, 1, 2};
deno_buf shared = {s, sizeof s};
Deno* d = deno_new(deno_config{0, snapshot, shared, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "Shared()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(s[0], 42);
EXPECT_EQ(s[1], 43);
EXPECT_EQ(s[2], 44);
deno_delete(d);
}
TEST(LibDenoTest, Utf8Bug) {
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, nullptr, nullptr});
// The following is a valid UTF-8 javascript which just defines a string
// literal. We had a bug where libdeno would choke on this.
deno_execute(d, nullptr, "a.js", "x = \"\xEF\xBF\xBD\"");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, LibDenoEvalContext) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "LibDenoEvalContext();");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, LibDenoEvalContextError) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "LibDenoEvalContextError();");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, LibDenoEvalContextInvalidArgument) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "LibDenoEvalContextInvalidArgument();");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, LibDenoPrintInvalidArgument) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr, nullptr});
deno_execute(d, nullptr, "a.js", "LibDenoPrintInvalidArgument();");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(LibDenoTest, SharedAtomics) {
int32_t s[] = {0, 1, 2};
deno_buf shared = {reinterpret_cast<uint8_t*>(s), sizeof s};
Deno* d = deno_new(deno_config{0, empty_snapshot, shared, nullptr, nullptr});
deno_execute(d, nullptr, "a.js",
"Atomics.add(new Int32Array(Deno.core.shared), 0, 1)");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(s[0], 1);
EXPECT_EQ(s[1], 1);
EXPECT_EQ(s[2], 2);
deno_delete(d);
}
TEST(LibDenoTest, WasmInstantiate) {
static int count = 0;
auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) {
EXPECT_EQ(op_id, 42u);
EXPECT_EQ(buf.data_len, 1u);
EXPECT_EQ(buf.data_ptr[0], 42);
count++;
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr});
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_execute(d, nullptr, "a.js", "WasmInstantiate()");
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 3);
deno_delete(d);
}

View file

@ -1,271 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// A simple runtime that doesn't involve typescript or protobufs to test
// libdeno. Invoked by libdeno_test.cc
// eslint-disable-next-line @typescript-eslint/no-this-alias
const global = this;
function assert(cond) {
if (!cond) throw Error("libdeno_test.js assert failed");
}
global.CanCallFunction = () => {
Deno.core.print("Hello world from foo");
return "foo";
};
// This object is created to test snapshotting.
// See DeserializeInternalFieldsCallback and SerializeInternalFieldsCallback.
const snapshotted = new Uint8Array([1, 3, 3, 7]);
global.TypedArraySnapshots = () => {
assert(snapshotted[0] === 1);
assert(snapshotted[1] === 3);
assert(snapshotted[2] === 3);
assert(snapshotted[3] === 7);
};
global.RecvReturnEmpty = () => {
const m1 = new Uint8Array("abc".split("").map(c => c.charCodeAt(0)));
const m2 = m1.slice();
const r1 = Deno.core.send(42, m1);
assert(r1 == null);
const r2 = Deno.core.send(42, m2);
assert(r2 == null);
};
global.BasicRecv = () => {
const m = new Uint8Array([1, 2, 3]);
Deno.core.recv((opId, buf) => {
assert(opId === 43);
assert(buf instanceof Uint8Array);
assert(buf.byteLength === 3);
const s = String.fromCharCode(...buf);
assert(s === "bar");
const r = Deno.core.send(42, m);
assert(!r); // async
});
const r = Deno.core.send(42, m);
assert(!r); // async
};
global.RecvReturnBar = () => {
const m = new Uint8Array("abc".split("").map(c => c.charCodeAt(0)));
const r = Deno.core.send(42, m);
assert(r instanceof Uint8Array);
assert(r.byteLength === 3);
const rstr = String.fromCharCode(...r);
assert(rstr === "bar");
};
global.DoubleRecvFails = () => {
// Deno.core.recv is an internal function and should only be called once from the
// runtime.
Deno.core.recv((_channel, _msg) => assert(false));
Deno.core.recv((_channel, _msg) => assert(false));
};
global.SendRecvSlice = () => {
const abLen = 1024;
let buf = new Uint8Array(abLen);
for (let i = 0; i < 5; i++) {
// Set first and last byte, for verification by the native side.
buf[0] = 100 + i;
buf[buf.length - 1] = 100 - i;
// On the native side, the slice is shortened by 19 bytes.
buf = Deno.core.send(42, buf);
assert(buf.byteOffset === i * 11);
assert(buf.byteLength === abLen - i * 30 - 19);
assert(buf.buffer.byteLength == abLen);
// Look for values written by the backend.
assert(buf[0] === 200 + i);
assert(buf[buf.length - 1] === 200 - i);
// On the JS side, the start of the slice is moved up by 11 bytes.
buf = buf.subarray(11);
assert(buf.byteOffset === (i + 1) * 11);
assert(buf.byteLength === abLen - (i + 1) * 30);
}
};
global.JSSendArrayBufferViewTypes = () => {
// Test that ArrayBufferView slices are transferred correctly.
// Send Uint8Array.
const ab1 = new ArrayBuffer(4321);
const u8 = new Uint8Array(ab1, 2468, 1000);
u8[0] = 1;
Deno.core.send(42, u8);
// Send Uint32Array.
const ab2 = new ArrayBuffer(4321);
const u32 = new Uint32Array(ab2, 2468, 1000 / Uint32Array.BYTES_PER_ELEMENT);
u32[0] = 0x02020202;
Deno.core.send(42, u32);
// Send DataView.
const ab3 = new ArrayBuffer(4321);
const dv = new DataView(ab3, 2468, 1000);
dv.setUint8(0, 3);
Deno.core.send(42, dv);
};
// The following join has caused SnapshotBug to segfault when using kKeep.
[].join("");
global.SnapshotBug = () => {
assert("1,2,3" === String([1, 2, 3]));
};
global.GlobalErrorHandling = () => {
eval("\n\n notdefined()\n//# sourceURL=helloworld.js");
};
// Allocate this buf at the top level to avoid GC.
const zeroCopyBuf = new Uint8Array([3, 4]);
global.ZeroCopyBuf = () => {
const a = new Uint8Array([1, 2]);
const b = zeroCopyBuf;
// The second parameter of send should modified by the
// privileged side.
const r = Deno.core.send(42, a, b);
assert(r == null);
// b is different.
assert(b[0] === 4);
assert(b[1] === 2);
// Now we modify it again.
b[0] = 9;
b[1] = 8;
};
global.CheckPromiseErrors = () => {
async function fn() {
throw new Error("message");
}
(async () => {
try {
await fn();
} catch (e) {
Deno.core.send(42, new Uint8Array([42]));
}
})();
};
global.Shared = () => {
const ab = Deno.core.shared;
assert(ab instanceof SharedArrayBuffer);
assert(Deno.core.shared != undefined);
assert(ab.byteLength === 3);
const ui8 = new Uint8Array(ab);
assert(ui8[0] === 0);
assert(ui8[1] === 1);
assert(ui8[2] === 2);
ui8[0] = 42;
ui8[1] = 43;
ui8[2] = 44;
};
global.LibDenoEvalContext = () => {
const [result, errInfo] = Deno.core.evalContext("let a = 1; a");
assert(result === 1);
assert(!errInfo);
const [result2, errInfo2] = Deno.core.evalContext("a = a + 1; a");
assert(result2 === 2);
assert(!errInfo2);
};
global.LibDenoEvalContextError = () => {
const [result, errInfo] = Deno.core.evalContext("not_a_variable");
assert(!result);
assert(!!errInfo);
assert(errInfo.isNativeError); // is a native error (ReferenceError)
assert(!errInfo.isCompileError); // is NOT a compilation error
assert(errInfo.thrown.message === "not_a_variable is not defined");
const [result2, errInfo2] = Deno.core.evalContext("throw 1");
assert(!result2);
assert(!!errInfo2);
assert(!errInfo2.isNativeError); // is NOT a native error
assert(!errInfo2.isCompileError); // is NOT a compilation error
assert(errInfo2.thrown === 1);
const [result3, errInfo3] = Deno.core.evalContext(
"class AError extends Error {}; throw new AError('e')"
);
assert(!result3);
assert(!!errInfo3);
assert(errInfo3.isNativeError); // extend from native error, still native error
assert(!errInfo3.isCompileError); // is NOT a compilation error
assert(errInfo3.thrown.message === "e");
const [result4, errInfo4] = Deno.core.evalContext("{");
assert(!result4);
assert(!!errInfo4);
assert(errInfo4.isNativeError); // is a native error (SyntaxError)
assert(errInfo4.isCompileError); // is a compilation error! (braces not closed)
assert(errInfo4.thrown.message === "Unexpected end of input");
const [result5, errInfo5] = Deno.core.evalContext("eval('{')");
assert(!result5);
assert(!!errInfo5);
assert(errInfo5.isNativeError); // is a native error (SyntaxError)
assert(!errInfo5.isCompileError); // is NOT a compilation error! (just eval)
assert(errInfo5.thrown.message === "Unexpected end of input");
};
global.LibDenoEvalContextInvalidArgument = () => {
try {
Deno.core.evalContext();
} catch (e) {
assert(e instanceof TypeError);
assert(e.message === "Invalid Argument");
}
};
global.LibDenoPrintInvalidArgument = () => {
try {
Deno.core.print();
} catch (e) {
assert(e instanceof TypeError);
assert(e.message === "Invalid Argument");
}
try {
Deno.core.print(2, 3, 4);
} catch (e) {
assert(e instanceof TypeError);
assert(e.message === "Invalid Argument");
}
};
global.WasmInstantiate = () => {
// The following blob can be created by taking the following s-expr and pass
// it through wat2wasm.
// (module
// (func $add (param $a i32) (param $b i32) (result i32)
// local.get $a
// local.get $b
// i32.add)
// (export "add" (func $add))
// )
// prettier-ignore
const bytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60,
0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01,
0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20,
0x00, 0x20, 0x01, 0x6a, 0x0b
]);
(async () => {
Deno.core.send(42, new Uint8Array([42]));
const wasm = await WebAssembly.instantiate(bytes);
Deno.core.send(42, new Uint8Array([42]));
const result = wasm.instance.exports.add(1, 3);
if (result != 4) {
throw Error("bad");
}
// To signal success, we send back a fixed buffer.
Deno.core.send(42, new Uint8Array([42]));
})();
};

View file

@ -1,223 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include "exceptions.h"
#include "internal.h"
using deno::ClearException;
using deno::DenoIsolate;
using deno::HandleException;
using v8::Boolean;
using v8::Context;
using v8::EscapableHandleScope;
using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Locker;
using v8::Module;
using v8::Object;
using v8::ScriptCompiler;
using v8::ScriptOrigin;
using v8::String;
using v8::Value;
v8::MaybeLocal<v8::Module> ResolveCallback(Local<Context> context,
Local<String> specifier,
Local<Module> referrer) {
auto* isolate = context->GetIsolate();
v8::Isolate::Scope isolate_scope(isolate);
v8::Locker locker(isolate);
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
v8::EscapableHandleScope handle_scope(isolate);
deno_mod referrer_id = referrer->GetIdentityHash();
auto* referrer_info = d->GetModuleInfo(referrer_id);
CHECK_NOT_NULL(referrer_info);
for (int i = 0; i < referrer->GetModuleRequestsLength(); i++) {
Local<String> req = referrer->GetModuleRequest(i);
if (req->Equals(context, specifier).ToChecked()) {
v8::String::Utf8Value req_utf8(isolate, req);
std::string req_str(*req_utf8);
deno_mod id = d->resolve_cb_(d->user_data_, req_str.c_str(), referrer_id);
// Note: id might be zero, in which case GetModuleInfo will return
// nullptr.
auto* info = d->GetModuleInfo(id);
if (info == nullptr) {
char buf[64 * 1024];
snprintf(buf, sizeof(buf), "Cannot resolve module \"%s\" from \"%s\"",
req_str.c_str(), referrer_info->name.c_str());
isolate->ThrowException(deno::v8_str(buf));
break;
} else {
Local<Module> child_mod = info->handle.Get(isolate);
return handle_scope.Escape(child_mod);
}
}
}
return v8::MaybeLocal<v8::Module>(); // Error
}
extern "C" {
deno_mod deno_mod_new(Deno* d_, bool main, const char* name_cstr,
const char* source_cstr) {
auto* d = deno::unwrap(d_);
return d->RegisterModule(main, name_cstr, source_cstr);
}
const char* deno_mod_name(Deno* d_, deno_mod id) {
auto* d = deno::unwrap(d_);
auto* info = d->GetModuleInfo(id);
return info->name.c_str();
}
size_t deno_mod_imports_len(Deno* d_, deno_mod id) {
auto* d = deno::unwrap(d_);
auto* info = d->GetModuleInfo(id);
return info->import_specifiers.size();
}
const char* deno_mod_imports_get(Deno* d_, deno_mod id, size_t index) {
auto* d = deno::unwrap(d_);
auto* info = d->GetModuleInfo(id);
if (info == nullptr || index >= info->import_specifiers.size()) {
return nullptr;
} else {
return info->import_specifiers[index].c_str();
}
}
void deno_mod_instantiate(Deno* d_, void* user_data, deno_mod id,
deno_resolve_cb cb) {
auto* d = deno::unwrap(d_);
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
v8::Isolate::Scope isolate_scope(isolate);
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(isolate);
{
CHECK_NULL(d->resolve_cb_);
d->resolve_cb_ = cb;
{
auto* info = d->GetModuleInfo(id);
if (info == nullptr) {
return;
}
Local<Module> module = info->handle.Get(isolate);
if (module->GetStatus() == Module::kErrored) {
return;
}
auto maybe_ok = module->InstantiateModule(context, ResolveCallback);
CHECK(maybe_ok.IsJust() || try_catch.HasCaught());
}
d->resolve_cb_ = nullptr;
}
if (try_catch.HasCaught()) {
HandleException(context, try_catch.Exception());
}
}
void deno_mod_evaluate(Deno* d_, void* user_data, deno_mod id) {
auto* d = deno::unwrap(d_);
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
v8::Isolate::Scope isolate_scope(isolate);
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
v8::Context::Scope context_scope(context);
auto* info = d->GetModuleInfo(id);
auto module = info->handle.Get(isolate);
auto status = module->GetStatus();
if (status == Module::kInstantiated) {
bool ok = !module->Evaluate(context).IsEmpty();
status = module->GetStatus(); // Update status after evaluating.
if (ok) {
// Note status can still be kErrored even if we get ok.
CHECK(status == Module::kEvaluated || status == Module::kErrored);
} else {
CHECK_EQ(status, Module::kErrored);
}
}
switch (status) {
case Module::kEvaluated:
ClearException(context);
break;
case Module::kErrored:
HandleException(context, module->GetException());
break;
default:
FATAL("Unexpected module status: %d", static_cast<int>(status));
}
}
void deno_dyn_import_done(Deno* d_, void* user_data,
deno_dyn_import_id import_id, deno_mod mod_id,
const char* error_str) {
auto* d = deno::unwrap(d_);
CHECK((mod_id == 0 && error_str != nullptr) ||
(mod_id != 0 && error_str == nullptr) ||
(mod_id == 0 && !d->last_exception_handle_.IsEmpty()));
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
v8::Isolate::Scope isolate_scope(isolate);
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
auto context = d->context_.Get(d->isolate_);
v8::Context::Scope context_scope(context);
auto it = d->dyn_import_map_.find(import_id);
if (it == d->dyn_import_map_.end()) {
CHECK(false); // TODO(ry) error on bad import_id.
return;
}
/// Resolve.
auto persistent_promise = &it->second;
auto promise = persistent_promise->Get(isolate);
auto* info = d->GetModuleInfo(mod_id);
// Do the following callback into JS?? Is user_data_scope needed?
persistent_promise->Reset();
d->dyn_import_map_.erase(it);
if (info == nullptr) {
// Resolution error.
if (error_str != nullptr) {
auto msg = deno::v8_str(error_str);
auto exception = v8::Exception::TypeError(msg);
promise->Reject(context, exception).ToChecked();
} else {
auto e = d->last_exception_handle_.Get(isolate);
ClearException(context);
promise->Reject(context, e).ToChecked();
}
} else {
// Resolution success
Local<Module> module = info->handle.Get(isolate);
CHECK_EQ(module->GetStatus(), v8::Module::kEvaluated);
Local<Value> module_namespace = module->GetModuleNamespace();
promise->Resolve(context, module_namespace).ToChecked();
}
d->isolate_->RunMicrotasks();
}
} // extern "C"

View file

@ -1,426 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include "test.h"
static int exec_count = 0;
void recv_cb(void* user_data, deno_op_id op_id, deno_buf buf,
deno_pinned_buf zero_copy_buf) {
// We use this to check that scripts have executed.
EXPECT_EQ(1u, buf.data_len);
EXPECT_EQ(42u, op_id);
EXPECT_EQ(buf.data_ptr[0], 4);
EXPECT_EQ(zero_copy_buf.data_ptr, nullptr);
EXPECT_EQ(zero_copy_buf.data_len, 0u);
EXPECT_EQ(zero_copy_buf.pin, nullptr);
exec_count++;
}
TEST(ModulesTest, Resolution) {
exec_count = 0; // Reset
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, recv_cb, nullptr});
EXPECT_EQ(0, exec_count);
static deno_mod a = deno_mod_new(d, true, "a.js",
"import { b } from 'b.js'\n"
"if (b() != 'b') throw Error();\n"
"Deno.core.send(42, new Uint8Array([4]));");
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
const char* b_src = "export function b() { return 'b' }";
static deno_mod b = deno_mod_new(d, false, "b.js", b_src);
EXPECT_NE(b, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(0, exec_count);
EXPECT_EQ(1u, deno_mod_imports_len(d, a));
EXPECT_EQ(0u, deno_mod_imports_len(d, b));
EXPECT_STREQ("b.js", deno_mod_imports_get(d, a, 0));
EXPECT_EQ(nullptr, deno_mod_imports_get(d, a, 1));
EXPECT_EQ(nullptr, deno_mod_imports_get(d, b, 0));
static int resolve_count = 0;
auto resolve_cb = [](void* user_data, const char* specifier,
deno_mod referrer) {
EXPECT_EQ(referrer, a);
EXPECT_STREQ(specifier, "b.js");
resolve_count++;
return b;
};
deno_mod_instantiate(d, d, b, resolve_cb);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(0, resolve_count);
EXPECT_EQ(0, exec_count);
deno_mod_instantiate(d, d, a, resolve_cb);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(1, resolve_count);
EXPECT_EQ(0, exec_count);
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(1, resolve_count);
EXPECT_EQ(1, exec_count);
deno_delete(d);
}
TEST(ModulesTest, ResolutionError) {
exec_count = 0; // Reset
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, recv_cb, nullptr});
EXPECT_EQ(0, exec_count);
static deno_mod a = deno_mod_new(d, true, "a.js",
"import 'bad'\n"
"Deno.core.send(42, new Uint8Array([4]));");
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(0, exec_count);
EXPECT_EQ(1u, deno_mod_imports_len(d, a));
EXPECT_STREQ("bad", deno_mod_imports_get(d, a, 0));
static int resolve_count = 0;
auto resolve_cb = [](void* user_data, const char* specifier,
deno_mod referrer) {
EXPECT_EQ(referrer, a);
EXPECT_STREQ(specifier, "bad");
resolve_count++;
return 0;
};
deno_mod_instantiate(d, d, a, resolve_cb);
EXPECT_NE(nullptr, deno_last_exception(d));
EXPECT_EQ(1, resolve_count);
EXPECT_EQ(0, exec_count);
deno_delete(d);
}
TEST(ModulesTest, ImportMetaUrl) {
exec_count = 0; // Reset
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, recv_cb, nullptr});
EXPECT_EQ(0, exec_count);
static deno_mod a =
deno_mod_new(d, true, "a.js",
"if ('a.js' != import.meta.url) throw 'hmm'\n"
"Deno.core.send(42, new Uint8Array([4]));");
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(0, exec_count);
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(1, exec_count);
}
TEST(ModulesTest, ImportMetaMain) {
Deno* d = deno_new(deno_config{0, empty_snapshot, empty, recv_cb, nullptr});
const char* throw_not_main_src = "if (!import.meta.main) throw 'err'";
static deno_mod throw_not_main =
deno_mod_new(d, true, "a.js", throw_not_main_src);
EXPECT_NE(throw_not_main, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, throw_not_main, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, throw_not_main);
EXPECT_EQ(nullptr, deno_last_exception(d));
const char* throw_main_src = "if (import.meta.main) throw 'err'";
static deno_mod throw_main = deno_mod_new(d, false, "b.js", throw_main_src);
EXPECT_NE(throw_main, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, throw_main, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, throw_main);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_delete(d);
}
TEST(ModulesTest, DynamicImportSuccess) {
exec_count = 0;
static int dyn_import_count = 0;
static deno_mod b = 0;
auto dyn_import_cb = [](auto user_data, const char* specifier,
const char* referrer, deno_dyn_import_id import_id) {
auto d = reinterpret_cast<Deno*>(user_data);
dyn_import_count++;
EXPECT_STREQ(specifier, "foo");
EXPECT_STREQ(referrer, "a.js");
deno_dyn_import_done(d, d, import_id, b, nullptr);
};
const char* src =
"(async () => { \n"
" let mod = await import('foo'); \n"
" assert(mod.b() === 'b'); \n"
// Send a message to signify that we're done.
" Deno.core.send(42, new Uint8Array([4])); \n"
"})(); \n";
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb});
static deno_mod a = deno_mod_new(d, true, "a.js", src);
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
const char* b_src = "export function b() { return 'b' }";
b = deno_mod_new(d, false, "b.js", b_src);
EXPECT_NE(b, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, b, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, b);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_delete(d);
EXPECT_EQ(1, exec_count);
EXPECT_EQ(1, dyn_import_count);
}
TEST(ModulesTest, DynamicImportError) {
exec_count = 0;
static int dyn_import_count = 0;
auto dyn_import_cb = [](auto user_data, const char* specifier,
const char* referrer, deno_dyn_import_id import_id) {
auto d = reinterpret_cast<Deno*>(user_data);
dyn_import_count++;
EXPECT_STREQ(specifier, "foo");
EXPECT_STREQ(referrer, "a.js");
// We indicate there was an error resolving by returning mod_id 0.
deno_dyn_import_done(d, d, import_id, 0, "foo not found");
};
const char* src =
"(async () => { \n"
" let mod = await import('foo'); \n"
// The following should be unreachable.
" Deno.core.send(42, new Uint8Array([4])); \n"
"})(); \n";
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb});
static deno_mod a = deno_mod_new(d, true, "a.js", src);
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
// No error when evaluating, because it's an async error.
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
// Now we should get an error.
deno_check_promise_errors(d);
EXPECT_NE(deno_last_exception(d), nullptr);
std::string e(deno_last_exception(d));
EXPECT_NE(e.find("Uncaught TypeError: foo not found"), std::string::npos);
deno_delete(d);
EXPECT_EQ(0, exec_count);
EXPECT_EQ(1, dyn_import_count);
}
TEST(ModulesTest, DynamicImportAsync) {
exec_count = 0;
static int dyn_import_count = 0;
static deno_mod b = 0;
static std::vector<deno_dyn_import_id> import_ids = {};
auto dyn_import_cb = [](auto user_data, const char* specifier,
const char* referrer, deno_dyn_import_id import_id) {
// auto d = reinterpret_cast<Deno*>(user_data);
dyn_import_count++;
EXPECT_STREQ(specifier, "foo");
EXPECT_STREQ(referrer, "a.js");
// We don't call deno_dyn_import_done until later.
import_ids.push_back(import_id);
};
const char* src =
"(async () => { \n"
" let mod = await import('foo'); \n"
" assert(mod.b() === 'b'); \n"
// AGAIN!
" mod = await import('foo'); \n"
" assert(mod.b() === 'b'); \n"
// Send a message to signify that we're done.
" Deno.core.send(42, new Uint8Array([4])); \n"
"})(); \n";
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb});
static deno_mod a = deno_mod_new(d, true, "a.js", src);
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
// Evaluate. We check that there are no errors, and Deno.core.send has not
// been called.
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
EXPECT_EQ(0, exec_count);
EXPECT_EQ(1, dyn_import_count);
// Instantiate b.js
const char* b_src = "export function b() { return 'b' }";
b = deno_mod_new(d, false, "b.js", b_src);
EXPECT_NE(b, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, b, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, b);
EXPECT_EQ(nullptr, deno_last_exception(d));
// Now we resolve the import.
EXPECT_EQ(1u, import_ids.size());
auto import_id = import_ids.back();
import_ids.pop_back();
deno_dyn_import_done(d, d, import_id, b, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
EXPECT_EQ(1u, import_ids.size());
EXPECT_EQ(2, dyn_import_count);
EXPECT_EQ(0, exec_count);
import_id = import_ids.back();
import_ids.pop_back();
deno_dyn_import_done(d, d, import_id, b, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
// We still have to resolve the second one
EXPECT_EQ(2, dyn_import_count);
EXPECT_EQ(1, exec_count);
deno_delete(d);
}
TEST(ModulesTest, DynamicImportThrows) {
exec_count = 0;
static int dyn_import_count = 0;
static deno_mod b = 0;
static std::vector<deno_dyn_import_id> import_ids = {};
auto dyn_import_cb = [](auto user_data, const char* specifier,
const char* referrer, deno_dyn_import_id import_id) {
dyn_import_count++;
EXPECT_STREQ(specifier, "b.js");
EXPECT_STREQ(referrer, "a.js");
// We don't call deno_dyn_import_done until later.
import_ids.push_back(import_id);
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb});
// Instantiate and evaluate the root module. This should succeed.
const char* a_src =
"(async () => { \n"
" let mod = await import('b.js'); \n"
// unreachable
" Deno.core.send(42, new Uint8Array([4])); \n"
"})(); \n";
static deno_mod a = deno_mod_new(d, true, "a.js", a_src);
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_check_promise_errors(d);
EXPECT_EQ(deno_last_exception(d), nullptr);
// Instantiate b.js, which should succeed.
const char* b_src = "throw new Error('foo')";
b = deno_mod_new(d, false, "b.js", b_src);
EXPECT_NE(b, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, b, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
// Evaluate b.js. It throws in the global scope, so deno_last_exception()
// should be non-null afterwards.
deno_mod_evaluate(d, d, b);
EXPECT_NE(deno_last_exception(d), nullptr);
// Resolve the dynamic import of b.js. Since deno_mod_evaluate() failed,
// we indicate failure to deno_dyn_import_done() by setting mod_id to 0.
// The last error should be picked up and cleared by deno_dyn_import_done().
EXPECT_EQ(1u, import_ids.size());
auto import_id = import_ids.back();
import_ids.pop_back();
deno_dyn_import_done(d, d, import_id, 0, nullptr);
EXPECT_EQ(deno_last_exception(d), nullptr);
// Since the dynamically imported module threw an error,
// it should show up as an unhandled promise rejection.
deno_check_promise_errors(d);
EXPECT_NE(deno_last_exception(d), nullptr);
std::string e(deno_last_exception(d));
EXPECT_NE(e.find("Uncaught Error: foo"), std::string::npos);
EXPECT_EQ(1, dyn_import_count);
EXPECT_EQ(0, exec_count);
deno_delete(d);
}
TEST(ModulesTest, DynamicImportSyntaxError) {
exec_count = 0;
static int dyn_import_count = 0;
auto dyn_import_cb = [](auto user_data, const char* specifier,
const char* referrer, deno_dyn_import_id import_id) {
auto d = reinterpret_cast<Deno*>(user_data);
dyn_import_count++;
EXPECT_STREQ(specifier, "b.js");
EXPECT_STREQ(referrer, "a.js");
// Compile b.js, which should fail because of the syntax error.
deno_mod b = deno_mod_new(d, false, "b.js", "syntax error");
EXPECT_EQ(b, 0);
EXPECT_NE(nullptr, deno_last_exception(d));
// `deno_dyn_import_done` should consume the last exception, and use it
// to reject the dynamic import promise.
deno_dyn_import_done(d, d, import_id, 0, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb});
// Instantiate and evaluate the root module. This should succeed.
const char* src =
"(async () => { \n"
" let mod = await import('b.js'); \n"
// unreachable
" Deno.core.send(42, new Uint8Array([4])); \n"
"})(); \n";
static deno_mod a = deno_mod_new(d, true, "a.js", src);
EXPECT_NE(a, 0);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_instantiate(d, d, a, nullptr);
EXPECT_EQ(nullptr, deno_last_exception(d));
deno_mod_evaluate(d, d, a);
EXPECT_EQ(nullptr, deno_last_exception(d));
// The failed dynamic import should cause an unhandled promise rejection.
deno_check_promise_errors(d);
EXPECT_NE(deno_last_exception(d), nullptr);
EXPECT_NE(std::string(deno_last_exception(d)).find("Syntax"),
std::string::npos);
EXPECT_EQ(1, dyn_import_count);
EXPECT_EQ(0, exec_count);
deno_delete(d);
}

View file

@ -1,47 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#include "test.h"
#include <fstream>
#include <string>
#include "internal.h"
deno_snapshot snapshot = {nullptr, 0};
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();
}
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);
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 = deno_snapshot_new(d);
testing::InitGoogleTest(&argc, argv);
deno_init();
deno_set_v8_flags(&argc, argv);
return RUN_ALL_TESTS();
}

View file

@ -1,12 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#ifndef TEST_H_
#define TEST_H_
#include "deno.h"
#include "testing/gtest/include/gtest/gtest.h"
extern deno_snapshot snapshot; // Loaded in libdeno/test.cc
const deno_buf empty = {nullptr, 0};
const deno_snapshot empty_snapshot = {nullptr, 0};
#endif // TEST_H_

View file

@ -1 +0,0 @@
v8/testing

View file

@ -1 +0,0 @@
v8/third_party

View file

@ -1 +0,0 @@
v8/tools

View file

@ -1 +0,0 @@
../../third_party/v8

View file

@ -225,8 +225,7 @@ fn write_snapshot(
) -> Result<(), ErrBox> { ) -> Result<(), ErrBox> {
println!("creating snapshot..."); println!("creating snapshot...");
let snapshot = runtime_isolate.snapshot()?; let snapshot = runtime_isolate.snapshot()?;
let snapshot_slice = let snapshot_slice: &[u8] = &*snapshot;
unsafe { std::slice::from_raw_parts(snapshot.data_ptr, snapshot.data_len) };
println!("snapshot bytes {}", snapshot_slice.len()); println!("snapshot bytes {}", snapshot_slice.len());
let snapshot_path = bundle.with_extension("bin"); let snapshot_path = bundle.with_extension("bin");

View file

@ -255,6 +255,9 @@ test(async function testPrettierPrintToStdout(): Promise<void> {
emptyDir(tempDir); emptyDir(tempDir);
}); });
// TODO(bartlomieju): reenable after landing rusty_v8 branch
// crashing on Windows
/*
test(async function testPrettierReadFromStdin(): Promise<void> { test(async function testPrettierReadFromStdin(): Promise<void> {
interface TestCase { interface TestCase {
stdin: string; stdin: string;
@ -377,6 +380,7 @@ test(async function testPrettierReadFromStdin(): Promise<void> {
); );
} }
}); });
*/
test(async function testPrettierWithAutoConfig(): Promise<void> { test(async function testPrettierWithAutoConfig(): Promise<void> {
const configs = [ const configs = [

@ -1 +1 @@
Subproject commit 54a98143f8ba78da045cb41a5db3ef0cfb099c5d Subproject commit 9ab7948049d96bdd3af67323f758b81a9e4cbc27

View file

@ -1,8 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. # Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import os
from util import build_path from util import build_path
from benchmark import read_json, write_json from benchmark import read_json, write_json
import os
current_data_file = os.path.join(build_path(), "bench.json") current_data_file = os.path.join(build_path(), "bench.json")
all_data_file = "gh-pages/data.json" # Includes all benchmark data. all_data_file = "gh-pages/data.json" # Includes all benchmark data.

View file

@ -1,166 +0,0 @@
#!/usr/bin/env python
# Because of limitations in Cargo, Deno must dynamically build temporary source
# directories in order to publish to crates.io.
# The "deno" crate corresponds to the //core/ directory and depends on a
# platform dependent crate binary crate containing pre-compiled libdeno
# https://crates.io/crates/deno
# https://crates.io/crates/deno-x86_64-pc-windows-msvc
# https://crates.io/crates/deno-x86_64-apple-darwin
# https://crates.io/crates/deno-x86_64-unknown-linux-gnu
import os
import sys
import re
import errno
from shutil import copytree, ignore_patterns, copyfile
from tempfile import mkdtemp
from string import Template
from util import root_path, run
if sys.platform == "linux2":
llvm_target = "x86_64-unknown-linux-gnu"
static_lib_suffix = ".a"
elif sys.platform == "darwin":
llvm_target = "x86_64-apple-darwin"
static_lib_suffix = ".a"
elif sys.platform == "win32":
llvm_target = "x86_64-pc-windows-msvc"
static_lib_suffix = ".lib"
else:
assert (False)
lib_name = os.path.join(root_path, "target", "release", "obj",
"libdeno" + static_lib_suffix)
def get_version(toml_path):
for line in open(toml_path):
match = re.search('version = "(.*)"', line)
if match:
return match.group(1)
core_path = os.path.join(root_path, "core")
cargo_toml_path = os.path.join(core_path, "Cargo.toml")
version = get_version(cargo_toml_path)
def main():
os.chdir(root_path)
run([
"cargo", "build", "-vv", "--manifest-path", cargo_toml_path, "--lib",
"--release", "--locked"
])
assert (os.path.exists(lib_name))
root_temp = mkdtemp()
print "cargo package temp dir", root_temp
build_core(root_temp)
build_platform_crate(root_temp)
print "Now go into %s and run 'cargo publish' manually." % root_temp
def build_core(root_temp):
core_temp = os.path.join(root_temp, "core")
# Copy entire core tree into temp directory, excluding build.rs and libdeno
# and unnecessary files.
copytree(
core_path,
core_temp,
ignore=ignore_patterns("build.rs", "libdeno", ".*", "*.gn", "*.orig"))
cargo_toml_temp = os.path.join(core_temp, "Cargo.toml")
t = cargo_toml_deps.substitute(VERSION=version)
# Append deps to //core/Cargo.toml
# This append is the entire reason we are copying the tree.
with open(cargo_toml_temp, "a") as f:
f.write(t)
def build_platform_crate(root_temp):
platform_temp = os.path.join(root_temp, "platform")
copy_static_lib(platform_temp)
inputs = {"TARGET": llvm_target, "VERSION": version}
generate(platform_temp, "build.rs", platform_build_rs.substitute(inputs))
generate(platform_temp, "Cargo.toml",
platform_cargo_toml.substitute(inputs))
generate(platform_temp, "src/lib.rs", "")
def copy_static_lib(platform_temp):
platform_lib = os.path.join(platform_temp, "lib/")
mkdir_p(platform_lib)
platform_lib_name = os.path.join(platform_lib, os.path.basename(lib_name))
assert (os.path.exists(lib_name))
copyfile(lib_name, platform_lib_name)
platform_build_rs = Template("""
fn main() {
use std::env::var;
use std::path::Path;
if var("TARGET")
.map(|target| target == "$TARGET")
.unwrap_or(false)
{
let dir = var("CARGO_MANIFEST_DIR").unwrap();
println!(
"cargo:rustc-link-search=native={}",
Path::new(&dir).join("lib").display()
);
}
}
""")
platform_cargo_toml = Template("""
[package]
name = "deno-$TARGET"
description = "Binary dependencies for the 'deno' crate"
authors = ["The deno authors <bertbelder@nodejs.org>"]
version = "$VERSION"
build = "build.rs"
include = ["src/*", "lib/*", "Cargo.toml", "build.rs"]
license = "MIT"
repository = "https://github.com/denoland/deno"
""")
cargo_toml_deps = Template("""
[target.x86_64-apple-darwin.dependencies]
deno-x86_64-apple-darwin = "=$VERSION"
[target.x86_64-pc-windows-msvc.dependencies]
deno-x86_64-pc-windows-msvc = "=$VERSION"
[target.x86_64-unknown-linux-gnu.dependencies]
deno-x86_64-unknown-linux-gnu = "=$VERSION"
""")
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def generate(out_dir, filename, content):
path = os.path.join(out_dir, filename)
d = os.path.dirname(path)
mkdir_p(d)
with open(path, "w") as f:
f.write(content)
if __name__ == '__main__':
sys.exit(main())

View file

@ -3,7 +3,7 @@
import os import os
import sys import sys
import argparse import argparse
from third_party import get_buildtools_tool_path, google_env, python_env from third_party import python_env
from util import git_ls_files, third_party_path, root_path, run from util import git_ls_files, third_party_path, root_path, run
@ -11,20 +11,12 @@ def main():
os.chdir(root_path) os.chdir(root_path)
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--cc", help="run clang-format", action="store_true")
parser.add_argument("--gn", help="run gn format", action="store_true")
parser.add_argument("--js", help="run prettier", action="store_true") parser.add_argument("--js", help="run prettier", action="store_true")
parser.add_argument("--py", help="run yapf", action="store_true") parser.add_argument("--py", help="run yapf", action="store_true")
parser.add_argument("--rs", help="run rustfmt", action="store_true") parser.add_argument("--rs", help="run rustfmt", action="store_true")
args = parser.parse_args() args = parser.parse_args()
did_fmt = False did_fmt = False
if args.cc:
clang_format()
did_fmt = True
if args.gn:
gn_format()
did_fmt = True
if args.js: if args.js:
prettier() prettier()
did_fmt = True did_fmt = True
@ -36,29 +28,11 @@ def main():
did_fmt = True did_fmt = True
if not did_fmt: if not did_fmt:
clang_format()
gn_format()
prettier() prettier()
yapf() yapf()
rustfmt() rustfmt()
def clang_format():
print "clang-format"
exe = get_buildtools_tool_path("clang-format")
source_files = git_ls_files(root_path, ["*.cc", "*.h"])
run([exe, "-i", "-style", "Google", "--"] + source_files,
env=google_env(),
quiet=True)
def gn_format():
print "gn format"
exe = get_buildtools_tool_path("gn")
source_files = git_ls_files(root_path, ["*.gn", "*.gni"])
run([exe, "format", "--"] + source_files, env=google_env(), quiet=True)
def prettier(): def prettier():
print "prettier" print "prettier"
script = os.path.join(third_party_path, "node_modules", "prettier", script = os.path.join(third_party_path, "node_modules", "prettier",

View file

@ -1,39 +0,0 @@
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
# pylint: disable=line-too-long
solutions = [
{
'url': 'https://chromium.googlesource.com/v8/v8.git@8.0.192',
'name': 'v8',
'deps_file': 'DEPS',
'custom_deps': {
'v8/build': None,
'v8/third_party/catapult': None,
'v8/third_party/colorama/src': None,
'v8/testing/gmock': None,
'v8/tools/swarming_client': None,
'v8/tools/gyp': None,
'v8/third_party/instrumented_libraries': None,
'v8/third_party/android_tools': None,
'v8/third_party/depot_tools': None,
'v8/test/wasm-js': None,
'v8/test/benchmarks/data': None,
'v8/test/mozilla/data': None,
'v8/third_party/icu': None,
'v8/test/test262/data': None,
'v8/test/test262/harness': None,
'v8/tools/luci-go': None
}
},
{
'url':
'https://chromium.googlesource.com/chromium/tools/depot_tools@23247b99321549c24e62ad45200409419423695d',
'name':
'depot_tools'
},
{
'url':
'https://github.com/cpplint/cpplint.git@a33992f68f36fcaa6d0f531a25012a4c474d3542',
'name':
'cpplint'
}
]

View file

@ -4,7 +4,7 @@
import os import os
import sys import sys
from util import enable_ansi_colors, git_ls_files, libdeno_path, root_path, run from util import enable_ansi_colors, git_ls_files, root_path, run
from util import third_party_path from util import third_party_path
from third_party import python_env from third_party import python_env
@ -12,28 +12,10 @@ from third_party import python_env
def main(): def main():
enable_ansi_colors() enable_ansi_colors()
os.chdir(root_path) os.chdir(root_path)
cpplint()
eslint() eslint()
pylint() pylint()
def cpplint():
print "cpplint"
script = os.path.join(third_party_path, "cpplint", "cpplint.py")
source_files = git_ls_files(libdeno_path, ["*.cc", "*.h"])
run([
sys.executable,
script,
"--quiet",
"--filter=-build/include_subdir",
"--repository=" + libdeno_path,
"--",
] + source_files,
env=python_env(),
shell=False,
quiet=True)
def eslint(): def eslint():
print "eslint" print "eslint"
script = os.path.join(third_party_path, "node_modules", "eslint", "bin", script = os.path.join(third_party_path, "node_modules", "eslint", "bin",
@ -55,7 +37,7 @@ def eslint():
def pylint(): def pylint():
print "pylint" print "pylint"
script = os.path.join(third_party_path, "python_packages", "pylint") script = os.path.join(third_party_path, "python_packages", "pylint")
rcfile = os.path.join(third_party_path, "depot_tools", "pylintrc") rcfile = os.path.join(root_path, "tools", "pylintrc")
source_files = git_ls_files(root_path, ["*.py"]) source_files = git_ls_files(root_path, ["*.py"])
run([sys.executable, script, "--rcfile=" + rcfile, "--"] + source_files, run([sys.executable, script, "--rcfile=" + rcfile, "--"] + source_files,
env=python_env(), env=python_env(),

332
tools/pylintrc Normal file
View file

@ -0,0 +1,332 @@
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
#
# These should get enabled, but the codebase has too many violations currently:
# bad-continuation
# anomalous-backslash-in-string
# bad-context-manager
# bad-indentation
# bad-str-strip-call
# bad-whitespace
# cell-var-from-loop
# deprecated-lambda
# eval-used
# function-redefined
# import-error
# locally-enabled
# missing-final-newline
# no-init
# no-name-in-module
# no-self-use
# not-callable
# old-style-class
# protected-access
# superfluous-parens
# super-on-old-class
# too-many-function-args
# trailing-whitespace
# unnecessary-semicolon
# unpacking-non-sequence
# unused-import
# useless-else-on-loop
#
# CHANGED:
disable=
invalid-name,
missing-docstring,
too-many-lines,
bad-inline-option,
locally-disabled,
duplicate-code,
too-many-ancestors,
too-many-instance-attributes,
too-few-public-methods,
too-many-public-methods,
too-many-return-statements,
too-many-branches,
too-many-arguments,
too-many-locals,
too-many-statements,
abstract-class-not-used,
abstract-class-little-used,
exec-used,
bad-builtin,
star-args,
deprecated-module,
reimported,
fixme,
global-statement,
broad-except,
logging-not-lazy,
bad-continuation,
anomalous-backslash-in-string,
bad-context-manager,
bad-indentation,
bad-str-strip-call,
bad-whitespace,
cell-var-from-loop,
deprecated-lambda,
eval-used,
function-redefined,
import-error,
locally-enabled,
missing-final-newline,
no-init,
no-name-in-module,
no-self-use,
not-callable,
old-style-class,
protected-access,
superfluous-parens,
super-on-old-class,
too-many-function-args,
trailing-whitespace,
unnecessary-semicolon,
unpacking-non-sequence,
unused-import,
useless-else-on-loop
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
# CHANGED:
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (RP0004).
comment=no
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the beginning of the name of dummy variables
# (i.e. not used).
dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent,multiprocessing.managers.SyncManager
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=80
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
# CHANGED:
indent-string=' '
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression which should only match correct module level names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression which should only match correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branchs=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

View file

@ -1,17 +0,0 @@
#!/usr/bin/env python
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
"""
gn can only run python scripts. This launches a subprocess Node process.
The working dir of this program is out/Debug/ (AKA root_build_dir)
Before running node, we symlink js/node_modules to out/Debug/node_modules.
"""
import sys
from os import path
from util import symlink, root_path, run
if not path.exists("node_modules"):
target_abs = path.join(root_path, "third_party/node_modules")
target_rel = path.relpath(target_abs)
symlink(target_rel, "node_modules", True)
run(["node"] + sys.argv[1:], quiet=True)

View file

@ -1,184 +0,0 @@
#!/usr/bin/env python
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import os
import re
import sys
from distutils.spawn import find_executable
import argparse
import third_party
from util import build_mode, build_path, enable_ansi_colors, libdeno_path
from util import shell_quote, root_path, run, third_party_path
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-binary-download",
help="Do not download binaries, must use depot_tools manually",
action="store_true")
def main():
enable_ansi_colors()
os.chdir(root_path)
args = parser.parse_args()
if args.no_binary_download:
print "no binary download"
else:
print "binary download"
third_party.download_gn()
third_party.download_clang_format()
third_party.download_clang()
third_party.maybe_download_sysroot()
write_lastchange()
mode = build_mode(default=None)
if mode is not None:
gn_gen(mode)
else:
gn_gen("release")
gn_gen("debug")
def write_if_not_exists(filename, contents):
if not os.path.exists(filename):
with open(filename, "w+") as f:
f.write(contents)
def write_lastchange():
lastchange_file = os.path.join(libdeno_path, "build", "util", "LASTCHANGE")
committime_file = lastchange_file + ".committime"
write_if_not_exists(
lastchange_file,
"LASTCHANGE=c42e4ddbb7973bfb0c57a49ab6bf6dc432baad7e-\n")
write_if_not_exists(committime_file, "1535518087")
# TODO Properly we should call the following script, but it seems to cause
# a rebuild on every commit.
# run([
# sys.executable, "build/util/lastchange.py", "-o", lastchange_file,
# "--source-dir", root_path, "--filter="
# ])
# If this text is found in args.gn, we assume it hasn't been hand edited.
gn_args_header = [
"# This file is automatically generated by tools/setup.py.",
"# REMOVE THIS LINE to preserve any changes you make.", ""
]
def gn_string(s):
# In gn, strings are enclosed in double-quotes and use backslash as the
# escape character. The only escape sequences supported are:
# \" (for literal quote)
# \$ (for literal dollars sign)
# \\ (for literal backslash)
# Any other use of a backslash is treated as a literal backslash.
s = re.sub(r'("|\$|\\(?=["$\\]))', r'\\\1', s)
s = '"' + s + '"'
return s
def gn_args_are_generated(lines):
for line in lines:
if re.match("^\s*#.*REMOVE THIS LINE", line):
return True
return False
def read_gn_args(args_filename):
if not os.path.exists(args_filename):
return (None, False) # No content, not hand edited.
with open(args_filename) as f:
lines = f.read().splitlines()
args = [l.strip() for l in lines if not re.match("^\s*(#|$)", l)]
hand_edited = not gn_args_are_generated(lines)
return (args, hand_edited)
def write_gn_args(args_filename, args):
assert not gn_args_are_generated(args) # No header -> hand crafted.
lines = gn_args_header + args
assert gn_args_are_generated(lines) # With header -> generated.
# Ensure the directory where args.gn goes exists.
d = os.path.dirname(args_filename)
if not os.path.isdir(d):
os.makedirs(d)
with open(args_filename, "w") as f:
f.write("\n".join(lines) + "\n")
def generate_gn_args(mode):
out = []
if mode == "release":
out += ["is_official_build=true", "symbol_level=0"]
elif mode == "debug":
out += ["is_debug=true"]
else:
print "Bad mode {}. Use 'release' or 'debug' (default)" % mode
sys.exit(1)
if "DENO_BUILD_ARGS" in os.environ:
out += os.environ["DENO_BUILD_ARGS"].split()
# Check if sccache is in the path, and if so we set cc_wrapper.
cc_wrapper = find_executable("sccache")
if not cc_wrapper:
cc_wrapper = third_party.get_prebuilt_tool_path("sccache")
if os.path.exists(cc_wrapper):
# The gn toolchain does not shell escape cc_wrapper, so do it here.
out += ['cc_wrapper=%s' % gn_string(shell_quote(cc_wrapper))]
if os.name == "nt":
# Disable treat_warnings_as_errors until this sccache bug is fixed:
# https://github.com/mozilla/sccache/issues/264
out += ["treat_warnings_as_errors=false"]
return out
def gn_exe():
if "DENO_GN_PATH" in os.environ:
return os.environ["DENO_GN_PATH"]
else:
return third_party.get_buildtools_tool_path("gn")
# gn gen.
def gn_gen(mode):
os.environ["DENO_BUILD_MODE"] = mode
# Rather than using gn gen --args we write directly to the args.gn file.
# This is to avoid quoting/escaping complications when passing overrides as
# command-line arguments.
args_filename = os.path.join(build_path(), "args.gn")
# Check if args.gn exists, and if it was auto-generated or handcrafted.
existing_gn_args, hand_edited = read_gn_args(args_filename)
# If args.gn wasn't handcrafted, regenerate it.
if hand_edited:
print "%s: Using gn options from hand edited '%s'." % (mode,
args_filename)
gn_args = existing_gn_args
else:
print "%s: Writing gn options to '%s'." % (mode, args_filename)
gn_args = generate_gn_args(mode)
if gn_args != existing_gn_args:
write_gn_args(args_filename, gn_args)
for line in gn_args:
print " " + line
run([gn_exe(), "gen", build_path()],
cwd=libdeno_path,
env=third_party.google_env())
if __name__ == '__main__':
sys.exit(main())

View file

@ -1,64 +0,0 @@
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import os
import sys
from shutil import rmtree
from tempfile import mktemp
from setup import gn_string, read_gn_args, write_gn_args
from test_util import DenoTestCase, run_tests
class TestSetup(DenoTestCase):
def test_gn_string(self):
assert gn_string('abc') == '"abc"'
assert gn_string('foo$bar"baz') == '"foo\\$bar\\"baz"'
assert gn_string('do\\not\\escape') == '"do\\not\\escape"'
assert gn_string('so\\\\very\\"fun\\') == '"so\\\\\\very\\\\\\"fun\\"'
def test_read_gn_args(self):
# Args file doesn't exist.
(args,
hand_edited) = read_gn_args("/baddir/hopefully/nonexistent/args.gn")
assert args is None
assert not hand_edited
# Handwritten empty args file.
filename = mktemp()
with open(filename, "w"):
pass
(args, hand_edited) = read_gn_args(filename)
os.remove(filename)
assert args == []
assert hand_edited
# Handwritten non-empty args file.
expect_args = ['some_number=2', 'another_string="ran/dom#yes"']
filename = mktemp()
with open(filename, "w") as f:
f.write("\n".join(expect_args + ["", "# A comment to be ignored"]))
(args, hand_edited) = read_gn_args(filename)
os.remove(filename)
assert args == expect_args
assert hand_edited
def test_write_gn_args(self):
# Build a nonexistent path; write_gn_args() should call mkdir as needed.
d = mktemp()
filename = os.path.join(d, "args.gn")
assert not os.path.exists(d)
assert not os.path.exists(filename)
# Write some args.
args = ['lalala=42', 'foo_bar_baz="lorem ipsum dolor#amet"']
write_gn_args(filename, args)
# Directory and args file should now be created.
assert os.path.isdir(d)
assert os.path.isfile(filename)
# Validate that the right contents were written.
(check_args, hand_edited) = read_gn_args(filename)
assert check_args == args
assert not hand_edited
# Clean up.
rmtree(d)
if __name__ == '__main__':
run_tests()

View file

@ -1,13 +0,0 @@
#!/usr/bin/env python
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
# Run this script if you are changing //gclient_config.py
# To update the deno_third_party git repo after running this, try the following:
# cd third_party
# find v8 -type f | grep -v "\.git" | \
# xargs -I% git add -f --no-warn-embedded-repo "%"
import third_party
import util
util.enable_ansi_colors()
third_party.run_gclient_sync()

View file

@ -21,9 +21,6 @@ class TestTarget(DenoTestCase):
self.check_exists(bin_file) self.check_exists(bin_file)
run([bin_file], quiet=True) run([bin_file], quiet=True)
def test_libdeno(self):
self._test("libdeno_test")
def test_no_color(self): def test_no_color(self):
t = os.path.join(tests_path, "no_color.js") t = os.path.join(tests_path, "no_color.js")
result = run_output([self.deno_exe, "run", t], result = run_output([self.deno_exe, "run", t],

File diff suppressed because it is too large Load diff

View file

@ -46,36 +46,6 @@ def python_env(env=None, merge_env=None):
return env return env
# This function creates or modifies an environment so that it matches the
# expectations of various google tools (gn, gclient, etc).
def google_env(env=None, merge_env=None, depot_tools_path_=depot_tools_path):
if merge_env is None:
merge_env = {}
# Google tools need the python env too.
env = python_env(env=env, merge_env=merge_env)
# Depot_tools to be in the PATH, before Python.
add_env_path(depot_tools_path_, env=env, prepend=True)
if os.name == "nt": # Windows-only enviroment tweaks.
# We're not using Google's internal infrastructure.
if os.name == "nt" and not "DEPOT_TOOLS_WIN_TOOLCHAIN" in env:
env["DEPOT_TOOLS_WIN_TOOLCHAIN"] = "0"
# The 'setup_toolchain.py' script does a good job finding the Windows
# SDK. Unfortunately, if any of the environment variables below are set
# (as vcvarsall.bat typically would), setup_toolchain absorbs them too,
# adding multiple identical -imsvc<path> items to CFLAGS.
# This small variation has no effect on compiler output, but it
# makes ninja rebuild everything, and causes sccache cache misses.
# TODO(piscisaureus): fix this upstream.
env["INCLUDE"] = ""
env["LIB"] = ""
env["LIBPATH"] = ""
return env
# Run Yarn to install JavaScript dependencies. # Run Yarn to install JavaScript dependencies.
def run_yarn(): def run_yarn():
node_modules_path = os.path.join(third_party_path, "node_modules") node_modules_path = os.path.join(third_party_path, "node_modules")
@ -125,54 +95,6 @@ def run_pip():
rmtree(temp_python_home) rmtree(temp_python_home)
# Run gclient to install V8.
def run_gclient_sync():
# Depot_tools will normally try to self-update, which will fail because
# it's not checked out from it's own git repository; gclient will then try
# to fix things up and not succeed, and and we'll end up with a huge mess.
# To work around this, we rename the `depot_tools` directory to
# `{root_path}/depot_tools_temp` first, and we set DEPOT_TOOLS_UPDATE=0 in
# the environment so depot_tools doesn't attempt to self-update.
# Since depot_tools is listed in .gclient_entries, gclient will install a
# fresh copy in `third_party/depot_tools`.
# If it all works out, we remove the depot_tools_temp directory afterwards.
depot_tools_temp_path = os.path.join(root_path, "depot_tools_temp")
# Rename depot_tools to depot_tools_temp.
try:
os.rename(depot_tools_path, depot_tools_temp_path)
except OSError:
# If renaming failed, and the depot_tools_temp directory already exists,
# assume that it's still there because a prior run_gclient_sync() call
# failed half-way, before we got the chance to remove the temp dir.
# We'll use whatever is in the temp dir that was already there.
# If not, the user can recover by removing the temp directory manually.
if os.path.isdir(depot_tools_temp_path):
pass
else:
raise
args = [
"gclient", "sync", "--reset", "--shallow", "--no-history", "--nohooks"
]
envs = {
"DEPOT_TOOLS_UPDATE": "0",
"GCLIENT_FILE": os.path.join(root_path, "tools", "gclient_config.py")
}
env = google_env(depot_tools_path_=depot_tools_temp_path, merge_env=envs)
run(args, cwd=third_party_path, env=env)
# Delete the depot_tools_temp directory, but not before verifying that
# gclient did indeed install a fresh copy.
# Also check that `{depot_tools_temp_path}/gclient.py` exists, so a typo in
# this script won't accidentally blow out someone's home dir.
if (os.path.isdir(os.path.join(depot_tools_path, ".git"))
and os.path.isfile(os.path.join(depot_tools_path, "gclient.py"))
and os.path.isfile(
os.path.join(depot_tools_temp_path, "gclient.py"))):
rmtree(depot_tools_temp_path)
def get_platform_dir_name(): def get_platform_dir_name():
if sys.platform == "win32": if sys.platform == "win32":
return "win" return "win"
@ -185,87 +107,3 @@ def get_platform_dir_name():
def get_prebuilt_tool_path(tool): def get_prebuilt_tool_path(tool):
return os.path.join(prebuilt_path, get_platform_dir_name(), return os.path.join(prebuilt_path, get_platform_dir_name(),
tool + executable_suffix) tool + executable_suffix)
def get_buildtools_tool_path(tool):
return os.path.join(libdeno_path, "buildtools", get_platform_dir_name(),
tool + executable_suffix)
def download_from_google_storage2(sha1_file, bucket):
download_script = os.path.join(depot_tools_path,
"download_from_google_storage.py")
run([
sys.executable,
download_script,
"--no_auth",
"--bucket=%s" % bucket,
"--sha1_file",
sha1_file,
],
env=google_env())
# Download the given item from Google storage.
def download_from_google_storage(item, bucket, base_dir):
sha1_file = os.path.join(base_dir, get_platform_dir_name(),
item + executable_suffix + ".sha1")
download_from_google_storage2(sha1_file, bucket)
# Download the given item from Chrome Infrastructure Package Deployment.
def download_from_cipd(item, version):
cipd_exe = os.path.join(depot_tools_path, "cipd")
download_dir = os.path.join(libdeno_path, "buildtools",
get_platform_dir_name())
if sys.platform == "win32":
item += "windows-amd64"
elif sys.platform == "darwin":
item += "mac-amd64"
elif sys.platform.startswith("linux"):
item += "linux-amd64"
# Init cipd if necessary.
if not os.path.exists(os.path.join(download_dir, ".cipd")):
run([
cipd_exe,
"init",
download_dir,
"-force",
], env=google_env())
run([
cipd_exe,
"install",
item,
"git_revision:" + version,
"-root",
download_dir,
],
env=google_env())
# Download gn from Google storage.
def download_gn():
download_from_cipd("gn/gn/", "152c5144ceed9592c20f0c8fd55769646077569b")
# Download clang-format from Google storage.
def download_clang_format():
download_from_google_storage("clang-format", "chromium-clang-format",
os.path.join(libdeno_path, "buildtools"))
# Download clang by calling the clang update script.
def download_clang():
update_script = os.path.join(libdeno_path, "v8", "tools", "clang",
"scripts", "update.py")
run([sys.executable, update_script], env=google_env())
def maybe_download_sysroot():
if sys.platform.startswith("linux"):
install_script = os.path.join(libdeno_path, "build", "linux",
"sysroot_scripts", "install-sysroot.py")
run([sys.executable, install_script, "--arch=amd64"], env=google_env())