poe-code 14.0.83 → 14.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +588 -93
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-37V6Q4K3.js → chunk-2EZQJQ2C.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-PT7PBLVT.js → chunk-CYVI4ZUK.js} +536 -85
- package/packages/safe-js/dist/chunks/chunk-CYVI4ZUK.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/array-buffer.d.ts +12 -0
- package/packages/safe-js/dist/interp/array-buffer.js +33 -0
- package/packages/safe-js/dist/interp/float32.d.ts +6 -1
- package/packages/safe-js/dist/interp/float32.js +38 -10
- package/packages/safe-js/dist/interp/globals/array-buffer.d.ts +3 -0
- package/packages/safe-js/dist/interp/globals/array-buffer.js +112 -0
- package/packages/safe-js/dist/interp/globals/float32array.d.ts +1 -1
- package/packages/safe-js/dist/interp/globals/float32array.js +104 -15
- package/packages/safe-js/dist/interp/globals.d.ts +1 -0
- package/packages/safe-js/dist/interp/globals.js +2 -0
- package/packages/safe-js/dist/interp/host-bridge.d.ts +1 -0
- package/packages/safe-js/dist/interp/host-bridge.js +21 -0
- package/packages/safe-js/dist/interp/host-call.js +26 -2
- package/packages/safe-js/dist/interp/methods/array-iterator.js +1 -1
- package/packages/safe-js/dist/interp/object-model.js +6 -0
- package/packages/safe-js/dist/interp/values.d.ts +1 -1
- package/packages/safe-js/dist/interp/values.js +47 -5
- package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
- package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
- package/packages/safe-js/dist/snapshot/array-buffer.d.ts +13 -0
- package/packages/safe-js/dist/snapshot/array-buffer.js +40 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +25 -9
- package/packages/safe-js/dist/snapshot/float32array.d.ts +8 -1
- package/packages/safe-js/dist/snapshot/float32array.js +23 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +35 -10
- package/packages/safe-js/dist/snapshot/restore.js +13 -1
- package/packages/safe-js/dist/snapshot/serialize.d.ts +5 -2
- package/packages/safe-js/dist/snapshot/serialize.js +20 -11
- package/packages/safe-js/dist/snapshot/validation.js +11 -1
- package/packages/safe-js/dist/chunks/chunk-PT7PBLVT.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-37V6Q4K3.js.map → chunk-2EZQJQ2C.js.map} +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveFsConfig,
|
|
23
23
|
splitFrontmatter,
|
|
24
24
|
withBrokenPipeGuard
|
|
25
|
-
} from "./chunks/chunk-
|
|
25
|
+
} from "./chunks/chunk-2EZQJQ2C.js";
|
|
26
26
|
import {
|
|
27
27
|
Budget,
|
|
28
28
|
SandboxError,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
replaceErrorStack,
|
|
35
35
|
restore,
|
|
36
36
|
run
|
|
37
|
-
} from "./chunks/chunk-
|
|
37
|
+
} from "./chunks/chunk-CYVI4ZUK.js";
|
|
38
38
|
import "./chunks/chunk-M2DLCGEF.js";
|
|
39
39
|
import "./chunks/chunk-Q7USUEL7.js";
|
|
40
40
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
runWithSpawnUsageAccumulator,
|
|
27
27
|
splitFrontmatter,
|
|
28
28
|
supportsSpawnMode
|
|
29
|
-
} from "./chunks/chunk-
|
|
29
|
+
} from "./chunks/chunk-2EZQJQ2C.js";
|
|
30
30
|
import {
|
|
31
31
|
Budget,
|
|
32
32
|
FileSnapshotBackend,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
registerPendingHostCallPolicy,
|
|
51
51
|
restore,
|
|
52
52
|
run
|
|
53
|
-
} from "./chunks/chunk-
|
|
53
|
+
} from "./chunks/chunk-CYVI4ZUK.js";
|
|
54
54
|
import "./chunks/chunk-M2DLCGEF.js";
|
|
55
55
|
import "./chunks/chunk-Q7USUEL7.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Budget } from "./budget.js";
|
|
2
|
+
import type { SandboxObject } from "./values.js";
|
|
3
|
+
export declare const arrayBufferPrototypes: WeakMap<Budget, SandboxObject>;
|
|
4
|
+
export declare function isSandboxArrayBuffer(value: unknown): value is ArrayBuffer;
|
|
5
|
+
export declare function arrayBufferLength(value: ArrayBuffer): number;
|
|
6
|
+
export declare function arrayBufferOptions(value: ArrayBuffer): {
|
|
7
|
+
maxByteLength: number;
|
|
8
|
+
} | undefined;
|
|
9
|
+
export declare function copyArrayBufferStorage(value: ArrayBuffer, state: {
|
|
10
|
+
float32Buffers?: WeakMap<ArrayBuffer, ArrayBuffer>;
|
|
11
|
+
}): ArrayBuffer;
|
|
12
|
+
export declare function arrayBufferDataProperties(value: ArrayBuffer): Array<[string | symbol, PropertyDescriptor]>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { types } from "node:util";
|
|
2
|
+
const readLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
|
|
3
|
+
const readResizable = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "resizable")?.get;
|
|
4
|
+
const readMaxLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "maxByteLength")?.get;
|
|
5
|
+
export const arrayBufferPrototypes = new WeakMap();
|
|
6
|
+
export function isSandboxArrayBuffer(value) {
|
|
7
|
+
return types.isArrayBuffer(value) && Object.getPrototypeOf(value) === ArrayBuffer.prototype;
|
|
8
|
+
}
|
|
9
|
+
export function arrayBufferLength(value) {
|
|
10
|
+
return Reflect.apply(readLength, value, []);
|
|
11
|
+
}
|
|
12
|
+
export function arrayBufferOptions(value) {
|
|
13
|
+
return readResizable !== undefined && Reflect.apply(readResizable, value, [])
|
|
14
|
+
? { maxByteLength: Reflect.apply(readMaxLength, value, []) } : undefined;
|
|
15
|
+
}
|
|
16
|
+
export function copyArrayBufferStorage(value, state) {
|
|
17
|
+
state.float32Buffers ??= new WeakMap();
|
|
18
|
+
let copy = state.float32Buffers.get(value);
|
|
19
|
+
if (copy === undefined) {
|
|
20
|
+
copy = Reflect.construct(ArrayBuffer, [arrayBufferLength(value), arrayBufferOptions(value)]);
|
|
21
|
+
new Uint8Array(copy).set(new Uint8Array(value));
|
|
22
|
+
state.float32Buffers.set(value, copy);
|
|
23
|
+
}
|
|
24
|
+
return copy;
|
|
25
|
+
}
|
|
26
|
+
export function arrayBufferDataProperties(value) {
|
|
27
|
+
return Reflect.ownKeys(value).map(key => {
|
|
28
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
29
|
+
if (!("value" in descriptor))
|
|
30
|
+
throw new TypeError("ArrayBuffer accessors cannot be copied as data.");
|
|
31
|
+
return [key, descriptor];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { Budget } from "./budget.js";
|
|
2
|
+
export declare const float32ViewLayouts: WeakMap<Float32Array<ArrayBufferLike>, {
|
|
3
|
+
byteOffset: number;
|
|
4
|
+
length?: number;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function restoreFloat32View(buffer: ArrayBuffer, byteOffset: number, length?: number, budget?: Budget): Float32Array;
|
|
2
7
|
export declare function isFloat32Array(value: unknown): value is Float32Array;
|
|
3
|
-
export declare function float32Storage(value: Float32Array): {
|
|
8
|
+
export declare function float32Storage(value: Float32Array, requireInBounds?: boolean): {
|
|
4
9
|
buffer: ArrayBuffer;
|
|
5
10
|
byteOffset: number;
|
|
6
11
|
length: number;
|
|
@@ -1,20 +1,48 @@
|
|
|
1
|
+
import { arrayBufferLength, arrayBufferOptions, copyArrayBufferStorage } from "./array-buffer.js";
|
|
1
2
|
const typedArrayPrototype = Object.getPrototypeOf(Float32Array.prototype);
|
|
2
3
|
const readLength = Object.getOwnPropertyDescriptor(typedArrayPrototype, "length").get;
|
|
3
4
|
const readOffset = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset").get;
|
|
4
5
|
const readBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
|
|
5
6
|
const readTag = Object.getOwnPropertyDescriptor(typedArrayPrototype, Symbol.toStringTag).get;
|
|
7
|
+
const createValuesIterator = Object.getOwnPropertyDescriptor(typedArrayPrototype, "values").value;
|
|
6
8
|
const bufferLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
|
|
7
9
|
const bufferResizable = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "resizable")?.get;
|
|
10
|
+
export const float32ViewLayouts = new WeakMap();
|
|
11
|
+
const resizeBuffer = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "resize").value;
|
|
12
|
+
export function restoreFloat32View(buffer, byteOffset, length, budget) {
|
|
13
|
+
const originalLength = arrayBufferLength(buffer);
|
|
14
|
+
const required = byteOffset + (length ?? 0) * 4;
|
|
15
|
+
const options = arrayBufferOptions(buffer);
|
|
16
|
+
const grow = required > originalLength;
|
|
17
|
+
if (grow) {
|
|
18
|
+
if (options === undefined || required > options.maxByteLength)
|
|
19
|
+
throw new RangeError("Float32Array layout exceeds backing capacity.");
|
|
20
|
+
budget?.allocateArrayLength(Math.ceil(required / 4));
|
|
21
|
+
budget?.provisionDataUsage(required - originalLength)();
|
|
22
|
+
Reflect.apply(resizeBuffer, buffer, [required]);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const view = new Float32Array(buffer, byteOffset, length);
|
|
26
|
+
if (options !== undefined)
|
|
27
|
+
float32ViewLayouts.set(view, { byteOffset, ...(length === undefined ? {} : { length }) });
|
|
28
|
+
return view;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
if (grow)
|
|
32
|
+
Reflect.apply(resizeBuffer, buffer, [originalLength]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
8
35
|
export function isFloat32Array(value) {
|
|
9
36
|
return (ArrayBuffer.isView(value) &&
|
|
10
37
|
Object.getPrototypeOf(value) === Float32Array.prototype &&
|
|
11
38
|
Reflect.apply(readTag, value, []) === "Float32Array");
|
|
12
39
|
}
|
|
13
|
-
export function float32Storage(value) {
|
|
40
|
+
export function float32Storage(value, requireInBounds = false) {
|
|
41
|
+
if (requireInBounds)
|
|
42
|
+
Reflect.apply(createValuesIterator, value, []);
|
|
14
43
|
const buffer = Reflect.apply(readBuffer, value, []);
|
|
15
|
-
if (Object.getPrototypeOf(buffer) !== ArrayBuffer.prototype
|
|
16
|
-
(
|
|
17
|
-
throw new TypeError("Float32Array requires a fixed, non-shared ArrayBuffer.");
|
|
44
|
+
if (Object.getPrototypeOf(buffer) !== ArrayBuffer.prototype) {
|
|
45
|
+
throw new TypeError("Float32Array requires a non-shared ArrayBuffer.");
|
|
18
46
|
}
|
|
19
47
|
return {
|
|
20
48
|
buffer,
|
|
@@ -63,12 +91,12 @@ export function checkFloat32Allocation(length, budget) {
|
|
|
63
91
|
}
|
|
64
92
|
export function copyFloat32Storage(value, state) {
|
|
65
93
|
const storage = float32Storage(value);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
94
|
+
const buffer = copyArrayBufferStorage(storage.buffer, state);
|
|
95
|
+
if (bufferResizable !== undefined && Reflect.apply(bufferResizable, storage.buffer, [])) {
|
|
96
|
+
const layout = float32ViewLayouts.get(value);
|
|
97
|
+
if (layout === undefined)
|
|
98
|
+
throw new TypeError("Resizable Float32Array copies require known view layout.");
|
|
99
|
+
return restoreFloat32View(buffer, layout.byteOffset, layout.length);
|
|
72
100
|
}
|
|
73
101
|
return new Float32Array(buffer, storage.byteOffset, storage.length);
|
|
74
102
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { arrayBufferLength, arrayBufferOptions, arrayBufferPrototypes, isSandboxArrayBuffer } from "../array-buffer.js";
|
|
2
|
+
import { accessorAdapter, readPropertyDescriptor } from "../accessors.js";
|
|
3
|
+
import { createSandboxClosure } from "../values.js";
|
|
4
|
+
import { getSandboxDataProperty, getSandboxPropertyDescriptor, getSandboxPrototype, materializeFunctionProperties, registerIntrinsicFunction, registerIntrinsicObject, setSandboxPrototype } from "../object-model.js";
|
|
5
|
+
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
6
|
+
import { registerBuiltinIdentities } from "../intrinsics.js";
|
|
7
|
+
import { sandboxNumber } from "../string-coercion.js";
|
|
8
|
+
import { retainValues } from "../resources.js";
|
|
9
|
+
const resizeBuffer = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "resize").value;
|
|
10
|
+
export function createArrayBufferGlobal(budget) {
|
|
11
|
+
const prototype = Object.create(null);
|
|
12
|
+
const constructor = createSandboxClosure({
|
|
13
|
+
guest: true, sandbox: true, name: "ArrayBuffer", length: 1,
|
|
14
|
+
call: () => { throw new TypeError("ArrayBuffer requires new."); },
|
|
15
|
+
construct: async (args, context) => {
|
|
16
|
+
let selected;
|
|
17
|
+
let current;
|
|
18
|
+
const bridge = {
|
|
19
|
+
...context, stack: context?.stack ?? [], thisValue: undefined,
|
|
20
|
+
getProperty: context?.getProperty ?? ((value, key) => {
|
|
21
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
22
|
+
return descriptor === undefined ? getSandboxDataProperty(value, key, budget)
|
|
23
|
+
: readPropertyDescriptor(descriptor, value, bridge);
|
|
24
|
+
}),
|
|
25
|
+
invokeClosure: context?.invokeClosure ?? ((callee, values, receiver, construct) => invokeBuiltinClosure(callee, values, budget, context, receiver, construct))
|
|
26
|
+
};
|
|
27
|
+
const release = retainValues(budget, () => [selected, current, ...args]);
|
|
28
|
+
try {
|
|
29
|
+
const number = await sandboxNumber(args[0], budget, bridge);
|
|
30
|
+
const length = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
31
|
+
if (length < 0 || !Number.isSafeInteger(length))
|
|
32
|
+
throw new RangeError("Invalid ArrayBuffer length.");
|
|
33
|
+
let maxByteLength;
|
|
34
|
+
if (args[1] !== null && typeof args[1] === "object") {
|
|
35
|
+
current = await bridge.getProperty(args[1], "maxByteLength");
|
|
36
|
+
if (current !== undefined) {
|
|
37
|
+
const maximum = await sandboxNumber(current, budget, bridge);
|
|
38
|
+
maxByteLength = Number.isNaN(maximum) ? 0 : Math.trunc(maximum);
|
|
39
|
+
if (!Number.isSafeInteger(maxByteLength) || maxByteLength < length)
|
|
40
|
+
throw new RangeError("Invalid ArrayBuffer maximum length.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const target = context?.newTarget ?? constructor;
|
|
44
|
+
selected = await bridge.getProperty(target, "prototype");
|
|
45
|
+
budget.allocateArrayLength(maxByteLength ?? length);
|
|
46
|
+
budget.provisionDataUsage(length + 1)();
|
|
47
|
+
const result = Reflect.construct(ArrayBuffer, [length, maxByteLength === undefined ? undefined : { maxByteLength }]);
|
|
48
|
+
setSandboxPrototype(result, selected !== null && typeof selected === "object" ? selected : prototype, budget);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
release();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(materializeFunctionProperties(constructor), "prototype", { value: prototype, writable: false });
|
|
57
|
+
Object.defineProperty(materializeFunctionProperties(constructor), "isView", {
|
|
58
|
+
writable: true, configurable: true,
|
|
59
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "isView", length: 1,
|
|
60
|
+
call: args => ArrayBuffer.isView(args[0]) })
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperties(prototype, {
|
|
63
|
+
constructor: { value: constructor, writable: true, configurable: true },
|
|
64
|
+
[Symbol.toStringTag]: { value: "ArrayBuffer", configurable: true }
|
|
65
|
+
});
|
|
66
|
+
const getters = [];
|
|
67
|
+
Object.defineProperty(prototype, "resize", { writable: true, configurable: true,
|
|
68
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "resize", length: 1,
|
|
69
|
+
call: async (args, context) => {
|
|
70
|
+
const receiver = context?.thisValue;
|
|
71
|
+
if (!isSandboxArrayBuffer(receiver) || arrayBufferOptions(receiver) === undefined)
|
|
72
|
+
throw new TypeError("ArrayBuffer resize requires a resizable buffer receiver.");
|
|
73
|
+
const release = retainValues(budget, () => [receiver, ...args]);
|
|
74
|
+
try {
|
|
75
|
+
const number = await sandboxNumber(args[0], budget, context);
|
|
76
|
+
const length = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
77
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > arrayBufferOptions(receiver).maxByteLength)
|
|
78
|
+
throw new RangeError("Invalid ArrayBuffer resize length.");
|
|
79
|
+
budget.allocateArrayLength(length);
|
|
80
|
+
budget.provisionDataUsage(Math.max(length - arrayBufferLength(receiver), 0))();
|
|
81
|
+
Reflect.apply(resizeBuffer, receiver, [length]);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
release();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
for (const key of ["byteLength", "maxByteLength", "resizable"]) {
|
|
91
|
+
const getter = createSandboxClosure({ guest: true, sandbox: true, name: `get ${key}`, length: 0,
|
|
92
|
+
call: (_args, context) => {
|
|
93
|
+
if (!isSandboxArrayBuffer(context?.thisValue))
|
|
94
|
+
throw new TypeError(`ArrayBuffer ${key} requires a buffer receiver.`);
|
|
95
|
+
if (key === "byteLength")
|
|
96
|
+
return arrayBufferLength(context.thisValue);
|
|
97
|
+
const options = arrayBufferOptions(context.thisValue);
|
|
98
|
+
return key === "resizable" ? options !== undefined : options?.maxByteLength ?? arrayBufferLength(context.thisValue);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
Object.defineProperty(prototype, key, { get: accessorAdapter(getter, "get"), configurable: true });
|
|
102
|
+
getters.push(getter);
|
|
103
|
+
}
|
|
104
|
+
setSandboxPrototype(prototype, getSandboxPrototype(Object.create(null), budget));
|
|
105
|
+
arrayBufferPrototypes.set(budget, prototype);
|
|
106
|
+
registerBuiltinIdentities(budget, { ArrayBuffer: constructor });
|
|
107
|
+
registerIntrinsicFunction(budget, constructor);
|
|
108
|
+
for (const getter of getters)
|
|
109
|
+
registerIntrinsicFunction(budget, getter);
|
|
110
|
+
registerIntrinsicObject(budget, prototype);
|
|
111
|
+
return constructor;
|
|
112
|
+
}
|
|
@@ -3,5 +3,5 @@ import { type SandboxClosure, type SandboxValue } from "../values.js";
|
|
|
3
3
|
export declare function createFloat32ArrayGlobal(budget: Budget, nativePrototype?: boolean): SandboxClosure;
|
|
4
4
|
export declare function createFloat32ArrayPrototypes(budget: Budget, constructor: SandboxClosure): void;
|
|
5
5
|
export declare function isFloat32ArrayConstructor(value: unknown): boolean;
|
|
6
|
-
export declare function getFloat32Member(value: Float32Array, property: string | number, budget: Budget): SandboxValue;
|
|
6
|
+
export declare function getFloat32Member(value: Float32Array, property: string | number, budget: Budget, defaultConstructor?: SandboxClosure): SandboxValue;
|
|
7
7
|
export declare function setFloat32Member(value: Float32Array, property: PropertyKey, entry: SandboxValue, budget?: Budget): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { checkFloat32Allocation, float32Number, float32Storage, isFloat32Array, isFloat32Index } from "../float32.js";
|
|
1
|
+
import { checkFloat32Allocation, float32Number, float32Storage, float32ViewLayouts, isFloat32Array, isFloat32Index } from "../float32.js";
|
|
2
2
|
import { createSandboxClosure, isSandboxClosure, measureSandboxData } from "../values.js";
|
|
3
3
|
import { accessorAdapter, readPropertyDescriptor } from "../accessors.js";
|
|
4
4
|
import { float32Prototypes } from "../float32-prototypes.js";
|
|
@@ -10,6 +10,7 @@ import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
|
10
10
|
import { acquireSandboxIterator, readIteratorResult } from "../iteration.js";
|
|
11
11
|
import { createDataCheckpoint } from "../data-checkpoint.js";
|
|
12
12
|
import { createSandboxBox } from "../boxed.js";
|
|
13
|
+
import { arrayBufferLength, arrayBufferOptions, isSandboxArrayBuffer } from "../array-buffer.js";
|
|
13
14
|
const constructors = new WeakSet();
|
|
14
15
|
export function createFloat32ArrayGlobal(budget, nativePrototype = false) {
|
|
15
16
|
const constructor = createSandboxClosure({
|
|
@@ -32,6 +33,32 @@ export function createFloat32ArrayGlobal(budget, nativePrototype = false) {
|
|
|
32
33
|
const prototype = candidate !== null && typeof candidate === "object" ? candidate : float32Prototypes.get(budget);
|
|
33
34
|
const release = retainValues(budget, () => [prototype, ...args]);
|
|
34
35
|
try {
|
|
36
|
+
if (isSandboxArrayBuffer(args[0])) {
|
|
37
|
+
const buffer = args[0];
|
|
38
|
+
const number = await sandboxNumber(args[1], budget, context);
|
|
39
|
+
const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
40
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset % 4 !== 0)
|
|
41
|
+
throw new RangeError("Invalid Float32Array buffer offset.");
|
|
42
|
+
const bytes = arrayBufferLength(buffer);
|
|
43
|
+
let length;
|
|
44
|
+
if (args[2] === undefined) {
|
|
45
|
+
if ((arrayBufferOptions(buffer) === undefined && bytes % 4 !== 0) || offset > bytes)
|
|
46
|
+
throw new RangeError("Invalid Float32Array buffer length.");
|
|
47
|
+
length = Math.floor((bytes - offset) / 4);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const size = await sandboxNumber(args[2], budget, context);
|
|
51
|
+
length = Number.isNaN(size) ? 0 : Math.trunc(size);
|
|
52
|
+
if (!Number.isSafeInteger(length) || length < 0 || offset + length * 4 > arrayBufferLength(buffer))
|
|
53
|
+
throw new RangeError("Invalid Float32Array view length.");
|
|
54
|
+
}
|
|
55
|
+
budget.allocateArrayLength(length);
|
|
56
|
+
const result = new Float32Array(buffer, offset, args[2] === undefined ? undefined : length);
|
|
57
|
+
if (arrayBufferOptions(buffer) !== undefined)
|
|
58
|
+
float32ViewLayouts.set(result, { byteOffset: offset, ...(args[2] === undefined ? {} : { length }) });
|
|
59
|
+
setSandboxPrototype(result, prototype, budget);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
35
62
|
const result = args[0] !== null && typeof args[0] === "object" && !isFloat32Array(args[0])
|
|
36
63
|
? await allocateFloat32Input(args[0], budget, context)
|
|
37
64
|
: allocateFloat32Array(args[0], budget);
|
|
@@ -242,7 +269,13 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
242
269
|
setSandboxPrototype(prototype, shared);
|
|
243
270
|
setSandboxPrototype(shared, getSandboxPrototype(Object.create(null), budget));
|
|
244
271
|
const getters = [];
|
|
245
|
-
|
|
272
|
+
const species = createSandboxClosure({ guest: true, sandbox: true, name: "get [Symbol.species]", length: 0,
|
|
273
|
+
call: (_args, context) => context?.thisValue });
|
|
274
|
+
getters.push(species);
|
|
275
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), Symbol.species, {
|
|
276
|
+
get: accessorAdapter(species, "get"), configurable: true
|
|
277
|
+
});
|
|
278
|
+
for (const key of ["length", "byteLength", "byteOffset", "buffer"]) {
|
|
246
279
|
const getter = createSandboxClosure({ guest: true, sandbox: true, name: `get ${key}`, length: 0,
|
|
247
280
|
call: (_args, context) => {
|
|
248
281
|
if (!isFloat32Array(context?.thisValue))
|
|
@@ -255,7 +288,7 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
255
288
|
Object.defineProperty(shared, key, { get: accessorAdapter(getter, "get"), configurable: true });
|
|
256
289
|
}
|
|
257
290
|
for (const key of ["set", "slice", "subarray"])
|
|
258
|
-
Object.defineProperty(shared, key, { value: getFloat32Member(new Float32Array(0), key, budget), writable: true, configurable: true });
|
|
291
|
+
Object.defineProperty(shared, key, { value: getFloat32Member(new Float32Array(0), key, budget, constructor), writable: true, configurable: true });
|
|
259
292
|
const arrayPrototype = resolveIntrinsicIdentity(budget, '["Array","prototype"]');
|
|
260
293
|
Object.defineProperty(shared, "toString", { value: getSandboxDataProperty(arrayPrototype, "toString", budget), writable: true, configurable: true });
|
|
261
294
|
Object.defineProperty(shared, "join", { writable: true, configurable: true,
|
|
@@ -264,7 +297,7 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
264
297
|
if (!isFloat32Array(context?.thisValue))
|
|
265
298
|
throw new TypeError("TypedArray join requires a typed array receiver.");
|
|
266
299
|
const receiver = context.thisValue;
|
|
267
|
-
const length = float32Storage(receiver).length;
|
|
300
|
+
const length = float32Storage(receiver, true).length;
|
|
268
301
|
let separator = ",";
|
|
269
302
|
let text = "";
|
|
270
303
|
const release = retainValues(budget, () => [receiver, separator, text, ...args]);
|
|
@@ -273,7 +306,8 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
273
306
|
separator = await sandboxString(args[0], budget, context);
|
|
274
307
|
for (let index = 0; index < length; index++) {
|
|
275
308
|
budget.visitNode();
|
|
276
|
-
|
|
309
|
+
const value = receiver[index];
|
|
310
|
+
text = budget.allocateString(text + (index === 0 ? "" : separator) + (value === undefined ? "" : String(value)));
|
|
277
311
|
}
|
|
278
312
|
return text;
|
|
279
313
|
}
|
|
@@ -293,6 +327,7 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
293
327
|
call: (args, context) => {
|
|
294
328
|
if (!isFloat32Array(context?.thisValue))
|
|
295
329
|
throw new TypeError(`TypedArray ${key} requires a typed array receiver.`);
|
|
330
|
+
float32Storage(context.thisValue, true);
|
|
296
331
|
return invokeBuiltinClosure(method, args, budget, context, context.thisValue);
|
|
297
332
|
}
|
|
298
333
|
});
|
|
@@ -312,7 +347,7 @@ export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
|
312
347
|
export function isFloat32ArrayConstructor(value) {
|
|
313
348
|
return typeof value === "object" && value !== null && constructors.has(value);
|
|
314
349
|
}
|
|
315
|
-
export function getFloat32Member(value, property, budget) {
|
|
350
|
+
export function getFloat32Member(value, property, budget, defaultConstructor) {
|
|
316
351
|
const key = String(property);
|
|
317
352
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
318
353
|
if (descriptor !== undefined) {
|
|
@@ -342,7 +377,7 @@ export function getFloat32Member(value, property, budget) {
|
|
|
342
377
|
const receiver = context?.thisValue;
|
|
343
378
|
if (!isFloat32Array(receiver))
|
|
344
379
|
throw new TypeError(`Float32Array#${key} requires a Float32Array receiver.`);
|
|
345
|
-
const storage = float32Storage(receiver);
|
|
380
|
+
const storage = float32Storage(receiver, key === "slice");
|
|
346
381
|
const bridge = {
|
|
347
382
|
...context, stack: context?.stack ?? [], thisValue: receiver,
|
|
348
383
|
getProperty: context?.getProperty ?? ((value, property) => {
|
|
@@ -363,18 +398,19 @@ export function getFloat32Member(value, property, budget) {
|
|
|
363
398
|
const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
364
399
|
if (offset < 0)
|
|
365
400
|
throw new RangeError("Float32Array#set offset is out of bounds.");
|
|
401
|
+
const targetStorage = float32Storage(receiver, true);
|
|
366
402
|
if (source === null || source === undefined)
|
|
367
403
|
throw new TypeError("Float32Array#set requires a non-null source.");
|
|
368
404
|
let length;
|
|
369
405
|
if (isFloat32Array(source))
|
|
370
|
-
length = float32Storage(source).length;
|
|
406
|
+
length = float32Storage(source, true).length;
|
|
371
407
|
else {
|
|
372
408
|
sourceObject = typeof source === "object" ? source : createSandboxBox(source);
|
|
373
409
|
current = await bridge.getProperty(sourceObject, "length");
|
|
374
410
|
const size = await sandboxNumber(current, budget, bridge);
|
|
375
411
|
length = Number.isNaN(size) || size <= 0 ? 0 : Math.min(Math.trunc(size), Number.MAX_SAFE_INTEGER);
|
|
376
412
|
}
|
|
377
|
-
if (offset + length >
|
|
413
|
+
if (offset + length > targetStorage.length)
|
|
378
414
|
throw new RangeError("Float32Array#set source is out of bounds.");
|
|
379
415
|
if (isFloat32Array(source))
|
|
380
416
|
Float32Array.prototype.set.call(receiver, source, offset);
|
|
@@ -392,17 +428,70 @@ export function getFloat32Member(value, property, budget) {
|
|
|
392
428
|
})();
|
|
393
429
|
}
|
|
394
430
|
return (async () => {
|
|
395
|
-
|
|
431
|
+
let candidate;
|
|
432
|
+
let result;
|
|
433
|
+
const release = retainValues(budget, () => [receiver, candidate, result, ...args]);
|
|
396
434
|
try {
|
|
397
435
|
const start = relativeIndex(await sandboxNumber(args[0], budget, bridge), storage.length);
|
|
398
436
|
const end = args[1] === undefined ? storage.length
|
|
399
437
|
: relativeIndex(await sandboxNumber(args[1], budget, bridge), storage.length);
|
|
400
438
|
const length = Math.max(end - start, 0);
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
439
|
+
const layout = float32ViewLayouts.get(receiver);
|
|
440
|
+
const offset = (layout?.byteOffset ?? storage.byteOffset) + start * 4;
|
|
441
|
+
const tracking = layout !== undefined && layout.length === undefined && args[1] === undefined;
|
|
442
|
+
if (defaultConstructor !== undefined) {
|
|
443
|
+
candidate = await bridge.getProperty(receiver, "constructor");
|
|
444
|
+
if (candidate !== undefined) {
|
|
445
|
+
if (candidate === null || typeof candidate !== "object")
|
|
446
|
+
throw new TypeError("TypedArray constructor must be an object.");
|
|
447
|
+
candidate = await bridge.getProperty(candidate, Symbol.species);
|
|
448
|
+
if (candidate !== undefined && candidate !== null &&
|
|
449
|
+
(!isSandboxClosure(candidate) || candidate.construct === undefined))
|
|
450
|
+
throw new TypeError("TypedArray species must be a constructor.");
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (candidate !== undefined && candidate !== null && candidate !== defaultConstructor) {
|
|
454
|
+
const values = key === "slice" ? [length]
|
|
455
|
+
: [storage.buffer, offset, tracking ? undefined : length];
|
|
456
|
+
result = await invokeBuiltinClosure(candidate, values, budget, bridge, undefined, true);
|
|
457
|
+
if (!isFloat32Array(result))
|
|
458
|
+
throw new TypeError("TypedArray species must return typed storage.");
|
|
459
|
+
const target = float32Storage(result, key === "slice");
|
|
460
|
+
if (key === "slice" && target.length < length)
|
|
461
|
+
throw new TypeError("TypedArray species returned insufficient storage.");
|
|
462
|
+
}
|
|
463
|
+
if (key === "subarray") {
|
|
464
|
+
if (result === undefined) {
|
|
465
|
+
result = new Float32Array(storage.buffer, offset, tracking ? undefined : length);
|
|
466
|
+
if (arrayBufferOptions(storage.buffer) !== undefined)
|
|
467
|
+
float32ViewLayouts.set(result, { byteOffset: offset, ...(tracking ? {} : { length }) });
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
if (result === undefined) {
|
|
472
|
+
checkFloat32Allocation(length, budget);
|
|
473
|
+
result = new Float32Array(length);
|
|
474
|
+
}
|
|
475
|
+
if (!isFloat32Array(result))
|
|
476
|
+
throw new TypeError("TypedArray species must return typed storage.");
|
|
477
|
+
if (length > 0) {
|
|
478
|
+
const current = float32Storage(receiver, true);
|
|
479
|
+
const target = float32Storage(result, true);
|
|
480
|
+
const count = Math.min(length, Math.max(current.length - start, 0));
|
|
481
|
+
if (count > 0) {
|
|
482
|
+
const sourceBytes = new Uint8Array(current.buffer, current.byteOffset + start * 4, count * 4);
|
|
483
|
+
const targetBytes = new Uint8Array(target.buffer, target.byteOffset, count * 4);
|
|
484
|
+
if (current.buffer === target.buffer && targetBytes.byteOffset > sourceBytes.byteOffset &&
|
|
485
|
+
targetBytes.byteOffset < sourceBytes.byteOffset + sourceBytes.length) {
|
|
486
|
+
for (let index = 0; index < sourceBytes.length; index++) {
|
|
487
|
+
budget.visitNode();
|
|
488
|
+
targetBytes[index] = sourceBytes[index];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else
|
|
492
|
+
targetBytes.set(sourceBytes);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
406
495
|
return result;
|
|
407
496
|
}
|
|
408
497
|
finally {
|
|
@@ -18,6 +18,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
|
|
|
18
18
|
parseFloat: import("./values.js").SandboxClosure;
|
|
19
19
|
isNaN: import("./values.js").SandboxClosure;
|
|
20
20
|
isFinite: import("./values.js").SandboxClosure;
|
|
21
|
+
ArrayBuffer: import("./values.js").SandboxClosure;
|
|
21
22
|
Object: import("./values.js").SandboxClosure;
|
|
22
23
|
Array: import("./values.js").SandboxClosure;
|
|
23
24
|
String: import("./values.js").SandboxClosure;
|
|
@@ -13,6 +13,7 @@ import { createPromiseGlobals } from "./promise.js";
|
|
|
13
13
|
import { createDateGlobal } from "./globals/date.js";
|
|
14
14
|
import { createSymbolGlobal } from "./globals/symbol.js";
|
|
15
15
|
import { createBigIntGlobal } from "./globals/bigint.js";
|
|
16
|
+
import { createArrayBufferGlobal } from "./globals/array-buffer.js";
|
|
16
17
|
import { registerBuiltinIdentities } from "./intrinsics.js";
|
|
17
18
|
export function createBuiltinBindings(options) {
|
|
18
19
|
const bindings = {
|
|
@@ -25,6 +26,7 @@ export function createBuiltinBindings(options) {
|
|
|
25
26
|
...createErrorGlobals({ ...options, errorPrototypes: options.errorPrototypes !== false }),
|
|
26
27
|
...createMathGlobals({ random: options.random, budget: options.budget }),
|
|
27
28
|
...createObjectArrayGlobals(options),
|
|
29
|
+
ArrayBuffer: createArrayBufferGlobal(options.budget),
|
|
28
30
|
...createMiscGlobals(options),
|
|
29
31
|
...createUriGlobals(options.budget),
|
|
30
32
|
...createPromiseGlobals(options),
|
|
@@ -5,6 +5,7 @@ import { exportHostCapability, importHostCapability, isLiveCapability } from "./
|
|
|
5
5
|
import { attachErrorSpan, replaceErrorStack } from "../error/shape.js";
|
|
6
6
|
import { SandboxError } from "./budget.js";
|
|
7
7
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
8
|
+
import { arrayBufferDataProperties, arrayBufferLength, copyArrayBufferStorage, isSandboxArrayBuffer } from "./array-buffer.js";
|
|
8
9
|
import { checkFloat32Allocation, copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
9
10
|
import { createSubsetErrorValue } from "./exceptions.js";
|
|
10
11
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
@@ -705,6 +706,25 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
705
706
|
state.seen.set(value, date);
|
|
706
707
|
return date;
|
|
707
708
|
}
|
|
709
|
+
if (isSandboxArrayBuffer(value)) {
|
|
710
|
+
const existing = state.seen.get(value);
|
|
711
|
+
if (existing !== undefined)
|
|
712
|
+
return existing;
|
|
713
|
+
const length = arrayBufferLength(value);
|
|
714
|
+
budget.allocateArrayLength(length);
|
|
715
|
+
budget.provisionDataUsage(length + 1)();
|
|
716
|
+
const copy = copyArrayBufferStorage(value, state);
|
|
717
|
+
state.seen.set(value, copy);
|
|
718
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
719
|
+
if (typeof key === "symbol")
|
|
720
|
+
throw new TypeError("Host ArrayBuffer symbol properties require an explicit capability path.");
|
|
721
|
+
Object.defineProperty(copy, key, { ...descriptor,
|
|
722
|
+
value: copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key)) });
|
|
723
|
+
}
|
|
724
|
+
if (!Object.isExtensible(value))
|
|
725
|
+
Object.preventExtensions(copy);
|
|
726
|
+
return copy;
|
|
727
|
+
}
|
|
708
728
|
if (isFloat32Array(value)) {
|
|
709
729
|
const existing = state.seen.get(value);
|
|
710
730
|
if (existing !== undefined)
|
|
@@ -712,6 +732,7 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
712
732
|
checkFloat32Allocation(Math.ceil(float32Storage(value).byteLength / 4), budget);
|
|
713
733
|
const copy = copyFloat32Storage(value, state);
|
|
714
734
|
state.seen.set(value, copy);
|
|
735
|
+
copyHostValueToSandbox(float32Storage(value).buffer, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), "buffer"] }, state, `${path}.buffer`);
|
|
715
736
|
for (const [key, descriptor] of float32DataProperties(value)) {
|
|
716
737
|
Object.defineProperty(copy, key, {
|
|
717
738
|
...descriptor,
|