Add SeqOneByteString to fast API calls (#1129)

This commit is contained in:
Divy Srivastava 2022-11-29 13:06:55 -08:00 committed by GitHub
parent 3603c6e9c5
commit f5c9e90c6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 92 additions and 0 deletions

View File

@ -91,6 +91,7 @@ pub enum CType {
Float32,
Float64,
V8Value,
SeqOneByteString,
// https://github.com/v8/v8/blob/492a32943bc34a527f42df2ae15a77154b16cc84/include/v8-fast-api-calls.h#L264-L267
// kCallbackOptionsType is not part of the Type enum
// because it is only used internally. Use value 255 that is larger
@ -110,6 +111,7 @@ pub enum Type {
Float32,
Float64,
V8Value,
SeqOneByteString,
CallbackOptions,
Sequence(CType),
TypedArray(CType),
@ -128,6 +130,7 @@ impl From<&Type> for CType {
Type::Float32 => CType::Float32,
Type::Float64 => CType::Float64,
Type::V8Value => CType::V8Value,
Type::SeqOneByteString => CType::SeqOneByteString,
Type::CallbackOptions => CType::CallbackOptions,
Type::Sequence(ty) => *ty,
Type::TypedArray(ty) => *ty,
@ -204,6 +207,25 @@ pub struct FastApiTypedArray<T: Default> {
data: *mut T,
}
#[repr(C)]
pub struct FastApiOneByteString {
data: *const u8,
pub length: usize,
}
impl FastApiOneByteString {
#[inline(always)]
pub fn as_str(&self) -> &str {
// SAFETY: The string is guaranteed to be valid UTF-8.
unsafe {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(
self.data,
self.length,
))
}
}
}
impl<T: Default> FastApiTypedArray<T> {
#[inline(always)]
pub fn get(&self, index: usize) -> T {

View File

@ -8603,3 +8603,73 @@ fn test_detach_key() {
assert!(buffer.was_detached());
}
}
#[test]
fn test_fast_calls_onebytestring() {
static mut WHO: &str = "none";
fn fast_fn(
_recv: v8::Local<v8::Object>,
data: *const fast_api::FastApiOneByteString,
) -> u32 {
unsafe { WHO = "fast" };
let data = unsafe { &*data }.as_str();
assert_eq!("hello", data);
data.len() as u32
}
pub struct FastTest;
impl fast_api::FastFunction for FastTest {
fn args(&self) -> &'static [fast_api::Type] {
&[fast_api::Type::V8Value, fast_api::Type::SeqOneByteString]
}
fn return_type(&self) -> fast_api::CType {
fast_api::CType::Uint32
}
fn function(&self) -> *const c_void {
fast_fn as _
}
}
fn slow_fn(
_: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments,
_: v8::ReturnValue,
) {
unsafe { WHO = "slow" };
}
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, None);
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(data) { return func(data); }
%PrepareFunctionForOptimization(f);
const str = "hello";
f(str);
"#;
eval(scope, source).unwrap();
assert_eq!("slow", unsafe { WHO });
let source = r#"
%OptimizeFunctionOnNextCall(f);
const result = f(str);
if (result != 5) {
throw new Error("wrong result");
}
"#;
eval(scope, source).unwrap();
assert_eq!("fast", unsafe { WHO });
}