Skip to content

Commit c74ef5e

Browse files
authored
Add fast-path for staticarray lowering if values is typedarray in bindings (#2370)
1 parent 2a55449 commit c74ef5e

File tree

16 files changed

+626
-295
lines changed

16 files changed

+626
-295
lines changed

src/bindings/js.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,12 +784,16 @@ export class JSBuilder extends ExportsWalker {
784784
`);
785785
}
786786
if (this.needsLowerStaticArray) {
787-
sb.push(` function __lowerStaticArray(lowerElement, id, align, values) {
787+
sb.push(` function __lowerStaticArray(lowerElement, id, align, values, typedConstructor) {
788788
if (values == null) return 0;
789789
const
790790
length = values.length,
791791
buffer = exports.__pin(exports.__new(length << align, id)) >>> 0;
792-
for (let i = 0; i < length; i++) lowerElement(buffer + (i << align >>> 0), values[i]);
792+
if (typedConstructor) {
793+
new typedConstructor(memory.buffer, buffer, length).set(values);
794+
} else {
795+
for (let i = 0; i < length; i++) lowerElement(buffer + (i << align >>> 0), values[i]);
796+
}
793797
exports.__unpin(buffer);
794798
return buffer;
795799
}
@@ -1051,7 +1055,7 @@ export class JSBuilder extends ExportsWalker {
10511055
sb.push(", ");
10521056
sb.push(clazz.id.toString());
10531057
sb.push(", ");
1054-
sb.push(clazz.getArrayValueType().alignLog2.toString());
1058+
sb.push(valueType.alignLog2.toString());
10551059
sb.push(", ");
10561060
this.needsLowerStaticArray = true;
10571061
} else if (clazz.extends(this.program.arrayBufferViewInstance.prototype)) {
@@ -1086,6 +1090,37 @@ export class JSBuilder extends ExportsWalker {
10861090
this.needsLowerInternref = true;
10871091
}
10881092
sb.push(name);
1093+
if (clazz.extends(this.program.staticArrayPrototype)) {
1094+
// optional last argument for __lowerStaticArray
1095+
let valueType = clazz.getArrayValueType();
1096+
if (valueType.isNumericValue) {
1097+
sb.push(", ");
1098+
if (valueType == Type.u8 || valueType == Type.bool) {
1099+
sb.push("Uint8Array");
1100+
} else if (valueType == Type.i8) {
1101+
sb.push("Int8Array");
1102+
} else if (valueType == Type.u16) {
1103+
sb.push("Uint16Array");
1104+
} else if (valueType == Type.i16) {
1105+
sb.push("Int16Array");
1106+
} else if (valueType == Type.u32) {
1107+
sb.push("Uint32Array");
1108+
} else if (valueType == Type.i32) {
1109+
sb.push("Int32Array");
1110+
} else if (valueType == Type.u64) {
1111+
sb.push("BigUint64Array");
1112+
} else if (valueType == Type.i64) {
1113+
sb.push("BigInt64Array");
1114+
} else if (valueType == Type.f32) {
1115+
sb.push("Float32Array");
1116+
} else if (valueType == Type.f64) {
1117+
sb.push("Float64Array");
1118+
} else {
1119+
// unreachable
1120+
assert(false);
1121+
}
1122+
}
1123+
}
10891124
sb.push(")");
10901125
if (!type.is(TypeFlags.NULLABLE)) {
10911126
this.needsNotNull = true;

src/bindings/tsd.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,16 @@ export class TSDBuilder extends ExportsWalker {
253253
sb.push("ArrayBuffer");
254254
} else if (clazz.extends(this.program.stringInstance.prototype)) {
255255
sb.push("string");
256-
} else if (
257-
clazz.extends(this.program.arrayPrototype) ||
258-
clazz.extends(this.program.staticArrayPrototype)
259-
) {
256+
} else if (clazz.extends(this.program.arrayPrototype)) {
260257
const valueType = clazz.getArrayValueType();
261258
sb.push("Array<");
262259
sb.push(this.toTypeScriptType(valueType, mode));
263260
sb.push(">");
261+
} else if (clazz.extends(this.program.staticArrayPrototype)) {
262+
const valueType = clazz.getArrayValueType();
263+
sb.push("ArrayLike<");
264+
sb.push(this.toTypeScriptType(valueType, mode));
265+
sb.push(">");
264266
} else if (clazz.extends(this.program.arrayBufferViewInstance.prototype)) {
265267
const valueType = clazz.getArrayValueType();
266268
if (valueType == Type.i8) {

tests/compiler/bindings/esm.debug.d.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,19 @@ export declare function typedarrayFunction(a: Int16Array, b: Float32Array): BigU
9898
* @param b `~lib/staticarray/StaticArray<i32>`
9999
* @returns `~lib/staticarray/StaticArray<i32>`
100100
*/
101-
export declare function staticarrayFunction(a: Array<number>, b: Array<number>): Array<number>;
101+
export declare function staticarrayFunction(a: ArrayLike<number>, b: ArrayLike<number>): ArrayLike<number>;
102+
/**
103+
* bindings/esm/staticarrayU16
104+
* @param a `~lib/staticarray/StaticArray<u16>`
105+
* @returns `~lib/staticarray/StaticArray<u16>`
106+
*/
107+
export declare function staticarrayU16(a: ArrayLike<number>): ArrayLike<number>;
108+
/**
109+
* bindings/esm/staticarrayI64
110+
* @param a `~lib/staticarray/StaticArray<i64>`
111+
* @returns `~lib/staticarray/StaticArray<i64>`
112+
*/
113+
export declare function staticarrayI64(a: ArrayLike<bigint>): ArrayLike<bigint>;
102114
/**
103115
* bindings/esm/arrayFunction
104116
* @param a `~lib/array/Array<i32>`
@@ -112,21 +124,21 @@ export declare function arrayFunction(a: Array<number>, b: Array<number>): Array
112124
* @param b `bindings/esm/PlainObject`
113125
* @returns `bindings/esm/PlainObject`
114126
*/
115-
export declare function objectFunction(a: __Record8<undefined>, b: __Record8<undefined>): __Record8<never>;
127+
export declare function objectFunction(a: __Record10<undefined>, b: __Record10<undefined>): __Record10<never>;
116128
/**
117129
* bindings/esm/newInternref
118130
* @returns `bindings/esm/NonPlainObject`
119131
*/
120-
export declare function newInternref(): __Internref11;
132+
export declare function newInternref(): __Internref13;
121133
/**
122134
* bindings/esm/internrefFunction
123135
* @param a `bindings/esm/NonPlainObject`
124136
* @param b `bindings/esm/NonPlainObject`
125137
* @returns `bindings/esm/NonPlainObject`
126138
*/
127-
export declare function internrefFunction(a: __Internref11, b: __Internref11): __Internref11;
139+
export declare function internrefFunction(a: __Internref13, b: __Internref13): __Internref13;
128140
/** bindings/esm/PlainObject */
129-
declare interface __Record8<TOmittable> {
141+
declare interface __Record10<TOmittable> {
130142
/** @type `i8` */
131143
a: number | TOmittable;
132144
/** @type `i16` */
@@ -161,6 +173,6 @@ declare interface __Record8<TOmittable> {
161173
p: Array<string> | null | TOmittable;
162174
}
163175
/** bindings/esm/NonPlainObject */
164-
declare class __Internref11 extends Number {
165-
private __nominal11: symbol;
176+
declare class __Internref13 extends Number {
177+
private __nominal13: symbol;
166178
}

tests/compiler/bindings/esm.debug.js

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,28 @@ async function instantiate(module, imports = {}) {
137137
},
138138
staticarrayFunction(a, b) {
139139
// bindings/esm/staticarrayFunction(~lib/staticarray/StaticArray<i32>, ~lib/staticarray/StaticArray<i32>) => ~lib/staticarray/StaticArray<i32>
140-
a = __retain(__lowerStaticArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 6, 2, a) || __notnull());
141-
b = __lowerStaticArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 6, 2, b) || __notnull();
140+
a = __retain(__lowerStaticArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 6, 2, a, Int32Array) || __notnull());
141+
b = __lowerStaticArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 6, 2, b, Int32Array) || __notnull();
142142
try {
143143
return __liftStaticArray(pointer => new Int32Array(memory.buffer)[pointer >>> 2], 2, exports.staticarrayFunction(a, b) >>> 0);
144144
} finally {
145145
__release(a);
146146
}
147147
},
148+
staticarrayU16(a) {
149+
// bindings/esm/staticarrayU16(~lib/staticarray/StaticArray<u16>) => ~lib/staticarray/StaticArray<u16>
150+
a = __lowerStaticArray((pointer, value) => { new Uint16Array(memory.buffer)[pointer >>> 1] = value; }, 7, 1, a, Uint16Array) || __notnull();
151+
return __liftStaticArray(pointer => new Uint16Array(memory.buffer)[pointer >>> 1], 1, exports.staticarrayU16(a) >>> 0);
152+
},
153+
staticarrayI64(a) {
154+
// bindings/esm/staticarrayI64(~lib/staticarray/StaticArray<i64>) => ~lib/staticarray/StaticArray<i64>
155+
a = __lowerStaticArray((pointer, value) => { new BigInt64Array(memory.buffer)[pointer >>> 3] = value || 0n; }, 8, 3, a, BigInt64Array) || __notnull();
156+
return __liftStaticArray(pointer => new BigInt64Array(memory.buffer)[pointer >>> 3], 3, exports.staticarrayI64(a) >>> 0);
157+
},
148158
arrayFunction(a, b) {
149159
// bindings/esm/arrayFunction(~lib/array/Array<i32>, ~lib/array/Array<i32>) => ~lib/array/Array<i32>
150-
a = __retain(__lowerArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 7, 2, a) || __notnull());
151-
b = __lowerArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 7, 2, b) || __notnull();
160+
a = __retain(__lowerArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 9, 2, a) || __notnull());
161+
b = __lowerArray((pointer, value) => { new Int32Array(memory.buffer)[pointer >>> 2] = value; }, 9, 2, b) || __notnull();
152162
try {
153163
return __liftArray(pointer => new Int32Array(memory.buffer)[pointer >>> 2], 2, exports.arrayFunction(a, b) >>> 0);
154164
} finally {
@@ -157,10 +167,10 @@ async function instantiate(module, imports = {}) {
157167
},
158168
objectFunction(a, b) {
159169
// bindings/esm/objectFunction(bindings/esm/PlainObject, bindings/esm/PlainObject) => bindings/esm/PlainObject
160-
a = __retain(__lowerRecord8(a) || __notnull());
161-
b = __lowerRecord8(b) || __notnull();
170+
a = __retain(__lowerRecord10(a) || __notnull());
171+
b = __lowerRecord10(b) || __notnull();
162172
try {
163-
return __liftRecord8(exports.objectFunction(a, b) >>> 0);
173+
return __liftRecord10(exports.objectFunction(a, b) >>> 0);
164174
} finally {
165175
__release(a);
166176
}
@@ -180,11 +190,11 @@ async function instantiate(module, imports = {}) {
180190
}
181191
},
182192
}, exports);
183-
function __lowerRecord8(value) {
193+
function __lowerRecord10(value) {
184194
// bindings/esm/PlainObject
185195
// Hint: Opt-out from lowering as a record by providing an empty constructor
186196
if (value == null) return 0;
187-
const pointer = exports.__pin(exports.__new(68, 8));
197+
const pointer = exports.__pin(exports.__new(68, 10));
188198
new Int8Array(memory.buffer)[pointer + 0 >>> 0] = value.a;
189199
new Int16Array(memory.buffer)[pointer + 2 >>> 1] = value.b;
190200
new Int32Array(memory.buffer)[pointer + 4 >>> 2] = value.c;
@@ -199,12 +209,12 @@ async function instantiate(module, imports = {}) {
199209
new Float32Array(memory.buffer)[pointer + 44 >>> 2] = value.l;
200210
new Float64Array(memory.buffer)[pointer + 48 >>> 3] = value.m;
201211
new Uint32Array(memory.buffer)[pointer + 56 >>> 2] = __lowerString(value.n);
202-
new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 9, 0, value.o);
203-
new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 10, 2, value.p);
212+
new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 11, 0, value.o);
213+
new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 12, 2, value.p);
204214
exports.__unpin(pointer);
205215
return pointer;
206216
}
207-
function __liftRecord8(pointer) {
217+
function __liftRecord10(pointer) {
208218
// bindings/esm/PlainObject
209219
// Hint: Opt-out from lifting as a record by providing an empty constructor
210220
if (!pointer) return null;
@@ -314,12 +324,16 @@ async function instantiate(module, imports = {}) {
314324
for (let i = 0; i < length; ++i) values[i] = liftElement(pointer + (i << align >>> 0));
315325
return values;
316326
}
317-
function __lowerStaticArray(lowerElement, id, align, values) {
327+
function __lowerStaticArray(lowerElement, id, align, values, typedConstructor) {
318328
if (values == null) return 0;
319329
const
320330
length = values.length,
321331
buffer = exports.__pin(exports.__new(length << align, id)) >>> 0;
322-
for (let i = 0; i < length; i++) lowerElement(buffer + (i << align >>> 0), values[i]);
332+
if (typedConstructor) {
333+
new typedConstructor(memory.buffer, buffer, length).set(values);
334+
} else {
335+
for (let i = 0; i < length; i++) lowerElement(buffer + (i << align >>> 0), values[i]);
336+
}
323337
exports.__unpin(buffer);
324338
return buffer;
325339
}
@@ -376,6 +390,8 @@ export const {
376390
stringFunctionOptional,
377391
typedarrayFunction,
378392
staticarrayFunction,
393+
staticarrayU16,
394+
staticarrayI64,
379395
arrayFunction,
380396
objectFunction,
381397
newInternref,

0 commit comments

Comments
 (0)