Sign in Join

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

Mailing lists / fpc-devel / 2016-04

c-blocks (darwin aarch64)

18 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

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

Dmitry Boyarintsev

Hello,

Does anyone know if cblocks are working for darwin-aarch64?

I'm trying to use GCController objects. The notification is based of blocks.

The code looks like this:
GCExtendedGamepad.inc
----
{$modeswitch cblocks}

type
  GCExtendedGamepadValueChangedHandler = reference to procedure (gamepad:
GCGamepad;
    element: GCControllerElement); cdecl;
type
  GCExtendedGamepad = objcclass external (NSObject)
  public
    ...
    procedure setValueChangedHandler(newValue:
GCExtendedGamepadValueChangedHandler); message 'setValueChangedHandler:';
    ...
  end;

---
maincode.pas
---
{$modeswitch cblocks}
...

procedure extendedGamePadChange(gamepad: GCGamepad; element:
GCControllerElement);
// calling convention cdecl is not specified
begin
  writeln('something changed');
end;
...
  // gc is GCController -  it's a valid object
  // gc.extendedGamepad  - exists and is avalid object
  gc.extendedGamepad.setValueChangedHandler(@extendedGamePadChange);
----

The problem is that code seems to be failing on "setValueCahngeHandler" call.

libobjc.A.dylib`objc_msgSend:
0x2469fa80 <+0>: cbz r0, 0x2469fabe ; <+62> 0x2469fa82 <+2>: ldr.w r9, [r0]
-> 0x2469fa86 <+6>: ldrh.w r12, [r9, #0xc] ; EXC_BAD_ACCESS 0x2469fa8a <+10>: ldr.w r9, [r9, #0x8]
0x2469fa8e <+14>: and.w r12, r12, r1
0x2469fa92 <+18>: add.w r9, r9, r12, lsl #3
0x2469fa96 <+22>: ldr.w r12, [r9]
0x2469fa9a <+26>: teq.w r12, r1
0x2469fa9e <+30>: bne 0x2469faa6 ; <+38> 0x2469faa0 <+32>: ldr.w r12, [r9, #0x4]
0x2469faa4 <+36>: bx r12
0x2469faa6 <+38>: cmp.w r12, #0x1
0x2469faaa <+42>: blo 0x2469fab8 ; <+56> 0x2469faac <+44>: it eq
0x2469faae <+46>: ldreq.w r9, [r9, #0x4]
0x2469fab2 <+50>: ldr r12, [r9, #8]!
0x2469fab6 <+54>: b 0x2469fa9a ; <+26> 0x2469fab8 <+56>: ldr.w r9, [r0]

    0x2469fabc <+60>: b      0x2469fd00                ;

_objc_msgSend_uncached
0x2469fabe <+62>: mov.w r1, #0x0
0x2469fac2 <+66>: mov.w r2, #0x0
0x2469fac6 <+70>: mov.w r3, #0x0
0x2469faca <+74>: bx lr
0x2469facc <+76>: nop
0x2469face <+78>: nop
0x2469fad0 <+80>: nop
0x2469fad2 <+82>: nop
0x2469fad4 <+84>: nop
0x2469fad6 <+86>: nop
0x2469fad8 <+88>: nop
0x2469fada <+90>: nop
0x2469fadc <+92>: nop
0x2469fade <+94>: nop

I wonder if it's related to aarch64, is block parameter passed incorrectly?.
I'm also using fpc-trunk some 2015-Nov revision.
Should I just update to the latest fpc revision?

thanks,
Dmitry

Dmitry Boyarintsev
to Dmitry Boyarintsev

On Thu, Apr 14, 2016 at 11:10 PM, Dmitry Boyarintsev <

Show quoted text 5 lines
wrote: Does anyone know if cblocks are working for darwin-aarch64?

Actually, It's (obviously) not aarch64, but arm7.
Xcode requires to build a fat binary, but still runs 32-bit version on iPhone5s

thanks,
Dmitry

Jonas Maebe
to Dmitry Boyarintsev: Does anyone know if cblocks are working for darwin-aarch64? I'm trying to use…

Dmitry Boyarintsev wrote on Fri, 15 Apr 2016:

Does anyone know if cblocks are working for darwin-aarch64?

The tests in the testsuite work at least, both for ARM and AArch64.

Show quoted text 7 lines
The problem is that code seems to be failing on "setValueCahngeHandler" call. libobjc.A.dylib`objc_msgSend: 0x2469fa80 <+0>: cbz r0, 0x2469fabe ; <+62> 0x2469fa82 <+2>: ldr.w r9, [r0] -> 0x2469fa86 <+6>: ldrh.w r12, [r9, #0xc] ; EXC_BAD_ACCESS

This crash probably has nothing to do with with blocks. objc_msgSend is the dispatch routine to call an Objective-C method. Blocks are called in a different way. The location of the error here suggests that this Objective instance pointer is invalid.

I wonder if it's related to aarch64, is block parameter passed incorrectly?.

Even if that were the case, it wouldn't crash at that place in objc_msgSend. r0 contains the "self" pointer of the Objective-C instance. It's unrelated to the the value of any parameters.

I'm also using fpc-trunk some 2015-Nov revision. Should I just update to the latest fpc revision?

When using trunk, you should always use the latest version.

Jonas

Dmitry Boyarintsev
to Jonas Maebe
Jonas Maebe wrote
The tests in the testsuite work at least, both for ARM and AArch64.

Could it be run-time environment dependent then...

Even if that were the case, it wouldn't crash at that place in objc_msgSend. r0 contains the "self" pointer of the Objective-C instance. It's unrelated to the the value of any parameters.

I think it attempted to copy the block in some way, didn't find the proper reference and crashed or something like that.
Again, without any useful debugging information (which i didn't provide), it's just impossible to say.

When using trunk, you should always use the latest version.

First all of - I am so sorry - I've not updated yet to the latest trunk. I decided to play with blocks first.
Second - THANK YOU - for blockrtl unit.

Instead of relying on FPC to do the block, I decided to make the block myself.

1) the declaration of
GCExtendedGamepadValueChangedHandler = reference to procedure (gamepad: GCGamepad;

    element: GCControllerElement); cdecl;

was changed back to:

  GCExtendedGamepadValueChangedHandler = OpaqueCBlock;

1.1)
the method declaration
GCExtendedGamepad = objcclass external (NSObject)
...

  procedure setValueChangedHandler(newValue:

GCExtendedGamepadValueChangedHandler); message 'setValueChangedHandler:';

remains unchanged.

2) the main unit is now using "blockrtl".
3) the call has been adjusted as following:

type
  Tblock = FPC_Block_literal_base
  Pblock = ^TBlock;
var
  descr : FPC_Block_descriptor_complex; // global block description
procedure joystickInit;
var
  ..
  gc   : GCController;
  block : tblock;
...
      fillchar(descr, sizeof(descr), 0);
      descr.Block_size:=sizeof(block);
...
      fillchar(block, sizeof(block), 0);
      ; // the block is on stack
      ; // pointing to description
      ; // point to the function
...
      gc.extendedGamepad.setValueChangedHandler(@block);

4) extendedGamePadChange_inblock() looks like this:

procedure extendedGamePadChange_inblock(block: PBlock; gamepad: GCGamepad;
element: GCControllerElement); cdecl;
begin
  writeln('block is calling!');
  writeln('A: ', gamepad.buttonA.isPressed);
  writeln('B: ', gamepad.buttonB.isPressed);
  writeln('X: ', gamepad.buttonX.isPressed);
  writeln('Y: ', gamepad.buttonY.isPressed);
end;

and that's it. The code works. The function is called as expected, providing accurate data.
call to ssetValueChangedHandler() doesn't crash. darwin-arm7

I'm going to update to the latest FPC revision now.

thanks,
Dmitry

Dmitry Boyarintsev
to Dmitry Boyarintsev

On Fri, Apr 15, 2016 at 9:09 PM, Dmitry Boyarintsev <

Show quoted text 5 lines
wrote: I'm going to update to the latest FPC revision now.

Using r33526, the app crashes with compiler native blocks at the same spot (on calling set block handler)

*(lldb) bt*

* thread #1: tid = 0x16034c, 0x2469fa86 libobjc.A.dylib`objc_msgSend + 6, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xe92d40bc)

* frame #0: 0x2469fa86 libobjc.A.dylib`objc_msgSend + 6

frame #1: 0x246a00cc libobjc.A.dylib`objc_setProperty_nonatomic_copy + 32

frame #2: 0x000d8da0 testbomber`___lldb_unnamed_function762$$testbomber
+ 1184

frame #3: 0x000d8e9c testbomber`ZGL_JOYSTICK_$$_JOY_INIT$$BYTE + 32

Manually generated block worked (doesn't make feel any better, though).

-------

Two differences I can see between "manual" block and compiler block.

1) set of flags. Manual block doesn't set any of them (in the original example, and GLOBAL flag is set in the example below), where the compiler always sets up BLOCK_HAS_SIGNATURE .

2) the compiler is using Simple description, where manual is using complex. I'm looking Blocks ABI (
http://clang.llvm.org/docs/Block-ABI-Apple.html#imported-variables),

I don't see any reference if "copy" and "dispose" fields could omit and it's allowed to "signature" follow "size" field right away. (I'd think they would use "union" in this case to declare "description")

Also, as far as I understand signature is used for functions returning structures (records)?

I'm looking at x86_64 code (which is a slightly modified version of the very first blocks example)
I can see that "signature" is populated, even though the procedure doesn't return anything.

{$mode objfpc}
{$modeswitch objectivec2}
{$modeswitch cblocks}

uses
ctypes,

  CocoaAll;
type
  tblock = FPC_Block_literal_base;
  pblock = ^tblock;
  NSArrayEnumeratorBlock = reference to procedure (obj: id; idx:
NSUInteger; var stop: boolean); cdecl;
  { normally part of the NSArray declaration, but not yet in
    our units since the released compilers don't support blocks
    yet }
  enumcategory = objccategory external (NSArray)
    procedure enumerateObjectsUsingBlock(block: NSArrayEnumeratorBlock);
message 'enumerateObjectsUsingBlock:';
    procedure enumerateObjectsUsingBlock2(block: pointer); message
'enumerateObjectsUsingBlock:';
  end;
procedure myenumerate(obj: id; idx: NSUInteger; var stop: boolean); cdecl;
begin
  NSLog(NSString.alloc.initWithUTF8String('Object at index %lu is %@'),
idx, obj);
end;
procedure myenumerate_inblock( data: pblock; obj: id; idx: NSUInteger; var
stop: boolean); cdecl;
begin
  writeln('mb');
  myenumerate(obj, idx, stop);
end;
var
  arr: NSMutableArray;
  str: NSString;
  block : FPC_Block_literal_base;
  descr : FPC_Block_descriptor_complex;
begin
  fillchar(descr, sizeof(descr), 0);
  descr.Block_size:=sizeof(block);
  fillchar(block, sizeof(block), 0);
  ; // could be left zero. didn't make
any difference for x86_64
  block.flags:=BLOCK_IS_GLOBAL; // could be left zero. didn't make any
difference
  ;
  ;
  arr := NSMutableArray.alloc.init;
  str:=NSString.alloc.initWithUTF8String('abc');
  arr.addObject(str);
  str:=NSString.alloc.initWithUTF8String('123');
  arr.addObject(str);
  str:=NSString.alloc.initWithUTF8String('XYZ');
  arr.addObject(str);
  arr.enumerateObjectsUsingBlock2(@block);
  arr.enumerateObjectsUsingBlock(@myenumerate);
end.

thanks,
Dmitry

Jonas Maebe
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 7 lines
On Fri, Apr 15, 2016 at 9:09 PM, Dmitry Boyarintsev < > wrote: I'm going to update to the latest FPC revision now. Using r33526, the app crashes with compiler native blocks at the same spot (on calling set block handler)

Can you share code that crashes?

Show quoted text 5 lines
Two differences I can see between "manual" block and compiler block. 1) set of flags. Manual block doesn't set any of them (in the original example, and GLOBAL flag is set in the example below), where the compiler always sets up BLOCK_HAS_SIGNATURE .

Yes, because it's required if you use the "ABI.2010.3.16", which FPC does (because otherwise the block functions are called as C-style varargs functions, which we cannot handle on the callee side).

Show quoted text 7 lines
2) the compiler is using Simple description, where manual is using complex. I'm looking Blocks ABI (http://clang.llvm.org/docs/Block-ABI-Apple.html#imported-variables), I don't see any reference if "copy" and "dispose" fields could omit and it's allowed to "signature" follow "size" field right away. (I'd think they would use "union" in this case to declare "description")

See http://clang.llvm.org/docs/Block-ABI-Apple.html#high-level

Those fields only exist if bits 25 resp. 26 are set in the flags.

Also, as far as I understand signature is used for functions returning structures (records)?

The signature field is required as soon as you say you comply to the "ABI.2010.3.16".

Jonas

Dmitry Boyarintsev
to Jonas Maebe
Jonas Maebe wrote 5 lines
Using r33526, the app crashes with compiler native blocks at the same > spot (on calling set block handler) > Can you share code that crashes?

uses
.. GameController // from iOS headers

procedure extendedGamePadChange(gamepad: GCExtendedGamepad; element:
GCControllerElement);
begin
  writeln('extendedGamepad changed! ', PtrUint(gamepad),' element:
',element._classDescription.utf8string);
end;
function iOS_joy_Init : Byte;
var
  list : NSArray;
  i    : integer;
  obj  : NSObject;
  gc   : GCController;
  block : tblock;
begin
  list:=GCController.controllers;
  Result:=list.count;
  for i:=0 to Result-1 do begin
    gc:=GCController(list.objectAtIndex(i));
    gc.setPlayerIndex(GCControllerPlayerIndex1+i);
    if Assigned(gc.extendedGamepad) then begin
       gc.extendedGamepad.setValueChangedHandler(@extendedGamePadChange);
// <- crash line
    end;
  end;
end;

... or are you looking for the whole project?
I should be able to create a stand-alone sample for you. (that could be a better basis for starting a bug report).

See http://clang.llvm.org/docs/Block-ABI-Apple.html#high-level

Those fields only exist if bits 25 resp. 26 are set in the flags.

There's no real indication that these fields could physically omit. (unless "IFF" or "optional helper fields" in comments actually mean that).

thanks,
Dmitry

Jonas Maebe
to Dmitry Boyarintsev
Show quoted text 10 lines
On 16 Apr 2016, at 21:35, Dmitry Boyarintsev wrote: On Sat, Apr 16, 2016 at 3:05 PM, Jonas Maebe wrote: >> Using r33526, the app crashes with compiler native blocks at the same >> spot (on calling set block handler) > > Can you share code that crashes? uses .. GameController // from iOS headers

[snip]

... or are you looking for the whole project?

Yes, a test program that can be used to reproduce the bug (preferably command line)

Show quoted text 5 lines
> See http://clang.llvm.org/docs/Block-ABI-Apple.html#high-level > > Those fields only exist if bits 25 resp. 26 are set in the flags. There's no real indication that these fields could physically omit. (unless "IFF" or "optional helper fields" in comments actually mean that).

Yes, that's what optional field means (as opposed to field that is optionally initialised or so). You can check the clang source code too: http://llvm.org/svn/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp

/// buildBlockDescriptor - Build the block descriptor meta-data for a block.
/// buildBlockDescriptor is accessed from 5th field of the Block_literal
/// meta-data and contains stationary information about the block literal.
/// Its definition will have 4 (or optinally 6) words.
/// \code
/// struct Block_descriptor {
///   unsigned long reserved;
///   unsigned long size;  // size of Block_literal metadata in bytes.
///   void *copy_func_helper_decl;  // optional copy helper.
///   void *destroy_func_decl; // optioanl destructor helper.
///   void *block_method_encoding_address; // @encode for block literal signature.
///   void *block_layout_info; // encoding of captured block variables.
/// };

Jonas

Dmitry Boyarintsev
to Jonas Maebe
Jonas Maebe wrote 5 lines
Yes, a test program that can be used to reproduce the bug (preferably command line) even better! it's pure OSX (x86_64)! not need for iOS

http://bugs.freepascal.org/view.php?id=30022

The sample is using block-based APIs of NSFileHandle https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileHandle_Class/

to be honest. I've no idea how the method should work, but I'd expect it shouldn't throw an access violation.

It feels like the problem arrises when the run time tries to copy the block. The sample with NSArrays traversing doesn't try to retain the block, instead it just calls it right away.

Yes, that's what optional field means (as opposed to field that is

optionally initialised or so). You can check the clang source code too: http://llvm.org/svn/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp

Got it!

thanks,
Dmitry

Sven Barth
to Dmitry Boyarintsev

Am 17.04.2016 01:25 schrieb "Dmitry Boyarintsev" <

: Aside question: Is syntax for blocks settled? at least for "reference to"

part?

I'm eager to create Code Tools feature request.

Yes, because aside from the cdecl Delphi uses the same syntax for anonymous function references, so we (aka Jonas) copied that for blocks.

Regards,
Sven

Dmitry Boyarintsev
to Sven Barth
Sven Barth wrote
Yes, because aside from the cdecl Delphi uses the same syntax for anonymous function references, so we (aka Jonas) copied that for blocks.

Oh yes, that rings a bell, I remember an email about reusing anonymous functions syntax for forward compatibility.

thanks,
Dmitry

Dmitry Boyarintsev
to Dmitry Boyarintsev

Hello Jonas,

Regarding the fix on 30022. I'd think the behavior is Delphi compatible, where it would also complain passing a function (block) with address operator.

It's just a bit surprising, since it's inconsistent with regular procedure type variables.

{$mode delphi}
type TMyProc = procedure;
procedure Test;
begin
  writeln('test');
end;
procedure Call(p: TMyProc);
begin
  p();
end;
begin
  Call(Test); // works
  Call(@Test); // works
end.

thanks,
Dmitry

Jonas Maebe
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote
Regarding the fix on 30022. I'd think the behavior is Delphi compatible, where it would also complain passing a function (block) with address operator.

Delphi does not support assigning procedures to variables representing anonymous functions, so I doubt they would allow it for C-blocks.

It's just a bit surprising, since it's inconsistent with regular procedure type variables.

It's the same as with procedure of object, also in Delphi. The fact that Type X (pointer) can be automatically converted to Type Y (procvar), does not mean that Type X can also be automatically converted to type Z (C-block).

In fact, it is plain bad to let (data) pointers be automatically converted into procvars and vice versa, because on some platforms (such as PowerPC64 ELFv1, and also MS-DOS in most memory models) they are quite different. We "solve" this by also returning a procvar for @procname on such platforms (or by introducing multiple pointer types like for MS-DOS), but that in turn requires workarounds like in r20820.

Jonas

Ondrej Pokorny
to Jonas Maebe
Jonas Maebe wrote
Delphi does not support assigning procedures to variables representing anonymous functions

It does. Both for procedure of object and plain procedure:

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
   System.SysUtils;
type
   TRefProc = reference to procedure;
   TMyObj = class(TObject)
   public
     procedure Test2;
   end;
   procedure Test;
   begin
     Writeln('hello');
     Readln;
   end;

{ TMyObj }

procedure TMyObj.Test2;
begin
   Writeln('hello2');
   Readln;
end;
var
   xR: TRefProc;
   xO: TMyObj;
begin
   xR := Test;
   xR();
   xR := xO.Test2;
   xR();
end.

Ondrej

Maciej Izak
to Ondrej Pokorny

2016-04-18 10:30 GMT+02:00 Ondrej Pokorny :

Show quoted text 8 lines
On 18.04.2016 10:18, Jonas Maebe wrote: Delphi does not support assigning procedures to variables representing anonymous functions It does. Both for procedure of object and plain procedure:

+1. ... this feature is important also for Generics.Defaults

Best regards, Maciej Izak
Jonas Maebe
to Ondrej Pokorny: It does. Both for procedure of object and plain procedure: program Project1; {$APPTYPE…
Ondrej Pokorny wrote 5 lines
On 18.04.2016 10:18, Jonas Maebe wrote: > Delphi does not support assigning procedures to variables representing > anonymous functions It does. Both for procedure of object and plain procedure:

Sorry, I misremembered: it does not support it for nested procedures, even though are semantically quite similar to anonymous functions (in terms of capturing context).

Jonas