mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-08 20:16:41 -05: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);
|
||||
}
|
||||
} // 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! { SymbolObject for SymbolObject use identity }
|
||||
|
||||
/// An instance of WebAssembly.Module.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct WasmModuleObject(Opaque);
|
||||
|
|
|
@ -141,6 +141,7 @@ pub use value_deserializer::ValueDeserializerImpl;
|
|||
pub use value_serializer::ValueSerializer;
|
||||
pub use value_serializer::ValueSerializerHelper;
|
||||
pub use value_serializer::ValueSerializerImpl;
|
||||
pub use wasm::CompiledWasmModule;
|
||||
pub use wasm::WasmStreaming;
|
||||
|
||||
// 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::scope::CallbackScope;
|
||||
use crate::scope::HandleScope;
|
||||
use crate::support::Opaque;
|
||||
use crate::support::UnitType;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
use crate::Value;
|
||||
use crate::WasmModuleObject;
|
||||
use std::ptr::null;
|
||||
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)
|
||||
where
|
||||
F: UnitType + Fn(&mut HandleScope, Local<Value>, WasmStreaming),
|
||||
|
@ -102,4 +164,18 @@ extern "C" {
|
|||
this: *mut WasmStreamingSharedPtr,
|
||||
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);
|
||||
}
|
||||
|
||||
#[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