wasmmem.inc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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 TLSMemblockSize : PTrUint;
  56. // Calculate the size of a TLS memory block.
  57. // This is the TLS size + Size of a pointer (cannot use TTLSMem for this)
  58. Var
  59. BlockSize : PTrUint;
  60. begin
  61. BlockSize:=Align(fpc_wasm32_tls_size+SizeOf(Pointer),fpc_wasm32_tls_align);
  62. TLSMemblockSize:=BlockSize*MemBlockCount;
  63. end;
  64. Function AllocateOSInfoBlock : POSMemInfoBlock;
  65. Var
  66. PMIB : POSMemInfoBlock;
  67. POMB : POSMemBlock;
  68. POSBlock,POSMem : PTLSMem;
  69. I : Integer;
  70. begin
  71. // allocate block
  72. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock');{$ENDIF}
  73. PMIB:=POSMemInfoBlock(SysOSAlloc(MemPageSize));
  74. if PMIB=Nil then
  75. begin
  76. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock nil');{$ENDIF}
  77. Halt(203);
  78. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('AllocateOSInfoBlock nil but halt returned');{$ENDIF}
  79. end;
  80. FillChar(PMIB^,SizeOf(TOSMemInfoBlock),#0);
  81. // Allocate corresponding TLS mem blocks
  82. POSBlock:=PTLSMem(SysOSAlloc(TLSMemblockSize));
  83. if POSBlock=Nil then
  84. Halt(203);
  85. POSMem:=POSBlock;
  86. For I:=0 to MemBlockCount-1 do
  87. begin
  88. PMIB^.Blocks[I].Data:=POSMem;
  89. POMB:=@(PMIB^.Blocks[I]);
  90. PosMem^.OSMemBlock:=POMB;
  91. Inc(Pointer(POSMem),BlockSize);
  92. end;
  93. AllocateOSInfoBlock:=PMIB;
  94. end;
  95. Function FindFreeOSBlock(aInfo: POSMemInfoBlock) : POSMemBlock;
  96. Var
  97. I : integer;
  98. Res : POSMemBlock;
  99. begin
  100. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock entry ('+IntToStr(PtrUint(aInfo))+')');{$ENDIF}
  101. Res:=Nil;
  102. I:=0;
  103. While (Res=Nil) and (I<MemBlockCount-1) do
  104. begin
  105. if Not aInfo^.Blocks[I].Used then
  106. begin
  107. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock: block '+IntToStr(i)+' is not used');{$ENDIF}
  108. aInfo^.Blocks[I].Used:=True;
  109. Res:=@(aInfo^.Blocks[I]);
  110. end;
  111. Inc(I);
  112. end;
  113. FindFreeOSBlock:=Res;
  114. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('FindFreeOSBlock exit ('+IntToStr(PtrUint(aInfo))+')');{$ENDIF}
  115. end;
  116. Procedure LockOSMem;
  117. begin
  118. // Todo
  119. end;
  120. Procedure UnLockOSMem;
  121. begin
  122. // Todo
  123. end;
  124. Function GetFreeOSBlock : POSMemBlock;
  125. Var
  126. aInfo : POSMemInfoBlock;
  127. Res : POSMemBlock;
  128. begin
  129. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock entry');{$ENDIF}
  130. LockOSMem;
  131. try
  132. Res:=nil;
  133. if TLSInfoBlock=Nil then
  134. begin
  135. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: Allocate OSInfoBlock');{$ENDIF}
  136. TLSInfoBlock:=AllocateOSInfoBlock;
  137. end
  138. else
  139. begin
  140. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: have OSInfoBlock ('+IntToStr(PtrUint(TLSInfoBlock)));{$ENDIF}
  141. end;
  142. aInfo:=TLSInfoBlock;
  143. While (Res=Nil) do
  144. begin
  145. Res:=FindFreeOSBlock(aInfo);
  146. if Res=Nil then
  147. begin
  148. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock: did not find free block, allocating another OSInfoBlock');{$ENDIF}
  149. if aInfo^.Next=Nil then
  150. aInfo^.Next:=AllocateOSInfoBlock;
  151. aInfo:=aInfo^.next;
  152. end;
  153. end;
  154. GetFreeOSBlock:=Res;
  155. finally
  156. UnlockOSMem
  157. end;
  158. {$IFDEF DEBUGWASMTHREADS}DebugWriteln('GetFreeOSBlock exit, result='+IntToStr(PtrUint(Res)));{$ENDIF}
  159. end;
  160. Procedure FreeOSInfoBlock(aBlock : POSMemInfoBlock);
  161. Var
  162. Next : POSMemInfoBlock;
  163. begin
  164. While aBlock<>Nil do
  165. begin
  166. Next:=aBlock^.Next;
  167. SysOsFree(aBlock^.Blocks[0].Data,TLSMemblockSize);
  168. SysOsFree(aBlock,MemPageSize);
  169. aBlock:=Next;
  170. end;
  171. end;
  172. Procedure ReleaseOSBlock (aBlock : POSMemBlock);
  173. begin
  174. aBlock^.Used:=False;
  175. end;