sysmarshal.inc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. constructor TMarshaller.TState.Create;
  2. begin
  3. inherited Create;
  4. DeferHead.Alloc := sizeof(TDeferQueueNode.StaticStore);
  5. DeferTail := @DeferHead;
  6. end;
  7. destructor TMarshaller.TState.Destroy;
  8. begin
  9. Flush;
  10. inherited Destroy;
  11. end;
  12. procedure TMarshaller.TState.Flush;
  13. begin
  14. try
  15. FlushQueue;
  16. finally
  17. ClearQueue;
  18. end;
  19. end;
  20. procedure TMarshaller.TState.FlushQueue;
  21. var
  22. Qn: PDeferQueueNode;
  23. D: PDeferBase;
  24. Pos: SizeInt;
  25. begin
  26. Qn := @DeferHead;
  27. repeat
  28. Pos := 0;
  29. while Pos < Qn^.Used do
  30. begin
  31. Pointer(D) := Pointer(PByte(Qn^.Mem)) + Pos;
  32. Pos := Pos + SizeOf(D^); { This is runtime SizeOf of the actual instance that accesses VMT. }
  33. D^.Done;
  34. end;
  35. Qn := Qn^.Next;
  36. until not Assigned(Qn);
  37. end;
  38. procedure TMarshaller.TState.ClearQueue;
  39. var
  40. Qn, Nx: PDeferQueueNode;
  41. begin
  42. Qn := DeferHead.Next;
  43. DeferHead.Next := nil;
  44. DeferHead.Used := 0;
  45. while Assigned(Qn) do
  46. begin
  47. Nx := Qn^.Next;
  48. System.FreeMem(Qn);
  49. Qn := Nx;
  50. end;
  51. end;
  52. procedure TMarshaller.TState.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
  53. var
  54. Qn: PDeferQueueNode;
  55. D: PDeferBase;
  56. Pos: SizeInt;
  57. begin
  58. Qn := @DeferHead;
  59. repeat
  60. Pos := 0;
  61. while Pos < Qn^.Used do
  62. begin
  63. Pointer(D) := Pointer(PByte(Qn^.Mem)) + Pos;
  64. Pos := Pos + SizeOf(D^); { This is runtime SizeOf of the actual instance that accesses VMT. }
  65. D^.NotePointerChanged(OldPtr, NewPtr);
  66. end;
  67. Qn := Qn^.Next;
  68. until not Assigned(Qn);
  69. end;
  70. constructor TMarshaller.TDeferBase.Init;
  71. begin
  72. end;
  73. procedure TMarshaller.TDeferBase.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
  74. begin
  75. end;
  76. destructor TMarshaller.TDeferFreeMem.Done;
  77. begin
  78. TMarshal.FreeMem(P);
  79. P := TPtrWrapper.NilValue;
  80. end;
  81. procedure TMarshaller.TDeferFreeMem.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
  82. begin
  83. if P = OldPtr then
  84. P := NewPtr;
  85. end;
  86. class procedure TMarshaller.TAddressableUnfixArraySpecialization.UnfixArray(ArrPtr: TPtrWrapper);
  87. begin
  88. TMarshal.specialize UnfixArray<T>(ArrPtr);
  89. end;
  90. destructor TMarshaller.TDeferUnfix.Done;
  91. begin
  92. if Assigned(P.Value) then
  93. Unfix(P);
  94. P := TPtrWrapper.NilValue;
  95. end;
  96. destructor TMarshaller.TDeferMoveToSBAndFree.Done;
  97. begin
  98. try
  99. if Assigned(SB) then
  100. begin
  101. SB.Clear;
  102. SB.Append(TMarshal.ReadStringAsUnicodeUpTo(Src, MaxLen));
  103. end;
  104. finally
  105. TMarshal.FreeMem(Src);
  106. Src := TPtrWrapper.NilValue;
  107. end;
  108. end;
  109. function TMarshaller.PushDefer(InstanceSize: SizeInt): PDeferBase;
  110. var
  111. Qn: PDeferQueueNode;
  112. Alloc: SizeInt;
  113. begin
  114. { Careful: FState starts uninitialized, Assigned(FStateLife) must be used rather than Assigned(FState). }
  115. if not Assigned(FStateLife) then
  116. begin
  117. FState := TState.Create;
  118. FStateLife := FState;
  119. end;
  120. Qn := FState.DeferTail;
  121. if InstanceSize <= Qn^.Alloc - Qn^.Used then
  122. begin
  123. { Enough space. }
  124. Result := Pointer(PByte(Qn^.Mem)) + Qn^.Used;
  125. Qn^.Used := Qn^.Used + InstanceSize;
  126. end else
  127. begin
  128. { Not enough space; allocate new node. }
  129. Alloc := InstanceSize + Qn^.Alloc + SizeInt(SizeUint(Qn^.Alloc) div 2);
  130. Qn := GetMem(SizeOf(TDeferQueueNode) - SizeOf(TDeferQueueNode.StaticStore) + Alloc);
  131. Qn^.Used := InstanceSize;
  132. Qn^.Alloc := Alloc;
  133. Qn^.Next := nil;
  134. FState.DeferTail^.Next := Qn;
  135. FState.DeferTail := Qn;
  136. Result := Pointer(PByte(Qn^.Mem));
  137. end;
  138. end;
  139. procedure TMarshaller.Flush;
  140. begin
  141. if Assigned(FStateLife) then
  142. FState.Flush;
  143. end;
  144. function TMarshaller.AllocMem(Size: SizeInt): TPtrWrapper;
  145. var
  146. D: PDeferFreeMem;
  147. begin
  148. Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
  149. D^.Init;
  150. Result := TMarshal.AllocMem(Size);
  151. D^.P := Result;
  152. end;
  153. function TMarshaller.ReallocMem(OldPtr: TPtrWrapper; NewSize: NativeInt): TPtrWrapper;
  154. begin
  155. if not Assigned(OldPtr.Value) then
  156. Exit(AllocMem(NewSize));
  157. Result := TMarshal.ReallocMem(OldPtr, NewSize);
  158. if (Result <> OldPtr) and Assigned(FStateLife) then
  159. FState.NotePointerChanged(OldPtr, Result);
  160. end;
  161. function TMarshaller.AllocStringAsAnsi(const Str: UnicodeString): TPtrWrapper;
  162. begin
  163. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), DefaultSystemCodePage);
  164. end;
  165. function TMarshaller.AllocStringAsAnsi(const Str: UnicodeString; CodePage: Word): TPtrWrapper;
  166. begin
  167. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CodePage);
  168. end;
  169. function TMarshaller.AllocStringAsUnicode(const Str: UnicodeString): TPtrWrapper;
  170. var
  171. D: PDeferFreeMem;
  172. begin
  173. Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
  174. D^.Init;
  175. Result := TMarshal.AllocStringAsUnicode(Str);
  176. D^.P := Result;
  177. end;
  178. function TMarshaller.AllocStringAsUtf8(const Str: UnicodeString): TPtrWrapper;
  179. begin
  180. Result := AllocStringAsAnsi(Str, CP_UTF8);
  181. end;
  182. function TMarshaller.AsAnsi(const S: UnicodeString): TPtrWrapper;
  183. begin
  184. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), DefaultSystemCodePage);
  185. end;
  186. function TMarshaller.AsAnsi(S: PUnicodeChar): TPtrWrapper;
  187. begin
  188. Result := AllocStringAsAnsi(S, Length(S), DefaultSystemCodePage);
  189. end;
  190. function TMarshaller.AsAnsi(const S: UnicodeString; CodePage: Word): TPtrWrapper;
  191. begin
  192. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), CodePage);
  193. end;
  194. function TMarshaller.AsAnsi(S: PUnicodeChar; CodePage: Word): TPtrWrapper;
  195. begin
  196. Result := AllocStringAsAnsi(S, Length(S), CodePage);
  197. end;
  198. function TMarshaller.AsUtf8(const S: UnicodeString): TPtrWrapper;
  199. begin
  200. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), CP_UTF8);
  201. end;
  202. function TMarshaller.AsUtf8(S: PUnicodeChar): TPtrWrapper;
  203. begin
  204. Result := AllocStringAsAnsi(S, Length(S), CP_UTF8);
  205. end;
  206. function TMarshaller.AllocStringAsAnsi(S: PUnicodeChar; Len: SizeInt; CodePage: Word): TPtrWrapper;
  207. var
  208. D: PDeferFreeMem;
  209. begin
  210. Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
  211. D^.Init;
  212. Result := TMarshal.AllocStringAsAnsi(S, Len, CodePage);
  213. D^.P := Result;
  214. end;
  215. function TMarshaller.AsRaw(const B: TBytes): TPtrWrapper;
  216. begin
  217. Result := specialize FixArray<Byte>(B);
  218. end;
  219. generic function TMarshaller.FixArray<T>(const Arr: specialize TArray<T>): TPtrWrapper;
  220. var
  221. D: PDeferUnfix;
  222. begin
  223. Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
  224. D^.Init;
  225. Result := TMarshal.specialize FixArray<T>(Arr);
  226. D^.Unfix := @specialize TAddressableUnfixArraySpecialization<T>.UnfixArray;
  227. D^.P := Result;
  228. end;
  229. function TMarshaller.FixString(var Str: UnicodeString): TPtrWrapper;
  230. var
  231. D: PDeferUnfix;
  232. begin
  233. Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
  234. D^.Init;
  235. Result := TMarshal.FixString(Str);
  236. D^.Unfix := @TMarshal.UnfixString;
  237. D^.P := Result;
  238. end;
  239. function TMarshaller.UnsafeFixString(const Str: UnicodeString): TPtrWrapper;
  240. var
  241. D: PDeferUnfix;
  242. begin
  243. Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
  244. D^.Init;
  245. Result := TMarshal.UnsafeFixString(Str);
  246. D^.Unfix := @TMarshal.UnfixString;
  247. D^.P := Result;
  248. end;
  249. function TMarshaller.InString(SB: TUnicodeStringBuilder; MaxLen: SizeInt): TPtrWrapper;
  250. var
  251. D: PDeferMoveToSBAndFree;
  252. begin
  253. Pointer(D) := PushDefer(SizeOf(TDeferMoveToSBAndFree));
  254. D^.Init;
  255. Result := TMarshal.AllocMem((MaxLen + 1) * SizeOf(UnicodeChar));
  256. D^.Src := Result;
  257. D^.SB := SB;
  258. D^.MaxLen := MaxLen;
  259. end;
  260. function TMarshaller.OutString(const S: UnicodeString): TPtrWrapper;
  261. var
  262. TS: UnicodeString;
  263. begin
  264. TS := S;
  265. Result := FixString(TS);
  266. end;
  267. function TMarshaller.InOutString(SB: TUnicodeStringBuilder; MaxLen: SizeInt): TPtrWrapper;
  268. var
  269. D: PDeferMoveToSBAndFree;
  270. NCopy: SizeInt;
  271. begin
  272. Pointer(D) := PushDefer(SizeOf(TDeferMoveToSBAndFree));
  273. D^.Init;
  274. Result := TMarshal.AllocMem((MaxLen + 1) * SizeOf(UnicodeChar));
  275. D^.Src := Result;
  276. NCopy := SB.Length;
  277. if MaxLen < NCopy then
  278. NCopy := MaxLen;
  279. TMarshal.WriteStringAsUnicode(Result, SB.ToString(0, NCopy), NCopy);
  280. D^.SB := SB;
  281. D^.MaxLen := MaxLen;
  282. end;