Skip to content

Commit

Permalink
feat: Infrastructure for op sanitizer in deno_core (#460)
Browse files Browse the repository at this point in the history
This is the underlying infrastructure we need to get the op sanitizer
working in Rust. There are no useful public-facing APIs from this yet,
but it implements the op portion of the work.

Step 2 will be adding resources and timers to the API, then we'll be
able to implement this in Deno itself.
  • Loading branch information
mmastrac authored Jan 22, 2024
1 parent 98d1cc5 commit 920e001
Show file tree
Hide file tree
Showing 8 changed files with 403 additions and 105 deletions.
10 changes: 5 additions & 5 deletions core/runtime/jsrealm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ impl Hasher for IdentityHasher {

/// We will be experimenting with different driver types in the future. This allows us to
/// swap the driver out for experimentation.
#[cfg(feature = "op_driver_joinset")]
type DefaultOpDriver = super::op_driver::JoinSetDriver;

#[cfg(all(
feature = "op_driver_futuresunordered",
not(feature = "op_driver_joinset")
feature = "op_driver_joinset",
not(feature = "op_driver_futuresunordered")
))]
type DefaultOpDriver = super::op_driver::JoinSetDriver;

#[cfg(feature = "op_driver_futuresunordered")]
type DefaultOpDriver = super::op_driver::FuturesUnorderedDriver;

pub(crate) struct ContextState<OpDriverImpl: OpDriver = DefaultOpDriver> {
Expand Down
15 changes: 15 additions & 0 deletions core/runtime/jsruntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::bindings::watch_promise;
use super::exception_state::ExceptionState;
use super::jsrealm::JsRealmInner;
use super::op_driver::OpDriver;
use super::op_driver::OpInflightStats;
use super::snapshot_util;
use super::SnapshottedData;
use crate::error::exception_to_err_result;
Expand Down Expand Up @@ -78,6 +79,14 @@ use v8::Isolate;
pub type WaitForInspectorDisconnectCallback = Box<dyn Fn()>;
const STATE_DATA_OFFSET: u32 = 0;

/// Information about in-flight ops, open resources, active timers and other runtime-specific
/// data that can be used for test sanitization.
pub struct RuntimeActivityStats {
/// This will be exposed in follow-up work.
#[allow(dead_code)]
op: OpInflightStats,
}

pub enum Snapshot {
Static(&'static [u8]),
JustCreated(v8::StartupData),
Expand Down Expand Up @@ -992,6 +1001,12 @@ impl JsRuntime {
}
}

pub fn inflight_stats(&self) -> RuntimeActivityStats {
RuntimeActivityStats {
op: self.inner.main_realm.0.context_state.pending_ops.stats(),
}
}

/// Returns the extensions that this runtime is using (including internal ones).
pub fn extensions(&self) -> &Vec<Extension> {
&self.extensions
Expand Down
18 changes: 13 additions & 5 deletions core/runtime/op_driver/erased_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ use std::marker::PhantomData;
use std::marker::PhantomPinned;
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::ptr::NonNull;
use std::task::Context;
use std::task::Poll;

#[repr(C, align(16))]
pub struct TypeErased<const MAX_SIZE: usize> {
memory: [MaybeUninit<u8>; MAX_SIZE],
drop: fn(this: *mut ()),
drop: fn(this: NonNull<()>),
_unpin: PhantomPinned,
}

impl<const MAX_SIZE: usize> TypeErased<MAX_SIZE> {
#[inline(always)]
pub unsafe fn take<R: 'static>(self) -> R {
assert!(
std::mem::size_of::<R>() <= std::mem::size_of_val(&self.memory),
Expand All @@ -35,14 +37,16 @@ impl<const MAX_SIZE: usize> TypeErased<MAX_SIZE> {
r
}

pub fn raw_ptr(&mut self) -> *mut () {
self.memory.as_mut_ptr() as _
#[inline(always)]
pub fn raw_ptr<R>(&mut self) -> NonNull<R> {
unsafe { NonNull::new_unchecked(self.memory.as_mut_ptr() as *mut _) }
}

#[inline(always)]
pub fn new<R>(r: R) -> Self {
let mut new = Self {
memory: [MaybeUninit::uninit(); MAX_SIZE],
drop: |this| unsafe { std::ptr::drop_in_place::<R>(this as _) },
drop: |this| unsafe { std::ptr::drop_in_place::<R>(this.as_ptr() as _) },
_unpin: PhantomPinned,
};
assert!(
Expand All @@ -66,10 +70,12 @@ impl<const MAX_SIZE: usize> TypeErased<MAX_SIZE> {

impl<const MAX_SIZE: usize> Drop for TypeErased<MAX_SIZE> {
fn drop(&mut self) {
(self.drop)(self.raw_ptr())
(self.drop)(self.raw_ptr::<()>())
}
}

// TODO(mmastrac): This code is also testing TypeErased above
#[allow(dead_code)]
pub struct ErasedFuture<const MAX_SIZE: usize, Output> {
erased: TypeErased<MAX_SIZE>,
poll: unsafe fn(
Expand All @@ -80,6 +86,7 @@ pub struct ErasedFuture<const MAX_SIZE: usize, Output> {
}

impl<const MAX_SIZE: usize, Output> ErasedFuture<MAX_SIZE, Output> {
#[allow(dead_code)]
unsafe fn poll<F>(
pin: Pin<&mut TypeErased<MAX_SIZE>>,
cx: &mut Context<'_>,
Expand All @@ -90,6 +97,7 @@ impl<const MAX_SIZE: usize, Output> ErasedFuture<MAX_SIZE, Output> {
F::poll(std::mem::transmute(pin), cx)
}

#[allow(dead_code)]
pub fn new<F>(f: F) -> Self
where
F: Future<Output = Output>,
Expand Down
Loading

0 comments on commit 920e001

Please sign in to comment.