JSGenericTypedArrayView.h [plain text]
#pragma once
#include "JSArrayBufferView.h"
#include "ThrowScope.h"
#include "ToNativeFromValue.h"
namespace JSC {
JS_EXPORT_PRIVATE const ClassInfo* getInt8ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getInt16ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getInt32ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getUint8ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getUint8ClampedArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getUint16ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getUint32ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getFloat32ArrayClassInfo();
JS_EXPORT_PRIVATE const ClassInfo* getFloat64ArrayClassInfo();
enum class CopyType {
LeftToRight,
Unobservable,
};
static const ASCIILiteral typedArrayBufferHasBeenDetachedErrorMessage { "Underlying ArrayBuffer has been detached from the view"_s };
template<typename Adaptor>
class JSGenericTypedArrayView final : public JSArrayBufferView {
public:
typedef JSArrayBufferView Base;
typedef typename Adaptor::Type ElementType;
static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
static const unsigned elementSize = sizeof(typename Adaptor::Type);
protected:
JSGenericTypedArrayView(VM&, ConstructionContext&);
public:
static JSGenericTypedArrayView* create(ExecState*, Structure*, unsigned length);
static JSGenericTypedArrayView* createWithFastVector(ExecState*, Structure*, unsigned length, void* vector);
static JSGenericTypedArrayView* createUninitialized(ExecState*, Structure*, unsigned length);
static JSGenericTypedArrayView* create(ExecState*, Structure*, RefPtr<ArrayBuffer>&&, unsigned byteOffset, unsigned length);
static JSGenericTypedArrayView* create(VM&, Structure*, RefPtr<typename Adaptor::ViewType>&& impl);
static JSGenericTypedArrayView* create(Structure*, JSGlobalObject*, RefPtr<typename Adaptor::ViewType>&& impl);
unsigned byteLength() const { return m_length * sizeof(typename Adaptor::Type); }
size_t byteSize() const { return sizeOf(m_length, sizeof(typename Adaptor::Type)); }
const typename Adaptor::Type* typedVector() const
{
return bitwise_cast<const typename Adaptor::Type*>(vector());
}
typename Adaptor::Type* typedVector()
{
return bitwise_cast<typename Adaptor::Type*>(vector());
}
bool canGetIndexQuickly(unsigned i)
{
return i < m_length;
}
bool canSetIndexQuickly(unsigned i)
{
return i < m_length;
}
typename Adaptor::Type getIndexQuicklyAsNativeValue(unsigned i)
{
ASSERT(i < m_length);
return typedVector()[i];
}
double getIndexQuicklyAsDouble(unsigned i)
{
return Adaptor::toDouble(getIndexQuicklyAsNativeValue(i));
}
JSValue getIndexQuickly(unsigned i)
{
return Adaptor::toJSValue(getIndexQuicklyAsNativeValue(i));
}
void setIndexQuicklyToNativeValue(unsigned i, typename Adaptor::Type value)
{
ASSERT(i < m_length);
typedVector()[i] = value;
}
void setIndexQuicklyToDouble(unsigned i, double value)
{
setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(jsNumber(value)));
}
void setIndexQuickly(unsigned i, JSValue value)
{
ASSERT(!value.isObject());
setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value));
}
bool setIndex(ExecState* exec, unsigned i, JSValue jsValue)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue);
RETURN_IF_EXCEPTION(scope, false);
if (isNeutered()) {
throwTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
return false;
}
if (i >= m_length)
return false;
setIndexQuicklyToNativeValue(i, value);
return true;
}
static ElementType toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue) { return toNativeFromValue<Adaptor>(exec, jsValue); }
static Optional<ElementType> toAdaptorNativeFromValueWithoutCoercion(JSValue jsValue) { return toNativeFromValueWithoutCoercion<Adaptor>(jsValue); }
void sort()
{
RELEASE_ASSERT(!isNeutered());
switch (Adaptor::typeValue) {
case TypeFloat32:
sortFloat<int32_t>();
break;
case TypeFloat64:
sortFloat<int64_t>();
break;
default: {
ElementType* array = typedVector();
std::sort(array, array + m_length);
break;
}
}
}
bool canAccessRangeQuickly(unsigned offset, unsigned length)
{
return offset <= m_length
&& offset + length <= m_length
&& offset + length >= offset;
}
bool validateRange(ExecState*, unsigned offset, unsigned length);
bool set(ExecState*, unsigned offset, JSObject*, unsigned objectOffset, unsigned length, CopyType type = CopyType::Unobservable);
RefPtr<typename Adaptor::ViewType> possiblySharedTypedImpl();
RefPtr<typename Adaptor::ViewType> unsharedTypedImpl();
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray);
}
static const ClassInfo s_info;
static const ClassInfo* info()
{
switch (Adaptor::typeValue) {
case TypeInt8:
return getInt8ArrayClassInfo();
case TypeInt16:
return getInt16ArrayClassInfo();
case TypeInt32:
return getInt32ArrayClassInfo();
case TypeUint8:
return getUint8ArrayClassInfo();
case TypeUint8Clamped:
return getUint8ClampedArrayClassInfo();
case TypeUint16:
return getUint16ArrayClassInfo();
case TypeUint32:
return getUint32ArrayClassInfo();
case TypeFloat32:
return getFloat32ArrayClassInfo();
case TypeFloat64:
return getFloat64ArrayClassInfo();
default:
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
}
ArrayBuffer* existingBuffer();
static const TypedArrayType TypedArrayStorageType = Adaptor::typeValue;
static RefPtr<typename Adaptor::ViewType> toWrapped(VM&, JSValue);
protected:
friend struct TypedArrayClassInfos;
static EncodedJSValue throwNeuteredTypedArrayTypeError(ExecState*, EncodedJSValue, PropertyName);
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static size_t estimatedSize(JSCell*, VM&);
static void visitChildren(JSCell*, SlotVisitor&);
private:
template<typename OtherAdaptor>
bool setWithSpecificType(
ExecState*, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>*,
unsigned objectOffset, unsigned length, CopyType);
void purifyArray()
{
ElementType* array = typedVector();
for (unsigned i = 0; i < m_length; i++)
array[i] = purifyNaN(array[i]);
}
template<typename IntegralType>
void sortFloat()
{
ASSERT(sizeof(IntegralType) == sizeof(ElementType));
purifyArray();
IntegralType* array = reinterpret_cast_ptr<IntegralType*>(typedVector());
std::sort(array, array + m_length, [] (IntegralType a, IntegralType b) {
if (a >= 0 || b >= 0)
return a < b;
return a > b;
});
}
};
template<typename Adaptor>
inline RefPtr<typename Adaptor::ViewType> toPossiblySharedNativeTypedView(VM& vm, JSValue value)
{
typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(vm, value);
if (!wrapper)
return nullptr;
return wrapper->possiblySharedTypedImpl();
}
template<typename Adaptor>
inline RefPtr<typename Adaptor::ViewType> toUnsharedNativeTypedView(VM& vm, JSValue value)
{
RefPtr<typename Adaptor::ViewType> result = toPossiblySharedNativeTypedView<Adaptor>(vm, value);
if (!result || result->isShared())
return nullptr;
return result;
}
template<typename Adaptor>
RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::toWrapped(VM& vm, JSValue value)
{
return JSC::toUnsharedNativeTypedView<Adaptor>(vm, value);
}
}