perf(linker): fix O(n²) string concatenation in internal linker (80s → 3s)

LkZeros built zero-padding strings by appending one byte at a time
(Result := Result + Chr(0)), which for a ~2.7 MB executable produced
trillions of byte copies. Replace with SetLength + PChar fill.

Also fix LkLE to pre-allocate via SetLength instead of concatenating
per-byte, and add an early-exit guard to LkCopyInto.
This commit is contained in:
Graeme Geldenhuys 2026-06-21 23:53:36 +01:00
parent 9d876b46aa
commit 05892561fe

View file

@ -309,15 +309,18 @@ end;
function LkZeros(ACount: Int64): string;
var
I: Int64;
P: PChar;
I: Integer;
begin
Result := '';
I := 0;
while I < ACount do
if ACount <= 0 then
begin
Result := Result + Chr(0);
I := I + 1;
Result := '';
Exit;
end;
SetLength(Result, Integer(ACount));
P := PChar(Result);
for I := 0 to Integer(ACount) - 1 do
P[I] := Chr(0);
end;
constructor TSectionMerger.Create;
@ -530,10 +533,12 @@ const
function LkLE(AVal: Int64; ANBytes: Integer): string;
var
I: Integer;
P: PChar;
begin
Result := '';
SetLength(Result, ANBytes);
P := PChar(Result);
for I := 0 to ANBytes - 1 do
Result := Result + Chr(Integer((AVal shr (I * 8)) and $FF));
P[I] := Chr(Integer((AVal shr (I * 8)) and $FF));
end;
{ Overwrite ABuf[AOff..] in place with ASrc's bytes (ABuf already large
@ -545,6 +550,7 @@ var
P: PChar;
I: Integer;
begin
if Length(ASrc) = 0 then Exit;
P := PChar(ABuf);
for I := 0 to Length(ASrc) - 1 do
P[AOff + I] := ASrc[I];