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,
};
extern const ASCIILiteral typedArrayBufferHasBeenDetachedErrorMessage;
template<typename Adaptor>
class JSGenericTypedArrayView final : public JSArrayBufferView {
public:
using Base = JSArrayBufferView;
typedef typename Adaptor::Type ElementType;
static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
static constexpr unsigned elementSize = sizeof(typename Adaptor::Type);
static JSGenericTypedArrayView* create(JSGlobalObject*, Structure*, unsigned length);
static JSGenericTypedArrayView* createWithFastVector(JSGlobalObject*, Structure*, unsigned length, void* vector);
static JSGenericTypedArrayView* createUninitialized(JSGlobalObject*, Structure*, unsigned length);
static JSGenericTypedArrayView* create(JSGlobalObject*, 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) const
{
return i < m_length;
}
bool canSetIndexQuickly(unsigned i, JSValue value) const
{
return i < m_length && value.isNumber();
}
typename Adaptor::Type getIndexQuicklyAsNativeValue(unsigned i) const
{
ASSERT(i < m_length);
return typedVector()[i];
}
double getIndexQuicklyAsDouble(unsigned i)
{
return Adaptor::toDouble(getIndexQuicklyAsNativeValue(i));
}
JSValue getIndexQuickly(unsigned i) const
{
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(JSGlobalObject* globalObject, unsigned i, JSValue jsValue)
{
VM& vm = getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
typename Adaptor::Type value = toNativeFromValue<Adaptor>(globalObject, jsValue);
RETURN_IF_EXCEPTION(scope, false);
if (isDetached() || i >= m_length)
return false;
setIndexQuicklyToNativeValue(i, value);
return true;
}
static ElementType toAdaptorNativeFromValue(JSGlobalObject* globalObject, JSValue jsValue) { return toNativeFromValue<Adaptor>(globalObject, jsValue); }
static Optional<ElementType> toAdaptorNativeFromValueWithoutCoercion(JSValue jsValue) { return toNativeFromValueWithoutCoercion<Adaptor>(jsValue); }
void sort()
{
RELEASE_ASSERT(!isDetached());
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(JSGlobalObject*, unsigned offset, unsigned length);
bool set(JSGlobalObject*, 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 nullptr;
}
}
template<typename CellType, SubspaceAccess mode>
static IsoSubspace* subspaceFor(VM& vm)
{
switch (Adaptor::typeValue) {
case TypeInt8:
return vm.int8ArraySpace<mode>();
case TypeInt16:
return vm.int16ArraySpace<mode>();
case TypeInt32:
return vm.int32ArraySpace<mode>();
case TypeUint8:
return vm.uint8ArraySpace<mode>();
case TypeUint8Clamped:
return vm.uint8ClampedArraySpace<mode>();
case TypeUint16:
return vm.uint16ArraySpace<mode>();
case TypeUint32:
return vm.uint32ArraySpace<mode>();
case TypeFloat32:
return vm.float32ArraySpace<mode>();
case TypeFloat64:
return vm.float64ArraySpace<mode>();
default:
RELEASE_ASSERT_NOT_REACHED();
return nullptr;
}
}
ArrayBuffer* existingBuffer();
static const TypedArrayType TypedArrayStorageType = Adaptor::typeValue;
static RefPtr<typename Adaptor::ViewType> toWrapped(VM&, JSValue);
static RefPtr<typename Adaptor::ViewType> toWrappedAllowShared(VM&, JSValue);
private:
friend struct TypedArrayClassInfos;
JSGenericTypedArrayView(VM&, ConstructionContext&);
static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode);
static size_t estimatedSize(JSCell*, VM&);
static void visitChildren(JSCell*, SlotVisitor&);
template<typename OtherAdaptor>
bool setWithSpecificType(
JSGlobalObject*, 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);
}
template<typename Adaptor>
RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::toWrappedAllowShared(VM& vm, JSValue value)
{
return JSC::toPossiblySharedNativeTypedView<Adaptor>(vm, value);
}
}