mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-09 13:38:51 -04:00
feat: Add v8::CompiledWasmModule
(#776)
`v8::CompiledWasmModule` is a representation of a compiled WebAssembly module, which can be shared by multiple `v8::WasmModuleObject`s. Closes #759.
This commit is contained in:
parent
8094d5d971
commit
babe41a990
5 changed files with 165 additions and 0 deletions
|
@ -2747,3 +2747,28 @@ bool v8__ValueDeserializer__ReadRawBytes(v8::ValueDeserializer* self,
|
||||||
return self->ReadRawBytes(length, data);
|
return self->ReadRawBytes(length, data);
|
||||||
}
|
}
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
|
// v8::CompiledWasmModule
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
const v8::WasmModuleObject* v8__WasmModuleObject__FromCompiledModule(v8::Isolate* isolate,
|
||||||
|
const v8::CompiledWasmModule* compiled_module) {
|
||||||
|
return maybe_local_to_ptr(v8::WasmModuleObject::FromCompiledModule(isolate, *compiled_module));
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::CompiledWasmModule* v8__WasmModuleObject__GetCompiledModule(const v8::WasmModuleObject* self) {
|
||||||
|
v8::CompiledWasmModule cwm = ptr_to_local(self)->GetCompiledModule();
|
||||||
|
return new v8::CompiledWasmModule(std::move(cwm));
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* v8__CompiledWasmModule__GetWireBytesRef(v8::CompiledWasmModule* self,
|
||||||
|
size_t* length) {
|
||||||
|
v8::MemorySpan<const uint8_t> span = self->GetWireBytesRef();
|
||||||
|
*length = span.size();
|
||||||
|
return span.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void v8__CompiledWasmModule__DELETE(v8::CompiledWasmModule* self) {
|
||||||
|
delete self;
|
||||||
|
}
|
||||||
|
} // extern "C"
|
|
@ -1381,6 +1381,7 @@ impl_partial_eq! { Value for SymbolObject use identity }
|
||||||
impl_partial_eq! { Object for SymbolObject use identity }
|
impl_partial_eq! { Object for SymbolObject use identity }
|
||||||
impl_partial_eq! { SymbolObject for SymbolObject use identity }
|
impl_partial_eq! { SymbolObject for SymbolObject use identity }
|
||||||
|
|
||||||
|
/// An instance of WebAssembly.Module.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WasmModuleObject(Opaque);
|
pub struct WasmModuleObject(Opaque);
|
||||||
|
|
|
@ -141,6 +141,7 @@ pub use value_deserializer::ValueDeserializerImpl;
|
||||||
pub use value_serializer::ValueSerializer;
|
pub use value_serializer::ValueSerializer;
|
||||||
pub use value_serializer::ValueSerializerHelper;
|
pub use value_serializer::ValueSerializerHelper;
|
||||||
pub use value_serializer::ValueSerializerImpl;
|
pub use value_serializer::ValueSerializerImpl;
|
||||||
|
pub use wasm::CompiledWasmModule;
|
||||||
pub use wasm::WasmStreaming;
|
pub use wasm::WasmStreaming;
|
||||||
|
|
||||||
// TODO(piscisaureus): Ideally this trait would not be exported.
|
// TODO(piscisaureus): Ideally this trait would not be exported.
|
||||||
|
|
76
src/wasm.rs
76
src/wasm.rs
|
@ -4,10 +4,12 @@ use crate::function::FunctionCallbackArguments;
|
||||||
use crate::function::FunctionCallbackInfo;
|
use crate::function::FunctionCallbackInfo;
|
||||||
use crate::scope::CallbackScope;
|
use crate::scope::CallbackScope;
|
||||||
use crate::scope::HandleScope;
|
use crate::scope::HandleScope;
|
||||||
|
use crate::support::Opaque;
|
||||||
use crate::support::UnitType;
|
use crate::support::UnitType;
|
||||||
use crate::Isolate;
|
use crate::Isolate;
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
use crate::WasmModuleObject;
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
|
|
||||||
|
@ -62,6 +64,66 @@ impl Drop for WasmStreaming {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WasmModuleObject {
|
||||||
|
/// Efficiently re-create a WasmModuleObject, without recompiling, from
|
||||||
|
/// a CompiledWasmModule.
|
||||||
|
pub fn from_compiled_module<'s>(
|
||||||
|
scope: &mut HandleScope<'s>,
|
||||||
|
compiled_module: &CompiledWasmModule,
|
||||||
|
) -> Option<Local<'s, WasmModuleObject>> {
|
||||||
|
unsafe {
|
||||||
|
scope.cast_local(|sd| {
|
||||||
|
v8__WasmModuleObject__FromCompiledModule(
|
||||||
|
sd.get_isolate_ptr(),
|
||||||
|
compiled_module.0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the compiled module for this module object. The compiled module can be
|
||||||
|
/// shared by several module objects.
|
||||||
|
pub fn get_compiled_module(&self) -> CompiledWasmModule {
|
||||||
|
let ptr = unsafe { v8__WasmModuleObject__GetCompiledModule(self) };
|
||||||
|
CompiledWasmModule(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type-erased v8::CompiledWasmModule. We need this because the C++
|
||||||
|
// v8::CompiledWasmModule must be destructed because its private fields hold
|
||||||
|
// pointers that must be freed, but v8::CompiledWasmModule itself doesn't have
|
||||||
|
// a destructor. Therefore, in order to avoid memory leaks, the Rust-side
|
||||||
|
// CompiledWasmModule must be a pointer to a C++ allocation of
|
||||||
|
// v8::CompiledWasmModule.
|
||||||
|
#[repr(C)]
|
||||||
|
struct InternalCompiledWasmModule(Opaque);
|
||||||
|
|
||||||
|
/// Wrapper around a compiled WebAssembly module, which is potentially shared by
|
||||||
|
/// different WasmModuleObjects.
|
||||||
|
pub struct CompiledWasmModule(*mut InternalCompiledWasmModule);
|
||||||
|
|
||||||
|
impl CompiledWasmModule {
|
||||||
|
/// Get the (wasm-encoded) wire bytes that were used to compile this module.
|
||||||
|
pub fn get_wire_bytes_ref(&self) -> &[u8] {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
let mut len = 0isize;
|
||||||
|
unsafe {
|
||||||
|
let ptr = v8__CompiledWasmModule__GetWireBytesRef(self.0, &mut len);
|
||||||
|
std::slice::from_raw_parts(ptr, len.try_into().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(andreubotella): Safety???
|
||||||
|
unsafe impl Send for CompiledWasmModule {}
|
||||||
|
unsafe impl Sync for CompiledWasmModule {}
|
||||||
|
|
||||||
|
impl Drop for CompiledWasmModule {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { v8__CompiledWasmModule__DELETE(self.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn trampoline<F>() -> extern "C" fn(*const FunctionCallbackInfo)
|
pub(crate) fn trampoline<F>() -> extern "C" fn(*const FunctionCallbackInfo)
|
||||||
where
|
where
|
||||||
F: UnitType + Fn(&mut HandleScope, Local<Value>, WasmStreaming),
|
F: UnitType + Fn(&mut HandleScope, Local<Value>, WasmStreaming),
|
||||||
|
@ -102,4 +164,18 @@ extern "C" {
|
||||||
this: *mut WasmStreamingSharedPtr,
|
this: *mut WasmStreamingSharedPtr,
|
||||||
exception: *const Value,
|
exception: *const Value,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fn v8__WasmModuleObject__FromCompiledModule(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
compiled_module: *const InternalCompiledWasmModule,
|
||||||
|
) -> *const WasmModuleObject;
|
||||||
|
fn v8__WasmModuleObject__GetCompiledModule(
|
||||||
|
this: *const WasmModuleObject,
|
||||||
|
) -> *mut InternalCompiledWasmModule;
|
||||||
|
|
||||||
|
fn v8__CompiledWasmModule__GetWireBytesRef(
|
||||||
|
this: *mut InternalCompiledWasmModule,
|
||||||
|
length: *mut isize,
|
||||||
|
) -> *const u8;
|
||||||
|
fn v8__CompiledWasmModule__DELETE(this: *mut InternalCompiledWasmModule);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5408,3 +5408,65 @@ fn counter_lookup_callback() {
|
||||||
|
|
||||||
assert_ne!(count, 0);
|
assert_ne!(count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compiled_wasm_module() {
|
||||||
|
let _setup_guard = setup();
|
||||||
|
|
||||||
|
let compiled_module = {
|
||||||
|
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 module: v8::Local<v8::WasmModuleObject> = eval(
|
||||||
|
scope,
|
||||||
|
r#"
|
||||||
|
new WebAssembly.Module(Uint8Array.from([
|
||||||
|
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x07, 0x03, 0x66, 0x6F, 0x6F, 0x62, 0x61, 0x72
|
||||||
|
]));
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
module.get_compiled_module()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled_module.get_wire_bytes_ref(),
|
||||||
|
&[
|
||||||
|
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x66,
|
||||||
|
0x6F, 0x6F, 0x62, 0x61, 0x72
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
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 module =
|
||||||
|
v8::WasmModuleObject::from_compiled_module(scope, &compiled_module)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let key = v8::String::new(scope, "module").unwrap().into();
|
||||||
|
global.set(scope, key, module.into());
|
||||||
|
|
||||||
|
let foo_ab: v8::Local<v8::ArrayBuffer> =
|
||||||
|
eval(scope, "WebAssembly.Module.customSections(module, 'foo')[0]")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
let foo_bs = foo_ab.get_backing_store();
|
||||||
|
let foo_section = unsafe {
|
||||||
|
std::slice::from_raw_parts(foo_bs.data() as *mut u8, foo_bs.byte_length())
|
||||||
|
};
|
||||||
|
assert_eq!(foo_section, b"bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue