11// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
22
3+ use std:: ffi:: c_void;
4+ use std:: ptr:: null;
5+ use std:: ptr:: null_mut;
6+
37use crate :: ArrayBuffer ;
8+ use crate :: Isolate ;
49use crate :: Local ;
510use crate :: PinScope ;
611use crate :: Value ;
@@ -18,8 +23,6 @@ use crate::support::Opaque;
1823use crate :: support:: ToCFn ;
1924use crate :: support:: UnitType ;
2025use crate :: support:: char;
21- use std:: ptr:: null;
22- use std:: ptr:: null_mut;
2326
2427// Type-erased std::shared_ptr<v8::WasmStreaming>. Assumes it's safe
2528// to move around (no backlinks). Not generally true for shared_ptrs
@@ -275,6 +278,194 @@ impl Drop for CompiledWasmModule {
275278 }
276279}
277280
281+ // Type-erased v8::WasmModuleCompilation allocated on the C++ heap.
282+ #[ repr( C ) ]
283+ struct InternalWasmModuleCompilation ( Opaque ) ;
284+
285+ /// An interface for asynchronous WebAssembly module compilation, to be used
286+ /// e.g. for implementing source phase imports.
287+ ///
288+ /// Note: This interface is experimental and can change or be removed without
289+ /// notice.
290+ pub struct WasmModuleCompilation ( * mut InternalWasmModuleCompilation ) ;
291+
292+ // OnBytesReceived can be called from any thread per V8 documentation.
293+ unsafe impl Send for WasmModuleCompilation { }
294+
295+ impl WasmModuleCompilation {
296+ /// Start an asynchronous module compilation. This can be called on any
297+ /// thread.
298+ #[ inline( always) ]
299+ pub fn new ( ) -> Self {
300+ unsafe { WasmModuleCompilation ( v8__WasmModuleCompilation__NEW ( ) ) }
301+ }
302+
303+ /// Pass a new chunk of bytes to WebAssembly compilation. The buffer is
304+ /// owned by the caller and will not be accessed after this call returns.
305+ /// Can be called from any thread.
306+ #[ inline( always) ]
307+ pub fn on_bytes_received ( & mut self , data : & [ u8 ] ) {
308+ unsafe {
309+ v8__WasmModuleCompilation__OnBytesReceived (
310+ self . 0 ,
311+ data. as_ptr ( ) ,
312+ data. len ( ) ,
313+ ) ;
314+ }
315+ }
316+
317+ /// Finish compilation. Must be called on the main thread after all bytes
318+ /// were passed to [`Self::on_bytes_received`].
319+ ///
320+ /// The `resolution_callback` will eventually be called with either the
321+ /// compiled module or a compilation error. The callback receives `&Isolate`
322+ /// so that [`crate::Global`] handles can be created from the [`Local`]
323+ /// handles to persist them beyond the callback.
324+ ///
325+ /// Must not be called after [`Self::abort`].
326+ #[ inline( always) ]
327+ pub fn finish (
328+ self ,
329+ scope : & mut PinScope ,
330+ caching_callback : Option < ModuleCachingCallback > ,
331+ resolution_callback : impl FnOnce (
332+ & Isolate ,
333+ Result < Local < ' _ , WasmModuleObject > , Local < ' _ , Value > > ,
334+ ) + ' static ,
335+ ) {
336+ // Double-box: the outer Box gives us a thin pointer suitable for void*.
337+ let boxed: Box <
338+ Box <
339+ dyn FnOnce (
340+ & Isolate ,
341+ Result < Local < ' _ , WasmModuleObject > , Local < ' _ , Value > > ,
342+ ) ,
343+ > ,
344+ > = Box :: new ( Box :: new ( resolution_callback) ) ;
345+ let data = Box :: into_raw ( boxed) as * mut c_void ;
346+
347+ unsafe {
348+ v8__WasmModuleCompilation__Finish (
349+ self . 0 ,
350+ scope. get_isolate_ptr ( ) ,
351+ caching_callback,
352+ resolution_trampoline,
353+ data,
354+ ) ;
355+ }
356+ }
357+
358+ /// Abort compilation. Can be called from any thread.
359+ /// Must not be called repeatedly, or after [`Self::finish`].
360+ #[ inline( always) ]
361+ pub fn abort ( self ) {
362+ unsafe { v8__WasmModuleCompilation__Abort ( self . 0 ) }
363+ }
364+
365+ /// Mark that the embedder has (potentially) cached compiled module bytes
366+ /// (i.e. a serialized [`CompiledWasmModule`]) that could match this
367+ /// compilation request. This will cause V8 to skip streaming compilation.
368+ /// The embedder should then pass a caching callback to [`Self::finish`].
369+ #[ inline( always) ]
370+ pub fn set_has_compiled_module_bytes ( & mut self ) {
371+ unsafe {
372+ v8__WasmModuleCompilation__SetHasCompiledModuleBytes ( self . 0 ) ;
373+ }
374+ }
375+
376+ /// Sets a callback which is called whenever a significant number of new
377+ /// functions are ready for serialization.
378+ #[ inline( always) ]
379+ pub fn set_more_functions_can_be_serialized_callback (
380+ & mut self ,
381+ callback : impl Fn ( CompiledWasmModule ) + Send + ' static ,
382+ ) {
383+ let boxed: Box < Box < dyn Fn ( CompiledWasmModule ) + Send > > =
384+ Box :: new ( Box :: new ( callback) ) ;
385+ let data = Box :: into_raw ( boxed) as * mut c_void ;
386+
387+ unsafe {
388+ v8__WasmModuleCompilation__SetMoreFunctionsCanBeSerializedCallback (
389+ self . 0 ,
390+ serialization_trampoline,
391+ data,
392+ drop_serialization_data,
393+ ) ;
394+ }
395+ }
396+
397+ /// Sets the UTF-8 encoded source URL for the `Script` object. This must
398+ /// be called before [`Self::finish`].
399+ #[ inline( always) ]
400+ pub fn set_url ( & mut self , url : & str ) {
401+ // V8 requires the url to be null terminated.
402+ let null_terminated_url = format ! ( "{url}\0 " ) ;
403+ unsafe {
404+ v8__WasmModuleCompilation__SetUrl (
405+ self . 0 ,
406+ null_terminated_url. as_ptr ( ) as * const char ,
407+ url. len ( ) ,
408+ ) ;
409+ }
410+ }
411+ }
412+
413+ impl Default for WasmModuleCompilation {
414+ fn default ( ) -> Self {
415+ Self :: new ( )
416+ }
417+ }
418+
419+ impl Drop for WasmModuleCompilation {
420+ fn drop ( & mut self ) {
421+ unsafe { v8__WasmModuleCompilation__DELETE ( self . 0 ) }
422+ }
423+ }
424+
425+ unsafe extern "C" fn resolution_trampoline (
426+ data : * mut c_void ,
427+ isolate : * mut RealIsolate ,
428+ module : * const WasmModuleObject ,
429+ error : * const Value ,
430+ ) {
431+ let callback: Box <
432+ Box <
433+ dyn FnOnce (
434+ & Isolate ,
435+ Result < Local < ' _ , WasmModuleObject > , Local < ' _ , Value > > ,
436+ ) ,
437+ > ,
438+ > = unsafe { Box :: from_raw ( data as * mut _ ) } ;
439+ let isolate = unsafe { Isolate :: from_raw_ptr ( isolate) } ;
440+ if !module. is_null ( ) {
441+ callback (
442+ & isolate,
443+ Ok ( unsafe { Local :: from_raw ( module) } . unwrap ( ) ) ,
444+ ) ;
445+ } else {
446+ callback (
447+ & isolate,
448+ Err ( unsafe { Local :: from_raw ( error) } . unwrap ( ) ) ,
449+ ) ;
450+ }
451+ }
452+
453+ unsafe extern "C" fn serialization_trampoline (
454+ data : * mut c_void ,
455+ compiled_module : * mut InternalCompiledWasmModule ,
456+ ) {
457+ let callback = unsafe {
458+ & * * ( data as * const Box < dyn Fn ( CompiledWasmModule ) + Send > )
459+ } ;
460+ callback ( CompiledWasmModule ( compiled_module) ) ;
461+ }
462+
463+ unsafe extern "C" fn drop_serialization_data ( data : * mut c_void ) {
464+ let _ = unsafe {
465+ Box :: from_raw ( data as * mut Box < dyn Fn ( CompiledWasmModule ) + Send > )
466+ } ;
467+ }
468+
278469impl WasmMemoryObject {
279470 /// Returns underlying ArrayBuffer.
280471 #[ inline( always) ]
@@ -380,4 +571,46 @@ unsafe extern "C" {
380571 fn v8__WasmMemoryObject__Buffer (
381572 this : * const WasmMemoryObject ,
382573 ) -> * mut ArrayBuffer ;
574+
575+ fn v8__WasmModuleCompilation__NEW ( ) -> * mut InternalWasmModuleCompilation ;
576+ fn v8__WasmModuleCompilation__DELETE (
577+ this : * mut InternalWasmModuleCompilation ,
578+ ) ;
579+ fn v8__WasmModuleCompilation__OnBytesReceived (
580+ this : * mut InternalWasmModuleCompilation ,
581+ bytes : * const u8 ,
582+ size : usize ,
583+ ) ;
584+ fn v8__WasmModuleCompilation__Finish (
585+ this : * mut InternalWasmModuleCompilation ,
586+ isolate : * mut RealIsolate ,
587+ caching_callback : Option < ModuleCachingCallback > ,
588+ resolution_callback : unsafe extern "C" fn (
589+ * mut c_void ,
590+ * mut RealIsolate ,
591+ * const WasmModuleObject ,
592+ * const Value ,
593+ ) ,
594+ resolution_data : * mut c_void ,
595+ ) ;
596+ fn v8__WasmModuleCompilation__Abort (
597+ this : * mut InternalWasmModuleCompilation ,
598+ ) ;
599+ fn v8__WasmModuleCompilation__SetHasCompiledModuleBytes (
600+ this : * mut InternalWasmModuleCompilation ,
601+ ) ;
602+ fn v8__WasmModuleCompilation__SetMoreFunctionsCanBeSerializedCallback (
603+ this : * mut InternalWasmModuleCompilation ,
604+ callback : unsafe extern "C" fn (
605+ * mut c_void ,
606+ * mut InternalCompiledWasmModule ,
607+ ) ,
608+ data : * mut c_void ,
609+ drop_data : unsafe extern "C" fn ( * mut c_void ) ,
610+ ) ;
611+ fn v8__WasmModuleCompilation__SetUrl (
612+ this : * mut InternalWasmModuleCompilation ,
613+ url : * const char ,
614+ length : usize ,
615+ ) ;
383616}
0 commit comments