wasmmem.inc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. {%MainUnit system.pp}
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2022 by Michael Van Canneyt,
  5. member of the Free Pascal development team.
  6. WASM minimal memory manager
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {
  14. WASM minimal TLS memory manager
  15. We can't use system unit memory manager, it uses threadvars.
  16. Wasm allocates new mem in pages of MemPageSize, but never frees blocks.
  17. So we must take care of freeing ourselves.
  18. We allocate 2 kind of blocks:
  19. - a pointer block TOSMemInfoBlock of MemBlockCount TOsMemBlock structure.
  20. linked. Each TOSMemBlock record has a pointer to TLS memory and a
  21. boolean to say whether it is used.
  22. - a TLS memory block, divided in blocks of (TLS size + SizeOf(Pointer))
  23. For each TLS block The first SizeOf(Pointer) bytes points back to the
  24. TOsMemBlock pointing to the TLS Block.
  25. This structure is represented by the TTLSMem structure
  26. }
  27. Type
  28. POSMemBlock = ^TOSMemBlock;
  29. PTLSMem = ^TTLSMem;
  30. TTLSMem = Record
  31. OSMemBlock : POSMemBlock;
  32. // Actually TTLSSize bytes, but we don't know in advance how much it is.
  33. TLSMemory : Array[0..0] of Byte;
  34. end;
  35. TOSMemBlock = record
  36. Data : PTLSMem;
  37. Used : Boolean;
  38. end;
  39. Const
  40. MemPageSize = 65536;
  41. // Theoretical TOSMemBlock record count that fits in a page. (around 4000)
  42. MaxPageMemBlockCount = (MemPageSize - (2 * SizeOf(Pointer))) div SizeOf(TOSMemBlock);
  43. // Actual used record count. Should be less than MaxPageMemBlockCount.
  44. MemBlockCount = 1000;
  45. Type
  46. TOSMemBlockArray = Array[0..MemBlockCount-1] of TOSMemBlock;
  47. POSMemInfoBlock = ^TOSMemInfoBlock;
  48. TOSMemInfoBlock = record
  49. Blocks : TOSMemBlockArray;
  50. Next : POSMemInfoBlock;
  51. end;
  52. Var
  53. // Root block of linked list of TOSMemInfoBlock
  54. TLSInfoBlock : POSMemInfoBlock = nil;
  55. Function GetSingleTLSMemblockSize : PTrUint;
  56. begin
  57. Result:=Align(fpc_wasm32_tls_size+SizeOf(Pointer),fpc_wasm32_tls_align);
  58. end;
  59. Function TLSMemblockSize : PTrUint;
  60. // Calculate the size of a TLS memory block.
  61. // This is the TLS size + Size of a pointer (cannot use TTLSMem for this)
  62. Var
  63. lBlockSize : PTrUint;
  64. begin
  65. lBlockSize:=GetSingleTLSMemblockSize;
  66. TLSMemblockSize:=lBlockSize*MemBlockCount;
  67. end;
  68. Function AllocateOSInfoBlock : POSMemInfoBlock;
  69. Var
  70. PMIB : POSMemInfoBlock;
  71. POMB : POSMemBlock;
  72. POSBlock,POSMem : PTLSMem;
  73. I : Integer;
  74. lBlockSize : PTrUint;
  75. begin
  76. // allocate block
  77. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock');{$ENDIF}
  78. PMIB:=POSMemInfoBlock(SysOSAlloc(MemPageSize));
  79. if PMIB=Nil then
  80. begin
  81. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock nil');{$ENDIF}
  82. Halt(203);
  83. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock nil but halt returned');{$ENDIF}
  84. end;
  85. FillChar(PMIB^,SizeOf(TOSMemInfoBlock),#0);
  86. // Allocate corresponding TLS mem blocks
  87. POSBlock:=PTLSMem(SysOSAlloc(TLSMemblockSize));
  88. if POSBlock=Nil then
  89. Halt(203);
  90. lBlockSize:=GetSingleTLSMemblockSize;
  91. POSMem:=POSBlock;
  92. For I:=0 to MemBlockCount-1 do
  93. begin
  94. PMIB^.Blocks[I].Data:=POSMem;
  95. POMB:=@(PMIB^.Blocks[I]);
  96. PosMem^.OSMemBlock:=POMB;
  97. Inc(Pointer(POSMem),lBlockSize);
  98. end;
  99. AllocateOSInfoBlock:=PMIB;
  100. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock done');{$ENDIF}
  101. end;
  102. Function FindFreeOSBlock(aInfo: POSMemInfoBlock) : POSMemBlock;
  103. Var
  104. I : integer;
  105. Res : POSMemBlock;
  106. begin
  107. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock entry ('+IntToStr(PtrUint(aInfo))+')');{$ENDIF}
  108. Res:=Nil;
  109. I:=0;
  110. While (Res=Nil) and (I<MemBlockCount-1) do
  111. begin
  112. if Not aInfo^.Blocks[I].Used then
  113. begin
  114. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock: block '+IntToStr(i)+' is not used');{$ENDIF}
  115. aInfo^.Blocks[I].Used:=True;
  116. Res:=@(aInfo^.Blocks[I]);
  117. end;
  118. Inc(I);
  119. end;
  120. FindFreeOSBlock:=Res;
  121. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock exit ('+IntToStr(PtrUint(aInfo))+')');{$ENDIF}
  122. end;
  123. Procedure LockOSMem;
  124. begin
  125. // Todo
  126. end;
  127. Procedure UnLockOSMem;
  128. begin
  129. // Todo
  130. end;
  131. Function GetFreeOSBlock : POSMemBlock;
  132. Var
  133. aInfo : POSMemInfoBlock;
  134. Res : POSMemBlock;
  135. begin
  136. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock entry');{$ENDIF}
  137. LockOSMem;
  138. try
  139. Res:=nil;
  140. if TLSInfoBlock=Nil then
  141. begin
  142. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: Allocate OSInfoBlock');{$ENDIF}
  143. TLSInfoBlock:=AllocateOSInfoBlock;
  144. end
  145. else
  146. begin
  147. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: have OSInfoBlock ('+IntToStr(PtrUint(TLSInfoBlock)));{$ENDIF}
  148. end;
  149. aInfo:=TLSInfoBlock;
  150. While (Res=Nil) do
  151. begin
  152. Res:=FindFreeOSBlock(aInfo);
  153. if Res=Nil then
  154. begin
  155. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: did not find free block, allocating another OSInfoBlock');{$ENDIF}
  156. if aInfo^.Next=Nil then
  157. aInfo^.Next:=AllocateOSInfoBlock;
  158. aInfo:=aInfo^.next;
  159. end;
  160. end;
  161. GetFreeOSBlock:=Res;
  162. finally
  163. UnlockOSMem
  164. end;
  165. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock exit, result='+IntToStr(PtrUint(Res)));{$ENDIF}
  166. end;
  167. Procedure FreeOSInfoBlock(aBlock : POSMemInfoBlock);
  168. Var
  169. Next : POSMemInfoBlock;
  170. begin
  171. While aBlock<>Nil do
  172. begin
  173. Next:=aBlock^.Next;
  174. SysOsFree(aBlock^.Blocks[0].Data,TLSMemblockSize);
  175. SysOsFree(aBlock,MemPageSize);
  176. aBlock:=Next;
  177. end;
  178. end;
  179. Procedure ReleaseOSBlock (aBlock : POSMemBlock);
  180. begin
  181. aBlock^.Used:=False;
  182. end;