Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2020-04

Internal jump instructions for longer conditional jumps

8 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin

FPC sometimes generates jump instructions as follows. (Not always bound to "IF" but that is the example I found

IF something then begin {long code} end;

The conditional asm jump does not jump all the way to the code after the "end".
Instead it points to an unconditional jump, that (according to line info) is at the end of some other line.

Such "jump pads" (?) seem common (gdb seems to know about them).

I try to detect them in fpDebug.
Which assumptions are reasonable?

- How long can a series of such "jump forwarders" be.   Can the unconditional jump, go to another unconditional jump, before eventually hitting the line that the pascal code would go to?   How many to expect max, before getting suspicious?

- If such jumps are within line info, they should not be at the start of a line?

Reply by email

Florian Klämpfl
to Martin
Martin wrote 9 lines
FPC sometimes generates jump instructions as follows. (Not always bound to "IF" but that is the example I found IF something then begin {long code} end; The conditional asm jump does not jump all the way to the code after the "end". Instead it points to an unconditional jump, that (according to line info) is at the end of some other line.

This might be some artifact introduced by the optimizer. Problem is, the jumps are generated at a certain point and then the optimizer starts to "mess" with them. During this, it might be that line info is mixed up.

Show quoted text 10 lines
Such "jump pads" (?) seem common (gdb seems to know about them). I try to detect them in fpDebug. Which assumptions are reasonable? - How long can a series of such "jump forwarders" be.   Can the unconditional jump, go to another unconditional jump, before eventually hitting the line that the pascal code would go to?   How many to expect max, before getting suspicious?

Unlimited in theory.

- If such jumps are within line info, they should not be at the start of a line?

Do you have some example code which shows this (together with the needed optimizer switches)?

Reply by email

J. Gareth Moreton
to Florian Klämpfl

To add my own two pence, although I'm not sure if it's related or not.

Some architectures are very limited in how far a conditional jump can branch compared to an unconditional jump (e.g. the offset might only be a signed byte).  I ran into this problem on certain ARM platforms when developing my recent cross-platform jump optimisations.

Jump pads are one means to avoid assembler errors by ensuring the conditional jump stays within range.  The other one, which seems more common in FPC, is to (in assembler form), change a conditional jump to @1 to "If not condition then goto @2; jump @1; @2:", thereby ensuring the conditional jump is within range by having it only jump across one instruction (the unconditional jump).

The problem is that it is not always easy to determine if a jump is in range during compilation - the problem might be NP-hard, not sure - even on architectures like ARM where each machine code instruction is the same length.  For example, if you have a procedure where a conditional jump to some future label is in range, but only just, and a 2nd conditional jump in between is not in range and requires changing to the "if not condition" construct described above, the addition of the new jump instruction may be enough to cause the 1st jump to become out of range.  Jump pads (I like that term, even if it sounds like it belongs in a Sonic the Hedgehog game!) suffer from a similar problem depending on where they are inserted.

Gareth aka. Kit

Florian Klämpfl wrote 39 lines
Am 20.04.20 um 16:44 schrieb Martin: > FPC sometimes generates jump instructions as follows. (Not always > bound to "IF" but that is the example I found > > IF something then begin {long code} end; > > The conditional asm jump does not jump all the way to the code after > the "end". > Instead it points to an unconditional jump, that (according to line > info) is at the end of some other line. This might be some artifact introduced by the optimizer. Problem is, the jumps are generated at a certain point and then the optimizer starts to "mess" with them. During this, it might be that line info is mixed up. > > Such "jump pads" (?) seem common (gdb seems to know about them). > > I try to detect them in fpDebug. > Which assumptions are reasonable? > > - How long can a series of such "jump forwarders" be. >    Can the unconditional jump, go to another unconditional jump, > before eventually hitting the line that the pascal code would go to? >    How many to expect max, before getting suspicious? Unlimited in theory. > > - If such jumps are within line info, they should not be at the start > of a line? Do you have some example code which shows this (together with the needed optimizer switches)? _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Martin Frb
to Florian Klämpfl: This might be some artifact introduced by the optimizer. Problem is, the jumps are…
Florian Klämpfl wrote 8 lines
Am 20.04.20 um 16:44 schrieb Martin: > FPC sometimes generates jump instructions as follows. (Not always > bound to "IF" but that is the example I found > - If such jumps are within line info, they should not be at the start > of a line? Do you have some example code which shows this (together with the needed optimizer switches)?

I have not yet tried in a small example. I got it in the Lazarus IDE from svn (with fpc 3.0.4)
components\fpdebug\fpdbgcontroller.pas
line 795 and following
-gh -g -gw -godwarfsets  -gl   -dCR   -Ct -Co -Cr -Ci  -gt  -Sa  -ve -vw -vn  -vi       -O-  -CX  -WC

See the lines marked with //////////

It may be the nested "IF"
If the inner "IF" evals false, it skips over it's "then" block. It jumps " jmp +$61 " to after the "then begin end" block.

That might actually be the line, that is the "end" of the outer "then" block, so that jump is skipping over the outer "else" block.

However, this jump, has the same line info as the "exit" line. Even so the "exit" is in the "then" block, and this "jmp" line is outside of it. I checked the line info with objdump.

So I guess, having had a 2nd look, I got a better explanation. Technically this "jmp" would probably belong to the "end" of the outer "then" block. But "end" for such blocks usually has no line info.

procedure TDbgControllerStepOutCmd.InternalContinue(AProcess: TDbgProcess;
   AThread: TDbgThread);
var
   Outside: Boolean;
begin
   assert(FProcess=AProcess, 'TDbgControllerStepOutCmd.DoContinue:
FProcess=AProcess');

  if (AThread = FThread) then begin
  if IsSteppedOut then begin
    CheckForCallAndSetBreak;
  end
  else
  if not assigned(FHiddenBreakpoint) then begin
    if GetOutsideFrame(Outside) then begin
      SetReturnAdressBreakpoint(AProcess, Outside);     end
    else
    if FStepCount < 12 then
    begin
      Inc(FStepCount);
      if NextInstruction.IsCallInstruction or NextInstruction.IsLeaveStackFrame then  // asm "call" // set break before "leave" or the frame becomes unavail
      begin
        SetReturnAdressBreakpoint(AProcess, False);       end
      else
      if NextInstruction.IsReturnInstruction then  ///////////////// LINE 817 ////////////////
      begin
        FStepCount := MaxInt; // Do one more single-step, and we're finished.
        FProcess.Continue(FProcess, FThread, True);         exit;   /////////////// LINE 821 ////////////////  here goes the forwarder
      end;
    end
    else
    begin
      // Enough with the single-stepping
      SetReturnAdressBreakpoint(AProcess, False);     end;
  end;
  end;

   FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil);
///////////////// LINE 832 ////////////
end;

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:817 if NextInstruction.IsReturnInstruction then  // asm "ret" 0000000100D93578 488B45E8                 mov rax,[rbp-$18] 0000000100D9357C 4883782800               cmp qword ptr [rax+$28],$00 0000000100D93581 7405                     jz +$05 0000000100D93583 E99E000000               jmp +$0000009E 0000000100D93588 488B45E8                 mov rax,[rbp-$18] ........
0000000100D93649 E8420E27FF               call -$00D8F1BE 0000000100D9364E 4889F1                   mov rcx,rsi 0000000100D93651 FF97E8000000             call dword ptr [rdi+$000000E8] 0000000100D93657 84C0                     test al,al 0000000100D93659 7502                     jnz +$02 0000000100D9365B EB61                     jmp +$61   //// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:819 FStepCount := MaxInt; // Do one more single-step, and we're finished. 0000000100D9365D 488B45E8                 mov rax,[rbp-$18] 0000000100D93661 C78088000000FFFFFF7F     mov [rax+$00000088],$7FFFFFFF

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:820 FProcess.Continue(FProcess, FThread, True);
0000000100D9366B 488B45E8                 mov rax,[rbp-$18] 0000000100D9366F 4C8B6810                 mov r13,[rax+$10] 0000000100D93673 488B45E8                 mov rax,[rbp-$18] ..............................
0000000100D936B0 4C89E2                   mov rdx,r12 0000000100D936B3 4D89E8                   mov rax,r13 0000000100D936B6 FF9390010000             call dword ptr [rbx+$00000190]

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:821 exit; 0000000100D936BC EB70                     jmp +$70   /////////// jump to end of proc
0000000100D936BE EB13                     jmp +$13   //// XXXXXXXXXXXXXXXX This is where the  jump forwards to line 832

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:827 SetReturnAdressBreakpoint(AProcess, False);
0000000100D936C0 488B55F8                 mov rdx,[rbp-$08] 0000000100D936C4 488B4DE8                 mov rcx,[rbp-$18] 0000000100D936C8 41B800000000             mov eax,$00000000 0000000100D936CE E8CDF7FFFF               call -$00000833

B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:832 FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil); 0000000100D936D3 488B45E8                 mov rax,[rbp-$18] 0000000100D936D7 4883784800               cmp qword ptr [rax+$48],$00

Reply by email

Florian Klämpfl
to Martin Frb
Martin Frb wrote 16 lines
On 20/04/2020 22:11, Florian Klämpfl wrote: > Am 20.04.20 um 16:44 schrieb Martin: >> FPC sometimes generates jump instructions as follows. (Not always >> bound to "IF" but that is the example I found >> - If such jumps are within line info, they should not be at the start >> of a line? > > Do you have some example code which shows this (together with the > needed optimizer switches)? I have not yet tried in a small example. I got it in the Lazarus IDE from svn (with fpc 3.0.4) components\fpdebug\fpdbgcontroller.pas line 795 and following -gh -g -gw -godwarfsets  -gl   -dCR   -Ct -Co -Cr -Ci  -gt  -Sa  -ve -vw -vn  -vi       -O-  -CX  -WC

Can you post also the relevant output of -al? It makes it easier to see where every assembler instruction comes from.

Show quoted text 124 lines
See the lines marked with ////////// It may be the nested "IF" If the inner "IF" evals false, it skips over it's "then" block. It jumps " jmp +$61 " to after the "then begin end" block. That might actually be the line, that is the "end" of the outer "then" block, so that jump is skipping over the outer "else" block. However, this jump, has the same line info as the "exit" line. Even so the "exit" is in the "then" block, and this "jmp" line is outside of it. I checked the line info with objdump. So I guess, having had a 2nd look, I got a better explanation. Technically this "jmp" would probably belong to the "end" of the outer "then" block. But "end" for such blocks usually has no line info. procedure TDbgControllerStepOutCmd.InternalContinue(AProcess: TDbgProcess;   AThread: TDbgThread); var   Outside: Boolean; begin   assert(FProcess=AProcess, 'TDbgControllerStepOutCmd.DoContinue: FProcess=AProcess');   if (AThread = FThread) then begin   if IsSteppedOut then begin     CheckForCallAndSetBreak;   end   else   if not assigned(FHiddenBreakpoint) then begin     if GetOutsideFrame(Outside) then begin       SetReturnAdressBreakpoint(AProcess, Outside);     end     else     if FStepCount < 12 then     begin       Inc(FStepCount);       if NextInstruction.IsCallInstruction or NextInstruction.IsLeaveStackFrame then  // asm "call" // set break before "leave" or the frame becomes unavail       begin         SetReturnAdressBreakpoint(AProcess, False);       end       else       if NextInstruction.IsReturnInstruction then  ///////////////// LINE 817 ////////////////       begin         FStepCount := MaxInt; // Do one more single-step, and we're finished.         FProcess.Continue(FProcess, FThread, True);         exit;   /////////////// LINE 821 ////////////////  here goes the forwarder       end;     end     else     begin       // Enough with the single-stepping       SetReturnAdressBreakpoint(AProcess, False);     end;   end;   end;   FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil); ///////////////// LINE 832 //////////// end; B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:817 if NextInstruction.IsReturnInstruction then  // asm "ret" 0000000100D93578 488B45E8                 mov rax,[rbp-$18] 0000000100D9357C 4883782800               cmp qword ptr [rax+$28],$00 0000000100D93581 7405                     jz +$05 0000000100D93583 E99E000000               jmp +$0000009E 0000000100D93588 488B45E8                 mov rax,[rbp-$18] ........ 0000000100D93649 E8420E27FF               call -$00D8F1BE 0000000100D9364E 4889F1                   mov rcx,rsi 0000000100D93651 FF97E8000000             call dword ptr [rdi+$000000E8] 0000000100D93657 84C0                     test al,al 0000000100D93659 7502                     jnz +$02 0000000100D9365B EB61                     jmp +$61   //// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:819 FStepCount := MaxInt; // Do one more single-step, and we're finished. 0000000100D9365D 488B45E8                 mov rax,[rbp-$18] 0000000100D93661 C78088000000FFFFFF7F     mov [rax+$00000088],$7FFFFFFF B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:820 FProcess.Continue(FProcess, FThread, True); 0000000100D9366B 488B45E8                 mov rax,[rbp-$18] 0000000100D9366F 4C8B6810                 mov r13,[rax+$10] 0000000100D93673 488B45E8                 mov rax,[rbp-$18] .............................. 0000000100D936B0 4C89E2                   mov rdx,r12 0000000100D936B3 4D89E8                   mov rax,r13 0000000100D936B6 FF9390010000             call dword ptr [rbx+$00000190] B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:821 exit; 0000000100D936BC EB70                     jmp +$70   /////////// jump to end of proc 0000000100D936BE EB13                     jmp +$13   //// XXXXXXXXXXXXXXXX This is where the  jump forwards to line 832 B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:827 SetReturnAdressBreakpoint(AProcess, False); 0000000100D936C0 488B55F8                 mov rdx,[rbp-$08] 0000000100D936C4 488B4DE8                 mov rcx,[rbp-$18] 0000000100D936C8 41B800000000             mov eax,$00000000 0000000100D936CE E8CDF7FFFF               call -$00000833 B:\lazarus_latest_svn_2\components\fpdebug\fpdbgcontroller.pas:832 FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil); 0000000100D936D3 488B45E8                 mov rax,[rbp-$18] 0000000100D936D7 4883784800               cmp qword ptr [rax+$48],$00 _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Martin Frb
to Florian Klämpfl
Florian Klämpfl wrote 5 lines
Am 20.04.20 um 22:45 schrieb Martin Frb: > Can you post also the relevant output of -al? It makes it easier to see where every assembler instruction comes from.

This is the entire proc
I put long
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// to mark the lines.
1) the begin of the IF
2) the jmp at the very end of that IF
3) the label
4) the next jmp

.section
.text.n_fpdbgcontroller$_$tdbgcontrollerstepoutcmd_$__$$_internalcontinue$tdbgprocess$tdbgthread,"x"     .balign 16,0x90
.globl
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_INTERNALCONTINUE$TDBGPROCESS$TDBGTHREAD FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_INTERNALCONTINUE$TDBGPROCESS$TDBGTHREAD: .Lc206:
# Temps allocated between rbp-72 and rbp-32
.seh_proc
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_INTERNALCONTINUE$TDBGPROCESS$TDBGTHREAD .Ll380:
# [793] begin
    pushq    %rbp
.seh_pushreg %rbp
.Lc208:
.Lc209:
    movq    %rsp,%rbp
.Lc210:
    leaq    -112(%rsp),%rsp
.seh_stackalloc 112
    movq    %rbx,-72(%rbp)
    movq    %rdi,-64(%rbp)
    movq    %rsi,-56(%rbp)
    movq    %r12,-48(%rbp)
    movq    %r13,-40(%rbp)
.seh_savereg %rbx, 40
.seh_savereg %rdi, 48
.seh_savereg %rsi, 56
.seh_savereg %r12, 64
.seh_savereg %r13, 72
.seh_endprologue
# Var AProcess located at rbp-8, size=OS_64
# Var AThread located at rbp-16, size=OS_64
# Var $self located at rbp-24, size=OS_64
# Var Outside located at rbp-32, size=OS_8
    movq    %rcx,-24(%rbp)
    movq    %rdx,-8(%rbp)
    movq    %r8,-16(%rbp)
.Ll381:
    movb    $85,-32(%rbp)
.Ll382:
# [794] assert(FProcess=AProcess, 'TDbgControllerStepOutCmd.DoContinue: FProcess=AProcess');
    movq    -24(%rbp),%rax
    movq    24(%rax),%rax
    cmpq    -8(%rbp),%rax
    jne    .Lj1617
    jmp    .Lj1618
.Lj1617:
    movq    %rbp,%r9
    leaq    _$FPDBGCONTROLLER$_Ld1(%rip),%rdx     leaq    _$FPDBGCONTROLLER$_Ld24(%rip),%rcx     movl    $794,%r8d
    call    fpc_assert
.Lj1618:
.Ll383:
# [796] if (AThread = FThread) then begin
    movq    -24(%rbp),%rax
    movq    16(%rax),%rax
    cmpq    -16(%rbp),%rax
    je    .Lj1627
    jmp    .Lj1628
.Lj1627:
.Ll384:
# [797] if IsSteppedOut then begin
    movq    -24(%rbp),%rcx
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERHIDDENBREAKSTEPBASECMD_$__$$_GETISSTEPPEDOUT$$BOOLEAN     testb    %al,%al
    jne    .Lj1629
    jmp    .Lj1630
.Lj1629:
.Ll385:
# [798] CheckForCallAndSetBreak;
    movq    -24(%rbp),%rcx
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERHIDDENBREAKSTEPBASECMD_$__$$_CHECKFORCALLANDSETBREAK$$BOOLEAN     jmp    .Lj1635
.Lj1630:
.Ll386:
# [801] if not assigned(FHiddenBreakpoint) then begin     movq    -24(%rbp),%rax
    cmpq    $0,72(%rax)
    je    .Lj1636
    jmp    .Lj1637
.Lj1636:
.Ll387:
# [802] if GetOutsideFrame(Outside) then begin
    leaq    -32(%rbp),%rdx
    movq    -24(%rbp),%rcx
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_GETOUTSIDEFRAME$BOOLEAN$$BOOLEAN     testb    %al,%al
    jne    .Lj1638
    jmp    .Lj1639
.Lj1638:
.Ll388:
# [803] SetReturnAdressBreakpoint(AProcess, Outside);     movzbl    -32(%rbp),%r8d
    movq    -8(%rbp),%rdx
    movq    -24(%rbp),%rcx
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_SETRETURNADRESSBREAKPOINT$TDBGPROCESS$BOOLEAN     jmp    .Lj1650
.Lj1639:
.Ll389:
# [806] if FStepCount < 12 then
    movq    -24(%rbp),%rax
    cmpl    $12,136(%rax)
    jl    .Lj1651
    jmp    .Lj1652
.Lj1651:
.Ll390:
# [811] Inc(FStepCount);
    movq    -24(%rbp),%rax
    movslq    136(%rax),%rbx
    addq    $1,%rbx
    jno    .Lj1655
    call    FPC_OVERFLOW
.Lj1655:
    movq    %rbx,%rax
    subq    $-2147483648,%rax
# Fix for Win64-GAS bug
    movl    $4294967295,%edx
    cmpq    %rdx,%rax
    jbe    .Lj1656
    call    fpc_rangeerror
.Lj1656:
    movq    -24(%rbp),%rax
    movl    %ebx,136(%rax)
.Ll391:
# [812] if NextInstruction.IsCallInstruction or
NextInstruction.IsLeaveStackFrame then  // asm "call" // set break before "leave" or the frame becomes unavail
    movq    -24(%rbp),%rax
    cmpq    $0,40(%rax)
    je    .Lj1663
    jmp    .Lj1664
.Lj1663:
    movq    -24(%rbp),%rax
    movq    24(%rax),%rcx
    call FPDBGCLASSES$_$TDBGPROCESS_$__$$_GETDISASSEMBLER$$TDBGASMDECODER     movq    %rax,%rbx
    movq    -24(%rbp),%rax
    movq    16(%rax),%rdi
    movq    -24(%rbp),%rax
    movq    16(%rax),%rsi
    testq    %rsi,%rsi
    jne    .Lj1675
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1675:
    movq    (%rsi),%rsi
    movq    %rsi,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    call    *248(%rsi)
    movq    %rax,%rsi
    movq    %rbx,%rdi
    movq    %rbx,%r12
    testq    %r12,%r12
    jne    .Lj1678
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1678:
    movq    (%r12),%r12
    movq    %r12,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    movq    %rsi,%rdx
    call    *256(%r12)
    movq    -24(%rbp),%rdx
    movq    %rax,40(%rdx)
    movq    -24(%rbp),%rax
    movq    40(%rax),%rcx
    movq    $0,%r8
    movq    $0,%rdx
    call
LAZCLASSES$_$TREFCOUNTEDOBJECT_$__$$_ADDREFERENCE$POINTER$ANSISTRING .Lj1664:
    movq    -24(%rbp),%rax
    movq    40(%rax),%rbx
    movq    %rbx,%rsi
    movq    %rbx,%rdi
    testq    %rdi,%rdi
    jne    .Lj1689
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1689:
    movq    (%rdi),%rdi
    movq    %rdi,%rcx
    call    fpc_check_object
    movq    %rsi,%rcx
    call    *224(%rdi)
    testb    %al,%al
    jne    .Lj1657
    jmp    .Lj1659
.Lj1659:
    movq    -24(%rbp),%rax
    cmpq    $0,40(%rax)
    je    .Lj1693
    jmp    .Lj1694
.Lj1693:
    movq    -24(%rbp),%rax
    movq    24(%rax),%rcx
    call FPDBGCLASSES$_$TDBGPROCESS_$__$$_GETDISASSEMBLER$$TDBGASMDECODER     movq    %rax,%rbx
    movq    -24(%rbp),%rax
    movq    16(%rax),%rdi
    movq    -24(%rbp),%rax
    movq    16(%rax),%rsi
    testq    %rsi,%rsi
    jne    .Lj1705
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1705:
    movq    (%rsi),%rsi
    movq    %rsi,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    call    *248(%rsi)
    movq    %rax,%rsi
    movq    %rbx,%rdi
    movq    %rbx,%r12
    testq    %r12,%r12
    jne    .Lj1708
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1708:
    movq    (%r12),%r12
    movq    %r12,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    movq    %rsi,%rdx
    call    *256(%r12)
    movq    -24(%rbp),%rdx
    movq    %rax,40(%rdx)
    movq    -24(%rbp),%rax
    movq    40(%rax),%rcx
    movq    $0,%r8
    movq    $0,%rdx
    call
LAZCLASSES$_$TREFCOUNTEDOBJECT_$__$$_ADDREFERENCE$POINTER$ANSISTRING .Lj1694:
    movq    -24(%rbp),%rax
    movq    40(%rax),%rbx
    movq    %rbx,%rsi
    movq    %rbx,%rdi
    testq    %rdi,%rdi
    jne    .Lj1719
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1719:
    movq    (%rdi),%rdi
    movq    %rdi,%rcx
    call    fpc_check_object
    movq    %rsi,%rcx
    call    *240(%rdi)
    testb    %al,%al
    jne    .Lj1657
    jmp    .Lj1658
.Lj1657:
.Ll392:
# [814] SetReturnAdressBreakpoint(AProcess, False);     movq    -8(%rbp),%rdx
    movq    -24(%rbp),%rcx
    movl    $0,%r8d
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_SETRETURNADRESSBREAKPOINT$TDBGPROCESS$BOOLEAN     jmp    .Lj1726
.Lj1658:
.Ll393:
# [817] if NextInstruction.IsReturnInstruction then  // asm "ret"          // 1
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////     movq    -24(%rbp),%rax
    cmpq    $0,40(%rax)
    je    .Lj1732
    jmp    .Lj1733
.Lj1732:
    movq    -24(%rbp),%rax
    movq    24(%rax),%rcx
    call FPDBGCLASSES$_$TDBGPROCESS_$__$$_GETDISASSEMBLER$$TDBGASMDECODER     movq    %rax,%rbx
    movq    -24(%rbp),%rax
    movq    16(%rax),%rdi
    movq    -24(%rbp),%rax
    movq    16(%rax),%rsi
    testq    %rsi,%rsi
    jne    .Lj1744
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1744:
    movq    (%rsi),%rsi
    movq    %rsi,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    call    *248(%rsi)
    movq    %rax,%rsi
    movq    %rbx,%rdi
    movq    %rbx,%r12
    testq    %r12,%r12
    jne    .Lj1747
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1747:
    movq    (%r12),%r12
    movq    %r12,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    movq    %rsi,%rdx
    call    *256(%r12)
    movq    -24(%rbp),%rdx
    movq    %rax,40(%rdx)
    movq    -24(%rbp),%rax
    movq    40(%rax),%rcx
    movq    $0,%r8
    movq    $0,%rdx
    call
LAZCLASSES$_$TREFCOUNTEDOBJECT_$__$$_ADDREFERENCE$POINTER$ANSISTRING .Lj1733:
    movq    -24(%rbp),%rax
    movq    40(%rax),%rbx
    movq    %rbx,%rsi
    movq    %rbx,%rdi
    testq    %rdi,%rdi
    jne    .Lj1758
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1758:
    movq    (%rdi),%rdi
    movq    %rdi,%rcx
    call    fpc_check_object
    movq    %rsi,%rcx
    call    *232(%rdi)
    testb    %al,%al
    jne    .Lj1727
    jmp    .Lj1728            // 2 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .Lj1727:
.Ll394:
# [819] FStepCount := MaxInt; // Do one more single-step, and we're finished.
    movq    -24(%rbp),%rax
    movl    $2147483647,136(%rax)
.Ll395:
# [820] FProcess.Continue(FProcess, FThread, True);     movq    -24(%rbp),%rax
    movq    16(%rax),%r13
    movq    -24(%rbp),%rax
    movq    24(%rax),%r12
    movq    -24(%rbp),%rax
    movq    24(%rax),%rdi
    movl    $1,%esi
    movq    -24(%rbp),%rax
    movq    24(%rax),%rbx
    testq    %rbx,%rbx
    jne    .Lj1769
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1769:
    movq    (%rbx),%rbx
    movq    %rbx,%rcx
    call    fpc_check_object
    movl    %esi,%r9d
    movq    %rdi,%rcx
    movq    %r12,%rdx
    movq    %r13,%r8
    call    *400(%rbx)
.Ll396:
# [821] exit;
    jmp    .Lj1611
.Lj1728:            // 3
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .Lj1726:
    jmp    .Lj1770              // 4 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// .Lj1652:
.Ll397:
# [827] SetReturnAdressBreakpoint(AProcess, False);     movq    -8(%rbp),%rdx
    movq    -24(%rbp),%rcx
    movl    $0,%r8d
    call
FPDBGCONTROLLER$_$TDBGCONTROLLERSTEPOUTCMD_$__$$_SETRETURNADRESSBREAKPOINT$TDBGPROCESS$BOOLEAN .Lj1770:
.Lj1650:
.Lj1637:
.Lj1635:
.Lj1628:
.Ll398:
# [832] FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil);     movq    -24(%rbp),%rax
    cmpq    $0,72(%rax)
    seteb    %bl
    movzbl    %bl,%ebx
    movq    -24(%rbp),%rax
    movq    16(%rax),%r13
    movq    -24(%rbp),%rax
    movq    24(%rax),%r12
    movq    -24(%rbp),%rax
    movq    24(%rax),%rdi
    movq    -24(%rbp),%rax
    movq    24(%rax),%rsi
    testq    %rsi,%rsi
    jne    .Lj1785
    movl    $210,%ecx
    call    fpc_handleerror
.Lj1785:
    movq    (%rsi),%rsi
    movq    %rsi,%rcx
    call    fpc_check_object
    movq    %rdi,%rcx
    movq    %r12,%rdx
    movq    %r13,%r8
    movl    %ebx,%r9d
    call    *400(%rsi)
.Lj1611:
.Ll399:
# [833] end;
    movq    -72(%rbp),%rbx
    movq    -64(%rbp),%rdi
    movq    -56(%rbp),%rsi
    movq    -48(%rbp),%r12
    movq    -40(%rbp),%r13
    leaq    (%rbp),%rsp
    popq    %rbp
    ret
.seh_endproc
.Lc207:
.Lt73:
.Ll400:

# [820:44]
    .byte    2
    .uleb128    .Ll395-.Ll394
    .byte    5
    .uleb128    44
    .byte    13
# [821:9]
    .byte    2
    .uleb128    .Ll396-.Ll395   // Ll396 is the label before the "exit"     .byte    5
    .uleb128    9
    .byte    13
# [827:7]
    .byte    2
    .uleb128    .Ll397-.Ll396  // and line info for it goes up to Ll397 which is the first statement in the following "else" block     .byte    5
    .uleb128    7
    .byte    18
# [832:40]

Reply by email

J. Gareth Moreton
to Martin Frb

Hi Martin,

Can you remind me which version of FPC you're compiling with, and the compiler options specified? My jump optimisation code in the trunk should eliminate most of those jump pads and 'conditional jump inversions'.

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Martin Frb
to J. Gareth Moreton
J. Gareth Moreton wrote 6 lines
Hi Martin, Can you remind me which version of FPC you're compiling with, and the compiler options specified? My jump optimisation code in the trunk should eliminate most of those jump pads and 'conditional jump inversions'.

Fpc 3.0.4
-gh -g -gw -godwarfsets  -gl   -dCR   -Ct -Co -Cr -Ci  -gt  -Sa  -ve -vw -vn  -vi       -O-  -CX  -WC

My concern right here was not about the performance.

This is about the line info applied to those.
In this case a "jmp" that I guess belongs after the "then begin end" is attributed to the last line in the "then begin end". Simply because no line exists between the last line of "then" and the first line of "else". So the "then" line extends until the next line starts, and eats anything that is inbetwen.

In the example below, a single step from the marked line, should go to DoGood().
But it does go to "bar" (which is not executed, but contains the jmp)

That is obviously irritating.
GDB somehow detects that.
Now, I added this to fpdebug too. Though currently with a limit, as to how many such jumps are stepped over. That limit may have to go.

The debugger has to deal with this.
    IF true then begin
       IF false then begin  // Single step from here
           foo;
           bar;
       end;
    end
    else begin
      ...
   end;
   DoGood();

----------
While the debugger runs best with -O-, if you do optimizations mind that line info may need adjustments.
You may well be aware of it, but it also is an easy to make oversight. So if you are interested below a real case:

Long ago there was an issue (fixed by now)
line 1:  mov  const => mem
line 2:  mov mem => reg
line 2: ....

2nd line was correctly removed.
But somehow it ended up
line 1: move const => reg
line 2:  mov reg => mem
line 2: ....

Which meant that when you stepped over line 1, the memory (which the debugger shows for the variable) was not yet updated. The debugger showed the outdated value.
https://bugs.freepascal.org/view.php?id=25584

Reply by email