소스 검색

LibJS: Add all of the DataView.prototype.get* methods

Idan Horowitz 4 년 전
부모
커밋
c54b9a6920

+ 13 - 0
Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h

@@ -47,6 +47,19 @@ public:
     static SignedBigInteger import_data(const StringView& data) { return import_data((const u8*)data.characters_without_null_termination(), data.length()); }
     static SignedBigInteger import_data(const StringView& data) { return import_data((const u8*)data.characters_without_null_termination(), data.length()); }
     static SignedBigInteger import_data(const u8* ptr, size_t length);
     static SignedBigInteger import_data(const u8* ptr, size_t length);
 
 
+    static SignedBigInteger create_from(i64 value)
+    {
+        auto sign = false;
+        u64 unsigned_value;
+        if (value < 0) {
+            unsigned_value = static_cast<u64>(-(value + 1)) + 1;
+            sign = true;
+        } else {
+            unsigned_value = value;
+        }
+        return SignedBigInteger { UnsignedBigInteger::create_from(unsigned_value), sign };
+    }
+
     size_t export_data(Bytes, bool remove_leading_zeros = false) const;
     size_t export_data(Bytes, bool remove_leading_zeros = false) const;
 
 
     static SignedBigInteger from_base10(StringView str);
     static SignedBigInteger from_base10(StringView str);

+ 10 - 0
Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h

@@ -41,6 +41,16 @@ public:
         return UnsignedBigInteger(ptr, length);
         return UnsignedBigInteger(ptr, length);
     }
     }
 
 
+    static UnsignedBigInteger create_from(u64 value)
+    {
+        VERIFY(sizeof(Word) == 4);
+        UnsignedBigInteger integer;
+        integer.m_words.resize(2);
+        integer.m_words[0] = static_cast<Word>(value & 0xFFFFFFFF);
+        integer.m_words[1] = static_cast<Word>((value >> 32) & 0xFFFFFFFF);
+        return integer;
+    }
+
     size_t export_data(Bytes, bool remove_leading_zeros = false) const;
     size_t export_data(Bytes, bool remove_leading_zeros = false) const;
 
 
     static UnsignedBigInteger from_base10(const String& str);
     static UnsignedBigInteger from_base10(const String& str);

+ 57 - 0
Userland/Libraries/LibJS/Runtime/ArrayBuffer.h

@@ -8,6 +8,7 @@
 
 
 #include <AK/ByteBuffer.h>
 #include <AK/ByteBuffer.h>
 #include <AK/Variant.h>
 #include <AK/Variant.h>
+#include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/Object.h>
 #include <LibJS/Runtime/Object.h>
 
 
 namespace JS {
 namespace JS {
@@ -33,6 +34,13 @@ 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>(); }
 
 
+    enum Order {
+        SeqCst,
+        Unordered
+    };
+    template<typename type>
+    Value get_value(size_t byte_index, bool is_typed_array, Order, bool is_little_endian = true);
+
 private:
 private:
     virtual void visit_edges(Visitor&) override;
     virtual void visit_edges(Visitor&) override;
 
 
@@ -51,4 +59,53 @@ private:
     Value m_detach_key;
     Value m_detach_key;
 };
 };
 
 
+// 25.1.2.9 RawBytesToNumeric ( type, rawBytes, isLittleEndian ), https://tc39.es/ecma262/#sec-rawbytestonumeric
+template<typename T>
+static Value raw_bytes_to_numeric(GlobalObject& global_object, ByteBuffer raw_value, bool is_little_endian)
+{
+    if (!is_little_endian) {
+        VERIFY(raw_value.size() % 2 == 0);
+        for (size_t i = 0; i < raw_value.size() / 2; ++i)
+            swap(raw_value[i], raw_value[raw_value.size() - 1 - i]);
+    }
+    if constexpr (IsSame<T, float>) {
+        float value;
+        raw_value.span().copy_to({ &value, sizeof(float) });
+        if (isnan(value))
+            return js_nan();
+        return Value(value);
+    }
+    if constexpr (IsSame<T, double>) {
+        double value;
+        raw_value.span().copy_to({ &value, sizeof(double) });
+        if (isnan(value))
+            return js_nan();
+        return Value(value);
+    }
+    if constexpr (!IsIntegral<T>)
+        VERIFY_NOT_REACHED();
+    T int_value = 0;
+    raw_value.span().copy_to({ &int_value, sizeof(T) });
+    if constexpr (sizeof(T) == 8) {
+        if constexpr (IsSigned<T>)
+            return js_bigint(global_object.heap(), Crypto::SignedBigInteger::create_from(int_value));
+        else
+            return js_bigint(global_object.heap(), Crypto::SignedBigInteger { Crypto::UnsignedBigInteger::create_from(int_value) });
+    } else {
+        return Value(int_value);
+    }
+}
+
+// 25.1.2.10 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isTypedArray, order [ , isLittleEndian ] ), https://tc39.es/ecma262/#sec-getvaluefrombuffer
+template<typename T>
+Value ArrayBuffer::get_value(size_t byte_index, [[maybe_unused]] bool is_typed_array, Order, bool is_little_endian)
+{
+    auto element_size = sizeof(T);
+
+    // FIXME: Check for shared buffer
+
+    auto raw_value = buffer_impl().slice(byte_index, element_size);
+    return raw_bytes_to_numeric<T>(global_object(), move(raw_value), is_little_endian);
+}
+
 }
 }

+ 10 - 0
Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h

@@ -128,10 +128,17 @@ namespace JS {
     P(fround)                                \
     P(fround)                                \
     P(gc)                                    \
     P(gc)                                    \
     P(get)                                   \
     P(get)                                   \
+    P(getBigInt64)                           \
+    P(getBigUint64)                          \
     P(getDate)                               \
     P(getDate)                               \
     P(getDay)                                \
     P(getDay)                                \
+    P(getFloat32)                            \
+    P(getFloat64)                            \
     P(getFullYear)                           \
     P(getFullYear)                           \
     P(getHours)                              \
     P(getHours)                              \
+    P(getInt8)                               \
+    P(getInt16)                              \
+    P(getInt32)                              \
     P(getMilliseconds)                       \
     P(getMilliseconds)                       \
     P(getMinutes)                            \
     P(getMinutes)                            \
     P(getMonth)                              \
     P(getMonth)                              \
@@ -142,6 +149,9 @@ namespace JS {
     P(getSeconds)                            \
     P(getSeconds)                            \
     P(getTime)                               \
     P(getTime)                               \
     P(getTimezoneOffset)                     \
     P(getTimezoneOffset)                     \
+    P(getUint8)                              \
+    P(getUint16)                             \
+    P(getUint32)                             \
     P(getUTCDate)                            \
     P(getUTCDate)                            \
     P(getUTCDay)                             \
     P(getUTCDay)                             \
     P(getUTCFullYear)                        \
     P(getUTCFullYear)                        \

+ 105 - 0
Userland/Libraries/LibJS/Runtime/DataViewPrototype.cpp

@@ -17,6 +17,18 @@ void DataViewPrototype::initialize(GlobalObject& global_object)
 {
 {
     auto& vm = this->vm();
     auto& vm = this->vm();
     Object::initialize(global_object);
     Object::initialize(global_object);
+    u8 attr = Attribute::Writable | Attribute::Configurable;
+
+    define_native_function(vm.names.getBigInt64, get_big_int_64, 1, attr);
+    define_native_function(vm.names.getBigUint64, get_big_uint_64, 1, attr);
+    define_native_function(vm.names.getFloat32, get_float_32, 1, attr);
+    define_native_function(vm.names.getFloat64, get_float_64, 1, attr);
+    define_native_function(vm.names.getInt8, get_int_8, 1, attr);
+    define_native_function(vm.names.getInt16, get_int_16, 1, attr);
+    define_native_function(vm.names.getInt32, get_int_32, 1, attr);
+    define_native_function(vm.names.getUint8, get_uint_8, 1, attr);
+    define_native_function(vm.names.getUint16, get_uint_16, 1, attr);
+    define_native_function(vm.names.getUint32, get_uint_32, 1, attr);
 
 
     define_native_accessor(vm.names.buffer, buffer_getter, {}, Attribute::Configurable);
     define_native_accessor(vm.names.buffer, buffer_getter, {}, Attribute::Configurable);
     define_native_accessor(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
     define_native_accessor(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
@@ -40,6 +52,99 @@ static DataView* typed_this(VM& vm, GlobalObject& global_object)
     return static_cast<DataView*>(&this_value.as_object());
     return static_cast<DataView*>(&this_value.as_object());
 }
 }
 
 
+// 25.3.1.1 GetViewValue ( view, requestIndex, isLittleEndian, type ), https://tc39.es/ecma262/#sec-getviewvalue
+template<typename T>
+static Value get_view_value(GlobalObject& global_object, Value request_index, Value is_little_endian)
+{
+    auto& vm = global_object.vm();
+    auto* view = typed_this(vm, global_object);
+    if (!view)
+        return {};
+
+    auto get_index = request_index.to_index(global_object);
+    if (vm.exception())
+        return {};
+    auto little_endian = is_little_endian.to_boolean();
+
+    auto buffer = view->viewed_array_buffer();
+    if (buffer->is_detached()) {
+        vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
+        return {};
+    }
+
+    auto view_offset = view->byte_offset();
+    auto view_size = view->byte_length();
+
+    auto element_size = sizeof(T);
+    if (get_index + element_size > view_size) {
+        vm.throw_exception<RangeError>(global_object, ErrorType::DataViewOutOfRangeByteOffset, get_index, view_size);
+        return {};
+    }
+
+    auto buffer_index = get_index + view_offset;
+    return buffer->get_value<T>(buffer_index, false, ArrayBuffer::Order::Unordered, little_endian);
+}
+
+// 25.3.4.5 DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getbigint64
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_big_int_64)
+{
+    return get_view_value<i64>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.6 DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getbiguint64
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_big_uint_64)
+{
+    return get_view_value<u64>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.7 DataView.prototype.getFloat32 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getfloat32
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_float_32)
+{
+    return get_view_value<float>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.8 DataView.prototype.getFloat64 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getfloat64
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_float_64)
+{
+    return get_view_value<double>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.9 DataView.prototype.getInt8 ( byteOffset ), https://tc39.es/ecma262/#sec-dataview.prototype.getint8
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_int_8)
+{
+    return get_view_value<i8>(global_object, vm.argument(0), Value(true));
+}
+
+// 25.3.4.10 DataView.prototype.getInt16 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getint16
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_int_16)
+{
+    return get_view_value<i16>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.11 DataView.prototype.getInt32 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getint32
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_int_32)
+{
+    return get_view_value<i32>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.12 DataView.prototype.getUint8 ( byteOffset ), https://tc39.es/ecma262/#sec-dataview.prototype.getuint8
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_uint_8)
+{
+    return get_view_value<u8>(global_object, vm.argument(0), Value(true));
+}
+
+// 25.3.4.13 DataView.prototype.getUint16 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getuint16
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_uint_16)
+{
+    return get_view_value<u16>(global_object, vm.argument(0), vm.argument(1));
+}
+
+// 25.3.4.14 DataView.prototype.getUint32 ( byteOffset [ , littleEndian ] ), https://tc39.es/ecma262/#sec-dataview.prototype.getuint32
+JS_DEFINE_NATIVE_FUNCTION(DataViewPrototype::get_uint_32)
+{
+    return get_view_value<u32>(global_object, vm.argument(0), vm.argument(1));
+}
+
 // 25.3.4.1 get DataView.prototype.buffer, https://tc39.es/ecma262/#sec-get-dataview.prototype.buffer
 // 25.3.4.1 get DataView.prototype.buffer, https://tc39.es/ecma262/#sec-get-dataview.prototype.buffer
 JS_DEFINE_NATIVE_GETTER(DataViewPrototype::buffer_getter)
 JS_DEFINE_NATIVE_GETTER(DataViewPrototype::buffer_getter)
 {
 {

+ 11 - 0
Userland/Libraries/LibJS/Runtime/DataViewPrototype.h

@@ -19,6 +19,17 @@ public:
     virtual ~DataViewPrototype() override;
     virtual ~DataViewPrototype() override;
 
 
 private:
 private:
+    JS_DECLARE_NATIVE_FUNCTION(get_big_int_64);
+    JS_DECLARE_NATIVE_FUNCTION(get_big_uint_64);
+    JS_DECLARE_NATIVE_FUNCTION(get_float_32);
+    JS_DECLARE_NATIVE_FUNCTION(get_float_64);
+    JS_DECLARE_NATIVE_FUNCTION(get_int_8);
+    JS_DECLARE_NATIVE_FUNCTION(get_int_16);
+    JS_DECLARE_NATIVE_FUNCTION(get_int_32);
+    JS_DECLARE_NATIVE_FUNCTION(get_uint_8);
+    JS_DECLARE_NATIVE_FUNCTION(get_uint_16);
+    JS_DECLARE_NATIVE_FUNCTION(get_uint_32);
+
     JS_DECLARE_NATIVE_GETTER(buffer_getter);
     JS_DECLARE_NATIVE_GETTER(buffer_getter);
     JS_DECLARE_NATIVE_GETTER(byte_length_getter);
     JS_DECLARE_NATIVE_GETTER(byte_length_getter);
     JS_DECLARE_NATIVE_GETTER(byte_offset_getter);
     JS_DECLARE_NATIVE_GETTER(byte_offset_getter);