The patch at the end of the message updates
class function TObject.InitInstance(instance : pointer) : tobject;
class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
in order to mimic the coding style of
procedure InitInterfacePointers(objclass: tclass;instance : pointer);
Now, a further improvement might be to replace the "while" loops with "for" loops because, as far as I know, during the "for" loops "i" will be kept in a CPU register, which increases speed most of the times. There are two things to consider and both of them need the experience of a rtl compiler developer:
1)class function TObject.MethodAddress(const name : shortstring) : codepointer; and class function TObject.MethodName(address : codepointer) : shortstring;, both of them have "for i:=0 to methodtable^.count-1 do" without an "if methodtable^.count>0 then" check, even though variable "i : dword;". This is either a bug, either if assigned(methodtable) then methodtable^.count is automatically greater than 0(which would allow the rtl compiler developer to avoid a prior "if methodtable^.count>0 then" check in the code).
Now the questions similar to the situation presented in the above paragraph. If assigned(mopinittable) can mopinittable^.Count be zero? If assigned(intftable) can intftable^.EntryCount be zero? Maybe automatically they are greater than zero. I consider this situation not just because of what I've written in the previous paragraph, but also because of the comment "{ ensure that no range check errors pop up with the [0..0] array }" at class function TObject.InitInstance, comment associated with compiler directives that I've removed in the patch.
2)If the answer is yes to the questions presented above, would it be better to replace in the mentioned routines "i:=... while i>0 do...begin ... inc(i);end;" with "if i>0 then for i:=i downto 1 do begin...end;"? The value of "i" during the loop would be stored in a CPU register, most likely making the loop faster.
By the way, I notice that "for...to -1 do" and "for ...downto 1 do" loops are not optimized for near zero comparisons. The code shows a cmp instruction which can be avoided by using a test one, removing at conditional jumps the "or equal".
Here is a patch that uses "while" loops. Changing "while" loops into "for" loops should also consider updating the coding style in the other mentioned functions.
diff --git a/rtl/inc/objpas.inc b/rtl/inc/objpas.inc
index 5479d3698a..ae836317fc 100644
--- a/rtl/inc/objpas.inc
+++ b/rtl/inc/objpas.inc
@@ -351,7 +351,7 @@
var
ovmt: PVmt;
- i: longint;
+ i: sizeuint;
intftable: pinterfacetable;
Res: pinterfaceentry;
begin
@@ -365,13 +365,14 @@
begin
i:=intftable^.EntryCount;
Res:=@intftable^.Entries[0];
- while i>0 do begin
- if Res^.IType = etStandard then
- ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
- pointer(Res^.VTable);
- inc(Res);
- dec(i);
- end;
+ while i>0 do
+ begin
+ if Res^.IType = etStandard then
+ ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
+ pointer(Res^.VTable);
+ inc(Res);
+ dec(i);
+ end;
end;
ovmt:=ovmt^.vParent;
end;
@@ -385,8 +386,9 @@
inittable : pointer;
{$ifdef FPC_HAS_FEATURE_RTTI}
mopinittable : PRTTIRecordOpOffsetTable;
+ Res : ^TRTTIRecordOpOffsetEntry;
{$endif def FPC_HAS_FEATURE_RTTI}
- i : longint;
+ i : longword;
{$endif VER3_0}
begin
{ the size is saved at offset 0 }
@@ -409,12 +411,14 @@
mopinittable:=RTTIRecordMopInitTable(inittable);
if assigned(mopinittable) then
begin
- {$push}
- { ensure that no range check errors pop up with the [0..0] array }
- {$R-}
- for i:=0 to mopinittable^.Count-1 do
- TRTTIRecVarOp(mopinittable^.Entries[i].ManagmentOperator)(PByte(Instance)+mopinittable^.Entries[i].FieldOffset);
- {$pop}
+ i:=mopinittable^.Count;
+ Res:=@mopinittable^.Entries[0];
+ while i>0 do
+ begin
+ TRTTIRecVarOp(Res^.ManagmentOperator)(PByte(Instance)+Res^.FieldOffset);
+ inc(Res);
+ dec(i);
+ end;
end;
end;
end;
@@ -930,7 +934,7 @@ TMsgInt = record
class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
var
- i: longint;
+ i: sizeuint;
intftable: pinterfacetable;
ovmt: PVmt;
begin
@@ -942,11 +946,14 @@ TMsgInt = record
if assigned(intftable) then
{$endif VER3_0}
begin
- for i:=0 to intftable^.EntryCount-1 do
+ i:=intftable^.EntryCount;
+ result:=@intftable^.Entries[0];
+ while i>0 do
begin
- result:=@intftable^.Entries[i];
if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
Exit;
+ inc(Result);
+ dec(i);
end;
end;
ovmt := ovmt^.vParent;
@@ -956,7 +963,7 @@ TMsgInt = record
class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
var
- i: longint;
+ i: sizeuint;
intftable: pinterfacetable;
ovmt: PVmt;
begin
@@ -968,11 +975,14 @@ TMsgInt = record
if assigned(intftable) then
{$endif VER3_0}
begin
- for i:=0 to intftable^.EntryCount-1 do
+ i:=intftable^.EntryCount;
+ result:=@intftable^.Entries[0];
+ while i>0 do
begin
- result:=@intftable^.Entries[i];
if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
Exit;
+ inc(Result);
+ dec(i);
end;
end;
ovmt := ovmt^.vParent;