A
Andreas Hausladen
Unregistered / Unconfirmed
GUEST, unregistred user!
While debugging the String4D code to hunt down a bug in the CompilerSpeedPack, I saw a lot of CopyRecord/FinalizeRecord calls with a try/finally that the compiler generated.
If you have a record with managed fields (string, interface, …) and use it as a function return type the Delphi compiler will change the function into a procedure with an extra var-parameter. So you would think that the compiler treats the result-parameter like a normal var-parameter, but that isn’t the case. The compiler will generate code that guarantees that the result record isn’t changed if the called function throws an exception. For this is adds a temporary record that is used for the function result and then copies it to the target record.
type
TMyRec = record
Value: string;
end;
function InternalGetRec: TMyRec;
begin
Result.Value := 'Hello';
end;
function GetRec: TMyRec;
begin
Result := InternalGetRec;
end;
procedure Test;
var
R: TMyRec;
begin
R := GetRec;
end;
The compiler rewrites the “Test” function to:
procedure Test;
var
R, TempR: TMyRec;
begin
try
GetRec(TempR);
CopyRecord(TempR, R, TypeInfo(TMyRec));
finally
FinalizeArray([TempR, R], TypeInfo(TMyRec));
end;
end;
The same happens if you assign another function’s record result value to your own record result value. The compiler rewrites the “GetRec” function’s code to:
function GetRec: TMyRec;
var
TempResult: TMyRec;
begin
try
InternalGetRec(TempResult);
CopyRecord(TempResult, Result, TypeInfo(TMyRec));
finally
FinalizeRecord(TempRecord, TypeInfo(TMyRec));
end;
end;
Because the compiler assumes that you may want to use “Result” in the function after the call, it has to guarantee that it is unchanged if an exception is thrown. But if it is the last statement in the function and not secured by an explicit try/finally/except where “Result” is used again, an optimization could be to omit the temporary record, making the code a lot faster.
查看更多...
If you have a record with managed fields (string, interface, …) and use it as a function return type the Delphi compiler will change the function into a procedure with an extra var-parameter. So you would think that the compiler treats the result-parameter like a normal var-parameter, but that isn’t the case. The compiler will generate code that guarantees that the result record isn’t changed if the called function throws an exception. For this is adds a temporary record that is used for the function result and then copies it to the target record.
type
TMyRec = record
Value: string;
end;
function InternalGetRec: TMyRec;
begin
Result.Value := 'Hello';
end;
function GetRec: TMyRec;
begin
Result := InternalGetRec;
end;
procedure Test;
var
R: TMyRec;
begin
R := GetRec;
end;
The compiler rewrites the “Test” function to:
procedure Test;
var
R, TempR: TMyRec;
begin
try
GetRec(TempR);
CopyRecord(TempR, R, TypeInfo(TMyRec));
finally
FinalizeArray([TempR, R], TypeInfo(TMyRec));
end;
end;
The same happens if you assign another function’s record result value to your own record result value. The compiler rewrites the “GetRec” function’s code to:
function GetRec: TMyRec;
var
TempResult: TMyRec;
begin
try
InternalGetRec(TempResult);
CopyRecord(TempResult, Result, TypeInfo(TMyRec));
finally
FinalizeRecord(TempRecord, TypeInfo(TMyRec));
end;
end;
Because the compiler assumes that you may want to use “Result” in the function after the call, it has to guarantee that it is unchanged if an exception is thrown. But if it is the last statement in the function and not secured by an explicit try/finally/except where “Result” is used again, an optimization could be to omit the temporary record, making the code a lot faster.
查看更多...