@@ -596,7 +596,179 @@ var LibraryDylink = {
596
596
}
597
597
} ,
598
598
#endif
599
+ $getStubImportModule__postset : `
600
+ var stubImportModuleCache = new Map();
601
+ ` ,
602
+ $getStubImportModule__deps : [
603
+ "$generateFuncType" ,
604
+ "$uleb128Encode"
605
+ ] ,
606
+ // We need to call out to JS to resolve the function, but then make the actual
607
+ // onward call from WebAssembly. The JavaScript $resolve function is
608
+ // responsible for putting the appropriate function in the table. When the sig
609
+ // is ii, the wat for the generated module looks like this:
610
+ //
611
+ // (module
612
+ // (type $r (func ))
613
+ // (type $ii (func (param i32) (result i32)))
614
+ // (import "e" "t" (table 0 funcref))
615
+ // (import "e" "r" (func $resolve))
616
+ // (global $isResolved (mut i32) i32.const 0)
617
+ //
618
+ // (func (export "o") (param $p1 i32) (result i32)
619
+ // global.get $isResolved
620
+ // i32.eqz
621
+ // if
622
+ // call $resolve
623
+ // i32.const 1
624
+ // global.set $isResolved
625
+ // end
626
+ // local.get $p1
627
+ // i32.const 0
628
+ // call_indirect (type $ii)
629
+ // )
630
+ // )
631
+ $getStubImportModule : ( sig ) = > {
632
+ var cached = stubImportModuleCache . get ( sig ) ;
633
+ if ( cached ) {
634
+ return cached ;
635
+ }
636
+ const bytes = [
637
+ 0x00 , 0x61 , 0x73 , 0x6d , // Magic number
638
+ 0x01 , 0x00 , 0x00 , 0x00 , // version 1
639
+ 0x01 , // Type section code
640
+ ] ;
641
+ var typeSectionBody = [
642
+ 0x02 , // count: 2
643
+ ] ;
644
+ generateFuncType ( 'v' , typeSectionBody ) ;
645
+ generateFuncType ( sig , typeSectionBody ) ;
646
+ uleb128Encode ( typeSectionBody . length , bytes ) ;
647
+ bytes . push ( ...typeSectionBody ) ;
648
+
649
+ // static sections
650
+ bytes . push (
651
+ // Import section
652
+ 0x02 , 0x0f ,
653
+ 0x02 , // 2 imports
654
+ 0x01 , 0x65 , // e
655
+ 0x01 , 0x74 , // t
656
+ // funcref table with no limits
657
+ 0x01 , 0x70 , 0x00 , 0x00 ,
658
+
659
+ 0x01 , 0x65 , // e
660
+ 0x01 , 0x72 , // r
661
+ 0x00 , 0x00 , // function of type 0 ('v')
662
+
663
+ // Function section
664
+ 0x03 , 0x02 ,
665
+ 0x01 , 0x01 , // One function of type 1 (sig)
666
+
667
+ // Globals section
668
+ 0x06 , 0x06 ,
669
+ 0x01 , // one global
670
+ 0x7f , 0x01 , // i32 mut
671
+ 0x41 , 0x00 , 0x0b , // initialized to i32.const 0
672
+
673
+ // Export section
674
+ 0x07 , 0x05 ,
675
+ 0x01 , // one export
676
+ 0x01 , 0x6f , // o
677
+ 0x00 , 0x01 , // function at index 1
678
+ ) ;
679
+ bytes . push ( 0x0a ) ; // Code section
680
+ var codeBody = [
681
+ 0x00 , // 0 locals
682
+ 0x23 , 0x00 , // global.get 0
683
+ 0x45 , // i32.eqz
684
+ 0x04 , // if
685
+ 0x40 , 0x10 , 0x00 , // Call function 0
686
+ 0x41 , 0x01 , // i32.const 1
687
+ 0x24 , 0x00 , // global.set 0
688
+ 0x0b , // end
689
+ ] ;
690
+ for ( let i = 0 ; i < sig . length - 1 ; i ++ ) {
691
+ codeBody . push ( 0x20 , i ) ;
692
+ }
599
693
694
+ codeBody . push (
695
+ 0x41 , 0x00 , // i32.const 0
696
+ 0x11 , 0x01 , 0x00 , // call_indirect table 0, type 0
697
+ 0x0b // end
698
+ ) ;
699
+ var codeSectionBody = [ 0x01 ] ;
700
+ uleb128Encode ( codeBody . length , codeSectionBody ) ;
701
+ codeSectionBody . push ( ...codeBody ) ;
702
+ uleb128Encode ( codeSectionBody . length , bytes ) ;
703
+ bytes . push ( ...codeSectionBody ) ;
704
+ var result = new WebAssembly . Module ( new Uint8Array ( bytes ) ) ;
705
+ stubImportModuleCache . set ( sig , result ) ;
706
+ return result ;
707
+ } ,
708
+
709
+ $wasmSigToEmscripten: ( type ) => {
710
+ var lookup = { i32 : 'i' , i64 : 'j' , f32 : 'f' , f64 : 'd' , externref : 'e' } ;
711
+ var sig = 'v' ;
712
+ if ( type . results . length ) {
713
+ sig = lookup [ type . results [ 0 ] ] ;
714
+ }
715
+ for ( var v of type . parameters ) {
716
+ sig += lookup [ v ] ;
717
+ }
718
+ return sig ;
719
+ } ,
720
+ $getStubImportResolver : ( name , sig , table , resolveSymbol ) = > {
721
+ return function r ( ) {
722
+ var res = resolveSymbol ( name ) ;
723
+ if ( res . orig ) {
724
+ res = res . orig ;
725
+ }
726
+ try {
727
+ // Attempting to call this with JS function will cause table.set() to fail
728
+ table . set ( 0 , res ) ;
729
+ } catch ( err ) {
730
+ if ( ! ( err instanceof TypeError ) ) {
731
+ throw err ;
732
+ }
733
+ var wrapped = convertJsFunctionToWasm ( res , sig ) ;
734
+ table . set ( 0 , wrapped ) ;
735
+ }
736
+ } ;
737
+ } ,
738
+ $addStubImports__deps : [
739
+ "$getStubImportModule" ,
740
+ "$wasmSigToEmscripten" ,
741
+ "$getStubImportResolver"
742
+ ] ,
743
+ $addStubImports : ( mod , stubs , resolveSymbol ) = > {
744
+ // Assumes --experimental-wasm-type-reflection to get type field of WebAssembly.Module.imports().
745
+ // TODO: Make this work without it.
746
+ for ( const { module, name, kind, type} of WebAssembly . Module . imports ( mod ) ) {
747
+ if ( module !== 'env' ) {
748
+ continue ;
749
+ }
750
+ if ( kind !== 'function' ) {
751
+ continue ;
752
+ }
753
+ if ( name in wasmImports && ! wasmImports [ name ] . stub ) {
754
+ continue ;
755
+ }
756
+ #if ! DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten'
757
+ if ( name . startsWith ( "invoke_" ) ) {
758
+ // JSPI + JS exceptions probably doesn't work but maybe nobody will
759
+ // attempt stack switch inside a try block.
760
+ stubs [ name ] = createInvokeFunction ( name . split ( '_' ) [ 1 ] ) ;
761
+ continue ;
762
+ }
763
+ #endif
764
+ var sig = wasmSigToEmscripten ( type ) ;
765
+ var mod = getStubImportModule ( sig ) ;
766
+ const t = new WebAssembly . Table ( { element : 'funcref' , initial : 1 } ) ;
767
+ const r = getStubImportResolver ( name , sig , t , resolveSymbol ) ;
768
+ const inst = new WebAssembly . Instance ( mod , { e : { t, r} } ) ;
769
+ stubs [ name ] = inst . exports . o ;
770
+ }
771
+ } ,
600
772
// Loads a side module from binary data or compiled Module. Returns the module's exports or a
601
773
// promise that resolves to its exports if the loadAsync flag is set.
602
774
$loadWebAssemblyModule__docs : `
@@ -613,6 +785,9 @@ var LibraryDylink = {
613
785
'$updateTableMap' ,
614
786
'$wasmTable' ,
615
787
'$addOnPostCtor' ,
788
+ #if JSPI
789
+ '$addStubImports' ,
790
+ #endif
616
791
] ,
617
792
$loadWebAssemblyModule : ( binary , flags , libName , localScope , handle ) = > {
618
793
#if DYLINK_DEBUG
@@ -697,6 +872,7 @@ var LibraryDylink = {
697
872
// to add the indirection for, without inspecting what A's imports
698
873
// are. To do that here, we use a JS proxy (another option would
699
874
// be to inspect the binary directly).
875
+ const stubs = { } ;
700
876
var proxyHandler = {
701
877
get ( stubs , prop ) {
702
878
// symbols that should be local to this module
@@ -728,16 +904,20 @@ var LibraryDylink = {
728
904
// Return a stub function that will resolve the symbol
729
905
// when first called.
730
906
if ( ! ( prop in stubs ) ) {
907
+ #if JSPI
908
+ throw new Error ( "Missing stub for " + prop ) ;
909
+ #else
731
910
var resolved ;
732
911
stubs [ prop ] = ( ...args ) => {
733
912
resolved ||= resolveSymbol ( prop ) ;
734
913
return resolved ( ...args ) ;
735
914
} ;
915
+ #endif
736
916
}
737
917
return stubs [ prop ] ;
738
918
}
739
919
} ;
740
- var proxy = new Proxy ( { } , proxyHandler ) ;
920
+ var proxy = new Proxy ( stubs , proxyHandler ) ;
741
921
var info = {
742
922
'GOT.mem' : new Proxy ( { } , GOTHandler ) ,
743
923
'GOT.func' : new Proxy ( { } , GOTHandler ) ,
@@ -877,16 +1057,28 @@ var LibraryDylink = {
877
1057
}
878
1058
879
1059
if ( flags . loadAsync ) {
880
- if ( binary instanceof WebAssembly . Module ) {
881
- var instance = new WebAssembly . Instance ( binary , info ) ;
882
- return Promise . resolve ( postInstantiation ( binary , instance ) ) ;
883
- }
884
- return WebAssembly . instantiate ( binary , info ) . then (
885
- ( result ) => postInstantiation ( result . module , result . instance )
886
- ) ;
1060
+ return ( async function ( ) {
1061
+ if ( binary instanceof WebAssembly . Module ) {
1062
+ #if JSPI
1063
+ addStubImports ( binary , stubs , resolveSymbol ) ;
1064
+ #endif
1065
+ var instance = new WebAssembly . Instance ( binary , info ) ;
1066
+ return postInstantiation ( binary , instance ) ;
1067
+ }
1068
+ #if JSPI
1069
+ var module = await WebAssembly . compile ( binary ) ;
1070
+ addStubImports ( module , stubs , resolveSymbol ) ;
1071
+ var instance = await WebAssembly . instantiate ( module , info ) ;
1072
+ #else
1073
+ var { module, instance} = await WebAssembly . instantiate ( binary , info ) ;
1074
+ #endif
1075
+ return postInstantiation ( module , instance ) ;
1076
+ } ) ( ) ;
887
1077
}
888
-
889
1078
var module = binary instanceof WebAssembly . Module ? binary : new WebAssembly . Module ( binary ) ;
1079
+ #if JSPI
1080
+ addStubImports ( module , stubs , resolveSymbol ) ;
1081
+ #endif
890
1082
var instance = new WebAssembly . Instance ( module , info ) ;
891
1083
return postInstantiation ( module , instance ) ;
892
1084
}
0 commit comments