blob: a5dad2a1f7060d1dabd10f1e47a82113d76ebb6b [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
namespace Js
{
class DataView : public ArrayBufferParent
{
friend ArrayBuffer;
protected:
DEFINE_VTABLE_CTOR(DataView, ArrayBufferParent);
DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(DataView);
public:
class EntryInfo
{
public:
static FunctionInfo NewInstance;
static FunctionInfo GetInt8;
static FunctionInfo GetUint8;
static FunctionInfo GetInt16;
static FunctionInfo GetUint16;
static FunctionInfo GetInt32;
static FunctionInfo GetUint32;
static FunctionInfo GetFloat32;
static FunctionInfo GetFloat64;
static FunctionInfo SetInt8;
static FunctionInfo SetUint8;
static FunctionInfo SetInt16;
static FunctionInfo SetUint16;
static FunctionInfo SetInt32;
static FunctionInfo SetUint32;
static FunctionInfo SetFloat32;
static FunctionInfo SetFloat64;
static FunctionInfo GetterBuffer;
static FunctionInfo GetterByteLength;
static FunctionInfo GetterByteOffset;
};
DataView(ArrayBufferBase* arrayBuffer, uint32 byteOffset, uint32 mappedLength, DynamicType* type);
static BOOL Is(Var aValue);
static inline DataView* FromVar(Var aValue)
{
Assert(DataView::Is(aValue));
return static_cast<DataView*>(aValue);
}
uint32 GetByteOffset() const { return byteOffset; }
void ClearLengthAndBufferOnDetach();
static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetInt8(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetUint8(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetInt16(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetUint16(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetInt32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetUint32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetFloat32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetFloat64(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetInt8(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetUint8(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetInt16(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetUint16(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetInt32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetUint32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetFloat32(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntrySetFloat64(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetterBuffer(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...);
static Var EntryGetterByteOffset(RecyclableObject* function, CallInfo callInfo, ...);
// objectArray support
virtual BOOL SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes) override;
virtual JavascriptEnumerator * GetIndexEnumerator(EnumeratorFlags flags, ScriptContext * requestContext) override
{
// Data View can not be an objectArray
Assert(false);
return nullptr;
}
private:
template<typename TypeName>
void SwapRoutine(TypeName* input, TypeName* dest);
template<> void SwapRoutine(int8* input, int8* dest) {*dest = *input; }
template<> void SwapRoutine(uint8* input, uint8* dest) {*dest = *input; }
template<> void SwapRoutine(int16* input, int16* dest) {*dest = RtlUshortByteSwap(*input); }
template<> void SwapRoutine(uint16* input, uint16* dest) {*dest = RtlUshortByteSwap(*input);}
template<> void SwapRoutine(int32* input, int32* dest) {*dest = RtlUlongByteSwap(*input);}
template<> void SwapRoutine(uint32* input, uint32* dest) {*dest = RtlUlongByteSwap(*input);}
// we don't want type conversion here, we just want to swap the bytes.
template<> void SwapRoutine(float* input, float* dest) { *((uint32*)dest) = RtlUlongByteSwap(*((uint32*)input)); }
template<> void SwapRoutine(double* input, double* dest) {*((uint64*)dest) = RtlUlonglongByteSwap(*((uint64*)input)); }
template<typename TypeName>
Var GetValue(uint32 byteOffset, const char16* funcName, BOOL isLittleEndian = FALSE)
{
ScriptContext* scriptContext = GetScriptContext();
if (this->GetArrayBuffer()->IsDetached())
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
}
if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
{
TypeName item;
TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
if (!isLittleEndian)
{
SwapRoutine<TypeName>(typedBuffer, &item);
}
else
{
item = *typedBuffer;
}
return JavascriptNumber::ToVar(item, GetScriptContext());
}
else
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
}
}
template<typename TypeName>
inline Var GetValueWithCheck(uint32 byteOffset, const char16* funcName, BOOL isLittleEndian = FALSE)
{
return GetValueWithCheck<TypeName, TypeName*>(byteOffset, isLittleEndian, funcName);
}
template<typename TypeName, typename PointerAccessTypeName>
Var GetValueWithCheck(uint32 byteOffset, BOOL isLittleEndian, const char16* funcName)
{
ScriptContext* scriptContext = GetScriptContext();
if (this->GetArrayBuffer()->IsDetached())
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
}
if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
{
TypeName item;
TypeName *typedBuffer = (TypeName*)(buffer + byteOffset);
if (!isLittleEndian)
{
SwapRoutine<TypeName>(typedBuffer, &item);
}
else
{
item = *static_cast<PointerAccessTypeName>(typedBuffer);
}
return JavascriptNumber::ToVarWithCheck(item, GetScriptContext());
}
else
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
}
}
template<typename TypeName>
inline void SetValue(uint32 byteOffset, TypeName value, const char16 *funcName, BOOL isLittleEndian = FALSE)
{
SetValue<TypeName, TypeName*>(byteOffset, value, isLittleEndian, funcName);
}
template<typename TypeName, typename PointerAccessTypeName>
void SetValue(uint32 byteOffset, TypeName value, BOOL isLittleEndian, const char16 *funcName)
{
ScriptContext* scriptContext = GetScriptContext();
if (this->GetArrayBuffer()->IsDetached())
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
}
if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
{
TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
if (!isLittleEndian)
{
SwapRoutine<TypeName>(&value, typedBuffer);
}
else
{
*static_cast<PointerAccessTypeName>(typedBuffer) = value;
}
}
else
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
}
}
#ifdef _M_ARM
// For ARM, memory access for float/double address causes data alignment exception if the address is not aligned.
// Provide template specialization (only) for these scenarios.
template<> Var GetValueWithCheck<float>(uint32 byteOffset, const char16 *funcName, BOOL isLittleEndian /* = FALSE */);
template<> Var GetValueWithCheck<double>(uint32 byteOffset, const char16 *funcName, BOOL isLittleEndian /* = FALSE */);
template<> void SetValue<float>(uint32 byteOffset, float value, const char16 *funcName, BOOL isLittleEndian /* = FALSE */);
template<> void SetValue<double>(uint32 byteOffset, double value, const char16 *funcName, BOOL isLittleEndian /* = FALSE */);
#endif
Field(uint32) byteOffset;
Field(BYTE*) buffer; // beginning of buffer
};
}