<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 4, 2019 at 11:43 AM Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Hi Holger,<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 4, 2019 at 10:04 AM Holger Freyther <<a href="mailto:holger@freyther.de" target="_blank">holger@freyther.de</a>> wrote:</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<br>
> On 3. Apr 2019, at 23:50, Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>> wrote:<br>
> <br>
> Hi Holger,<br>
<br>
> It's represented as FFIExternalStructure subclass: #CXCursor. In the case of the callback the handle is an instance of FFIExternalStructureReferenceHandle with an Alien embedded into it.<br>
> <br>
> What is the C signature of the callback function, and what is the source of the marshaling method in the relevant Callback subclass's signatures protocol?<br>
> Also, what's the callout's signature and what is the Smalltalk code for the call?<br>
<br>
<br>
C declaration:<br>
<br>
typedef enum CXChildVisitResult(* CXCursorVisitor) (CXCursor cursor, CXCursor parent, CXClientData client_data);<br>
<br>
and passed to the c function below.<br>
<br>
unsigned clang_visitChildren (CXCursor parent, CXCursorVisitor visitor, CXClientData client_data );<br>
<br>
<br>
Smalltalk Source:<br>
<br>
acceptCallbackFn := <br>
FFICallback<br>
signature: #( CXChildVisitResult (<br>
CXCursor cursor, <br>
CXCursor parent, <br>
CXString client_data))<br></blockquote><div><br></div><div>somewhere in the Callback hierarchy there should me a marshaling method for the platform you're on that matches that signature. Fo example, in Squeak if I'm calling, say, sort, then there's a callback such as</div><div><br></div><div><span style="white-space:pre-wrap"> </span>Callback</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>signature: #(int (*)(const void *, const void *))</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2 doubleAt: 1)) sign].</div><div><br></div><div>to marshal the callback's incoming arguments each platform needs a suitable marshaling method that the Callback machinery matches to the signature. Here they are from Squeak:</div><div><br></div><div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>Callback methods for signatures</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>voidstarvoidstarRetint: callbackContext regs: regsAlien</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span><signature: #(int (*)(const void *, const void *))></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>self subclassResponsibility</div><div><br></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>CallbackForARM32 methods for signatures</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>voidstarvoidstarRetint: callbackContext regs: regsAlien</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span><signature: #(int (*)(const void *, const void *))></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>^callbackContext wordResult:</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>(block</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongAt: 1))</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongAt: 5)))</div><div><br></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>CallbackForWin64X64 methods for signatures</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>voidstarvoidstarRetint: callbackContext regs: regsAlien</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span><signature: #(int (*)(const void *, const void *))></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>^callbackContext wordResult:</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>(block</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongLongAt: 1))</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongLongAt: 9)))</div><div><br></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>CallbackForX64 methods for signatures</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>voidstarvoidstarRetint: callbackContext regs: regsAlien</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span><signature: #(int (*)(const void *, const void *))></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>^callbackContext wordResult:</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>(block</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongLongAt: 1))</div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>value: (Alien forPointer: (regsAlien unsignedLongLongAt: 9)))</div></div></div></div></div></div></div></blockquote><div><br></div><div>Missed one (finger trouble)</div><div><br></div><div><span class="gmail-m_3874790475876866737gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>CallbackForIA32 methods for signatures<br></div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>voidstarvoidstarRetint: callbackContext sp: spAlien</div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span><signature: #(int (*)(const void *, const void *))></div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>^callbackContext wordResult:</div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>(block</div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>value: (Alien forPointer: (spAlien unsignedLongAt: 1))</div><div><span class="gmail-Apple-tab-span" style="white-space:pre"> </span>value: (Alien forPointer: (spAlien unsignedLongAt: 5)))</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div><br></div><div>What are is method for your platform?</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">CXChildVisitResult is an enum, CXCursor/CXString are FFIExternalStructure subclasses.<br>
<br>
<br>
<br>
Smalltalk code:<br>
<br>
<br>
Libclang clang_visitChildren__parentCursor: rootCursor <br>
visitorCallback: acceptCallbackFn <br>
clientData: rootClientData.<br>
<br>
>>#clang_visitChildren__parentCursor: parent <br>
visitorCallback: visitor <br>
clientData: client_data<br>
^ self ffiCall: #( uint clang_visitChildren(<br>
CXCursor parent,<br>
CXCursorVisitor visitor,<br>
CXClientData client_data))<br>
<br>
<br>
<br>
> Or do I chase it from the wrong end?<br>
> <br>
> Without the code I can't help, hence my questions above.<br>
<br>
The full code is in Ben's LibclangPractice (<a href="http://smalltalkhub.com/#!/~BenComan/LibclangPractice" rel="noreferrer" target="_blank">http://smalltalkhub.com/#!/~BenComan/LibclangPractice</a>). I have set a breakpoint in LibclangTest>>#visitChildrenCallbackReturning: to look at the cursor variable and call it's methods. I think my Pharo PR (<a href="https://github.com/pharo-project/pharo/pull/3136/files#diff-8f4b31166c3a817dd8ad1f0518ae633a" rel="noreferrer" target="_blank">https://github.com/pharo-project/pharo/pull/3136/files#diff-8f4b31166c3a817dd8ad1f0518ae633a</a>) is fixing the callback handling in Unified-FFI.<br>
<br>
<br>
I think I have stumbled into three separate bugs and I just noticed that they are Pharo specific. Unified-FFI doesn't seem to exist for Squeak.<br>
<br>
<br>
1st) an Alien ending inside a handle of a FFIExternalStructure sub-instance. I have made a PR for it and I think it is reasonable to turn the Alien into an ExternalAddress early.<br>
<br>
2nd) Pushing a FFIExternalStructure sub-instance with a FFIExternalStructureReferenceHandle in it to the stack doesn't work. Squeak+ThreadedFFIPlugin simply don't know what a FFIExternalStructureReferenceHandle valueOOP is.<br>
<br>
<br>
3rd) Returning a struct from the callback doesn't to work either. That's a UnifiedFFI bug as well:<br>
<br>
In FFICallbackParameterTests>>#testPassingStructureInTheStack <br>
<br>
| param |<br>
callback := FFICallback <br>
signature: #(int (FFITestStructureSmallIntFloatStructure a))<br>
block: [ :a |<br>
self assert: a x equals: 2.0. <br>
self assert: a y equals: 3. ..<br>
<br>
change the "int" to "FFITestStructureSmallIntFloatStructure" and the first assertion will fail. The value of "a x" becomes 3. I have not debugged this.<br>
<br>
<br>
I think only 2nd) is relevant to this list. Support for FFIExternalStructureReferenceHandle will add one level of indirection.<br>
<br>
<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail-m_3874790475876866737gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div></div></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div></div></div>