Search code examples
javascriptfirefoxasm.js

Unable to work around Firefox's AMS.js link restriction


I received the error:

asm.js link error: As a temporary limitation, modules cannot be linked more than once.
This limitation should be removed in a future release. To work around this, compile a second module (e.g., using the Function constructor).

I haven't been able to find any documentation on this workaround. Does anyone have a working example?

Not my code, but this suffers from the same issue: http://jsperf.com/simplex-noise-comparison-asm View the issue in the console using FireFox.


Solution

  • I was able to solve this myself. Here's a JSFiddle link for anyone who has the same issue: http://jsfiddle.net/QLtMB/

    // Store template as actual function, do not use real pragma to avoid compile
    var asmTemplate = function MyAsmModule( stdlib, foreign, heap ) {
       "asm template";
    
       var HEAP = new stdlib.Uint8Array(heap);
       var _sqrt = stdlib.Math.sqrt;
       var _sin = stdlib.Math.sin;
       var _cos = stdlib.Math.cos;
    
    
       function fastSqr( x ) {
          x = +x;
          return +(x*x);
       }
    
       function fastSqrt( x ) {
          x = +x;
          return +_sqrt( x );
       }
    
       function fastSin( x ) {
          x = +x;
          return +_sin( x );
       }
    
       function fastCos( x ) {
          x = +x;
          return +_cos( x );
       }
    
       function fastTest( x ) {
          x = +x;
          return +fastSqr( 2.17 * (+fastSqrt( 0.75 * +fastSin( x ) + 0.25 * +fastCos( x ) )) );
       }
    
       return { sqrt: fastSqrt, sin: fastSin, cos: fastCos, test: fastTest };
    }
    
    // Generate source string once, replace with real pragma.
    asmTemplate = asmTemplate.toString().replace('asm template', 'use asm');
    
    function createASM(buffer) {
        window.asmBufferExport = buffer;
        return Function(asmTemplate + "\nreturn MyAsmModule( Function( 'return this;' )(), null, asmBufferExport.buffer );")();
    }
    
    var Asm = createASM(new Uint8Array(4 * 1024));
    var Asm2 = createASM(new Uint8Array(4 * 1024));
    

    As a bonus, this will round your heap size up to asm.js standards:

        var size = <actual size>;
        // Round up to multiple of 4096
        var remainder = size % 4096;
        size = remainder ? size + 4096 - remainder : size;
        // Round up to the nearest power of 2
        size--;
        size |= size >> 1;  // handle  2 bit numbers
        size |= size >> 2;  // handle  4 bit numbers
        size |= size >> 4;  // handle  8 bit numbers
        size |= size >> 8;  // handle 16 bit numbers
        size |= size >> 16; // handle 32 bit numbers
        size++;
    

    Resources: