mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 19:45:07 +00:00
LibJS: Implement and test getters added by resizable ArrayBuffer
This commit is contained in:
parent
e01ee4e30b
commit
b29e19c52a
6 changed files with 113 additions and 0 deletions
|
@ -48,6 +48,16 @@ ArrayBuffer::~ArrayBuffer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.1.5 IsResizableArrayBuffer ( arrayBuffer ), https://tc39.es/proposal-resizablearraybuffer/#sec-isresizablearraybuffer
|
||||||
|
bool ArrayBuffer::is_resizable_array_buffer() const
|
||||||
|
{
|
||||||
|
// 1. Assert: Type(arrayBuffer) is Object and arrayBuffer has an [[ArrayBufferData]] internal slot.
|
||||||
|
|
||||||
|
// 2. If buffer has an [[ArrayBufferMaxByteLength]] internal slot, return true.
|
||||||
|
// 3. Return false.
|
||||||
|
return m_max_byte_length.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
void ArrayBuffer::visit_edges(Cell::Visitor& visitor)
|
void ArrayBuffer::visit_edges(Cell::Visitor& visitor)
|
||||||
{
|
{
|
||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
virtual ~ArrayBuffer() override;
|
virtual ~ArrayBuffer() override;
|
||||||
|
|
||||||
size_t byte_length() const { return buffer_impl().size(); }
|
size_t byte_length() const { return buffer_impl().size(); }
|
||||||
|
size_t max_byte_length() const { return m_max_byte_length.value(); } // Will VERIFY() that it has value
|
||||||
ByteBuffer& buffer() { return buffer_impl(); }
|
ByteBuffer& buffer() { return buffer_impl(); }
|
||||||
const ByteBuffer& buffer() const { return buffer_impl(); }
|
const ByteBuffer& buffer() const { return buffer_impl(); }
|
||||||
|
|
||||||
|
@ -47,6 +48,8 @@ public:
|
||||||
void detach_buffer() { m_buffer = Empty {}; }
|
void detach_buffer() { m_buffer = Empty {}; }
|
||||||
bool is_detached() const { return m_buffer.has<Empty>(); }
|
bool is_detached() const { return m_buffer.has<Empty>(); }
|
||||||
|
|
||||||
|
bool is_resizable_array_buffer() const;
|
||||||
|
|
||||||
enum Order {
|
enum Order {
|
||||||
SeqCst,
|
SeqCst,
|
||||||
Unordered
|
Unordered
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
|
* Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
|
||||||
* Copyright (c) 2021-2022, Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2021-2022, Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||||
|
* Copyright (c) 2022, the SerenityOS developers.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +27,8 @@ void ArrayBufferPrototype::initialize(GlobalObject& global_object)
|
||||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
define_native_function(vm.names.slice, slice, 2, attr);
|
define_native_function(vm.names.slice, slice, 2, attr);
|
||||||
define_native_accessor(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
|
define_native_accessor(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
|
||||||
|
define_native_accessor(vm.names.maxByteLength, max_byte_length_getter, {}, Attribute::Configurable);
|
||||||
|
define_native_accessor(vm.names.resizable, resizable_getter, {}, Attribute::Configurable);
|
||||||
|
|
||||||
// 25.1.5.4 ArrayBuffer.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-arraybuffer.prototype-@@tostringtag
|
// 25.1.5.4 ArrayBuffer.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-arraybuffer.prototype-@@tostringtag
|
||||||
define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, vm.names.ArrayBuffer.as_string()), Attribute::Configurable);
|
define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, vm.names.ArrayBuffer.as_string()), Attribute::Configurable);
|
||||||
|
@ -145,4 +148,44 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::byte_length_getter)
|
||||||
return Value(length);
|
return Value(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.3.2 get ArrayBuffer.prototype.maxByteLength, https://tc39.es/proposal-resizablearraybuffer/#sec-get-arraybuffer.prototype.maxbytelength
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::max_byte_length_getter)
|
||||||
|
{
|
||||||
|
// 1. Let O be the this value.
|
||||||
|
// 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
|
||||||
|
auto* array_buffer_object = TRY(typed_this_value(global_object));
|
||||||
|
|
||||||
|
// 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
|
||||||
|
// FIXME: Check for shared buffer
|
||||||
|
|
||||||
|
// 4. If IsDetachedBuffer(O) is true, return +0𝔽.
|
||||||
|
if (array_buffer_object->is_detached())
|
||||||
|
return Value(0);
|
||||||
|
|
||||||
|
// 5. If IsResizableArrayBuffer(O) is true, then
|
||||||
|
if (array_buffer_object->is_resizable_array_buffer()) {
|
||||||
|
// a. Let length be O.[[ArrayBufferMaxByteLength]].
|
||||||
|
return array_buffer_object->max_byte_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Else
|
||||||
|
// a. Let length be O.[[ArrayBufferByteLength]].
|
||||||
|
// 7. Return 𝔽(length).
|
||||||
|
return array_buffer_object->byte_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.3.3 get ArrayBuffer.prototype.resizable, https://tc39.es/proposal-resizablearraybuffer/#sec-get-arraybuffer.prototype.resizable
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::resizable_getter)
|
||||||
|
{
|
||||||
|
// 1. Let O be the this value.
|
||||||
|
// 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
|
||||||
|
auto* array_buffer_object = TRY(typed_this_value(global_object));
|
||||||
|
|
||||||
|
// 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
|
||||||
|
// FIXME: Check for shared buffer
|
||||||
|
|
||||||
|
// 4. Return IsResizableArrayBuffer(O).
|
||||||
|
return array_buffer_object->is_resizable_array_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ public:
|
||||||
private:
|
private:
|
||||||
JS_DECLARE_NATIVE_FUNCTION(slice);
|
JS_DECLARE_NATIVE_FUNCTION(slice);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(byte_length_getter);
|
JS_DECLARE_NATIVE_FUNCTION(byte_length_getter);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(max_byte_length_getter);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(resizable_getter);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,6 +380,7 @@ namespace JS {
|
||||||
P(reject) \
|
P(reject) \
|
||||||
P(relativeTo) \
|
P(relativeTo) \
|
||||||
P(repeat) \
|
P(repeat) \
|
||||||
|
P(resizable) \
|
||||||
P(resolve) \
|
P(resolve) \
|
||||||
P(resolvedOptions) \
|
P(resolvedOptions) \
|
||||||
P(reverse) \
|
P(reverse) \
|
||||||
|
|
|
@ -11,3 +11,57 @@ test("ArrayBuffer constructor must be invoked with 'new'", () => {
|
||||||
ArrayBuffer();
|
ArrayBuffer();
|
||||||
}).toThrowWithMessage(TypeError, "ArrayBuffer constructor must be called with 'new'");
|
}).toThrowWithMessage(TypeError, "ArrayBuffer constructor must be called with 'new'");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("resizable array buffer", () => {
|
||||||
|
test("construct with options", () => {
|
||||||
|
expect(new ArrayBuffer(5, { maxByteLength: 5 })).toBeInstanceOf(ArrayBuffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("resizable when provided max byte length", () => {
|
||||||
|
expect(new ArrayBuffer(1).resizable).toEqual(false);
|
||||||
|
expect(new ArrayBuffer(1, {}).resizable).toEqual(false);
|
||||||
|
expect(new ArrayBuffer(1, { maxByteLength: undefined }).resizable).toEqual(false);
|
||||||
|
expect(new ArrayBuffer(1, { maxByteLength: 1 }).resizable).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("byte length must be shorter than max byte length", () => {
|
||||||
|
expect(() => {
|
||||||
|
new ArrayBuffer(1, { maxByteLength: 0 });
|
||||||
|
}).toThrowWithMessage(RangeError, "Byte length exceeds maxByteLength option");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("max byte length cannot be too large", () => {
|
||||||
|
expect(() => {
|
||||||
|
new ArrayBuffer(0, { maxByteLength: 9007199254740992 });
|
||||||
|
}).toThrowWithMessage(RangeError, "Index must be a positive integer");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("max byte length cannot be negative", () => {
|
||||||
|
expect(() => {
|
||||||
|
new ArrayBuffer(0, { maxByteLength: -1 });
|
||||||
|
}).toThrowWithMessage(RangeError, "Index must be a positive integer");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("invalid max byte length object", () => {
|
||||||
|
expect(() => {
|
||||||
|
new ArrayBuffer(0, {
|
||||||
|
maxByteLength: {
|
||||||
|
toString: function () {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
valueOf: function () {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}).toThrowWithMessage(TypeError, "Cannot convert object to number");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new ArrayBuffer(0, {
|
||||||
|
get maxByteLength() {
|
||||||
|
throw "Exception";
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue