Type helpers generate bad code, especially for constant strings
Type helpers always receive their implicit self parameter as var, thus forcing it into memory instead of a register. Not a big problem (except when it is), but constant strings are even worse.
This code
{$mode objfpc} {$longstrings on} {$modeswitch typehelpers}
type
StringHelper = type helper for string
function Len: SizeInt;
end;
function StringHelper.Len: SizeInt;
begin
result := length(self);
end;
function Len(const s: string): SizeInt;
begin
result := length(s);
end;
const
ConstantString = 'constant string';
begin
ConstantString.Len;
Len(ConstantString);
end.
produces the following assembly (x86-64-win64):
# ConstantString.Len;
lea -0x8(%rbp),%rcx
callq 0x100002990 <fpc_ansistr_decr_ref>
lea 0xd9a9(%rip),%rdx # 0x10000f020 <FPC_RESOURCESTRINGTABLES+32>
lea -0x8(%rbp),%rcx
callq 0x100002a00 <fpc_ansistr_assign>
lea -0x8(%rbp),%rcx
callq 0x100001610 <LEN>
# Len(ConstantString);
lea 0xd990(%rip),%rcx # 0x10000f020 <FPC_RESOURCESTRINGTABLES+32>
callq 0x100001620 <LEN>
I have a relatively simple case when this slows things down by the factor of two. Imagine a method StringHelper.NextCp(var pos: SizeInt): Codepoint that iterates codepoints, and a constant string storing said codepoints.
Moreover, when inlined, Len(ConstantString) is optimized down to 15 but helper version is not.
Is there any possibility to have type helpers accept self as const (which will pass them by value when it sees fit) instead of var when they don't change self, don't take its address, etc.?