Skip to content

loader: Fix TypedArray view not considering .byteLength of slices #2162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lib/loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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[bufPtr + SIZE_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. */
Expand Down
122 changes: 75 additions & 47 deletions lib/loader/umd/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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. */


Expand All @@ -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. */


Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -318,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[bufPtr + SIZE_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. */

Expand Down Expand Up @@ -348,7 +377,7 @@ var loader = (function(exports) {
if (id <= getRttiCount(U32)) {
do {
if (id == baseId) return true;
id = getBase(id);
id = getRttBase(id);
} while (id);
}

Expand Down Expand Up @@ -424,15 +453,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];
}

Expand Down Expand Up @@ -472,7 +500,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, {
Expand All @@ -489,7 +517,7 @@ var loader = (function(exports) {
}
} else {
if (name === 'constructor') {
(curr[name] = (...args) => {
(curr[name] = function (...args) {
setArgumentsLength(args.length);
return elem(...args);
}).original = elem;
Expand All @@ -504,7 +532,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:")],
Expand Down