SharedArrayBuffer.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. // Implements SharedArrayBuffer according to http://tc39.github.io/ecmascript_sharedmem/shmem.html
  6. //----------------------------------------------------------------------------
  7. #pragma once
  8. namespace Js
  9. {
  10. class WaiterList;
  11. typedef JsUtil::List<DWORD_PTR, HeapAllocator> SharableAgents;
  12. typedef JsUtil::BaseDictionary<uint, WaiterList *, HeapAllocator> IndexToWaitersMap;
  13. class SharedContents
  14. {
  15. public:
  16. BYTE *buffer; // Points to a heap allocated RGBA buffer, can be null
  17. IndexToWaitersMap *indexToWaiterList; // Map of agents waiting on a particular index.
  18. uint32 bufferLength; // Number of bytes allocated
  19. uint32 maxBufferLength = 0; // Maximum number of bytes to allocate (only used by WebAssemblySharedArrayBuffer)
  20. bool isWebAssembly = false;
  21. private:
  22. // Addref/release counter for current buffer, this is needed as the current buffer will be shared among different workers
  23. long refCount;
  24. public:
  25. long AddRef();
  26. long Release();
  27. bool IsWebAssembly() const { return isWebAssembly; }
  28. void SetIsWebAssembly() { isWebAssembly = true; }
  29. static int GetBufferOffset() { return offsetof(SharedContents, buffer); }
  30. static int GetBufferLengthOffset() { return offsetof(SharedContents, bufferLength); }
  31. #if DBG
  32. // This is mainly used for validation purpose as the wait/wake APIs should be used on the agents (Workers) among which this buffer is shared.
  33. SharableAgents *allowedAgents;
  34. CriticalSection csAgent;
  35. void AddAgent(DWORD_PTR agent);
  36. bool IsValidAgent(DWORD_PTR agent);
  37. #endif
  38. void Cleanup();
  39. SharedContents(BYTE* b, uint32 l, uint32 m)
  40. : buffer(b), bufferLength(l), maxBufferLength(m), refCount(1), indexToWaiterList(nullptr)
  41. #if DBG
  42. , allowedAgents(nullptr)
  43. #endif
  44. {
  45. }
  46. };
  47. class SharedArrayBuffer : public ArrayBufferBase
  48. {
  49. public:
  50. DEFINE_VTABLE_CTOR_ABSTRACT(SharedArrayBuffer, ArrayBufferBase);
  51. SharedArrayBuffer(DynamicType * type);
  52. SharedArrayBuffer(SharedContents *contents, DynamicType * type);
  53. class EntryInfo
  54. {
  55. public:
  56. static FunctionInfo NewInstance;
  57. static FunctionInfo Slice;
  58. static FunctionInfo GetterByteLength;
  59. static FunctionInfo GetterSymbolSpecies;
  60. };
  61. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  62. static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
  63. static Var EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...);
  64. static Var EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...);
  65. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  66. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  67. virtual uint32 GetByteLength() const override;
  68. virtual BYTE* GetBuffer() const override;
  69. static int GetByteLengthOffset() { Assert(false); return 0; }
  70. static int GetBufferOffset() { Assert(false); return 0; }
  71. static int GetSharedContentsOffset() { return offsetof(SharedArrayBuffer, sharedContents); }
  72. virtual bool IsArrayBuffer() override { return false; }
  73. virtual bool IsSharedArrayBuffer() override { return true; }
  74. virtual ArrayBuffer * GetAsArrayBuffer() { return nullptr; }
  75. virtual SharedArrayBuffer * GetAsSharedArrayBuffer() override;
  76. WaiterList *GetWaiterList(uint index);
  77. SharedContents *GetSharedContents() { return sharedContents; }
  78. #if defined(TARGET_64)
  79. //maximum 2G -1 for amd64
  80. static const uint32 MaxSharedArrayBufferLength = 0x7FFFFFFF;
  81. #else
  82. // maximum 1G to avoid arithmetic overflow.
  83. static const uint32 MaxSharedArrayBufferLength = 1 << 30;
  84. #endif
  85. virtual bool IsValidVirtualBufferLength(uint length) const;
  86. protected:
  87. // maxLength is necessary only for WebAssemblySharedArrayBuffer to know how much it can grow
  88. // Must call after constructor of child class is completed. Required to be able to make correct virtual calls
  89. void Init(uint32 length, uint32 maxLength);
  90. virtual BYTE* AllocBuffer(uint32 length, uint32 maxLength);
  91. virtual void FreeBuffer(BYTE* buffer, uint32 length, uint32 maxLength);
  92. FieldNoBarrier(SharedContents *) sharedContents;
  93. static CriticalSection csSharedArrayBuffer;
  94. };
  95. template <> inline bool VarIsImpl<SharedArrayBuffer>(RecyclableObject* obj)
  96. {
  97. return JavascriptOperators::GetTypeId(obj) == TypeIds_SharedArrayBuffer;
  98. }
  99. class JavascriptSharedArrayBuffer : public SharedArrayBuffer
  100. {
  101. protected:
  102. DEFINE_VTABLE_CTOR(JavascriptSharedArrayBuffer, SharedArrayBuffer);
  103. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptSharedArrayBuffer);
  104. public:
  105. static JavascriptSharedArrayBuffer* Create(uint32 length, DynamicType * type);
  106. static JavascriptSharedArrayBuffer* Create(SharedContents *sharedContents, DynamicType * type);
  107. virtual void Dispose(bool isShutdown) override;
  108. virtual void Finalize(bool isShutdown) override;
  109. protected:
  110. JavascriptSharedArrayBuffer(DynamicType * type);
  111. JavascriptSharedArrayBuffer(SharedContents *sharedContents, DynamicType * type);
  112. };
  113. #ifdef ENABLE_WASM_THREADS
  114. class WebAssemblySharedArrayBuffer : public JavascriptSharedArrayBuffer
  115. {
  116. protected:
  117. DEFINE_VTABLE_CTOR(WebAssemblySharedArrayBuffer, JavascriptSharedArrayBuffer);
  118. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(WebAssemblySharedArrayBuffer);
  119. public:
  120. static WebAssemblySharedArrayBuffer* Create(uint32 length, uint32 maxLength, DynamicType * type);
  121. static WebAssemblySharedArrayBuffer* Create(SharedContents *sharedContents, DynamicType * type);
  122. virtual bool IsValidVirtualBufferLength(uint length) const override;
  123. virtual bool IsWebAssemblyArrayBuffer() override { return true; }
  124. _Must_inspect_result_ bool GrowMemory(uint32 newBufferLength);
  125. protected:
  126. virtual BYTE* AllocBuffer(uint32 length, uint32 maxLength) override;
  127. virtual void FreeBuffer(BYTE* buffer, uint32 length, uint32 maxLength) override;
  128. private:
  129. WebAssemblySharedArrayBuffer(DynamicType * type);
  130. WebAssemblySharedArrayBuffer(SharedContents *sharedContents, DynamicType * type);
  131. void ValidateBuffer();
  132. };
  133. template <> inline bool VarIsImpl<WebAssemblySharedArrayBuffer>(RecyclableObject* obj)
  134. {
  135. return VarIs<SharedArrayBuffer>(obj) && UnsafeVarTo<SharedArrayBuffer>(obj)->IsWebAssemblyArrayBuffer();
  136. }
  137. #endif
  138. // An agent can be viewed as a worker
  139. struct AgentOfBuffer
  140. {
  141. public:
  142. AgentOfBuffer() :identity(NULL), event(NULL) {}
  143. AgentOfBuffer(DWORD_PTR agent, HANDLE e) :identity(agent), event(e) {}
  144. static bool AgentCanSuspend(ScriptContext *scriptContext);
  145. DWORD_PTR identity;
  146. HANDLE event;
  147. };
  148. typedef JsUtil::List<AgentOfBuffer, HeapAllocator> Waiters;
  149. class WaiterList
  150. {
  151. public:
  152. WaiterList();
  153. void Cleanup();
  154. bool _Requires_lock_held_(csForAccess.cs) AddAndSuspendWaiter(DWORD_PTR waiter, uint32 timeout);
  155. void RemoveWaiter(DWORD_PTR waiter);
  156. uint32 RemoveAndWakeWaiters(int32 count);
  157. CriticalSection * GetCriticalSectionForAccess() { return &csForAccess; }
  158. private:
  159. void InitWaiterList();
  160. bool Contains(DWORD_PTR agent);
  161. Waiters * m_waiters;
  162. // Below CS is used for synchronizing access in wait/wake API
  163. CriticalSection csForAccess;
  164. };
  165. }