mirror of
https://github.com/denoland/deno.git
synced 2024-10-29 08:58:01 -04:00
chore(core): Refactor runtime and split out tests (#19491)
This is a quick first refactoring to split the tests out of runtime and move runtime-related code to a top-level runtime module. There will be a followup to refactor imports a bit, but this is the major change that will most likely conflict with other work and I want to merge it early.
This commit is contained in:
parent
fd9d6baea3
commit
ec8e9d4f5b
18 changed files with 2616 additions and 2581 deletions
|
@ -9,8 +9,7 @@ use std::fmt::Formatter;
|
|||
|
||||
use anyhow::Error;
|
||||
|
||||
use crate::realm::JsRealm;
|
||||
use crate::runtime::GetErrorClassFn;
|
||||
use crate::runtime::JsRealm;
|
||||
use crate::runtime::JsRuntime;
|
||||
use crate::source_map::apply_source_map;
|
||||
use crate::source_map::get_source_line;
|
||||
|
@ -20,6 +19,9 @@ use crate::url::Url;
|
|||
// TODO(ry) Deprecate AnyError and encourage deno_core::anyhow::Error instead.
|
||||
pub type AnyError = anyhow::Error;
|
||||
|
||||
pub type JsErrorCreateFn = dyn Fn(JsError) -> Error;
|
||||
pub type GetErrorClassFn = &'static dyn for<'e> Fn(&'e Error) -> &'static str;
|
||||
|
||||
/// Creates a new error with a caller-specified error class name and message.
|
||||
pub fn custom_error(
|
||||
class: &'static str,
|
||||
|
@ -643,6 +645,56 @@ fn abbrev_file_name(file_name: &str) -> Option<String> {
|
|||
Some(format!("{}:{},{}......{}", url.scheme(), head, start, end))
|
||||
}
|
||||
|
||||
pub(crate) fn exception_to_err_result<T>(
|
||||
scope: &mut v8::HandleScope,
|
||||
exception: v8::Local<v8::Value>,
|
||||
in_promise: bool,
|
||||
) -> Result<T, Error> {
|
||||
let state_rc = JsRuntime::state_from(scope);
|
||||
|
||||
let was_terminating_execution = scope.is_execution_terminating();
|
||||
// Disable running microtasks for a moment. When upgrading to V8 v11.4
|
||||
// we discovered that canceling termination here will cause the queued
|
||||
// microtasks to run which breaks some tests.
|
||||
scope.set_microtasks_policy(v8::MicrotasksPolicy::Explicit);
|
||||
// If TerminateExecution was called, cancel isolate termination so that the
|
||||
// exception can be created. Note that `scope.is_execution_terminating()` may
|
||||
// have returned false if TerminateExecution was indeed called but there was
|
||||
// no JS to execute after the call.
|
||||
scope.cancel_terminate_execution();
|
||||
let mut exception = exception;
|
||||
{
|
||||
// If termination is the result of a `op_dispatch_exception` call, we want
|
||||
// to use the exception that was passed to it rather than the exception that
|
||||
// was passed to this function.
|
||||
let state = state_rc.borrow();
|
||||
exception = if let Some(exception) = &state.dispatched_exception {
|
||||
v8::Local::new(scope, exception.clone())
|
||||
} else if was_terminating_execution && exception.is_null_or_undefined() {
|
||||
let message = v8::String::new(scope, "execution terminated").unwrap();
|
||||
v8::Exception::error(scope, message)
|
||||
} else {
|
||||
exception
|
||||
};
|
||||
}
|
||||
|
||||
let mut js_error = JsError::from_v8_exception(scope, exception);
|
||||
if in_promise {
|
||||
js_error.exception_message = format!(
|
||||
"Uncaught (in promise) {}",
|
||||
js_error.exception_message.trim_start_matches("Uncaught ")
|
||||
);
|
||||
}
|
||||
|
||||
if was_terminating_execution {
|
||||
// Resume exception termination.
|
||||
scope.terminate_execution();
|
||||
}
|
||||
scope.set_microtasks_policy(v8::MicrotasksPolicy::Auto);
|
||||
|
||||
Err(js_error.into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
32
core/lib.rs
32
core/lib.rs
|
@ -1,7 +1,6 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
mod async_cancel;
|
||||
mod async_cell;
|
||||
mod bindings;
|
||||
pub mod error;
|
||||
mod error_codes;
|
||||
mod extensions;
|
||||
|
@ -18,10 +17,8 @@ mod ops_builtin;
|
|||
mod ops_builtin_v8;
|
||||
mod ops_metrics;
|
||||
mod path;
|
||||
mod realm;
|
||||
mod resources;
|
||||
mod runtime;
|
||||
pub mod snapshot_util;
|
||||
mod source_map;
|
||||
pub mod task;
|
||||
mod task_queue;
|
||||
|
@ -57,6 +54,8 @@ pub use crate::async_cell::AsyncRefCell;
|
|||
pub use crate::async_cell::AsyncRefFuture;
|
||||
pub use crate::async_cell::RcLike;
|
||||
pub use crate::async_cell::RcRef;
|
||||
pub use crate::error::GetErrorClassFn;
|
||||
pub use crate::error::JsErrorCreateFn;
|
||||
pub use crate::extensions::Extension;
|
||||
pub use crate::extensions::ExtensionBuilder;
|
||||
pub use crate::extensions::ExtensionFileSource;
|
||||
|
@ -103,15 +102,13 @@ pub use crate::ops_builtin::op_void_async;
|
|||
pub use crate::ops_builtin::op_void_sync;
|
||||
pub use crate::ops_metrics::OpsTracker;
|
||||
pub use crate::path::strip_unc_prefix;
|
||||
pub use crate::realm::JsRealm;
|
||||
pub use crate::resources::AsyncResult;
|
||||
pub use crate::resources::Resource;
|
||||
pub use crate::resources::ResourceId;
|
||||
pub use crate::resources::ResourceTable;
|
||||
pub use crate::runtime::CompiledWasmModuleStore;
|
||||
pub use crate::runtime::CrossIsolateStore;
|
||||
pub use crate::runtime::GetErrorClassFn;
|
||||
pub use crate::runtime::JsErrorCreateFn;
|
||||
pub use crate::runtime::JsRealm;
|
||||
pub use crate::runtime::JsRuntime;
|
||||
pub use crate::runtime::JsRuntimeForSnapshot;
|
||||
pub use crate::runtime::RuntimeOptions;
|
||||
|
@ -130,21 +127,30 @@ pub fn v8_version() -> &'static str {
|
|||
/// An internal module re-exporting functions used by the #[op] (`deno_ops`) macro
|
||||
#[doc(hidden)]
|
||||
pub mod _ops {
|
||||
pub use super::bindings::throw_type_error;
|
||||
pub use super::error_codes::get_error_code;
|
||||
pub use super::ops::to_op_result;
|
||||
pub use super::ops::OpCtx;
|
||||
pub use super::ops::OpResult;
|
||||
pub use super::runtime::map_async_op1;
|
||||
pub use super::runtime::map_async_op2;
|
||||
pub use super::runtime::map_async_op3;
|
||||
pub use super::runtime::map_async_op4;
|
||||
pub use super::runtime::queue_async_op;
|
||||
pub use super::runtime::queue_fast_async_op;
|
||||
pub use super::runtime::ops::map_async_op1;
|
||||
pub use super::runtime::ops::map_async_op2;
|
||||
pub use super::runtime::ops::map_async_op3;
|
||||
pub use super::runtime::ops::map_async_op4;
|
||||
pub use super::runtime::ops::queue_async_op;
|
||||
pub use super::runtime::ops::queue_fast_async_op;
|
||||
pub use super::runtime::throw_type_error;
|
||||
pub use super::runtime::V8_WRAPPER_OBJECT_INDEX;
|
||||
pub use super::runtime::V8_WRAPPER_TYPE_INDEX;
|
||||
}
|
||||
|
||||
// TODO(mmastrac): Temporary while we move code around
|
||||
pub mod snapshot_util {
|
||||
pub use crate::runtime::create_snapshot;
|
||||
pub use crate::runtime::get_js_files;
|
||||
pub use crate::runtime::CreateSnapshotOptions;
|
||||
pub use crate::runtime::CreateSnapshotOutput;
|
||||
pub use crate::runtime::FilterFn;
|
||||
}
|
||||
|
||||
/// A helper macro that will return a call site in Rust code. Should be
|
||||
/// used when executing internal one-line scripts for JsRuntime lifecycle.
|
||||
///
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::JsRuntime;
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::bindings;
|
||||
use crate::error::generic_error;
|
||||
use crate::fast_string::FastString;
|
||||
use crate::modules::get_asserted_module_type_from_assertions;
|
||||
|
@ -20,7 +18,8 @@ use crate::modules::NoopModuleLoader;
|
|||
use crate::modules::PrepareLoadFuture;
|
||||
use crate::modules::RecursiveModuleLoad;
|
||||
use crate::modules::ResolutionKind;
|
||||
use crate::snapshot_util::SnapshottedData;
|
||||
use crate::runtime::JsRuntime;
|
||||
use crate::runtime::SnapshottedData;
|
||||
use anyhow::Error;
|
||||
use futures::future::FutureExt;
|
||||
use futures::stream::FuturesUnordered;
|
||||
|
@ -467,7 +466,7 @@ impl ModuleMap {
|
|||
let name_str = name.v8(scope);
|
||||
let source_str = source.v8(scope);
|
||||
|
||||
let origin = bindings::module_origin(scope, name_str);
|
||||
let origin = module_origin(scope, name_str);
|
||||
let source = v8::script_compiler::Source::new(source_str, Some(&origin));
|
||||
|
||||
let tc_scope = &mut v8::TryCatch::new(scope);
|
||||
|
@ -820,3 +819,22 @@ fn json_module_evaluation_steps<'a>(
|
|||
resolver.resolve(tc_scope, undefined.into());
|
||||
Some(resolver.get_promise(tc_scope).into())
|
||||
}
|
||||
|
||||
pub fn module_origin<'a>(
|
||||
s: &mut v8::HandleScope<'a>,
|
||||
resource_name: v8::Local<'a, v8::String>,
|
||||
) -> v8::ScriptOrigin<'a> {
|
||||
let source_map_url = v8::String::empty(s);
|
||||
v8::ScriptOrigin::new(
|
||||
s,
|
||||
resource_name.into(),
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
123,
|
||||
source_map_url.into(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::ascii_str;
|
||||
use crate::resolve_import;
|
||||
use crate::JsRuntime;
|
||||
use crate::JsRuntimeForSnapshot;
|
||||
use crate::runtime::JsRuntime;
|
||||
use crate::runtime::JsRuntimeForSnapshot;
|
||||
use crate::RuntimeOptions;
|
||||
use crate::Snapshot;
|
||||
use deno_ops::op;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::error::AnyError;
|
||||
use crate::error::GetErrorClassFn;
|
||||
use crate::gotham_state::GothamState;
|
||||
use crate::realm::ContextState;
|
||||
use crate::resources::ResourceTable;
|
||||
use crate::runtime::GetErrorClassFn;
|
||||
use crate::runtime::ContextState;
|
||||
use crate::runtime::JsRuntimeState;
|
||||
use crate::OpDecl;
|
||||
use crate::OpsTracker;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::bindings::script_origin;
|
||||
use crate::error::custom_error;
|
||||
use crate::error::is_instance_of_error;
|
||||
use crate::error::range_error;
|
||||
|
@ -7,6 +6,7 @@ use crate::error::type_error;
|
|||
use crate::error::JsError;
|
||||
use crate::ops_builtin::WasmStreamingResource;
|
||||
use crate::resolve_url;
|
||||
use crate::runtime::script_origin;
|
||||
use crate::serde_v8::from_v8;
|
||||
use crate::source_map::apply_source_map;
|
||||
use crate::JsRealm;
|
||||
|
|
|
@ -78,25 +78,6 @@ pub fn script_origin<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
pub fn module_origin<'a>(
|
||||
s: &mut v8::HandleScope<'a>,
|
||||
resource_name: v8::Local<'a, v8::String>,
|
||||
) -> v8::ScriptOrigin<'a> {
|
||||
let source_map_url = v8::String::empty(s);
|
||||
v8::ScriptOrigin::new(
|
||||
s,
|
||||
resource_name.into(),
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
123,
|
||||
source_map_url.into(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
fn get<'s, T>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
from: v8::Local<v8::Object>,
|
|
@ -1,9 +1,8 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::bindings;
|
||||
use super::bindings;
|
||||
use crate::error::exception_to_err_result;
|
||||
use crate::modules::ModuleCode;
|
||||
use crate::ops::OpCtx;
|
||||
use crate::runtime::exception_to_err_result;
|
||||
use crate::runtime::JsRuntimeState;
|
||||
use crate::task::MaskResultAsSend;
|
||||
use crate::JsRuntime;
|
File diff suppressed because it is too large
Load diff
35
core/runtime/mod.rs
Normal file
35
core/runtime/mod.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
mod bindings;
|
||||
mod jsrealm;
|
||||
mod jsruntime;
|
||||
#[doc(hidden)]
|
||||
pub mod ops;
|
||||
mod snapshot_util;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub const V8_WRAPPER_TYPE_INDEX: i32 = 0;
|
||||
pub const V8_WRAPPER_OBJECT_INDEX: i32 = 1;
|
||||
|
||||
pub(crate) use jsrealm::ContextState;
|
||||
pub use jsrealm::JsRealm;
|
||||
pub use jsruntime::CompiledWasmModuleStore;
|
||||
pub use jsruntime::CrossIsolateStore;
|
||||
pub(crate) use jsruntime::InitMode;
|
||||
pub use jsruntime::JsRuntime;
|
||||
pub use jsruntime::JsRuntimeForSnapshot;
|
||||
pub use jsruntime::JsRuntimeState;
|
||||
pub use jsruntime::RuntimeOptions;
|
||||
pub use jsruntime::RuntimeSnapshotOptions;
|
||||
pub use jsruntime::SharedArrayBufferStore;
|
||||
pub use jsruntime::Snapshot;
|
||||
pub use snapshot_util::create_snapshot;
|
||||
pub use snapshot_util::get_js_files;
|
||||
pub use snapshot_util::CreateSnapshotOptions;
|
||||
pub use snapshot_util::CreateSnapshotOutput;
|
||||
pub use snapshot_util::FilterFn;
|
||||
pub(crate) use snapshot_util::SnapshottedData;
|
||||
|
||||
pub use bindings::script_origin;
|
||||
pub use bindings::throw_type_error;
|
156
core/runtime/ops.rs
Normal file
156
core/runtime/ops.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::ops::*;
|
||||
use crate::OpResult;
|
||||
use crate::PromiseId;
|
||||
use anyhow::Error;
|
||||
use futures::future::Future;
|
||||
use futures::future::FutureExt;
|
||||
use futures::future::MaybeDone;
|
||||
use futures::task::noop_waker;
|
||||
use std::cell::RefCell;
|
||||
use std::option::Option;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
|
||||
#[inline]
|
||||
pub fn queue_fast_async_op<R: serde::Serialize + 'static>(
|
||||
ctx: &OpCtx,
|
||||
promise_id: PromiseId,
|
||||
op: impl Future<Output = Result<R, Error>> + 'static,
|
||||
) {
|
||||
let get_class = {
|
||||
let state = RefCell::borrow(&ctx.state);
|
||||
state.tracker.track_async(ctx.id);
|
||||
state.get_error_class_fn
|
||||
};
|
||||
let fut = op
|
||||
.map(|result| crate::_ops::to_op_result(get_class, result))
|
||||
.boxed_local();
|
||||
// SAFETY: this this is guaranteed to be running on a current-thread executor
|
||||
ctx.context_state.borrow_mut().pending_ops.spawn(unsafe {
|
||||
crate::task::MaskFutureAsSend::new(OpCall::pending(ctx, promise_id, fut))
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_async_op1<R: serde::Serialize + 'static>(
|
||||
ctx: &OpCtx,
|
||||
op: impl Future<Output = Result<R, Error>> + 'static,
|
||||
) -> MaybeDone<Pin<Box<dyn Future<Output = OpResult>>>> {
|
||||
let get_class = {
|
||||
let state = RefCell::borrow(&ctx.state);
|
||||
state.tracker.track_async(ctx.id);
|
||||
state.get_error_class_fn
|
||||
};
|
||||
|
||||
let fut = op
|
||||
.map(|result| crate::_ops::to_op_result(get_class, result))
|
||||
.boxed_local();
|
||||
MaybeDone::Future(fut)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_async_op2<R: serde::Serialize + 'static>(
|
||||
ctx: &OpCtx,
|
||||
op: impl Future<Output = R> + 'static,
|
||||
) -> MaybeDone<Pin<Box<dyn Future<Output = OpResult>>>> {
|
||||
let state = RefCell::borrow(&ctx.state);
|
||||
state.tracker.track_async(ctx.id);
|
||||
|
||||
let fut = op.map(|result| OpResult::Ok(result.into())).boxed_local();
|
||||
MaybeDone::Future(fut)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_async_op3<R: serde::Serialize + 'static>(
|
||||
ctx: &OpCtx,
|
||||
op: Result<impl Future<Output = Result<R, Error>> + 'static, Error>,
|
||||
) -> MaybeDone<Pin<Box<dyn Future<Output = OpResult>>>> {
|
||||
let get_class = {
|
||||
let state = RefCell::borrow(&ctx.state);
|
||||
state.tracker.track_async(ctx.id);
|
||||
state.get_error_class_fn
|
||||
};
|
||||
|
||||
match op {
|
||||
Err(err) => MaybeDone::Done(OpResult::Err(OpError::new(get_class, err))),
|
||||
Ok(fut) => MaybeDone::Future(
|
||||
fut
|
||||
.map(|result| crate::_ops::to_op_result(get_class, result))
|
||||
.boxed_local(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_async_op4<R: serde::Serialize + 'static>(
|
||||
ctx: &OpCtx,
|
||||
op: Result<impl Future<Output = R> + 'static, Error>,
|
||||
) -> MaybeDone<Pin<Box<dyn Future<Output = OpResult>>>> {
|
||||
let get_class = {
|
||||
let state = RefCell::borrow(&ctx.state);
|
||||
state.tracker.track_async(ctx.id);
|
||||
state.get_error_class_fn
|
||||
};
|
||||
|
||||
match op {
|
||||
Err(err) => MaybeDone::Done(OpResult::Err(OpError::new(get_class, err))),
|
||||
Ok(fut) => MaybeDone::Future(
|
||||
fut.map(|result| OpResult::Ok(result.into())).boxed_local(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn queue_async_op<'s>(
|
||||
ctx: &OpCtx,
|
||||
scope: &'s mut v8::HandleScope,
|
||||
deferred: bool,
|
||||
promise_id: PromiseId,
|
||||
mut op: MaybeDone<Pin<Box<dyn Future<Output = OpResult>>>>,
|
||||
) -> Option<v8::Local<'s, v8::Value>> {
|
||||
// An op's realm (as given by `OpCtx::realm_idx`) must match the realm in
|
||||
// which it is invoked. Otherwise, we might have cross-realm object exposure.
|
||||
// deno_core doesn't currently support such exposure, even though embedders
|
||||
// can cause them, so we panic in debug mode (since the check is expensive).
|
||||
// TODO(mmastrac): Restore this
|
||||
// debug_assert_eq!(
|
||||
// runtime_state.borrow().context(ctx.realm_idx as usize, scope),
|
||||
// Some(scope.get_current_context())
|
||||
// );
|
||||
|
||||
// All ops are polled immediately
|
||||
let waker = noop_waker();
|
||||
let mut cx = Context::from_waker(&waker);
|
||||
|
||||
// Note that MaybeDone returns () from the future
|
||||
let op_call = match op.poll_unpin(&mut cx) {
|
||||
Poll::Pending => {
|
||||
let MaybeDone::Future(fut) = op else {
|
||||
unreachable!()
|
||||
};
|
||||
OpCall::pending(ctx, promise_id, fut)
|
||||
}
|
||||
Poll::Ready(_) => {
|
||||
let mut op_result = Pin::new(&mut op).take_output().unwrap();
|
||||
// If the op is ready and is not marked as deferred we can immediately return
|
||||
// the result.
|
||||
if !deferred {
|
||||
ctx.state.borrow_mut().tracker.track_async_completed(ctx.id);
|
||||
return Some(op_result.to_v8(scope).unwrap());
|
||||
}
|
||||
|
||||
OpCall::ready(ctx, promise_id, op_result)
|
||||
}
|
||||
};
|
||||
|
||||
// Otherwise we will push it to the `pending_ops` and let it be polled again
|
||||
// or resolved on the next tick of the event loop.
|
||||
ctx
|
||||
.context_state
|
||||
.borrow_mut()
|
||||
.pending_ops
|
||||
// SAFETY: this this is guaranteed to be running on a current-thread executor
|
||||
.spawn(unsafe { crate::task::MaskFutureAsSend::new(op_call) });
|
||||
None
|
||||
}
|
2306
core/runtime/tests.rs
Normal file
2306
core/runtime/tests.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue