diff --git a/Userland/Libraries/LibJS/Contrib/Test262/$262Object.cpp b/Userland/Libraries/LibJS/Contrib/Test262/$262Object.cpp index a1be5b39df1..8975b27b4f0 100644 --- a/Userland/Libraries/LibJS/Contrib/Test262/$262Object.cpp +++ b/Userland/Libraries/LibJS/Contrib/Test262/$262Object.cpp @@ -62,17 +62,14 @@ JS_DEFINE_NATIVE_FUNCTION($262Object::create_realm) return Value(realm->$262()); } -// 25.1.2.3 DetachArrayBuffer, https://tc39.es/ecma262/#sec-detacharraybuffer JS_DEFINE_NATIVE_FUNCTION($262Object::detach_array_buffer) { auto array_buffer = vm.argument(0); if (!array_buffer.is_object() || !is(array_buffer.as_object())) return vm.throw_completion(global_object); + auto& array_buffer_object = static_cast(array_buffer.as_object()); - if (!same_value(array_buffer_object.detach_key(), vm.argument(1))) - return vm.throw_completion(global_object); - array_buffer_object.detach_buffer(); - return js_null(); + return JS::detach_array_buffer(global_object, array_buffer_object, vm.argument(1)); } JS_DEFINE_NATIVE_FUNCTION($262Object::eval_script) diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp index 4e71f3adf57..35766ba9c09 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.cpp @@ -96,6 +96,30 @@ ThrowCompletionOr allocate_array_buffer(GlobalObject& global_objec return obj; } +// 25.1.2.3 DetachArrayBuffer ( arrayBuffer [ , key ] ), https://tc39.es/ecma262/#sec-detacharraybuffer +ThrowCompletionOr detach_array_buffer(GlobalObject& global_object, ArrayBuffer& array_buffer, Optional key) +{ + auto& vm = global_object.vm(); + + // 1. Assert: IsSharedArrayBuffer(arrayBuffer) is false. + // FIXME: Check for shared buffer + + // 2. If key is not present, set key to undefined. + if (!key.has_value()) + key = js_undefined(); + + // 3. If SameValue(arrayBuffer.[[ArrayBufferDetachKey]], key) is false, throw a TypeError exception. + if (!same_value(array_buffer.detach_key(), *key)) + return vm.throw_completion(global_object, ErrorType::DetachKeyMismatch, *key, array_buffer.detach_key()); + + // 4. Set arrayBuffer.[[ArrayBufferData]] to null. + // 5. Set arrayBuffer.[[ArrayBufferByteLength]] to 0. + array_buffer.detach_buffer(); + + // 6. Return unused. + return js_null(); +} + // 25.1.2.4 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength, cloneConstructor ), https://tc39.es/ecma262/#sec-clonearraybuffer ThrowCompletionOr clone_array_buffer(GlobalObject& global_object, ArrayBuffer& source_buffer, size_t source_byte_offset, size_t source_length, FunctionObject& clone_constructor) { diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h index 7a728a79659..0dddc1d1bae 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h +++ b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h @@ -81,6 +81,7 @@ private: }; ThrowCompletionOr allocate_array_buffer(GlobalObject&, FunctionObject& constructor, size_t byte_length, Optional max_byte_length = {}); +ThrowCompletionOr detach_array_buffer(GlobalObject&, ArrayBuffer& array_buffer, Optional key = {}); ThrowCompletionOr clone_array_buffer(GlobalObject&, ArrayBuffer& source_buffer, size_t source_byte_offset, size_t source_length, FunctionObject& clone_constructor); // 25.1.2.9 RawBytesToNumeric ( type, rawBytes, isLittleEndian ), https://tc39.es/ecma262/#sec-rawbytestonumeric diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index 90b51982eda..64986a74d8a 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -29,6 +29,7 @@ M(DerivedConstructorReturningInvalidValue, "Derived constructor return invalid value") \ M(DescWriteNonWritable, "Cannot write to non-writable property '{}'") \ M(DetachedArrayBuffer, "ArrayBuffer is detached") \ + M(DetachKeyMismatch, "Provided detach key {} does not match the ArrayBuffer's detach key {}") \ M(DivisionByZero, "Division by zero") \ M(DynamicImportNotAllowed, "Dynamic Imports are not allowed") \ M(FinalizationRegistrySameTargetAndValue, "Target and held value must not be the same") \