SharedArrayBufferPrototype.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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.SharedArrayBuffer;
  7. /// <summary>
  8. /// https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-prototype-object
  9. /// </summary>
  10. internal sealed class SharedArrayBufferPrototype : Prototype
  11. {
  12. private readonly SharedArrayBufferConstructor _constructor;
  13. internal SharedArrayBufferPrototype(
  14. Engine engine,
  15. SharedArrayBufferConstructor constructor,
  16. ObjectPrototype objectPrototype) : base(engine, engine.Realm)
  17. {
  18. _prototype = objectPrototype;
  19. _constructor = constructor;
  20. }
  21. protected override void Initialize()
  22. {
  23. const PropertyFlag lengthFlags = PropertyFlag.Configurable;
  24. var properties = new PropertyDictionary(3, checkExistingKeys: false)
  25. {
  26. ["byteLength"] = new GetSetPropertyDescriptor(new ClrFunction(_engine, "get byteLength", ByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  27. [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
  28. ["growable"] = new GetSetPropertyDescriptor(new ClrFunction(_engine, "get growable", Growable, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  29. ["grow"] = new PropertyDescriptor(new ClrFunction(_engine, "grow", Grow, 1, lengthFlags), PropertyFlag.NonEnumerable),
  30. ["maxByteLength"] = new GetSetPropertyDescriptor(new ClrFunction(_engine, "get maxByteLength", MaxByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  31. ["slice"] = new PropertyDescriptor(new ClrFunction(Engine, "slice", Slice, 2, lengthFlags), PropertyFlag.Configurable | PropertyFlag.Writable)
  32. };
  33. SetProperties(properties);
  34. var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("SharedArrayBuffer", PropertyFlag.Configurable) };
  35. SetSymbols(symbols);
  36. }
  37. /// <summary>
  38. /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.bytelength
  39. /// </summary>
  40. private JsNumber ByteLength(JsValue thisObj, JsCallArguments arguments)
  41. {
  42. var o = thisObj as JsSharedArrayBuffer;
  43. if (o is null || !o.IsSharedArrayBuffer)
  44. {
  45. Throw.TypeError(_realm, "Method prototype.byteLength called on incompatible receiver " + thisObj);
  46. }
  47. return JsNumber.Create(o.ArrayBufferByteLength);
  48. }
  49. /// <summary>
  50. /// https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
  51. /// </summary>
  52. private JsSharedArrayBuffer Slice(JsValue thisObj, JsCallArguments arguments)
  53. {
  54. var o = thisObj as JsSharedArrayBuffer;
  55. if (o is null || !o.IsSharedArrayBuffer)
  56. {
  57. Throw.TypeError(_realm, "Method prototype.slice called on incompatible receiver " + thisObj);
  58. }
  59. o.AssertNotDetached();
  60. var start = arguments.At(0);
  61. var end = arguments.At(1);
  62. var len = o.ArrayBufferByteLength;
  63. var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
  64. var first = relativeStart switch
  65. {
  66. double.NegativeInfinity => 0,
  67. < 0 => (int) System.Math.Max(len + relativeStart, 0),
  68. _ => (int) System.Math.Min(relativeStart, len)
  69. };
  70. double relativeEnd;
  71. if (end.IsUndefined())
  72. {
  73. relativeEnd = len;
  74. }
  75. else
  76. {
  77. relativeEnd = TypeConverter.ToIntegerOrInfinity(end);
  78. }
  79. var final = relativeEnd switch
  80. {
  81. double.NegativeInfinity => 0,
  82. < 0 => (int) System.Math.Max(len + relativeEnd, 0),
  83. _ => (int) System.Math.Min(relativeEnd, len)
  84. };
  85. var newLen = System.Math.Max(final - first, 0);
  86. var ctor = SpeciesConstructor(o, _realm.Intrinsics.SharedArrayBuffer);
  87. var bufferInstance = Construct(ctor, [JsNumber.Create(newLen)]) as JsSharedArrayBuffer;
  88. if (bufferInstance is null)
  89. {
  90. Throw.TypeError(_realm);
  91. }
  92. if (!bufferInstance.IsSharedArrayBuffer)
  93. {
  94. Throw.TypeError(_realm);
  95. }
  96. if (bufferInstance.IsDetachedBuffer)
  97. {
  98. Throw.TypeError(_realm);
  99. }
  100. if (ReferenceEquals(bufferInstance, o))
  101. {
  102. Throw.TypeError(_realm);
  103. }
  104. if (bufferInstance.ArrayBufferByteLength < newLen)
  105. {
  106. Throw.TypeError(_realm);
  107. }
  108. // NOTE: Side-effects of the above steps may have detached O.
  109. if (bufferInstance.IsDetachedBuffer)
  110. {
  111. Throw.TypeError(_realm);
  112. }
  113. var fromBuf = o.ArrayBufferData!;
  114. var toBuf = bufferInstance.ArrayBufferData!;
  115. System.Array.Copy(fromBuf, first, toBuf, 0, newLen);
  116. return bufferInstance;
  117. }
  118. /// <summary>
  119. /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.growable
  120. /// </summary>
  121. private JsValue Growable(JsValue thisObject, JsCallArguments arguments)
  122. {
  123. var o = thisObject as JsSharedArrayBuffer;
  124. if (o is null || !o.IsSharedArrayBuffer)
  125. {
  126. Throw.TypeError(_realm, "Method SharedArrayBuffer.prototype.growable called on incompatible receiver " + thisObject);
  127. }
  128. return !o.IsFixedLengthArrayBuffer;
  129. }
  130. /// <summary>
  131. /// https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.grow
  132. /// </summary>
  133. private JsValue Grow(JsValue thisObject, JsCallArguments arguments)
  134. {
  135. var o = thisObject as JsSharedArrayBuffer;
  136. if (o is null || !o.IsSharedArrayBuffer)
  137. {
  138. Throw.TypeError(_realm, "Method SharedArrayBuffer.prototype.grow called on incompatible receiver " + thisObject);
  139. }
  140. var newLength = arguments.At(0);
  141. var newByteLength = TypeConverter.ToIndex(_realm, newLength);
  142. o.AssertNotDetached();
  143. o.Resize(newByteLength);
  144. return Undefined;
  145. }
  146. /// <summary>
  147. /// https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.maxbytelength
  148. /// </summary>
  149. private JsValue MaxByteLength(JsValue thisObject, JsCallArguments arguments)
  150. {
  151. var o = thisObject as JsSharedArrayBuffer;
  152. if (o is null || !o.IsSharedArrayBuffer)
  153. {
  154. Throw.TypeError(_realm, "Method SharedArrayBuffer.prototype.maxByteLength called on incompatible receiver " + thisObject);
  155. }
  156. if (o.IsDetachedBuffer)
  157. {
  158. return JsNumber.PositiveZero;
  159. }
  160. long length = o.IsFixedLengthArrayBuffer
  161. ? o.ArrayBufferByteLength
  162. : o._arrayBufferMaxByteLength.GetValueOrDefault();
  163. return length;
  164. }
  165. }