SharedArrayBuffer.h 8.0 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. // 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. static bool Is(Var aValue);
  66. static SharedArrayBuffer* FromVar(Var aValue);
  67. static SharedArrayBuffer* UnsafeFromVar(Var aValue);
  68. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  69. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  70. virtual uint32 GetByteLength() const override;
  71. virtual BYTE* GetBuffer() const override;
  72. static int GetByteLengthOffset() { Assert(false); return 0; }
  73. static int GetBufferOffset() { Assert(false); return 0; }
  74. static int GetSharedContentsOffset() { return offsetof(SharedArrayBuffer, sharedContents); }
  75. virtual bool IsArrayBuffer() override { return false; }
  76. virtual bool IsSharedArrayBuffer() override { return true; }
  77. virtual ArrayBuffer * GetAsArrayBuffer() { return nullptr; }
  78. virtual SharedArrayBuffer * GetAsSharedArrayBuffer() override { return SharedArrayBuffer::FromVar(this); }
  79. WaiterList *GetWaiterList(uint index);
  80. SharedContents *GetSharedContents() { return sharedContents; }
  81. #if defined(TARGET_64)
  82. //maximum 2G -1 for amd64
  83. static const uint32 MaxSharedArrayBufferLength = 0x7FFFFFFF;
  84. #else
  85. // maximum 1G to avoid arithmetic overflow.
  86. static const uint32 MaxSharedArrayBufferLength = 1 << 30;
  87. #endif
  88. virtual bool IsValidVirtualBufferLength(uint length) const;
  89. protected:
  90. // maxLength is necessary only for WebAssemblySharedArrayBuffer to know how much it can grow
  91. // Must call after constructor of child class is completed. Required to be able to make correct virtual calls
  92. void Init(uint32 length, uint32 maxLength);
  93. virtual BYTE* AllocBuffer(uint32 length, uint32 maxLength);
  94. virtual void FreeBuffer(BYTE* buffer, uint32 length, uint32 maxLength);
  95. FieldNoBarrier(SharedContents *) sharedContents;
  96. static CriticalSection csSharedArrayBuffer;
  97. };
  98. class JavascriptSharedArrayBuffer : public SharedArrayBuffer
  99. {
  100. protected:
  101. DEFINE_VTABLE_CTOR(JavascriptSharedArrayBuffer, SharedArrayBuffer);
  102. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptSharedArrayBuffer);
  103. public:
  104. static JavascriptSharedArrayBuffer* Create(uint32 length, DynamicType * type);
  105. static JavascriptSharedArrayBuffer* Create(SharedContents *sharedContents, DynamicType * type);
  106. virtual void Dispose(bool isShutdown) override;
  107. virtual void Finalize(bool isShutdown) override;
  108. protected:
  109. JavascriptSharedArrayBuffer(DynamicType * type);
  110. JavascriptSharedArrayBuffer(SharedContents *sharedContents, DynamicType * type);
  111. };
  112. #ifdef ENABLE_WASM_THREADS
  113. class WebAssemblySharedArrayBuffer : public JavascriptSharedArrayBuffer
  114. {
  115. protected:
  116. DEFINE_VTABLE_CTOR(WebAssemblySharedArrayBuffer, JavascriptSharedArrayBuffer);
  117. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(WebAssemblySharedArrayBuffer);
  118. public:
  119. static WebAssemblySharedArrayBuffer* Create(uint32 length, uint32 maxLength, DynamicType * type);
  120. static WebAssemblySharedArrayBuffer* Create(SharedContents *sharedContents, DynamicType * type);
  121. static bool Is(Var aValue);
  122. static WebAssemblySharedArrayBuffer* FromVar(Var aValue);
  123. virtual bool IsValidVirtualBufferLength(uint length) const override;
  124. virtual bool IsWebAssemblyArrayBuffer() override { return true; }
  125. _Must_inspect_result_ bool GrowMemory(uint32 newBufferLength);
  126. protected:
  127. virtual BYTE* AllocBuffer(uint32 length, uint32 maxLength) override;
  128. virtual void FreeBuffer(BYTE* buffer, uint32 length, uint32 maxLength) override;
  129. private:
  130. WebAssemblySharedArrayBuffer(DynamicType * type);
  131. WebAssemblySharedArrayBuffer(SharedContents *sharedContents, DynamicType * type);
  132. void ValidateBuffer();
  133. };
  134. #endif
  135. // An agent can be viewed as a worker
  136. struct AgentOfBuffer
  137. {
  138. public:
  139. AgentOfBuffer() :identity(NULL), event(NULL) {}
  140. AgentOfBuffer(DWORD_PTR agent, HANDLE e) :identity(agent), event(e) {}
  141. static bool AgentCanSuspend(ScriptContext *scriptContext);
  142. DWORD_PTR identity;
  143. HANDLE event;
  144. };
  145. typedef JsUtil::List<AgentOfBuffer, HeapAllocator> Waiters;
  146. class WaiterList
  147. {
  148. public:
  149. WaiterList();
  150. void Cleanup();
  151. bool _Requires_lock_held_(csForAccess.cs) AddAndSuspendWaiter(DWORD_PTR waiter, uint32 timeout);
  152. void RemoveWaiter(DWORD_PTR waiter);
  153. uint32 RemoveAndWakeWaiters(int32 count);
  154. CriticalSection * GetCriticalSectionForAccess() { return &csForAccess; }
  155. private:
  156. void InitWaiterList();
  157. bool Contains(DWORD_PTR agent);
  158. Waiters * m_waiters;
  159. // Below CS is used for synchronizing access in wait/wake API
  160. CriticalSection csForAccess;
  161. };
  162. }