mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Add six typed arrays (signed and unsigned 8/16/32-bit)
This patch adds six of the standard type arrays and tries to share as much code as possible: - Uint8Array - Uint16Array - Uint32Array - Int8Array - Int16Array - Int32Array
This commit is contained in:
parent
93feb7a81f
commit
3565d3c60c
Notes:
sideshowbarker
2024-07-19 01:07:26 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/3565d3c60c4
15 changed files with 402 additions and 43 deletions
|
@ -72,6 +72,7 @@ set(SOURCES
|
|||
Runtime/SymbolConstructor.cpp
|
||||
Runtime/SymbolObject.cpp
|
||||
Runtime/SymbolPrototype.cpp
|
||||
Runtime/TypedArray.cpp
|
||||
Runtime/Uint8ClampedArray.cpp
|
||||
Runtime/VM.cpp
|
||||
Runtime/Value.cpp
|
||||
|
|
|
@ -45,28 +45,36 @@
|
|||
void name([[maybe_unused]] JS::VM& vm, [[maybe_unused]] JS::GlobalObject& global_object, JS::Value value)
|
||||
|
||||
// NOTE: Proxy is not included here as it doesn't have a prototype - m_proxy_constructor is initialized separately.
|
||||
#define JS_ENUMERATE_NATIVE_OBJECTS \
|
||||
__JS_ENUMERATE(Array, array, ArrayPrototype, ArrayConstructor) \
|
||||
__JS_ENUMERATE(BigIntObject, bigint, BigIntPrototype, BigIntConstructor) \
|
||||
__JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor) \
|
||||
__JS_ENUMERATE(Date, date, DatePrototype, DateConstructor) \
|
||||
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor) \
|
||||
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor) \
|
||||
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor) \
|
||||
__JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor) \
|
||||
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor) \
|
||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor) \
|
||||
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor)
|
||||
#define JS_ENUMERATE_NATIVE_OBJECTS \
|
||||
__JS_ENUMERATE(Array, array, ArrayPrototype, ArrayConstructor, void) \
|
||||
__JS_ENUMERATE(BigIntObject, bigint, BigIntPrototype, BigIntConstructor, void) \
|
||||
__JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor, void) \
|
||||
__JS_ENUMERATE(Date, date, DatePrototype, DateConstructor, void) \
|
||||
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor, void) \
|
||||
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor, void) \
|
||||
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor, void) \
|
||||
__JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor, void) \
|
||||
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \
|
||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \
|
||||
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void)
|
||||
|
||||
#define JS_ENUMERATE_ERROR_SUBCLASSES \
|
||||
__JS_ENUMERATE(EvalError, eval_error, EvalErrorPrototype, EvalErrorConstructor) \
|
||||
__JS_ENUMERATE(InternalError, internal_error, InternalErrorPrototype, InternalErrorConstructor) \
|
||||
__JS_ENUMERATE(InvalidCharacterError, invalid_character_error, InvalidCharacterErrorPrototype, InvalidCharacterErrorConstructor) \
|
||||
__JS_ENUMERATE(RangeError, range_error, RangeErrorPrototype, RangeErrorConstructor) \
|
||||
__JS_ENUMERATE(ReferenceError, reference_error, ReferenceErrorPrototype, ReferenceErrorConstructor) \
|
||||
__JS_ENUMERATE(SyntaxError, syntax_error, SyntaxErrorPrototype, SyntaxErrorConstructor) \
|
||||
__JS_ENUMERATE(TypeError, type_error, TypeErrorPrototype, TypeErrorConstructor) \
|
||||
__JS_ENUMERATE(URIError, uri_error, URIErrorPrototype, URIErrorConstructor)
|
||||
#define JS_ENUMERATE_ERROR_SUBCLASSES \
|
||||
__JS_ENUMERATE(EvalError, eval_error, EvalErrorPrototype, EvalErrorConstructor, void) \
|
||||
__JS_ENUMERATE(InternalError, internal_error, InternalErrorPrototype, InternalErrorConstructor, void) \
|
||||
__JS_ENUMERATE(InvalidCharacterError, invalid_character_error, InvalidCharacterErrorPrototype, InvalidCharacterErrorConstructor, void) \
|
||||
__JS_ENUMERATE(RangeError, range_error, RangeErrorPrototype, RangeErrorConstructor, void) \
|
||||
__JS_ENUMERATE(ReferenceError, reference_error, ReferenceErrorPrototype, ReferenceErrorConstructor, void) \
|
||||
__JS_ENUMERATE(SyntaxError, syntax_error, SyntaxErrorPrototype, SyntaxErrorConstructor, void) \
|
||||
__JS_ENUMERATE(TypeError, type_error, TypeErrorPrototype, TypeErrorConstructor, void) \
|
||||
__JS_ENUMERATE(URIError, uri_error, URIErrorPrototype, URIErrorConstructor, void)
|
||||
|
||||
#define JS_ENUMERATE_TYPED_ARRAYS \
|
||||
__JS_ENUMERATE(Uint8Array, uint8_array, Uint8ArrayPrototype, Uint8ArrayConstructor, u8) \
|
||||
__JS_ENUMERATE(Uint16Array, uint16_array, Uint16ArrayPrototype, Uint16ArrayConstructor, u16) \
|
||||
__JS_ENUMERATE(Uint32Array, uint32_array, Uint32ArrayPrototype, Uint32ArrayConstructor, u32) \
|
||||
__JS_ENUMERATE(Int8Array, int8_array, Int8ArrayPrototype, Int8ArrayConstructor, i8) \
|
||||
__JS_ENUMERATE(Int16Array, int16_array, Int16ArrayPrototype, Int16ArrayConstructor, i16) \
|
||||
__JS_ENUMERATE(Int32Array, int32_array, Int32ArrayPrototype, Int32ArrayConstructor, i32)
|
||||
|
||||
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
|
||||
__JS_ENUMERATE(Iterator, iterator) \
|
||||
|
@ -75,7 +83,8 @@
|
|||
|
||||
#define JS_ENUMERATE_BUILTIN_TYPES \
|
||||
JS_ENUMERATE_NATIVE_OBJECTS \
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES \
|
||||
JS_ENUMERATE_TYPED_ARRAYS
|
||||
|
||||
#define JS_ENUMERATE_WELL_KNOWN_SYMBOLS \
|
||||
__JS_ENUMERATE(iterator, iterator) \
|
||||
|
@ -138,9 +147,9 @@ enum class DeclarationKind;
|
|||
class ProxyObject;
|
||||
class ProxyConstructor;
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, ConstructorName, PrototypeName) \
|
||||
class ClassName; \
|
||||
class ConstructorName; \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, ConstructorName, PrototypeName, ArrayType) \
|
||||
class ClassName; \
|
||||
class ConstructorName; \
|
||||
class PrototypeName;
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -223,7 +223,7 @@ struct CommonPropertyNames {
|
|||
#define __ENUMERATE(x) FlyString x { #x };
|
||||
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
|
||||
#undef __ENUMERATE
|
||||
#define __JS_ENUMERATE(x, a, b, c) FlyString x { #x };
|
||||
#define __JS_ENUMERATE(x, a, b, c, t) FlyString x { #x };
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
#undef __JS_ENUMERATE
|
||||
#define __JS_ENUMERATE(x, a) FlyString x { #x };
|
||||
|
|
|
@ -45,7 +45,7 @@ Error::~Error()
|
|||
{
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
ClassName* ClassName::create(GlobalObject& global_object, const String& message) \
|
||||
{ \
|
||||
return global_object.heap().allocate<ClassName>(global_object, message, *global_object.snake_name##_prototype()); \
|
||||
|
|
|
@ -63,7 +63,7 @@ private:
|
|||
virtual ~ClassName() override; \
|
||||
};
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
DECLARE_ERROR_SUBCLASS(ClassName, snake_name, PrototypeName, ConstructorName)
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -64,7 +64,7 @@ Value ErrorConstructor::construct(Function&)
|
|||
return Error::create(global_object(), vm.names.Error, message);
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
ConstructorName::ConstructorName(GlobalObject& global_object) \
|
||||
: NativeFunction(*global_object.function_prototype()) \
|
||||
{ \
|
||||
|
|
|
@ -61,7 +61,7 @@ private:
|
|||
virtual bool has_constructor() const override { return true; } \
|
||||
};
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
DECLARE_ERROR_SUBCLASS_CONSTRUCTOR(ClassName, snake_name, PrototypeName, ConstructorName)
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -127,11 +127,11 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
|
|||
return js_string(vm, String::formatted("{}: {}", name, message));
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
PrototypeName::PrototypeName(GlobalObject& global_object) \
|
||||
: Object(*global_object.error_prototype()) \
|
||||
{ \
|
||||
} \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
PrototypeName::PrototypeName(GlobalObject& global_object) \
|
||||
: Object(*global_object.error_prototype()) \
|
||||
{ \
|
||||
} \
|
||||
PrototypeName::~PrototypeName() { }
|
||||
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
|
|
|
@ -57,7 +57,7 @@ private:
|
|||
virtual ~PrototypeName() override; \
|
||||
};
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
DECLARE_ERROR_SUBCLASS_PROTOTYPE(ClassName, snake_name, PrototypeName, ConstructorName)
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include <LibJS/Runtime/StringPrototype.h>
|
||||
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
@ -95,8 +96,8 @@ void GlobalObject::initialize()
|
|||
|
||||
set_prototype(m_object_prototype);
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
if (!m_##snake_name##_prototype) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
if (!m_##snake_name##_prototype) \
|
||||
m_##snake_name##_prototype = heap().allocate<PrototypeName>(*this, *this);
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
#undef __JS_ENUMERATE
|
||||
|
@ -136,9 +137,10 @@ void GlobalObject::initialize()
|
|||
add_constructor(vm.names.String, m_string_constructor, m_string_prototype);
|
||||
add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype);
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
add_constructor(vm.names.ClassName, m_##snake_name##_constructor, m_##snake_name##_prototype);
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
JS_ENUMERATE_TYPED_ARRAYS
|
||||
#undef __JS_ENUMERATE
|
||||
}
|
||||
|
||||
|
@ -154,7 +156,7 @@ void GlobalObject::visit_edges(Visitor& visitor)
|
|||
visitor.visit(m_new_object_shape);
|
||||
visitor.visit(m_new_script_function_prototype_object_shape);
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
visitor.visit(m_##snake_name##_constructor);
|
||||
JS_ENUMERATE_ERROR_SUBCLASSES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
|
||||
ProxyConstructor* proxy_constructor() { return m_proxy_constructor; }
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
|
||||
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
|
@ -90,8 +90,8 @@ private:
|
|||
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
|
||||
ProxyConstructor* m_proxy_constructor { nullptr };
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||
ConstructorName* m_##snake_name##_constructor { nullptr }; \
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
ConstructorName* m_##snake_name##_constructor { nullptr }; \
|
||||
Object* m_##snake_name##_prototype { nullptr };
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
#undef __JS_ENUMERATE
|
||||
|
|
|
@ -129,6 +129,7 @@ public:
|
|||
virtual bool is_array_iterator_object() const { return false; }
|
||||
virtual bool is_lexical_environment() const { return false; }
|
||||
virtual bool is_global_object() const { return false; }
|
||||
virtual bool is_typed_array() const { return false; }
|
||||
|
||||
virtual const char* class_name() const override { return "Object"; }
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
|
95
Libraries/LibJS/Runtime/TypedArray.cpp
Normal file
95
Libraries/LibJS/Runtime/TypedArray.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
#define JS_DEFINE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
|
||||
ClassName::~ClassName() { } \
|
||||
ClassName* ClassName::create(GlobalObject& global_object, u32 length) \
|
||||
{ \
|
||||
return global_object.heap().allocate<ClassName>(global_object, length, *global_object.snake_name##_prototype()); \
|
||||
} \
|
||||
\
|
||||
ClassName::ClassName(u32 length, Object& prototype) \
|
||||
: TypedArray(length, prototype) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
PrototypeName::PrototypeName(GlobalObject& global_object) \
|
||||
: Object(*global_object.object_prototype()) \
|
||||
{ \
|
||||
} \
|
||||
void PrototypeName::initialize(GlobalObject& global_object) \
|
||||
{ \
|
||||
auto& vm = this->vm(); \
|
||||
Object::initialize(global_object); \
|
||||
define_property(vm.names.length, Value(0), Attribute::Configurable); \
|
||||
} \
|
||||
PrototypeName::~PrototypeName() { } \
|
||||
\
|
||||
ConstructorName::~ConstructorName() { } \
|
||||
Value ConstructorName::construct(Function&) { return call(); } \
|
||||
ConstructorName::ConstructorName(GlobalObject& global_object) \
|
||||
: NativeFunction(vm().names.ClassName, *global_object.function_prototype()) \
|
||||
{ \
|
||||
} \
|
||||
void ConstructorName::initialize(GlobalObject& global_object) \
|
||||
{ \
|
||||
auto& vm = this->vm(); \
|
||||
NativeFunction::initialize(global_object); \
|
||||
define_property(vm.names.prototype, global_object.snake_name##_prototype(), 0); \
|
||||
define_property(vm.names.length, Value(1), Attribute::Configurable); \
|
||||
} \
|
||||
Value ConstructorName::call() \
|
||||
{ \
|
||||
if (vm().argument_count() <= 0) \
|
||||
return ClassName::create(global_object(), 0); \
|
||||
\
|
||||
if (vm().argument_count() == 1 && vm().argument(0).is_number()) { \
|
||||
auto array_length_value = vm().argument(0); \
|
||||
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) { \
|
||||
vm().throw_exception<TypeError>(global_object(), ErrorType::ArrayInvalidLength); \
|
||||
return {}; \
|
||||
} \
|
||||
auto* array = ClassName::create(global_object(), array_length_value.as_i32()); \
|
||||
return array; \
|
||||
} \
|
||||
auto* array = ClassName::create(global_object(), vm().argument_count()); \
|
||||
for (size_t i = 0; i < vm().argument_count(); ++i) \
|
||||
array->put_by_index(i, vm().argument(i)); \
|
||||
return array; \
|
||||
}
|
||||
|
||||
#undef __JS_ENUMERATE
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
JS_DEFINE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType);
|
||||
JS_ENUMERATE_TYPED_ARRAYS
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
}
|
165
Libraries/LibJS/Runtime/TypedArray.h
Normal file
165
Libraries/LibJS/Runtime/TypedArray.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
template<typename T>
|
||||
class TypedArray : public Object {
|
||||
JS_OBJECT(TypedArray, Object);
|
||||
|
||||
public:
|
||||
virtual ~TypedArray() override
|
||||
{
|
||||
ASSERT(m_data);
|
||||
free(m_data);
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
i32 length() const { return m_length; }
|
||||
|
||||
virtual bool put_by_index(u32 property_index, Value value) override
|
||||
{
|
||||
if (property_index >= m_length)
|
||||
return Base::put_by_index(property_index, value);
|
||||
|
||||
if constexpr (sizeof(T) < 4) {
|
||||
auto number = value.to_i32(global_object());
|
||||
if (vm().exception())
|
||||
return {};
|
||||
m_data[property_index] = number;
|
||||
} else if constexpr (sizeof(T) == 4) {
|
||||
auto number = value.to_double(global_object());
|
||||
if (vm().exception())
|
||||
return {};
|
||||
m_data[property_index] = number;
|
||||
} else {
|
||||
static_assert(DependentFalse<T>, "TypedArray::put_by_index with unhandled type size");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Value get_by_index(u32 property_index) const override
|
||||
{
|
||||
if (property_index >= m_length)
|
||||
return Base::get_by_index(property_index);
|
||||
|
||||
if constexpr (sizeof(T) < 4) {
|
||||
return Value((i32)m_data[property_index]);
|
||||
} else if constexpr (sizeof(T) == 4) {
|
||||
auto value = m_data[property_index];
|
||||
if constexpr (NumericLimits<T>::is_signed()) {
|
||||
if (value > NumericLimits<i32>::max() || value < NumericLimits<i32>::min())
|
||||
return Value((double)value);
|
||||
} else {
|
||||
if (value > NumericLimits<i32>::max())
|
||||
return Value((double)value);
|
||||
}
|
||||
return Value((i32)value);
|
||||
} else {
|
||||
static_assert(DependentFalse<T>, "TypedArray::get_by_index with unhandled type size");
|
||||
}
|
||||
}
|
||||
|
||||
T* data() { return m_data; }
|
||||
const T* data() const { return m_data; }
|
||||
|
||||
protected:
|
||||
TypedArray(u32 length, Object& prototype)
|
||||
: Object(prototype)
|
||||
, m_length(length)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
define_native_property(vm.names.length, length_getter, nullptr);
|
||||
m_data = (T*)calloc(m_length, sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool is_typed_array() const final { return true; }
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(length_getter);
|
||||
|
||||
T* m_data { nullptr };
|
||||
u32 m_length { 0 };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline JS_DEFINE_NATIVE_GETTER(TypedArray<T>::length_getter)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (!this_object->is_typed_array()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "TypedArray");
|
||||
return {};
|
||||
}
|
||||
return Value(static_cast<const TypedArray*>(this_object)->length());
|
||||
}
|
||||
|
||||
#define JS_DECLARE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
|
||||
class ClassName : public TypedArray<Type> { \
|
||||
JS_OBJECT(ClassName, TypedArray); \
|
||||
\
|
||||
public: \
|
||||
virtual ~ClassName(); \
|
||||
static ClassName* create(GlobalObject&, u32 length); \
|
||||
ClassName(u32 length, Object& prototype); \
|
||||
}; \
|
||||
class PrototypeName final : public Object { \
|
||||
JS_OBJECT(PrototypeName, Object); \
|
||||
\
|
||||
public: \
|
||||
PrototypeName(GlobalObject&); \
|
||||
virtual void initialize(GlobalObject&) override; \
|
||||
virtual ~PrototypeName() override; \
|
||||
}; \
|
||||
class ConstructorName final : public NativeFunction { \
|
||||
JS_OBJECT(ConstructorName, NativeFunction); \
|
||||
\
|
||||
public: \
|
||||
explicit ConstructorName(GlobalObject&); \
|
||||
virtual void initialize(GlobalObject&) override; \
|
||||
virtual ~ConstructorName() override; \
|
||||
\
|
||||
virtual Value call() override; \
|
||||
virtual Value construct(Function& new_target) override; \
|
||||
\
|
||||
private: \
|
||||
virtual bool has_constructor() const override { return true; } \
|
||||
};
|
||||
|
||||
#undef __JS_ENUMERATE
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
JS_DECLARE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType);
|
||||
JS_ENUMERATE_TYPED_ARRAYS
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
test("basic Uint8Array", () => {
|
||||
var a = new Uint8Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Uint8Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(0xff);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
});
|
||||
|
||||
test("basic Uint16Array", () => {
|
||||
var a = new Uint16Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Uint16Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(0xffff);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
});
|
||||
|
||||
test("basic Uint32Array", () => {
|
||||
var a = new Uint32Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Uint32Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(0xffffffff);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
});
|
||||
|
||||
test("basic Int8Array", () => {
|
||||
var a = new Int8Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Int8Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(-1);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
a[0] = 127;
|
||||
a[0]++;
|
||||
expect(a[0]).toBe(-128);
|
||||
});
|
||||
|
||||
test("basic Int16Array", () => {
|
||||
var a = new Int16Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Int16Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(-1);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
a[0] = 32767;
|
||||
a[0]++;
|
||||
expect(a[0]).toBe(-32768);
|
||||
});
|
||||
|
||||
test("basic Int32Array", () => {
|
||||
var a = new Int32Array(1);
|
||||
expect(typeof a).toBe("object");
|
||||
expect(a instanceof Int32Array).toBe(true);
|
||||
expect(a.length).toBe(1);
|
||||
a[0] = 1;
|
||||
expect(a[0]).toBe(1);
|
||||
a[0] -= 2;
|
||||
expect(a[0]).toBe(-1);
|
||||
++a[0];
|
||||
expect(a[0]).toBe(0);
|
||||
a[0] = 0x7fffffff;
|
||||
a[0]++;
|
||||
expect(a[0]).toBe(-0x80000000);
|
||||
});
|
Loading…
Reference in a new issue