Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core) deno_core::extension! macro to simplify extension registration #18210

Merged
merged 50 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
1e33059
WIP: deno_core::ops!
mmastrac Mar 14, 2023
dd7f871
WIP extension
mmastrac Mar 15, 2023
782225d
WIP extension: napi
mmastrac Mar 15, 2023
ea04949
WIP: deno_websocket extension!
mmastrac Mar 15, 2023
ad224fb
WIP: extension! for deno_webidl and core
mmastrac Mar 15, 2023
910aaa6
Move state into the macro (though it could still live externally)
mmastrac Mar 15, 2023
e543288
Call the state initialization closure using the config fields
mmastrac Mar 15, 2023
f82ff1e
extension! for deno_bench, remove requirement for Default for now
mmastrac Mar 15, 2023
9b3180a
extension! for deno_console and deno_url
mmastrac Mar 15, 2023
0ed5c8c
extension! for deno_cli, deno_test, deno_tsc
mmastrac Mar 15, 2023
c55fda0
extension! for deno_broadcast_channel (required making Config object …
mmastrac Mar 15, 2023
702cfda
extension! for cache, crypto, ffi, webgpu
mmastrac Mar 15, 2023
df0112b
extension! deno_fetch, deno_flash, deno_bench and some internal exten…
mmastrac Mar 16, 2023
c846913
Move ops out of function
mmastrac Mar 16, 2023
81dc32a
Refactor extension! macro slightly
mmastrac Mar 16, 2023
d78cfb8
extension! for cli/build
mmastrac Mar 16, 2023
07044e7
Restore old init_ops/init_ops_and_esm names
mmastrac Mar 16, 2023
2f90862
extension! for webgpu and webgpu_surface
mmastrac Mar 16, 2023
5076f04
ops -> ops_fn
mmastrac Mar 16, 2023
c72730e
extension! deno_fs
mmastrac Mar 16, 2023
4c6f23d
extension! deno_io and deno_http
mmastrac Mar 16, 2023
34150ac
extension! for deno_net, deno_node, deno_load_loading
mmastrac Mar 16, 2023
a563d9e
Update runtime/build and cli/build
mmastrac Mar 16, 2023
37c43fa
extension! deno_tls, deno_web, runtime
mmastrac Mar 16, 2023
fa0eb50
extension! for various deno_* extensions
mmastrac Mar 16, 2023
c7b55b3
Rework extension! to use a struct
mmastrac Mar 16, 2023
0ed4b23
Update tests to use extension! macro
mmastrac Mar 16, 2023
38a0666
Merge branch 'main' into ops_extension
mmastrac Mar 16, 2023
7eb8eb5
Restore extensions after merge conflict
mmastrac Mar 16, 2023
d7bc1e5
Fold ops! into extension!
mmastrac Mar 16, 2023
80b04ca
Trailing comma
mmastrac Mar 16, 2023
4a1ad1d
Fix typo (moved code)
mmastrac Mar 16, 2023
661566d
Add customizer as a 'last resort' and implement extension! for cli
mmastrac Mar 16, 2023
6b39e21
Remove redundant clones
mmastrac Mar 16, 2023
993aa0f
Add deps for deno_fs
mmastrac Mar 16, 2023
6ef38e5
[ci]
mmastrac Mar 16, 2023
bbe8890
Merge branch 'main' into ops_extension
bartlomieju Mar 16, 2023
044c1b7
Add docs for extension!
mmastrac Mar 16, 2023
c16b4ea
Merge branch 'ops_extension' of https://github.com/mmastrac/deno into…
mmastrac Mar 16, 2023
dca0405
One last merge fix
mmastrac Mar 16, 2023
bb7a5fc
Missed deps for deno_websocket
mmastrac Mar 17, 2023
c4fb235
cargo fmt
mmastrac Mar 17, 2023
9983941
Merge branch 'main' into ops_extension
mmastrac Mar 17, 2023
f300f6a
Restore missing comment
mmastrac Mar 17, 2023
9a90368
Slighly cleaner approach for runtime_main extension
mmastrac Mar 17, 2023
3e03787
Construct vector in-place rather than using push
mmastrac Mar 17, 2023
ff419ae
Merge branch 'main' into ops_extension
mmastrac Mar 17, 2023
b009d64
Construct vec! in-place and avoid push
mmastrac Mar 17, 2023
93a9367
Merge branch 'main' of https://github.com/denoland/deno into ops_exte…
mmastrac Mar 17, 2023
0727418
Missed #[inline] on two functions
mmastrac Mar 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions bench_util/benches/op_baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ use deno_bench_util::bencher::Bencher;
use deno_core::op;
use deno_core::Extension;

deno_core::ops!(deno_ops, [op_pi_json, op_pi_async, op_nop,]);
mmastrac marked this conversation as resolved.
Show resolved Hide resolved

deno_core::extension!(bench_setup, ops_fn = deno_ops,);

fn setup() -> Vec<Extension> {
vec![Extension::builder("bench_setup")
.ops(vec![
op_pi_json::decl(),
op_pi_async::decl(),
op_nop::decl(),
])
.build()]
vec![bench_setup::init_ops()]
}

#[op]
Expand Down
257 changes: 136 additions & 121 deletions cli/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

use std::cell::RefCell;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;

use deno_core::include_js_files;
use deno_core::snapshot_util::*;
Expand Down Expand Up @@ -35,6 +37,110 @@ mod ts {
specifier: String,
}

#[op]
fn op_build_info(state: &mut OpState) -> Value {
let build_specifier = "asset:https:///bootstrap.ts";

let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES
.iter()
.map(|s| s.name)
.collect::<Vec<&str>>();
let build_libs = state.borrow::<Vec<&str>>();
json!({
"buildSpecifier": build_specifier,
"libs": build_libs,
"nodeBuiltInModuleNames": node_built_in_module_names,
})
}

#[op]
fn op_is_node_file() -> bool {
false
}

#[op]
fn op_script_version(
_state: &mut OpState,
_args: Value,
) -> Result<Option<String>, AnyError> {
Ok(Some("1".to_string()))
}

#[op]
// using the same op that is used in `tsc.rs` for loading modules and reading
// files, but a slightly different implementation at build time.
fn op_load(state: &mut OpState, args: LoadArgs) -> Result<Value, AnyError> {
let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>();
let path_dts = state.borrow::<PathBuf>();
let re_asset =
Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex");
let build_specifier = "asset:https:///bootstrap.ts";

// we need a basic file to send to tsc to warm it up.
if args.specifier == build_specifier {
Ok(json!({
"data": r#"Deno.writeTextFile("hello.txt", "hello deno!");"#,
"version": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
// specifiers come across as `asset:https:///lib.{lib_name}.d.ts` and we need to
// parse out just the name so we can lookup the asset.
} else if let Some(caps) = re_asset.captures(&args.specifier) {
if let Some(lib) = caps.get(1).map(|m| m.as_str()) {
// if it comes from an op crate, we were supplied with the path to the
// file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
PathBuf::from(op_crate_lib).canonicalize()?
// otherwise we are will generate the path ourself
mmastrac marked this conversation as resolved.
Show resolved Hide resolved
} else {
path_dts.join(format!("lib.{lib}.d.ts"))
};
let data = std::fs::read_to_string(path)?;
Ok(json!({
"data": data,
"version": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
}

deno_core::ops!(
deno_ops,
[op_build_info, op_is_node_file, op_load, op_script_version,]
);

deno_core::extension!(deno_tsc,
ops_fn = deno_ops,
js = [
dir "tsc",
"00_typescript.js",
"99_main_compiler.js",
],
config = {
op_crate_libs: HashMap<&'static str, PathBuf>,
build_libs: Vec<&'static str>,
path_dts: PathBuf,
},
state = |state, op_crate_libs, build_libs, path_dts| {
state.put(op_crate_libs.clone());
state.put(build_libs.clone());
state.put(path_dts.clone());
},
);

pub fn create_compiler_snapshot(snapshot_path: PathBuf, cwd: &Path) {
// libs that are being provided by op crates.
let mut op_crate_libs = HashMap::new();
Expand Down Expand Up @@ -161,110 +267,15 @@ mod ts {
)
.unwrap();

#[op]
fn op_build_info(state: &mut OpState) -> Value {
let build_specifier = "asset:https:///bootstrap.ts";

let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES
.iter()
.map(|s| s.name)
.collect::<Vec<&str>>();
let build_libs = state.borrow::<Vec<&str>>();
json!({
"buildSpecifier": build_specifier,
"libs": build_libs,
"nodeBuiltInModuleNames": node_built_in_module_names,
})
}

#[op]
fn op_is_node_file() -> bool {
false
}

#[op]
fn op_script_version(
_state: &mut OpState,
_args: Value,
) -> Result<Option<String>, AnyError> {
Ok(Some("1".to_string()))
}

#[op]
// using the same op that is used in `tsc.rs` for loading modules and reading
// files, but a slightly different implementation at build time.
fn op_load(state: &mut OpState, args: LoadArgs) -> Result<Value, AnyError> {
let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>();
let path_dts = state.borrow::<PathBuf>();
let re_asset =
Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex");
let build_specifier = "asset:https:///bootstrap.ts";

// we need a basic file to send to tsc to warm it up.
if args.specifier == build_specifier {
Ok(json!({
"data": r#"Deno.writeTextFile("hello.txt", "hello deno!");"#,
"version": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
// specifiers come across as `asset:https:///lib.{lib_name}.d.ts` and we need to
// parse out just the name so we can lookup the asset.
} else if let Some(caps) = re_asset.captures(&args.specifier) {
if let Some(lib) = caps.get(1).map(|m| m.as_str()) {
// if it comes from an op crate, we were supplied with the path to the
// file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
PathBuf::from(op_crate_lib).canonicalize()?
// otherwise we are will generate the path ourself
} else {
path_dts.join(format!("lib.{lib}.d.ts"))
};
let data = std::fs::read_to_string(path)?;
Ok(json!({
"data": data,
"version": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
}

let tsc_extension = Extension::builder("deno_tsc")
.ops(vec![
op_build_info::decl(),
op_is_node_file::decl(),
op_load::decl(),
op_script_version::decl(),
])
.js(include_js_files! {
dir "tsc",
"00_typescript.js",
"99_main_compiler.js",
})
.state(move |state| {
state.put(op_crate_libs.clone());
state.put(build_libs.clone());
state.put(path_dts.clone());
})
.build();

create_snapshot(CreateSnapshotOptions {
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
snapshot_path,
startup_snapshot: None,
extensions: vec![tsc_extension],
extensions: vec![deno_tsc::init_ops_and_esm(
op_crate_libs,
build_libs,
path_dts,
)],

// NOTE(bartlomieju): Compressing the TSC snapshot in debug build took
// ~45s on M1 MacBook Pro; without compression it took ~1s.
Expand Down Expand Up @@ -311,36 +322,40 @@ fn create_cli_snapshot(snapshot_path: PathBuf) {
// NOTE(bartlomieju): ordering is important here, keep it in sync with
// `runtime/worker.rs`, `runtime/web_worker.rs` and `runtime/build.rs`!
let mut extensions: Vec<Extension> = vec![
deno_webidl::init(),
deno_console::init(),
deno_url::init_ops(),
deno_web::init_ops::<PermissionsContainer>(
deno_webidl::deno_webidl::init_ops(),
deno_console::deno_console::init_ops(),
deno_url::deno_url::init_ops(),
deno_web::deno_web::init_ops::<PermissionsContainer>(
deno_web::BlobStore::default(),
Default::default(),
),
deno_fetch::init_ops::<PermissionsContainer>(Default::default()),
deno_cache::init_ops::<SqliteBackedCache>(None),
deno_websocket::init_ops::<PermissionsContainer>("".to_owned(), None, None),
deno_webstorage::init_ops(None),
deno_crypto::init_ops(None),
deno_webgpu::init_ops(false),
deno_broadcast_channel::init_ops(
deno_fetch::deno_fetch::init_ops::<PermissionsContainer>(Default::default()),
deno_cache::deno_cache::init_ops::<SqliteBackedCache>(None),
deno_websocket::deno_websocket::init_ops::<PermissionsContainer>(
"".to_owned(),
None,
None,
),
deno_webstorage::deno_webstorage::init_ops(None),
deno_crypto::deno_crypto::init_ops(None),
deno_webgpu::deno_webgpu::init_ops(false),
deno_broadcast_channel::deno_broadcast_channel::init_ops(
deno_broadcast_channel::InMemoryBroadcastChannel::default(),
false, // No --unstable.
),
deno_ffi::init_ops::<PermissionsContainer>(false),
deno_net::init_ops::<PermissionsContainer>(
deno_ffi::deno_ffi::init_ops::<PermissionsContainer>(false),
deno_net::deno_net::init_ops::<PermissionsContainer>(
None, false, // No --unstable.
None,
),
deno_tls::init_ops(),
deno_napi::init_ops::<PermissionsContainer>(),
deno_http::init_ops(),
deno_io::init_ops(Default::default()),
deno_fs::init_ops::<PermissionsContainer>(false),
deno_flash::init_ops::<PermissionsContainer>(false), // No --unstable
deno_node::init_ops::<PermissionsContainer>(None), // No --unstable.
deno_node::init_polyfill_ops(),
deno_tls::deno_tls::init_ops(),
deno_napi::deno_napi::init_ops::<PermissionsContainer>(),
deno_http::deno_http::init_ops(),
deno_io::deno_io::init_ops(Rc::new(RefCell::new(Some(Default::default())))),
deno_fs::deno_fs::init_ops::<PermissionsContainer>(false),
deno_flash::deno_flash::init_ops::<PermissionsContainer>(false), // No --unstable
deno_node::deno_node_loading::init_ops::<PermissionsContainer>(None), // No --unstable.
deno_node::deno_node::init_ops(),
];

let mut esm_files = include_js_files!(
Expand Down
6 changes: 5 additions & 1 deletion cli/lsp/testing/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ async fn test_specifier(
&ps,
specifier.clone(),
PermissionsContainer::new(permissions),
vec![ops::testing::init(sender, fail_fast_tracker, filter)],
vec![ops::testing::deno_test::init_ops(
sender,
fail_fast_tracker,
filter,
)],
Stdio {
stdin: StdioPipe::Inherit,
stdout,
Expand Down
47 changes: 26 additions & 21 deletions cli/lsp/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::url::Url;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
Expand Down Expand Up @@ -2819,31 +2818,37 @@ fn op_script_version(
/// server.
fn js_runtime(performance: Arc<Performance>) -> JsRuntime {
JsRuntime::new(RuntimeOptions {
extensions: vec![init_extension(performance)],
extensions: vec![deno_tsc::init_ops(performance)],
startup_snapshot: Some(tsc::compiler_snapshot()),
..Default::default()
})
}

fn init_extension(performance: Arc<Performance>) -> Extension {
Extension::builder("deno_tsc")
.ops(vec![
op_is_cancelled::decl(),
op_is_node_file::decl(),
op_load::decl(),
op_resolve::decl(),
op_respond::decl(),
op_script_names::decl(),
op_script_version::decl(),
])
.state(move |state| {
state.put(State::new(
Arc::new(StateSnapshot::default()),
performance.clone(),
));
})
.build()
}
deno_core::ops!(
deno_ops,
[
op_is_cancelled,
op_is_node_file,
op_load,
op_resolve,
op_respond,
op_script_names,
op_script_version,
]
);

deno_core::extension!(deno_tsc,
ops_fn = deno_ops,
config = {
performance: Arc<Performance>
},
state = |state, performance| {
state.put(State::new(
Arc::new(StateSnapshot::default()),
performance.clone(),
));
},
);

/// Instruct a language server runtime to start the language server and provide
/// it with a minimal bootstrap configuration.
Expand Down
Loading