From b0f615d94288f751cc87c1a81212a9ae76ab0a7d Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 4 Dec 2021 12:18:04 +0100 Subject: [PATCH 1/2] loader: Fix TypedArray view buffer range --- lib/loader/index.js | 6 +- lib/loader/umd/index.js | 121 +++++++++++++++++++++++++--------------- 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/lib/loader/index.js b/lib/loader/index.js index b76d8a89c3..d4e6120e65 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -29,7 +29,7 @@ const VAL_MANAGED = 1 << 14; // Array(BufferView) layout const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0; const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4; -const ARRAYBUFFERVIEW_DATALENGTH_OFFSET = 8; +const ARRAYBUFFERVIEW_BYTELENGTH_OFFSET = 8; const ARRAYBUFFERVIEW_SIZE = 12; const ARRAY_LENGTH_OFFSET = 12; const ARRAY_SIZE = 16; @@ -212,7 +212,7 @@ function postInstantiate(extendedExports, instance) { const U32 = new Uint32Array(memory.buffer); U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = buf; U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf; - U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align; + U32[arr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] = length << align; if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length; result = arr; } @@ -288,7 +288,7 @@ function postInstantiate(extendedExports, instance) { const buffer = memory.buffer; const U32 = new Uint32Array(buffer); const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; - return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2); + return new Type(buffer, bufPtr, U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2); } /** Attach a set of get TypedArray and View functions to the exports. */ diff --git a/lib/loader/umd/index.js b/lib/loader/umd/index.js index 44a6fe11a0..dedf4d807c 100644 --- a/lib/loader/umd/index.js +++ b/lib/loader/umd/index.js @@ -38,10 +38,17 @@ var loader = (function(exports) { const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0; const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4; - const ARRAYBUFFERVIEW_DATALENGTH_OFFSET = 8; + const ARRAYBUFFERVIEW_BYTELENGTH_OFFSET = 8; const ARRAYBUFFERVIEW_SIZE = 12; const ARRAY_LENGTH_OFFSET = 12; const ARRAY_SIZE = 16; + const E_NO_EXPORT_TABLE = "Operation requires compiling with --exportTable"; + const E_NO_EXPORT_RUNTIME = "Operation requires compiling with --exportRuntime"; + + const F_NO_EXPORT_RUNTIME = () => { + throw Error(E_NO_EXPORT_RUNTIME); + }; + const BIGINT = typeof BigUint64Array !== "undefined"; const THIS = Symbol(); const STRING_SMALLSIZE = 192; // break-even point in V8 @@ -52,8 +59,14 @@ var loader = (function(exports) { fatal: true }); // != wtf16 + /** polyfill for Object.hasOwn */ + + Object.hasOwn = Object.hasOwn || function (obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); + }; /** Gets a string from memory. */ + function getStringImpl(buffer, ptr) { let len = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2] >>> 1; const wtf16 = new Uint16Array(buffer, ptr, len); @@ -102,12 +115,6 @@ var loader = (function(exports) { imports.Date = imports.Date || Date; return extendedExports; } - - const E_NOEXPORTRUNTIME = "Operation requires compiling with --exportRuntime"; - - const F_NOEXPORTRUNTIME = function () { - throw Error(E_NOEXPORTRUNTIME); - }; /** Prepares the final module once instantiation is complete. */ @@ -116,47 +123,43 @@ var loader = (function(exports) { const memory = exports.memory; const table = exports.table; - const __new = exports.__new || F_NOEXPORTRUNTIME; + const __new = exports.__new || F_NO_EXPORT_RUNTIME; - const __pin = exports.__pin || F_NOEXPORTRUNTIME; + const __pin = exports.__pin || F_NO_EXPORT_RUNTIME; - const __unpin = exports.__unpin || F_NOEXPORTRUNTIME; + const __unpin = exports.__unpin || F_NO_EXPORT_RUNTIME; - const __collect = exports.__collect || F_NOEXPORTRUNTIME; + const __collect = exports.__collect || F_NO_EXPORT_RUNTIME; const __rtti_base = exports.__rtti_base; - const getRttiCount = __rtti_base ? function (arr) { - return arr[__rtti_base >>> 2]; - } : F_NOEXPORTRUNTIME; + const getRttiCount = __rtti_base ? arr => arr[__rtti_base >>> 2] : F_NO_EXPORT_RUNTIME; extendedExports.__new = __new; extendedExports.__pin = __pin; extendedExports.__unpin = __unpin; extendedExports.__collect = __collect; /** Gets the runtime type info for the given id. */ - function getInfo(id) { + function getRttInfo(id) { + const U32 = new Uint32Array(memory.buffer); + if ((id >>>= 0) >= getRttiCount(U32)) throw Error(`invalid id: ${id}`); + return U32[(__rtti_base + 4 >>> 2) + (id << 1)]; + } + /** Gets the runtime base id for the given id. */ + + + function getRttBase(id) { const U32 = new Uint32Array(memory.buffer); - const count = getRttiCount(U32); - if ((id >>>= 0) >= count) throw Error(`invalid id: ${id}`); - return U32[(__rtti_base + 4 >>> 2) + id * 2]; + if ((id >>>= 0) >= getRttiCount(U32)) throw Error(`invalid id: ${id}`); + return U32[(__rtti_base + 4 >>> 2) + (id << 1) + 1]; } /** Gets and validate runtime type info for the given id for array like objects */ function getArrayInfo(id) { - const info = getInfo(id); + const info = getRttInfo(id); if (!(info & (ARRAYBUFFERVIEW | ARRAY | STATICARRAY))) throw Error(`not an array: ${id}, flags=${info}`); return info; } - /** Gets the runtime base id for the given id. */ - - - function getBase(id) { - const U32 = new Uint32Array(memory.buffer); - const count = getRttiCount(U32); - if ((id >>>= 0) >= count) throw Error(`invalid id: ${id}`); - return U32[(__rtti_base + 4 >>> 2) + id * 2 + 1]; - } /** Gets the runtime alignment of a collection's values. */ @@ -185,6 +188,20 @@ var loader = (function(exports) { } extendedExports.__newString = __newString; + /** Allocates a new ArrayBuffer in the module's memory and returns its pointer. */ + + function __newArrayBuffer(buf) { + if (buf == null) return 0; + const bufview = new Uint8Array(buf); + + const ptr = __new(bufview.length, ARRAYBUFFER_ID); + + const U8 = new Uint8Array(memory.buffer); + U8.set(bufview, ptr); + return ptr; + } + + extendedExports.__newArrayBuffer = __newArrayBuffer; /** Reads a string from the module's memory by its pointer. */ function __getString(ptr) { @@ -230,10 +247,12 @@ var loader = (function(exports) { /** Allocates a new array in the module's memory and returns its pointer. */ - function __newArray(id, values) { + function __newArray(id, valuesOrCapacity = 0) { + const input = valuesOrCapacity; const info = getArrayInfo(id); const align = getValueAlign(info); - const length = values.length; + const isArrayLike = typeof input !== "number"; + const length = isArrayLike ? input.length : input; const buf = __new(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID); @@ -251,20 +270,22 @@ var loader = (function(exports) { const U32 = new Uint32Array(memory.buffer); U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = buf; U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf; - U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align; + U32[arr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] = length << align; if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length; result = arr; } - const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT); + if (isArrayLike) { + const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT); + const start = buf >>> align; - if (info & VAL_MANAGED) { - for (let i = 0; i < length; ++i) { - const value = values[i]; - view[(buf >>> align) + i] = value; + if (info & VAL_MANAGED) { + for (let i = 0; i < length; ++i) { + view[start + i] = input[i]; + } + } else { + view.set(input, start); } - } else { - view.set(values, buf >>> align); } return result; @@ -307,6 +328,15 @@ var loader = (function(exports) { } extendedExports.__getArrayBuffer = __getArrayBuffer; + /** Gets a function from poiner which contain table's index. */ + + function __getFunction(ptr) { + if (!table) throw Error(E_NO_EXPORT_TABLE); + const index = new Uint32Array(memory.buffer)[ptr >>> 2]; + return table.get(index); + } + + extendedExports.__getFunction = __getFunction; /** Copies a typed array's values from the module's memory. */ function getTypedArray(Type, alignLog2, ptr) { @@ -319,7 +349,7 @@ var loader = (function(exports) { const buffer = memory.buffer; const U32 = new Uint32Array(buffer); const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; - return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2); + return new Type(buffer, bufPtr, U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2); } /** Attach a set of get TypedArray and View functions to the exports. */ @@ -348,7 +378,7 @@ var loader = (function(exports) { if (id <= getRttiCount(U32)) { do { if (id == baseId) return true; - id = getBase(id); + id = getRttBase(id); } while (id); } @@ -424,15 +454,14 @@ var loader = (function(exports) { /* nop */ }); - for (let internalName in exports) { - if (!Object.prototype.hasOwnProperty.call(exports, internalName)) continue; + for (let internalName of Object.keys(exports)) { const elem = exports[internalName]; let parts = internalName.split("."); let curr = extendedExports; while (parts.length > 1) { let part = parts.shift(); - if (!Object.prototype.hasOwnProperty.call(curr, part)) curr[part] = {}; + if (!Object.hasOwn(curr, part)) curr[part] = {}; curr = curr[part]; } @@ -472,7 +501,7 @@ var loader = (function(exports) { curr = curr[className].prototype; if (/^(get|set):/.test(name)) { - if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) { + if (!Object.hasOwn(curr, name = name.substring(4))) { let getter = exports[internalName.replace("set:", "get:")]; let setter = exports[internalName.replace("get:", "set:")]; Object.defineProperty(curr, name, { @@ -489,7 +518,7 @@ var loader = (function(exports) { } } else { if (name === 'constructor') { - (curr[name] = (...args) => { + (curr[name] = function (...args) { setArgumentsLength(args.length); return elem(...args); }).original = elem; @@ -504,7 +533,7 @@ var loader = (function(exports) { } } else { if (/^(get|set):/.test(name)) { - if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) { + if (!Object.hasOwn(curr, name = name.substring(4))) { Object.defineProperty(curr, name, { get: exports[internalName.replace("set:", "get:")], set: exports[internalName.replace("get:", "set:")], From fcf4ac745082a3226d7a099c921ffb10802be842 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 5 Dec 2021 15:44:44 +0100 Subject: [PATCH 2/2] apply suggestion --- lib/loader/index.js | 7 +++++-- lib/loader/umd/index.js | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/loader/index.js b/lib/loader/index.js index d4e6120e65..1185890644 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -287,8 +287,11 @@ function postInstantiate(extendedExports, instance) { function getTypedArrayView(Type, alignLog2, ptr) { const buffer = memory.buffer; const U32 = new Uint32Array(buffer); - const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; - return new Type(buffer, bufPtr, U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2); + return new Type( + buffer, + U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2], + U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2 + ); } /** Attach a set of get TypedArray and View functions to the exports. */ diff --git a/lib/loader/umd/index.js b/lib/loader/umd/index.js index dedf4d807c..950abb749e 100644 --- a/lib/loader/umd/index.js +++ b/lib/loader/umd/index.js @@ -348,8 +348,7 @@ var loader = (function(exports) { function getTypedArrayView(Type, alignLog2, ptr) { const buffer = memory.buffer; const U32 = new Uint32Array(buffer); - const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; - return new Type(buffer, bufPtr, U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2); + return new Type(buffer, U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2], U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2); } /** Attach a set of get TypedArray and View functions to the exports. */