123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- constructor TMarshaller.TState.Create;
- begin
- inherited Create;
- DeferHead.Alloc := sizeof(TDeferQueueNode.StaticStore);
- DeferTail := @DeferHead;
- end;
- destructor TMarshaller.TState.Destroy;
- begin
- Flush;
- inherited Destroy;
- end;
- procedure TMarshaller.TState.Flush;
- begin
- try
- FlushQueue;
- finally
- ClearQueue;
- end;
- end;
- procedure TMarshaller.TState.FlushQueue;
- var
- Qn: PDeferQueueNode;
- D: PDeferBase;
- Pos: SizeInt;
- begin
- Qn := @DeferHead;
- repeat
- Pos := 0;
- while Pos < Qn^.Used do
- begin
- Pointer(D) := Pointer(PByte(Qn^.Mem)) + Pos;
- Pos := Pos + SizeOf(D^); { This is runtime SizeOf of the actual instance that accesses VMT. }
- D^.Done;
- end;
- Qn := Qn^.Next;
- until not Assigned(Qn);
- end;
- procedure TMarshaller.TState.ClearQueue;
- var
- Qn, Nx: PDeferQueueNode;
- begin
- Qn := DeferHead.Next;
- DeferHead.Next := nil;
- DeferHead.Used := 0;
- while Assigned(Qn) do
- begin
- Nx := Qn^.Next;
- System.FreeMem(Qn);
- Qn := Nx;
- end;
- end;
- procedure TMarshaller.TState.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
- var
- Qn: PDeferQueueNode;
- D: PDeferBase;
- Pos: SizeInt;
- begin
- Qn := @DeferHead;
- repeat
- Pos := 0;
- while Pos < Qn^.Used do
- begin
- Pointer(D) := Pointer(PByte(Qn^.Mem)) + Pos;
- Pos := Pos + SizeOf(D^); { This is runtime SizeOf of the actual instance that accesses VMT. }
- D^.NotePointerChanged(OldPtr, NewPtr);
- end;
- Qn := Qn^.Next;
- until not Assigned(Qn);
- end;
- constructor TMarshaller.TDeferBase.Init;
- begin
- end;
- procedure TMarshaller.TDeferBase.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
- begin
- end;
- destructor TMarshaller.TDeferFreeMem.Done;
- begin
- TMarshal.FreeMem(P);
- P := TPtrWrapper.NilValue;
- end;
- procedure TMarshaller.TDeferFreeMem.NotePointerChanged(OldPtr, NewPtr: TPtrWrapper);
- begin
- if P = OldPtr then
- P := NewPtr;
- end;
- class procedure TMarshaller.TAddressableUnfixArraySpecialization.UnfixArray(ArrPtr: TPtrWrapper);
- begin
- TMarshal.specialize UnfixArray<T>(ArrPtr);
- end;
- destructor TMarshaller.TDeferUnfix.Done;
- begin
- if Assigned(P.Value) then
- Unfix(P);
- P := TPtrWrapper.NilValue;
- end;
- destructor TMarshaller.TDeferMoveToSBAndFree.Done;
- begin
- try
- if Assigned(SB) then
- begin
- SB.Clear;
- SB.Append(TMarshal.ReadStringAsUnicodeUpTo(Src, MaxLen));
- end;
- finally
- TMarshal.FreeMem(Src);
- Src := TPtrWrapper.NilValue;
- end;
- end;
- function TMarshaller.PushDefer(InstanceSize: SizeInt): PDeferBase;
- var
- Qn: PDeferQueueNode;
- Alloc: SizeInt;
- begin
- { Careful: FState starts uninitialized, Assigned(FStateLife) must be used rather than Assigned(FState). }
- if not Assigned(FStateLife) then
- begin
- FState := TState.Create;
- FStateLife := FState;
- end;
- Qn := FState.DeferTail;
- if InstanceSize <= Qn^.Alloc - Qn^.Used then
- begin
- { Enough space. }
- Result := Pointer(PByte(Qn^.Mem)) + Qn^.Used;
- Qn^.Used := Qn^.Used + InstanceSize;
- end else
- begin
- { Not enough space; allocate new node. }
- Alloc := InstanceSize + Qn^.Alloc + SizeInt(SizeUint(Qn^.Alloc) div 2);
- Qn := GetMem(SizeOf(TDeferQueueNode) - SizeOf(TDeferQueueNode.StaticStore) + Alloc);
- Qn^.Used := InstanceSize;
- Qn^.Alloc := Alloc;
- Qn^.Next := nil;
- FState.DeferTail^.Next := Qn;
- FState.DeferTail := Qn;
- Result := Pointer(PByte(Qn^.Mem));
- end;
- end;
- procedure TMarshaller.Flush;
- begin
- if Assigned(FStateLife) then
- FState.Flush;
- end;
- function TMarshaller.AllocMem(Size: SizeInt): TPtrWrapper;
- var
- D: PDeferFreeMem;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
- D^.Init;
- Result := TMarshal.AllocMem(Size);
- D^.P := Result;
- end;
- function TMarshaller.ReallocMem(OldPtr: TPtrWrapper; NewSize: NativeInt): TPtrWrapper;
- begin
- if not Assigned(OldPtr.Value) then
- Exit(AllocMem(NewSize));
- Result := TMarshal.ReallocMem(OldPtr, NewSize);
- if (Result <> OldPtr) and Assigned(FStateLife) then
- FState.NotePointerChanged(OldPtr, Result);
- end;
- function TMarshaller.AllocStringAsAnsi(const Str: UnicodeString): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), DefaultSystemCodePage);
- end;
- function TMarshaller.AllocStringAsAnsi(const Str: UnicodeString; CodePage: Word): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CodePage);
- end;
- function TMarshaller.AllocStringAsUnicode(const Str: UnicodeString): TPtrWrapper;
- var
- D: PDeferFreeMem;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
- D^.Init;
- Result := TMarshal.AllocStringAsUnicode(Str);
- D^.P := Result;
- end;
- function TMarshaller.AllocStringAsUtf8(const Str: UnicodeString): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(Str, CP_UTF8);
- end;
- function TMarshaller.AsAnsi(const S: UnicodeString): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), DefaultSystemCodePage);
- end;
- function TMarshaller.AsAnsi(S: PUnicodeChar): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(S, Length(S), DefaultSystemCodePage);
- end;
- function TMarshaller.AsAnsi(const S: UnicodeString; CodePage: Word): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), CodePage);
- end;
- function TMarshaller.AsAnsi(S: PUnicodeChar; CodePage: Word): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(S, Length(S), CodePage);
- end;
- function TMarshaller.AsUtf8(const S: UnicodeString): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(PUnicodeChar(Pointer(S)), Length(S), CP_UTF8);
- end;
- function TMarshaller.AsUtf8(S: PUnicodeChar): TPtrWrapper;
- begin
- Result := AllocStringAsAnsi(S, Length(S), CP_UTF8);
- end;
- function TMarshaller.AllocStringAsAnsi(S: PUnicodeChar; Len: SizeInt; CodePage: Word): TPtrWrapper;
- var
- D: PDeferFreeMem;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferFreeMem));
- D^.Init;
- Result := TMarshal.AllocStringAsAnsi(S, Len, CodePage);
- D^.P := Result;
- end;
- function TMarshaller.AsRaw(const B: TBytes): TPtrWrapper;
- begin
- Result := specialize FixArray<Byte>(B);
- end;
- generic function TMarshaller.FixArray<T>(const Arr: specialize TArray<T>): TPtrWrapper;
- var
- D: PDeferUnfix;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
- D^.Init;
- Result := TMarshal.specialize FixArray<T>(Arr);
- D^.Unfix := @specialize TAddressableUnfixArraySpecialization<T>.UnfixArray;
- D^.P := Result;
- end;
- function TMarshaller.FixString(var Str: UnicodeString): TPtrWrapper;
- var
- D: PDeferUnfix;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
- D^.Init;
- Result := TMarshal.FixString(Str);
- D^.Unfix := @TMarshal.UnfixString;
- D^.P := Result;
- end;
- function TMarshaller.UnsafeFixString(const Str: UnicodeString): TPtrWrapper;
- var
- D: PDeferUnfix;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferUnfix));
- D^.Init;
- Result := TMarshal.UnsafeFixString(Str);
- D^.Unfix := @TMarshal.UnfixString;
- D^.P := Result;
- end;
- function TMarshaller.InString(SB: TUnicodeStringBuilder; MaxLen: SizeInt): TPtrWrapper;
- var
- D: PDeferMoveToSBAndFree;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferMoveToSBAndFree));
- D^.Init;
- Result := TMarshal.AllocMem((MaxLen + 1) * SizeOf(UnicodeChar));
- D^.Src := Result;
- D^.SB := SB;
- D^.MaxLen := MaxLen;
- end;
- function TMarshaller.OutString(const S: UnicodeString): TPtrWrapper;
- var
- TS: UnicodeString;
- begin
- TS := S;
- Result := FixString(TS);
- end;
- function TMarshaller.InOutString(SB: TUnicodeStringBuilder; MaxLen: SizeInt): TPtrWrapper;
- var
- D: PDeferMoveToSBAndFree;
- NCopy: SizeInt;
- begin
- Pointer(D) := PushDefer(SizeOf(TDeferMoveToSBAndFree));
- D^.Init;
- Result := TMarshal.AllocMem((MaxLen + 1) * SizeOf(UnicodeChar));
- D^.Src := Result;
- NCopy := SB.Length;
- if MaxLen < NCopy then
- NCopy := MaxLen;
- TMarshal.WriteStringAsUnicode(Result, SB.ToString(0, NCopy), NCopy);
- D^.SB := SB;
- D^.MaxLen := MaxLen;
- end;
|