2021-02-13 12:31:18 +00:00
|
|
|
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
2020-12-31 15:06:29 +00:00
|
|
|
|
|
|
|
use crate::function::FunctionCallbackArguments;
|
|
|
|
use crate::function::FunctionCallbackInfo;
|
|
|
|
use crate::scope::CallbackScope;
|
|
|
|
use crate::scope::HandleScope;
|
2021-09-22 18:34:39 +00:00
|
|
|
use crate::support::char;
|
2021-09-17 16:02:40 +00:00
|
|
|
use crate::support::Opaque;
|
2020-12-31 15:06:29 +00:00
|
|
|
use crate::support::UnitType;
|
2022-11-23 16:14:37 +00:00
|
|
|
use crate::ArrayBuffer;
|
2020-12-31 15:06:29 +00:00
|
|
|
use crate::Isolate;
|
|
|
|
use crate::Local;
|
|
|
|
use crate::Value;
|
2022-11-23 16:14:37 +00:00
|
|
|
use crate::WasmMemoryObject;
|
2021-09-17 16:02:40 +00:00
|
|
|
use crate::WasmModuleObject;
|
2020-12-31 15:06:29 +00:00
|
|
|
use std::ptr::null;
|
|
|
|
use std::ptr::null_mut;
|
|
|
|
|
|
|
|
// Type-erased std::shared_ptr<v8::WasmStreaming>. Assumes it's safe
|
|
|
|
// to move around (no backlinks). Not generally true for shared_ptrs
|
|
|
|
// but it is in this case - other shared_ptrs that point to the same
|
|
|
|
// v8::WasmStreaming exist but are managed by V8 and don't leak out.
|
|
|
|
//
|
|
|
|
// We don't use crate::support::SharedPtr because it only allows
|
|
|
|
// immutable borrows and derefs to avoid aliasing but that's not
|
|
|
|
// a problem here, only a single instance outside V8 exists.
|
|
|
|
//
|
|
|
|
// Note: uses *mut u8 rather than e.g. usize to enforce !Send and !Sync.
|
|
|
|
#[repr(C)]
|
|
|
|
struct WasmStreamingSharedPtr([*mut u8; 2]);
|
|
|
|
|
|
|
|
/// The V8 interface for WebAssembly streaming compilation.
|
|
|
|
/// When streaming compilation is initiated, V8 passes a [Self]
|
|
|
|
/// object to the embedder such that the embedder can pass the
|
|
|
|
/// input bytes for streaming compilation to V8.
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct WasmStreaming(WasmStreamingSharedPtr);
|
|
|
|
|
|
|
|
impl WasmStreaming {
|
|
|
|
/// Pass a new chunk of bytes to WebAssembly streaming compilation.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2020-12-31 15:06:29 +00:00
|
|
|
pub fn on_bytes_received(&mut self, data: &[u8]) {
|
|
|
|
unsafe {
|
|
|
|
v8__WasmStreaming__OnBytesReceived(&mut self.0, data.as_ptr(), data.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Should be called after all received bytes where passed to
|
|
|
|
/// [`Self::on_bytes_received()`] to tell V8 that there will be no
|
|
|
|
/// more bytes. Does not have to be called after [`Self::abort()`]
|
|
|
|
/// has been called already.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2020-12-31 15:06:29 +00:00
|
|
|
pub fn finish(mut self) {
|
|
|
|
unsafe { v8__WasmStreaming__Finish(&mut self.0) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Abort streaming compilation. If {exception} has a value, then the promise
|
|
|
|
/// associated with streaming compilation is rejected with that value. If
|
|
|
|
/// {exception} does not have value, the promise does not get rejected.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2020-12-31 15:06:29 +00:00
|
|
|
pub fn abort(mut self, exception: Option<Local<Value>>) {
|
|
|
|
let exception = exception.map(|v| &*v as *const Value).unwrap_or(null());
|
|
|
|
unsafe { v8__WasmStreaming__Abort(&mut self.0, exception) }
|
|
|
|
}
|
2021-09-22 18:34:39 +00:00
|
|
|
|
|
|
|
/// Sets the UTF-8 encoded source URL for the `Script` object. This must be
|
|
|
|
/// called before [`Self::finish()`].
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2021-09-22 18:34:39 +00:00
|
|
|
pub fn set_url(&mut self, url: &str) {
|
2021-12-13 04:12:24 +00:00
|
|
|
// Although not documented, V8 requires the url to be null terminated.
|
|
|
|
// See https://chromium-review.googlesource.com/c/v8/v8/+/3289148.
|
|
|
|
let null_terminated_url = format!("{}\0", url);
|
2021-09-22 18:34:39 +00:00
|
|
|
unsafe {
|
|
|
|
v8__WasmStreaming__SetUrl(
|
|
|
|
&mut self.0,
|
2021-12-13 04:12:24 +00:00
|
|
|
null_terminated_url.as_ptr() as *const char,
|
2021-09-22 18:34:39 +00:00
|
|
|
url.len(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2020-12-31 15:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for WasmStreaming {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { v8__WasmStreaming__shared_ptr_DESTRUCT(&mut self.0) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-17 16:02:40 +00:00
|
|
|
impl WasmModuleObject {
|
|
|
|
/// Efficiently re-create a WasmModuleObject, without recompiling, from
|
|
|
|
/// a CompiledWasmModule.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2021-09-17 16:02:40 +00:00
|
|
|
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.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2021-09-17 16:02:40 +00:00
|
|
|
pub fn get_compiled_module(&self) -> CompiledWasmModule {
|
|
|
|
let ptr = unsafe { v8__WasmModuleObject__GetCompiledModule(self) };
|
|
|
|
CompiledWasmModule(ptr)
|
|
|
|
}
|
2022-05-07 16:02:39 +00:00
|
|
|
|
|
|
|
/// Compile a Wasm module from the provided uncompiled bytes.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2022-05-07 16:02:39 +00:00
|
|
|
pub fn compile<'s>(
|
|
|
|
scope: &mut HandleScope<'s>,
|
|
|
|
wire_bytes: &[u8],
|
|
|
|
) -> Option<Local<'s, WasmModuleObject>> {
|
|
|
|
unsafe {
|
|
|
|
scope.cast_local(|sd| {
|
|
|
|
v8__WasmModuleObject__Compile(
|
|
|
|
sd.get_isolate_ptr(),
|
|
|
|
wire_bytes.as_ptr(),
|
|
|
|
wire_bytes.len(),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-09-17 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2021-09-17 16:02:40 +00:00
|
|
|
pub fn get_wire_bytes_ref(&self) -> &[u8] {
|
|
|
|
let mut len = 0isize;
|
|
|
|
unsafe {
|
|
|
|
let ptr = v8__CompiledWasmModule__GetWireBytesRef(self.0, &mut len);
|
|
|
|
std::slice::from_raw_parts(ptr, len.try_into().unwrap())
|
|
|
|
}
|
|
|
|
}
|
2021-09-22 18:34:39 +00:00
|
|
|
|
2022-09-21 02:45:33 +00:00
|
|
|
#[inline(always)]
|
2021-09-22 18:34:39 +00:00
|
|
|
pub fn source_url(&self) -> &str {
|
|
|
|
let mut len = 0;
|
|
|
|
unsafe {
|
|
|
|
let ptr = v8__CompiledWasmModule__SourceUrl(self.0, &mut len);
|
2024-03-01 17:28:17 +00:00
|
|
|
let bytes = std::slice::from_raw_parts(ptr as _, len);
|
2021-09-22 18:34:39 +00:00
|
|
|
std::str::from_utf8_unchecked(bytes)
|
|
|
|
}
|
|
|
|
}
|
2021-09-17 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-23 16:14:37 +00:00
|
|
|
impl WasmMemoryObject {
|
|
|
|
/// Returns underlying ArrayBuffer.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn buffer(&self) -> Local<ArrayBuffer> {
|
|
|
|
unsafe { Local::from_raw(v8__WasmMemoryObject__Buffer(self)) }.unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-31 15:06:29 +00:00
|
|
|
pub(crate) fn trampoline<F>() -> extern "C" fn(*const FunctionCallbackInfo)
|
|
|
|
where
|
|
|
|
F: UnitType + Fn(&mut HandleScope, Local<Value>, WasmStreaming),
|
|
|
|
{
|
|
|
|
extern "C" fn c_fn<F>(info: *const FunctionCallbackInfo)
|
|
|
|
where
|
|
|
|
F: UnitType + Fn(&mut HandleScope, Local<Value>, WasmStreaming),
|
|
|
|
{
|
2022-10-19 19:41:22 +00:00
|
|
|
let info = unsafe { &*info };
|
|
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
|
|
let args = FunctionCallbackArguments::from_function_callback_info(info);
|
|
|
|
let data = args.data();
|
2020-12-31 15:06:29 +00:00
|
|
|
let zero = null_mut();
|
|
|
|
let mut that = WasmStreamingSharedPtr([zero, zero]);
|
|
|
|
unsafe {
|
2022-10-19 19:41:22 +00:00
|
|
|
v8__WasmStreaming__Unpack(scope.get_isolate_ptr(), &*data, &mut that)
|
2020-12-31 15:06:29 +00:00
|
|
|
};
|
|
|
|
let source = args.get(0);
|
|
|
|
(F::get())(scope, source, WasmStreaming(that));
|
|
|
|
}
|
|
|
|
c_fn::<F>
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn v8__WasmStreaming__Unpack(
|
|
|
|
isolate: *mut Isolate,
|
|
|
|
value: *const Value,
|
|
|
|
that: *mut WasmStreamingSharedPtr, // Out parameter.
|
|
|
|
);
|
|
|
|
fn v8__WasmStreaming__shared_ptr_DESTRUCT(this: *mut WasmStreamingSharedPtr);
|
|
|
|
fn v8__WasmStreaming__OnBytesReceived(
|
|
|
|
this: *mut WasmStreamingSharedPtr,
|
|
|
|
data: *const u8,
|
|
|
|
len: usize,
|
|
|
|
);
|
|
|
|
fn v8__WasmStreaming__Finish(this: *mut WasmStreamingSharedPtr);
|
|
|
|
fn v8__WasmStreaming__Abort(
|
|
|
|
this: *mut WasmStreamingSharedPtr,
|
|
|
|
exception: *const Value,
|
|
|
|
);
|
2021-09-22 18:34:39 +00:00
|
|
|
fn v8__WasmStreaming__SetUrl(
|
|
|
|
this: *mut WasmStreamingSharedPtr,
|
|
|
|
url: *const char,
|
|
|
|
len: usize,
|
|
|
|
);
|
2021-09-17 16:02:40 +00:00
|
|
|
|
|
|
|
fn v8__WasmModuleObject__FromCompiledModule(
|
|
|
|
isolate: *mut Isolate,
|
|
|
|
compiled_module: *const InternalCompiledWasmModule,
|
|
|
|
) -> *const WasmModuleObject;
|
|
|
|
fn v8__WasmModuleObject__GetCompiledModule(
|
|
|
|
this: *const WasmModuleObject,
|
|
|
|
) -> *mut InternalCompiledWasmModule;
|
2022-05-07 16:02:39 +00:00
|
|
|
fn v8__WasmModuleObject__Compile(
|
|
|
|
isolate: *mut Isolate,
|
|
|
|
wire_bytes_data: *const u8,
|
|
|
|
length: usize,
|
|
|
|
) -> *mut WasmModuleObject;
|
2021-09-17 16:02:40 +00:00
|
|
|
|
|
|
|
fn v8__CompiledWasmModule__GetWireBytesRef(
|
|
|
|
this: *mut InternalCompiledWasmModule,
|
|
|
|
length: *mut isize,
|
|
|
|
) -> *const u8;
|
2021-09-22 18:34:39 +00:00
|
|
|
fn v8__CompiledWasmModule__SourceUrl(
|
|
|
|
this: *mut InternalCompiledWasmModule,
|
|
|
|
length: *mut usize,
|
|
|
|
) -> *const char;
|
2021-09-17 16:02:40 +00:00
|
|
|
fn v8__CompiledWasmModule__DELETE(this: *mut InternalCompiledWasmModule);
|
2022-11-23 16:14:37 +00:00
|
|
|
|
|
|
|
fn v8__WasmMemoryObject__Buffer(
|
|
|
|
this: *const WasmMemoryObject,
|
|
|
|
) -> *mut ArrayBuffer;
|
2020-12-31 15:06:29 +00:00
|
|
|
}
|