From f9d8e234b2cbc23c6854c041262744ef5cdfd6f4 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sun, 11 Jul 2021 13:20:28 -0400 Subject: [PATCH] LibJS: Implement Atomics.or --- .../Libraries/LibJS/Runtime/AtomicsObject.cpp | 19 +++++ .../Libraries/LibJS/Runtime/AtomicsObject.h | 1 + .../LibJS/Runtime/CommonPropertyNames.h | 1 + .../Tests/builtins/Atomics/Atomics.or.js | 70 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.or.js diff --git a/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp b/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp index c149ee7fe4..e1dfca91bb 100644 --- a/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp @@ -120,6 +120,7 @@ void AtomicsObject::initialize(GlobalObject& global_object) define_native_function(vm.names.add, add, 3, attr); define_native_function(vm.names.and_, and_, 3, attr); define_native_function(vm.names.load, load, 2, attr); + define_native_function(vm.names.or_, or_, 3, attr); // 25.4.15 Atomics [ @@toStringTag ], https://tc39.es/ecma262/#sec-atomics-@@tostringtag define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Atomics"), Attribute::Configurable); @@ -184,4 +185,22 @@ JS_DEFINE_NATIVE_FUNCTION(AtomicsObject::load) return typed_array->get_value_from_buffer(*indexed_position, ArrayBuffer::Order::SeqCst, true); } +// 25.4.9 Atomics.or ( typedArray, index, value ), https://tc39.es/ecma262/#sec-atomics.or +JS_DEFINE_NATIVE_FUNCTION(AtomicsObject::or_) +{ + auto* typed_array = typed_array_from(global_object, vm.argument(0)); + if (!typed_array) + return {}; + + auto atomic_or = [](auto* storage, auto value) { return AK::atomic_fetch_or(storage, value); }; + +#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \ + if (is(typed_array)) \ + return perform_atomic_operation(global_object, *typed_array, move(atomic_or)); + JS_ENUMERATE_TYPED_ARRAYS +#undef __JS_ENUMERATE + + VERIFY_NOT_REACHED(); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/AtomicsObject.h b/Userland/Libraries/LibJS/Runtime/AtomicsObject.h index bf15d19594..52a989cc1c 100644 --- a/Userland/Libraries/LibJS/Runtime/AtomicsObject.h +++ b/Userland/Libraries/LibJS/Runtime/AtomicsObject.h @@ -22,6 +22,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(add); JS_DECLARE_NATIVE_FUNCTION(and_); JS_DECLARE_NATIVE_FUNCTION(load); + JS_DECLARE_NATIVE_FUNCTION(or_); }; } diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 1b5fb699cd..640298b1f8 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -355,6 +355,7 @@ struct CommonPropertyNames { PropertyName catch_ { "catch", PropertyName::StringMayBeNumber::No }; PropertyName delete_ { "delete", PropertyName::StringMayBeNumber::No }; PropertyName for_ { "for", PropertyName::StringMayBeNumber::No }; + PropertyName or_ { "or", PropertyName::StringMayBeNumber::No }; PropertyName register_ { "register", PropertyName::StringMayBeNumber::No }; PropertyName return_ { "return", PropertyName::StringMayBeNumber::No }; PropertyName throw_ { "throw", PropertyName::StringMayBeNumber::No }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.or.js b/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.or.js new file mode 100644 index 0000000000..72c4eb118c --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.or.js @@ -0,0 +1,70 @@ +test("invariants", () => { + expect(Atomics.or).toHaveLength(3); +}); + +test("error cases", () => { + expect(() => { + Atomics.or("not an array", 0, 1); + }).toThrow(TypeError); + + expect(() => { + const bad_array_type = new Float32Array(4); + Atomics.or(bad_array_type, 0, 1); + }).toThrow(TypeError); + + expect(() => { + const bad_array_type = new Uint8ClampedArray(4); + Atomics.or(bad_array_type, 0, 1); + }).toThrow(TypeError); + + expect(() => { + const array = new Int32Array(4); + Atomics.or(array, 100, 1); + }).toThrow(RangeError); +}); + +test("basic functionality (non-BigInt)", () => { + [Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array].forEach(ArrayType => { + const array = new ArrayType(2); + array[0] = 0b0000; + array[1] = 0b0101; + + expect(Atomics.or(array, 0, 0b0000)).toBe(0b0000); + expect(array).toEqual([0b0000, 0b0101]); + + expect(Atomics.or(array, 0, 0b1111)).toBe(0b0000); + expect(array).toEqual([0b1111, 0b0101]); + + expect(Atomics.or(array, 1, 0b0101)).toBe(0b0101); + expect(array).toEqual([0b1111, 0b0101]); + + expect(Atomics.or(array, 1, 0b1000)).toBe(0b0101); + expect(array).toEqual([0b1111, 0b1101]); + + expect(Atomics.or(array, 1, 0b0010)).toBe(0b1101); + expect(array).toEqual([0b1111, 0b1111]); + }); +}); + +test("basic functionality (BigInt)", () => { + [BigInt64Array, BigUint64Array].forEach(ArrayType => { + const array = new ArrayType(2); + array[0] = 0b0000n; + array[1] = 0b0101n; + + expect(Atomics.or(array, 0, 0b0000n)).toBe(0b0000n); + expect(array).toEqual([0b0000n, 0b0101n]); + + expect(Atomics.or(array, 0, 0b1111n)).toBe(0b0000n); + expect(array).toEqual([0b1111n, 0b0101n]); + + expect(Atomics.or(array, 1, 0b0101n)).toBe(0b0101n); + expect(array).toEqual([0b1111n, 0b0101n]); + + expect(Atomics.or(array, 1, 0b1000n)).toBe(0b0101n); + expect(array).toEqual([0b1111n, 0b1101n]); + + expect(Atomics.or(array, 1, 0b0010n)).toBe(0b1101n); + expect(array).toEqual([0b1111n, 0b1111n]); + }); +});