dataview.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. class DataView : public ArrayBufferParent
  9. {
  10. friend ArrayBuffer;
  11. protected:
  12. DEFINE_VTABLE_CTOR(DataView, ArrayBufferParent);
  13. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(DataView);
  14. public:
  15. class EntryInfo
  16. {
  17. public:
  18. static FunctionInfo NewInstance;
  19. static FunctionInfo GetInt8;
  20. static FunctionInfo GetUint8;
  21. static FunctionInfo GetInt16;
  22. static FunctionInfo GetUint16;
  23. static FunctionInfo GetInt32;
  24. static FunctionInfo GetUint32;
  25. static FunctionInfo GetFloat32;
  26. static FunctionInfo GetFloat64;
  27. static FunctionInfo SetInt8;
  28. static FunctionInfo SetUint8;
  29. static FunctionInfo SetInt16;
  30. static FunctionInfo SetUint16;
  31. static FunctionInfo SetInt32;
  32. static FunctionInfo SetUint32;
  33. static FunctionInfo SetFloat32;
  34. static FunctionInfo SetFloat64;
  35. static FunctionInfo GetterBuffer;
  36. static FunctionInfo GetterByteLength;
  37. static FunctionInfo GetterByteOffset;
  38. };
  39. DataView(ArrayBuffer* arrayBuffer, uint32 byteOffset, uint32 mappedLength, DynamicType* type);
  40. static BOOL Is(Var aValue);
  41. static __inline DataView* FromVar(Var aValue)
  42. {
  43. Assert(DataView::Is(aValue));
  44. return static_cast<DataView*>(aValue);
  45. }
  46. uint32 GetByteOffset() const { return byteOffset; }
  47. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  48. static Var EntryGetInt8(RecyclableObject* function, CallInfo callInfo, ...);
  49. static Var EntryGetUint8(RecyclableObject* function, CallInfo callInfo, ...);
  50. static Var EntryGetInt16(RecyclableObject* function, CallInfo callInfo, ...);
  51. static Var EntryGetUint16(RecyclableObject* function, CallInfo callInfo, ...);
  52. static Var EntryGetInt32(RecyclableObject* function, CallInfo callInfo, ...);
  53. static Var EntryGetUint32(RecyclableObject* function, CallInfo callInfo, ...);
  54. static Var EntryGetFloat32(RecyclableObject* function, CallInfo callInfo, ...);
  55. static Var EntryGetFloat64(RecyclableObject* function, CallInfo callInfo, ...);
  56. static Var EntrySetInt8(RecyclableObject* function, CallInfo callInfo, ...);
  57. static Var EntrySetUint8(RecyclableObject* function, CallInfo callInfo, ...);
  58. static Var EntrySetInt16(RecyclableObject* function, CallInfo callInfo, ...);
  59. static Var EntrySetUint16(RecyclableObject* function, CallInfo callInfo, ...);
  60. static Var EntrySetInt32(RecyclableObject* function, CallInfo callInfo, ...);
  61. static Var EntrySetUint32(RecyclableObject* function, CallInfo callInfo, ...);
  62. static Var EntrySetFloat32(RecyclableObject* function, CallInfo callInfo, ...);
  63. static Var EntrySetFloat64(RecyclableObject* function, CallInfo callInfo, ...);
  64. static Var EntryGetterBuffer(RecyclableObject* function, CallInfo callInfo, ...);
  65. static Var EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...);
  66. static Var EntryGetterByteOffset(RecyclableObject* function, CallInfo callInfo, ...);
  67. // objectArray support
  68. virtual BOOL SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes) override;
  69. private:
  70. template<typename TypeName>
  71. void SwapRoutine(TypeName* input, TypeName* dest);
  72. template<> void SwapRoutine(int8* input, int8* dest) {*dest = *input; }
  73. template<> void SwapRoutine(uint8* input, uint8* dest) {*dest = *input; }
  74. template<> void SwapRoutine(int16* input, int16* dest) {*dest = RtlUshortByteSwap(*input); }
  75. template<> void SwapRoutine(uint16* input, uint16* dest) {*dest = RtlUshortByteSwap(*input);}
  76. template<> void SwapRoutine(int32* input, int32* dest) {*dest = RtlUlongByteSwap(*input);}
  77. template<> void SwapRoutine(uint32* input, uint32* dest) {*dest = RtlUlongByteSwap(*input);}
  78. // we don't want type conversion here, we just want to swap the bytes.
  79. template<> void SwapRoutine(float* input, float* dest) { *((ulong*)dest) = RtlUlongByteSwap(*((ulong*)input)); }
  80. template<> void SwapRoutine(double* input, double* dest) {*((uint64*)dest) = RtlUlonglongByteSwap(*((uint64*)input)); }
  81. template<typename TypeName>
  82. Var GetValue(uint32 byteOffset, wchar_t* funcName, BOOL isLittleEndian = FALSE)
  83. {
  84. ScriptContext* scriptContext = GetScriptContext();
  85. if (this->GetArrayBuffer()->IsDetached())
  86. {
  87. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
  88. }
  89. if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
  90. {
  91. TypeName item;
  92. TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
  93. if (!isLittleEndian)
  94. {
  95. SwapRoutine<TypeName>(typedBuffer, &item);
  96. }
  97. else
  98. {
  99. item = *typedBuffer;
  100. }
  101. return JavascriptNumber::ToVar(item, GetScriptContext());
  102. }
  103. else
  104. {
  105. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
  106. }
  107. }
  108. template<typename TypeName>
  109. inline Var GetValueWithCheck(uint32 byteOffset, wchar_t* funcName, BOOL isLittleEndian = FALSE)
  110. {
  111. return GetValueWithCheck<TypeName, TypeName*>(byteOffset, isLittleEndian, funcName);
  112. }
  113. template<typename TypeName, typename PointerAccessTypeName>
  114. Var GetValueWithCheck(uint32 byteOffset, BOOL isLittleEndian, wchar_t* funcName)
  115. {
  116. ScriptContext* scriptContext = GetScriptContext();
  117. if (this->GetArrayBuffer()->IsDetached())
  118. {
  119. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
  120. }
  121. if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
  122. {
  123. TypeName item;
  124. TypeName *typedBuffer = (TypeName*)(buffer + byteOffset);
  125. if (!isLittleEndian)
  126. {
  127. SwapRoutine<TypeName>(typedBuffer, &item);
  128. }
  129. else
  130. {
  131. item = *static_cast<PointerAccessTypeName>(typedBuffer);
  132. }
  133. return JavascriptNumber::ToVarWithCheck(item, GetScriptContext());
  134. }
  135. else
  136. {
  137. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
  138. }
  139. }
  140. template<typename TypeName>
  141. inline void SetValue(uint32 byteOffset, TypeName value, wchar_t *funcName, BOOL isLittleEndian = FALSE)
  142. {
  143. SetValue<TypeName, TypeName*>(byteOffset, value, isLittleEndian, funcName);
  144. }
  145. template<typename TypeName, typename PointerAccessTypeName>
  146. void SetValue(uint32 byteOffset, TypeName value, BOOL isLittleEndian, wchar_t *funcName)
  147. {
  148. ScriptContext* scriptContext = GetScriptContext();
  149. if (this->GetArrayBuffer()->IsDetached())
  150. {
  151. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
  152. }
  153. if ((byteOffset + sizeof(TypeName) <= GetLength()) && (byteOffset <= GetLength()))
  154. {
  155. TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
  156. if (!isLittleEndian)
  157. {
  158. SwapRoutine<TypeName>(&value, typedBuffer);
  159. }
  160. else
  161. {
  162. *static_cast<PointerAccessTypeName>(typedBuffer) = value;
  163. }
  164. }
  165. else
  166. {
  167. JavascriptError::ThrowTypeError(scriptContext, JSERR_DataView_InvalidOffset);
  168. }
  169. }
  170. #ifdef _M_ARM
  171. // For ARM, memory access for float/double address causes data alignment exception if the address is not aligned.
  172. // Provide template specilization (only) for these scenarios.
  173. template<> Var GetValueWithCheck<float>(uint32 byteOffset, wchar_t *funcName, BOOL isLittleEndian /* = FALSE */);
  174. template<> Var GetValueWithCheck<double>(uint32 byteOffset, wchar_t *funcName, BOOL isLittleEndian /* = FALSE */);
  175. template<> void SetValue<float>(uint32 byteOffset, float value, wchar_t *funcName, BOOL isLittleEndian /* = FALSE */);
  176. template<> void SetValue<double>(uint32 byteOffset, double value, wchar_t *funcName, BOOL isLittleEndian /* = FALSE */);
  177. #endif
  178. uint32 byteOffset;
  179. BYTE* buffer; // beginning of buffer
  180. };
  181. }