Sign in Join

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

Mailing lists / fpc-devel / 2018-10

OSX: Setting up parameters to objc_msgSend()

28 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

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

David Jenkins

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.Handle0);
   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

Reply by email

Jonas Maebe
to David Jenkins
David Jenkins wrote 17 lines
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).

That's because the x86-64 ABI says
(https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf ):

***
When a value of type _Bool is returned or passed in a register or on the stack, bit 0 contains the truth value and bits 1 to 7 shall be zero. (14)

...

(14) Other bits are left unspecified, hence the consumer side of those values can rely on it being 0 or 1 when truncated to 8 bit ***

However, the Objective-C BOOL type does not map to _Bool on x86-64, but to signed char. And values of that type indeed do need to (sign) extended. So this needs to be fixed in the compiler. Please file a bug report, and thanks for the analysis.

Jonas

Reply by email

David Jenkins
to Jonas Maebe

Thanks.  I'll get a bug report in tomorrow morning.

Jonas Maebe wrote 45 lines
On 11/10/18 21:41, David Jenkins wrote: > 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). That's because the x86-64 ABI says (https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf ): *** When a value of type _Bool is returned or passed in a register or on the stack, bit 0 contains the truth value and bits 1 to 7 shall be zero. (14) ... (14) Other bits are left unspecified, hence the consumer side of those values can rely on it being 0 or 1 when truncated to 8 bit *** However, the Objective-C BOOL type does not map to _Bool on x86-64, but to signed char. And values of that type indeed do need to (sign) extended. So this needs to be fixed in the compiler. Please file a bug report, and thanks for the analysis. Jonas _______________________________________________ fpc-devel maillist  -  http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Dmitry Boyarintsev
to Jonas Maebe: That's because the x86-64 ABI says (https://software.intel.com/sites/default/files/article…
PM Jonas Maebe wrote
However, the Objective-C BOOL type does not map to _Bool on x86-64, but to signed char. And values of that type indeed do need to (sign) extended.

Should use of ByteBool resolve the problems for ObjC mapped headers for the current version of the compiler?
is "ByteBool" an alias for Boolean, or is it forcefully "char" sized for x86_64 ABI?

thanks,
Dmitry

Reply by email

Sven Barth
to Dmitry Boyarintsev

Dmitry Boyarintsev schrieb am Fr., 12. Okt.
2018, 02:07:

Show quoted text 12 lines
On Thu, Oct 11, 2018 at 4:16 PM Jonas Maebe wrote: > However, the Objective-C BOOL type does not map to _Bool on x86-64, but > to signed char. And values of that type indeed do need to (sign) > extended. > Should use of ByteBool resolve the problems for ObjC mapped headers for the current version of the compiler? is "ByteBool" an alias for Boolean, or is it forcefully "char" sized for x86_64 ABI?

Even Boolean has the correct size of 1 Byte. The difference is the value of True: For Boolean its always 1, for ByteBool it's "not 0".

Regards,
Sven

Reply by email

Dmitry Boyarintsev
to Sven Barth

On Fri, Oct 12, 2018 at 1:51 AM Sven Barth via fpc-devel <

Show quoted text 21 lines
wrote: Dmitry Boyarintsev schrieb am Fr., 12. Okt. 2018, 02:07: > On Thu, Oct 11, 2018 at 4:16 PM Jonas Maebe wrote: > >> However, the Objective-C BOOL type does not map to _Bool on x86-64, but >> to signed char. And values of that type indeed do need to (sign) >> extended. >> > > Should use of ByteBool resolve the problems for ObjC mapped headers for > the current version of the compiler? > is "ByteBool" an alias for Boolean, or is it forcefully "char" sized for > x86_64 ABI? > Even Boolean has the correct size of 1 Byte. The difference is the value of True: For Boolean its always 1, for ByteBool it's "not 0".

But it feels like "signed chars" are treated differently, where the value would extended to the remaining bits of the register. That's why I was wondering if "ByteBool" would be passed differently than "Boolean" on 64-bit.

Here's a similar discussion
https://stackoverflow.com/questions/31267325/bool-with-64-bit-on-ios

It actually states that true _Bool is only used for 64-bit ARM and no other targets.

So, I'm wondering if it's actually a compiler issue or headers issue. and can ByteBool be used as a substitute for signed char.

thanks,
Dmitry

Reply by email

David Jenkins
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 11 lines
So, I'm wondering if it's actually a compiler issue or headers issue. and can ByteBool be used as a substitute for signed char. thanks, Dmitry _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Changing the header for NSMenuItem.setEnable(BOOL) to NSMenuItem(ByteBool) results in the following code in TCocoaWSmenuITem.setEnable:

    0x1001ba67e <+70>:  movq   %rax, %rbx
    0x1001ba681 <+73>:  movq   0x329ef8(%rip), %rsi      ; "setEnabled:"     0x1001ba688 <+80>:  movb   -0x10(%rbp), %al     0x1001ba68b <+83>:  orb    %al, %al
    0x1001ba68d <+85>:  setne  %dl
    0x1001ba690 <+88>:  negb   %dl
    0x1001ba692 <+90>:  movsbl %dl, %edx
    0x1001ba695 <+93>:  movq   %rbx, %rdi
    0x1001ba698 <+96>:  callq  0x1002d23da               ; symbol stub for: objc

The movsbl %dl, %edx is good.  Unfortunately the value of %edx is 0xffffffff not 0x00000001.  This is the same result I saw when I changed it to LongBool.

David

Reply by email

Dmitry Boyarintsev
to David Jenkins: Changing the header for NSMenuItem.setEnable(BOOL) to NSMenuItem(ByteBool) results in the…
AM David Jenkins wrote
The movsbl %dl, %edx is good. Unfortunately the value of %edx is 0xffffffff not 0x00000001. This is the same result I saw when I changed it to LongBool.

I presume this is due to the definition of YES macro in objc, which is 1 (rather than ~NO)
https://developer.apple.com/documentation/objectivec/objective-c_runtime/boolean_values?language=objchttps://developer.apple.com/documentation/objectivec/bool

so, far the only reliable approach to fix the issue (for the current compiler version) is something like that:

unit cocoa_extra;
type
  OBJCBOOL = ShortInt;
...
  NSMenuFix = objccategory external (NSMenu)
    function itemAtIndex(index: NSInteger): NSMenuItem; message
'itemAtIndex:';
    function setEnabled_(aenabled:  OBJCBOOL ): NSMenuItem; message
'setEnabled:'; // same method, different parameter type
  end;
class function TCocoaWSMenuItem.SetEnable(const AMenuItem: TMenuItem;
   const Enabled: boolean): boolean;
begin
   Result:=Assigned(AMenuItem) and (AMenuItem.Handle0);
   if not Result then Exit;
   NSMenuItem(AMenuItem.Handle).setEnabled_( Ord(Enabled) ); // totally
matches ObjC YES / NO definitions
end;

Not really sure, if it can be properly be solved through the compiler. Because it either would break Boolean (_Bool) or ByteBool. OR ByteBool needs to be more strict on it's Ord() value (optionally?)

thanks,
Dmitry

Reply by email

Dmitry Boyarintsev
to Dmitry Boyarintsev

On Fri, Oct 12, 2018 at 11:09 AM Dmitry Boyarintsev <

Show quoted text 5 lines
wrote: so, far the only reliable approach to fix the issue (for the current compiler version) is something like that:

Maybe "Boolean8" type should help instead?
David, could you please test with Boolean8 instead of ByteBool?

thanks,
Dmitry

Reply by email

Sven Barth
to Dmitry Boyarintsev

Dmitry Boyarintsev schrieb am Fr., 12. Okt.
2018, 17:26:

Show quoted text 12 lines
On Fri, Oct 12, 2018 at 11:09 AM Dmitry Boyarintsev < > wrote: > so, far the only reliable approach to fix the issue (for the current > compiler version) is something like that: > Maybe "Boolean8" type should help instead? David, could you please test with Boolean8 instead of ByteBool?

Boolean8 is an alias to Boolean. But if you need to work with 1 and 0, but have 4 Byte width then you could try Boolean32.

Regards,
Sven

Reply by email

Dmitry Boyarintsev
to Sven Barth

On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel <

Show quoted text 12 lines
wrote: Dmitry Boyarintsev schrieb am Fr., 12. Okt. 2018, 17:26: > Maybe "Boolean8" type should help instead? > David, could you please test with Boolean8 instead of ByteBool? > Boolean8 is an alias to Boolean. But if you need to work with 1 and 0, but have 4 Byte width then you could try Boolean32.

Hmm, this is odd.
https://www.freepascal.org/docs-html/ref/refsu4.html Boolean8, size=1, ord=1
"In addition to the simple Boolean type, the additional Boolean8, Boolean16, Boolean32 and Boolean64 types exist. There are in fact integer types, which are assignment-compatible with the simple boolean type. As an integer, the values for True and False are 1 and 0. This can be used to interfac with C code that defines a boolean of this size with values 0 and 1."

Boolean8 is not exactly an alias to Boolean, as it's expected to act as an integer, rather than _Bool. (and would be expected? to be passed an integer).
However, fpc 3.0.4 doesn't have Boolean8 as builtin type. Instead it provides Boolean16+ only. Maybe it's available in trunk only.

thanks,
Dmitry

Reply by email

Dmitry Boyarintsev
to Sven Barth: Dmitry Boyarintsev schrieb am Fr., 12. Okt. 2018, 17:26: Boolean8 is an alias to…

On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel <

Show quoted text 6 lines
wrote: Boolean8 is an alias to Boolean. But if you need to work with 1 and 0, but have 4 Byte width then you could try Boolean32.

Indeed. It's scheduled for 3.2.0 release as alias for Boolean. However, it would work the same as Boolean type. so the issue would not resolved.
It would surely be nice to have that difference between Boolean (treated as _Bool) and Boolean8 (treated as signer char with Ord(1)) type.

thanks,
Dmitry

Reply by email

Jonas Maebe
to Dmitry Boyarintsev: On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel < Hmm, this is odd.…
Dmitry Boyarintsev wrote
Boolean8 is not exactly an alias to Boolean, as it's expected to act as an integer,

The documentation is wrong.

rather than _Bool. (and would be expected? to be passed an

Boolean8 is defined as an alias for Boolean in the RTL, so it won't help. The only ways I can think of to fix this are to either add a new ObjCBool type to the compiler (or make Pasbool8 a built-in type that is different from Boolean, which amounts to the same thing), or to remove the optimization for passing boolean types that's specified in the x86-64 ABI.

Jonas

Reply by email

Dmitry Boyarintsev
to Jonas Maebe
PM Jonas Maebe wrote
The documentation is wrong. Boolean8 is defined as an alias for Boolean in the RTL, so it won't help.

If the intent of BooleanN is to help interfacing C-libraries. Would it make sense to change BooleanN from being an alias to more consistent behavior with its 16,32 and 64 counterparts?

The only ways I can think of to fix this are to either add a new ObjCBool type to the compiler (or make Pasbool8 a built-in type that is different from Boolean, which amounts to the same thing),

There are chances that other libraries might benefit from Boolean8. Not limited to ObjC declaration/use.

or to remove the optimization for passing boolean types that's specified in the x86-64 ABI.

Wouldn't it break the compatibility with any existing x86_64 _Bool code?

If it's the same amount of work anyway, why not to make Boolean8 work as described in the documentation.
It would save time on fixing docs for sure :)

thanks,
Dmitry

Reply by email

Sven Barth
to Dmitry Boyarintsev: On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel < Hmm, this is odd.…
Dmitry Boyarintsev wrote 31 lines
On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel < > wrote: Dmitry Boyarintsev < > schrieb am Fr., 12. Okt. 2018, 17:26: Maybe "Boolean8"  type should help instead?  David, could you please test with Boolean8 instead of ByteBool? Boolean8 is an alias to Boolean. But if you need to work with 1 and 0, but have 4 Byte width then you could try Boolean32.  Hmm, this is odd. https://www.freepascal.org/docs-html/ref/refsu4.html Boolean8, size=1, ord=1  "In addition to the simple Boolean type, the additional Boolean8, Boolean16, Boolean32 and Boolean64 types exist. There are in fact integer types, which are assignment-compatible with the simple boolean type. As an integer, the values for True and False are 1 and 0. This can be used to interfac with C code that defines a boolean of this size with values 0 and 1." Boolean8 is not exactly an alias to Boolean, as it's expected to act as an integer, rather than _Bool. (and would be expected? to be passed an integer). However, fpc 3.0.4 doesn't have Boolean8 as builtin type. Instead it provides Boolean16+ only.  Maybe it's available in trunk only.

All the Pascal Boolean types are not "Integer types". You can't assign any of them to a Integer or whatever without typecasting. They *all* behave like Boolean, because that was the way they were added. They are all 1-bit zero extended to the specified size. Look at the compiler sources, they are all implemented as pasboolSIZE, including Boolean. The documentation simply is *wrong* here.
Compare this to the *Bool family of types that are 1-bit *sign*-extended to the specified size.

Now for the problem at hand the question is either if the ABI is implemented incorrectly or that a new kind of Boolean type is required to correctly represent the _Bool type needed by Objective C.

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth
Sven Barth wrote 39 lines
On 10/12/18 7:21 PM, Dmitry Boyarintsev wrote: > On Fri, Oct 12, 2018 at 1:07 PM Sven Barth via fpc-devel > < > > wrote: > > Dmitry Boyarintsev < > > schrieb am Fr., 12. Okt. 2018, > 17:26: > > Maybe "Boolean8"  type should help instead?  > David, could you please test with Boolean8 instead of ByteBool? > > > Boolean8 is an alias to Boolean. But if you need to work with 1 and > 0, but have 4 Byte width then you could try Boolean32.  > > > Hmm, this is odd. > https://www.freepascal.org/docs-html/ref/refsu4.html > Boolean8, size=1, ord=1  > "In addition to the simple Boolean type, the additional Boolean8, > Boolean16, Boolean32 and Boolean64 types exist. There are in fact > integer types, which are assignment-compatible with the simple boolean > type. As an integer, the values for True and False are 1 and 0. This can > be used to interfac with C code that defines a boolean of this size with > values 0 and 1." > > Boolean8 is not exactly an alias to Boolean, as it's expected to act as > an integer, rather than _Bool. (and would be expected? to be passed an > integer). > However, fpc 3.0.4 doesn't have Boolean8 as builtin type. Instead it > provides Boolean16+ only.  Maybe it's available in trunk only. All the Pascal Boolean types are not "Integer types". You can't assign any of them to a Integer or whatever without typecasting. They *all* behave like Boolean, because that was the way they were added. They are all 1-bit zero extended to the specified size. Look at the compiler sources, they are all implemented as pasboolSIZE, including Boolean. The documentation simply is *wrong* here.

What exactly is wrong ?

boolean8 has been removed from the docs some time ago after a bugreport. It should be online for 3.2

The statement about ord(true) being 1 is correct.

home:~/docs> fpc b1.pp
home:~/docs> ./b1
1
home:~/docs> cat b1.pp
var

   B16 : Boolean16;
begin
   B16:=True;
   Writeln(ord(B16));
end.

So what is still wrong ?

Michael.

Reply by email

Michael Van Canneyt
to Jonas Maebe
Jonas Maebe wrote 5 lines
On 12/10/18 22:00, Michael Van Canneyt wrote: > > What exactly is wrong ? Boolean8/16/32/64 are ordinal and boolean types, but not integer types.

OK. I will rephrase the wording. Thanks!

Michael.

Reply by email

Dmitry Boyarintsev
to Sven Barth: All the Pascal Boolean types are not "Integer types". You can't assign any of them to a…

On Fri, Oct 12, 2018 at 3:51 PM Sven Barth via fpc-devel <

Show quoted text 6 lines
wrote: All the Pascal Boolean types are not "Integer types". You can't assign any of them to a Integer or whatever without typecasting. They *all* behave like Boolean, because that was the way they were added. They are all 1-bit zero extended to the specified size.

It's true for pascal sources, but the issue is not with pascal, but rather interfacing C-world (where before C99 boolean didn't quite exist). And the whole family of boolean types (if the documentation can be trusted) was introduced for this whole purpose.

Documentation itself lays out pretty structured and consistent layout: BooleanX - indicates a boolean of a size N-bits, and if the value is requested, it would be translated to either 0 or 1. NNNNBool - indicates a boolean of a sizeof(NNNN), and if the value is requested, it can be anything that is non zero.

But since the documentation is wrong, I believe there's no consistency, and everything is pretty much target dependent. (and it's sad).

Now for the problem at hand the question is either if the ABI is implemented incorrectly or that a new kind of Boolean type is required to correctly represent the _Bool type needed by Objective C.

I do not believe that it is Objective-C specific issue. Declared BOOL macro can be used in a plain C-function call and would have the exact side effect.
(Apple puts it a special consideration
https://developer.apple.com/documentation/objectivec/bool)

thanks,
Dmitry

Reply by email

Sven Barth
to Dmitry Boyarintsev

Dmitry Boyarintsev schrieb am Fr., 12. Okt.
2018, 22:55:

Show quoted text 13 lines
On Fri, Oct 12, 2018 at 3:51 PM Sven Barth via fpc-devel < > wrote: > All the Pascal Boolean types are not "Integer types". You can't assign > any of them to a Integer or whatever without typecasting. They *all* > behave like Boolean, because that was the way they were added. They are > all 1-bit zero extended to the specified size. It's true for pascal sources, but the issue is not with pascal, but rather interfacing C-world (where before C99 boolean didn't quite exist). And the whole family of boolean types (if the documentation can be trusted) was introduced for this whole purpose.

Not quite: the Boolean16, Boolean32 and Boolean64 types were introduced because the libraries provided by GTK required a 4-Byte boolean type that worked like Object Pascal's Boolean. Until then only Boolean and the *Bool types existed (and in Delphi that is still true). And Boolean exists this way because it existed this way in Turbo Pascal.

Show quoted text 9 lines
Documentation itself lays out pretty structured and consistent layout: BooleanX - indicates a boolean of a size N-bits, and if the value is requested, it would be translated to either 0 or 1. NNNNBool - indicates a boolean of a sizeof(NNNN), and if the value is requested, it can be anything that is non zero. But since the documentation is wrong, I believe there's no consistency, and everything is pretty much target dependent. (and it's sad).

It's not target dependent, it works the same on all platforms that FPC supports.

Also the documentation is now going to be revised as the meaning should have been that these Boolean types are *ordinals* not *integers*.

Show quoted text 11 lines
> Now for the problem at hand the question is either if the ABI is > implemented incorrectly or that a new kind of Boolean type is required > to correctly represent the _Bool type needed by Objective C. > I do not believe that it is Objective-C specific issue. Declared BOOL macro can be used in a plain C-function call and would have the exact side effect. (Apple puts it a special consideration https://developer.apple.com/documentation/objectivec/bool)

Then maybe it's an issue about the ABI (maybe all values with a size < 4 need to be correctly extended due to the ABI).

Regards,
Sven

Reply by email

Dmitry Boyarintsev
to Sven Barth

On Fri, Oct 12, 2018 at 6:48 PM Sven Barth via fpc-devel <

Show quoted text 6 lines
wrote: Not quite: the Boolean16, Boolean32 and Boolean64 types were introduced because the libraries provided by GTK required a 4-Byte boolean type that worked like Object Pascal's Boolean.

That's interesting.
Let me ask a couple of things here:

1) gboolean is a size of int (
https://www.gtk.org/api/2.6/glib/glib-Basic-Types.html#gboolean) where FALSE is 0 and TRUE is not FALSE.
https://www.gtk.org/api/2.6/glib/glib-Standard-Macros.html#TRUE:CAPS so, it's more -1, rather than 1 and it doesn't quite maps to Boolean and/or Boolean32. It's matches to LongBool.

var
  b : Boolean;
  lb : LongBool;
  b32 : Boolean32;
begin
  b := true;
  lb := true;
  b32 := true;
  writeln(byte(b),' ',LongWord(b32),' ',LongWord(lb));
  writeln(ord(b),' ',Ord(b32),' ',Ord(lb));
end.
Results in:
1 1 4294967295
1 1 -1
(matches documentation)

2) why the were they named booleanN rather than gtkboolean or something? (I'm referring to the suggestion of using objcbool name. It seem to fit)

Then maybe it's an issue about the ABI (maybe all values with a size < 4 need to be correctly extended due to the ABI).

I think Jonas clearly stated that ABI call works properly (to the word of the specification)
The issues is that BOOL in objective-C is for Intel (macOS) is not _Bool but rather a signed char.

As of today, Pascal doesn't provide Boolean type that behaves like a signed char in ABI terms.
(Boolean, and Boolean8 are size of _Bool which matched the size of signed char, though treated are passed as "_Bool" following ABI rules)

thanks,
Dmitry

Reply by email

Michael Van Canneyt
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote
2) why the were they named booleanN rather than gtkboolean or something? (I'm referring to the suggestion of using objcbool name. It seem to fit)

Because introducing a type in a language and naming it after some library is not done. objcbool at least refers to another language.

Michael.

Reply by email

Sven Barth
to Dmitry Boyarintsev: On Fri, Oct 12, 2018 at 6:48 PM Sven Barth via fpc-devel < That's interesting. Let me ask…

Dmitry Boyarintsev schrieb am Sa., 13. Okt.
2018, 01:57:

Show quoted text 33 lines
On Fri, Oct 12, 2018 at 6:48 PM Sven Barth via fpc-devel < > wrote: > Not quite: the Boolean16, Boolean32 and Boolean64 types were introduced > because the libraries provided by GTK required a 4-Byte boolean type that > worked like Object Pascal's Boolean. > That's interesting. Let me ask a couple of things here: 1) gboolean is a size of int ( https://www.gtk.org/api/2.6/glib/glib-Basic-Types.html#gboolean) where FALSE is 0 and TRUE is not FALSE. https://www.gtk.org/api/2.6/glib/glib-Standard-Macros.html#TRUE:CAPS so, it's more -1, rather than 1 and it doesn't quite maps to Boolean and/or Boolean32. It's matches to LongBool. var b : Boolean; lb : LongBool; b32 : Boolean32; begin b := true; lb := true; b32 := true; writeln(byte(b),' ',LongWord(b32),' ',LongWord(lb)); writeln(ord(b),' ',Ord(b32),' ',Ord(lb)); end. Results in: 1 1 4294967295 1 1 -1 (matches documentation)

This was the reason they were added:
https://bugs.freepascal.org/view.php?id=17400

2) why the were they named booleanN rather than gtkboolean or something? (I'm referring to the suggestion of using objcbool name. It seem to fit)

They're an extension of the existing Boolean type with merely a different size, so why should they be named any differently? (in addition to what Michael wrote)

Show quoted text 15 lines
> Then maybe it's an issue about the ABI (maybe all values with a size < 4 > need to be correctly extended due to the ABI). > I think Jonas clearly stated that ABI call works properly (to the word of the specification) The issues is that BOOL in objective-C is for Intel (macOS) is not _Bool but rather a signed char. As of today, Pascal doesn't provide Boolean type that behaves like a signed char in ABI terms. (Boolean, and Boolean8 are size of _Bool which matched the size of signed char, though treated are passed as "_Bool" following ABI rules)

Then maybe the type used to represent that BOOL should be a "type char" alias instead of using one of the build in Boolean types.

Regards,
Sven

Reply by email

Dmitry Boyarintsev
to Michael Van Canneyt: Because introducing a type in a language and naming it after some library is not done.…
AM Michael Van Canneyt wrote 5 lines
Because introducing a type in a language and naming it after some library is not done. objcbool at least refers to another language.

ObjC language doesn't have its own boolean type.
It's either C "_Bool" for ARM, or "a signed char" for Intel/PPC, with 1 for TRUE and 0 for FALSE.

So, in sources we could declare objcbool as such:
type
  objcbool = {IFDEF ARM}Boolean{$ELSE}Bool???{$ENDIF};

Bool??? - what type?
ByteBool - doesn't fit, because it's true value is not false ($FF) Boolean - doesn't fit, because it's _Bool type (and that makes difference for 64-bit, because passing parameters is different) Boolean8 - doesn't fit, because it's just and alias to Boolean. ShortInt or Byte - obviously don't fit, because they cannot accept boolean values.

thanks,
Dmitry

Reply by email

Jonas Maebe
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 9 lines
On Sat, Oct 13, 2018 at 9:55 AM Dmitry Boyarintsev < > wrote: ObjC language doesn't have its own boolean type. No. I'm convienced now: http://wiki.freepascal.org/ObjC_Bool It appears the the compiler is always clearing the entire register to pass the paramater. No matter _Bool or BOOL (signed char). No special treatment for _Bool.

A single test program compiled at a single optimization level does not demonstrate how a particular compiler generates code in all possible situations. In addition, the ABI specification trumps a particular compiler's implementation in any case.

Jonas

Reply by email

Dmitry Boyarintsev
to Jonas Maebe
Jonas Maebe wrote 5 lines
A single test program compiled at a single optimization level does not demonstrate how a particular compiler generates code in all possible situations. In addition, the ABI specification trumps a particular compiler's implementation in any case.

Fair enough.
Are there any particular cases/optimizations you’re interested in?

Thanks,
Dmitry

Reply by email