poe-code 14.0.82 → 14.0.83
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 +543 -156
- 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-37V6Q4K3.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-PT7PBLVT.js} +457 -91
- package/packages/safe-js/dist/chunks/chunk-PT7PBLVT.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/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 +1 -0
- package/packages/safe-js/dist/interp/float32.js +12 -4
- package/packages/safe-js/dist/interp/globals/float32array.d.ts +3 -2
- package/packages/safe-js/dist/interp/globals/float32array.js +371 -65
- package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
- package/packages/safe-js/dist/interp/globals.d.ts +1 -0
- package/packages/safe-js/dist/interp/globals.js +4 -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/object-model.js +16 -1
- package/packages/safe-js/dist/interp/values.js +12 -4
- 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/float32array.d.ts +3 -0
- package/packages/safe-js/dist/snapshot/float32array.js +20 -1
- package/packages/safe-js/dist/snapshot/restore.js +17 -2
- package/packages/safe-js/dist/snapshot/serialize.d.ts +2 -1
- package/packages/safe-js/dist/snapshot/serialize.js +10 -9
- package/packages/safe-js/dist/snapshot/validation.js +10 -0
- package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js.map → chunk-37V6Q4K3.js.map} +0 -0
|
@@ -27,7 +27,7 @@ export async function ordinaryHasInstance(value, constructor, budget, context) {
|
|
|
27
27
|
return evaluateInstanceof(value, constructor.boundTarget, budget, context);
|
|
28
28
|
}
|
|
29
29
|
// These existing built-ins do not yet have ordinary prototype graphs.
|
|
30
|
-
if (isFloat32ArrayConstructor(constructor))
|
|
30
|
+
if (isFloat32ArrayConstructor(constructor) && !isGuestClosure(constructor))
|
|
31
31
|
return isFloat32Array(value);
|
|
32
32
|
if ((!isGuestClosure(constructor) || (value !== null && typeof value === "object" && !hasExplicitSandboxPrototype(value))) &&
|
|
33
33
|
isSandboxErrorConstructorInstance(value, constructor))
|
|
@@ -2380,7 +2380,7 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
2380
2380
|
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2381
2381
|
}
|
|
2382
2382
|
if (isFloat32Array(member.object)) {
|
|
2383
|
-
return evaluateResolvedCallExpression(node,
|
|
2383
|
+
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2384
2384
|
}
|
|
2385
2385
|
if (isSandboxSet(member.object)) {
|
|
2386
2386
|
return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
|
|
@@ -2911,9 +2911,7 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
|
|
|
2911
2911
|
if (isSandboxMap(target) || isSandboxSet(target))
|
|
2912
2912
|
target = getCollectionProperties(target);
|
|
2913
2913
|
if (isFloat32Array(target)) {
|
|
2914
|
-
|
|
2915
|
-
throw new TypeError("Typed array symbol properties are not yet supported.");
|
|
2916
|
-
setFloat32Member(target, property, value);
|
|
2914
|
+
setFloat32Member(target, property, value, budget);
|
|
2917
2915
|
return;
|
|
2918
2916
|
}
|
|
2919
2917
|
if (isSandboxRegex(target)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxSet } from "./values.js";
|
|
2
2
|
import { enterRunningState } from "./running-state.js";
|
|
3
3
|
import { isFloat32Array } from "./float32.js";
|
|
4
|
+
import { float32Prototypes } from "./float32-prototypes.js";
|
|
4
5
|
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
5
6
|
import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
|
|
6
7
|
import { isSandboxCollectionIterator, nextCollectionIterator } from "./collection-iterator.js";
|
|
@@ -98,6 +99,9 @@ export async function acquireSandboxIterator(value, budget, context, asyncProtoc
|
|
|
98
99
|
const iterator = await invokeBuiltinClosure(factory, [], budget, context, value);
|
|
99
100
|
if ((typeof iterator !== "object" && typeof iterator !== "function") || iterator === null)
|
|
100
101
|
throw new TypeError("Iterator must be an object.");
|
|
102
|
+
if (!asyncProtocol && isSandboxGenerator(iterator) && !iterator.async &&
|
|
103
|
+
!hasExplicitSandboxPrototype(iterator) && getSandboxPropertyDescriptor(iterator, "next", budget) === undefined)
|
|
104
|
+
return getSandboxIterator(iterator, budget, context);
|
|
101
105
|
const next = await context.getProperty(iterator, "next");
|
|
102
106
|
return guestIterator(iterator, next, asyncProtocol, budget, context, signal);
|
|
103
107
|
}
|
|
@@ -137,7 +141,7 @@ export async function readIteratorResult(iterator, result, property) {
|
|
|
137
141
|
export function getSandboxAsyncIterator(value, budget, context, signal) {
|
|
138
142
|
if (isSandboxGenerator(value) && value.async) {
|
|
139
143
|
return hasExplicitSandboxPrototype(value) ? context?.getProperty === undefined
|
|
140
|
-
?
|
|
144
|
+
? guestProtocolAdapter(value, budget, context, true, signal) : undefined
|
|
141
145
|
: { ...generatorObjectIterator(value, budget, context), asyncProtocol: true };
|
|
142
146
|
}
|
|
143
147
|
if (value !== null &&
|
|
@@ -293,6 +297,11 @@ export function getSandboxIterator(value, budget, context) {
|
|
|
293
297
|
if (isGuestHostObject(value))
|
|
294
298
|
return getHostObjectIterator(value);
|
|
295
299
|
if (isFloat32Array(value)) {
|
|
300
|
+
if (hasExplicitSandboxPrototype(value) || (budget !== undefined && float32Prototypes.has(budget))) {
|
|
301
|
+
if (getSandboxPropertyDescriptor(value, Symbol.iterator, budget) === undefined)
|
|
302
|
+
return undefined;
|
|
303
|
+
return guestProtocolAdapter(value, budget ?? new Budget(), context, false);
|
|
304
|
+
}
|
|
296
305
|
return syncIterator(Float32Array.prototype.values.call(value));
|
|
297
306
|
}
|
|
298
307
|
if (isSandboxGenerator(value)) {
|
|
@@ -300,7 +309,7 @@ export function getSandboxIterator(value, budget, context) {
|
|
|
300
309
|
return undefined;
|
|
301
310
|
if (hasExplicitSandboxPrototype(value))
|
|
302
311
|
return context?.getProperty === undefined
|
|
303
|
-
?
|
|
312
|
+
? guestProtocolAdapter(value, budget ?? new Budget(), context, false) : undefined;
|
|
304
313
|
return generatorObjectIterator(value, budget, context);
|
|
305
314
|
}
|
|
306
315
|
if (typeof value === "string") {
|
|
@@ -386,9 +395,9 @@ function collectionIterator(collection, value) {
|
|
|
386
395
|
return adapter;
|
|
387
396
|
}
|
|
388
397
|
const asyncGeneratorRequests = new WeakMap();
|
|
389
|
-
function
|
|
390
|
-
// Direct
|
|
391
|
-
// cached next methods
|
|
398
|
+
function guestProtocolAdapter(value, budget, context, asyncProtocol, signal) {
|
|
399
|
+
// Direct adapters still need guest property reads, receiver binding and
|
|
400
|
+
// cached next methods without exposing native iterator objects.
|
|
392
401
|
const bridge = {
|
|
393
402
|
...context,
|
|
394
403
|
stack: context?.stack ?? [],
|
|
@@ -403,7 +412,7 @@ function generatorProtocolAdapter(value, budget, context, asyncProtocol, signal)
|
|
|
403
412
|
let pending;
|
|
404
413
|
const initialize = () => pending ??= acquireSandboxIterator(value, budget, bridge, asyncProtocol, signal).then(iterator => {
|
|
405
414
|
if (iterator === undefined)
|
|
406
|
-
throw new TypeError("
|
|
415
|
+
throw new TypeError("Value does not provide an iterator protocol.");
|
|
407
416
|
return resolved = iterator;
|
|
408
417
|
});
|
|
409
418
|
return {
|
|
@@ -8,6 +8,8 @@ import { isSandboxDate } from "./date.js";
|
|
|
8
8
|
import { retainedAccessorClosures } from "./accessors.js";
|
|
9
9
|
import { getHostObjectMember, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
10
10
|
import { errorPrototypes } from "./error-prototypes.js";
|
|
11
|
+
import { float32Properties, isFloat32Array, isFloat32Index } from "./float32.js";
|
|
12
|
+
import { float32Prototypes } from "./float32-prototypes.js";
|
|
11
13
|
import { sandboxErrorTypes } from "../error/shape.js";
|
|
12
14
|
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
13
15
|
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, getPromiseProperties, isSandboxRegex, getRegexProperties, getCollectionProperties, isSandboxSet } from "./values.js";
|
|
@@ -276,12 +278,15 @@ export function releaseObjectPrototype(budget) {
|
|
|
276
278
|
functionPrototypes.delete(budget);
|
|
277
279
|
generatorPrototypes.delete(budget);
|
|
278
280
|
errorPrototypes.delete(budget);
|
|
281
|
+
float32Prototypes.delete(budget);
|
|
279
282
|
initialRegexDescriptors.delete(budget);
|
|
280
283
|
intrinsicPrototypes.delete(budget);
|
|
281
284
|
}
|
|
282
285
|
export function getSandboxPrototype(value, budget) {
|
|
283
286
|
if (prototypes.has(value))
|
|
284
287
|
return prototypes.get(value) ?? null;
|
|
288
|
+
if (isFloat32Array(value))
|
|
289
|
+
return budget === undefined ? null : float32Prototypes.get(budget) ?? null;
|
|
285
290
|
// Host transport records are data-only. Resolve their default prototype in
|
|
286
291
|
// the receiving realm without persisting executable intrinsic graphs.
|
|
287
292
|
const errorType = sandboxErrorTypes.get(value);
|
|
@@ -328,6 +333,10 @@ export function getSandboxPropertyDescriptor(value, key, budget) {
|
|
|
328
333
|
while (typeof current === "object" &&
|
|
329
334
|
current !== null &&
|
|
330
335
|
(Array.isArray(current) || isSandboxGenerator(current) || isSandboxDate(current) || isSandboxPromise(current) || isSandboxRegex(current) || isSandboxMap(current) || isSandboxSet(current) || isPrototypeRecord(current))) {
|
|
336
|
+
// An integer-indexed object stops numeric-key lookup even when it occurs
|
|
337
|
+
// inside another object's prototype chain and the index is invalid.
|
|
338
|
+
if (isFloat32Array(current) && typeof key !== "symbol" && isFloat32Index(String(key)))
|
|
339
|
+
return Object.getOwnPropertyDescriptor(current, key);
|
|
331
340
|
const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current)
|
|
332
341
|
? key === "prototype" && current.construct !== undefined && current.boundTarget === undefined
|
|
333
342
|
? materializeFunctionProperties(current) : getGuestFunctionProperties(current)
|
|
@@ -350,6 +359,8 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
350
359
|
let current = value;
|
|
351
360
|
let depth = 0;
|
|
352
361
|
while (typeof current === "object" && current !== null) {
|
|
362
|
+
if (isFloat32Array(current) && typeof key !== "symbol" && isFloat32Index(String(key)))
|
|
363
|
+
return Object.getOwnPropertyDescriptor(current, key)?.value;
|
|
353
364
|
if (isGuestHostObject(current))
|
|
354
365
|
return typeof key === "symbol" ? undefined : getHostObjectMember(current, String(key));
|
|
355
366
|
if (isSandboxRegex(current))
|
|
@@ -416,6 +427,8 @@ export function setSandboxPrototype(value, prototype, budget) {
|
|
|
416
427
|
prototypes.set(value, prototype);
|
|
417
428
|
}
|
|
418
429
|
function isPrototypeRecord(value) {
|
|
430
|
+
if (isFloat32Array(value))
|
|
431
|
+
return true;
|
|
419
432
|
if (isGuestClosure(value))
|
|
420
433
|
return true;
|
|
421
434
|
if (isGuestHostObject(value))
|
|
@@ -447,5 +460,7 @@ export function hasGuestObjectState(value) {
|
|
|
447
460
|
if (isSandboxBox(value) || isSandboxDate(value))
|
|
448
461
|
return false;
|
|
449
462
|
return (descriptorObjects.has(value) &&
|
|
450
|
-
|
|
463
|
+
(isFloat32Array(value)
|
|
464
|
+
? float32Properties(value).map(([, descriptor]) => descriptor)
|
|
465
|
+
: Object.values(Object.getOwnPropertyDescriptors(value))).some((descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable));
|
|
451
466
|
}
|
|
@@ -17,7 +17,7 @@ import { boxedDataProperties, boxedValue, createSandboxBox, isSandboxBox, native
|
|
|
17
17
|
import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
18
18
|
import { types as nodeTypes } from "node:util";
|
|
19
19
|
import { CompileScope, RegexCompileGuard, regexCompiledData } from "./regex/compile-guard.js";
|
|
20
|
-
import { copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
20
|
+
import { copyFloat32Storage, float32DataProperties, float32Properties, float32Storage, isFloat32Array } from "./float32.js";
|
|
21
21
|
import { SandboxError } from "./budget.js";
|
|
22
22
|
import { observeSandboxPromise, trackSandboxPromise } from "./promise-tracker.js";
|
|
23
23
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
@@ -405,9 +405,17 @@ export function measureSandboxData(values, options = {}) {
|
|
|
405
405
|
seen.add(storage.buffer);
|
|
406
406
|
usage += storage.byteLength;
|
|
407
407
|
}
|
|
408
|
-
for (const [key, descriptor] of
|
|
409
|
-
usage +=
|
|
410
|
-
|
|
408
|
+
for (const [key, descriptor] of float32Properties(value)) {
|
|
409
|
+
usage += 1;
|
|
410
|
+
if (typeof key === "string")
|
|
411
|
+
usage += key.length;
|
|
412
|
+
else
|
|
413
|
+
visit(key, depth + 1);
|
|
414
|
+
if ("value" in descriptor)
|
|
415
|
+
visit(descriptor.value, depth + 1);
|
|
416
|
+
else
|
|
417
|
+
for (const closure of retainedAccessorClosures(descriptor))
|
|
418
|
+
visit(closure, depth + 1);
|
|
411
419
|
}
|
|
412
420
|
return;
|
|
413
421
|
}
|
|
@@ -2709,6 +2709,7 @@ class Parser {
|
|
|
2709
2709
|
return undefined;
|
|
2710
2710
|
}
|
|
2711
2711
|
findTopLevelForIterationOperator(startIndex) {
|
|
2712
|
+
let operator;
|
|
2712
2713
|
let depth = 0;
|
|
2713
2714
|
let previousToken;
|
|
2714
2715
|
for (let index = startIndex; index < this.tokens.length; index += 1) {
|
|
@@ -2719,7 +2720,7 @@ class Parser {
|
|
|
2719
2720
|
}
|
|
2720
2721
|
else if (token.value === ")" || token.value === "]" || token.value === "}") {
|
|
2721
2722
|
if (depth === 0 && token.value === ")") {
|
|
2722
|
-
return
|
|
2723
|
+
return operator;
|
|
2723
2724
|
}
|
|
2724
2725
|
depth -= 1;
|
|
2725
2726
|
}
|
|
@@ -2730,9 +2731,12 @@ class Parser {
|
|
|
2730
2731
|
if (depth === 0 &&
|
|
2731
2732
|
token.type === "keyword" &&
|
|
2732
2733
|
(token.value === "of" || token.value === "in") &&
|
|
2734
|
+
index !== startIndex &&
|
|
2735
|
+
!(token.value === "of" && index === startIndex + 1 &&
|
|
2736
|
+
["const", "let", "var"].includes(previousToken?.value ?? "")) &&
|
|
2733
2737
|
previousToken?.value !== "." &&
|
|
2734
2738
|
previousToken?.value !== "?.") {
|
|
2735
|
-
|
|
2739
|
+
operator ??= token;
|
|
2736
2740
|
}
|
|
2737
2741
|
previousToken = token;
|
|
2738
2742
|
}
|
|
@@ -3752,7 +3756,8 @@ function isLiteralPropertyKey(token) {
|
|
|
3752
3756
|
return token.type === "numeric" || token.type === "string";
|
|
3753
3757
|
}
|
|
3754
3758
|
function isIdentifierLikeToken(token) {
|
|
3755
|
-
return token.type === "identifier" ||
|
|
3759
|
+
return token.type === "identifier" ||
|
|
3760
|
+
(token.type === "keyword" && (token.value === "async" || token.value === "of"));
|
|
3756
3761
|
}
|
|
3757
3762
|
function isNewToken(token) {
|
|
3758
3763
|
return token.value === "new";
|
|
@@ -358,7 +358,7 @@ class Lexer {
|
|
|
358
358
|
}
|
|
359
359
|
if (char === "/" &&
|
|
360
360
|
this.peekChar(1) !== "=" &&
|
|
361
|
-
shouldRejectRegexLiteral(tokens[tokens.length - 1], lastClosedControlParenthesis)) {
|
|
361
|
+
shouldRejectRegexLiteral(tokens[tokens.length - 1], lastClosedControlParenthesis, tokens)) {
|
|
362
362
|
if (!this.options.allowRegexLiterals) {
|
|
363
363
|
this.syntaxError("Regular expression literals are not supported", this.position());
|
|
364
364
|
}
|
|
@@ -633,7 +633,7 @@ class Lexer {
|
|
|
633
633
|
readSlashOrPunctuator(start) {
|
|
634
634
|
if (this.currentChar() === "/" &&
|
|
635
635
|
this.peekChar(1) !== "=" &&
|
|
636
|
-
shouldRejectRegexLiteral(this.lastSignificantToken(), this.lastClosedControlParenthesis)) {
|
|
636
|
+
shouldRejectRegexLiteral(this.lastSignificantToken(), this.lastClosedControlParenthesis, this.tokens)) {
|
|
637
637
|
if (!this.options.allowRegexLiterals) {
|
|
638
638
|
this.syntaxError("Regular expression literals are not supported", start);
|
|
639
639
|
}
|
|
@@ -919,7 +919,7 @@ function matchPunctuator(source, index) {
|
|
|
919
919
|
return PUNCTUATORS.find((punctuator) => source.startsWith(punctuator, index) &&
|
|
920
920
|
(punctuator !== "?." || !isDecimalDigit(source[index + 2] ?? "")));
|
|
921
921
|
}
|
|
922
|
-
function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
922
|
+
function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis, tokens) {
|
|
923
923
|
if (previousToken === undefined) {
|
|
924
924
|
return true;
|
|
925
925
|
}
|
|
@@ -930,6 +930,8 @@ function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
|
930
930
|
return false;
|
|
931
931
|
}
|
|
932
932
|
if (previousToken.type === "keyword") {
|
|
933
|
+
if (previousToken.value === "of")
|
|
934
|
+
return endsWithForOfSeparator(tokens);
|
|
933
935
|
return !EXPRESSION_ENDING_KEYWORDS.has(previousToken.value);
|
|
934
936
|
}
|
|
935
937
|
if (previousToken.value === ")") {
|
|
@@ -937,6 +939,46 @@ function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
|
937
939
|
}
|
|
938
940
|
return !isExpressionEndingPunctuator(previousToken.value);
|
|
939
941
|
}
|
|
942
|
+
function endsWithForOfSeparator(tokens) {
|
|
943
|
+
let depth = 0;
|
|
944
|
+
let start = -1;
|
|
945
|
+
for (let index = tokens.length - 2; index >= 0; index--) {
|
|
946
|
+
const token = tokens[index];
|
|
947
|
+
if (token.type !== "punctuator")
|
|
948
|
+
continue;
|
|
949
|
+
if ([")", "]", "}"].includes(token.value))
|
|
950
|
+
depth++;
|
|
951
|
+
else if (["(", "[", "{"].includes(token.value)) {
|
|
952
|
+
if (depth > 0) {
|
|
953
|
+
depth--;
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
if (token.value === "(" && (tokens[index - 1]?.value === "for" ||
|
|
957
|
+
(tokens[index - 1]?.value === "await" && tokens[index - 2]?.value === "for")))
|
|
958
|
+
start = index + 1;
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
else if (depth === 0 && token.value === ";")
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
if (start < 0)
|
|
965
|
+
return false;
|
|
966
|
+
depth = 0;
|
|
967
|
+
for (let index = start; index < tokens.length; index++) {
|
|
968
|
+
const token = tokens[index];
|
|
969
|
+
if (token.type === "punctuator") {
|
|
970
|
+
if (["(", "[", "{"].includes(token.value))
|
|
971
|
+
depth++;
|
|
972
|
+
else if ([")", "]", "}"].includes(token.value))
|
|
973
|
+
depth--;
|
|
974
|
+
}
|
|
975
|
+
if (depth === 0 && token.type === "keyword" && token.value === "of" &&
|
|
976
|
+
index !== start && tokens[index - 1]?.value !== "." && tokens[index - 1]?.value !== "?." &&
|
|
977
|
+
!(index === start + 1 && ["const", "let", "var"].includes(tokens[start].value)))
|
|
978
|
+
return index === tokens.length - 1;
|
|
979
|
+
}
|
|
980
|
+
return false;
|
|
981
|
+
}
|
|
940
982
|
function updateGroupingState(groupingStack, previousToken, punctuator) {
|
|
941
983
|
if (punctuator === "(") {
|
|
942
984
|
groupingStack.push({
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { GuestObjectState } from "./guest-heap.js";
|
|
2
|
+
export declare function captureFloat32State<T>(value: Float32Array, encode: (value: unknown) => T): GuestObjectState<T>;
|
|
3
|
+
export declare function restoreFloat32Properties<T>(value: Float32Array, state: GuestObjectState<T>, decode: (value: T) => unknown): void;
|
|
1
4
|
export type Float32Data<TReference> = {
|
|
2
5
|
kind: "float32array";
|
|
3
6
|
byteOffset: number;
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import { float32Storage, isFloat32Array } from "../interp/float32.js";
|
|
1
|
+
import { float32Properties, float32Storage, isFloat32Array, isFloat32Index } from "../interp/float32.js";
|
|
2
|
+
import { getSandboxPrototype, hasExplicitSandboxPrototype } from "../interp/object-model.js";
|
|
3
|
+
import { restorePropertyDescriptors, serializePropertyDescriptors } from "./property-descriptors.js";
|
|
4
|
+
export function captureFloat32State(value, encode) {
|
|
5
|
+
const metadata = Object.defineProperties(Object.create(null), Object.fromEntries(float32Properties(value)));
|
|
6
|
+
if (!Object.isExtensible(value))
|
|
7
|
+
Object.preventExtensions(metadata);
|
|
8
|
+
return { properties: serializePropertyDescriptors(metadata, encode),
|
|
9
|
+
...(hasExplicitSandboxPrototype(value) ? { prototype: encode(getSandboxPrototype(value)) } : {}) };
|
|
10
|
+
}
|
|
11
|
+
export function restoreFloat32Properties(value, state, decode) {
|
|
12
|
+
const metadata = Object.create(null);
|
|
13
|
+
restorePropertyDescriptors(metadata, state.properties, decode);
|
|
14
|
+
const descriptors = Object.getOwnPropertyDescriptors(metadata);
|
|
15
|
+
if (Object.keys(descriptors).some(isFloat32Index))
|
|
16
|
+
throw new TypeError("Float32Array metadata cannot replace numeric storage.");
|
|
17
|
+
Object.defineProperties(value, descriptors);
|
|
18
|
+
if (!Object.isExtensible(metadata))
|
|
19
|
+
Object.preventExtensions(value);
|
|
20
|
+
}
|
|
2
21
|
export function encodeFloat32Storage(value, id, buffers, reference) {
|
|
3
22
|
const storage = float32Storage(value);
|
|
4
23
|
const existing = buffers.get(storage.buffer);
|
|
@@ -17,7 +17,7 @@ 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
21
|
import { restoreDateTime } from "../interp/date.js";
|
|
22
22
|
import { createRawJson } from "../interp/raw-json.js";
|
|
23
23
|
import { createSandboxBox } from "../interp/boxed.js";
|
|
@@ -411,7 +411,11 @@ function initializeIntrinsicRealm(state) {
|
|
|
411
411
|
return prototype?.kind === "intrinsic" &&
|
|
412
412
|
prototype.id === JSON.stringify([...JSON.parse(node.id), "prototype"]);
|
|
413
413
|
}));
|
|
414
|
-
|
|
414
|
+
const float32 = Object.values(state.heap).find(node => node.kind === "intrinsic" && node.id === '["Float32Array"]');
|
|
415
|
+
const float32Prototypes = float32?.kind !== "intrinsic" ||
|
|
416
|
+
float32.state?.properties.properties.some(([key, descriptor]) => key === "prototype" && descriptor.kind === "data" &&
|
|
417
|
+
!descriptor.writable && !descriptor.enumerable && !descriptor.configurable) === true;
|
|
418
|
+
createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes, float32Prototypes });
|
|
415
419
|
state.intrinsicsInitialized = true;
|
|
416
420
|
}
|
|
417
421
|
function restoreHeapValue(id, state) {
|
|
@@ -453,8 +457,19 @@ function restoreHeapValue(id, state) {
|
|
|
453
457
|
return value;
|
|
454
458
|
}
|
|
455
459
|
if (serialized.kind === "float32array") {
|
|
460
|
+
if (serialized.state !== undefined)
|
|
461
|
+
initializeIntrinsicRealm(state);
|
|
456
462
|
const value = decodeFloat32Storage(serialized, (reference) => deserializeValue(reference, state));
|
|
457
463
|
state.heapValueById.set(id, value);
|
|
464
|
+
if (serialized.state !== undefined) {
|
|
465
|
+
const objectState = serialized.state;
|
|
466
|
+
state.initializeIterators.push(() => {
|
|
467
|
+
if (objectState.prototype !== undefined)
|
|
468
|
+
setSandboxPrototype(value, deserializeValue(objectState.prototype, state), state.budget);
|
|
469
|
+
restoreFloat32Properties(value, objectState, entry => deserializeValue(entry, state));
|
|
470
|
+
});
|
|
471
|
+
return value;
|
|
472
|
+
}
|
|
458
473
|
for (const [key, entry] of Object.entries(serialized.entries)) {
|
|
459
474
|
Object.defineProperty(value, key, {
|
|
460
475
|
value: deserializeValue(entry, state),
|
|
@@ -4,7 +4,7 @@ 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";
|
|
@@ -75,6 +75,7 @@ export type SerializedHeapValue = GuestHeapNode<SerializedSnapshotValue> | {
|
|
|
75
75
|
entries: Record<string, SerializedSnapshotValue>;
|
|
76
76
|
} | SerializedDate<SerializedSnapshotValue> | (Float32Data<SerializedReferenceValue> & {
|
|
77
77
|
entries: Record<string, SerializedSnapshotValue>;
|
|
78
|
+
state?: GuestObjectState<SerializedSnapshotValue>;
|
|
78
79
|
}) | SerializedArguments<SerializedSnapshotValue> | SerializedArray<SerializedSnapshotValue> | {
|
|
79
80
|
kind: "object";
|
|
80
81
|
sandboxNullPrototype?: true;
|
|
@@ -11,8 +11,8 @@ 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 { encodeFloat32Storage } from "./float32array.js";
|
|
14
|
+
import { isFloat32Array } from "../interp/float32.js";
|
|
15
|
+
import { captureFloat32State, encodeFloat32Storage } from "./float32array.js";
|
|
16
16
|
import { dateDataProperties, isSandboxDate } from "../interp/date.js";
|
|
17
17
|
import { serializeDate } from "./date-properties.js";
|
|
18
18
|
import { boxedDataProperties, isSandboxBox } from "../interp/boxed.js";
|
|
@@ -104,7 +104,7 @@ function serializeValue(value, path, state) {
|
|
|
104
104
|
}
|
|
105
105
|
return { kind: "ref", id };
|
|
106
106
|
}
|
|
107
|
-
if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value)) {
|
|
107
|
+
if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isFloat32Array(value)) {
|
|
108
108
|
throw new TypeError("Guest function properties and prototype links cannot be serialized.");
|
|
109
109
|
}
|
|
110
110
|
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
@@ -265,10 +265,8 @@ function serializeHeapReference(value, path, state) {
|
|
|
265
265
|
kind: "ref",
|
|
266
266
|
id
|
|
267
267
|
}));
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
for (const [key, descriptor] of float32DataProperties(value))
|
|
271
|
-
entries[key] = serializeValue(descriptor.value, `${path}.${key}`, state);
|
|
268
|
+
state.heap[String(id)] = { ...storage, entries: {},
|
|
269
|
+
state: captureFloat32State(value, entry => serializeValue(entry, `${path}.<typed-array>`, state)) };
|
|
272
270
|
}
|
|
273
271
|
else if (isSandboxArguments(value)) {
|
|
274
272
|
state.heap[String(id)] = serializeArguments(value, (entry, key) => serializeValue(entry, `${path}.${key}`, state));
|
|
@@ -431,9 +429,12 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
|
|
|
431
429
|
stat.expanded = true;
|
|
432
430
|
ancestors.add(value);
|
|
433
431
|
const guestEntries = [];
|
|
434
|
-
const guest =
|
|
432
|
+
const guest = isFloat32Array(value)
|
|
433
|
+
? { kind: "float32array", state: captureFloat32State(value, entry => { guestEntries.push(entry); return null; }) }
|
|
434
|
+
: captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
|
|
435
435
|
if (guest !== undefined) {
|
|
436
|
-
|
|
436
|
+
if (!isFloat32Array(value))
|
|
437
|
+
guestValues.add(value);
|
|
437
438
|
for (const entry of guestEntries) {
|
|
438
439
|
collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
|
|
439
440
|
if (entry !== null && typeof entry === "object") {
|
|
@@ -120,6 +120,11 @@ function validateDumpHeap(root, state) {
|
|
|
120
120
|
if (entry.kind === "float32array") {
|
|
121
121
|
validateFloat32Storage(entry);
|
|
122
122
|
requireRecord(entry.entries, `${path}.entries`);
|
|
123
|
+
if (Object.hasOwn(entry, "state")) {
|
|
124
|
+
if (Object.keys(entry.entries).length !== 0)
|
|
125
|
+
fail("invalidValue", path, "ambiguous Float32Array property state");
|
|
126
|
+
validateGuestHeapNode({ kind: "guest-object", state: entry.state }, heap, state.limits.maxEntries);
|
|
127
|
+
}
|
|
123
128
|
continue;
|
|
124
129
|
}
|
|
125
130
|
if (entry.kind === "arguments") {
|
|
@@ -551,6 +556,11 @@ function validateHeapValue(value, path, state, heap) {
|
|
|
551
556
|
if (record.kind === "float32array") {
|
|
552
557
|
validateFloat32Storage(record);
|
|
553
558
|
requireRecord(record.entries, `${path}.entries`);
|
|
559
|
+
if (Object.hasOwn(record, "state")) {
|
|
560
|
+
if (Object.keys(record.entries).length !== 0)
|
|
561
|
+
fail("invalidValue", path, "ambiguous Float32Array property state");
|
|
562
|
+
validateGuestHeapNode({ kind: "guest-object", state: record.state }, heap, state.limits.maxEntries);
|
|
563
|
+
}
|
|
554
564
|
}
|
|
555
565
|
if (record.kind === "map") {
|
|
556
566
|
const entries = requireArray(record.entries, `${path}.entries`, state);
|