This is specifically about objectivce C bridge.  Hopefully this is the right forum.

I am seeing a problem with how BOOL values are passed to objc_msgSend.  The example is a call to NSMenuItem.setEnable(BOOL) from the lcl/interfaces/cocoa/cocoawsmenus.pas file.  Here is the code:

class function TCocoaWSMenuItem.SetEnable(const AMenuItem: TMenuItem;
  const Enabled: boolean): boolean;
begin
  Result:=Assigned(AMenuItem) and (AMenuItem.Handle<>0);
  if not Result then Exit;
  NSMenuItem(AMenuItem.Handle).setEnabled( Enabled );
end;

Here is the assembly code generated by fpc (3.1.1) for just the section where .setEnabled(Enabled) is called

->  0x1001ba68d <+61>:  movq   -0x8(%rbp), %rdi
    0x1001ba691 <+65>:  callq  0x1002016d0               ; GETHANDLE at menuitem.inc:515
    0x1001ba696 <+70>:  movq   %rax, %rbx
    0x1001ba699 <+73>:  movq   0x329ee0(%rip), %rsi      ; "setEnabled:"
    0x1001ba6a0 <+80>:  movb   -0x10(%rbp), %dl
    0x1001ba6a3 <+83>:  movq   %rbx, %rdi
    0x1001ba6a6 <+86>:  callq  0x1002d23da               ; symbol stub for: objc_msgSend

Notice the the value of Enabled (a BOOL) is treated as 8bit (which BOOL is) and placed into the lowest 8 bits of edx with the line 'movb   -0x10(%rbp), %dl'.  Which means that the upper 24 bits of edx are not changed (not cleared, not signed extended, nothing, just left alone).

Here is the assembly code generated by XCode for a similar call to NSMenuItem.setEnable() from objective c code:
0x100001258 <+440>: movq   -0x40(%rbp), %rax
    0x10000125c <+444>: movb   -0x19(%rbp), %cl
    0x10000125f <+447>: movq   0x185a(%rip), %rsi        ; "setEnabled:"
    0x100001266 <+454>: movq   %rax, %rdi
    0x100001269 <+457>: movsbl %cl, %edx
    0x10000126c <+460>: callq  *0xd9e(%rip)              ; (void *)0x00007fff55e30e80: objc_msgSend

Register 'edx' is the register of concern again.  In this case the 8 bit BOOL value stored in %cl is placed into %edx with the line 'movsbl %cl, %edx'.  In other words the 8 bit BOOL value is sign extended through all the bits of %edx.

This is different than what fpc does and I think causing a problem. The top level symptom of the problem that lead me to look at this is that currently I cannot manually enable/disable NSMenuItem's because calling .setEnable doesn't work.

Looking at the disassembly for .setEnable I see that the 'disable' flag for the object is stored in a 32bit record bitfield (bit 8) in NSMenuItem._miFlags;  The code loads %ecx with the _miFlags, shifts left 8 to get the 'disable' bit in to 0 position, and then ands with 0x00000001 to mask off all other bits.  It then does a cmpl of %edx and %ecx to determine if the NSMenuITem is already in the desired state or not.  If it is in the desired state then the code exists without changing the state.

here is the assembly for the first part of NSMenuItem.setEnabled:

AppKit`-[NSMenuItem setEnabled:]:
->  0x7fff2bff1a5f <+0>:   pushq  %rbp
    0x7fff2bff1a60 <+1>:   movq   %rsp, %rbp
    0x7fff2bff1a63 <+4>:   pushq  %r15
    0x7fff2bff1a65 <+6>:   pushq  %r14
    0x7fff2bff1a67 <+8>:   pushq  %rbx
    0x7fff2bff1a68 <+9>:   pushq  %rax
    0x7fff2bff1a69 <+10>:  movq   %rdi, %rbx
     0x7fff2bff1a6c <+13>:  movq   0x5c365045(%rip), %rax    ; NSMenuItem._miFlags
    0x7fff2bff1a73 <+20>:  movl   (%rbx,%rax), %esi
    0x7fff2bff1a76 <+23>:  movl   %esi, %ecx
    0x7fff2bff1a78 <+25>:  shrl   $0x8, %ecx
    0x7fff2bff1a7b <+28>:  andl   $0x1, %ecx
    0x7fff2bff1a7e <+31>:  cmpl   %edx, %ecx
    0x7fff2bff1a80 <+33>:  jne    0x7fff2bff1ae8            ; <+137>


The FPC code works when %edx upper bits are, by luck, empty but not when they have non-zero bits.  On my machine coming into the above LCL code %edx always has upper bits set and I cannot get .setEnable to work.

It appears to me that objc_msgSend is expecting that parameters passed in are signed extended and that any code called by objc_msgSend will treat the registers as such.  I spent some time trying to find documentation for objc runtime / objc_msgSend that shows this but didn't find anything that went into that level of detail.

If objc_msgSend does expect this then I think the FPC objective c bridging is not correct.  Can any of you all verify this?

David Jenkins
Scooter Software





_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to