1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
|
/*
* Copyright 2015 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function integrateWasmJS(Module) {
// wasm.js has several methods for creating the compiled code module here:
// * 'native-wasm' : use native WebAssembly support in the browser
// * 'interpret-s-expr': load s-expression code from a .wast and interpret
// * 'interpret-binary': load binary wasm and interpret
// * 'interpret-asm2wasm': load asm.js code, translate to wasm, and interpret
// * 'asmjs': no wasm, just load the asm.js code and use that (good for testing)
// The method can be set at compile time (BINARYEN_METHOD), or runtime by setting Module['wasmJSMethod'].
// The method can be a comma-separated list, in which case, we will try the
// options one by one. Some of them can fail gracefully, and then we can try
// the next.
// inputs
var method = Module['wasmJSMethod'] || {{{ wasmJSMethod }}} || 'native-wasm'; // by default, use native support
Module['wasmJSMethod'] = method;
var wasmTextFile = Module['wasmTextFile'] || {{{ wasmTextFile }}};
var wasmBinaryFile = Module['wasmBinaryFile'] || {{{ wasmBinaryFile }}};
var asmjsCodeFile = Module['asmjsCodeFile'] || {{{ asmjsCodeFile }}};
// utilities
var wasmPageSize = 64*1024;
var asm2wasmImports = { // special asm2wasm imports
"f64-rem": function(x, y) {
return x % y;
},
"f64-to-int": function(x) {
return x | 0;
},
"i32s-div": function(x, y) {
return ((x | 0) / (y | 0)) | 0;
},
"i32u-div": function(x, y) {
return ((x >>> 0) / (y >>> 0)) >>> 0;
},
"i32s-rem": function(x, y) {
return ((x | 0) % (y | 0)) | 0;
},
"i32u-rem": function(x, y) {
return ((x >>> 0) % (y >>> 0)) >>> 0;
},
"debugger": function() {
debugger;
},
};
var info = {
'global': null,
'env': null,
'asm2wasm': asm2wasmImports,
'parent': Module // Module inside wasm-js.cpp refers to wasm-js.cpp; this allows access to the outside program.
};
var exports = null;
function lookupImport(mod, base) {
var lookup = info;
if (mod.indexOf('.') < 0) {
lookup = (lookup || {})[mod];
} else {
var parts = mod.split('.');
lookup = (lookup || {})[parts[0]];
lookup = (lookup || {})[parts[1]];
}
if (base) {
lookup = (lookup || {})[base];
}
if (lookup === undefined) {
abort('bad lookupImport to (' + mod + ').' + base);
}
return lookup;
}
function mergeMemory(newBuffer) {
// The wasm instance creates its memory. But static init code might have written to
// buffer already, including the mem init file, and we must copy it over in a proper merge.
// TODO: avoid this copy, by avoiding such static init writes
// TODO: in shorter term, just copy up to the last static init write
var oldBuffer = Module['buffer'];
if (newBuffer.byteLength < oldBuffer.byteLength) {
Module['printErr']('the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here');
}
var oldView = new Int8Array(oldBuffer);
var newView = new Int8Array(newBuffer);
// If we have a mem init file, do not trample it
if (!memoryInitializer) {
oldView.set(newView.subarray(STATIC_BASE, STATIC_BASE + STATIC_BUMP), STATIC_BASE);
}
newView.set(oldView);
updateGlobalBuffer(newBuffer);
updateGlobalBufferViews();
}
var WasmTypes = {
none: 0,
i32: 1,
i64: 2,
f32: 3,
f64: 4
};
function fixImports(imports) {
if (!{{{ WASM_BACKEND }}}) return imports;
var ret = {};
for (var i in imports) {
var fixed = i;
if (fixed[0] == '_') fixed = fixed.substr(1);
ret[fixed] = imports[i];
}
return ret;
}
function getBinary() {
var binary;
if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
binary = Module['wasmBinary'];
assert(binary, "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)");
binary = new Uint8Array(binary);
} else {
binary = Module['readBinary'](wasmBinaryFile);
}
return binary;
}
// do-method functions
function doJustAsm(global, env, providedBuffer) {
// if no Module.asm, or it's the method handler helper (see below), then apply
// the asmjs
if (typeof Module['asm'] !== 'function' || Module['asm'] === methodHandler) {
if (!Module['asmPreload']) {
// you can load the .asm.js file before this, to avoid this sync xhr and eval
eval(Module['read'](asmjsCodeFile)); // set Module.asm
} else {
Module['asm'] = Module['asmPreload'];
}
}
if (typeof Module['asm'] !== 'function') {
Module['printErr']('asm evalling did not set the module properly');
return false;
}
return Module['asm'](global, env, providedBuffer);
}
function doNativeWasm(global, env, providedBuffer) {
if (typeof WebAssembly !== 'object') {
Module['printErr']('no native wasm support detected');
return false;
}
// prepare memory import
if (!(Module['wasmMemory'] instanceof WebAssembly.Memory)) {
Module['printErr']('no native wasm Memory in use');
return false;
}
env['memory'] = Module['wasmMemory'];
// Load the wasm module and create an instance of using native support in the JS engine.
info['global'] = {
'NaN': NaN,
'Infinity': Infinity
};
info['global.Math'] = global.Math;
info['env'] = env;
var instance;
try {
instance = new WebAssembly.Instance(new WebAssembly.Module(getBinary()), info)
} catch (e) {
Module['printErr']('failed to compile wasm module: ' + e);
if (e.toString().indexOf('imported Memory with incompatible size') >= 0) {
Module['printErr']('Memory size incompatibility issues may be due to changing TOTAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set TOTAL_MEMORY at runtime to something smaller than it was at compile time).');
}
return false;
}
exports = instance.exports;
if (exports.memory) mergeMemory(exports.memory);
Module["usingWasm"] = true;
return exports;
}
function doWasmPolyfill(global, env, providedBuffer, method) {
if (typeof WasmJS !== 'function') {
Module['printErr']('WasmJS not detected - polyfill not bundled?');
return false;
}
// Use wasm.js to polyfill and execute code in a wasm interpreter.
var wasmJS = WasmJS({});
// XXX don't be confused. Module here is in the outside program. wasmJS is the inner wasm-js.cpp.
wasmJS['outside'] = Module; // Inside wasm-js.cpp, Module['outside'] reaches the outside module.
// Information for the instance of the module.
wasmJS['info'] = info;
wasmJS['lookupImport'] = lookupImport;
assert(providedBuffer === Module['buffer']); // we should not even need to pass it as a 3rd arg for wasm, but that's the asm.js way.
info.global = global;
info.env = env;
// polyfill interpreter expects an ArrayBuffer
assert(providedBuffer === Module['buffer']);
env['memory'] = providedBuffer;
assert(env['memory'] instanceof ArrayBuffer);
wasmJS['providedTotalMemory'] = Module['buffer'].byteLength;
// Prepare to generate wasm, using either asm2wasm or s-exprs
var code;
if (method === 'interpret-binary') {
code = getBinary();
} else {
code = Module['read'](method == 'interpret-asm2wasm' ? asmjsCodeFile : wasmTextFile);
}
var temp;
if (method == 'interpret-asm2wasm') {
temp = wasmJS['_malloc'](code.length + 1);
wasmJS['writeAsciiToMemory'](code, temp);
wasmJS['_load_asm2wasm'](temp);
} else if (method === 'interpret-s-expr') {
temp = wasmJS['_malloc'](code.length + 1);
wasmJS['writeAsciiToMemory'](code, temp);
wasmJS['_load_s_expr2wasm'](temp);
} else if (method === 'interpret-binary') {
temp = wasmJS['_malloc'](code.length);
wasmJS['HEAPU8'].set(code, temp);
wasmJS['_load_binary2wasm'](temp, code.length);
} else {
throw 'what? ' + method;
}
wasmJS['_free'](temp);
wasmJS['_instantiate'](temp);
if (Module['newBuffer']) {
mergeMemory(Module['newBuffer']);
Module['newBuffer'] = null;
}
exports = wasmJS['asmExports'];
return exports;
}
// We may have a preloaded value in Module.asm, save it
Module['asmPreload'] = Module['asm'];
// Memory growth integration code
Module['reallocBuffer'] = function(size) {
size = Math.ceil(size / wasmPageSize) * wasmPageSize; // round up to wasm page size
var old = Module['buffer'];
var result = exports['__growWasmMemory'](size / wasmPageSize); // tiny wasm method that just does grow_memory
if (Module["usingWasm"]) {
if (result !== (-1 | 0)) {
// success in native wasm memory growth, get the buffer from the memory
return Module['buffer'] = Module['wasmMemory'].buffer;
} else {
return null;
}
} else {
// in interpreter, we replace Module.buffer if we allocate
return Module['buffer'] !== old ? Module['buffer'] : null; // if it was reallocated, it changed
}
};
// Provide an "asm.js function" for the application, called to "link" the asm.js module. We instantiate
// the wasm module at that time, and it receives imports and provides exports and so forth, the app
// doesn't need to care that it is wasm or olyfilled wasm or asm.js.
Module['asm'] = function(global, env, providedBuffer) {
global = fixImports(global);
env = fixImports(env);
// import table
if (!env['table']) {
var TABLE_SIZE = Module['wasmTableSize'];
if (TABLE_SIZE === undefined) TABLE_SIZE = 1024; // works in binaryen interpreter at least
if (typeof WebAssembly === 'object' && typeof WebAssembly.Table === 'function') {
env['table'] = new WebAssembly.Table({ initial: TABLE_SIZE, maximum: TABLE_SIZE, element: 'anyfunc' });
} else {
env['table'] = new Array(TABLE_SIZE); // works in binaryen interpreter at least
}
}
if (!env['memoryBase']) {
env['memoryBase'] = STATIC_BASE; // tell the memory segments where to place themselves
}
if (!env['tableBase']) {
env['tableBase'] = 0; // table starts at 0 by default, in dynamic linking this will change
}
// try the methods. each should return the exports if it succeeded
var exports;
var methods = method.split(',');
for (var i = 0; i < methods.length; i++) {
var curr = methods[i];
Module['printErr']('trying binaryen method: ' + curr);
if (curr === 'native-wasm') {
if (exports = doNativeWasm(global, env, providedBuffer)) break;
} else if (curr === 'asmjs') {
if (exports = doJustAsm(global, env, providedBuffer)) break;
} else if (curr === 'interpret-asm2wasm' || curr === 'interpret-s-expr' || curr === 'interpret-binary') {
if (exports = doWasmPolyfill(global, env, providedBuffer, curr)) break;
} else {
throw 'bad method: ' + curr;
}
}
if (!exports) throw 'no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods';
Module['printErr']('binaryen method succeeded.');
return exports;
};
var methodHandler = Module['asm']; // note our method handler, as we may modify Module['asm'] later
}
|