poe-code 14.0.82 → 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 +1105 -223
- 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-7LGBDF56.js → chunk-2EZQJQ2C.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-CYVI4ZUK.js} +978 -161
- 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-prototypes.d.ts +3 -0
- package/packages/safe-js/dist/interp/float32-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/float32.d.ts +7 -1
- package/packages/safe-js/dist/interp/float32.js +50 -14
- 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 +4 -3
- package/packages/safe-js/dist/interp/globals/float32array.js +463 -68
- package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
- package/packages/safe-js/dist/interp/globals.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals.js +6 -2
- 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/instanceof.js +1 -1
- package/packages/safe-js/dist/interp/interpreter.js +2 -4
- package/packages/safe-js/dist/interp/iteration.js +15 -6
- package/packages/safe-js/dist/interp/methods/array-iterator.js +1 -1
- package/packages/safe-js/dist/interp/object-model.js +22 -1
- package/packages/safe-js/dist/interp/values.d.ts +1 -1
- package/packages/safe-js/dist/interp/values.js +59 -9
- 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/parse/parser.js +8 -3
- package/packages/safe-js/dist/parse/tokenizer.js +45 -3
- 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 +11 -1
- package/packages/safe-js/dist/snapshot/float32array.js +42 -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 +30 -3
- package/packages/safe-js/dist/snapshot/serialize.d.ts +7 -3
- package/packages/safe-js/dist/snapshot/serialize.js +24 -14
- package/packages/safe-js/dist/snapshot/validation.js +21 -1
- package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js.map → chunk-2EZQJQ2C.js.map} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { arrayBufferLength, arrayBufferOptions, isSandboxArrayBuffer } from "../interp/array-buffer.js";
|
|
2
|
+
import { float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
3
|
+
import { getSandboxPrototype, hasExplicitSandboxPrototype } from "../interp/object-model.js";
|
|
4
|
+
import { serializePropertyDescriptors } from "./property-descriptors.js";
|
|
5
|
+
export function captureArrayBufferState(value, encode) {
|
|
6
|
+
return { properties: serializePropertyDescriptors(value, encode),
|
|
7
|
+
...(hasExplicitSandboxPrototype(value) ? { prototype: encode(getSandboxPrototype(value)) } : {}) };
|
|
8
|
+
}
|
|
9
|
+
export function encodeArrayBufferStorage(value, id, buffers, reference) {
|
|
10
|
+
arrayBufferLength(value);
|
|
11
|
+
const existing = buffers.get(value);
|
|
12
|
+
if (existing === undefined)
|
|
13
|
+
buffers.set(value, id);
|
|
14
|
+
return { kind: "arraybuffer", ...(existing === undefined ? { bytes: Array.from(new Uint8Array(value)), ...arrayBufferOptions(value) } : { buffer: reference(existing) }) };
|
|
15
|
+
}
|
|
16
|
+
export function validateArrayBufferStorage(value) {
|
|
17
|
+
if (Object.hasOwn(value, "bytes") === Object.hasOwn(value, "buffer"))
|
|
18
|
+
throw new TypeError("ArrayBuffer requires one backing storage description.");
|
|
19
|
+
if (Object.hasOwn(value, "bytes") && (!Array.isArray(value.bytes) ||
|
|
20
|
+
value.bytes.some(byte => !Number.isInteger(byte) || byte < 0 || byte > 255)))
|
|
21
|
+
throw new TypeError("Invalid ArrayBuffer bytes.");
|
|
22
|
+
if (Object.hasOwn(value, "maxByteLength") && (!Array.isArray(value.bytes) ||
|
|
23
|
+
!Number.isSafeInteger(value.maxByteLength) || Number(value.maxByteLength) < value.bytes.length))
|
|
24
|
+
throw new TypeError("Invalid ArrayBuffer maximum length.");
|
|
25
|
+
}
|
|
26
|
+
export function decodeArrayBufferStorage(value, resolve) {
|
|
27
|
+
validateArrayBufferStorage(value);
|
|
28
|
+
if (Array.isArray(value.bytes)) {
|
|
29
|
+
const buffer = Reflect.construct(ArrayBuffer, [value.bytes.length,
|
|
30
|
+
Object.hasOwn(value, "maxByteLength") ? { maxByteLength: value.maxByteLength } : undefined]);
|
|
31
|
+
new Uint8Array(buffer).set(value.bytes);
|
|
32
|
+
return buffer;
|
|
33
|
+
}
|
|
34
|
+
const referenced = resolve(value.buffer);
|
|
35
|
+
if (isSandboxArrayBuffer(referenced))
|
|
36
|
+
return referenced;
|
|
37
|
+
if (isFloat32Array(referenced))
|
|
38
|
+
return float32Storage(referenced).buffer;
|
|
39
|
+
throw new TypeError("Invalid ArrayBuffer backing reference.");
|
|
40
|
+
}
|
|
@@ -12,8 +12,10 @@ import { sandboxErrorTypes } from "../error/shape.js";
|
|
|
12
12
|
import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
|
|
13
13
|
import { serializeArguments } from "./arguments.js";
|
|
14
14
|
import { requiresArrayEntries, serializeArray } from "./arrays.js";
|
|
15
|
-
import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
|
|
16
|
-
import {
|
|
15
|
+
import { float32DataProperties, float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
16
|
+
import { encodeFloat32Layout } from "./float32array.js";
|
|
17
|
+
import { isSandboxArrayBuffer } from "../interp/array-buffer.js";
|
|
18
|
+
import { captureArrayBufferState, encodeArrayBufferStorage } from "./array-buffer.js";
|
|
17
19
|
import { dateDataProperties, isSandboxDate } from "../interp/date.js";
|
|
18
20
|
import { serializeDate } from "./date-properties.js";
|
|
19
21
|
import { boxedDataProperties, isSandboxBox } from "../interp/boxed.js";
|
|
@@ -109,7 +111,7 @@ function serializeDumpValue(value, path, state) {
|
|
|
109
111
|
if (hasGuestObjectState(value) && !(state.trustedRunReplay && (isSandboxDate(value) || isSandboxPromise(value) || isPromiseResolvingFunction(value)))) {
|
|
110
112
|
throw new TypeError("Guest function properties and prototype links cannot be serialized.");
|
|
111
113
|
}
|
|
112
|
-
if (isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
|
|
114
|
+
if (isSandboxArrayBuffer(value) || isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
|
|
113
115
|
return serializeHeapReference(value, path, state);
|
|
114
116
|
if (Array.isArray(value)) {
|
|
115
117
|
const reference = serializeHeapReference(value, path, state);
|
|
@@ -186,11 +188,17 @@ function serializeHeapReference(value, path, state) {
|
|
|
186
188
|
return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
|
|
187
189
|
});
|
|
188
190
|
}
|
|
191
|
+
else if (isSandboxArrayBuffer(value)) {
|
|
192
|
+
state.heap[String(id)] = { ...encodeArrayBufferStorage(value, id, state.float32Buffers, id => ({ kind: "ref", id })),
|
|
193
|
+
state: captureArrayBufferState(value, entry => {
|
|
194
|
+
const serialized = serializeDumpValue(entry, `${path}.<buffer>`, state);
|
|
195
|
+
return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
|
|
196
|
+
}) };
|
|
197
|
+
}
|
|
189
198
|
else if (isFloat32Array(value)) {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}));
|
|
199
|
+
const backing = float32Storage(value);
|
|
200
|
+
const storage = { kind: "float32array", ...encodeFloat32Layout(value),
|
|
201
|
+
buffer: serializeHeapReference(backing.buffer, `${path}.buffer`, state) };
|
|
194
202
|
const entries = Object.create(null);
|
|
195
203
|
state.heap[String(id)] = { ...storage, entries };
|
|
196
204
|
for (const [key, descriptor] of float32DataProperties(value)) {
|
|
@@ -271,6 +279,7 @@ function indexHeapContainers(snapshot) {
|
|
|
271
279
|
(isSandboxRegex(value) && hasCustomRegexProperties(value)) ||
|
|
272
280
|
isSandboxDate(value) ||
|
|
273
281
|
isFloat32Array(value) ||
|
|
282
|
+
isSandboxArrayBuffer(value) ||
|
|
274
283
|
(Array.isArray(value) && requiresArrayEntries(value)) ||
|
|
275
284
|
isSandboxArguments(value) ||
|
|
276
285
|
sandboxErrorTypes.has(value)) {
|
|
@@ -305,9 +314,14 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
|
|
|
305
314
|
stat.expanded = true;
|
|
306
315
|
ancestors.add(value);
|
|
307
316
|
const guestEntries = [];
|
|
308
|
-
|
|
317
|
+
if (isFloat32Array(value))
|
|
318
|
+
guestEntries.push(float32Storage(value).buffer);
|
|
319
|
+
const guest = isSandboxArrayBuffer(value)
|
|
320
|
+
? { kind: "arraybuffer", state: captureArrayBufferState(value, entry => { guestEntries.push(entry); return null; }) }
|
|
321
|
+
: captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
|
|
309
322
|
if (guest !== undefined) {
|
|
310
|
-
|
|
323
|
+
if (!isSandboxArrayBuffer(value))
|
|
324
|
+
guestValues.add(value);
|
|
311
325
|
for (const entry of guestEntries) {
|
|
312
326
|
collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
|
|
313
327
|
if (entry !== null && typeof entry === "object")
|
|
@@ -316,6 +330,8 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
|
|
|
316
330
|
ancestors.delete(value);
|
|
317
331
|
return;
|
|
318
332
|
}
|
|
333
|
+
for (const entry of guestEntries)
|
|
334
|
+
collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
|
|
319
335
|
if (!Array.isArray(value) && !isPlainObject(value) && !isFloat32Array(value) && !isSandboxDate(value)) {
|
|
320
336
|
ancestors.delete(value);
|
|
321
337
|
return;
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import type { GuestObjectState } from "./guest-heap.js";
|
|
2
|
+
import type { Budget } from "../interp/budget.js";
|
|
3
|
+
export declare function captureFloat32State<T>(value: Float32Array, encode: (value: unknown) => T): GuestObjectState<T>;
|
|
4
|
+
export declare function restoreFloat32Properties<T>(value: Float32Array, state: GuestObjectState<T>, decode: (value: T) => unknown): void;
|
|
1
5
|
export type Float32Data<TReference> = {
|
|
2
6
|
kind: "float32array";
|
|
3
7
|
byteOffset: number;
|
|
4
8
|
length: number;
|
|
9
|
+
lengthTracking?: true;
|
|
5
10
|
} & ({
|
|
6
11
|
bytes: number[];
|
|
7
12
|
} | {
|
|
8
13
|
buffer: TReference;
|
|
9
14
|
});
|
|
15
|
+
export declare function encodeFloat32Layout(value: Float32Array): {
|
|
16
|
+
byteOffset: number;
|
|
17
|
+
length: number;
|
|
18
|
+
lengthTracking?: true;
|
|
19
|
+
};
|
|
10
20
|
export declare function encodeFloat32Storage<TReference>(value: Float32Array, id: number, buffers: WeakMap<ArrayBuffer, number>, reference: (id: number) => TReference): Float32Data<TReference>;
|
|
11
21
|
export declare function validateFloat32Storage(value: Record<string, unknown>): void;
|
|
12
|
-
export declare function decodeFloat32Storage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown): Float32Array;
|
|
22
|
+
export declare function decodeFloat32Storage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown, budget?: Budget): Float32Array;
|
|
@@ -1,4 +1,34 @@
|
|
|
1
|
-
import { float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
1
|
+
import { float32Properties, float32Storage, float32ViewLayouts, restoreFloat32View, isFloat32Array, isFloat32Index } from "../interp/float32.js";
|
|
2
|
+
import { getSandboxPrototype, hasExplicitSandboxPrototype } from "../interp/object-model.js";
|
|
3
|
+
import { restorePropertyDescriptors, serializePropertyDescriptors } from "./property-descriptors.js";
|
|
4
|
+
import { arrayBufferOptions, isSandboxArrayBuffer } from "../interp/array-buffer.js";
|
|
5
|
+
export function captureFloat32State(value, encode) {
|
|
6
|
+
const metadata = Object.defineProperties(Object.create(null), Object.fromEntries(float32Properties(value)));
|
|
7
|
+
if (!Object.isExtensible(value))
|
|
8
|
+
Object.preventExtensions(metadata);
|
|
9
|
+
return { properties: serializePropertyDescriptors(metadata, encode),
|
|
10
|
+
...(hasExplicitSandboxPrototype(value) ? { prototype: encode(getSandboxPrototype(value)) } : {}) };
|
|
11
|
+
}
|
|
12
|
+
export function restoreFloat32Properties(value, state, decode) {
|
|
13
|
+
const metadata = Object.create(null);
|
|
14
|
+
restorePropertyDescriptors(metadata, state.properties, decode);
|
|
15
|
+
const descriptors = Object.getOwnPropertyDescriptors(metadata);
|
|
16
|
+
if (Object.keys(descriptors).some(isFloat32Index))
|
|
17
|
+
throw new TypeError("Float32Array metadata cannot replace numeric storage.");
|
|
18
|
+
Object.defineProperties(value, descriptors);
|
|
19
|
+
if (!Object.isExtensible(metadata))
|
|
20
|
+
Object.preventExtensions(value);
|
|
21
|
+
}
|
|
22
|
+
export function encodeFloat32Layout(value) {
|
|
23
|
+
const storage = float32Storage(value);
|
|
24
|
+
if (arrayBufferOptions(storage.buffer) === undefined)
|
|
25
|
+
return { byteOffset: storage.byteOffset, length: storage.length };
|
|
26
|
+
const layout = float32ViewLayouts.get(value);
|
|
27
|
+
if (layout === undefined)
|
|
28
|
+
throw new TypeError("Resizable Float32Array snapshots require known view layout.");
|
|
29
|
+
return { byteOffset: layout.byteOffset, length: layout.length ?? 0,
|
|
30
|
+
...(layout.length === undefined ? { lengthTracking: true } : {}) };
|
|
31
|
+
}
|
|
2
32
|
export function encodeFloat32Storage(value, id, buffers, reference) {
|
|
3
33
|
const storage = float32Storage(value);
|
|
4
34
|
const existing = buffers.get(storage.buffer);
|
|
@@ -14,6 +44,8 @@ export function encodeFloat32Storage(value, id, buffers, reference) {
|
|
|
14
44
|
};
|
|
15
45
|
}
|
|
16
46
|
export function validateFloat32Storage(value) {
|
|
47
|
+
if (Object.hasOwn(value, "lengthTracking") && (value.lengthTracking !== true || value.length !== 0 || Object.hasOwn(value, "bytes")))
|
|
48
|
+
throw new TypeError("Invalid Float32Array length-tracking layout.");
|
|
17
49
|
if (!Number.isSafeInteger(value.length) ||
|
|
18
50
|
Number(value.length) < 0 ||
|
|
19
51
|
!Number.isSafeInteger(value.byteOffset) ||
|
|
@@ -29,7 +61,7 @@ export function validateFloat32Storage(value) {
|
|
|
29
61
|
throw new TypeError("Invalid Float32Array backing bytes.");
|
|
30
62
|
}
|
|
31
63
|
}
|
|
32
|
-
export function decodeFloat32Storage(value, resolve) {
|
|
64
|
+
export function decodeFloat32Storage(value, resolve, budget) {
|
|
33
65
|
validateFloat32Storage(value);
|
|
34
66
|
let buffer;
|
|
35
67
|
if (Array.isArray(value.bytes)) {
|
|
@@ -38,9 +70,14 @@ export function decodeFloat32Storage(value, resolve) {
|
|
|
38
70
|
}
|
|
39
71
|
else {
|
|
40
72
|
const referenced = resolve(value.buffer);
|
|
41
|
-
if (
|
|
73
|
+
if (isSandboxArrayBuffer(referenced))
|
|
74
|
+
buffer = referenced;
|
|
75
|
+
else if (isFloat32Array(referenced))
|
|
76
|
+
buffer = float32Storage(referenced).buffer;
|
|
77
|
+
else
|
|
42
78
|
throw new TypeError("Invalid Float32Array backing reference.");
|
|
43
|
-
buffer = float32Storage(referenced).buffer;
|
|
44
79
|
}
|
|
45
|
-
|
|
80
|
+
if (value.lengthTracking === true && arrayBufferOptions(buffer) === undefined)
|
|
81
|
+
throw new TypeError("Length-tracking layout requires resizable backing storage.");
|
|
82
|
+
return restoreFloat32View(buffer, Number(value.byteOffset), value.lengthTracking === true ? undefined : Number(value.length), budget);
|
|
46
83
|
}
|
|
@@ -4,6 +4,7 @@ import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.
|
|
|
4
4
|
import { type CollectionIterationMethod } from "../interp/collection-iterator.js";
|
|
5
5
|
import { CompileScope } from "../interp/regex/compile-guard.js";
|
|
6
6
|
import { type Float32Data } from "./float32array.js";
|
|
7
|
+
import { type ArrayBufferData } from "./array-buffer.js";
|
|
7
8
|
import { type SandboxErrorName } from "../error/shape.js";
|
|
8
9
|
import { type SandboxClosure, type SandboxPromise, type SandboxValue } from "../interp/values.js";
|
|
9
10
|
import { type SerializedArguments } from "./arguments.js";
|
|
@@ -69,6 +70,10 @@ type DataNode = {
|
|
|
69
70
|
} | (Float32Data<Atom> & {
|
|
70
71
|
properties: Properties;
|
|
71
72
|
extensible: boolean;
|
|
73
|
+
}) | (ArrayBufferData<Atom> & {
|
|
74
|
+
properties: Properties;
|
|
75
|
+
extensible: boolean;
|
|
76
|
+
symbolEntries?: Array<SerializedSymbolProperty<Atom>>;
|
|
72
77
|
}) | {
|
|
73
78
|
kind: "capability";
|
|
74
79
|
id: string;
|
|
@@ -10,8 +10,10 @@ import { isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshot
|
|
|
10
10
|
import { isSandboxRegExpIterator, regexpIteratorState, restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
|
|
11
11
|
import { hasGuestObjectState, hasNullObjectPrototype, setSandboxPrototype } from "../interp/object-model.js";
|
|
12
12
|
import { CompileScope } from "../interp/regex/compile-guard.js";
|
|
13
|
-
import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
|
|
14
|
-
import { decodeFloat32Storage,
|
|
13
|
+
import { float32DataProperties, float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
14
|
+
import { decodeFloat32Storage, encodeFloat32Layout } from "./float32array.js";
|
|
15
|
+
import { arrayBufferDataProperties, isSandboxArrayBuffer } from "../interp/array-buffer.js";
|
|
16
|
+
import { decodeArrayBufferStorage, encodeArrayBufferStorage } from "./array-buffer.js";
|
|
15
17
|
import { dateDataProperties, isSandboxDate, restoreDateTime, serializedDateTime } from "../interp/date.js";
|
|
16
18
|
import { createRawJson, isRawJson } from "../interp/raw-json.js";
|
|
17
19
|
import { boxedDataProperties, createSandboxBox, nativeBoxedValue } from "../interp/boxed.js";
|
|
@@ -119,11 +121,22 @@ export function encodeReplayData(value, options = {}) {
|
|
|
119
121
|
...(Object.isExtensible(entry) ? {} : { extensible: false })
|
|
120
122
|
};
|
|
121
123
|
}
|
|
124
|
+
else if (isSandboxArrayBuffer(entry)) {
|
|
125
|
+
const storage = encodeArrayBufferStorage(entry, id, float32Buffers, id => ({ tag: "ref", id }));
|
|
126
|
+
const properties = Object.create(null);
|
|
127
|
+
for (const [key, descriptor] of arrayBufferDataProperties(entry)) {
|
|
128
|
+
if (typeof key === "symbol")
|
|
129
|
+
continue;
|
|
130
|
+
properties[key] = { value: child(descriptor.value, key), configurable: descriptor.configurable === true,
|
|
131
|
+
enumerable: descriptor.enumerable === true, writable: descriptor.writable === true };
|
|
132
|
+
}
|
|
133
|
+
let symbolIndex = 0;
|
|
134
|
+
const symbolEntries = serializeSymbolProperties(entry, value => encode(value, depth + 1, [...path, { symbol: Math.floor(symbolIndex++ / 2) }]));
|
|
135
|
+
nodes[id] = { ...storage, properties, extensible: Object.isExtensible(entry), symbolEntries };
|
|
136
|
+
}
|
|
122
137
|
else if (isFloat32Array(entry)) {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
id
|
|
126
|
-
}));
|
|
138
|
+
const backing = float32Storage(entry);
|
|
139
|
+
const storage = { kind: "float32array", ...encodeFloat32Layout(entry), buffer: child(backing.buffer, "<buffer>") };
|
|
127
140
|
const properties = Object.create(null);
|
|
128
141
|
for (const [key, descriptor] of float32DataProperties(entry)) {
|
|
129
142
|
properties[key] = {
|
|
@@ -227,7 +240,7 @@ export function decodeReplayData(input, options = {}, parent) {
|
|
|
227
240
|
const graph = record(input);
|
|
228
241
|
const nodes = list(own(graph, "nodes"));
|
|
229
242
|
const restored = new Map();
|
|
230
|
-
const
|
|
243
|
+
const initializeValues = [];
|
|
231
244
|
const decode = (entry, depth = 0) => {
|
|
232
245
|
if (depth > MAX_DATA_DEPTH)
|
|
233
246
|
throw new TypeError("Replay data exceeds the nesting limit.");
|
|
@@ -378,10 +391,22 @@ export function decodeReplayData(input, options = {}, parent) {
|
|
|
378
391
|
Object.preventExtensions(result);
|
|
379
392
|
return result;
|
|
380
393
|
}
|
|
394
|
+
if (kind === "arraybuffer") {
|
|
395
|
+
if (typeof node.extensible !== "boolean")
|
|
396
|
+
throw new TypeError("Invalid ArrayBuffer extensibility.");
|
|
397
|
+
const result = decodeArrayBufferStorage(node, child);
|
|
398
|
+
restored.set(id, result);
|
|
399
|
+
initializeValues.push(() => {
|
|
400
|
+
defineProperties(result, record(own(node, "properties")), child, node.symbolEntries);
|
|
401
|
+
if (!node.extensible)
|
|
402
|
+
Object.preventExtensions(result);
|
|
403
|
+
});
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
381
406
|
if (kind === "float32array") {
|
|
382
407
|
if (typeof node.extensible !== "boolean")
|
|
383
408
|
throw new TypeError("Invalid Float32Array extensibility.");
|
|
384
|
-
const result = decodeFloat32Storage(node, child);
|
|
409
|
+
const result = decodeFloat32Storage(node, child, compilation.owner?.budget);
|
|
385
410
|
restored.set(id, result);
|
|
386
411
|
defineProperties(result, record(own(node, "properties")), child);
|
|
387
412
|
if (!node.extensible)
|
|
@@ -421,7 +446,7 @@ export function decodeReplayData(input, options = {}, parent) {
|
|
|
421
446
|
const collection = child(own(node, "collection"));
|
|
422
447
|
if (collection !== undefined && !isSandboxMap(collection) && !isSandboxSet(collection))
|
|
423
448
|
throw new TypeError("Invalid replay collection iterator source.");
|
|
424
|
-
|
|
449
|
+
initializeValues.push(() => { restoreSandboxCollectionIterator({ collection, collectionKind, method, index, exhausted }, result); });
|
|
425
450
|
defineProperties(result, record(own(node, "properties")), child);
|
|
426
451
|
if (!node.extensible)
|
|
427
452
|
Object.preventExtensions(result);
|
|
@@ -503,7 +528,7 @@ export function decodeReplayData(input, options = {}, parent) {
|
|
|
503
528
|
return result;
|
|
504
529
|
};
|
|
505
530
|
const result = decode(own(graph, "root"));
|
|
506
|
-
for (const initialize of
|
|
531
|
+
for (const initialize of initializeValues)
|
|
507
532
|
initialize();
|
|
508
533
|
if (parent !== undefined)
|
|
509
534
|
compilation.forward(compilation.tickets, parent);
|
|
@@ -17,7 +17,8 @@ import { awaitSandboxValue } from "../interp/cancel.js";
|
|
|
17
17
|
import { runAsyncPrefix } from "../interp/jobs.js";
|
|
18
18
|
import { toPropertyKey } from "../interp/property-key.js";
|
|
19
19
|
import { CompileScope } from "../interp/regex/compile-guard.js";
|
|
20
|
-
import { decodeFloat32Storage } from "./float32array.js";
|
|
20
|
+
import { decodeFloat32Storage, restoreFloat32Properties } from "./float32array.js";
|
|
21
|
+
import { decodeArrayBufferStorage } from "./array-buffer.js";
|
|
21
22
|
import { restoreDateTime } from "../interp/date.js";
|
|
22
23
|
import { createRawJson } from "../interp/raw-json.js";
|
|
23
24
|
import { createSandboxBox } from "../interp/boxed.js";
|
|
@@ -411,7 +412,11 @@ function initializeIntrinsicRealm(state) {
|
|
|
411
412
|
return prototype?.kind === "intrinsic" &&
|
|
412
413
|
prototype.id === JSON.stringify([...JSON.parse(node.id), "prototype"]);
|
|
413
414
|
}));
|
|
414
|
-
|
|
415
|
+
const float32 = Object.values(state.heap).find(node => node.kind === "intrinsic" && node.id === '["Float32Array"]');
|
|
416
|
+
const float32Prototypes = float32?.kind !== "intrinsic" ||
|
|
417
|
+
float32.state?.properties.properties.some(([key, descriptor]) => key === "prototype" && descriptor.kind === "data" &&
|
|
418
|
+
!descriptor.writable && !descriptor.enumerable && !descriptor.configurable) === true;
|
|
419
|
+
createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes, float32Prototypes });
|
|
415
420
|
state.intrinsicsInitialized = true;
|
|
416
421
|
}
|
|
417
422
|
function restoreHeapValue(id, state) {
|
|
@@ -452,9 +457,31 @@ function restoreHeapValue(id, state) {
|
|
|
452
457
|
restoreRegexProperties(value, serialized, entry => deserializeValue(entry, state));
|
|
453
458
|
return value;
|
|
454
459
|
}
|
|
460
|
+
if (serialized.kind === "arraybuffer") {
|
|
461
|
+
initializeIntrinsicRealm(state);
|
|
462
|
+
const value = decodeArrayBufferStorage(serialized, reference => deserializeValue(reference, state));
|
|
463
|
+
state.heapValueById.set(id, value);
|
|
464
|
+
state.initializeIterators.push(() => {
|
|
465
|
+
if (serialized.state.prototype !== undefined)
|
|
466
|
+
setSandboxPrototype(value, deserializeValue(serialized.state.prototype, state), state.budget);
|
|
467
|
+
restorePropertyDescriptors(value, serialized.state.properties, entry => deserializeValue(entry, state));
|
|
468
|
+
});
|
|
469
|
+
return value;
|
|
470
|
+
}
|
|
455
471
|
if (serialized.kind === "float32array") {
|
|
456
|
-
|
|
472
|
+
if (serialized.state !== undefined)
|
|
473
|
+
initializeIntrinsicRealm(state);
|
|
474
|
+
const value = decodeFloat32Storage(serialized, (reference) => deserializeValue(reference, state), state.budget);
|
|
457
475
|
state.heapValueById.set(id, value);
|
|
476
|
+
if (serialized.state !== undefined) {
|
|
477
|
+
const objectState = serialized.state;
|
|
478
|
+
state.initializeIterators.push(() => {
|
|
479
|
+
if (objectState.prototype !== undefined)
|
|
480
|
+
setSandboxPrototype(value, deserializeValue(objectState.prototype, state), state.budget);
|
|
481
|
+
restoreFloat32Properties(value, objectState, entry => deserializeValue(entry, state));
|
|
482
|
+
});
|
|
483
|
+
return value;
|
|
484
|
+
}
|
|
458
485
|
for (const [key, entry] of Object.entries(serialized.entries)) {
|
|
459
486
|
Object.defineProperty(value, key, {
|
|
460
487
|
value: deserializeValue(entry, state),
|
|
@@ -4,10 +4,11 @@ import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.
|
|
|
4
4
|
import { type CollectionIterationMethod, type SandboxCollectionIterator } from "../interp/collection-iterator.js";
|
|
5
5
|
import { type SandboxRegExpIterator } from "../interp/regexp-iterator.js";
|
|
6
6
|
import { type SandboxErrorName } from "../error/shape.js";
|
|
7
|
-
import { type GuestHeapNode } from "./guest-heap.js";
|
|
7
|
+
import { type GuestHeapNode, type GuestObjectState } from "./guest-heap.js";
|
|
8
8
|
import { type SerializedArguments } from "./arguments.js";
|
|
9
9
|
import { type SerializedArray } from "./arrays.js";
|
|
10
10
|
import { type Float32Data } from "./float32array.js";
|
|
11
|
+
import { type ArrayBufferData } from "./array-buffer.js";
|
|
11
12
|
import { type SerializedDate } from "./date-properties.js";
|
|
12
13
|
import { type SandboxBox } from "../interp/boxed.js";
|
|
13
14
|
import { type BoxedData } from "./boxed.js";
|
|
@@ -51,7 +52,9 @@ export type SerializedReferenceValue = {
|
|
|
51
52
|
kind: "ref";
|
|
52
53
|
id: number;
|
|
53
54
|
};
|
|
54
|
-
export type SerializedHeapValue =
|
|
55
|
+
export type SerializedHeapValue = (ArrayBufferData<SerializedReferenceValue> & {
|
|
56
|
+
state: GuestObjectState<SerializedSnapshotValue>;
|
|
57
|
+
}) | GuestHeapNode<SerializedSnapshotValue> | {
|
|
55
58
|
kind: "regexp-iterator";
|
|
56
59
|
matcher: SerializedSnapshotValue;
|
|
57
60
|
input: SerializedSnapshotValue;
|
|
@@ -75,6 +78,7 @@ export type SerializedHeapValue = GuestHeapNode<SerializedSnapshotValue> | {
|
|
|
75
78
|
entries: Record<string, SerializedSnapshotValue>;
|
|
76
79
|
} | SerializedDate<SerializedSnapshotValue> | (Float32Data<SerializedReferenceValue> & {
|
|
77
80
|
entries: Record<string, SerializedSnapshotValue>;
|
|
81
|
+
state?: GuestObjectState<SerializedSnapshotValue>;
|
|
78
82
|
}) | SerializedArguments<SerializedSnapshotValue> | SerializedArray<SerializedSnapshotValue> | {
|
|
79
83
|
kind: "object";
|
|
80
84
|
sandboxNullPrototype?: true;
|
|
@@ -111,7 +115,7 @@ export type RuntimePromiseValue = {
|
|
|
111
115
|
id: SnapshotId;
|
|
112
116
|
promise?: Promise<unknown>;
|
|
113
117
|
};
|
|
114
|
-
export type RuntimeSnapshotValue = bigint | symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
|
|
118
|
+
export type RuntimeSnapshotValue = bigint | symbol | SandboxBox | Date | Float32Array | ArrayBuffer | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
|
|
115
119
|
[key: string]: RuntimeSnapshotValue;
|
|
116
120
|
};
|
|
117
121
|
export type RuntimeScopeFrame = {
|
|
@@ -11,8 +11,10 @@ import { captureGuestHeapNode } from "./guest-heap.js";
|
|
|
11
11
|
import { getGeneratorOrigin } from "../interp/closure-origin.js";
|
|
12
12
|
import { serializeArguments } from "./arguments.js";
|
|
13
13
|
import { requiresArrayEntries, serializeArray } from "./arrays.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
15
|
+
import { captureFloat32State, encodeFloat32Layout } from "./float32array.js";
|
|
16
|
+
import { isSandboxArrayBuffer } from "../interp/array-buffer.js";
|
|
17
|
+
import { captureArrayBufferState, encodeArrayBufferStorage } from "./array-buffer.js";
|
|
16
18
|
import { dateDataProperties, isSandboxDate } from "../interp/date.js";
|
|
17
19
|
import { serializeDate } from "./date-properties.js";
|
|
18
20
|
import { boxedDataProperties, isSandboxBox } from "../interp/boxed.js";
|
|
@@ -104,7 +106,7 @@ function serializeValue(value, path, state) {
|
|
|
104
106
|
}
|
|
105
107
|
return { kind: "ref", id };
|
|
106
108
|
}
|
|
107
|
-
if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value)) {
|
|
109
|
+
if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isFloat32Array(value) && !isSandboxArrayBuffer(value)) {
|
|
108
110
|
throw new TypeError("Guest function properties and prototype links cannot be serialized.");
|
|
109
111
|
}
|
|
110
112
|
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
@@ -197,7 +199,7 @@ function serializeValue(value, path, state) {
|
|
|
197
199
|
throw new TypeError(`Missing regex heap reference at ${path}.`);
|
|
198
200
|
return { kind: "regex", source: value.source, flags: value.flags, lastIndex: value.lastIndex };
|
|
199
201
|
}
|
|
200
|
-
if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
|
|
202
|
+
if (isSandboxArrayBuffer(value) || isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
|
|
201
203
|
const reference = serializeHeapReference(value, path, state);
|
|
202
204
|
if (reference === undefined) {
|
|
203
205
|
throw new TypeError(`Cannot serialize collection without a heap reference at ${path}.`);
|
|
@@ -260,15 +262,15 @@ function serializeHeapReference(value, path, state) {
|
|
|
260
262
|
else if (isSandboxDate(value)) {
|
|
261
263
|
state.heap[String(id)] = serializeDate(value, entry => serializeValue(entry, `${path}.<date-property>`, state));
|
|
262
264
|
}
|
|
265
|
+
else if (isSandboxArrayBuffer(value)) {
|
|
266
|
+
state.heap[String(id)] = { ...encodeArrayBufferStorage(value, id, state.float32Buffers, id => ({ kind: "ref", id })),
|
|
267
|
+
state: captureArrayBufferState(value, entry => serializeValue(entry, `${path}.<buffer>`, state)) };
|
|
268
|
+
}
|
|
263
269
|
else if (isFloat32Array(value)) {
|
|
264
|
-
const storage =
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const entries = Object.create(null);
|
|
269
|
-
state.heap[String(id)] = { ...storage, entries };
|
|
270
|
-
for (const [key, descriptor] of float32DataProperties(value))
|
|
271
|
-
entries[key] = serializeValue(descriptor.value, `${path}.${key}`, state);
|
|
270
|
+
const storage = float32Storage(value);
|
|
271
|
+
state.heap[String(id)] = { kind: "float32array", ...encodeFloat32Layout(value),
|
|
272
|
+
buffer: serializeHeapReference(storage.buffer, `${path}.buffer`, state), entries: {},
|
|
273
|
+
state: captureFloat32State(value, entry => serializeValue(entry, `${path}.<typed-array>`, state)) };
|
|
272
274
|
}
|
|
273
275
|
else if (isSandboxArguments(value)) {
|
|
274
276
|
state.heap[String(id)] = serializeArguments(value, (entry, key) => serializeValue(entry, `${path}.${key}`, state));
|
|
@@ -389,6 +391,7 @@ function indexHeapContainers(input) {
|
|
|
389
391
|
isSandboxBox(value) ||
|
|
390
392
|
isSandboxDate(value) ||
|
|
391
393
|
isFloat32Array(value) ||
|
|
394
|
+
isSandboxArrayBuffer(value) ||
|
|
392
395
|
(Array.isArray(value) && requiresArrayEntries(value)) ||
|
|
393
396
|
sandboxErrorTypes.has(value) ||
|
|
394
397
|
isSandboxArguments(value) ||
|
|
@@ -431,9 +434,16 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
|
|
|
431
434
|
stat.expanded = true;
|
|
432
435
|
ancestors.add(value);
|
|
433
436
|
const guestEntries = [];
|
|
434
|
-
|
|
437
|
+
if (isFloat32Array(value))
|
|
438
|
+
guestEntries.push(float32Storage(value).buffer);
|
|
439
|
+
const guest = isFloat32Array(value)
|
|
440
|
+
? { kind: "float32array", state: captureFloat32State(value, entry => { guestEntries.push(entry); return null; }) }
|
|
441
|
+
: isSandboxArrayBuffer(value)
|
|
442
|
+
? { kind: "arraybuffer", state: captureArrayBufferState(value, entry => { guestEntries.push(entry); return null; }) }
|
|
443
|
+
: captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
|
|
435
444
|
if (guest !== undefined) {
|
|
436
|
-
|
|
445
|
+
if (!isFloat32Array(value) && !isSandboxArrayBuffer(value))
|
|
446
|
+
guestValues.add(value);
|
|
437
447
|
for (const entry of guestEntries) {
|
|
438
448
|
collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
|
|
439
449
|
if (entry !== null && typeof entry === "object") {
|
|
@@ -6,6 +6,7 @@ import { types } from "node:util";
|
|
|
6
6
|
import { DUMP_FORMAT_VERSION } from "./dump-format.js";
|
|
7
7
|
import { MAX_DATA_DEPTH } from "../graph-depth.js";
|
|
8
8
|
import { validateFloat32Storage } from "./float32array.js";
|
|
9
|
+
import { validateArrayBufferStorage } from "./array-buffer.js";
|
|
9
10
|
import { restoreDateTime } from "../interp/date.js";
|
|
10
11
|
import { validateBoxedProperties } from "./boxed.js";
|
|
11
12
|
import { hasGuestObjectState } from "../interp/object-model.js";
|
|
@@ -117,9 +118,19 @@ function validateDumpHeap(root, state) {
|
|
|
117
118
|
validateDateRecord(entry, path);
|
|
118
119
|
continue;
|
|
119
120
|
}
|
|
121
|
+
if (entry.kind === "arraybuffer") {
|
|
122
|
+
validateArrayBufferStorage(entry);
|
|
123
|
+
validateGuestHeapNode({ kind: "guest-object", state: entry.state }, heap, state.limits.maxEntries);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
120
126
|
if (entry.kind === "float32array") {
|
|
121
127
|
validateFloat32Storage(entry);
|
|
122
128
|
requireRecord(entry.entries, `${path}.entries`);
|
|
129
|
+
if (Object.hasOwn(entry, "state")) {
|
|
130
|
+
if (Object.keys(entry.entries).length !== 0)
|
|
131
|
+
fail("invalidValue", path, "ambiguous Float32Array property state");
|
|
132
|
+
validateGuestHeapNode({ kind: "guest-object", state: entry.state }, heap, state.limits.maxEntries);
|
|
133
|
+
}
|
|
123
134
|
continue;
|
|
124
135
|
}
|
|
125
136
|
if (entry.kind === "arguments") {
|
|
@@ -533,7 +544,7 @@ function validateHeapValue(value, path, state, heap) {
|
|
|
533
544
|
fail("invalidValue", path, String(error));
|
|
534
545
|
}
|
|
535
546
|
validateErrorType(record, path);
|
|
536
|
-
if (!["symbol", "arguments", "array", "object", "map", "set", "float32array", "date", "boxed", "collection-iterator", "regexp-iterator", "regex-object"].includes(String(record.kind)))
|
|
547
|
+
if (!["symbol", "arguments", "array", "object", "map", "set", "float32array", "arraybuffer", "date", "boxed", "collection-iterator", "regexp-iterator", "regex-object"].includes(String(record.kind)))
|
|
537
548
|
fail("unknownTag", `${path}.kind`, "unknown heap tag");
|
|
538
549
|
validateValue(record, path, 1, state);
|
|
539
550
|
if (record.kind === "symbol")
|
|
@@ -548,9 +559,18 @@ function validateHeapValue(value, path, state, heap) {
|
|
|
548
559
|
validateBoxedRecord(record, path, heap);
|
|
549
560
|
if (record.kind === "date")
|
|
550
561
|
validateDateRecord(record, path);
|
|
562
|
+
if (record.kind === "arraybuffer") {
|
|
563
|
+
validateArrayBufferStorage(record);
|
|
564
|
+
validateGuestHeapNode({ kind: "guest-object", state: record.state }, heap, state.limits.maxEntries);
|
|
565
|
+
}
|
|
551
566
|
if (record.kind === "float32array") {
|
|
552
567
|
validateFloat32Storage(record);
|
|
553
568
|
requireRecord(record.entries, `${path}.entries`);
|
|
569
|
+
if (Object.hasOwn(record, "state")) {
|
|
570
|
+
if (Object.keys(record.entries).length !== 0)
|
|
571
|
+
fail("invalidValue", path, "ambiguous Float32Array property state");
|
|
572
|
+
validateGuestHeapNode({ kind: "guest-object", state: record.state }, heap, state.limits.maxEntries);
|
|
573
|
+
}
|
|
554
574
|
}
|
|
555
575
|
if (record.kind === "map") {
|
|
556
576
|
const entries = requireArray(record.entries, `${path}.entries`, state);
|