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

refactor: internal ops are under Deno.core.coreOps #523

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
27 changes: 25 additions & 2 deletions core/01_core.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@
TypeError,
} = window.__bootstrap.primordials;
const {
coreOps,
ops,
getPromise,
hasPromise,
promiseIdSymbol,
} = window.Deno.core;
// TODO(bartlomieju): because op bindings are generated on each startup
// we can't remove it right now. See https://github.com/denoland/deno_core/issues/521.
// Delete `Deno.core.coreOps` immediately. These bindings shouldn't be accessible
// outside deno_core.
delete window.Deno.core.coreOps;

let unhandledPromiseRejectionHandler = () => false;
let timerDepth = 0;
Expand Down Expand Up @@ -302,7 +308,7 @@
op_read_sync: readSync,
op_write_sync: writeSync,
op_shutdown: shutdown,
} = ensureFastOps(true);
} = coreOps;

const callSiteRetBuf = new Uint32Array(2);
const callSiteRetBufU8 = new Uint8Array(callSiteRetBuf.buffer);
Expand Down Expand Up @@ -421,6 +427,14 @@
op_set_wasm_streaming_callback,
op_str_byte_length,
op_timer_cancel,
op_void_async,
op_void_async_deferred,
op_set_format_exception_callback,
op_format_file_name,
op_apply_source_map_filename,
op_wasm_streaming_feed,
op_wasm_streaming_set_url,
op_apply_source_map,
op_timer_queue,
op_timer_ref,
op_timer_unref,
Expand Down Expand Up @@ -454,7 +468,7 @@
op_is_typed_array,
op_is_weak_map,
op_is_weak_set,
} = ensureFastOps();
} = coreOps;

function propWritable(value) {
return {
Expand Down Expand Up @@ -617,6 +631,8 @@
isRegExp: (value) => op_is_reg_exp(value),
isSet: (value) => op_is_set(value),
isSetIterator: (value) => op_is_set_iterator(value),
wasmStreamingFeed: (rid, bytes) => op_wasm_streaming_feed(rid, bytes),
wasmStreamingSetUrl: (rid, url) => op_wasm_streaming_set_url(rid, url),
isSharedArrayBuffer: (value) => op_is_shared_array_buffer(value),
isStringObject: (value) => op_is_string_object(value),
isSymbolObject: (value) => op_is_symbol_object(value),
Expand All @@ -632,7 +648,14 @@
destructureError: (error) => op_destructure_error(error),
opNames: () => op_op_names(),
eventLoopHasMoreWork: () => op_event_loop_has_more_work(),
setFormatExceptionCallback: (cb) => op_set_format_exception_callback(cb),
applySourceMapFilename: () => op_apply_source_map_filename(),
applySourceMap: (fileName, lineNumber, columnNumber, retBuf) =>
op_apply_source_map(fileName, lineNumber, columnNumber, retBuf),
formatFileName: (fileName) => op_format_file_name(fileName),
byteLength: (str) => op_str_byte_length(str),
opVoidAsync: () => op_void_async(),
opVoidAsyncDeferred: () => op_void_async_deferred(),
setHandledPromiseRejectionHandler: (handler) =>
op_set_handled_promise_rejection_handler(handler),
setUnhandledPromiseRejectionHandler: (handler) =>
Expand Down
7 changes: 3 additions & 4 deletions core/02_error.js
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should probably be rolled into 01_core.js to avoid having to expose these APIs to Deno.core

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

((window) => {
const core = Deno.core;
const ops = core.ops;
const {
Error,
ObjectDefineProperties,
Expand All @@ -22,7 +21,7 @@
fileName.startsWith("data:") &&
fileName.length > DATA_URL_ABBREV_THRESHOLD
) {
return ops.op_format_file_name(fileName);
return core.formatFileName(fileName);
}
return fileName;
}
Expand Down Expand Up @@ -151,7 +150,7 @@
callSite.fileName !== null && callSite.lineNumber !== null &&
callSite.columnNumber !== null
) {
res = ops.op_apply_source_map(
res = core.applySourceMap(
callSite.fileName,
callSite.lineNumber,
callSite.columnNumber,
Expand All @@ -163,7 +162,7 @@
callSite.columnNumber = applySourceMapRetBuf[1];
}
if (res >= 2) {
callSite.fileName = ops.op_apply_source_map_filename();
callSite.fileName = core.applySourceMapFilename();
}
ArrayPrototypePush(error.__callSiteEvals, callSite);
stack += `\n at ${formatCallSiteEval(callSite)}`;
Expand Down
59 changes: 56 additions & 3 deletions core/runtime/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ where
.get(scope, key.into())
.unwrap_or_else(|| panic!("{path} exists"))
.try_into()
.unwrap_or_else(|_| panic!("unable to convert"))
.unwrap_or_else(|_| panic!("Unable to convert {path} to desired type"))
Comment on lines 145 to +148
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This funciton should probably be a macro and accept a token tree to print out the desired type nicely

}

pub mod v8_static_strings {
Expand All @@ -140,6 +140,7 @@ pub mod v8_static_strings {

pub static DENO: &[u8] = b"Deno";
pub static CORE: &[u8] = b"core";
pub static CORE_OPS: &[u8] = b"coreOps";
pub static OPS: &[u8] = b"ops";
pub static URL: &[u8] = b"url";
pub static MAIN: &[u8] = b"main";
Expand Down Expand Up @@ -196,6 +197,20 @@ pub(crate) fn initialize_deno_core_namespace<'s>(
.set(scope, deno_core_ops_key.into(), deno_core_ops_obj.into())
.unwrap();

// Set up `Deno.core.coreOps` object
let deno_core_core_ops_obj = v8::Object::new(scope);
let deno_core_core_ops_key =
v8::String::new_external_onebyte_static(scope, v8_static_strings::CORE_OPS)
.unwrap();

deno_core_obj
.set(
scope,
deno_core_core_ops_key.into(),
deno_core_core_ops_obj.into(),
)
.unwrap();

// If we're initializing fresh context set up the console
if init_mode == InitMode::New {
// Bind `call_console` to Deno.core.callConsole
Expand Down Expand Up @@ -241,10 +256,13 @@ pub(crate) fn initialize_primordials_and_infra(
}

/// Set up JavaScript bindings for ops.
pub(crate) fn initialize_deno_core_ops_bindings<'s>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function needs to be split into two separate functions - one for "core" ops and one for "ext" ops.

pub(crate) fn initialize_ops_bindings<'s>(
scope: &mut v8::HandleScope<'s>,
context: v8::Local<'s, v8::Context>,
op_ctxs: &[OpCtx],
init_mode: InitMode,
// TODO(bartlomieju): this is really hacky solution
last_deno_core_op_id: usize,
) {
let global = context.global(scope);

Expand All @@ -260,6 +278,7 @@ pub(crate) fn initialize_deno_core_ops_bindings<'s>(
v8_static_strings::OPS,
"Deno.core.ops",
);

let set_up_async_stub_fn: v8::Local<v8::Function> = get(
scope,
deno_core_obj,
Expand All @@ -268,7 +287,41 @@ pub(crate) fn initialize_deno_core_ops_bindings<'s>(
);

let undefined = v8::undefined(scope);
for op_ctx in op_ctxs {

let deno_core_op_ctxs = &op_ctxs[..last_deno_core_op_id];
let ext_op_ctxs = &op_ctxs[last_deno_core_op_id..];
littledivy marked this conversation as resolved.
Show resolved Hide resolved

// TODO(bartlomieju): hoist this to a separate function
if init_mode == InitMode::New {
let deno_core_core_ops_obj: v8::Local<v8::Object> = get(
scope,
deno_core_obj,
v8_static_strings::CORE_OPS,
"Deno.core.coreOps",
);
for op_ctx in deno_core_op_ctxs {
let mut op_fn = op_ctx_function(scope, op_ctx);
let key = v8::String::new_external_onebyte_static(
scope,
op_ctx.decl.name.as_bytes(),
)
.unwrap();

// For async ops we need to set them up, by calling `Deno.core.setUpAsyncStub` -
// this call will generate an optimized function that binds to the provided
// op, while keeping track of promises and error remapping.
if op_ctx.decl.is_async {
let result = set_up_async_stub_fn
.call(scope, undefined.into(), &[key.into(), op_fn.into()])
.unwrap();
op_fn = result.try_into().unwrap()
}

deno_core_core_ops_obj.set(scope, key.into(), op_fn.into());
}
}

for op_ctx in ext_op_ctxs {
let mut op_fn = op_ctx_function(scope, op_ctx);
let key = v8_static_strings::new(scope, op_ctx.decl.name.as_bytes());

Expand Down
7 changes: 6 additions & 1 deletion core/runtime/jsruntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,10 +730,15 @@ impl JsRuntime {
// If we're creating a new runtime or there are new ops to register
// set up JavaScript bindings for them.
if init_mode.needs_ops_bindings() {
bindings::initialize_deno_core_ops_bindings(
// TODO(bartlomieju): this is a really hacky solution and relies
// implicitly on how `extension_set::create_op_ctxs` works.
let last_deno_core_op_id = crate::ops_builtin::BUILTIN_OPS.len() - 1;
bindings::initialize_ops_bindings(
scope,
context,
&context_state.op_ctxs,
init_mode,
last_deno_core_op_id,
);
}

Expand Down
2 changes: 1 addition & 1 deletion core/runtime/tests/jsrealm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn test_set_format_exception_callback_realms() {
"",
format!(
r#"
Deno.core.ops.op_set_format_exception_callback((error) => {{
Deno.core.setFormatExceptionCallback((error) => {{
return `{realm_name} / ${{error}}`;
}});
"#
Expand Down
10 changes: 5 additions & 5 deletions core/runtime/tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,8 @@ async fn wasm_streaming_op_invocation_in_import() {
runtime.execute_script_static("setup.js",
r#"
Deno.core.setWasmStreamingCallback((source, rid) => {
Deno.core.ops.op_wasm_streaming_set_url(rid, "file:///foo.wasm");
Deno.core.ops.op_wasm_streaming_feed(rid, source);
Deno.core.wasmStreamingSetUrl(rid, "file:///foo.wasm");
Deno.core.wasmStreamingFeed(rid, source);
Deno.core.close(rid);
});
"#).unwrap();
Expand Down Expand Up @@ -826,7 +826,7 @@ async fn test_promise_rejection_handler_generic(
function throwError() {
throw new Error("boom");
}
const { op_void_async, op_void_async_deferred } = Deno.core.ensureFastOps();
const { opVoidAsync, opVoidAsyncDeferred } = Deno.core;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to verify it, but I believe deno relies on these ops as well

if (test != "no_handler") {
Deno.core.setUnhandledPromiseRejectionHandler((promise, rejection) => {
if (test.startsWith("exception_")) {
Expand All @@ -841,9 +841,9 @@ async fn test_promise_rejection_handler_generic(
}
if (test != "no_reject") {
if (test.startsWith("async_op_eager_")) {
op_void_async().then(() => { Deno.core.ops.op_breakpoint(); throw new Error("fail") });
opVoidAsync().then(() => { Deno.core.ops.op_breakpoint(); throw new Error("fail") });
} else if (test.startsWith("async_op_deferred_")) {
op_void_async_deferred().then(() => { Deno.core.ops.op_breakpoint(); throw new Error("fail") });
opVoidAsyncDeferred().then(() => { Deno.core.ops.op_breakpoint(); throw new Error("fail") });
} else if (test.startsWith("throw_")) {
Deno.core.ops.op_breakpoint();
throw new Error("fail");
Expand Down
4 changes: 2 additions & 2 deletions core/runtime/tests/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,8 @@ await import('./mod.js');
Url::parse("http://x/mod.js").unwrap(),
ascii_str!(
r#"
const { op_void_async_deferred } = Deno.core.ensureFastOps();
await op_void_async_deferred();
const { opVoidAsyncDeferred } = Deno.core;
await opVoidAsyncDeferred();
"#
),
),
Expand Down
2 changes: 1 addition & 1 deletion core/runtime/tests/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn test_snapshot_callbacks() {
Deno.core.setMacrotaskCallback(() => {
return true;
});
Deno.core.ops.op_set_format_exception_callback(()=> {
Deno.core.setFormatExceptionCallback(()=> {
return null;
})
Deno.core.setUnhandledPromiseRejectionHandler(() => {
Expand Down
Loading