SharedArrayBufferPrototype.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Function.h>
  7. #include <LibJS/Runtime/AbstractOperations.h>
  8. #include <LibJS/Runtime/GlobalObject.h>
  9. #include <LibJS/Runtime/SharedArrayBufferConstructor.h>
  10. #include <LibJS/Runtime/SharedArrayBufferPrototype.h>
  11. namespace JS {
  12. GC_DEFINE_ALLOCATOR(SharedArrayBufferPrototype);
  13. SharedArrayBufferPrototype::SharedArrayBufferPrototype(Realm& realm)
  14. : PrototypeObject(realm.intrinsics().object_prototype())
  15. {
  16. }
  17. void SharedArrayBufferPrototype::initialize(Realm& realm)
  18. {
  19. auto& vm = this->vm();
  20. Base::initialize(realm);
  21. u8 attr = Attribute::Writable | Attribute::Configurable;
  22. define_native_accessor(realm, vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
  23. define_native_function(realm, vm.names.slice, slice, 2, attr);
  24. // 25.2.5.7 SharedArrayBuffer.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.toString
  25. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.SharedArrayBuffer.as_string()), Attribute::Configurable);
  26. }
  27. // 25.2.5.1 get SharedArrayBuffer.prototype.byteLength, https://tc39.es/ecma262/#sec-get-sharedarraybuffer.prototype.bytelength
  28. JS_DEFINE_NATIVE_FUNCTION(SharedArrayBufferPrototype::byte_length_getter)
  29. {
  30. // 1. Let O be the this value.
  31. // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
  32. auto array_buffer_object = TRY(typed_this_value(vm));
  33. // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
  34. if (!array_buffer_object->is_shared_array_buffer())
  35. return vm.throw_completion<TypeError>(ErrorType::NotASharedArrayBuffer);
  36. // 4. Let length be O.[[ArrayBufferByteLength]].
  37. // 5. Return 𝔽(length).
  38. return Value(array_buffer_object->byte_length());
  39. }
  40. // 25.2.5.6 SharedArrayBuffer.prototype.slice ( start, end ), https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
  41. JS_DEFINE_NATIVE_FUNCTION(SharedArrayBufferPrototype::slice)
  42. {
  43. auto& realm = *vm.current_realm();
  44. auto start = vm.argument(0);
  45. auto end = vm.argument(1);
  46. // 1. Let O be the this value.
  47. // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
  48. auto array_buffer_object = TRY(typed_this_value(vm));
  49. // 3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
  50. if (!array_buffer_object->is_shared_array_buffer())
  51. return vm.throw_completion<TypeError>(ErrorType::NotASharedArrayBuffer);
  52. // 4. Let len be O.[[ArrayBufferByteLength]].
  53. auto length = array_buffer_object->byte_length();
  54. // 5. Let relativeStart be ? ToIntegerOrInfinity(start).
  55. auto relative_start = TRY(start.to_integer_or_infinity(vm));
  56. double first;
  57. // 6. If relativeStart is -∞, let first be 0.
  58. if (Value(relative_start).is_negative_infinity())
  59. first = 0;
  60. // 7. Else if relativeStart < 0, let first be max(len + relativeStart, 0).
  61. else if (relative_start < 0)
  62. first = max(length + relative_start, 0.0);
  63. // 8. Else, let first be min(relativeStart, len).
  64. else
  65. first = min(relative_start, (double)length);
  66. // 9. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  67. auto relative_end = end.is_undefined() ? length : TRY(end.to_integer_or_infinity(vm));
  68. double final;
  69. // 10. If relativeEnd is -∞, let final be 0.
  70. if (Value(relative_end).is_negative_infinity())
  71. final = 0;
  72. // 11. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  73. else if (relative_end < 0)
  74. final = max(length + relative_end, 0.0);
  75. // 12. Else, let final be min(relativeEnd, len).
  76. else
  77. final = min(relative_end, (double)length);
  78. // 13. Let newLen be max(final - first, 0).
  79. auto new_length = max(final - first, 0.0);
  80. // 14. Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%).
  81. auto* constructor = TRY(species_constructor(vm, array_buffer_object, realm.intrinsics().shared_array_buffer_constructor()));
  82. // 15. Let new be ? Construct(ctor, « 𝔽(newLen) »).
  83. auto new_array_buffer = TRY(construct(vm, *constructor, Value(new_length)));
  84. // 16. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
  85. if (!is<ArrayBuffer>(new_array_buffer.ptr()))
  86. return vm.throw_completion<TypeError>(ErrorType::SpeciesConstructorDidNotCreate, "an ArrayBuffer");
  87. auto* new_array_buffer_object = static_cast<ArrayBuffer*>(new_array_buffer.ptr());
  88. // 17. If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
  89. if (!new_array_buffer_object->is_shared_array_buffer())
  90. return vm.throw_completion<TypeError>(ErrorType::NotASharedArrayBuffer);
  91. // 18. If new.[[ArrayBufferData]] is O.[[ArrayBufferData]], throw a TypeError exception.
  92. if (new_array_buffer == array_buffer_object)
  93. return vm.throw_completion<TypeError>(ErrorType::SpeciesConstructorReturned, "same ArrayBuffer instance");
  94. // 19. If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
  95. if (new_array_buffer_object->byte_length() < new_length)
  96. return vm.throw_completion<TypeError>(ErrorType::SpeciesConstructorReturned, "an ArrayBuffer smaller than requested");
  97. // 20. Let fromBuf be O.[[ArrayBufferData]].
  98. auto& from_buf = array_buffer_object->buffer();
  99. // 21. Let toBuf be new.[[ArrayBufferData]].
  100. auto& to_buf = new_array_buffer_object->buffer();
  101. // 22. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
  102. copy_data_block_bytes(to_buf, 0, from_buf, first, new_length);
  103. // 23. Return new.
  104. return new_array_buffer_object;
  105. }
  106. }