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.
Files changed (34) hide show
  1. package/dist/index.js +543 -156
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js → chunk-37V6Q4K3.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-PT7PBLVT.js} +457 -91
  7. package/packages/safe-js/dist/chunks/chunk-PT7PBLVT.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/interp/float32-prototypes.d.ts +3 -0
  12. package/packages/safe-js/dist/interp/float32-prototypes.js +1 -0
  13. package/packages/safe-js/dist/interp/float32.d.ts +1 -0
  14. package/packages/safe-js/dist/interp/float32.js +12 -4
  15. package/packages/safe-js/dist/interp/globals/float32array.d.ts +3 -2
  16. package/packages/safe-js/dist/interp/globals/float32array.js +371 -65
  17. package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
  18. package/packages/safe-js/dist/interp/globals.d.ts +1 -0
  19. package/packages/safe-js/dist/interp/globals.js +4 -2
  20. package/packages/safe-js/dist/interp/instanceof.js +1 -1
  21. package/packages/safe-js/dist/interp/interpreter.js +2 -4
  22. package/packages/safe-js/dist/interp/iteration.js +15 -6
  23. package/packages/safe-js/dist/interp/object-model.js +16 -1
  24. package/packages/safe-js/dist/interp/values.js +12 -4
  25. package/packages/safe-js/dist/parse/parser.js +8 -3
  26. package/packages/safe-js/dist/parse/tokenizer.js +45 -3
  27. package/packages/safe-js/dist/snapshot/float32array.d.ts +3 -0
  28. package/packages/safe-js/dist/snapshot/float32array.js +20 -1
  29. package/packages/safe-js/dist/snapshot/restore.js +17 -2
  30. package/packages/safe-js/dist/snapshot/serialize.d.ts +2 -1
  31. package/packages/safe-js/dist/snapshot/serialize.js +10 -9
  32. package/packages/safe-js/dist/snapshot/validation.js +10 -0
  33. package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
  34. /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, getFloat32Member(member.object, member.property, context.budget), context, member.object);
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
- if (typeof property === "symbol")
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
- ? generatorProtocolAdapter(value, budget, context, true, signal) : undefined
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
- ? generatorProtocolAdapter(value, budget ?? new Budget(), context, false) : undefined;
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 generatorProtocolAdapter(value, budget, context, asyncProtocol, signal) {
390
- // Direct host adapters still need guest property reads, receiver binding and
391
- // cached next methods, but retain their asynchronous generator result channel.
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("Generator does not provide an iterator protocol.");
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
- Object.values(Object.getOwnPropertyDescriptors(value)).some((descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable));
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 float32DataProperties(value)) {
409
- usage += key.length + 1;
410
- visit(descriptor.value, depth + 1);
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 undefined;
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
- return token;
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" || (token.type === "keyword" && token.value === "async");
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
- createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes });
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 { float32DataProperties, isFloat32Array } from "../interp/float32.js";
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
- 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);
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 = captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
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
- guestValues.add(value);
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);