@@ -599,48 +599,128 @@ Module['registerFunctions'] = registerFunctions;
599599#endif // RELOCATABLE
600600#endif // EMULATED_FUNCTION_POINTERS
601601
602- #if EMULATED_FUNCTION_POINTERS == 0
603- #if WASM_BACKEND && RESERVED_FUNCTION_POINTERS
604- var jsCallStartIndex = { { { JSCALL_START_INDEX } } } ;
605- var jsCallSigOrder = { { { JSON . stringify ( JSCALL_SIG_ORDER ) } } } ;
606- var jsCallNumSigs = Object . keys ( jsCallSigOrder ) . length ;
607- var functionPointers = new Array ( jsCallNumSigs * { { { RESERVED_FUNCTION_POINTERS } } } ) ;
608- #else // WASM_BACKEND && RESERVED_FUNCTION_POINTERS == 0
602+ #if ! WASM_BACKEND && EMULATED_FUNCTION_POINTERS == 0
609603var jsCallStartIndex = 1 ;
610604var functionPointers = new Array ( { { { RESERVED_FUNCTION_POINTERS } } } ) ;
611- #endif // WASM_BACKEND && RESERVED_FUNCTION_POINTERS
612- #endif // EMULATED_FUNCTION_POINTERS == 0
605+ #endif // !WASM_BACKEND && EMULATED_FUNCTION_POINTERS == 0
613606
614607#if WASM
608+ // Wraps a JS function as a wasm function with a given signature.
609+ // In the future, we may get a WebAssembly.Function constructor. Until then,
610+ // we create a wasm module that takes the JS function as an import with a given
611+ // signature, and re-exports that as a wasm function.
612+ function convertJsFunctionToWasm ( func , sig ) {
613+ // The module is static, with the exception of the type section, which is
614+ // generated based on the signature passed in.
615+ var typeSection = [
616+ 0x01 , // id: section,
617+ 0x00 , // length: 0 (placeholder)
618+ 0x01 , // count: 1
619+ 0x60 , // form: func
620+ ] ;
621+ var sigRet = sig . slice ( 0 , 1 ) ;
622+ var sigParam = sig . slice ( 1 ) ;
623+ var typeCodes = {
624+ 'i' : 0x7f , // i32
625+ 'j' : 0x7e , // i64
626+ 'f' : 0x7d , // f32
627+ 'd' : 0x7c , // f64
628+ } ;
629+
630+ // Parameters, length + signatures
631+ typeSection . push ( sigParam . length ) ;
632+ for ( var i = 0 ; i < sigParam . length ; ++ i ) {
633+ typeSection . push ( typeCodes [ sigParam [ i ] ] ) ;
634+ }
635+
636+ // Return values, length + signatures
637+ // With no multi-return in MVP, either 0 (void) or 1 (anything else)
638+ if ( sigRet == 'v' ) {
639+ typeSection . push ( 0x00 ) ;
640+ } else {
641+ typeSection = typeSection . concat ( [ 0x01 , typeCodes [ sigRet ] ] ) ;
642+ }
643+
644+ // Write the overall length of the type section back into the section header
645+ // (excepting the 2 bytes for the section id and length)
646+ typeSection [ 1 ] = typeSection . length - 2 ;
647+
648+ // Rest of the module is static
649+ var bytes = new Uint8Array ( [
650+ 0x00 , 0x61 , 0x73 , 0x6d , // magic ("\0asm")
651+ 0x01 , 0x00 , 0x00 , 0x00 , // version: 1
652+ ] . concat ( typeSection , [
653+ 0x02 , 0x07 , // import section
654+ // (import "e" "f" (func 0 (type 0)))
655+ 0x01 , 0x01 , 0x65 , 0x01 , 0x66 , 0x00 , 0x00 ,
656+ 0x07 , 0x05 , // export section
657+ // (export "f" (func 0 (type 0)))
658+ 0x01 , 0x01 , 0x66 , 0x00 , 0x00 ,
659+ ] ) ) ;
660+
661+ // We can compile this wasm module synchronously because it is very small.
662+ // This accepts an import (at "e.f"), that it reroutes to an export (at "f")
663+ var module = new WebAssembly . Module ( bytes ) ;
664+ var instance = new WebAssembly . Instance ( module , {
665+ e : {
666+ f : func
667+ }
668+ } ) ;
669+ var wrappedFunc = instance . exports . f ;
670+ return wrappedFunc ;
671+ }
672+
615673// Add a wasm function to the table.
616- // Attempting to call this with JS function will cause of table.set() to fail
617- function addWasmFunction ( func ) {
674+ function addFunctionWasm ( func , sig ) {
618675 var table = wasmTable ;
619676 var ret = table . length ;
620- table . grow ( 1 ) ;
621- table . set ( ret , func ) ;
677+
678+ // Grow the table
679+ try {
680+ table . grow ( 1 ) ;
681+ } catch ( err ) {
682+ if ( ! err instanceof RangeError ) {
683+ throw err ;
684+ }
685+ throw 'Unable to grow wasm table. Use a higher value for RESERVED_FUNCTION_POINTERS or set ALLOW_TABLE_GROWTH.' ;
686+ }
687+
688+ // Insert new element
689+ try {
690+ // Attempting to call this with JS function will cause of table.set() to fail
691+ table . set ( ret , func ) ;
692+ } catch ( err ) {
693+ if ( ! err instanceof TypeError ) {
694+ throw err ;
695+ }
696+ assert ( typeof sig !== 'undefined' , 'Missing signature argument to addFunction' ) ;
697+ var wrapped = convertJsFunctionToWasm ( func , sig ) ;
698+ table . set ( ret , wrapped ) ;
699+ }
700+
622701 return ret ;
623702}
703+
704+ function removeFunctionWasm ( index ) {
705+ // TODO(sbc): Look into implementing this to allow re-using of table slots
706+ }
624707#endif
625708
626- // 'sig' parameter is currently only used for LLVM backend under certain
627- // circumstance: RESERVED_FUNCTION_POINTERS=1, EMULATED_FUNCTION_POINTERS=0 .
709+ // 'sig' parameter is required for the llvm backend but only when func is not
710+ // already a WebAssembly function .
628711function addFunction ( func , sig ) {
629712#if ASSERTIONS == 2
630713 if ( typeof sig === 'undefined' ) {
631714 err ( 'warning: addFunction(): You should provide a wasm function signature string as a second argument. This is not necessary for asm.js and asm2wasm, but can be required for the LLVM wasm backend, so it is recommended for full portability.' ) ;
632715 }
633716#endif // ASSERTIONS
634717
718+ #if WASM_BACKEND
719+ return addFunctionWasm ( func , sig ) ;
720+ #else
721+
635722#if EMULATED_FUNCTION_POINTERS == 0
636- #if WASM_BACKEND && RESERVED_FUNCTION_POINTERS
637- assert ( typeof sig !== 'undefined' ,
638- 'Second argument of addFunction should be a wasm function signature ' +
639- 'string' ) ;
640- var base = jsCallSigOrder [ sig ] * { { { RESERVED_FUNCTION_POINTERS } } } ;
641- #else // WASM_BACKEND && RESERVED_FUNCTION_POINTERS == 0
642723 var base = 0 ;
643- #endif // WASM_BACKEND && RESERVED_FUNCTION_POINTERS
644724 for ( var i = base ; i < base + { { { RESERVED_FUNCTION_POINTERS } } } ; i ++ ) {
645725 if ( ! functionPointers [ i ] ) {
646726 functionPointers [ i ] = func ;
@@ -652,13 +732,9 @@ function addFunction(func, sig) {
652732#else // EMULATED_FUNCTION_POINTERS == 0
653733
654734#if WASM
655- // assume we have been passed a wasm function and can add it to the table
656- // directly.
657- // TODO(sbc): This assumtion is most likely not valid. Look into ways of
658- // creating wasm functions based on JS functions as input.
659- return addWasmFunction ( func ) ;
735+ return addFunctionWasm ( func , sig ) ;
660736#else
661- alignFunctionTables ( ) ; // XXX we should rely on this being an invariant
737+ alignFunctionTables ( ) ; // TODO: we should rely on this being an invariant
662738 var tables = getFunctionTables ( ) ;
663739 var ret = - 1 ;
664740 for ( var sig in tables ) {
@@ -668,21 +744,32 @@ function addFunction(func, sig) {
668744 table . push ( func ) ;
669745 }
670746 return ret ;
671- #endif
747+ #endif // WASM
672748
673749#endif // EMULATED_FUNCTION_POINTERS == 0
750+ #endif // WASM_BACKEND
674751}
675752
676753function removeFunction ( index ) {
754+ #if WASM_BACKEND
755+ removeFunctionWasm ( index ) ;
756+ #else
757+
677758#if EMULATED_FUNCTION_POINTERS == 0
678759 functionPointers [ index - jsCallStartIndex ] = null ;
760+ #else
761+ #if WASM
762+ removeFunctionWasm ( index ) ;
679763#else
680764 alignFunctionTables ( ) ; // XXX we should rely on this being an invariant
681765 var tables = getFunctionTables ( ) ;
682766 for ( var sig in tables ) {
683767 tables [ sig ] [ index ] = null ;
684768 }
685- #endif
769+ #endif // WASM
770+
771+ #endif // EMULATE_FUNCTION_POINTER_CASTS == 0
772+ #endif // WASM_BACKEND
686773}
687774
688775var funcWrappers = { } ;
0 commit comments