mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 23:42:15 +00:00
Update loader to support environments where 'new WebAssembly.Instance' is limited, see #295
This commit is contained in:
parent
63d4579118
commit
e22524fab8
@ -2,45 +2,69 @@
|
|||||||
|
|
||||||
const hasBigInt64 = typeof BigUint64Array !== "undefined";
|
const hasBigInt64 = typeof BigUint64Array !== "undefined";
|
||||||
|
|
||||||
/** Instantiates an AssemblyScript module using the specified imports. */
|
/** Gets a string from an U32 and an U16 view on a memory. */
|
||||||
function instantiate(module, imports) {
|
function getStringImpl(U32, U16, ptr) {
|
||||||
|
var dataLength = U32[ptr >>> 2];
|
||||||
|
var dataOffset = (ptr + 4) >>> 1;
|
||||||
|
var dataRemain = dataLength;
|
||||||
|
var parts = [];
|
||||||
|
const chunkSize = 1024;
|
||||||
|
while (dataRemain > chunkSize) {
|
||||||
|
let last = U16[dataOffset + chunkSize - 1];
|
||||||
|
let size = last >= 0xD800 && last < 0xDC00 ? chunkSize - 1 : chunkSize;
|
||||||
|
let part = U16.subarray(dataOffset, dataOffset += size);
|
||||||
|
parts.push(String.fromCharCode.apply(String, part));
|
||||||
|
dataRemain -= size;
|
||||||
|
}
|
||||||
|
return parts.join("") + String.fromCharCode.apply(String, U16.subarray(dataOffset, dataOffset + dataRemain));
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the imports object
|
/** Prepares the base module prior to instantiation. */
|
||||||
if (!imports) imports = {};
|
function preInstantiate(imports) {
|
||||||
|
var baseModule = {};
|
||||||
|
|
||||||
|
// add the internal abort function that is called when an assertion fails or an error is thrown
|
||||||
if (!imports.env) imports.env = {};
|
if (!imports.env) imports.env = {};
|
||||||
if (!imports.env.abort) imports.env.abort = function(mesg, file, line, colm) {
|
if (!imports.env.abort) imports.env.abort = function abort(mesg, file, line, colm) {
|
||||||
mesg = mem ? getString(mesg) : "";
|
var memory = baseModule.memory || this.memory; // prefer exported, otherwise try imported
|
||||||
file = mem ? getString(file) : "<instantiate>";
|
function getString(memory, ptr) {
|
||||||
throw Error("abort: " + mesg + " at " + file + ":" + line + ":" + colm);
|
if (!memory) return "<yet unknown>";
|
||||||
|
var buffer = memory.buffer;
|
||||||
|
return getStringImpl(new Uint32Array(buffer), new Uint16Array(buffer), ptr);
|
||||||
|
}
|
||||||
|
throw Error("abort: " + getString(memory, mesg) + " at " + getString(memory, file) + ":" + line + ":" + colm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate the module and obtain its (flat) exports
|
return baseModule;
|
||||||
var instance = new WebAssembly.Instance(module, imports);
|
}
|
||||||
var exports = instance.exports;
|
|
||||||
var memory_allocate = exports["memory.allocate"];
|
/** Prepares the final module once instantiation is complete. */
|
||||||
var memory_fill = exports["memory.fill"];
|
function postInstantiate(baseModule, instance) {
|
||||||
var memory_free = exports["memory.free"];
|
var memory = instance.exports.memory;
|
||||||
|
var memory_allocate = instance.exports["memory.allocate"];
|
||||||
|
var memory_fill = instance.exports["memory.fill"];
|
||||||
|
var memory_free = instance.exports["memory.free"];
|
||||||
|
|
||||||
// Provide views for all sorts of basic values
|
// Provide views for all sorts of basic values
|
||||||
var mem, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64;
|
var buffer, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64;
|
||||||
|
|
||||||
/** Updates memory views if memory has grown meanwhile. */
|
/** Updates memory views if memory has grown meanwhile. */
|
||||||
function checkMem() {
|
function checkMem() {
|
||||||
// see: https://github.com/WebAssembly/design/issues/1210
|
// see: https://github.com/WebAssembly/design/issues/1210
|
||||||
if (mem !== exports.memory.buffer) {
|
if (buffer !== memory.buffer) {
|
||||||
mem = exports.memory.buffer;
|
buffer = memory.buffer;
|
||||||
I8 = new Int8Array(mem);
|
I8 = new Int8Array(buffer);
|
||||||
U8 = new Uint8Array(mem);
|
U8 = new Uint8Array(buffer);
|
||||||
I16 = new Int16Array(mem);
|
I16 = new Int16Array(buffer);
|
||||||
U16 = new Uint16Array(mem);
|
U16 = new Uint16Array(buffer);
|
||||||
I32 = new Int32Array(mem);
|
I32 = new Int32Array(buffer);
|
||||||
U32 = new Uint32Array(mem);
|
U32 = new Uint32Array(buffer);
|
||||||
if (hasBigInt64) {
|
if (hasBigInt64) {
|
||||||
I64 = new BigInt64Array(mem);
|
I64 = new BigInt64Array(buffer);
|
||||||
U64 = new BigUint64Array(mem);
|
U64 = new BigUint64Array(buffer);
|
||||||
}
|
}
|
||||||
F32 = new Float32Array(mem);
|
F32 = new Float32Array(buffer);
|
||||||
F64 = new Float64Array(mem);
|
F64 = new Float64Array(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkMem();
|
checkMem();
|
||||||
@ -56,24 +80,16 @@ function instantiate(module, imports) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseModule.newString = newString;
|
||||||
|
|
||||||
/** Gets a string from the module's memory by its pointer. */
|
/** Gets a string from the module's memory by its pointer. */
|
||||||
function getString(ptr) {
|
function getString(ptr) {
|
||||||
checkMem();
|
checkMem();
|
||||||
var dataLength = U32[ptr >>> 2];
|
return getStringImpl(U32, U16, ptr);
|
||||||
var dataOffset = (ptr + 4) >>> 1;
|
|
||||||
var dataRemain = dataLength;
|
|
||||||
var parts = [];
|
|
||||||
const chunkSize = 1024;
|
|
||||||
while (dataRemain > chunkSize) {
|
|
||||||
let last = U16[dataOffset + chunkSize - 1];
|
|
||||||
let size = last >= 0xD800 && last < 0xDC00 ? chunkSize - 1 : chunkSize;
|
|
||||||
let part = U16.subarray(dataOffset, dataOffset += size);
|
|
||||||
parts.push(String.fromCharCode.apply(String, part));
|
|
||||||
dataRemain -= size;
|
|
||||||
}
|
|
||||||
return parts.join("") + String.fromCharCode.apply(String, U16.subarray(dataOffset, dataOffset + dataRemain));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseModule.getString = getString;
|
||||||
|
|
||||||
function computeBufferSize(byteLength) {
|
function computeBufferSize(byteLength) {
|
||||||
const HEADER_SIZE = 8;
|
const HEADER_SIZE = 8;
|
||||||
return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1));
|
return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1));
|
||||||
@ -100,7 +116,7 @@ function instantiate(module, imports) {
|
|||||||
U32[ buf >>> 2] = byteLength; // .byteLength
|
U32[ buf >>> 2] = byteLength; // .byteLength
|
||||||
U32[(buf + 4) >>> 2] = 0; // 0
|
U32[(buf + 4) >>> 2] = 0; // 0
|
||||||
if (view) {
|
if (view) {
|
||||||
new ctor(mem, buf + 8, length).set(view);
|
new ctor(buffer, buf + 8, length).set(view);
|
||||||
if (view.length < length && !unsafe) {
|
if (view.length < length && !unsafe) {
|
||||||
let setLength = elementSize * view.length;
|
let setLength = elementSize * view.length;
|
||||||
memory_fill(buf + 8 + setLength, 0, byteLength - setLength);
|
memory_fill(buf + 8 + setLength, 0, byteLength - setLength);
|
||||||
@ -111,6 +127,8 @@ function instantiate(module, imports) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseModule.newArray = newArray;
|
||||||
|
|
||||||
/** Gets a view on a typed array in the module's memory by its pointer. */
|
/** Gets a view on a typed array in the module's memory by its pointer. */
|
||||||
function getArray(ctor, ptr) {
|
function getArray(ctor, ptr) {
|
||||||
var elementSize = ctor.BYTES_PER_ELEMENT;
|
var elementSize = ctor.BYTES_PER_ELEMENT;
|
||||||
@ -119,9 +137,11 @@ function instantiate(module, imports) {
|
|||||||
var buf = U32[ ptr >>> 2];
|
var buf = U32[ ptr >>> 2];
|
||||||
var byteOffset = U32[(ptr + 4) >>> 2];
|
var byteOffset = U32[(ptr + 4) >>> 2];
|
||||||
var byteLength = U32[(ptr + 8) >>> 2];
|
var byteLength = U32[(ptr + 8) >>> 2];
|
||||||
return new ctor(mem, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize);
|
return new ctor(buffer, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseModule.getArray = getArray;
|
||||||
|
|
||||||
/** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */
|
/** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */
|
||||||
function freeArray(ptr) {
|
function freeArray(ptr) {
|
||||||
checkMem();
|
checkMem();
|
||||||
@ -130,40 +150,46 @@ function instantiate(module, imports) {
|
|||||||
memory_free(ptr);
|
memory_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseModule.freeArray = freeArray;
|
||||||
|
|
||||||
// Demangle exports and provide the usual utility on the prototype
|
// Demangle exports and provide the usual utility on the prototype
|
||||||
return demangle(exports, {
|
return demangle(instance.exports, Object.defineProperties(baseModule, {
|
||||||
get I8() { checkMem(); return I8; },
|
I8: { get: function() { checkMem(); return I8; } },
|
||||||
get U8() { checkMem(); return U8; },
|
U8: { get: function() { checkMem(); return U8; } },
|
||||||
get I16() { checkMem(); return I16; },
|
I16: { get: function() { checkMem(); return I16; } },
|
||||||
get U16() { checkMem(); return U16; },
|
U16: { get: function() { checkMem(); return U16; } },
|
||||||
get I32() { checkMem(); return I32; },
|
I32: { get: function() { checkMem(); return I32; } },
|
||||||
get U32() { checkMem(); return U32; },
|
U32: { get: function() { checkMem(); return U32; } },
|
||||||
get I64() { checkMem(); return I64; },
|
I64: { get: function() { checkMem(); return I64; } },
|
||||||
get U64() { checkMem(); return U64; },
|
U64: { get: function() { checkMem(); return U64; } },
|
||||||
get F32() { checkMem(); return F32; },
|
F32: { get: function() { checkMem(); return F32; } },
|
||||||
get F64() { checkMem(); return F64; },
|
F64: { get: function() { checkMem(); return F64; } }
|
||||||
newString,
|
}));
|
||||||
getString,
|
}
|
||||||
newArray,
|
|
||||||
getArray,
|
/** Instantiates an AssemblyScript module using the specified imports. */
|
||||||
freeArray
|
function instantiate(module, imports) {
|
||||||
});
|
return postInstantiate(
|
||||||
|
preInstantiate(imports || (imports = {})),
|
||||||
|
new WebAssembly.Instance(module, imports)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.instantiate = instantiate;
|
exports.instantiate = instantiate;
|
||||||
|
|
||||||
/** Instantiates an AssemblyScript module from a buffer using the specified imports. */
|
/** Instantiates an AssemblyScript module from a buffer using the specified imports. */
|
||||||
function instantiateBuffer(buffer, imports) {
|
function instantiateBuffer(buffer, imports) {
|
||||||
var module = new WebAssembly.Module(buffer);
|
return instantiate(new WebAssembly.Module(buffer), imports);
|
||||||
return instantiate(module, imports);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.instantiateBuffer = instantiateBuffer;
|
exports.instantiateBuffer = instantiateBuffer;
|
||||||
|
|
||||||
/** Instantiates an AssemblyScript module from a response using the specified imports. */
|
/** Instantiates an AssemblyScript module from a response using the specified imports. */
|
||||||
async function instantiateStreaming(response, imports) {
|
async function instantiateStreaming(response, imports) {
|
||||||
var module = await WebAssembly.compileStreaming(response);
|
return postInstantiate(
|
||||||
return instantiate(module, imports);
|
preInstantiate(imports || (imports = {})),
|
||||||
|
await WebAssembly.instantiateStreaming(response, imports)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.instantiateStreaming = instantiateStreaming;
|
exports.instantiateStreaming = instantiateStreaming;
|
||||||
|
8
lib/loader/tests/index.html
Normal file
8
lib/loader/tests/index.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<script>var exports = {};</script>
|
||||||
|
<script src="../index.js"></script>
|
||||||
|
<script>
|
||||||
|
(async () => {
|
||||||
|
var module = await exports.instantiateStreaming(fetch("./build/untouched.wasm"));
|
||||||
|
console.log(module);
|
||||||
|
})();
|
||||||
|
</script>
|
Loading…
x
Reference in New Issue
Block a user