Skip to content

Commit

Permalink
V8 Fast API Sequence (denoland#1022)
Browse files Browse the repository at this point in the history
Co-authored-by: Bartek Iwańczuk <[email protected]>
  • Loading branch information
littledivy and bartlomieju committed Jul 8, 2022
1 parent 1d0a4c1 commit 47a7bec
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 1 deletion.
19 changes: 18 additions & 1 deletion src/fast_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ pub enum Type {
Float32,
Float64,
V8Value,
Sequence(CType),
TypedArray(CType),
ArrayBuffer(CType),
}

impl From<&Type> for CType {
Expand All @@ -116,6 +119,20 @@ impl From<&Type> for CType {
Type::Float32 => CType::Float32,
Type::Float64 => CType::Float64,
Type::V8Value => CType::V8Value,
Type::Sequence(ty) => *ty,
Type::TypedArray(ty) => *ty,
Type::ArrayBuffer(ty) => *ty,
}
}
}

impl From<&Type> for SequenceType {
fn from(ty: &Type) -> SequenceType {
match ty {
Type::Sequence(_) => SequenceType::IsSequence,
Type::TypedArray(_) => SequenceType::IsTypedArray,
Type::ArrayBuffer(_) => SequenceType::IsArrayBuffer,
_ => SequenceType::Scalar,
}
}
}
Expand All @@ -124,7 +141,7 @@ impl From<&Type> for CTypeSequenceInfo {
fn from(ty: &Type) -> CTypeSequenceInfo {
CTypeSequenceInfo {
c_type: ty.into(),
sequence_type: SequenceType::Scalar,
sequence_type: ty.into(),
}
}
}
Expand Down
167 changes: 167 additions & 0 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7078,3 +7078,170 @@ fn test_fast_calls() {
eval(scope, source).unwrap();
assert_eq!("fast", unsafe { WHO });
}

#[test]
fn test_fast_calls_sequence() {
static mut WHO: &str = "none";
fn fast_fn(
_recv: v8::Local<v8::Object>,
a: u32,
b: u32,
array: v8::Local<v8::Array>,
) -> u32 {
unsafe { WHO = "fast" };
assert_eq!(array.length(), 2);
a + b + array.length()
}

pub struct FastTest;
impl fast_api::FastFunction for FastTest {
fn args(&self) -> &'static [fast_api::Type] {
&[
fast_api::Type::V8Value,
fast_api::Type::Uint32,
fast_api::Type::Uint32,
fast_api::Type::Sequence(fast_api::CType::Void),
]
}

fn return_type(&self) -> fast_api::CType {
fast_api::CType::Uint32
}

type Signature = fn(
receiver: v8::Local<v8::Object>,
a: u32,
b: u32,
array: v8::Local<v8::Array>,
) -> u32;
fn function(&self) -> Self::Signature {
fast_fn
}
}

fn slow_fn(
scope: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
unsafe { WHO = "slow" };
rv.set(v8::Boolean::new(scope, false).into());
}

let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);

let global = context.global(scope);

let template =
v8::FunctionTemplate::builder(slow_fn).build_fast(scope, FastTest);

let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap();
global.set(scope, name.into(), value.into()).unwrap();
let source = r#"
function f(x, y, data) { return func(x, y, data); }
%PrepareFunctionForOptimization(f);
const arr = [3, 4];
f(1, 2, arr);
"#;
eval(scope, source).unwrap();
assert_eq!("slow", unsafe { WHO });

let source = r#"
%OptimizeFunctionOnNextCall(f);
f(1, 2, arr);
"#;
eval(scope, source).unwrap();
assert_eq!("fast", unsafe { WHO });
}

#[repr(C)]
pub struct FastApiArrayBuffer {
byte_length: usize,
data: *mut u32,
}

#[test]
fn test_fast_calls_arraybuffer() {
static mut WHO: &str = "none";
fn fast_fn(
_recv: v8::Local<v8::Object>,
a: u32,
b: u32,
data: *const FastApiArrayBuffer,
) -> u32 {
unsafe { WHO = "fast" };
let buf =
unsafe { std::slice::from_raw_parts((*data).data, (*data).byte_length) };
a + b + buf[0]
}

pub struct FastTest;
impl fast_api::FastFunction for FastTest {
fn args(&self) -> &'static [fast_api::Type] {
&[
fast_api::Type::V8Value,
fast_api::Type::Uint32,
fast_api::Type::Uint32,
fast_api::Type::TypedArray(fast_api::CType::Uint32),
]
}

fn return_type(&self) -> fast_api::CType {
fast_api::CType::Uint32
}

type Signature = fn(
receiver: v8::Local<v8::Object>,
a: u32,
b: u32,
data: *const FastApiArrayBuffer,
) -> u32;
fn function(&self) -> Self::Signature {
fast_fn
}
}

fn slow_fn(
scope: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
unsafe { WHO = "slow" };
rv.set(v8::Boolean::new(scope, false).into());
}

let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);

let global = context.global(scope);

let template =
v8::FunctionTemplate::builder(slow_fn).build_fast(scope, FastTest);

let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap();
global.set(scope, name.into(), value.into()).unwrap();
let source = r#"
function f(x, y, data) { return func(x, y, data); }
%PrepareFunctionForOptimization(f);
const arr = new Uint32Array([3, 4]);
f(1, 2, arr);
"#;
eval(scope, source).unwrap();
assert_eq!("slow", unsafe { WHO });

let source = r#"
%OptimizeFunctionOnNextCall(f);
f(1, 2, arr);
"#;
eval(scope, source).unwrap();
assert_eq!("fast", unsafe { WHO });
}

0 comments on commit 47a7bec

Please sign in to comment.