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

This commit is contained in:
Idan Horowitz 2021-06-14 01:57:15 +03:00 committed by Linus Groh
parent e4d267d4fb
commit c54b9a6920
Notes: sideshowbarker 2024-07-18 12:17:06 +09:00
6 changed files with 206 additions and 0 deletions

View File

@ -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 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;
static SignedBigInteger from_base10(StringView str);

View File

@ -41,6 +41,16 @@ public:
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;
static UnsignedBigInteger from_base10(const String& str);

View File

@ -8,6 +8,7 @@
#include <AK/ByteBuffer.h>
#include <AK/Variant.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
@ -33,6 +34,13 @@ public:
void detach_buffer() { m_buffer = 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:
virtual void visit_edges(Visitor&) override;
@ -51,4 +59,53 @@ private:
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);
}
}

View File

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

View File

@ -17,6 +17,18 @@ void DataViewPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
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.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());
}
// 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
JS_DEFINE_NATIVE_GETTER(DataViewPrototype::buffer_getter)
{

View File

@ -19,6 +19,17 @@ public:
virtual ~DataViewPrototype() override;
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(byte_length_getter);
JS_DECLARE_NATIVE_GETTER(byte_offset_getter);