├── .babelrc ├── .eslintrc.yml ├── .gitignore ├── .npmignore ├── Dockerfile ├── LICENSE ├── README.md ├── dist └── wasm-loader.js ├── example ├── .babelrc ├── Makefile ├── README.md ├── docker-compose.yml ├── hello-wasm.js ├── hello.cc ├── hello.js ├── hello.wasm ├── index.html ├── module_loader.js ├── package-lock.json ├── package.json ├── webpack.config.js └── yarn.lock ├── package-lock.json ├── package.json ├── pre.js ├── src ├── helper.js └── loader.js ├── wasm-builder.go ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": ["es2015"] } 2 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | extends: airbnb 5 | parserOptions: 6 | sourceType: module 7 | rules: 8 | indent: 9 | - error 10 | - 2 11 | linebreak-style: 12 | - error 13 | - unix 14 | quotes: 15 | - error 16 | - single 17 | semi: 18 | - error 19 | - always 20 | max-len: 21 | - 2 22 | - code: 150 23 | ignoreComments: true 24 | no-multi-spaces: 0 25 | no-param-reassign: 0 26 | no-underscore-dangle: 0 27 | no-return-assign: 0 28 | prefer-destructuring: 0 29 | key-spacing: 0 30 | arrow-body-style: 0 31 | import/no-cycle: 0 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.mem 3 | *.wast 4 | *.map 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM trzeci/emscripten:sdk-tag-1.38.8-64bit 2 | LABEL maintainer "Knocknote" 3 | 4 | RUN apt-get -qq -y update && apt-get install -y --no-install-recommends \ 5 | build-essential \ 6 | openjdk-8-jre && apt-get clean && rm -rf /var/lib/apt/lists/* 7 | 8 | RUN wget https://dl.google.com/go/go1.11.linux-amd64.tar.gz && tar -xvf go1.11.linux-amd64.tar.gz && mv go /usr/local && rm go1.11.linux-amd64.tar.gz 9 | ENV GOROOT /usr/local/go 10 | ENV GOPATH /go 11 | ENV PATH $GOPATH/bin:$GOROOT/bin:$PATH 12 | 13 | RUN git clone --recursive https://github.com/WebAssembly/wabt /src/wabt 14 | RUN mkdir -p /src/wabt/build 15 | 16 | WORKDIR /src/wabt/build 17 | RUN cmake ../ && make && make install 18 | 19 | RUN mkdir -p /go/src/wasm-builder 20 | COPY ./wasm-builder.go /go/src/wasm-builder 21 | RUN go install wasm-builder 22 | 23 | RUN mkdir -p /src/emscripten 24 | COPY ./pre.js /src/emscripten 25 | 26 | WORKDIR /src/emscripten 27 | 28 | RUN rm -rf /src/wabt 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Knocknote, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm 2 | Supports building and loading optimized WebAssembly ( powered by emscripten toolchain ) 3 | 4 | # Motivation 5 | 6 | ## 1. Supports our WebAssembly application as much as possible of all browsers 7 | 8 | We would like to use WebAssembly in our web application. 9 | But, not every browser supports WebAssembly. 10 | So, we must use it together with **not** WebAssembly module ( like `asm.js` ). 11 | 12 | Currently, some languages supports WebAssembly ( `Go`, `Rust`, `C`/`C++`, ... ). 13 | Go and Rust are famous and popular language. Also, they aggressively support WebAssembly. But, they not provide fallback plan from WebAssembly. 14 | Therefore, we cannot select them. 15 | 16 | On the other hand, `Emscripten` can compile `C`/`C++` to WebAssembly and pure javascript with `asm.js`. So we select it for WebAssembly because in this fact is very attractive for us. 17 | 18 | ## 2. Compactly use WebAssembly 19 | 20 | We know WebAssembly's binary size and memory usage is too large. But, we want to use it compactly. 21 | 22 | # Supports building optimized WebAssembly 23 | 24 | We provide `Dockerfile` and docker image (by DockerHub) for building WebAssembly. 25 | Image includes `wasm-builder` and it supports building optimized WebAssembly. 26 | If you doesn't use `wasm-builder`, compiled WebAssembly use **16MB** memory at least. But, if you compile with `wasm-builder`, it use only **64KB** !!! 27 | 28 | # Supports loading WebAssembly with fallback plan 29 | 30 | We provide `wasm-loader.js` for loading WebAssembly. 31 | `wasm-loader.js` provides `WasmLoader` class and it provides `load` method only. 32 | `load` method call dynamic import statement for loading wasm module. 33 | First, `load` method try to call dynamic import callback for **`wasm`** module. But if your browser doesn't support to `WebAssembly` , `load` to call dynamic import callback for **`asm.js`** module. 34 | 35 | ## Install 36 | 37 | ``` 38 | npm install --save @knocknote/wasm-loader 39 | ``` 40 | 41 | # Example 42 | 43 | See https://github.com/knocknote/wasm/blob/master/example/README.md 44 | 45 | # LICENSE 46 | 47 | MIT -------------------------------------------------------------------------------- /dist/wasm-loader.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WasmLoader=t():e.WasmLoader=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var i=r[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var r={};return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/",t(t.s=1)}([function(e,t){var r;r=function(){return this}();try{r=r||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var r=0;r=10&&/^iPad Pro/.test(b),g=/native/.test(Object.keys+""),C=/native/.test(String.raw+"");return{OS:h,OS_VERSION:P,PC:!v,MOBILE:v,BROWSER:E,BASE_BROWSER:O,BROWSER_VERSION:p,USER_AGENT:d,LANGUAGE:A,WEB_VIEW:y,DEVICE:b,TOUCH_3D:I,CARRIER:f,FEATURE_PHONE:!!f,ES5:g,ES6:C,ES2015:C,iOS:W,Mac:"Mac"===h,macOS:"Mac"===h,Android:w,Windows:"Windows"===h,IE:"IE"===E,Edge:"Edge"===E,Firefox:"Firefox"===E,Chrome:"Chrome"===E,Safari:"Safari"===E,Silk:"Silk"===E,AOSP:"AOSP"===E,WebKit:"WebKit"===O,Chromium:"Chromium"===O,iPod:W&&/iPod/.test(d),iPad:W&&/iPad/.test(d),iPhone:W&&/iPhone/.test(d),Kindle:"Silk"===E,has:function(e){return void 0!==this[e]},get:function(e){return this[e]}}}function n(e){var t=e.language||"en";return e.languages&&Array.isArray(e.languages)&&(t=e.languages[0]||t),t.split("-")[0]}function i(e){switch(!0){case/Android/.test(e):return"Android";case/iPhone|iPad|iPod/.test(e):return"iOS";case/Windows/.test(e):return"Windows";case/Mac OS X/.test(e):return"Mac";case/CrOS/.test(e):return"Chrome OS";case/Firefox/.test(e):return"Firefox OS"}return""}function o(e,t){switch(t){case"Android":return f(e,"Android");case"iOS":return f(e,/OS /);case"Windows":return f(e,/Phone/.test(e)?/Windows Phone (?:OS )?/:/Windows NT/);case"Mac":return f(e,/Mac OS X /)}return"0.0.0"}function s(e){var t=/Android/.test(e);switch(!0){case/CriOS/.test(e):return"Chrome for iOS";case/Edge/.test(e):return"Edge";case t&&/Silk\//.test(e):return"Silk";case/Chrome/.test(e):return"Chrome";case/Firefox/.test(e):return"Firefox";case t:return"AOSP";case/MSIE|Trident/.test(e):return"IE";case/Safari\//.test(e):return"Safari";case/AppleWebKit/.test(e):return"WebKit"}return""}function a(e,t){switch(t){case"Chrome for iOS":return f(e,"CriOS/");case"Edge":return f(e,"Edge/");case"Chrome":return f(e,"Chrome/");case"Firefox":return f(e,"Firefox/");case"Silk":return f(e,"Silk/");case"AOSP":return f(e,"Version/");case"IE":return/IEMobile/.test(e)?f(e,"IEMobile/"):/MSIE/.test(e)?f(e,"MSIE "):f(e,"rv:");case"Safari":return f(e,"Version/");case"WebKit":return f(e,"WebKit/")}return"0.0.0"}function u(e,t){return"Silk"===e&&t>=4.4?"Chromium":O[e]||""}function c(t,r,n,i,o){var s=e.screen||{},a=s.width||0,u=s.height||0,c=i.DISPLAY_DPR||e.devicePixelRatio||1,f=i.DISPLAY_LONG||Math.max(a,u),h=i.DISPLAY_SHORT||Math.min(a,u),S=c>=2,P=Math.max(f,h);switch(r){case"Android":return l(t,S);case"iOS":return d(t,S,P,n)}return o?p(t,o):""}function l(e,t){if(/Firefox/.test(e))return"";try{var r=e.split("Build/")[0].split(";").slice(-1).join().trim().replace(/^SonyEricsson/,"").replace(/^Sony/,"").replace(/ 4G$/,"");return"Nexus 7"===r?t?"Nexus 7 2nd":"Nexus 7":r}catch(e){}return""}function d(t,r,n,i){var o=e.WebModule.WebGLDetector||{};"detect"in o&&o.detect();var s=o.WEBGL_VERSION||"",a=o.WEBGL_RENDERER||"",u=/543/.test(s),c=/554/.test(s),l=/A7 /.test(s),d=/A8X/.test(s),f=/A8 /.test(s),h=/A9X/.test(s),S=/A9 /.test(s),P=/Metal/.test(s),E=/Software/.test(a);return/iPhone/.test(t)?E?"iPhone Simulator":r?n<=480?u||i>=8?"iPhone 4s":"iPhone 4":n<=568?P?"iPhone 7":S?"iPhone SE":f?"iPhone 6":l?"iPhone 5s":u?"iPhone 5":"iPhone x":n<=667?P?"iPhone 7":S?"iPhone 6s":f?"iPhone 6":"iPhone x":n<=736?P?"iPhone 7 Plus":S?"iPhone 6s Plus":f?"iPhone 6 Plus":"iPhone x":"iPhone x":"iPhone 3GS":/iPad/.test(t)?E?"iPad Simulator":r?u?"iPad 3":c?"iPad 4":l?"iPad mini 2":d?"iPad Air 2":f?"iPad mini 4":h?n<=1024?"iPad Pro 9.7":"iPad Pro":S?"iPad 5":"iPad x":"iPad 2":/iPod/.test(t)?E?"iPod Simulator":n<=480?r?"iPod touch 4":"iPod touch 3":f?"iPod touch 6":"iPod touch 5":"iPhone x"}function f(e,t){try{return h(e.split(t)[1].trim().split(/[^\w\.]/)[0])}catch(e){}return"0.0.0"}function h(e){var t=e.split(/[\._]/);return(parseInt(t[0],10)||0)+"."+(parseInt(t[1],10)||0)+"."+(parseInt(t[2],10)||0)}function S(e,t,r,n,i){switch(t+r){case"iOSSafari":return!1;case"iOSWebKit":return P(i);case"AndroidAOSP":return!1;case"AndroidChrome":return parseFloat(n)>=42?/; wv/.test(e):!!/\d{2}\.0\.0/.test(n)||E(i)}return!1}function P(t){var r=e.document||{};return"WEB_VIEW"in t?t.WEB_VIEW:!("fullscreenEnabled"in r||"webkitFullscreenEnabled"in r)}function E(t){return"WEB_VIEW"in t?t.WEB_VIEW:!("requestFileSystem"in e||"webkitRequestFileSystem"in e)}function m(e){switch(!0){case/DoCoMo/.test(e):return"DOCOMO";case/KDDI/.test(e):return"KDDI";case/SoftBank|Vodafone/.test(e):return"SOFTBANK"}return""}function p(e,t){switch(t){case"DOCOMO":return e.split("DoCoMo/2.0 ")[1].split("(")[0];case"KDDI":return e.split("KDDI-")[1].split(" ")[0];case"SOFTBANK":return/^Vodafone/.test(e)?e.split("/")[2].slice(1):e.split("/")[2]}return""}var O={Chrome:"Chromium",Firefox:"Firefox",IE:"IE",Edge:"Edge",AOSP:"WebKit",Safari:"WebKit",WebKit:"WebKit","Chrome for iOS":"WebKit",Silk:"WebKit"};return t.DISABLE_CACHE=!1,t.cache=null,t.parse=r,t.repository="https://github.com/uupaa/UserAgent.js",t})}])}); -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["syntax-dynamic-import"] 4 | } 5 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: wasm 2 | 3 | wasm: 4 | wasm-builder --name hello -- \ 5 | em++ -Oz -std=c++11 \ 6 | --closure 1 \ 7 | --memory-init-file 0 \ 8 | -fno-exceptions \ 9 | --llvm-lto 1 \ 10 | -s ALLOW_MEMORY_GROWTH=1 \ 11 | -s MODULARIZE=1 \ 12 | -s NO_FILESYSTEM=1 \ 13 | --pre-js /src/emscripten/pre.js \ 14 | --bind \ 15 | hello.cc -o hello.js 16 | 17 | .PHONY: asmjs 18 | 19 | asmjs: 20 | em++ -Oz -std=c++11 \ 21 | --closure 1 \ 22 | --memory-init-file 0 \ 23 | -fno-exceptions \ 24 | --llvm-lto 1 \ 25 | -s MODULARIZE=1 \ 26 | -s NO_FILESYSTEM=1 \ 27 | -s WASM=0 \ 28 | --bind \ 29 | hello.cc -o hello.js 30 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # HOW TO WORK Example 2 | 3 | ## 1. Run Container by docker-compose 4 | 5 | ``` 6 | # pwd => /path/to/wasm/example 7 | docker-compose up -d 8 | docker ps 9 | 10 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11 | 40585001c1c2 example_hello_wasm "tail -f /dev/null" 1 minutes ago Up 1 minutes hello_wasm 12 | ``` 13 | 14 | ## 2. Build hello.cc simply 15 | 16 | ``` 17 | docker exec -it hello_wasm bash 18 | root@40585001c1c2:/src/emscripten/example# em++ -Oz -std=c++11 \ 19 | --closure 1 \ 20 | --memory-init-file 0 \ 21 | -fno-exceptions \ 22 | --llvm-lto 1 \ 23 | -s ALLOW_MEMORY_GROWTH=1 \ 24 | -s MODULARIZE=1 \ 25 | -s NO_FILESYSTEM=1 \ 26 | --bind \ 27 | hello.cc -o hello.js 28 | ``` 29 | 30 | output `hello.js` and `hello.wasm` 31 | 32 | Copy these files into your application. 33 | And load by ` 109 | 110 | 111 | 112 | ``` 113 | 114 | `module_loader.js` is the following. 115 | 116 | ```javascript 117 | import WasmLoader from '../dist/wasm-loader'; 118 | 119 | const loader = new WasmLoader(); 120 | loader.load( 121 | () => import('./hello-wasm'), 122 | () => import('./hello') 123 | ).then(module => { 124 | console.log('loaded module', module); 125 | module.hello(); 126 | }); 127 | ``` 128 | 129 | This example use `wasm-loader.js` . 130 | `wasm-loader.js` provides `WasmLoader` class and it provides `load` method only. 131 | `load` method call dynamic import statement for loading wasm module. 132 | First, `load` method try to call dynamic import callback for **`wasm`** module. But if your browser doesn't support to `WebAssembly` , `load` to call dynamic import callback for **`asm.js`** module. 133 | -------------------------------------------------------------------------------- /example/docker-compose.yml: -------------------------------------------------------------------------------- 1 | hello_wasm: 2 | build: ../ 3 | container_name: 'hello_wasm' 4 | command: tail -f /dev/null 5 | working_dir: /src/emscripten/example 6 | environment: 7 | COLUMNS: 1000 8 | LINES: 50 9 | volumes: 10 | - ".:/src/emscripten/example" 11 | -------------------------------------------------------------------------------- /example/hello-wasm.js: -------------------------------------------------------------------------------- 1 | var Module = function(Module) { 2 | Module = Module || {}; 3 | 4 | var d;d||(d=typeof Module !== 'undefined' ? Module : {});d.TOTAL_MEMORY=65536;d.TOTAL_STACK=32768;d.preInit=function(){aa=ba=65536}; 5 | d.instantiateWasm=function(a,b){return function(a){return new Promise(function(b,c){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=function(){b(e.response)};e.onerror=function(){c("error "+e.status)};e.send(null)})}("/hello.wasm?v=1c682e4e9553703d8c87dbc78d005538").then(function(c){return WebAssembly.instantiate(new Uint8Array(c),a).then(function(c){b(c.instance);a.parent.then=null;return Promise.resolve(a.parent)})}).catch(function(a){ca();throw a;})};var n={},r; 6 | for(r in d)d.hasOwnProperty(r)&&(n[r]=d[r]);d.arguments=[];d.thisProgram="./this.program";d.quit=function(a,b){throw b;};d.preRun=[];d.postRun=[];var t=!1,u=!1,da=!1,ea=!1;t="object"===typeof window;u="function"===typeof importScripts;da="object"===typeof process&&"function"===typeof require&&!t&&!u;ea=!t&&!da&&!u; 7 | if(da){var fa,ha;d.read=function(a,b){fa||(fa=require("fs"));ha||(ha=require("path"));a=ha.normalize(a);a=fa.readFileSync(a);return b?a:a.toString()};d.readBinary=function(a){a=d.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};1>0];c|=e;if(0==e&&!b)break;g++;if(b&&g==b)break}b||(b=g);e="";if(128>c){for(;0e?c+=String.fromCharCode(e):(e-= 13 | 65536,c+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else c+=String.fromCharCode(e)}} 14 | function pa(a,b,c,e){if(0=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++g)&1023);if(127>=f){if(c>=e)break;b[c++]=f}else{if(2047>=f){if(c+1>=e)break;b[c++]=192|f>>6}else{if(65535>=f){if(c+2>=e)break;b[c++]=224|f>>12}else{if(2097151>=f){if(c+3>=e)break;b[c++]=240|f>>18}else{if(67108863>=f){if(c+4>=e)break;b[c++]=248|f>>24}else{if(c+5>=e)break;b[c++]=252|f>>30;b[c++]=128|f>>24&63}b[c++]=128|f>>18&63}b[c++]=128|f>>12&63}b[c++]= 15 | 128|f>>6&63}b[c++]=128|f&63}}b[c]=0}}function qa(a){for(var b=0,c=0;c=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++c)&1023);127>=e?++b:b=2047>=e?b+2:65535>=e?b+3:2097151>=e?b+4:67108863>=e?b+5:b+6}return b}"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var ba=16777216,aa=16777216;function ra(a,b){0>2]=a);return a}var K=0;function M(){K+=4;return z[K-4>>2]}var N={}; 27 | function O(a,b){K=b;try{var c=M(),e=M(),g=M();a=0;O.b||(O.b=[null,[],[]],O.u=function(a,b){var c=O.b[a];assert(c);0===b||10===b?((1===a?ia:v)(na(c,0)),c.length=0):c.push(b)});for(b=0;b>2],h=z[e+(8*b+4)>>2],l=0;l=b?"_"+a:a}function Ua(a,b){a=Ta(a);return(new Function("body","return function "+a+'() {\n "use strict"; return body.apply(this, arguments);\n};\n'))(b)} 29 | function Va(a){var b=Error,c=Ua(a,function(b){this.name=a;this.message=b;b=Error(b).stack;void 0!==b&&(this.stack=this.toString()+"\n"+b.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(b.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message};return c}var Wa=void 0;function U(a){throw new Wa(a);}var Ya=void 0; 30 | function Za(a,b){var c=[];function e(a){a=b(a);if(a.length!==c.length)throw new Ya("Mismatched type converter count");for(var e=0;e>2])}function cb(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a} 33 | function db(a,b){switch(b){case 2:return function(a){return this.fromWireType(ua[a>>2])};case 3:return function(a){return this.fromWireType(va[a>>3])};default:throw new TypeError("Unknown float type: "+a);}}function eb(a){var b=Function;if(!(b instanceof Function))throw new TypeError("new_ called with constructor type "+typeof b+" which is not a function");var c=Ua(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c} 34 | function gb(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function hb(a,b){var c=d;if(void 0===c[a].c){var e=c[a];c[a]=function(){c[a].c.hasOwnProperty(arguments.length)||U("Function '"+b+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+c[a].c+")!");return c[a].c[arguments.length].apply(this,arguments)};c[a].c=[];c[a].c[e.A]=e}} 35 | function ib(a,b,c){d.hasOwnProperty(a)?((void 0===c||void 0!==d[a].c&&void 0!==d[a].c[c])&&U("Cannot register public name '"+a+"' twice"),hb(a,a),d.hasOwnProperty(c)&&U("Cannot register multiple overloads of a function with the same number of arguments ("+c+")!"),d[a].c[c]=b):(d[a]=b,void 0!==c&&(d[a].X=c))}function jb(a,b){for(var c=[],e=0;e>2)+e]);return c} 36 | function kb(a,b){a=Q(a);if(void 0!==d["FUNCTION_TABLE_"+a])var c=d["FUNCTION_TABLE_"+a][b];else if("undefined"!==typeof FUNCTION_TABLE)c=FUNCTION_TABLE[b];else{c=d.asm["dynCall_"+a];void 0===c&&(c=d.asm["dynCall_"+a.replace(/f/g,"d")],void 0===c&&U("No dynCall invoker for signature: "+a));for(var e=[],g=1;g>1]}:function(a){return ta[a>>1]};case 2:return c?function(a){return z[a>>2]}:function(a){return A[a>>2]};default:throw new TypeError("Unknown integer type: "+a);}}var qb={};function Y(a){if(0===a)return 0;a=ma(a);if(!qb.hasOwnProperty(a))return 0;Y.b&&X(Y.b);a=qb[a];var b=qa(a)+1,c=rb(b);c&&pa(a,y,c,b);Y.b=c;return Y.b} 39 | function Z(){Z.b||(Z.b=[]);Z.b.push(sb());return Z.b.length-1}function tb(a){return 0===a%4&&(0!==a%100||0===a%400)}function ub(a,b){for(var c=0,e=0;e<=b;c+=a[e++]);return c}var vb=[31,29,31,30,31,30,31,31,30,31,30,31],wb=[31,28,31,30,31,30,31,31,30,31,30,31]; 40 | function xb(a,b){for(a=new Date(a.getTime());0e-a.getDate())b-=e-a.getDate()+1,a.setDate(1),11>c?a.setMonth(c+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+b);break}}return a} 41 | function yb(a,b,c,e){function g(a,b,c){for(a="number"===typeof a?a.toString():a||"";a.lengtha?-1:0=h(l(new Date(a.getFullYear(),0,4)),a)?0>=h(b,a)?a.getFullYear()+1:a.getFullYear():a.getFullYear()-1}var p=z[e+40>>2];e={K:z[e>>2],J:z[e+4>>2],l:z[e+8>>2],h:z[e+12>>2],g:z[e+16>>2],a:z[e+20>>2],w:z[e+24>>2],m:z[e+28>>2],Y:z[e+32>>2],I:z[e+36>>2],L:p?ma(p):""}; 43 | c=ma(c);p={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S"};for(var m in p)c=c.replace(new RegExp(m,"g"),p[m]);var I="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),P="January February March April May June July August September October November December".split(" ");p={"%a":function(a){return I[a.w].substring(0,3)},"%A":function(a){return I[a.w]},"%b":function(a){return P[a.g].substring(0, 44 | 3)},"%B":function(a){return P[a.g]},"%C":function(a){return f((a.a+1900)/100|0,2)},"%d":function(a){return f(a.h,2)},"%e":function(a){return g(a.h,2," ")},"%g":function(a){return q(a).toString().substring(2)},"%G":function(a){return q(a)},"%H":function(a){return f(a.l,2)},"%I":function(a){a=a.l;0==a?a=12:12a.l?"AM":"PM"},"%S":function(a){return f(a.K,2)},"%t":function(){return"\t"},"%u":function(a){return(new Date(a.a+1900,a.g+1,a.h,0,0,0,0)).getDay()||7},"%U":function(a){var b=new Date(a.a+1900,0,1),c=0===b.getDay()?b:xb(b,7-b.getDay());a=new Date(a.a+1900,a.g,a.h);return 0>h(c,a)?f(Math.ceil((31-c.getDate()+(ub(tb(a.getFullYear())?vb:wb,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(c,b)?"01":"00"},"%V":function(a){var b=l(new Date(a.a+1900,0,4)),c=l(new Date(a.a+1901,0,4)),e=xb(new Date(a.a+ 46 | 1900,0,1),a.m);return 0>h(e,b)?"53":0>=h(c,e)?"01":f(Math.ceil((b.getFullYear()h(c,a)?f(Math.ceil((31-c.getDate()+(ub(tb(a.getFullYear())?vb:wb,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(c,b)?"01":"00"},"%y":function(a){return(a.a+1900).toString().substring(2)}, 47 | "%Y":function(a){return a.a+1900},"%z":function(a){a=a.I;var b=0<=a;a=Math.abs(a)/60;return(b?"+":"-")+String("0000"+(a/60*100+a%60)).slice(-4)},"%Z":function(a){return a.L},"%%":function(){return"%"}};for(m in p)0<=c.indexOf(m)&&(c=c.replace(new RegExp(m,"g"),p[m](e)));m=zb(c);if(m.length>b)return 0;y.set(m,a);return m.length-1}for(var Ab=Array(256),Bb=0;256>Bb;++Bb)Ab[Bb]=String.fromCharCode(Bb);Ra=Ab;Wa=d.BindingError=Va("BindingError");Ya=d.InternalError=Va("InternalError"); 48 | d.count_emval_handles=function(){for(var a=0,b=5;b>2]=Aa;function zb(a){var b=Array(qa(a)+1);pa(a,b,0,b.length);return b}d.wasmTableSize=479;d.wasmMaxTableSize=479;d.B={}; 49 | d.C={abort:w,enlargeMemory:function(){var a=d.usingWasm?65536:ba,b=2147483648-a;if(z[D>>2]>b)return!1;var c=F;for(F=Math.max(F,aa);F>2];)536870912>=F?F=ra(2*F,a):F=Math.min(ra((3*F+2147483648)/4,a),b);a=d.reallocBuffer(F);if(!a||a.byteLength!=F)return F=c,!1;d.buffer=buffer=a;wa();return!0},getTotalMemory:function(){return F},abortOnCannotGrowMemory:function(){w("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+F+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}, 50 | ___cxa_uncaught_exception:function(){return!!Db.u},___lock:function(){},___map_file:function(){Pa(1);return-1},___setErrNo:Pa,___syscall140:function(a,b){K=b;try{var c=N.v();M();var e=M(),g=M(),f=M();FS.U(c,e,f);z[g>>2]=c.position;c.D&&0===e&&0===f&&(c.D=null);return 0}catch(h){return"undefined"!==typeof FS&&h instanceof FS.i||w(h),-h.j}},___syscall145:function(a,b){K=b;try{var c=N.v(),e=M(),g=M();return N.P(c,e,g)}catch(f){return"undefined"!==typeof FS&&f instanceof FS.i||w(f),-f.j}},___syscall146:O, 51 | ___syscall54:function(a,b){K=b;return 0},___syscall6:function(a,b){K=b;try{var c=N.v();FS.close(c);return 0}catch(e){return"undefined"!==typeof FS&&e instanceof FS.i||w(e),-e.j}},___syscall91:function(a,b){K=b;try{var c=M(),e=M(),g=N.G[c];if(!g)return 0;if(e===g.T){var f=FS.R(g.fd);N.O(c,f,e,g.flags);FS.W(f);N.G[c]=null;g.N&&X(g.V)}return 0}catch(h){return"undefined"!==typeof FS&&h instanceof FS.i||w(h),-h.j}},___unlock:function(){},__embind_register_bool:function(a,b,c,e,g){var f=Qa(c);b=Q(b);V(a, 52 | {name:b,fromWireType:function(a){return!!a},toWireType:function(a,b){return b?e:g},argPackAdvance:8,readValueFromPointer:function(a){if(1===c)var e=y;else if(2===c)e=sa;else if(4===c)e=z;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(e[a>>f])},f:null})},__embind_register_emval:function(a,b){b=Q(b);V(a,{name:b,fromWireType:function(a){var b=W[a].value;4l&&U("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var P=null!==e[1]&&!1,E=!1,k=1;k>>l}}var q=-1!=b.indexOf("unsigned");V(a,{name:b,fromWireType:f,toWireType:function(a,c){if("number"!==typeof c&&"boolean"!==typeof c)throw new TypeError('Cannot convert "'+cb(c)+'" to '+this.name);if(cg)throw new TypeError('Passing a number "'+cb(c)+'" from JS side to C/C++ side to an argument of type "'+b+'", which is outside the valid range ['+e+", "+g+"]!");return q?c>>>0:c|0},argPackAdvance:8,readValueFromPointer:pb(b, 58 | h,0!==e),f:null})},__embind_register_memory_view:function(a,b,c){function e(a){a>>=2;var b=A;return new g(b.buffer,b[a+1],b[a])}var g=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=Q(c);V(a,{name:c,fromWireType:e,argPackAdvance:8,readValueFromPointer:e},{F:!0})},__embind_register_std_string:function(a,b){b=Q(b);V(a,{name:b,fromWireType:function(a){for(var b=A[a>>2],c=Array(b),f=0;f>2]=l;for(var p=0;p>2],f=Array(c),p=a+4>>g,m=0;m>2]=h;for(var m=p+4>>g,I=0;I 2 | #include 3 | 4 | static void hello() 5 | { 6 | std::cout << "Hello World" << std::endl; 7 | } 8 | 9 | EMSCRIPTEN_BINDINGS(hello) { 10 | emscripten::function("hello", &hello); 11 | }; 12 | -------------------------------------------------------------------------------- /example/hello.js: -------------------------------------------------------------------------------- 1 | var Module = function(Module) { 2 | Module = Module || {}; 3 | 4 | var d;d||(d=typeof Module !== 'undefined' ? Module : {});d.TOTAL_MEMORY=65536;d.TOTAL_STACK=32768;d.preInit=function(){aa=ba=65536}; 5 | d.instantiateWasm=function(a,b){return function(a){return new Promise(function(b,c){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=function(){b(e.response)};e.onerror=function(){c("error "+e.status)};e.send(null)})}("/{{ .Name }}.wasm?v={{ .Version }}").then(function(c){return WebAssembly.instantiate(new Uint8Array(c),a).then(function(c){b(c.instance);a.parent.then=null;return Promise.resolve(a.parent)})}).catch(function(a){ca();throw a;})};var n={},r; 6 | for(r in d)d.hasOwnProperty(r)&&(n[r]=d[r]);d.arguments=[];d.thisProgram="./this.program";d.quit=function(a,b){throw b;};d.preRun=[];d.postRun=[];var t=!1,u=!1,da=!1,ea=!1;t="object"===typeof window;u="function"===typeof importScripts;da="object"===typeof process&&"function"===typeof require&&!t&&!u;ea=!t&&!da&&!u; 7 | if(da){var fa,ha;d.read=function(a,b){fa||(fa=require("fs"));ha||(ha=require("path"));a=ha.normalize(a);a=fa.readFileSync(a);return b?a:a.toString()};d.readBinary=function(a){a=d.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};1>0];c|=e;if(0==e&&!b)break;g++;if(b&&g==b)break}b||(b=g);e="";if(128>c){for(;0e?c+=String.fromCharCode(e):(e-= 13 | 65536,c+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else c+=String.fromCharCode(e)}} 14 | function pa(a,b,c,e){if(0=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++g)&1023);if(127>=f){if(c>=e)break;b[c++]=f}else{if(2047>=f){if(c+1>=e)break;b[c++]=192|f>>6}else{if(65535>=f){if(c+2>=e)break;b[c++]=224|f>>12}else{if(2097151>=f){if(c+3>=e)break;b[c++]=240|f>>18}else{if(67108863>=f){if(c+4>=e)break;b[c++]=248|f>>24}else{if(c+5>=e)break;b[c++]=252|f>>30;b[c++]=128|f>>24&63}b[c++]=128|f>>18&63}b[c++]=128|f>>12&63}b[c++]= 15 | 128|f>>6&63}b[c++]=128|f&63}}b[c]=0}}function qa(a){for(var b=0,c=0;c=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++c)&1023);127>=e?++b:b=2047>=e?b+2:65535>=e?b+3:2097151>=e?b+4:67108863>=e?b+5:b+6}return b}"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var ba=16777216,aa=16777216;function ra(a,b){0>2]=a);return a}var K=0;function M(){K+=4;return z[K-4>>2]}var N={}; 27 | function O(a,b){K=b;try{var c=M(),e=M(),g=M();a=0;O.b||(O.b=[null,[],[]],O.u=function(a,b){var c=O.b[a];assert(c);0===b||10===b?((1===a?ia:v)(na(c,0)),c.length=0):c.push(b)});for(b=0;b>2],h=z[e+(8*b+4)>>2],l=0;l=b?"_"+a:a}function Ua(a,b){a=Ta(a);return(new Function("body","return function "+a+'() {\n "use strict"; return body.apply(this, arguments);\n};\n'))(b)} 29 | function Va(a){var b=Error,c=Ua(a,function(b){this.name=a;this.message=b;b=Error(b).stack;void 0!==b&&(this.stack=this.toString()+"\n"+b.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(b.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message};return c}var Wa=void 0;function U(a){throw new Wa(a);}var Ya=void 0; 30 | function Za(a,b){var c=[];function e(a){a=b(a);if(a.length!==c.length)throw new Ya("Mismatched type converter count");for(var e=0;e>2])}function cb(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a} 33 | function db(a,b){switch(b){case 2:return function(a){return this.fromWireType(ua[a>>2])};case 3:return function(a){return this.fromWireType(va[a>>3])};default:throw new TypeError("Unknown float type: "+a);}}function eb(a){var b=Function;if(!(b instanceof Function))throw new TypeError("new_ called with constructor type "+typeof b+" which is not a function");var c=Ua(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c} 34 | function gb(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function hb(a,b){var c=d;if(void 0===c[a].c){var e=c[a];c[a]=function(){c[a].c.hasOwnProperty(arguments.length)||U("Function '"+b+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+c[a].c+")!");return c[a].c[arguments.length].apply(this,arguments)};c[a].c=[];c[a].c[e.A]=e}} 35 | function ib(a,b,c){d.hasOwnProperty(a)?((void 0===c||void 0!==d[a].c&&void 0!==d[a].c[c])&&U("Cannot register public name '"+a+"' twice"),hb(a,a),d.hasOwnProperty(c)&&U("Cannot register multiple overloads of a function with the same number of arguments ("+c+")!"),d[a].c[c]=b):(d[a]=b,void 0!==c&&(d[a].X=c))}function jb(a,b){for(var c=[],e=0;e>2)+e]);return c} 36 | function kb(a,b){a=Q(a);if(void 0!==d["FUNCTION_TABLE_"+a])var c=d["FUNCTION_TABLE_"+a][b];else if("undefined"!==typeof FUNCTION_TABLE)c=FUNCTION_TABLE[b];else{c=d.asm["dynCall_"+a];void 0===c&&(c=d.asm["dynCall_"+a.replace(/f/g,"d")],void 0===c&&U("No dynCall invoker for signature: "+a));for(var e=[],g=1;g>1]}:function(a){return ta[a>>1]};case 2:return c?function(a){return z[a>>2]}:function(a){return A[a>>2]};default:throw new TypeError("Unknown integer type: "+a);}}var qb={};function Y(a){if(0===a)return 0;a=ma(a);if(!qb.hasOwnProperty(a))return 0;Y.b&&X(Y.b);a=qb[a];var b=qa(a)+1,c=rb(b);c&&pa(a,y,c,b);Y.b=c;return Y.b} 39 | function Z(){Z.b||(Z.b=[]);Z.b.push(sb());return Z.b.length-1}function tb(a){return 0===a%4&&(0!==a%100||0===a%400)}function ub(a,b){for(var c=0,e=0;e<=b;c+=a[e++]);return c}var vb=[31,29,31,30,31,30,31,31,30,31,30,31],wb=[31,28,31,30,31,30,31,31,30,31,30,31]; 40 | function xb(a,b){for(a=new Date(a.getTime());0e-a.getDate())b-=e-a.getDate()+1,a.setDate(1),11>c?a.setMonth(c+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+b);break}}return a} 41 | function yb(a,b,c,e){function g(a,b,c){for(a="number"===typeof a?a.toString():a||"";a.lengtha?-1:0=h(l(new Date(a.getFullYear(),0,4)),a)?0>=h(b,a)?a.getFullYear()+1:a.getFullYear():a.getFullYear()-1}var p=z[e+40>>2];e={K:z[e>>2],J:z[e+4>>2],l:z[e+8>>2],h:z[e+12>>2],g:z[e+16>>2],a:z[e+20>>2],w:z[e+24>>2],m:z[e+28>>2],Y:z[e+32>>2],I:z[e+36>>2],L:p?ma(p):""}; 43 | c=ma(c);p={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S"};for(var m in p)c=c.replace(new RegExp(m,"g"),p[m]);var I="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),P="January February March April May June July August September October November December".split(" ");p={"%a":function(a){return I[a.w].substring(0,3)},"%A":function(a){return I[a.w]},"%b":function(a){return P[a.g].substring(0, 44 | 3)},"%B":function(a){return P[a.g]},"%C":function(a){return f((a.a+1900)/100|0,2)},"%d":function(a){return f(a.h,2)},"%e":function(a){return g(a.h,2," ")},"%g":function(a){return q(a).toString().substring(2)},"%G":function(a){return q(a)},"%H":function(a){return f(a.l,2)},"%I":function(a){a=a.l;0==a?a=12:12a.l?"AM":"PM"},"%S":function(a){return f(a.K,2)},"%t":function(){return"\t"},"%u":function(a){return(new Date(a.a+1900,a.g+1,a.h,0,0,0,0)).getDay()||7},"%U":function(a){var b=new Date(a.a+1900,0,1),c=0===b.getDay()?b:xb(b,7-b.getDay());a=new Date(a.a+1900,a.g,a.h);return 0>h(c,a)?f(Math.ceil((31-c.getDate()+(ub(tb(a.getFullYear())?vb:wb,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(c,b)?"01":"00"},"%V":function(a){var b=l(new Date(a.a+1900,0,4)),c=l(new Date(a.a+1901,0,4)),e=xb(new Date(a.a+ 46 | 1900,0,1),a.m);return 0>h(e,b)?"53":0>=h(c,e)?"01":f(Math.ceil((b.getFullYear()h(c,a)?f(Math.ceil((31-c.getDate()+(ub(tb(a.getFullYear())?vb:wb,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(c,b)?"01":"00"},"%y":function(a){return(a.a+1900).toString().substring(2)}, 47 | "%Y":function(a){return a.a+1900},"%z":function(a){a=a.I;var b=0<=a;a=Math.abs(a)/60;return(b?"+":"-")+String("0000"+(a/60*100+a%60)).slice(-4)},"%Z":function(a){return a.L},"%%":function(){return"%"}};for(m in p)0<=c.indexOf(m)&&(c=c.replace(new RegExp(m,"g"),p[m](e)));m=zb(c);if(m.length>b)return 0;y.set(m,a);return m.length-1}for(var Ab=Array(256),Bb=0;256>Bb;++Bb)Ab[Bb]=String.fromCharCode(Bb);Ra=Ab;Wa=d.BindingError=Va("BindingError");Ya=d.InternalError=Va("InternalError"); 48 | d.count_emval_handles=function(){for(var a=0,b=5;b>2]=Aa;function zb(a){var b=Array(qa(a)+1);pa(a,b,0,b.length);return b}d.wasmTableSize=479;d.wasmMaxTableSize=479;d.B={}; 49 | d.C={abort:w,enlargeMemory:function(){var a=d.usingWasm?65536:ba,b=2147483648-a;if(z[D>>2]>b)return!1;var c=F;for(F=Math.max(F,aa);F>2];)536870912>=F?F=ra(2*F,a):F=Math.min(ra((3*F+2147483648)/4,a),b);a=d.reallocBuffer(F);if(!a||a.byteLength!=F)return F=c,!1;d.buffer=buffer=a;wa();return!0},getTotalMemory:function(){return F},abortOnCannotGrowMemory:function(){w("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+F+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}, 50 | ___cxa_uncaught_exception:function(){return!!Db.u},___lock:function(){},___map_file:function(){Pa(1);return-1},___setErrNo:Pa,___syscall140:function(a,b){K=b;try{var c=N.v();M();var e=M(),g=M(),f=M();FS.U(c,e,f);z[g>>2]=c.position;c.D&&0===e&&0===f&&(c.D=null);return 0}catch(h){return"undefined"!==typeof FS&&h instanceof FS.i||w(h),-h.j}},___syscall145:function(a,b){K=b;try{var c=N.v(),e=M(),g=M();return N.P(c,e,g)}catch(f){return"undefined"!==typeof FS&&f instanceof FS.i||w(f),-f.j}},___syscall146:O, 51 | ___syscall54:function(a,b){K=b;return 0},___syscall6:function(a,b){K=b;try{var c=N.v();FS.close(c);return 0}catch(e){return"undefined"!==typeof FS&&e instanceof FS.i||w(e),-e.j}},___syscall91:function(a,b){K=b;try{var c=M(),e=M(),g=N.G[c];if(!g)return 0;if(e===g.T){var f=FS.R(g.fd);N.O(c,f,e,g.flags);FS.W(f);N.G[c]=null;g.N&&X(g.V)}return 0}catch(h){return"undefined"!==typeof FS&&h instanceof FS.i||w(h),-h.j}},___unlock:function(){},__embind_register_bool:function(a,b,c,e,g){var f=Qa(c);b=Q(b);V(a, 52 | {name:b,fromWireType:function(a){return!!a},toWireType:function(a,b){return b?e:g},argPackAdvance:8,readValueFromPointer:function(a){if(1===c)var e=y;else if(2===c)e=sa;else if(4===c)e=z;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(e[a>>f])},f:null})},__embind_register_emval:function(a,b){b=Q(b);V(a,{name:b,fromWireType:function(a){var b=W[a].value;4l&&U("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var P=null!==e[1]&&!1,E=!1,k=1;k>>l}}var q=-1!=b.indexOf("unsigned");V(a,{name:b,fromWireType:f,toWireType:function(a,c){if("number"!==typeof c&&"boolean"!==typeof c)throw new TypeError('Cannot convert "'+cb(c)+'" to '+this.name);if(cg)throw new TypeError('Passing a number "'+cb(c)+'" from JS side to C/C++ side to an argument of type "'+b+'", which is outside the valid range ['+e+", "+g+"]!");return q?c>>>0:c|0},argPackAdvance:8,readValueFromPointer:pb(b, 58 | h,0!==e),f:null})},__embind_register_memory_view:function(a,b,c){function e(a){a>>=2;var b=A;return new g(b.buffer,b[a+1],b[a])}var g=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=Q(c);V(a,{name:c,fromWireType:e,argPackAdvance:8,readValueFromPointer:e},{F:!0})},__embind_register_std_string:function(a,b){b=Q(b);V(a,{name:b,fromWireType:function(a){for(var b=A[a>>2],c=Array(b),f=0;f>2]=l;for(var p=0;p>2],f=Array(c),p=a+4>>g,m=0;m>2]=h;for(var m=p+4>>g,I=0;I 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/module_loader.js: -------------------------------------------------------------------------------- 1 | import WasmLoader from '../dist/wasm-loader'; 2 | 3 | const loader = new WasmLoader(); 4 | loader.load( 5 | () => import('./hello-wasm'), 6 | () => import('./hello') 7 | ).then(module => { 8 | console.log('loaded module', module); 9 | module.hello(); 10 | }); 11 | -------------------------------------------------------------------------------- /example/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "dependencies": { 4 | "babel-plugin-syntax-dynamic-import": { 5 | "version": "6.18.0", 6 | "resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", 7 | "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", 8 | "dev": true 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "version": "", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "build": "webpack", 8 | "server": "webpack-dev-server --host 0.0.0.0 --progress --port 5000" 9 | }, 10 | "author": "", 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "babel-cli": "^6.26.0", 14 | "babel-eslint": "^8.1.2", 15 | "babel-loader": "^7.1.2", 16 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 17 | "babel-polyfill": "^6.26.0", 18 | "babel-preset-es2015": "^6.24.1", 19 | "babelify": "^7.3.0", 20 | "browserify": "^14.5.0", 21 | "copy-webpack-plugin": "^4.5.2", 22 | "webpack": "^3.6.0", 23 | "webpack-dev-server": "^2.9.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | 5 | module.exports = { 6 | devtool: 'source-map', 7 | entry: './module_loader.js', 8 | output: { 9 | publicPath: '/', 10 | path: path.resolve(__dirname, 'dist'), 11 | filename: 'module_loader.js' 12 | }, 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.js$/, 17 | exclude: /node_modules/, 18 | use: 'babel-loader' 19 | } 20 | ] 21 | }, 22 | 23 | plugins: [ 24 | new CopyWebpackPlugin([ 25 | { from: 'index.html' }, 26 | { from: 'hello*.{wasm,js}' } 27 | ]), 28 | ], 29 | 30 | devServer: { 31 | contentBase: 'dist', 32 | disableHostCheck: true, 33 | inline: true, 34 | historyApiFallback: true, 35 | compress: true 36 | }, 37 | 38 | node: { 39 | fs: 'empty' 40 | } 41 | 42 | }; 43 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasm", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "uupaa.useragent.js": { 7 | "version": "1.0.2", 8 | "resolved": "https://registry.npmjs.org/uupaa.useragent.js/-/uupaa.useragent.js-1.0.2.tgz", 9 | "integrity": "sha1-89cQWoghHxBNTs0RMqzfEsgEVZc=", 10 | "dev": true 11 | }, 12 | "uupaa.webgldetector.js": { 13 | "version": "0.1.2", 14 | "resolved": "https://registry.npmjs.org/uupaa.webgldetector.js/-/uupaa.webgldetector.js-0.1.2.tgz", 15 | "integrity": "sha1-XkYMlINfdUZcFmqmEjP836OnsS4=", 16 | "dev": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasm-loader", 3 | "version": "0.0.1", 4 | "description": "simple loader for WebAssembly or asm.js", 5 | "main": "dist/wasm-loader.js", 6 | "scripts": { 7 | "build": "webpack", 8 | "server": "webpack-dev-server --host 0.0.0.0 --progress --port 5000", 9 | "lint": "eslint src", 10 | "doc": "jsdoc -c .jsdoc.json -R README.md" 11 | }, 12 | "files": [ 13 | "README.md", 14 | "LICENSE", 15 | "package.json", 16 | "dist/wasm-loader.js", 17 | "src" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/knocknote/wasm" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/knocknote/wasm/issues" 25 | }, 26 | "homepage": "https://github.com/knocknote/wasm", 27 | "author": "", 28 | "license": "MIT", 29 | "dependencies": { 30 | "uupaa.useragent.js": "^1.0.2" 31 | }, 32 | "devDependencies": { 33 | "babel-cli": "^6.26.0", 34 | "babel-eslint": "^8.1.2", 35 | "babel-loader": "^7.1.2", 36 | "babel-polyfill": "^6.26.0", 37 | "babel-preset-es2015": "^6.24.1", 38 | "babelify": "^7.3.0", 39 | "browserify": "^14.5.0", 40 | "copy-webpack-plugin": "^4.5.2", 41 | "eslint": "^4.14.0", 42 | "eslint-config-airbnb": "^17.0.0", 43 | "eslint-plugin-import": "^2.13.0", 44 | "eslint-plugin-jsx-a11y": "^6.1.1", 45 | "eslint-plugin-react": "^7.10.0", 46 | "jsdoc": "^3.5.5", 47 | "webpack": "^3.6.0", 48 | "webpack-dev-server": "^2.9.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pre.js: -------------------------------------------------------------------------------- 1 | Module['TOTAL_MEMORY'] = 65536; 2 | Module['TOTAL_STACK'] = 32768; 3 | 4 | Module['preInit'] = function() { 5 | ASMJS_PAGE_SIZE = 65536; 6 | MIN_TOTAL_MEMORY = 65536; 7 | }; 8 | 9 | Module['instantiateWasm'] = function(imports, successCallback) { 10 | function downloadWasm(url) { 11 | return new Promise(function(resolve, reject) { 12 | var wasmXHR = new XMLHttpRequest(); 13 | wasmXHR.open('GET', url, true); 14 | wasmXHR.responseType = 'arraybuffer'; 15 | wasmXHR.onload = function() { resolve(wasmXHR.response); }; 16 | wasmXHR.onerror = function() { reject('error ' + wasmXHR.status); }; 17 | wasmXHR.send(null); 18 | }); 19 | }; 20 | return downloadWasm('/{{ .Name }}.wasm?v={{ .Version }}'). 21 | then(function(wasmBinary) { 22 | return WebAssembly.instantiate(new Uint8Array(wasmBinary), imports). 23 | then(function(output) { 24 | successCallback(output.instance); 25 | imports.parent.then = null; 26 | return Promise.resolve(imports.parent); 27 | }); 28 | }).catch(function(err) { 29 | removeRunDependency('wasm-instantiate'); 30 | throw err; 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | let UserAgent; 2 | if (!global.GLOBAL) { 3 | require('uupaa.useragent.js/lib/WebModule.js'); 4 | global.GLOBAL = global; 5 | } 6 | UserAgent = require('uupaa.useragent.js/lib/UserAgent'); 7 | 8 | export default class WasmHelper { 9 | constructor() { 10 | this.ua = new UserAgent(); 11 | } 12 | 13 | canUseWebAssembly() { 14 | return window.WebAssembly !== undefined 15 | && !this.isIgnoreBrowser() 16 | && WasmHelper.validateSafariWebAssemblyBug(); 17 | } 18 | 19 | // FYI : https://github.com/brion/min-wasm-fail 20 | static validateSafariWebAssemblyBug() { 21 | const binary = new Uint8Array([ 22 | 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 23 | 127, 1, 127, 3, 2, 1, 0, 5, 3, 1, 0, 1, 7, 8, 24 | 1, 4, 116, 101, 115, 116, 0, 0, 10, 16, 1, 14, 25 | 0, 32, 0, 65, 1, 54, 2, 0, 32, 0, 40, 2, 0, 11, 26 | ]); 27 | const module = new WebAssembly.Module(binary); 28 | const instance = new WebAssembly.Instance(module, {}); 29 | // test storing to and loading from a non-zero location via a parameter. 30 | // Safari on iOS 11.2.X returns 0 unexpectedly at non-zero locations 31 | return instance.exports.test(4) !== 0; 32 | } 33 | 34 | isIgnoreBrowser() { 35 | // Android Default Browser is not supported because it will be unexpected behaviour. 36 | if (this.isAndroidDefaultBrowser()) { return true; } 37 | 38 | // Google Chrome version less or 60 is not supported WebAssembly fully. 39 | if (this.ua.Chrome && this.browserMajorVersion() <= 60) { 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | browserMajorVersion() { 46 | const semanticVersion = this.ua.BROWSER_VERSION.split('.'); 47 | if (semanticVersion.length === 3) { 48 | return parseInt(semanticVersion[0], 10); 49 | } 50 | return 0; 51 | } 52 | 53 | isAndroidDefaultBrowser() { 54 | const ua = this.ua; 55 | if (!ua.Android) { return false; } 56 | 57 | return ((/Linux; U;/.test(ua) && !/Chrome/.test(ua)) 58 | || (/Chrome/.test(ua) && /Version/.test(ua)) 59 | || (/Chrome/.test(ua) && /SamsungBrowser/.test(ua))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/loader.js: -------------------------------------------------------------------------------- 1 | import WasmHelper from './helper'; 2 | 3 | /** 4 | * @example 5 | * const loader = new WasmLoader(); 6 | * loader.load( 7 | * () => import('./hello-wasm'), 8 | * () => import('./hello') 9 | * ).then(module => { 10 | * console.log('loaded module', module); 11 | * module.hello(); 12 | * }); 13 | * @class WasmLoader 14 | */ 15 | export default class WasmLoader { 16 | constructor() { 17 | this.helper = new WasmHelper(); 18 | } 19 | 20 | /** 21 | * Load call dynamic import statement for loading wasm module. 22 | * First, try to call dynamic import callback for **`wasm`** module. 23 | * But if your browser doesn't support to `WebAssembly`, 24 | * this try to call dynamic import callback for **`asm.js`** module. 25 | * 26 | * @memberof WasmLoader 27 | * @param {Function} - returns Promise by dynamic import for wasm 28 | * @param {Function} - returns Promise by dynamic import for asm.js 29 | * @return {Promise} 30 | */ 31 | load(wasmImportCallback, asmjsImportCallback) { 32 | if (!this.helper.canUseWebAssembly()) { 33 | return this._loadFromAsmJS(asmjsImportCallback); 34 | } 35 | 36 | return this._loadFromWasm(wasmImportCallback, asmjsImportCallback); 37 | } 38 | 39 | static _loadFromAsmJS(asmjsImportCallback) { 40 | if (!asmjsImportCallback) { 41 | return Promise.reject(new Error('required callback for asm.js')); 42 | } 43 | 44 | return asmjsImportCallback().then((module) => { 45 | const loadedModule = module(); 46 | loadedModule.then = null; // remove promise object 47 | return loadedModule; 48 | }); 49 | } 50 | 51 | _loadFromWasm(wasmImportCallback, asmjsImportCallback) { 52 | if (!wasmImportCallback) { 53 | return Promise.reject(new Error('required callback for wasm')); 54 | } 55 | 56 | return wasmImportCallback().then(module => module().asm) 57 | .catch(() => { 58 | // cannot load wasm module. fallback to asm.js 59 | return this._loadFromAsmJS(asmjsImportCallback); 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /wasm-builder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "compress/gzip" 7 | "crypto/md5" 8 | "errors" 9 | "flag" 10 | "fmt" 11 | "io/ioutil" 12 | "log" 13 | "os" 14 | "os/exec" 15 | "path/filepath" 16 | "text/template" 17 | ) 18 | 19 | var ( 20 | fileName = flag.String("name", "module", "output filename. if '--name=output' specified, generated output-wasm.js and output.wasm") 21 | compressed = flag.Bool("compressed", false, "use gzip compress for wasm file") 22 | src = flag.String("src", ".", "generate src directory") 23 | dst = flag.String("dst", ".", "generate target directory") 24 | ) 25 | 26 | func validateOption() error { 27 | if fileName == nil { 28 | flag.PrintDefaults() 29 | return errors.New("required --name option") 30 | } 31 | return nil 32 | } 33 | 34 | type wasmBuilder struct { 35 | fileName string 36 | src string 37 | dst string 38 | cwd string 39 | compressed bool 40 | } 41 | 42 | func newWasmBuilder(fileName, src, dst string, compressed bool) (*wasmBuilder, error) { 43 | cwd, err := os.Getwd() 44 | if err != nil { 45 | return nil, err 46 | } 47 | return &wasmBuilder{ 48 | fileName: fileName, 49 | src: src, 50 | dst: dst, 51 | cwd: cwd, 52 | compressed: compressed, 53 | }, nil 54 | } 55 | 56 | func (b *wasmBuilder) command(args ...string) *exec.Cmd { 57 | cmd := exec.Command(args[0], args[1:]...) 58 | cmd.Dir = b.cwd 59 | return cmd 60 | } 61 | 62 | func (b *wasmBuilder) runBuildCommand(args []string) error { 63 | log.Println("- run build command") 64 | if len(args) == 0 { 65 | return errors.New("required build command") 66 | } 67 | cmd := b.command(args...) 68 | stdout, err := cmd.StdoutPipe() 69 | if err != nil { 70 | return err 71 | } 72 | cmd.Start() 73 | 74 | scanner := bufio.NewScanner(stdout) 75 | for scanner.Scan() { 76 | log.Println(scanner.Text()) 77 | } 78 | 79 | cmd.Wait() 80 | return nil 81 | } 82 | 83 | func (b *wasmBuilder) wasmFilePath() string { 84 | return filepath.Join(b.cwd, b.src, b.fileName+".wasm") 85 | } 86 | 87 | func (b *wasmBuilder) wastFilePath() string { 88 | return filepath.Join(b.cwd, b.src, b.fileName+".wast") 89 | } 90 | 91 | func (b *wasmBuilder) runWasm2Wat() error { 92 | log.Println("- run wasm2wat") 93 | return b.command("wasm2wat", b.wasmFilePath(), "-o", b.wastFilePath()).Run() 94 | } 95 | 96 | func (b *wasmBuilder) runWat2Wasm() error { 97 | log.Println("- run wat2wasm") 98 | return b.command("wat2wasm", b.wastFilePath(), "-o", b.wasmFilePath()).Run() 99 | } 100 | 101 | func (b *wasmBuilder) replaceWasmInitialPageNumber() error { 102 | log.Println("- replace wasm initial page number") 103 | return b.command( 104 | "sed", 105 | "-i", 106 | "-e", 107 | `s/(import "env" "memory" (memory (;0;) 256))/(import "env" "memory" (memory (;0;) 1))/`, 108 | b.wastFilePath(), 109 | ).Run() 110 | } 111 | 112 | func (b *wasmBuilder) wasmVersion() (string, error) { 113 | wasmFilePath := filepath.Join(b.cwd, b.src, b.fileName+".wasm") 114 | bytes, err := ioutil.ReadFile(wasmFilePath) 115 | if err != nil { 116 | return "", err 117 | } 118 | return fmt.Sprintf("%x", md5.Sum(bytes)), nil 119 | } 120 | 121 | func (b *wasmBuilder) compressWasmFile() error { 122 | if !b.compressed { 123 | return nil 124 | } 125 | 126 | log.Println("- compress wasm") 127 | file, err := ioutil.ReadFile(b.wasmFilePath()) 128 | if err != nil { 129 | return err 130 | } 131 | var buf bytes.Buffer 132 | zw := gzip.NewWriter(&buf) 133 | defer zw.Close() 134 | if _, err := zw.Write(file); err != nil { 135 | return err 136 | } 137 | if err := zw.Flush(); err != nil { 138 | return err 139 | } 140 | 141 | return ioutil.WriteFile(b.wasmFilePath(), buf.Bytes(), 0644) 142 | } 143 | 144 | func (b *wasmBuilder) putWasmFileToDstDirectory() error { 145 | log.Println("- move wasm file to dst directory") 146 | dstWasmPath := filepath.Join(b.cwd, b.dst, b.fileName+".wasm") 147 | return os.Rename(b.wasmFilePath(), dstWasmPath) 148 | } 149 | 150 | func (b *wasmBuilder) putWasmHelperFileToDstDirectory() error { 151 | log.Println("- output js file to dst directory") 152 | jsPath := filepath.Join(b.cwd, b.src, b.fileName+".js") 153 | jsContent, err := ioutil.ReadFile(jsPath) 154 | if err != nil { 155 | return err 156 | } 157 | tmpl, err := template.New("").Parse(string(jsContent)) 158 | if err != nil { 159 | return err 160 | } 161 | version, err := b.wasmVersion() 162 | if err != nil { 163 | return err 164 | } 165 | param := struct { 166 | Version string 167 | Name string 168 | }{ 169 | Version: version, 170 | Name: *fileName, 171 | } 172 | var buf bytes.Buffer 173 | if err := tmpl.Execute(&buf, ¶m); err != nil { 174 | return err 175 | } 176 | 177 | dstJsPath := filepath.Join(b.cwd, b.dst, b.fileName+"-wasm.js") 178 | return ioutil.WriteFile(dstJsPath, buf.Bytes(), 0644) 179 | } 180 | 181 | func (b *wasmBuilder) run(args []string) error { 182 | if err := b.runBuildCommand(args); err != nil { 183 | return err 184 | } 185 | if err := b.runWasm2Wat(); err != nil { 186 | return err 187 | } 188 | if err := b.replaceWasmInitialPageNumber(); err != nil { 189 | return err 190 | } 191 | if err := b.runWat2Wasm(); err != nil { 192 | return err 193 | } 194 | if err := b.compressWasmFile(); err != nil { 195 | return err 196 | } 197 | if err := b.putWasmFileToDstDirectory(); err != nil { 198 | return err 199 | } 200 | if err := b.putWasmHelperFileToDstDirectory(); err != nil { 201 | return err 202 | } 203 | return nil 204 | } 205 | 206 | func _main(args []string) error { 207 | if err := validateOption(); err != nil { 208 | return err 209 | } 210 | builder, err := newWasmBuilder(*fileName, *src, *dst, *compressed) 211 | if err != nil { 212 | return err 213 | } 214 | return builder.run(args) 215 | } 216 | 217 | func main() { 218 | flag.Parse() 219 | if err := _main(flag.Args()); err != nil { 220 | log.Printf("error: %+v\n", err) 221 | os.Exit(1) 222 | } 223 | os.Exit(0) 224 | } 225 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | 5 | module.exports = { 6 | devtool: 'source-map', 7 | entry: './src/loader.js', 8 | output: { 9 | publicPath: '/', 10 | path: path.resolve(__dirname, 'dist'), 11 | filename: 'wasm-loader.js', 12 | library: 'WasmLoader', 13 | libraryTarget: 'umd' 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.js$/, 19 | exclude: /node_modules/, 20 | use: 'babel-loader' 21 | } 22 | ] 23 | }, 24 | 25 | plugins: [ 26 | new webpack.optimize.UglifyJsPlugin({ 27 | sourceMap: false 28 | }) 29 | ], 30 | 31 | devServer: { 32 | contentBase: 'dist', 33 | disableHostCheck: true, 34 | inline: true, 35 | historyApiFallback: true, 36 | compress: true 37 | } 38 | }; 39 | --------------------------------------------------------------------------------