TMS FixInsight and the inline directive

Bookmarks: 

Monday, April 24, 2017

The Delphi compiler allows functions and procedures to be tagged with the inline directive to improve performance. If the function or procedure meets certain criteria, the compiler will insert code directly, rather than generating a call. Embarcadero docwiki gives a list of conditions under which inlining does or does not occur.

One of basic conditions says: within a unit, the body for an inline function should be defined before calls to the function are made.

TMS FixInsight 2017.04 introduces rule O805 “Inline marked routine comes after its call in the same unit”. Let’s check FMX and VCL code to see if Embarcadero follows their own rules. Short answer: it doesn’t.

I will give a couple of examples from Delphi 10.1 Berlin (version 24.0.22858.6822).

Vcl.Controls.pas
//at line 8529 
procedure TWinControl.ReadState(Reader: TReader);
begin
  DisableAlign;
  try
    inherited ReadState(Reader);
  finally
    EnableAlign;
  end;
  FixupTabList;
  if FParent <> nil then Perform(CM_PARENTCTL3DCHANGED, 0, 0);
  UpdateControlState;
end;

Vcl.Controls.pas
//at line 9010
procedure TWinControl.AlignControl(AControl: TControl);
var
  Rect: TRect;
begin
  if not HandleAllocated or (csDestroying in ComponentState) then Exit;
  if FAlignLevel <> 0 then
    Include(FControlState, csAlignmentNeeded)
  else
  begin
    DisableAlign;
    try
      Rect := GetClientRect;
      AlignControls(AControl, Rect);
    finally
      Exclude(FControlState, csAlignmentNeeded);
      EnableAlign;
    end;
  end;
end;

Vcl.Controls.pas
//at line 9030 
procedure TWinControl.DisableAlign;
begin
  Inc(FAlignLevel);
end;
TWinControl.DisableAlign is an inline marked procedure. It is called at line 8531 and line 9019, but its body is defined after the calls – at line 9030. Obviously, this function will not be inlined.

One more example from another unit:

Fmx.ListView.pas
//at line 2430 
procedure TListViewBase.UpdateDeleteButtonLayout;
var
  RelRect: TRectF;
begin
  if (Adapter.Count < 1) or (FDeleteLayout = nil) or ((FDeleteButtonIndex = -1) and
    (FPrevDeleteButtonIndex = -1)) then
    Exit;
 
  if (FListingService <> nil) and (TListingTransitionFeature.DeleteButtonSlide in FListingService.GetTransitionFeatures) then
  begin
    FDeleteLayout.Width := DefaultDeleteButtonWidth * FDeleteModeTransitionAlpha;
    FDeleteButton.Opacity := 1;
  end
  else
  begin
    if FDeleteModeTransitionAlpha > 0 then
      FDeleteLayout.Width := DefaultDeleteButtonWidth
    else
      FDeleteLayout.Width := 0;
 
    FDeleteButton.Opacity := 0.5 + (FDeleteModeTransitionAlpha / 2);
  end;
 
  FDeleteLayout.Height := GetItemHeight(FDeleteButtonIndex);
  FDeleteLayout.Position.X := Width - FDeleteLayout.Width;
 
  if FDeleteButtonIndex = -1 then
    RelRect := GetItemRelRect(FPrevDeleteButtonIndex, LocalRect)
  else
    RelRect := GetItemRelRect(FDeleteButtonIndex, LocalRect);
 
  FDeleteLayout.Position.Y := (RelRect.Top + RelRect.Bottom - FDeleteLayout.Height) / 2;
end;
The method above contains two GetItemRelRect calls (lines 2457 and 2459), but both are before the actual GetItemRelRect body position in that unit (line 2868):

Fmx.ListView.pas
//at line 2868
function TListViewBase.GetItemRelRect(const Index: Integer; const LocRect: TRectF;
  const SideSpace: Integer = 0): TRectF;
begin
  Result := RectF(LocRect.Left + FSideSpace + SideSpace, LocRect.Top + FSideSpace + FHeightSums[Index] - FScrollViewPos,
    LocRect.Width - ((SideSpace + FSideSpace) * 2), GetItemHeight(Index));
 
  if (FScrollBar <> nil) and (not HasTouchTracking) and FScrollBar.Visible then
    Result.Right := Result.Right - FScrollBar.Width;
end;
Despite being declared as inline, this method will not be inlined.

It is not a critical issue, but this makes inline directive useless. There are more occurrences of this issue in Vcl.ExtActns.pas, FMX.ASE.Lexer.pas, FMX.Graphics.pas, FMX.Types.pas, FMX.Utils.pas and FMX.ZOrder.Win.pas.

This means that inlining conditions are not easy to follow, even though at first glance inline directive seems to be an easy way to slightly optimize your code. TMS FixInsight may help to make inlining more useful by avoiding such mistakes.

You can download TMS FixInsight trial and check your own code.

Nancy Lescouhier


Bookmarks: 

This blog post has not received any comments yet. Add a comment.



TMS teams up with Roman Yankovsky to bring TMS FixInsight, the static code analysis tool

Bookmarks: 

Monday, June 20, 2016

We're pleased and honoured to announce that Roman Yankovsky joins the TMS family and the excellent static code analysis tool FixInsight is from now on available as TMS FixInsight product. Roman Yankovsky is the architect and developer of the highly respected FixInsight tool for Delphi. We're proud and excited that the high expertise and talent of Roman is now part of the TMS family! First of all, some details about what FixInsight can do for you:

FixInsight is an IDE plugin from where you can start a static code analysis or you can configure FixInsight to run as part of the build process. This code analysis helps you identify all potential issues in the code and coding convention compliance. This let's you trace bugs before you or your customers do. At this time, FixInsight has 29 specific code warnings, like for example a warning about objects created in the Try block or destructors without override directive... It has 10 code convention warnings and 2 code optimization hints.



FixInsight is all about watching over the quality of the code from early on in the development process and by that reducing the number of bugs and reduce support.

With FixInsight being part of the TMS family now, we'll work together with Roman and we look forward to bring future versions of TMS FixInsight that make it even more feature-rich than today. We of course also welcome & look forward to all feedback, comments, needs from you about FixInsight.

FixInsight is available in two editions: TMS FixInsight Personal and TMS FixInsight Pro. The difference between the two is that TMS FixInsight Pro comes with a command-line tool to integrate running TMS FixInsight from various automation / build processes.
Discover FixInsight now by loading the trial version from here

Bruno Fierens


Bookmarks: 

This blog post has received 5 comments. Add a comment.




Previous  |  Next  |  Index