summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-06-10 22:37:56 +0300
committerLinus Groh <mail@linusgroh.de>2021-06-10 22:44:26 +0100
commit8dc86c6aadb6114f5f32809ed3e3a295648ea549 (patch)
treeed27257cb6d1edbb4106ec8d26a03c81bbac0162
parentb041108a1e4afc72905be9b60285890ddf41ad48 (diff)
downloadserenity-8dc86c6aadb6114f5f32809ed3e3a295648ea549.zip
LibJS: Bring ArrayBuffer.prototype.slice closer to spec
The exception order was incorrect in the old implementation, and it did not use the Symbol.species constructor as required by the spec.
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp11
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArrayBuffer.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp73
-rw-r--r--Userland/Libraries/LibJS/Runtime/ErrorTypes.h2
4 files changed, 51 insertions, 37 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp
index fc168cabf2..a34955dd9c 100644
--- a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp
+++ b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp
@@ -14,11 +14,6 @@ ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, size_t byte_size)
return global_object.heap().allocate<ArrayBuffer>(global_object, byte_size, *global_object.array_buffer_prototype());
}
-ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, ByteBuffer& buffer)
-{
- return global_object.heap().allocate<ArrayBuffer>(global_object, buffer, *global_object.array_buffer_prototype());
-}
-
ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, ByteBuffer* buffer)
{
return global_object.heap().allocate<ArrayBuffer>(global_object, buffer, *global_object.array_buffer_prototype());
@@ -30,12 +25,6 @@ ArrayBuffer::ArrayBuffer(size_t byte_size, Object& prototype)
{
}
-ArrayBuffer::ArrayBuffer(ByteBuffer& buffer, Object& prototype)
- : Object(prototype)
- , m_buffer(buffer)
-{
-}
-
ArrayBuffer::ArrayBuffer(ByteBuffer* buffer, Object& prototype)
: Object(prototype)
, m_buffer(buffer)
diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h
index d731afc322..db2e13b605 100644
--- a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h
+++ b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h
@@ -17,11 +17,9 @@ class ArrayBuffer : public Object {
public:
static ArrayBuffer* create(GlobalObject&, size_t);
- static ArrayBuffer* create(GlobalObject&, ByteBuffer&);
static ArrayBuffer* create(GlobalObject&, ByteBuffer*);
ArrayBuffer(size_t, Object& prototype);
- ArrayBuffer(ByteBuffer& buffer, Object& prototype);
ArrayBuffer(ByteBuffer* buffer, Object& prototype);
virtual ~ArrayBuffer() override;
diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp
index ebfc37d96a..db345379ed 100644
--- a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp
@@ -6,6 +6,7 @@
#include <AK/Function.h>
#include <LibJS/Runtime/ArrayBuffer.h>
+#include <LibJS/Runtime/ArrayBufferConstructor.h>
#include <LibJS/Runtime/ArrayBufferPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
@@ -49,9 +50,6 @@ static ArrayBuffer* array_buffer_object_from(VM& vm, GlobalObject& global_object
// 25.1.5.3 ArrayBuffer.prototype.slice, https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice)
{
- const auto start = vm.argument(0);
- const auto end = vm.argument(1);
-
auto array_buffer_object = array_buffer_object_from(vm, global_object);
if (!array_buffer_object)
return {};
@@ -59,38 +57,65 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice)
// FIXME: Check for shared buffer
// FIXME: Check for detached buffer
- const auto len = array_buffer_object->byte_length();
+ auto length = array_buffer_object->byte_length();
- const auto relative_start = start.is_negative_infinity()
- ? 0
- : start.to_integer_or_infinity(global_object);
+ auto relative_start = vm.argument(0).to_integer_or_infinity(global_object);
if (vm.exception())
return {};
- const auto first = relative_start < 0
- ? max(len + relative_start, 0.0)
- : min(relative_start, static_cast<double>(len));
+ double first;
+ if (relative_start < 0)
+ first = max(length + relative_start, 0.0);
+ else
+ first = min(relative_start, (double)length);
- const auto relative_end = end.is_undefined()
- ? len
- : end.to_integer_or_infinity(global_object);
+ auto relative_end = vm.argument(1).is_undefined() ? length : vm.argument(1).to_integer_or_infinity(global_object);
if (vm.exception())
return {};
- double final_;
- if (end.is_negative_infinity())
- final_ = 0;
- else if (relative_end < 0)
- final_ = max(len + relative_end, 0.0);
+ double final;
+ if (relative_end < 0)
+ final = max(length + relative_end, 0.0);
else
- final_ = min(relative_end, static_cast<double>(len));
+ final = min(relative_end, (double)length);
+
+ auto new_length = max(final - first, 0.0);
+
+ auto constructor = species_constructor(global_object, *array_buffer_object, *global_object.array_buffer_constructor());
+ if (vm.exception())
+ return {};
- const auto new_len = max(final_ - first, 0.0);
+ MarkedValueList arguments(vm.heap());
+ arguments.append(Value(new_length));
+ auto new_array_buffer = vm.construct(*constructor, *constructor, move(arguments));
+ if (vm.exception())
+ return {};
+
+ if (!new_array_buffer.is_object() || !is<ArrayBuffer>(new_array_buffer.as_object())) {
+ vm.throw_exception<TypeError>(global_object, ErrorType::SpeciesConstructorDidNotCreate, "an ArrayBuffer");
+ return {};
+ }
+ auto* new_array_buffer_object = static_cast<ArrayBuffer*>(&new_array_buffer.as_object());
+
+ // FIXME: Check for shared buffer
+ // FIXME: Check for detached buffer
+ if (same_value(new_array_buffer_object, array_buffer_object)) {
+ vm.throw_exception<TypeError>(global_object, ErrorType::SpeciesConstructorReturned, "same ArrayBuffer instance");
+ return {};
+ }
+ if (new_array_buffer_object->byte_length() < new_length) {
+ vm.throw_exception<TypeError>(global_object, ErrorType::SpeciesConstructorReturned, "an ArrayBuffer smaller than requested");
+ return {};
+ }
+
+ if (array_buffer_object->is_detached()) {
+ vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
+ return {};
+ }
- // FIXME: this is a bit more involved in the specification
- auto sliced = array_buffer_object->buffer().slice(first, new_len);
- auto buffer = ArrayBuffer::create(global_object, sliced);
- return buffer;
+ // This is ugly, is there a better way to do this?
+ array_buffer_object->buffer().span().slice(first, new_length).copy_to(new_array_buffer_object->buffer().span());
+ return new_array_buffer_object;
}
JS_DEFINE_NATIVE_GETTER(ArrayBufferPrototype::byte_length_getter)
diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
index fb416cdd7c..014436c121 100644
--- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
+++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
@@ -140,6 +140,8 @@
M(RegExpCompileError, "RegExp compile error: {}") \
M(RegExpObjectBadFlag, "Invalid RegExp flag '{}'") \
M(RegExpObjectRepeatedFlag, "Repeated RegExp flag '{}'") \
+ M(SpeciesConstructorDidNotCreate, "Species constructor did not create {}") \
+ M(SpeciesConstructorReturned, "Species constructor returned {}") \
M(StringRawCannotConvert, "Cannot convert property 'raw' to object from {}") \
M(StringRepeatCountMustBe, "repeat count must be a {} number") \
M(ThisHasNotBeenInitialized, "|this| has not been initialized") \