poe-code 14.0.57 → 14.0.59

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.
@@ -4,6 +4,7 @@ import { toPropertyKey } from "./property-key.js";
4
4
  import { assertPromiseExecutionAllowed } from "./promise-tracker.js";
5
5
  import { SandboxJobQueue, runAsyncPrefix, suspendJob } from "./jobs.js";
6
6
  import { withCancellationSignal } from "./cancel.js";
7
+ import { runResources } from "./resources.js";
7
8
  import { attachErrorSpan, formatErrorStack, replaceErrorStack } from "../error/shape.js";
8
9
  import { evaluateArrowFunctionExpression, evaluateFunctionExpression, evaluateAwaitExpression, emitResumeBreakpoint, createInterpretedClosure, normalizeClosureResult } from "./async.js";
9
10
  import { HostCallResumabilityError } from "./host-call.js";
@@ -272,89 +273,114 @@ async function evaluateEmptyStatement(_node, _context) {
272
273
  }
273
274
  async function evaluateArrayExpression(node, context) {
274
275
  const values = [];
275
- for (const element of node.elements) {
276
- if (element.type === "UndefinedLiteral" && element.elision === true) {
277
- values.length += 1;
278
- context.budget.allocateArrayLength(values.length);
279
- continue;
280
- }
281
- if (element.type === "SpreadElement") {
282
- const spreadValues = await evaluateSpreadElement(element, context);
283
- if (!spreadValues.ok) {
284
- return spreadValues.result;
276
+ const release = retainValues(context.budget, () => [values]);
277
+ try {
278
+ for (const element of node.elements) {
279
+ if (element.type === "UndefinedLiteral" && element.elision === true) {
280
+ values.length += 1;
281
+ context.budget.allocateArrayLength(values.length);
282
+ continue;
283
+ }
284
+ if (element.type === "SpreadElement") {
285
+ const spreadValues = await evaluateSpreadElement(element, context);
286
+ if (!spreadValues.ok) {
287
+ return spreadValues.result;
288
+ }
289
+ appendArrayValues(values, spreadValues.value);
290
+ context.budget.allocateArrayLength(values.length);
291
+ continue;
292
+ }
293
+ const result = await evaluateNode(element, context);
294
+ if (result.kind !== "normal") {
295
+ return result;
285
296
  }
286
- appendArrayValues(values, spreadValues.value);
297
+ values.push(result.value);
287
298
  context.budget.allocateArrayLength(values.length);
288
- continue;
289
- }
290
- const result = await evaluateNode(element, context);
291
- if (result.kind !== "normal") {
292
- return result;
293
299
  }
294
- values.push(result.value);
295
- context.budget.allocateArrayLength(values.length);
300
+ return {
301
+ kind: "normal",
302
+ hasValue: true,
303
+ value: values
304
+ };
305
+ }
306
+ finally {
307
+ release();
296
308
  }
297
- return {
298
- kind: "normal",
299
- hasValue: true,
300
- value: values
301
- };
302
309
  }
303
310
  async function evaluateObjectExpression(node, context) {
304
311
  const object = Object.create(null);
305
- for (const property of node.properties) {
306
- if (property.type === "SpreadElement") {
307
- const spreadEntries = await evaluateObjectSpread(property, context);
308
- if (!spreadEntries.ok) {
309
- return spreadEntries.result;
312
+ const release = retainValues(context.budget, () => [object]);
313
+ try {
314
+ for (const property of node.properties) {
315
+ if (property.type === "SpreadElement") {
316
+ const spreadEntries = await evaluateObjectSpread(property, context);
317
+ if (!spreadEntries.ok) {
318
+ return spreadEntries.result;
319
+ }
320
+ for (const [key, value] of spreadEntries.value) {
321
+ defineSandboxProperty(object, key, value);
322
+ }
323
+ continue;
310
324
  }
311
- for (const [key, value] of spreadEntries.value) {
312
- defineSandboxProperty(object, key, value);
325
+ const key = await evaluateObjectPropertyKey(property, context);
326
+ if (!key.ok) {
327
+ return key.result;
313
328
  }
314
- continue;
315
- }
316
- const key = await evaluateObjectPropertyKey(property, context);
317
- if (!key.ok) {
318
- return key.result;
319
- }
320
- const value = await evaluateNode(property.value, context);
321
- if (value.kind !== "normal") {
322
- return value;
323
- }
324
- if (isObjectPrototypeSetterProperty(property, key.value)) {
325
- if (value.value === null || typeof value.value === "object") {
326
- setSandboxPrototype(object, value.value, context.budget);
329
+ const releaseKey = retainValues(context.budget, () => [key.value]);
330
+ let value;
331
+ try {
332
+ value = await evaluateNode(property.value, context);
327
333
  }
328
- continue;
334
+ finally {
335
+ releaseKey();
336
+ }
337
+ if (value.kind !== "normal") {
338
+ return value;
339
+ }
340
+ if (isObjectPrototypeSetterProperty(property, key.value)) {
341
+ if (value.value === null || typeof value.value === "object") {
342
+ setSandboxPrototype(object, value.value, context.budget);
343
+ }
344
+ continue;
345
+ }
346
+ defineSandboxProperty(object, String(key.value), value.value);
329
347
  }
330
- defineSandboxProperty(object, String(key.value), value.value);
348
+ return {
349
+ kind: "normal",
350
+ hasValue: true,
351
+ value: object
352
+ };
353
+ }
354
+ finally {
355
+ release();
331
356
  }
332
- return {
333
- kind: "normal",
334
- hasValue: true,
335
- value: object
336
- };
337
357
  }
338
358
  function isObjectPrototypeSetterProperty(property, key) {
339
359
  return !property.computed && !property.shorthand && key === "__proto__";
340
360
  }
341
361
  async function evaluateTemplateLiteral(node, context) {
342
362
  let value = context.budget.allocateString(node.quasis[0]?.value.cooked ?? "");
343
- for (let index = 0; index < node.expressions.length; index += 1) {
344
- const expression = await evaluateNode(node.expressions[index], context);
345
- if (expression.kind !== "normal") {
346
- return expression;
363
+ const release = retainValues(context.budget, () => [value]);
364
+ try {
365
+ for (let index = 0; index < node.expressions.length; index += 1) {
366
+ const expression = await evaluateNode(node.expressions[index], context);
367
+ if (expression.kind !== "normal") {
368
+ return expression;
369
+ }
370
+ const expressionText = context.budget.allocateString(String(expression.value));
371
+ value = context.budget.allocateString(value + expressionText);
372
+ const quasiText = context.budget.allocateString(node.quasis[index + 1]?.value.cooked ?? "");
373
+ value = context.budget.allocateString(value + quasiText);
347
374
  }
348
- const expressionText = context.budget.allocateString(String(expression.value));
349
- value = context.budget.allocateString(value + expressionText);
350
- const quasiText = context.budget.allocateString(node.quasis[index + 1]?.value.cooked ?? "");
351
- value = context.budget.allocateString(value + quasiText);
375
+ return {
376
+ kind: "normal",
377
+ hasValue: true,
378
+ value
379
+ };
380
+ }
381
+ finally {
382
+ release();
352
383
  }
353
- return {
354
- kind: "normal",
355
- hasValue: true,
356
- value
357
- };
358
384
  }
359
385
  async function evaluateTaggedTemplateExpression(node, context) {
360
386
  const tag = await evaluateNode(node.tag, context);
@@ -376,20 +402,26 @@ async function evaluateTaggedTemplateExpression(node, context) {
376
402
  }
377
403
  async function evaluateTemplateExpressionValues(node, context) {
378
404
  const values = [];
379
- for (const expressionNode of node.expressions) {
380
- const expression = await evaluateNode(expressionNode, context);
381
- if (expression.kind !== "normal") {
382
- return {
383
- ok: false,
384
- result: expression
385
- };
405
+ const release = retainValues(context.budget, () => values);
406
+ try {
407
+ for (const expressionNode of node.expressions) {
408
+ const expression = await evaluateNode(expressionNode, context);
409
+ if (expression.kind !== "normal") {
410
+ return {
411
+ ok: false,
412
+ result: expression
413
+ };
414
+ }
415
+ values.push(expression.value);
386
416
  }
387
- values.push(expression.value);
417
+ return {
418
+ ok: true,
419
+ value: values
420
+ };
421
+ }
422
+ finally {
423
+ release();
388
424
  }
389
- return {
390
- ok: true,
391
- value: values
392
- };
393
425
  }
394
426
  function createTaggedTemplateStrings(node, context) {
395
427
  context.budget.allocateArrayLength(node.quasis.length);
@@ -429,23 +461,31 @@ async function evaluateBinaryExpression(node, context) {
429
461
  if (left.kind !== "normal") {
430
462
  return left;
431
463
  }
432
- const right = await evaluateNode(node.right, context);
433
- if (right.kind !== "normal") {
434
- return right;
435
- }
436
- let leftValue = left.value;
437
- if (node.operator === "in") {
438
- if (typeof right.value !== "object" || right.value === null) {
439
- throw new TypeError("Right-hand side of 'in' must be an object.");
464
+ let rightValue;
465
+ const release = retainValues(context.budget, () => [left.value, rightValue]);
466
+ try {
467
+ const right = await evaluateNode(node.right, context);
468
+ if (right.kind !== "normal") {
469
+ return right;
440
470
  }
441
- leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
471
+ rightValue = right.value;
472
+ let leftValue = left.value;
473
+ if (node.operator === "in") {
474
+ if (typeof right.value !== "object" || right.value === null) {
475
+ throw new TypeError("Right-hand side of 'in' must be an object.");
476
+ }
477
+ leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
478
+ }
479
+ const value = applyBinaryOperator(node, leftValue, right.value, context);
480
+ return {
481
+ kind: "normal",
482
+ hasValue: true,
483
+ value
484
+ };
485
+ }
486
+ finally {
487
+ release();
442
488
  }
443
- const value = applyBinaryOperator(node, leftValue, right.value, context);
444
- return {
445
- kind: "normal",
446
- hasValue: true,
447
- value
448
- };
449
489
  }
450
490
  async function evaluateAssignmentExpression(node, context) {
451
491
  if (node.left.type === "ArrayPattern" || node.left.type === "ObjectPattern") {
@@ -519,66 +559,70 @@ async function evaluateMemberAssignmentExpression(node, context) {
519
559
  if (node.left.type !== "MemberExpression") {
520
560
  throw new TypeError("Expected member assignment target.");
521
561
  }
522
- const member = await evaluateMemberAccess(node.left, context);
523
- if (member.kind === "error") {
524
- return member;
525
- }
526
- if (member.kind === "completion") {
527
- return member.result;
528
- }
529
- if (member.kind === "nullish") {
530
- throw new TypeError("Cannot assign properties of null or undefined.");
531
- }
532
- let property;
533
- let current = undefined;
534
- if (node.operator !== "=") {
535
- if (member.object === null || member.object === undefined) {
562
+ return evaluateMemberAccess(node.left, context, async (member) => {
563
+ if (member.kind === "nullish") {
536
564
  throw new TypeError("Cannot assign properties of null or undefined.");
537
565
  }
538
- property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
539
- current = getPropertyValue(member.object, property, context);
540
- }
541
- if (node.operator === "&&=" && !isTruthy(current)) {
542
- return {
543
- kind: "normal",
544
- hasValue: true,
545
- value: current
546
- };
547
- }
548
- if (node.operator === "||=" && isTruthy(current)) {
549
- return {
550
- kind: "normal",
551
- hasValue: true,
552
- value: current
553
- };
554
- }
555
- if (node.operator === "??=" && current !== null && current !== undefined) {
556
- return {
557
- kind: "normal",
558
- hasValue: true,
559
- value: current
560
- };
561
- }
562
- const right = await evaluateNode(node.right, context);
563
- if (right.kind !== "normal") {
564
- return right;
565
- }
566
- const value = node.operator === "=" ||
567
- node.operator === "&&=" ||
568
- node.operator === "||=" ||
569
- node.operator === "??="
570
- ? right.value
571
- : await applyCompoundAssignmentOperator(node.operator, current, right.value, context);
572
- if (member.object === null || member.object === undefined) {
573
- throw new TypeError("Cannot assign properties of null or undefined.");
574
- }
575
- property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
576
- setSandboxProperty(member.object, property, value, context.budget);
577
- return {
578
- kind: "normal",
579
- hasValue: true,
580
- value
581
- };
566
+ let property;
567
+ let current = undefined;
568
+ if (node.operator !== "=") {
569
+ if (member.object === null || member.object === undefined) {
570
+ throw new TypeError("Cannot assign properties of null or undefined.");
571
+ }
572
+ property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
573
+ current = getPropertyValue(member.object, property, context);
574
+ }
575
+ if (node.operator === "&&=" && !isTruthy(current)) {
576
+ return {
577
+ kind: "normal",
578
+ hasValue: true,
579
+ value: current
580
+ };
581
+ }
582
+ if (node.operator === "||=" && isTruthy(current)) {
583
+ return {
584
+ kind: "normal",
585
+ hasValue: true,
586
+ value: current
587
+ };
588
+ }
589
+ if (node.operator === "??=" && current !== null && current !== undefined) {
590
+ return {
591
+ kind: "normal",
592
+ hasValue: true,
593
+ value: current
594
+ };
595
+ }
596
+ let operands = [current, property];
597
+ const release = retainValues(context.budget, () => operands);
598
+ try {
599
+ const right = await evaluateNode(node.right, context);
600
+ if (right.kind !== "normal") {
601
+ return right;
602
+ }
603
+ operands.push(right.value);
604
+ const value = node.operator === "=" ||
605
+ node.operator === "&&=" ||
606
+ node.operator === "||=" ||
607
+ node.operator === "??="
608
+ ? right.value
609
+ : await applyCompoundAssignmentOperator(node.operator, current, right.value, context);
610
+ if (member.object === null || member.object === undefined) {
611
+ throw new TypeError("Cannot assign properties of null or undefined.");
612
+ }
613
+ operands = [value];
614
+ property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
615
+ setSandboxProperty(member.object, property, value, context.budget);
616
+ return {
617
+ kind: "normal",
618
+ hasValue: true,
619
+ value
620
+ };
621
+ }
622
+ finally {
623
+ release();
624
+ }
625
+ });
582
626
  }
583
627
  async function evaluateLogicalExpression(node, context) {
584
628
  const left = await evaluateNode(node.left, context);
@@ -1572,33 +1616,28 @@ async function evaluateDeleteExpression(node, context) {
1572
1616
  if (node.argument.type !== "MemberExpression") {
1573
1617
  throw createError("UNSUPPORTED_NODE", node, "Unary operator 'delete' requires a member target.");
1574
1618
  }
1575
- const member = await evaluateMemberAccess(node.argument, context);
1576
- if (member.kind === "error") {
1577
- return member;
1578
- }
1579
- if (member.kind === "completion") {
1580
- return member.result;
1581
- }
1582
- if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1583
- if (member.kind === "nullish" && node.argument.optional) {
1584
- return {
1585
- kind: "normal",
1586
- hasValue: true,
1587
- value: true
1588
- };
1619
+ return evaluateMemberAccess(node.argument, context, async (member) => {
1620
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1621
+ if (member.kind === "nullish") {
1622
+ return {
1623
+ kind: "normal",
1624
+ hasValue: true,
1625
+ value: true
1626
+ };
1627
+ }
1628
+ throw new TypeError("Cannot delete properties of null or undefined.");
1589
1629
  }
1590
- throw new TypeError("Cannot delete properties of null or undefined.");
1591
- }
1592
- if (!isIndexableSandboxValue(member.object)) {
1593
- throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
1594
- }
1595
- const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1596
- const deleted = deleteSandboxProperty(member.object, property);
1597
- return {
1598
- kind: "normal",
1599
- hasValue: true,
1600
- value: deleted
1601
- };
1630
+ if (!isIndexableSandboxValue(member.object)) {
1631
+ throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
1632
+ }
1633
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1634
+ const deleted = deleteSandboxProperty(member.object, property);
1635
+ return {
1636
+ kind: "normal",
1637
+ hasValue: true,
1638
+ value: deleted
1639
+ };
1640
+ });
1602
1641
  }
1603
1642
  async function evaluateUpdateExpression(node, context) {
1604
1643
  if (node.argument.type === "Identifier") {
@@ -1630,42 +1669,34 @@ async function evaluateMemberUpdateExpression(node, context) {
1630
1669
  if (node.argument.type !== "MemberExpression") {
1631
1670
  throw new TypeError("Expected member update target.");
1632
1671
  }
1633
- const member = await evaluateMemberAccess(node.argument, context);
1634
- if (member.kind === "error") {
1635
- return member;
1636
- }
1637
- if (member.kind === "completion") {
1638
- return member.result;
1639
- }
1640
- if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1641
- throw new TypeError("Cannot update properties of null or undefined.");
1642
- }
1643
- const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1644
- const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, property, context), context));
1645
- const next = node.operator === "++" ? current + 1 : current - 1;
1646
- setSandboxProperty(member.object, property, next, context.budget);
1647
- return {
1648
- kind: "normal",
1649
- hasValue: true,
1650
- value: node.prefix ? next : current
1651
- };
1672
+ return evaluateMemberAccess(node.argument, context, async (member) => {
1673
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1674
+ throw new TypeError("Cannot update properties of null or undefined.");
1675
+ }
1676
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1677
+ const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, property, context), context));
1678
+ const next = node.operator === "++" ? current + 1 : current - 1;
1679
+ setSandboxProperty(member.object, property, next, context.budget);
1680
+ return {
1681
+ kind: "normal",
1682
+ hasValue: true,
1683
+ value: node.prefix ? next : current
1684
+ };
1685
+ });
1652
1686
  }
1653
1687
  async function evaluateMemberExpression(node, context) {
1654
- const member = await evaluateMemberAccess(node, context);
1655
- if (member.kind === "error")
1656
- return member;
1657
- if (member.kind === "completion")
1658
- return member.result;
1659
- if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1660
- if (member.kind === "nullish" && node.optional)
1661
- return { kind: "normal", hasValue: true, value: undefined };
1662
- throw new TypeError("Cannot read properties of null or undefined.");
1663
- }
1664
- return {
1665
- kind: "normal",
1666
- hasValue: true,
1667
- value: getPropertyValue(member.object, await toPropertyKey(member.property, context.budget, createCoercionContext(context)), context)
1668
- };
1688
+ return evaluateMemberAccess(node, context, async (member) => {
1689
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1690
+ if (member.kind === "nullish")
1691
+ return { kind: "normal", hasValue: true, value: undefined };
1692
+ throw new TypeError("Cannot read properties of null or undefined.");
1693
+ }
1694
+ return {
1695
+ kind: "normal",
1696
+ hasValue: true,
1697
+ value: getPropertyValue(member.object, await toPropertyKey(member.property, context.budget, createCoercionContext(context)), context)
1698
+ };
1699
+ });
1669
1700
  }
1670
1701
  function getPropertyValue(target, property, context) {
1671
1702
  if (isGuestHostObject(target))
@@ -1778,29 +1809,38 @@ function attachFatalSandboxErrorContext(error, node, stackFrames) {
1778
1809
  attachErrorSpan(error, node.span);
1779
1810
  replaceErrorStack(error, stackFrames);
1780
1811
  }
1781
- async function evaluateMemberAccess(node, context) {
1812
+ async function evaluateMemberAccess(node, context, consume) {
1782
1813
  const object = await evaluateNode(node.object, context);
1783
- if (object.kind !== "normal") {
1784
- return {
1785
- kind: "completion",
1786
- result: object
1787
- };
1788
- }
1814
+ if (object.kind !== "normal")
1815
+ return object;
1789
1816
  if ((object.value === null || object.value === undefined) && node.optional) {
1790
- return {
1791
- kind: "nullish"
1792
- };
1817
+ return consume({ kind: "nullish" });
1793
1818
  }
1794
- const property = node.computed
1795
- ? await evaluateNode(node.property, context)
1796
- : { kind: "normal", value: getStaticPropertyName(node.property) };
1797
- if (property.kind !== "normal")
1798
- return { kind: "completion", result: property };
1799
- return {
1800
- kind: "resolved",
1801
- object: object.value,
1802
- property: property.value
1819
+ let property;
1820
+ const release = retainValues(context.budget, () => [object.value, property]);
1821
+ try {
1822
+ const result = node.computed
1823
+ ? await evaluateNode(node.property, context)
1824
+ : { kind: "normal", value: getStaticPropertyName(node.property) };
1825
+ if (result.kind !== "normal")
1826
+ return result;
1827
+ property = result.value;
1828
+ return await consume({ kind: "resolved", object: object.value, property });
1829
+ }
1830
+ finally {
1831
+ release();
1832
+ }
1833
+ }
1834
+ function retainValues(budget, values) {
1835
+ const retained = {};
1836
+ budget.setRetainedValues(retained, values);
1837
+ const pending = runResources.getStore()?.referenceReleases;
1838
+ const release = () => {
1839
+ budget.setRetainedValues(retained, undefined);
1840
+ pending?.delete(release);
1803
1841
  };
1842
+ pending?.add(release);
1843
+ return release;
1804
1844
  }
1805
1845
  async function evaluateMemberProperty(node, context) {
1806
1846
  const property = await evaluateNode(node, context);
@@ -1837,89 +1877,84 @@ async function evaluateMemberCallExpression(node, context) {
1837
1877
  if (node.callee.type !== "MemberExpression") {
1838
1878
  throw new TypeError("Expected member call expression.");
1839
1879
  }
1840
- const reference = await evaluateMemberAccess(node.callee, context);
1841
- if (reference.kind === "error") {
1842
- return reference;
1843
- }
1844
- if (reference.kind === "completion") {
1845
- return reference.result;
1846
- }
1847
- if (reference.kind === "nullish" || reference.object === null || reference.object === undefined) {
1848
- if (reference.kind === "nullish") {
1849
- return {
1850
- kind: "normal",
1851
- hasValue: true,
1852
- value: undefined
1853
- };
1880
+ return evaluateMemberAccess(node.callee, context, async (reference) => {
1881
+ if (reference.kind === "nullish" || reference.object === null || reference.object === undefined) {
1882
+ if (reference.kind === "nullish") {
1883
+ return {
1884
+ kind: "normal",
1885
+ hasValue: true,
1886
+ value: undefined
1887
+ };
1888
+ }
1889
+ throw new TypeError("Cannot read properties of null or undefined.");
1854
1890
  }
1855
- throw new TypeError("Cannot read properties of null or undefined.");
1856
- }
1857
- const member = {
1858
- ...reference,
1859
- property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
1860
- };
1861
- if (typeof member.object === "string" && isStringMethodName(member.property)) {
1862
- return evaluateStringMethodCall(node, member.object, member.property, context);
1863
- }
1864
- if (typeof member.object === "number" && isNumberMethodName(member.property)) {
1865
- return evaluateNumberMethodCall(node, member.object, member.property, context);
1866
- }
1867
- if (Array.isArray(member.object) &&
1868
- isArrayMethodName(member.property) &&
1869
- !Object.hasOwn(member.object, member.property)) {
1870
- return evaluateArrayMethodCall(node, member.object, member.property, context);
1871
- }
1872
- if (isSandboxMap(member.object) && isMapMethodName(member.property)) {
1873
- return evaluateMapMethodCall(node, member.object, member.property, context);
1874
- }
1875
- if (isSandboxSet(member.object) && isSetMethodName(member.property)) {
1876
- return evaluateSetMethodCall(node, member.object, member.property, context);
1877
- }
1878
- if (typeof member.object === "string") {
1879
- return evaluatePrimitiveMemberCall(node, "String", member.property, getStringMember(member.object, member.property, context.budget), context);
1880
- }
1881
- if (typeof member.object === "number") {
1882
- return evaluatePrimitiveMemberCall(node, "Number", member.property, getNumberMember(member.property, context.budget), context);
1883
- }
1884
- if (Array.isArray(member.object) && !Object.hasOwn(member.object, member.property)) {
1885
- return evaluatePrimitiveMemberCall(node, "Array", member.property, getArrayMemberValue(member.object, member.property, context), context);
1886
- }
1887
- if (isSandboxMap(member.object)) {
1888
- return evaluatePrimitiveMemberCall(node, "Map", member.property, getMapMember(member.object, member.property, createMapMethodOptions(context)), context);
1889
- }
1890
- if (isSandboxDate(member.object)) {
1891
- return evaluateResolvedCallExpression(node, getDateMember(member.property, context.budget, context.compilation?.owner), context, member.object);
1892
- }
1893
- if (isFloat32Array(member.object)) {
1894
- return evaluateResolvedCallExpression(node, getFloat32Member(member.object, member.property, context.budget), context, member.object);
1895
- }
1896
- if (isSandboxSet(member.object)) {
1897
- return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
1898
- }
1899
- if (isSandboxGenerator(member.object)) {
1900
- const memberValue = getGeneratorMember(member.object, member.property, context.budget);
1901
- if (memberValue === undefined) {
1902
- throw new TypeError(`Generator#${String(member.property)} is not a supported method.`);
1891
+ const member = {
1892
+ ...reference,
1893
+ property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
1894
+ };
1895
+ if (typeof member.object === "string" && isStringMethodName(member.property)) {
1896
+ return evaluateStringMethodCall(node, member.object, member.property, context);
1903
1897
  }
1904
- return evaluateResolvedCallExpression(node, memberValue, context, member.object);
1905
- }
1906
- if (isSandboxClosure(member.object)) {
1907
- const memberValue = getClosureMemberValue(member.object, member.property, context);
1908
- if (memberValue === undefined) {
1909
- throw new TypeError(`Function#${String(member.property)} is not a supported method.`);
1898
+ if (typeof member.object === "number" && isNumberMethodName(member.property)) {
1899
+ return evaluateNumberMethodCall(node, member.object, member.property, context);
1910
1900
  }
1911
- return evaluateResolvedCallExpression(node, memberValue, context, member.object);
1912
- }
1913
- if (isSandboxPromise(member.object)) {
1914
- return evaluateResolvedCallExpression(node, getPromiseMember(member.property, context.budget), context, member.object);
1915
- }
1916
- if (isSandboxRegex(member.object) && isRegexMethodName(member.property)) {
1917
- return evaluateResolvedCallExpression(node, getRegexMember(member.object, member.property, context.budget), context, member.object);
1918
- }
1919
- if (!isIndexableSandboxValue(member.object)) {
1920
- throw new TypeError("Attempted to read a property from a non-object value.");
1921
- }
1922
- return evaluateResolvedCallExpression(node, getMemberValue(member.object, member.property, context), context, member.object);
1901
+ if (Array.isArray(member.object) &&
1902
+ isArrayMethodName(member.property) &&
1903
+ !Object.hasOwn(member.object, member.property)) {
1904
+ return evaluateArrayMethodCall(node, member.object, member.property, context);
1905
+ }
1906
+ if (isSandboxMap(member.object) && isMapMethodName(member.property)) {
1907
+ return evaluateMapMethodCall(node, member.object, member.property, context);
1908
+ }
1909
+ if (isSandboxSet(member.object) && isSetMethodName(member.property)) {
1910
+ return evaluateSetMethodCall(node, member.object, member.property, context);
1911
+ }
1912
+ if (typeof member.object === "string") {
1913
+ return evaluatePrimitiveMemberCall(node, "String", member.property, getStringMember(member.object, member.property, context.budget), context);
1914
+ }
1915
+ if (typeof member.object === "number") {
1916
+ return evaluatePrimitiveMemberCall(node, "Number", member.property, getNumberMember(member.property, context.budget), context);
1917
+ }
1918
+ if (Array.isArray(member.object) && !Object.hasOwn(member.object, member.property)) {
1919
+ return evaluatePrimitiveMemberCall(node, "Array", member.property, getArrayMemberValue(member.object, member.property, context), context);
1920
+ }
1921
+ if (isSandboxMap(member.object)) {
1922
+ return evaluatePrimitiveMemberCall(node, "Map", member.property, getMapMember(member.object, member.property, createMapMethodOptions(context)), context);
1923
+ }
1924
+ if (isSandboxDate(member.object)) {
1925
+ return evaluateResolvedCallExpression(node, getDateMember(member.property, context.budget, context.compilation?.owner), context, member.object);
1926
+ }
1927
+ if (isFloat32Array(member.object)) {
1928
+ return evaluateResolvedCallExpression(node, getFloat32Member(member.object, member.property, context.budget), context, member.object);
1929
+ }
1930
+ if (isSandboxSet(member.object)) {
1931
+ return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
1932
+ }
1933
+ if (isSandboxGenerator(member.object)) {
1934
+ const memberValue = getGeneratorMember(member.object, member.property, context.budget);
1935
+ if (memberValue === undefined) {
1936
+ throw new TypeError(`Generator#${String(member.property)} is not a supported method.`);
1937
+ }
1938
+ return evaluateResolvedCallExpression(node, memberValue, context, member.object);
1939
+ }
1940
+ if (isSandboxClosure(member.object)) {
1941
+ const memberValue = getClosureMemberValue(member.object, member.property, context);
1942
+ if (memberValue === undefined) {
1943
+ throw new TypeError(`Function#${String(member.property)} is not a supported method.`);
1944
+ }
1945
+ return evaluateResolvedCallExpression(node, memberValue, context, member.object);
1946
+ }
1947
+ if (isSandboxPromise(member.object)) {
1948
+ return evaluateResolvedCallExpression(node, getPromiseMember(member.property, context.budget), context, member.object);
1949
+ }
1950
+ if (isSandboxRegex(member.object) && isRegexMethodName(member.property)) {
1951
+ return evaluateResolvedCallExpression(node, getRegexMember(member.object, member.property, context.budget), context, member.object);
1952
+ }
1953
+ if (!isIndexableSandboxValue(member.object)) {
1954
+ throw new TypeError("Attempted to read a property from a non-object value.");
1955
+ }
1956
+ return evaluateResolvedCallExpression(node, getMemberValue(member.object, member.property, context), context, member.object);
1957
+ });
1923
1958
  }
1924
1959
  function evaluatePrimitiveMemberCall(node, receiverType, property, value, context) {
1925
1960
  if (value === undefined) {
@@ -2557,30 +2592,36 @@ async function invokeSandboxClosure(callee, args, context, stack, span, thisValu
2557
2592
  }
2558
2593
  async function evaluateCallArguments(args, context) {
2559
2594
  const values = [];
2560
- for (const arg of args) {
2561
- if (arg.type === "SpreadElement") {
2562
- const spreadValues = await evaluateSpreadElement(arg, context);
2563
- if (!spreadValues.ok) {
2564
- return spreadValues;
2595
+ const release = retainValues(context.budget, () => values);
2596
+ try {
2597
+ for (const arg of args) {
2598
+ if (arg.type === "SpreadElement") {
2599
+ const spreadValues = await evaluateSpreadElement(arg, context);
2600
+ if (!spreadValues.ok) {
2601
+ return spreadValues;
2602
+ }
2603
+ appendArrayValues(values, spreadValues.value);
2604
+ context.budget.allocateArrayLength(values.length);
2605
+ continue;
2565
2606
  }
2566
- appendArrayValues(values, spreadValues.value);
2607
+ const result = await evaluateNode(arg, context);
2608
+ if (result.kind !== "normal") {
2609
+ return {
2610
+ ok: false,
2611
+ result
2612
+ };
2613
+ }
2614
+ values.push(result.value);
2567
2615
  context.budget.allocateArrayLength(values.length);
2568
- continue;
2569
2616
  }
2570
- const result = await evaluateNode(arg, context);
2571
- if (result.kind !== "normal") {
2572
- return {
2573
- ok: false,
2574
- result
2575
- };
2576
- }
2577
- values.push(result.value);
2578
- context.budget.allocateArrayLength(values.length);
2617
+ return {
2618
+ ok: true,
2619
+ value: values
2620
+ };
2621
+ }
2622
+ finally {
2623
+ release();
2579
2624
  }
2580
- return {
2581
- ok: true,
2582
- value: values
2583
- };
2584
2625
  }
2585
2626
  async function evaluateSpreadElement(node, context) {
2586
2627
  const value = await evaluateNode(node.argument, context);
@@ -2595,21 +2636,27 @@ async function evaluateSpreadElement(node, context) {
2595
2636
  throw new TypeError("Spread arguments must evaluate to an iterable.");
2596
2637
  }
2597
2638
  const spreadValues = [];
2598
- while (true) {
2599
- const next = await iterator.next();
2600
- if (typeof next !== "object" || next === null) {
2601
- throw new TypeError("Iterator result must be an object.");
2602
- }
2603
- if (next.done === true) {
2604
- break;
2639
+ const release = retainValues(context.budget, () => [value.value, ...spreadValues]);
2640
+ try {
2641
+ while (true) {
2642
+ const next = await iterator.next();
2643
+ if (typeof next !== "object" || next === null) {
2644
+ throw new TypeError("Iterator result must be an object.");
2645
+ }
2646
+ if (next.done === true) {
2647
+ break;
2648
+ }
2649
+ spreadValues.push(next.value);
2650
+ context.budget.allocateArrayLength(spreadValues.length);
2605
2651
  }
2606
- spreadValues.push(next.value);
2607
- context.budget.allocateArrayLength(spreadValues.length);
2652
+ return {
2653
+ ok: true,
2654
+ value: spreadValues
2655
+ };
2656
+ }
2657
+ finally {
2658
+ release();
2608
2659
  }
2609
- return {
2610
- ok: true,
2611
- value: spreadValues
2612
- };
2613
2660
  }
2614
2661
  async function evaluateObjectSpread(node, context) {
2615
2662
  const value = await evaluateNode(node.argument, context);