FinalizationRegistryPrototype.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using Jint.Native.Object;
  2. using Jint.Native.Symbol;
  3. using Jint.Runtime;
  4. using Jint.Runtime.Descriptors;
  5. using Jint.Runtime.Interop;
  6. namespace Jint.Native.FinalizationRegistry;
  7. /// <summary>
  8. /// https://tc39.es/ecma262/#sec-properties-of-the-finalization-registry-prototype-object
  9. /// </summary>
  10. internal sealed class FinalizationRegistryPrototype : Prototype
  11. {
  12. private readonly FinalizationRegistryConstructor _constructor;
  13. public FinalizationRegistryPrototype(
  14. Engine engine,
  15. Realm realm,
  16. FinalizationRegistryConstructor constructor,
  17. ObjectPrototype objectPrototype) : base(engine, realm)
  18. {
  19. _constructor = constructor;
  20. _prototype = objectPrototype;
  21. }
  22. protected override void Initialize()
  23. {
  24. const PropertyFlag PropertyFlags = PropertyFlag.NonEnumerable;
  25. var properties = new PropertyDictionary(4, checkExistingKeys: false)
  26. {
  27. [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
  28. ["register"] = new PropertyDescriptor(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags),
  29. ["unregister"] = new PropertyDescriptor(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags),
  30. };
  31. SetProperties(properties);
  32. var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new("FinalizationRegistry", PropertyFlag.Configurable) };
  33. SetSymbols(symbols);
  34. }
  35. /// <summary>
  36. /// https://tc39.es/ecma262/#sec-finalization-registry.prototype.register
  37. /// </summary>
  38. private JsValue Register(JsValue thisObject, JsCallArguments arguments)
  39. {
  40. var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
  41. var target = arguments.At(0);
  42. var heldValue = arguments.At(1);
  43. var unregisterToken = arguments.At(2);
  44. if (!target.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
  45. {
  46. Throw.TypeError(_realm, "target must be an object or symbol");
  47. }
  48. if (SameValue(target, heldValue))
  49. {
  50. Throw.TypeError(_realm, "target and holdings must not be same");
  51. }
  52. if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
  53. {
  54. if (!unregisterToken.IsUndefined())
  55. {
  56. Throw.TypeError(_realm, unregisterToken + " must be an object");
  57. }
  58. }
  59. var cell = new Cell(target, heldValue, unregisterToken);
  60. finalizationRegistry.AddCell(cell);
  61. return Undefined;
  62. }
  63. /// <summary>
  64. /// https://tc39.es/ecma262/#sec-finalization-registry.prototype.unregister
  65. /// </summary>
  66. private JsValue Unregister(JsValue thisObject, JsCallArguments arguments)
  67. {
  68. var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
  69. var unregisterToken = arguments.At(0);
  70. if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
  71. {
  72. Throw.TypeError(_realm, unregisterToken + " must be an object or symbol");
  73. }
  74. return finalizationRegistry.Remove(unregisterToken);
  75. }
  76. private FinalizationRegistryInstance AssertFinalizationRegistryInstance(JsValue thisObject)
  77. {
  78. if (thisObject is FinalizationRegistryInstance finalizationRegistryInstance)
  79. {
  80. return finalizationRegistryInstance;
  81. }
  82. Throw.TypeError(_realm, "object must be a FinalizationRegistry");
  83. return default;
  84. }
  85. }