poe-code 14.0.79 → 14.0.81

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 (47) hide show
  1. package/dist/index.js +772 -341
  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-B3AL4KJ3.js → chunk-2LNBLFJ3.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-BGSPSHLP.js → chunk-ZSYBRZU6.js} +644 -292
  7. package/packages/safe-js/dist/chunks/chunk-ZSYBRZU6.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/graph-depth.js +2 -1
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/async.d.ts +1 -1
  13. package/packages/safe-js/dist/interp/async.js +65 -43
  14. package/packages/safe-js/dist/interp/bound-function-state.d.ts +7 -0
  15. package/packages/safe-js/dist/interp/bound-function-state.js +1 -0
  16. package/packages/safe-js/dist/interp/bound-function.d.ts +4 -0
  17. package/packages/safe-js/dist/interp/bound-function.js +18 -0
  18. package/packages/safe-js/dist/interp/generator-properties.d.ts +3 -0
  19. package/packages/safe-js/dist/interp/generator-properties.js +9 -0
  20. package/packages/safe-js/dist/interp/generator-prototypes.d.ts +6 -0
  21. package/packages/safe-js/dist/interp/generator-prototypes.js +1 -0
  22. package/packages/safe-js/dist/interp/globals/function.d.ts +2 -0
  23. package/packages/safe-js/dist/interp/globals/function.js +32 -0
  24. package/packages/safe-js/dist/interp/globals/generator.d.ts +2 -0
  25. package/packages/safe-js/dist/interp/globals/generator.js +51 -0
  26. package/packages/safe-js/dist/interp/globals/object-array.js +28 -7
  27. package/packages/safe-js/dist/interp/globals/object.js +2 -1
  28. package/packages/safe-js/dist/interp/globals.d.ts +1 -0
  29. package/packages/safe-js/dist/interp/globals.js +4 -0
  30. package/packages/safe-js/dist/interp/instanceof.d.ts +4 -0
  31. package/packages/safe-js/dist/interp/instanceof.js +58 -0
  32. package/packages/safe-js/dist/interp/interpreter.js +16 -47
  33. package/packages/safe-js/dist/interp/iteration.js +76 -5
  34. package/packages/safe-js/dist/interp/methods/function.d.ts +5 -2
  35. package/packages/safe-js/dist/interp/methods/function.js +55 -42
  36. package/packages/safe-js/dist/interp/methods/generator.d.ts +4 -1
  37. package/packages/safe-js/dist/interp/methods/generator.js +12 -6
  38. package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
  39. package/packages/safe-js/dist/interp/object-model.js +69 -17
  40. package/packages/safe-js/dist/interp/string-coercion.js +3 -2
  41. package/packages/safe-js/dist/interp/values.js +21 -3
  42. package/packages/safe-js/dist/snapshot/guest-heap-validation.js +27 -3
  43. package/packages/safe-js/dist/snapshot/guest-heap.d.ts +9 -0
  44. package/packages/safe-js/dist/snapshot/guest-heap.js +11 -0
  45. package/packages/safe-js/dist/snapshot/restore.js +61 -7
  46. package/packages/safe-js/dist/chunks/chunk-BGSPSHLP.js.map +0 -7
  47. /package/packages/safe-js/dist/chunks/{chunk-B3AL4KJ3.js.map → chunk-2LNBLFJ3.js.map} +0 -0
@@ -29,17 +29,18 @@ import { getPromiseMember } from "./promise.js";
29
29
  import { acquireSandboxIterator, closeIterator, readIteratorResult, restoreSandboxIterator } from "./iteration.js";
30
30
  import { assertCollectionMutable } from "./running-state.js";
31
31
  import { getGeneratorMember } from "./methods/generator.js";
32
+ import { getGeneratorProperties } from "./generator-properties.js";
32
33
  import { getRegexMember, setRegexMember } from "./methods/regex.js";
33
34
  import { bindPattern } from "./patterns.js";
34
35
  import { callStringMethod, getStringMember, isStringMethodName, validateStringMethodArguments } from "./methods/string.js";
35
36
  import { callSetMethod, getSetMember, isSetMethodName } from "./methods/set.js";
36
- import { isSandboxErrorConstructorInstance } from "./globals/error.js";
37
+ import { evaluateInstanceof } from "./instanceof.js";
37
38
  import { hasOwnSandboxProperty } from "./globals/object.js";
38
39
  import { collectionIteratorState, isSandboxCollectionIterator } from "./collection-iterator.js";
39
40
  import { getCollectionIteratorMember } from "./methods/collection-iterator.js";
40
41
  import { isSandboxRegExpIterator, regexpIteratorState } from "./regexp-iterator.js";
41
42
  import { getRegExpIteratorMember } from "./methods/regexp-iterator.js";
42
- import { getFloat32Member, isFloat32ArrayConstructor, setFloat32Member } from "./globals/float32array.js";
43
+ import { getFloat32Member, setFloat32Member } from "./globals/float32array.js";
43
44
  import { isFloat32Array } from "./float32.js";
44
45
  import { dateString, dateTime, isSandboxDate } from "./date.js";
45
46
  import { createSandboxRegex, allocateProducedSandboxValue, ownEnumerableSandboxKeys, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, getPromiseProperties, isSandboxRegex, getRegexProperties, getCollectionProperties, isSandboxSet, reconcileCompiledValues } from "./values.js";
@@ -1494,7 +1495,7 @@ function forInKeys(object, budget) {
1494
1495
  if (depth > 0)
1495
1496
  budget.visitNode();
1496
1497
  assertSandboxDataDepth(depth++);
1497
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1498
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1498
1499
  for (const key of Object.getOwnPropertyNames(properties)) {
1499
1500
  if (seen.has(key))
1500
1501
  continue;
@@ -1515,7 +1516,7 @@ function hasForInProperty(object, key, budget) {
1515
1516
  if (depth > 0)
1516
1517
  budget.visitNode();
1517
1518
  assertSandboxDataDepth(depth++);
1518
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1519
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1519
1520
  if (Object.hasOwn(properties, key))
1520
1521
  return true;
1521
1522
  }
@@ -2097,7 +2098,8 @@ function getPropertyValue(target, property, context, receiver = target) {
2097
2098
  if (isSandboxCollectionIterator(target))
2098
2099
  return getCollectionIteratorMember(target, property, context.budget);
2099
2100
  if (isSandboxGenerator(target))
2100
- return getGeneratorMember(target, property, context.budget);
2101
+ return hasExplicitSandboxPrototype(target)
2102
+ ? undefined : getGeneratorMember(target, property, context.budget);
2101
2103
  if (isSandboxClosure(target))
2102
2104
  return getClosureMemberValue(target, property, context);
2103
2105
  if (isSandboxPromise(target))
@@ -2384,7 +2386,7 @@ async function evaluateMemberCallExpression(node, context) {
2384
2386
  return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
2385
2387
  }
2386
2388
  if (isSandboxGenerator(member.object)) {
2387
- const memberValue = getGeneratorMember(member.object, member.property, context.budget);
2389
+ const memberValue = await getPropertyValue(member.object, member.property, context);
2388
2390
  if (memberValue === undefined) {
2389
2391
  throw new TypeError(`Generator#${String(member.property)} is not a supported method.`);
2390
2392
  }
@@ -2602,48 +2604,11 @@ function applyBinaryOperator(node, left, right, context) {
2602
2604
  case ">>>":
2603
2605
  return toNumber(left) >>> toNumber(right);
2604
2606
  case "instanceof":
2605
- return evaluateInstanceof(left, right, context);
2607
+ return evaluateInstanceof(left, right, context.budget, createCoercionContext(context));
2606
2608
  case "in":
2607
2609
  return hasSandboxProperty(right, left, context);
2608
2610
  }
2609
2611
  }
2610
- async function evaluateInstanceof(left, right, context) {
2611
- while (true) {
2612
- if (right === null || (typeof right !== "object" && typeof right !== "function"))
2613
- throw new TypeError("Right-hand side of 'instanceof' must be an object.");
2614
- const method = await getPropertyValue(right, Symbol.hasInstance, context);
2615
- if (method !== undefined && method !== null) {
2616
- if (!isSandboxClosure(method))
2617
- throw new TypeError("Symbol.hasInstance must be callable.");
2618
- return Boolean(await invokeSandboxClosure(method, [left], context, context.callStack, undefined, right));
2619
- }
2620
- if (!isSandboxClosure(right))
2621
- throw new TypeError("Right-hand side of 'instanceof' is not a function.");
2622
- if (right.boundTarget === undefined)
2623
- break;
2624
- context.budget.visitNode();
2625
- right = right.boundTarget;
2626
- }
2627
- if (isFloat32ArrayConstructor(right))
2628
- return isFloat32Array(left);
2629
- if (isSandboxErrorConstructorInstance(left, right))
2630
- return true;
2631
- if (isGuestClosure(right)) {
2632
- if (typeof left !== "object" || left === null)
2633
- return false;
2634
- const prototype = await getPropertyValue(right, "prototype", context);
2635
- if (typeof prototype !== "object" || prototype === null)
2636
- throw new TypeError("Function has a non-object prototype in instanceof check.");
2637
- let depth = 0;
2638
- for (let current = getSandboxPrototype(left, context.budget); current !== null; current = getSandboxPrototype(current, context.budget)) {
2639
- context.budget.visitNode();
2640
- assertSandboxDataDepth(depth++);
2641
- if (current === prototype)
2642
- return true;
2643
- }
2644
- }
2645
- return false;
2646
- }
2647
2612
  export function createCoercionContext(context) {
2648
2613
  return {
2649
2614
  stack: context.callStack,
@@ -2662,7 +2627,7 @@ function hasSandboxProperty(value, key, context) {
2662
2627
  return typeof key === "symbol" ? false : hasHostObjectMember(current, String(key));
2663
2628
  if (hasOwnSandboxProperty(current, key, false))
2664
2629
  return true;
2665
- if (!isSandboxDate(current) && !isSandboxRegex(current) && !isSandboxMap(current) && !isSandboxSet(current) && !((isGuestClosure(current) || Array.isArray(current)) && hasExplicitSandboxPrototype(current)) &&
2630
+ if (!isSandboxDate(current) && !isSandboxRegex(current) && !isSandboxMap(current) && !isSandboxSet(current) && !((isGuestClosure(current) || isSandboxGenerator(current) || Array.isArray(current)) && hasExplicitSandboxPrototype(current)) &&
2666
2631
  (Array.isArray(current) || !isPlainSandboxObject(current) ||
2667
2632
  isSandboxDate(current) || isFloat32Array(current) || isSandboxGenerator(current) || isSandboxCollectionIterator(current) || isSandboxRegExpIterator(current))) {
2668
2633
  return getPropertyValue(current, key, context) !== undefined;
@@ -2941,6 +2906,8 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
2941
2906
  target = materializeFunctionProperties(target);
2942
2907
  if (isSandboxPromise(target))
2943
2908
  target = getPromiseProperties(target);
2909
+ if (isSandboxGenerator(target))
2910
+ target = getGeneratorProperties(target);
2944
2911
  if (isSandboxMap(target) || isSandboxSet(target))
2945
2912
  target = getCollectionProperties(target);
2946
2913
  if (isFloat32Array(target)) {
@@ -2977,7 +2944,7 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
2977
2944
  for (let prototype = getSandboxPrototype(prototypeOwner, budget); prototype !== null; prototype = getSandboxPrototype(prototype, budget)) {
2978
2945
  budget.visitNode();
2979
2946
  assertSandboxDataDepth(depth++);
2980
- const properties = isSandboxClosure(prototype) ? prototype.properties : prototype;
2947
+ const properties = isSandboxGenerator(prototype) ? getGeneratorProperties(prototype) : isSandboxClosure(prototype) ? prototype.properties : prototype;
2981
2948
  const inherited = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
2982
2949
  if (inherited === undefined)
2983
2950
  continue;
@@ -2997,7 +2964,7 @@ function setSuperProperty(base, receiver, key, value, context) {
2997
2964
  for (let current = base; current !== null; current = getSandboxPrototype(current, budget)) {
2998
2965
  budget.visitNode();
2999
2966
  assertSandboxDataDepth(depth++);
3000
- const properties = isSandboxClosure(current) ? current.properties : current;
2967
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxClosure(current) ? current.properties : current;
3001
2968
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
3002
2969
  if (descriptor === undefined)
3003
2970
  continue;
@@ -3020,6 +2987,8 @@ export function deleteSandboxProperty(target, property) {
3020
2987
  target = getRegexProperties(target);
3021
2988
  if (isSandboxPromise(target))
3022
2989
  target = getPromiseProperties(target);
2990
+ if (isSandboxGenerator(target))
2991
+ target = getGeneratorProperties(target);
3023
2992
  if (isSandboxMap(target) || isSandboxSet(target))
3024
2993
  target = getCollectionProperties(target);
3025
2994
  if (Array.isArray(target)) {
@@ -14,6 +14,7 @@ import { suspendJob } from "./jobs.js";
14
14
  import { invokeBuiltinClosure } from "./builtin-call.js";
15
15
  import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype } from "./object-model.js";
16
16
  import { getIntrinsicIdentity } from "./intrinsics.js";
17
+ import { readPropertyDescriptor } from "./accessors.js";
17
18
  export function mapIteratorSnapshot(snapshot, map) {
18
19
  if (snapshot.kind === "unsupported")
19
20
  throw new TypeError("Host-owned iterator cannot be portably snapshotted.");
@@ -31,8 +32,9 @@ export async function restoreSandboxIterator(snapshot, budget, context, signal)
31
32
  return asyncFromSyncIterator(await restoreSandboxIterator(snapshot.inner, budget, context, signal), budget, signal, context);
32
33
  if (Array.isArray(snapshot.value))
33
34
  return arrayIterator(snapshot.value, context, budget, snapshot.index);
34
- const iterator = isSandboxGenerator(snapshot.value) && snapshot.value.async
35
- ? getSandboxAsyncIterator(snapshot.value, budget, context, signal)
35
+ const iterator = isSandboxGenerator(snapshot.value)
36
+ ? { ...generatorObjectIterator(snapshot.value, budget, context),
37
+ ...(snapshot.value.async ? { asyncProtocol: true } : {}) }
36
38
  : getSandboxIterator(snapshot.value, budget, context);
37
39
  if (iterator === undefined)
38
40
  throw new TypeError("Invalid builtin iterator snapshot.");
@@ -49,11 +51,15 @@ export async function acquireSandboxIterator(value, budget, context, asyncProtoc
49
51
  : getSandboxIterator(value, budget, context);
50
52
  if (getSandboxPropertyDescriptor(value, key, budget) === undefined &&
51
53
  !(isSandboxRegExpIterator(value) && !asyncProtocol && getSandboxPropertyDescriptor(value, "next", budget) !== undefined)) {
54
+ if (isSandboxGenerator(value)) {
55
+ if (!hasExplicitSandboxPrototype(value) && (value.async === true) === asyncProtocol && getSandboxPropertyDescriptor(value, "next", budget) !== undefined)
56
+ return guestIterator(value, await context.getProperty(value, "next"), asyncProtocol, budget, context, signal);
57
+ }
52
58
  if (!asyncProtocol && Array.isArray(value) && getSandboxPrototype(value, budget) !== null)
53
59
  return undefined;
54
60
  if (!asyncProtocol)
55
61
  return getSandboxIterator(value, budget, context);
56
- if (isSandboxGenerator(value) && value.async)
62
+ if (isSandboxGenerator(value) && value.async && !hasExplicitSandboxPrototype(value))
57
63
  return getSandboxAsyncIterator(value, budget, context, signal);
58
64
  const iterator = await acquireSandboxIterator(value, budget, context);
59
65
  return iterator === undefined ? undefined : asyncFromSyncIterator(iterator, budget, signal, context);
@@ -130,7 +136,9 @@ export async function readIteratorResult(iterator, result, property) {
130
136
  }
131
137
  export function getSandboxAsyncIterator(value, budget, context, signal) {
132
138
  if (isSandboxGenerator(value) && value.async) {
133
- return { ...generatorIterator(value, budget, context), asyncProtocol: true };
139
+ return hasExplicitSandboxPrototype(value) ? context?.getProperty === undefined
140
+ ? generatorProtocolAdapter(value, budget, context, true, signal) : undefined
141
+ : { ...generatorObjectIterator(value, budget, context), asyncProtocol: true };
134
142
  }
135
143
  if (value !== null &&
136
144
  (typeof value === "object" || typeof value === "function") &&
@@ -288,7 +296,12 @@ export function getSandboxIterator(value, budget, context) {
288
296
  return syncIterator(Float32Array.prototype.values.call(value));
289
297
  }
290
298
  if (isSandboxGenerator(value)) {
291
- return value.async ? undefined : generatorIterator(value);
299
+ if (value.async)
300
+ return undefined;
301
+ if (hasExplicitSandboxPrototype(value))
302
+ return context?.getProperty === undefined
303
+ ? generatorProtocolAdapter(value, budget ?? new Budget(), context, false) : undefined;
304
+ return generatorObjectIterator(value, budget, context);
292
305
  }
293
306
  if (typeof value === "string") {
294
307
  const iterator = value[Symbol.iterator]();
@@ -373,6 +386,64 @@ function collectionIterator(collection, value) {
373
386
  return adapter;
374
387
  }
375
388
  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.
392
+ const bridge = {
393
+ ...context,
394
+ stack: context?.stack ?? [],
395
+ thisValue: value,
396
+ invokeClosure: (closure, args, receiver, construct) => invokeBuiltinClosure(closure, args, budget, context, receiver, construct),
397
+ getProperty: (target, key) => {
398
+ const descriptor = getSandboxPropertyDescriptor(target, key, budget);
399
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, target, bridge, true);
400
+ }
401
+ };
402
+ let resolved;
403
+ let pending;
404
+ const initialize = () => pending ??= acquireSandboxIterator(value, budget, bridge, asyncProtocol, signal).then(iterator => {
405
+ if (iterator === undefined)
406
+ throw new TypeError("Generator does not provide an iterator protocol.");
407
+ return resolved = iterator;
408
+ });
409
+ return {
410
+ asynchronous: true,
411
+ ...(asyncProtocol ? { asyncProtocol: true } : {}),
412
+ get retainedValue() { return [value, resolved?.retainedValue]; },
413
+ snapshot: () => resolved?.snapshot?.() ?? { kind: "unsupported" },
414
+ next: async (...args) => (await initialize()).next(...args),
415
+ getOperation: async (method) => {
416
+ const iterator = await initialize();
417
+ return iterator.getOperation === undefined ? iterator[method] : iterator.getOperation(method);
418
+ },
419
+ readResultProperty: async (result, property) => readIteratorResult(await initialize(), result, property)
420
+ };
421
+ }
422
+ function generatorObjectIterator(generator, budget, context) {
423
+ const iterator = generatorIterator(generator, budget, context);
424
+ if (context?.getProperty === undefined)
425
+ return iterator;
426
+ return {
427
+ ...iterator,
428
+ getOperation: async (method) => {
429
+ if (method === "next" || (!hasExplicitSandboxPrototype(generator) &&
430
+ getSandboxPropertyDescriptor(generator, method, budget) === undefined))
431
+ return iterator[method];
432
+ const operation = await context.getProperty(generator, method);
433
+ if (operation === undefined || operation === null)
434
+ return undefined;
435
+ if (!isSandboxClosure(operation))
436
+ throw new TypeError("Iterator operation must be callable.");
437
+ return async (...args) => {
438
+ const result = await invokeBuiltinClosure(operation, args, budget ?? new Budget(), context, generator);
439
+ return (generator.async ? await awaitSandboxValue(result, undefined, budget, context) : result);
440
+ };
441
+ },
442
+ readResultProperty: async (result, property) => ({
443
+ value: await context.getProperty(result, property)
444
+ })
445
+ };
446
+ }
376
447
  export function generatorIterator(generator, budget, context) {
377
448
  const invoke = async (method, value) => {
378
449
  const leaveRunning = enterRunningState(generator);
@@ -1,7 +1,10 @@
1
- import { type SandboxClosure, type SandboxValue } from "../values.js";
2
- import type { Budget } from "../budget.js";
1
+ import { type SandboxCallContext, type SandboxClosure, type SandboxValue } from "../values.js";
2
+ import { Budget } from "../budget.js";
3
3
  export type FunctionMethodOptions = {
4
4
  budget?: Budget;
5
5
  callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue: SandboxValue, construct?: boolean, newTarget?: SandboxClosure) => Promise<SandboxValue> | SandboxValue;
6
6
  };
7
+ type FunctionMethodName = "apply" | "bind" | "call" | "toString";
7
8
  export declare function getFunctionMember(target: SandboxClosure, property: string | number, options: FunctionMethodOptions): SandboxValue | undefined;
9
+ export declare function callFunctionMethod(target: SandboxValue, methodName: FunctionMethodName, args: readonly SandboxValue[], options: FunctionMethodOptions, stack: readonly string[], context?: SandboxCallContext): Promise<SandboxValue> | SandboxValue;
10
+ export {};
@@ -1,8 +1,12 @@
1
1
  import { createSandboxClosure, isSandboxClosure } from "../values.js";
2
- import { getGuestFunctionProperty, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure, setSandboxPrototype } from "../object-model.js";
2
+ import { getGuestFunctionProperty, getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure, setSandboxPrototype } from "../object-model.js";
3
3
  import { assertSandboxDataDepth } from "../../graph-depth.js";
4
+ import { Budget } from "../budget.js";
4
5
  import { functionString } from "../function-string.js";
5
- import { runResources } from "../resources.js";
6
+ import { retainValues, runResources } from "../resources.js";
7
+ import { createBoundFunction } from "../bound-function.js";
8
+ import { sandboxNumber } from "../string-coercion.js";
9
+ import { readPropertyDescriptor } from "../accessors.js";
6
10
  const functionMethodNames = new Set(["apply", "bind", "call", "toString"]);
7
11
  export function getFunctionMember(target, property, options) {
8
12
  let current = target;
@@ -22,7 +26,7 @@ export function getFunctionMember(target, property, options) {
22
26
  else if (Object.hasOwn(current, String(property))) {
23
27
  return current[String(property)];
24
28
  }
25
- if (isSandboxClosure(current) && !hasExplicitSandboxPrototype(current))
29
+ if (isSandboxClosure(current) && !hasExplicitSandboxPrototype(current) && getSandboxPrototype(current, options.budget) === null)
26
30
  break;
27
31
  current = getSandboxPrototype(current, options.budget);
28
32
  if (current !== null) {
@@ -47,7 +51,7 @@ export function getFunctionMember(target, property, options) {
47
51
  function isFunctionMethodName(property) {
48
52
  return typeof property === "string" && functionMethodNames.has(property);
49
53
  }
50
- function callFunctionMethod(target, methodName, args, options, stack, context) {
54
+ export function callFunctionMethod(target, methodName, args, options, stack, context) {
51
55
  if (!isSandboxClosure(target)) {
52
56
  throw new TypeError(`Function#${methodName} requires a callable receiver.`);
53
57
  }
@@ -58,40 +62,36 @@ function callFunctionMethod(target, methodName, args, options, stack, context) {
58
62
  const thisValue = args[0];
59
63
  if (methodName === "bind") {
60
64
  const boundArgs = args.slice(1);
65
+ const explicitPrototype = hasExplicitSandboxPrototype(target);
66
+ const prototype = getSandboxPrototype(target, options.budget);
61
67
  const bind = (length, name) => {
62
- const bound = createSandboxClosure({
63
- guest: true,
64
- sandbox: true,
65
- name: `bound ${name}`,
66
- length,
67
- boundTarget: target,
68
- retainedValues: () => [target, thisValue, ...boundArgs, bound.name],
69
- call: (callArgs, context) => options.callClosure(target, [...boundArgs, ...callArgs], context?.stack ?? [], thisValue),
70
- ...(target.construct === undefined
71
- ? {}
72
- : {
73
- construct: (callArgs, context) => options.callClosure(target, [...boundArgs, ...callArgs], context?.stack ?? [], undefined, true, context?.newTarget === bound ? target : context?.newTarget)
74
- })
75
- });
76
- if (hasExplicitSandboxPrototype(target))
77
- setSandboxPrototype(bound, getSandboxPrototype(target, options.budget), options.budget);
68
+ const bound = createBoundFunction({ target, thisValue, args: boundArgs }, `bound ${name}`, length, options.callClosure);
69
+ if (explicitPrototype)
70
+ setSandboxPrototype(bound, prototype, options.budget);
78
71
  return bound;
79
72
  };
80
73
  if (context?.getProperty === undefined)
81
74
  return bind(target.length === undefined ? undefined : Math.max(0, target.length - boundArgs.length), target.name ?? "");
82
75
  return (async () => {
83
- const properties = target.properties;
84
- const defaultName = target.name;
85
- const hasLength = !isGuestClosure(target) ||
86
- target.properties === undefined ||
87
- Object.hasOwn(target.properties, "length");
88
- const length = hasLength ? await context.getProperty(target, "length") : undefined;
89
- const name = !isGuestClosure(target) && !Object.hasOwn(properties ?? {}, "name")
90
- ? defaultName
91
- : await context.getProperty(target, "name");
92
- return bind(typeof length === "number" && !Number.isNaN(length)
93
- ? Math.max(0, Math.trunc(length) - boundArgs.length)
94
- : 0, typeof name === "string" ? name : "");
76
+ const release = options.budget !== undefined && explicitPrototype && prototype !== null
77
+ ? retainValues(options.budget, () => [prototype]) : undefined;
78
+ try {
79
+ const properties = target.properties;
80
+ const defaultName = target.name;
81
+ const hasLength = !isGuestClosure(target) ||
82
+ target.properties === undefined ||
83
+ Object.hasOwn(target.properties, "length");
84
+ const length = hasLength ? await context.getProperty(target, "length") : undefined;
85
+ const name = !isGuestClosure(target) && !Object.hasOwn(properties ?? {}, "name")
86
+ ? defaultName
87
+ : await context.getProperty(target, "name");
88
+ return bind(typeof length === "number" && !Number.isNaN(length)
89
+ ? Math.max(0, Math.trunc(length) - boundArgs.length)
90
+ : 0, typeof name === "string" ? name : "");
91
+ }
92
+ finally {
93
+ release?.();
94
+ }
95
95
  })();
96
96
  }
97
97
  if (methodName === "call") {
@@ -101,26 +101,39 @@ function callFunctionMethod(target, methodName, args, options, stack, context) {
101
101
  if (applyArgs === null || applyArgs === undefined) {
102
102
  return options.callClosure(target, [], stack, thisValue);
103
103
  }
104
- if (!Array.isArray(applyArgs)) {
105
- throw new TypeError("Function#apply requires an array or nullish arguments value.");
104
+ if (typeof applyArgs !== "object") {
105
+ throw new TypeError("Function#apply requires an object or nullish arguments value.");
106
106
  }
107
- if (context?.getProperty === undefined)
107
+ if (context?.getProperty === undefined && Array.isArray(applyArgs))
108
108
  return options.callClosure(target, applyArgs, stack, thisValue);
109
109
  return (async () => {
110
+ const budget = options.budget ?? new Budget();
111
+ const invocationContext = {
112
+ ...context,
113
+ stack,
114
+ thisValue: context?.thisValue,
115
+ invokeClosure: context?.invokeClosure ?? ((callee, values, receiver) => Promise.resolve(options.callClosure(callee, values, stack, receiver)))
116
+ };
117
+ const read = (value, key) => {
118
+ if (context?.getProperty !== undefined)
119
+ return context.getProperty(value, key);
120
+ const descriptor = getSandboxPropertyDescriptor(value, key, budget);
121
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, invocationContext);
122
+ };
110
123
  const values = [];
111
- const length = applyArgs.length;
112
- options.budget?.allocateArrayLength(length);
113
- const retained = {};
114
- options.budget?.setRetainedValues(retained, () => values);
124
+ const release = retainValues(budget, () => [applyArgs, ...values]);
115
125
  try {
126
+ const number = await sandboxNumber(await read(applyArgs, "length"), budget, invocationContext);
127
+ const length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
128
+ budget.allocateArrayLength(length);
116
129
  for (let index = 0; index < length; index++) {
117
- options.budget?.visitNode();
118
- values.push(await context.getProperty(applyArgs, index));
130
+ budget.visitNode();
131
+ values.push(await read(applyArgs, String(index)));
119
132
  }
120
133
  return await options.callClosure(target, values, stack, thisValue);
121
134
  }
122
135
  finally {
123
- options.budget?.setRetainedValues(retained, undefined);
136
+ release();
124
137
  }
125
138
  })();
126
139
  }
@@ -1,3 +1,6 @@
1
- import { type SandboxGenerator, type SandboxValue } from "../values.js";
1
+ import { type SandboxCallContext, type SandboxGenerator, type SandboxValue } from "../values.js";
2
2
  import type { Budget } from "../budget.js";
3
+ type GeneratorMethodName = "next" | "return" | "throw";
3
4
  export declare function getGeneratorMember(target: SandboxGenerator, property: string | number, budget: Budget): SandboxValue | undefined;
5
+ export declare function callGeneratorMethod(target: SandboxValue, method: GeneratorMethodName, value: SandboxValue, budget: Budget, context: SandboxCallContext | undefined, async: boolean): SandboxValue | Promise<SandboxValue>;
6
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { generatorIterator } from "../iteration.js";
2
- import { allocateProducedSandboxValue, createSandboxClosure, createSandboxPromise } from "../values.js";
2
+ import { allocateProducedSandboxValue, createSandboxClosure, createSandboxPromise, isSandboxGenerator } from "../values.js";
3
3
  const generatorMethodNames = new Set(["next", "return", "throw"]);
4
4
  export function getGeneratorMember(target, property, budget) {
5
5
  if (typeof property !== "string" || !generatorMethodNames.has(property)) {
@@ -8,10 +8,16 @@ export function getGeneratorMember(target, property, budget) {
8
8
  return createSandboxClosure({
9
9
  sandbox: true,
10
10
  name: property,
11
- call: ([value], context) => {
12
- const iterator = generatorIterator(target, budget, context);
13
- const result = Promise.resolve(iterator[property](value)).then(result => allocateProducedSandboxValue({ value: result.value, done: result.done === true }, budget));
14
- return target.async ? createSandboxPromise(result) : result;
15
- }
11
+ call: ([value], context) => callGeneratorMethod(target, property, value, budget, context, target.async === true)
16
12
  });
17
13
  }
14
+ export function callGeneratorMethod(target, method, value, budget, context, async) {
15
+ const result = (async () => {
16
+ if (!isSandboxGenerator(target) || (target.async === true) !== async)
17
+ throw new TypeError(`${async ? "AsyncGenerator" : "Generator"}.${method} requires a matching generator receiver.`);
18
+ const iterator = generatorIterator(target, budget, context);
19
+ const result = await iterator[method](value);
20
+ return allocateProducedSandboxValue({ value: result.value, done: result.done === true }, budget);
21
+ })();
22
+ return async ? createSandboxPromise(result) : result;
23
+ }
@@ -7,6 +7,7 @@ export declare function getGuestFunctionProperties(closure: SandboxClosure): San
7
7
  export declare function materializeFunctionProperties(closure: SandboxClosure): SandboxObject;
8
8
  export declare function getGuestFunctionProperty(closure: SandboxClosure, key: PropertyKey): SandboxValue;
9
9
  export declare function installObjectPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
10
+ export declare function installFunctionPrototype(budget: Budget, prototype: SandboxClosure): void;
10
11
  export declare function installBoxedPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure, kind?: BoxedKind): void;
11
12
  export declare function getBoxedPrototype(value: BoxedPrimitive, budget: Budget): SandboxObject | undefined;
12
13
  export declare function installRegexPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;