Skip to content

Commit

Permalink
feat: upgrade deno_core (#25042)
Browse files Browse the repository at this point in the history
- Update ffi turbocall to use revised fast call api
- Remove `v8_version` function calls
- `*mut OwnedIsolate` is no longer stored in OpCtx gotham store
  • Loading branch information
devsnek authored Aug 19, 2024
1 parent 526f39f commit c0aa68a
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 117 deletions.
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ repository = "https://github.com/denoland/deno"

[workspace.dependencies]
deno_ast = { version = "=0.41.2", features = ["transpiling"] }
deno_core = { version = "0.303.0" }
deno_core = { version = "0.304.0" }

deno_bench_util = { version = "0.158.0", path = "./bench_util" }
deno_lockfile = "0.21.1"
Expand Down
2 changes: 1 addition & 1 deletion cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ pub fn clap_root() -> Command {
crate::version::DENO_VERSION_INFO.release_channel.name(),
env!("PROFILE"),
env!("TARGET"),
deno_core::v8_version(),
deno_core::v8::VERSION_STRING,
crate::version::DENO_VERSION_INFO.typescript
);

Expand Down
2 changes: 1 addition & 1 deletion cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ fn create_cli_snapshot(snapshot_path: PathBuf) {

let snapshot_options = SnapshotOptions {
ts_version: ts::version(),
v8_version: deno_core::v8_version(),
v8_version: deno_core::v8::VERSION_STRING,
target: std::env::var("TARGET").unwrap(),
};

Expand Down
138 changes: 70 additions & 68 deletions ext/ffi/dlfcn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use crate::ir::out_buffer_as_ptr;
use crate::symbol::NativeType;
use crate::symbol::Symbol;
use crate::turbocall;
use crate::turbocall::Turbocall;
use crate::FfiPermissions;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::v8;
use deno_core::GarbageCollected;
use deno_core::OpState;
use deno_core::Resource;
use dlopen2::raw::Library;
Expand Down Expand Up @@ -208,84 +210,84 @@ where
Ok(out.into())
}

struct FunctionData {
// Held in a box to keep memory while function is alive.
#[allow(unused)]
symbol: Box<Symbol>,
// Held in a box to keep inner data alive while function is alive.
#[allow(unused)]
turbocall: Option<Turbocall>,
}

impl GarbageCollected for FunctionData {}

// Create a JavaScript function for synchronous FFI call to
// the given symbol.
fn make_sync_fn<'s>(
scope: &mut v8::HandleScope<'s>,
sym: Box<Symbol>,
symbol: Box<Symbol>,
) -> v8::Local<'s, v8::Function> {
let sym = Box::leak(sym);
let builder = v8::FunctionTemplate::builder(
|scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue| {
let external: v8::Local<v8::External> = args.data().try_into().unwrap();
// SAFETY: The pointer will not be deallocated until the function is
// garbage collected.
let symbol = unsafe { &*(external.value() as *const Symbol) };
let out_buffer = match symbol.result_type {
NativeType::Struct(_) => {
let argc = args.length();
out_buffer_as_ptr(
scope,
Some(
v8::Local::<v8::TypedArray>::try_from(args.get(argc - 1))
.unwrap(),
),
)
}
_ => None,
};
match crate::call::ffi_call_sync(scope, args, symbol, out_buffer) {
Ok(result) => {
let result =
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
unsafe { result.to_v8(scope, symbol.result_type.clone()) };
rv.set(result);
}
Err(err) => {
deno_core::_ops::throw_type_error(scope, err.to_string());
}
};
},
)
.data(v8::External::new(scope, sym as *mut Symbol as *mut _).into());

let mut fast_call_alloc = None;

let func = if turbocall::is_compatible(sym) {
let trampoline = turbocall::compile_trampoline(sym);
let func = builder.build_fast(
scope,
&turbocall::make_template(sym, &trampoline),
None,
None,
None,
);
fast_call_alloc = Some(Box::into_raw(Box::new(trampoline)));
func
let turbocall = if turbocall::is_compatible(&symbol) {
let trampoline = turbocall::compile_trampoline(&symbol);
let turbocall = turbocall::make_template(&symbol, trampoline);
Some(turbocall)
} else {
None
};

let c_function = turbocall.as_ref().map(|turbocall| {
v8::fast_api::CFunction::new(
turbocall.trampoline.ptr(),
&turbocall.c_function_info,
)
});

let data = FunctionData { symbol, turbocall };
let data = deno_core::cppgc::make_cppgc_object(scope, data);

let builder = v8::FunctionTemplate::builder(sync_fn_impl).data(data.into());

let func = if let Some(c_function) = c_function {
builder.build_fast(scope, &[c_function])
} else {
builder.build(scope)
};
let func = func.get_function(scope).unwrap();
func.get_function(scope).unwrap()
}

let weak = v8::Weak::with_finalizer(
fn sync_fn_impl<'s>(
scope: &mut v8::HandleScope<'s>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue,
) {
let data = deno_core::cppgc::try_unwrap_cppgc_object::<FunctionData>(
scope,
func,
Box::new(move |_| {
// SAFETY: This is never called twice. pointer obtained
// from Box::into_raw, hence, satisfies memory layout requirements.
let _ = unsafe { Box::from_raw(sym) };
if let Some(fast_call_ptr) = fast_call_alloc {
// fast-call compiled trampoline is unmapped when the MMAP handle is dropped
// SAFETY: This is never called twice. pointer obtained
// from Box::into_raw, hence, satisfies memory layout requirements.
let _ = unsafe { Box::from_raw(fast_call_ptr) };
}
}),
);

weak.to_local(scope).unwrap()
args.data(),
)
.unwrap();
let out_buffer = match data.symbol.result_type {
NativeType::Struct(_) => {
let argc = args.length();
out_buffer_as_ptr(
scope,
Some(
v8::Local::<v8::TypedArray>::try_from(args.get(argc - 1)).unwrap(),
),
)
}
_ => None,
};
match crate::call::ffi_call_sync(scope, args, &data.symbol, out_buffer) {
Ok(result) => {
let result =
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
unsafe { result.to_v8(scope, data.symbol.result_type.clone()) };
rv.set(result);
}
Err(err) => {
deno_core::_ops::throw_type_error(scope, err.to_string());
}
};
}

// `path` is only used on Windows.
Expand Down
69 changes: 41 additions & 28 deletions ext/ffi/turbocall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,39 @@ pub(crate) fn compile_trampoline(sym: &Symbol) -> Trampoline {
}
}

pub(crate) fn make_template(
sym: &Symbol,
trampoline: &Trampoline,
) -> fast_api::FastFunction {
let params = once(fast_api::Type::V8Value) // Receiver
pub(crate) struct Turbocall {
pub trampoline: Trampoline,
// Held in a box to keep the memory alive for CFunctionInfo
#[allow(unused)]
pub param_info: Box<[fast_api::CTypeInfo]>,
// Held in a box to keep the memory alive for V8
#[allow(unused)]
pub c_function_info: Box<fast_api::CFunctionInfo>,
}

pub(crate) fn make_template(sym: &Symbol, trampoline: Trampoline) -> Turbocall {
let param_info = once(fast_api::Type::V8Value.scalar()) // Receiver
.chain(sym.parameter_types.iter().map(|t| t.into()))
.collect::<Vec<_>>();
.collect::<Box<_>>();

let ret = if sym.result_type == NativeType::Buffer {
// Buffer can be used as a return type and converts differently than in parameters.
fast_api::CType::Pointer
fast_api::Type::Pointer.scalar()
} else {
fast_api::CType::from(&fast_api::Type::from(&sym.result_type))
(&sym.result_type).into()
};

fast_api::FastFunction::new_with_bigint(
Box::leak(params.into_boxed_slice()),
let c_function_info = Box::new(fast_api::CFunctionInfo::new(
ret,
trampoline.ptr(),
)
&param_info,
fast_api::Int64Representation::BigInt,
));

Turbocall {
trampoline,
param_info,
c_function_info,
}
}

/// Trampoline for fast-call FFI functions
Expand All @@ -68,33 +81,33 @@ pub(crate) fn make_template(
pub(crate) struct Trampoline(ExecutableBuffer);

impl Trampoline {
fn ptr(&self) -> *const c_void {
pub(crate) fn ptr(&self) -> *const c_void {
&self.0[0] as *const u8 as *const c_void
}
}

impl From<&NativeType> for fast_api::Type {
impl From<&NativeType> for fast_api::CTypeInfo {
fn from(native_type: &NativeType) -> Self {
match native_type {
NativeType::Bool => fast_api::Type::Bool,
NativeType::Bool => fast_api::Type::Bool.scalar(),
NativeType::U8 | NativeType::U16 | NativeType::U32 => {
fast_api::Type::Uint32
fast_api::Type::Uint32.scalar()
}
NativeType::I8 | NativeType::I16 | NativeType::I32 => {
fast_api::Type::Int32
fast_api::Type::Int32.scalar()
}
NativeType::F32 => fast_api::Type::Float32,
NativeType::F64 => fast_api::Type::Float64,
NativeType::Void => fast_api::Type::Void,
NativeType::I64 => fast_api::Type::Int64,
NativeType::U64 => fast_api::Type::Uint64,
NativeType::ISize => fast_api::Type::Int64,
NativeType::USize => fast_api::Type::Uint64,
NativeType::Pointer | NativeType::Function => fast_api::Type::Pointer,
NativeType::Buffer => fast_api::Type::TypedArray(fast_api::CType::Uint8),
NativeType::Struct(_) => {
fast_api::Type::TypedArray(fast_api::CType::Uint8)
NativeType::F32 => fast_api::Type::Float32.scalar(),
NativeType::F64 => fast_api::Type::Float64.scalar(),
NativeType::Void => fast_api::Type::Void.scalar(),
NativeType::I64 => fast_api::Type::Int64.scalar(),
NativeType::U64 => fast_api::Type::Uint64.scalar(),
NativeType::ISize => fast_api::Type::Int64.scalar(),
NativeType::USize => fast_api::Type::Uint64.scalar(),
NativeType::Pointer | NativeType::Function => {
fast_api::Type::Pointer.scalar()
}
NativeType::Buffer => fast_api::Type::Uint8.typed_array(),
NativeType::Struct(_) => fast_api::Type::Uint8.typed_array(),
}
}
}
Expand Down
Loading

0 comments on commit c0aa68a

Please sign in to comment.