Tiny tweak: don't inline InitInstance
`InitInstance` is big enough so that not inlining it shouldn't have any negative impact on standard object creation, and inlining hurts the non-standard one. Imagine an object that has some data allocated and owned by itself, where the size of the data is unknown at compilation time but known at creation time and does not change for the lifetime of the object. You may want to allocate the instance and the data in the same memory block (I have more complex cases where this makes two orders of magnitude of memory savings, but even saving one allocation can feel nice enough to do it). This can be done by replacing single `constructor call on the class` (like `TFPList.Create`) with manual `GetMem(InstanceSize + ExtraDataSize)` + `InitInstance` + `constructor call on the instance`. Inlining `InitInstance` hurts here because different classes can viably use this trick ad-hoc without any wrapper, just calling `GetMem + InitInstance + constructor` explicitly :|. ```pascal {$mode objfpc} {$modeswitch duplicatelocals} type TFixedIntegerList = class items: pInteger; n: SizeUint; constructor Create(items: pInteger; n: SizeUint); // Allocates itself and items[] in the same block. class function Create(n: SizeUint; workaround: boolean): TFixedIntegerList; static; end; constructor TFixedIntegerList.Create(items: pInteger; n: SizeUint); begin inherited Create; self.items := items; self.n := n; end; class function TFixedIntegerList.Create(n: SizeUint; workaround: boolean): TFixedIntegerList; label InlinedStart, InlinedEnd, WorkaroundStart, WorkaroundEnd; type InitInstanceAsPlainProc = function(cls: pointer; instance: pointer): pointer; var itemsOfs, regionSize: SizeUint; region: pointer; begin itemsOfs := Align(InstanceSize, sizeof(integer)); regionSize := itemsOfs + n * sizeof(integer); region := GetMem(regionSize); if workaround then begin WorkaroundStart: region := InitInstanceAsPlainProc(@TFixedIntegerList.InitInstance)(TFixedIntegerList, region); WorkaroundEnd: end else begin InlinedStart: region := InitInstance(region); InlinedEnd: end; writeln('Inlined InitInstance takes ', CodePointer(@InlinedEnd) - CodePointer(@InlinedStart), ' b,'); writeln('while not inlined could take ', CodePointer(@WorkaroundEnd) - CodePointer(@WorkaroundStart), ' b.'); result := TFixedIntegerList(region); result.Create(pointer(result) + itemsOfs, n); end; begin TFixedIntegerList.Create(10, true).Free; end. ``` ``` Inlined InitInstance takes 146 b, while not inlined could take 22 b. ```
issue