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.?

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information