Skip to content

Commit 81d5898

Browse files
authored
fix: loader: Consider .byteLength of slices when obtaining typed arrays (#2162)
1 parent f87a1fd commit 81d5898

File tree

2 files changed

+82
-51
lines changed

2 files changed

+82
-51
lines changed

lib/loader/index.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const VAL_MANAGED = 1 << 14;
2929
// Array(BufferView) layout
3030
const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0;
3131
const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4;
32-
const ARRAYBUFFERVIEW_DATALENGTH_OFFSET = 8;
32+
const ARRAYBUFFERVIEW_BYTELENGTH_OFFSET = 8;
3333
const ARRAYBUFFERVIEW_SIZE = 12;
3434
const ARRAY_LENGTH_OFFSET = 12;
3535
const ARRAY_SIZE = 16;
@@ -212,7 +212,7 @@ function postInstantiate(extendedExports, instance) {
212212
const U32 = new Uint32Array(memory.buffer);
213213
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = buf;
214214
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
215-
U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align;
215+
U32[arr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] = length << align;
216216
if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
217217
result = arr;
218218
}
@@ -287,8 +287,11 @@ function postInstantiate(extendedExports, instance) {
287287
function getTypedArrayView(Type, alignLog2, ptr) {
288288
const buffer = memory.buffer;
289289
const U32 = new Uint32Array(buffer);
290-
const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
291-
return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2);
290+
return new Type(
291+
buffer,
292+
U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2],
293+
U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2
294+
);
292295
}
293296

294297
/** Attach a set of get TypedArray and View functions to the exports. */

lib/loader/umd/index.js

+75-47
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,17 @@ var loader = (function(exports) {
3838

3939
const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0;
4040
const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4;
41-
const ARRAYBUFFERVIEW_DATALENGTH_OFFSET = 8;
41+
const ARRAYBUFFERVIEW_BYTELENGTH_OFFSET = 8;
4242
const ARRAYBUFFERVIEW_SIZE = 12;
4343
const ARRAY_LENGTH_OFFSET = 12;
4444
const ARRAY_SIZE = 16;
45+
const E_NO_EXPORT_TABLE = "Operation requires compiling with --exportTable";
46+
const E_NO_EXPORT_RUNTIME = "Operation requires compiling with --exportRuntime";
47+
48+
const F_NO_EXPORT_RUNTIME = () => {
49+
throw Error(E_NO_EXPORT_RUNTIME);
50+
};
51+
4552
const BIGINT = typeof BigUint64Array !== "undefined";
4653
const THIS = Symbol();
4754
const STRING_SMALLSIZE = 192; // break-even point in V8
@@ -52,8 +59,14 @@ var loader = (function(exports) {
5259
fatal: true
5360
}); // != wtf16
5461

62+
/** polyfill for Object.hasOwn */
63+
64+
Object.hasOwn = Object.hasOwn || function (obj, prop) {
65+
return Object.prototype.hasOwnProperty.call(obj, prop);
66+
};
5567
/** Gets a string from memory. */
5668

69+
5770
function getStringImpl(buffer, ptr) {
5871
let len = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2] >>> 1;
5972
const wtf16 = new Uint16Array(buffer, ptr, len);
@@ -102,12 +115,6 @@ var loader = (function(exports) {
102115
imports.Date = imports.Date || Date;
103116
return extendedExports;
104117
}
105-
106-
const E_NOEXPORTRUNTIME = "Operation requires compiling with --exportRuntime";
107-
108-
const F_NOEXPORTRUNTIME = function () {
109-
throw Error(E_NOEXPORTRUNTIME);
110-
};
111118
/** Prepares the final module once instantiation is complete. */
112119

113120

@@ -116,47 +123,43 @@ var loader = (function(exports) {
116123
const memory = exports.memory;
117124
const table = exports.table;
118125

119-
const __new = exports.__new || F_NOEXPORTRUNTIME;
126+
const __new = exports.__new || F_NO_EXPORT_RUNTIME;
120127

121-
const __pin = exports.__pin || F_NOEXPORTRUNTIME;
128+
const __pin = exports.__pin || F_NO_EXPORT_RUNTIME;
122129

123-
const __unpin = exports.__unpin || F_NOEXPORTRUNTIME;
130+
const __unpin = exports.__unpin || F_NO_EXPORT_RUNTIME;
124131

125-
const __collect = exports.__collect || F_NOEXPORTRUNTIME;
132+
const __collect = exports.__collect || F_NO_EXPORT_RUNTIME;
126133

127134
const __rtti_base = exports.__rtti_base;
128-
const getRttiCount = __rtti_base ? function (arr) {
129-
return arr[__rtti_base >>> 2];
130-
} : F_NOEXPORTRUNTIME;
135+
const getRttiCount = __rtti_base ? arr => arr[__rtti_base >>> 2] : F_NO_EXPORT_RUNTIME;
131136
extendedExports.__new = __new;
132137
extendedExports.__pin = __pin;
133138
extendedExports.__unpin = __unpin;
134139
extendedExports.__collect = __collect;
135140
/** Gets the runtime type info for the given id. */
136141

137-
function getInfo(id) {
142+
function getRttInfo(id) {
143+
const U32 = new Uint32Array(memory.buffer);
144+
if ((id >>>= 0) >= getRttiCount(U32)) throw Error(`invalid id: ${id}`);
145+
return U32[(__rtti_base + 4 >>> 2) + (id << 1)];
146+
}
147+
/** Gets the runtime base id for the given id. */
148+
149+
150+
function getRttBase(id) {
138151
const U32 = new Uint32Array(memory.buffer);
139-
const count = getRttiCount(U32);
140-
if ((id >>>= 0) >= count) throw Error(`invalid id: ${id}`);
141-
return U32[(__rtti_base + 4 >>> 2) + id * 2];
152+
if ((id >>>= 0) >= getRttiCount(U32)) throw Error(`invalid id: ${id}`);
153+
return U32[(__rtti_base + 4 >>> 2) + (id << 1) + 1];
142154
}
143155
/** Gets and validate runtime type info for the given id for array like objects */
144156

145157

146158
function getArrayInfo(id) {
147-
const info = getInfo(id);
159+
const info = getRttInfo(id);
148160
if (!(info & (ARRAYBUFFERVIEW | ARRAY | STATICARRAY))) throw Error(`not an array: ${id}, flags=${info}`);
149161
return info;
150162
}
151-
/** Gets the runtime base id for the given id. */
152-
153-
154-
function getBase(id) {
155-
const U32 = new Uint32Array(memory.buffer);
156-
const count = getRttiCount(U32);
157-
if ((id >>>= 0) >= count) throw Error(`invalid id: ${id}`);
158-
return U32[(__rtti_base + 4 >>> 2) + id * 2 + 1];
159-
}
160163
/** Gets the runtime alignment of a collection's values. */
161164

162165

@@ -185,6 +188,20 @@ var loader = (function(exports) {
185188
}
186189

187190
extendedExports.__newString = __newString;
191+
/** Allocates a new ArrayBuffer in the module's memory and returns its pointer. */
192+
193+
function __newArrayBuffer(buf) {
194+
if (buf == null) return 0;
195+
const bufview = new Uint8Array(buf);
196+
197+
const ptr = __new(bufview.length, ARRAYBUFFER_ID);
198+
199+
const U8 = new Uint8Array(memory.buffer);
200+
U8.set(bufview, ptr);
201+
return ptr;
202+
}
203+
204+
extendedExports.__newArrayBuffer = __newArrayBuffer;
188205
/** Reads a string from the module's memory by its pointer. */
189206

190207
function __getString(ptr) {
@@ -230,10 +247,12 @@ var loader = (function(exports) {
230247
/** Allocates a new array in the module's memory and returns its pointer. */
231248

232249

233-
function __newArray(id, values) {
250+
function __newArray(id, valuesOrCapacity = 0) {
251+
const input = valuesOrCapacity;
234252
const info = getArrayInfo(id);
235253
const align = getValueAlign(info);
236-
const length = values.length;
254+
const isArrayLike = typeof input !== "number";
255+
const length = isArrayLike ? input.length : input;
237256

238257
const buf = __new(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
239258

@@ -251,20 +270,22 @@ var loader = (function(exports) {
251270
const U32 = new Uint32Array(memory.buffer);
252271
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = buf;
253272
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
254-
U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align;
273+
U32[arr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] = length << align;
255274
if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
256275
result = arr;
257276
}
258277

259-
const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT);
278+
if (isArrayLike) {
279+
const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT);
280+
const start = buf >>> align;
260281

261-
if (info & VAL_MANAGED) {
262-
for (let i = 0; i < length; ++i) {
263-
const value = values[i];
264-
view[(buf >>> align) + i] = value;
282+
if (info & VAL_MANAGED) {
283+
for (let i = 0; i < length; ++i) {
284+
view[start + i] = input[i];
285+
}
286+
} else {
287+
view.set(input, start);
265288
}
266-
} else {
267-
view.set(values, buf >>> align);
268289
}
269290

270291
return result;
@@ -307,6 +328,15 @@ var loader = (function(exports) {
307328
}
308329

309330
extendedExports.__getArrayBuffer = __getArrayBuffer;
331+
/** Gets a function from poiner which contain table's index. */
332+
333+
function __getFunction(ptr) {
334+
if (!table) throw Error(E_NO_EXPORT_TABLE);
335+
const index = new Uint32Array(memory.buffer)[ptr >>> 2];
336+
return table.get(index);
337+
}
338+
339+
extendedExports.__getFunction = __getFunction;
310340
/** Copies a typed array's values from the module's memory. */
311341

312342
function getTypedArray(Type, alignLog2, ptr) {
@@ -318,8 +348,7 @@ var loader = (function(exports) {
318348
function getTypedArrayView(Type, alignLog2, ptr) {
319349
const buffer = memory.buffer;
320350
const U32 = new Uint32Array(buffer);
321-
const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
322-
return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2);
351+
return new Type(buffer, U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2], U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2);
323352
}
324353
/** Attach a set of get TypedArray and View functions to the exports. */
325354

@@ -348,7 +377,7 @@ var loader = (function(exports) {
348377
if (id <= getRttiCount(U32)) {
349378
do {
350379
if (id == baseId) return true;
351-
id = getBase(id);
380+
id = getRttBase(id);
352381
} while (id);
353382
}
354383

@@ -424,15 +453,14 @@ var loader = (function(exports) {
424453
/* nop */
425454
});
426455

427-
for (let internalName in exports) {
428-
if (!Object.prototype.hasOwnProperty.call(exports, internalName)) continue;
456+
for (let internalName of Object.keys(exports)) {
429457
const elem = exports[internalName];
430458
let parts = internalName.split(".");
431459
let curr = extendedExports;
432460

433461
while (parts.length > 1) {
434462
let part = parts.shift();
435-
if (!Object.prototype.hasOwnProperty.call(curr, part)) curr[part] = {};
463+
if (!Object.hasOwn(curr, part)) curr[part] = {};
436464
curr = curr[part];
437465
}
438466

@@ -472,7 +500,7 @@ var loader = (function(exports) {
472500
curr = curr[className].prototype;
473501

474502
if (/^(get|set):/.test(name)) {
475-
if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) {
503+
if (!Object.hasOwn(curr, name = name.substring(4))) {
476504
let getter = exports[internalName.replace("set:", "get:")];
477505
let setter = exports[internalName.replace("get:", "set:")];
478506
Object.defineProperty(curr, name, {
@@ -489,7 +517,7 @@ var loader = (function(exports) {
489517
}
490518
} else {
491519
if (name === 'constructor') {
492-
(curr[name] = (...args) => {
520+
(curr[name] = function (...args) {
493521
setArgumentsLength(args.length);
494522
return elem(...args);
495523
}).original = elem;
@@ -504,7 +532,7 @@ var loader = (function(exports) {
504532
}
505533
} else {
506534
if (/^(get|set):/.test(name)) {
507-
if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) {
535+
if (!Object.hasOwn(curr, name = name.substring(4))) {
508536
Object.defineProperty(curr, name, {
509537
get: exports[internalName.replace("set:", "get:")],
510538
set: exports[internalName.replace("get:", "set:")],

0 commit comments

Comments
 (0)