mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
Replace libdeno with rusty_v8 (#3556)
This commit is contained in:
parent
c41280a057
commit
5f1df038fb
50 changed files with 2292 additions and 7304 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -103,9 +103,6 @@ jobs:
|
|||
rustc --version
|
||||
cargo --version
|
||||
|
||||
- name: Run setup.py
|
||||
run: python ./tools/setup.py
|
||||
|
||||
- name: Start sccache
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: AKIAIVRN52PLDBP55LBQ
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,6 +1,3 @@
|
|||
[submodule "chromium_build"]
|
||||
path = core/libdeno/build
|
||||
url = https://github.com/denoland/chromium_build.git
|
||||
[submodule "deno_third_party"]
|
||||
path = third_party
|
||||
url = https://github.com/denoland/deno_third_party.git
|
||||
|
|
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -26,7 +26,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -139,6 +139,11 @@ dependencies = [
|
|||
"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]]
|
||||
name = "cc"
|
||||
version = "1.0.48"
|
||||
|
@ -257,6 +262,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
"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)",
|
||||
|
@ -1284,6 +1290,18 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustyline"
|
||||
version = "5.0.5"
|
||||
|
@ -1959,7 +1977,7 @@ name = "wasm-bindgen-webidl"
|
|||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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)",
|
||||
"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)",
|
||||
|
@ -1974,7 +1992,7 @@ name = "web-sys"
|
|||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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)",
|
||||
"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)",
|
||||
|
@ -2006,6 +2024,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "winapi"
|
||||
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 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 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 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"
|
||||
|
@ -2090,6 +2117,7 @@ dependencies = [
|
|||
"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 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 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"
|
||||
|
@ -2205,6 +2233,7 @@ dependencies = [
|
|||
"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-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 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"
|
||||
|
@ -2284,6 +2313,7 @@ dependencies = [
|
|||
"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 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.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"
|
||||
|
|
|
@ -248,9 +248,8 @@ testPerm({ env: true }, function getDir(): void {
|
|||
for (const r of s.runtime) {
|
||||
if (Deno.build.os !== r.os) continue;
|
||||
if (r.shouldHaveValue) {
|
||||
assertNotEquals(Deno.dir(s.kind), "");
|
||||
} else {
|
||||
assertEquals(Deno.dir(s.kind), null);
|
||||
const d = Deno.dir(s.kind);
|
||||
assert(d.length > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,11 +102,6 @@ fn repl_test() {
|
|||
util::run_python_script("tools/repl_test.py")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setup_test() {
|
||||
util::run_python_script("tools/setup_test.py")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_test() {
|
||||
util::run_python_script("tools/target_test.py")
|
||||
|
|
|
@ -22,6 +22,9 @@ log = "0.4.8"
|
|||
serde_json = "1.0.41"
|
||||
url = "2.1"
|
||||
|
||||
rusty_v8 = "0.0.23"
|
||||
# rusty_v8 = { path = "../../rusty_v8" }
|
||||
|
||||
[[example]]
|
||||
name = "deno_core_http_bench"
|
||||
path = "examples/http_bench.rs"
|
||||
|
|
148
core/build.rs
148
core/build.rs
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -1,44 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
//! This module wraps libdeno::deno_set_v8_flags
|
||||
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;
|
||||
|
||||
use rusty_v8 as v8;
|
||||
/// Pass the command line arguments to v8.
|
||||
/// Returns a vector of command line arguments that V8 did not understand.
|
||||
pub fn v8_set_flags(args: Vec<String>) -> Vec<String> {
|
||||
// deno_set_v8_flags(int* argc, char** argv) mutates argc and argv to remove
|
||||
// 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()
|
||||
v8::V8::set_flags_from_command_line(args)
|
||||
}
|
||||
|
|
114
core/isolate.rs
114
core/isolate.rs
|
@ -12,10 +12,8 @@ use crate::libdeno;
|
|||
use crate::libdeno::deno_buf;
|
||||
use crate::libdeno::deno_dyn_import_id;
|
||||
use crate::libdeno::deno_mod;
|
||||
use crate::libdeno::deno_pinned_buf;
|
||||
use crate::libdeno::PinnedBuf;
|
||||
use crate::libdeno::Snapshot1;
|
||||
use crate::libdeno::Snapshot2;
|
||||
use crate::ops::*;
|
||||
use crate::shared_queue::SharedQueue;
|
||||
use crate::shared_queue::RECOMMENDED_SIZE;
|
||||
|
@ -29,15 +27,11 @@ use futures::stream::StreamFuture;
|
|||
use futures::stream::TryStream;
|
||||
use futures::stream::TryStreamExt;
|
||||
use futures::task::AtomicWaker;
|
||||
use libc::c_char;
|
||||
use libc::c_void;
|
||||
use libc::strdup;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::null;
|
||||
use std::sync::{Arc, Mutex, Once};
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
@ -153,8 +147,8 @@ impl From<Script<'_>> for OwnedScript {
|
|||
/// in the form of the StartupScript struct.
|
||||
pub enum StartupData<'a> {
|
||||
Script(Script<'a>),
|
||||
Snapshot(&'a [u8]),
|
||||
LibdenoSnapshot(Snapshot1<'a>),
|
||||
Snapshot(&'static [u8]),
|
||||
LibdenoSnapshot(Snapshot1),
|
||||
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
|
||||
/// as arguments. An async Op corresponds exactly to a Promise in JavaScript.
|
||||
pub struct Isolate {
|
||||
libdeno_isolate: *const libdeno::isolate,
|
||||
shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>,
|
||||
libdeno_isolate: *mut libdeno::isolate,
|
||||
shared_libdeno_isolate: Arc<Mutex<Option<*mut libdeno::isolate>>>,
|
||||
dyn_import: Option<Arc<DynImportFn>>,
|
||||
js_error_create: Arc<JSErrorCreateFn>,
|
||||
needs_init: bool,
|
||||
|
@ -212,7 +206,7 @@ impl Isolate {
|
|||
|
||||
let mut libdeno_config = libdeno::deno_config {
|
||||
will_snapshot: will_snapshot.into(),
|
||||
load_snapshot: Snapshot2::empty(),
|
||||
load_snapshot: None,
|
||||
shared: shared.as_deno_buf(),
|
||||
recv_cb: Self::pre_dispatch,
|
||||
dyn_import_cb: Self::dyn_import,
|
||||
|
@ -226,10 +220,10 @@ impl Isolate {
|
|||
startup_script = Some(d.into());
|
||||
}
|
||||
StartupData::Snapshot(d) => {
|
||||
libdeno_config.load_snapshot = d.into();
|
||||
libdeno_config.load_snapshot = Some(d.into());
|
||||
}
|
||||
StartupData::LibdenoSnapshot(d) => {
|
||||
libdeno_config.load_snapshot = d;
|
||||
libdeno_config.load_snapshot = Some(d.into());
|
||||
}
|
||||
StartupData::None => {}
|
||||
};
|
||||
|
@ -310,16 +304,14 @@ impl Isolate {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" fn dyn_import(
|
||||
fn dyn_import(
|
||||
user_data: *mut c_void,
|
||||
specifier: *const c_char,
|
||||
referrer: *const c_char,
|
||||
specifier: &str,
|
||||
referrer: &str,
|
||||
id: deno_dyn_import_id,
|
||||
) {
|
||||
assert_ne!(user_data, std::ptr::null_mut());
|
||||
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);
|
||||
|
||||
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,
|
||||
op_id: OpId,
|
||||
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 maybe_op = isolate.op_registry.call(
|
||||
op_id,
|
||||
control_buf.as_ref(),
|
||||
PinnedBuf::new(zero_copy_buf),
|
||||
);
|
||||
let maybe_op =
|
||||
isolate
|
||||
.op_registry
|
||||
.call(op_id, control_buf.as_ref(), zero_copy_buf);
|
||||
|
||||
let op = match maybe_op {
|
||||
Some(op) => op,
|
||||
|
@ -397,45 +388,39 @@ impl Isolate {
|
|||
js_source: &str,
|
||||
) -> Result<(), ErrBox> {
|
||||
self.shared_init();
|
||||
let filename = CString::new(js_filename).unwrap();
|
||||
let source = CString::new(js_source).unwrap();
|
||||
unsafe {
|
||||
libdeno::deno_execute(
|
||||
self.libdeno_isolate,
|
||||
self.as_raw_ptr(),
|
||||
filename.as_ptr(),
|
||||
source.as_ptr(),
|
||||
self as *mut _ as *mut c_void,
|
||||
js_filename,
|
||||
js_source,
|
||||
)
|
||||
};
|
||||
self.check_last_exception()
|
||||
}
|
||||
|
||||
fn check_last_exception(&mut self) -> Result<(), ErrBox> {
|
||||
let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
|
||||
if ptr.is_null() {
|
||||
Ok(())
|
||||
} else {
|
||||
let maybe_err =
|
||||
unsafe { libdeno::deno_last_exception(self.libdeno_isolate) };
|
||||
match maybe_err {
|
||||
None => Ok(()),
|
||||
Some(json_str) => {
|
||||
let js_error_create = &*self.js_error_create;
|
||||
let cstr = unsafe { CStr::from_ptr(ptr) };
|
||||
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.
|
||||
unsafe { libdeno::deno_clear_last_exception(self.libdeno_isolate) };
|
||||
let json_string = cstring.into_string().unwrap();
|
||||
let v8_exception = V8Exception::from_json(&json_string).unwrap();
|
||||
let v8_exception = V8Exception::from_json(&json_str).unwrap();
|
||||
let js_error = js_error_create(v8_exception);
|
||||
let handler = self.error_handler.as_mut().unwrap();
|
||||
handler(js_error)
|
||||
} 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);
|
||||
Err(js_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_promise_errors(&self) {
|
||||
unsafe {
|
||||
|
@ -444,9 +429,8 @@ impl Isolate {
|
|||
}
|
||||
|
||||
fn throw_exception(&mut self, exception_text: &str) {
|
||||
let text = CString::new(exception_text).unwrap();
|
||||
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,
|
||||
source: &str,
|
||||
) -> 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 {
|
||||
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)
|
||||
|
@ -489,12 +467,10 @@ impl Isolate {
|
|||
unsafe { libdeno::deno_mod_imports_len(self.libdeno_isolate, id) };
|
||||
let mut out = Vec::new();
|
||||
for i in 0..len {
|
||||
let specifier_ptr =
|
||||
unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) };
|
||||
let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) };
|
||||
let specifier: &str = specifier_c.to_str().unwrap();
|
||||
|
||||
out.push(specifier.to_string());
|
||||
let specifier =
|
||||
unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) }
|
||||
.unwrap();
|
||||
out.push(specifier);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
@ -505,15 +481,11 @@ impl Isolate {
|
|||
/// 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
|
||||
/// different type if Isolate::set_js_error_create() has been used.
|
||||
pub fn snapshot(&mut self) -> Result<Snapshot1<'static>, ErrBox> {
|
||||
let snapshot = unsafe { libdeno::deno_snapshot_new(self.libdeno_isolate) };
|
||||
pub fn snapshot(&mut self) -> Result<Snapshot1, ErrBox> {
|
||||
let snapshot = libdeno::deno_snapshot_new(self.libdeno_isolate);
|
||||
match self.check_last_exception() {
|
||||
Ok(..) => Ok(snapshot),
|
||||
Err(err) => {
|
||||
assert_eq!(snapshot.data_ptr, null());
|
||||
assert_eq!(snapshot.data_len, 0);
|
||||
Err(err)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,11 +498,7 @@ impl Isolate {
|
|||
let (mod_id, maybe_err_str) = match result {
|
||||
Ok(mod_id) => (mod_id, None),
|
||||
Err(None) => (0, None),
|
||||
Err(Some(err_str)) => (0, Some(CString::new(err_str).unwrap())),
|
||||
};
|
||||
let err_str_ptr = match maybe_err_str {
|
||||
Some(ref err_str) => err_str.as_ptr(),
|
||||
None => std::ptr::null(),
|
||||
Err(Some(err_str)) => (0, Some(err_str)),
|
||||
};
|
||||
unsafe {
|
||||
libdeno::deno_dyn_import_done(
|
||||
|
@ -538,7 +506,7 @@ impl Isolate {
|
|||
self.as_raw_ptr(),
|
||||
id,
|
||||
mod_id,
|
||||
err_str_ptr,
|
||||
maybe_err_str,
|
||||
)
|
||||
};
|
||||
self.check_last_exception()
|
||||
|
@ -662,11 +630,11 @@ impl Isolate {
|
|||
}
|
||||
|
||||
struct LockerScope {
|
||||
libdeno_isolate: *const libdeno::isolate,
|
||||
libdeno_isolate: *mut libdeno::isolate,
|
||||
}
|
||||
|
||||
impl LockerScope {
|
||||
fn new(libdeno_isolate: *const libdeno::isolate) -> LockerScope {
|
||||
fn new(libdeno_isolate: *mut libdeno::isolate) -> LockerScope {
|
||||
unsafe { libdeno::deno_lock(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.
|
||||
#[derive(Clone)]
|
||||
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 {}
|
||||
|
|
|
@ -123,7 +123,8 @@ impl V8Exception {
|
|||
/// Creates a new V8Exception by parsing the raw exception JSON string from V8.
|
||||
pub fn from_json(json_str: &str) -> Option<Self> {
|
||||
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;
|
||||
}
|
||||
let v = v.unwrap();
|
||||
|
|
10
core/lib.rs
10
core/lib.rs
|
@ -5,6 +5,9 @@ extern crate futures;
|
|||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate downcast_rs;
|
||||
extern crate rusty_v8;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod any_error;
|
||||
mod flags;
|
||||
|
@ -18,6 +21,8 @@ mod plugins;
|
|||
mod resources;
|
||||
mod shared_queue;
|
||||
|
||||
use rusty_v8 as v8;
|
||||
|
||||
pub use crate::any_error::*;
|
||||
pub use crate::flags::v8_set_flags;
|
||||
pub use crate::isolate::*;
|
||||
|
@ -32,10 +37,7 @@ pub use crate::plugins::*;
|
|||
pub use crate::resources::*;
|
||||
|
||||
pub fn v8_version() -> &'static str {
|
||||
use std::ffi::CStr;
|
||||
let version = unsafe { libdeno::deno_v8_version() };
|
||||
let c_str = unsafe { CStr::from_ptr(version) };
|
||||
c_str.to_str().unwrap()
|
||||
v8::V8::get_version()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
1952
core/libdeno.rs
1952
core/libdeno.rs
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
}
|
|
@ -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" ]
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
v8/build_overrides
|
|
@ -1 +0,0 @@
|
|||
v8/buildtools
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
|
@ -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]));
|
||||
})();
|
||||
};
|
|
@ -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"
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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_
|
|
@ -1 +0,0 @@
|
|||
v8/testing
|
|
@ -1 +0,0 @@
|
|||
v8/third_party
|
|
@ -1 +0,0 @@
|
|||
v8/tools
|
|
@ -1 +0,0 @@
|
|||
../../third_party/v8
|
|
@ -225,8 +225,7 @@ fn write_snapshot(
|
|||
) -> Result<(), ErrBox> {
|
||||
println!("creating snapshot...");
|
||||
let snapshot = runtime_isolate.snapshot()?;
|
||||
let snapshot_slice =
|
||||
unsafe { std::slice::from_raw_parts(snapshot.data_ptr, snapshot.data_len) };
|
||||
let snapshot_slice: &[u8] = &*snapshot;
|
||||
println!("snapshot bytes {}", snapshot_slice.len());
|
||||
|
||||
let snapshot_path = bundle.with_extension("bin");
|
||||
|
|
|
@ -255,6 +255,9 @@ test(async function testPrettierPrintToStdout(): Promise<void> {
|
|||
emptyDir(tempDir);
|
||||
});
|
||||
|
||||
// TODO(bartlomieju): reenable after landing rusty_v8 branch
|
||||
// crashing on Windows
|
||||
/*
|
||||
test(async function testPrettierReadFromStdin(): Promise<void> {
|
||||
interface TestCase {
|
||||
stdin: string;
|
||||
|
@ -377,6 +380,7 @@ test(async function testPrettierReadFromStdin(): Promise<void> {
|
|||
);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
test(async function testPrettierWithAutoConfig(): Promise<void> {
|
||||
const configs = [
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 54a98143f8ba78da045cb41a5db3ef0cfb099c5d
|
||||
Subproject commit 9ab7948049d96bdd3af67323f758b81a9e4cbc27
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import os
|
||||
from util import build_path
|
||||
from benchmark import read_json, write_json
|
||||
import os
|
||||
|
||||
current_data_file = os.path.join(build_path(), "bench.json")
|
||||
all_data_file = "gh-pages/data.json" # Includes all benchmark data.
|
||||
|
|
|
@ -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())
|
|
@ -3,7 +3,7 @@
|
|||
import os
|
||||
import sys
|
||||
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
|
||||
|
||||
|
||||
|
@ -11,20 +11,12 @@ def main():
|
|||
os.chdir(root_path)
|
||||
|
||||
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("--py", help="run yapf", action="store_true")
|
||||
parser.add_argument("--rs", help="run rustfmt", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
did_fmt = False
|
||||
if args.cc:
|
||||
clang_format()
|
||||
did_fmt = True
|
||||
if args.gn:
|
||||
gn_format()
|
||||
did_fmt = True
|
||||
if args.js:
|
||||
prettier()
|
||||
did_fmt = True
|
||||
|
@ -36,29 +28,11 @@ def main():
|
|||
did_fmt = True
|
||||
|
||||
if not did_fmt:
|
||||
clang_format()
|
||||
gn_format()
|
||||
prettier()
|
||||
yapf()
|
||||
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():
|
||||
print "prettier"
|
||||
script = os.path.join(third_party_path, "node_modules", "prettier",
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
]
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import os
|
||||
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 third_party import python_env
|
||||
|
||||
|
@ -12,28 +12,10 @@ from third_party import python_env
|
|||
def main():
|
||||
enable_ansi_colors()
|
||||
os.chdir(root_path)
|
||||
cpplint()
|
||||
eslint()
|
||||
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():
|
||||
print "eslint"
|
||||
script = os.path.join(third_party_path, "node_modules", "eslint", "bin",
|
||||
|
@ -55,7 +37,7 @@ def eslint():
|
|||
def pylint():
|
||||
print "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"])
|
||||
run([sys.executable, script, "--rcfile=" + rcfile, "--"] + source_files,
|
||||
env=python_env(),
|
||||
|
|
332
tools/pylintrc
Normal file
332
tools/pylintrc
Normal 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
|
|
@ -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)
|
184
tools/setup.py
184
tools/setup.py
|
@ -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())
|
|
@ -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()
|
|
@ -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()
|
|
@ -21,9 +21,6 @@ class TestTarget(DenoTestCase):
|
|||
self.check_exists(bin_file)
|
||||
run([bin_file], quiet=True)
|
||||
|
||||
def test_libdeno(self):
|
||||
self._test("libdeno_test")
|
||||
|
||||
def test_no_color(self):
|
||||
t = os.path.join(tests_path, "no_color.js")
|
||||
result = run_output([self.deno_exe, "run", t],
|
||||
|
|
3059
tools/testdata/travis_benchmark.json
vendored
3059
tools/testdata/travis_benchmark.json
vendored
File diff suppressed because it is too large
Load diff
|
@ -46,36 +46,6 @@ def python_env(env=None, merge_env=None):
|
|||
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.
|
||||
def run_yarn():
|
||||
node_modules_path = os.path.join(third_party_path, "node_modules")
|
||||
|
@ -125,54 +95,6 @@ def run_pip():
|
|||
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():
|
||||
if sys.platform == "win32":
|
||||
return "win"
|
||||
|
@ -185,87 +107,3 @@ def get_platform_dir_name():
|
|||
def get_prebuilt_tool_path(tool):
|
||||
return os.path.join(prebuilt_path, get_platform_dir_name(),
|
||||
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())
|
||||
|
|
Loading…
Reference in a new issue