On 07 Sep 2016, at 5:38 , Ben Coman <btc@openInWorld.com> wrote:

On Wed, Sep 7, 2016 at 10:42 PM, Ben Coman <btc@openinworld.com> wrote:
On Wed, Sep 7, 2016 at 9:09 PM, Esteban Lorenzano <estebanlm@gmail.com> wrote:

On 07 Sep 2016, at 14:56, Ben Coman <btc@openInWorld.com> wrote:

On Tue, Sep 6, 2016 at 8:08 PM, Esteban Lorenzano <estebanlm@gmail.com>
wrote:

Hi,

sorry for arriving so late to this, but I was on holidays :)
this is how autoRelease works:

1) #autoRelease of an object registers object for finalisation with a
particular executor. Then behaviour is divided:

2.1.1) for ExternalAddresses, it just registers in regular way, who will
call #finalize on GC
2.1.2) finalize will just call a free assuming ExternalAddress was allocated
(which is a malloc)

2.2.1) for all FFIExternalReference, it will register for finalisation what
#resourceData answers (normally, the handle of the object)
2.2.2) finalisation process will call the object
class>>#finalizeResourceData: method, with the #resourceData result as
parameter
2.2.3) each kind of external reference can decide how to free that data (by
default is also just freeing).

An example of this is how CairoFontFace works (or AthensCairoSurface).



At the bottom of FFIExternalResourceExecutor class comment I read...
  "Note that in #finalizeResourceData: you cannot
   access any other properties of your instance,
   since it is already garbage collected."

But in my experiments it seems okay to access instance variables in
#finalize.
For example...

CXString >> autoRelease
 self class finalizationRegistry add: self

CXString >> finalize
  Transcript crShow: 'Finalizing CXString ' ; show: self private_flags.
  self dispose.
  Transcript show: ', done!'.

CXString >>private_flags
  "This method was automatically generated"
  ^handle unsignedLongAt: 5

Libclang getClangVersion autoRelease.
Smalltalk garbageCollect.
"==> Finalizing CXString 1, done! "


Is this an unlucky coincidence?   Or maybe something changed from NB
to UFFI?  (There is a reference to NB there)


yes, is a coincidence.
the idea of using #finalizeResourceData: is that you keep minimal
information (in general, just the handle)��� this way we ensure instances will
be collected because we will not have circular references (preventing the
weakregistry to work).

In general, you can always implement as you did it, but I would prefer the
#finalizeResourceData: approach, even for structures.
The only reason it is not implemented is because I didn���t reach the
necessity, then I just skipped it (not in purpose, it was not in my head
:P), but now is a good moment to implement it��� if you want it :)

Thanks for the offer, but hold off for the moment.  I think I actually
need more than just finalization session management.  To get a real
displayable string requires calling the clang_getCString() library
function.  I imagine I'd like to call this from  CXString>>printOn: --
but this of course this would break after restarting the image.

extern "C" {
const char *clang_getCString(CXString string) {
  ....
  return static_cast<const char *>(string.data);
}}

typedef struct {
 const void *data;
 unsigned private_flags;
} CXString;

So I think I need to register CXString with SessionManager to set *data <-- 0
on startup.

An alternative might be adding a session variable to CXString,
   FFIExternalStructure subclass: #CXString
       instanceVariableNames: 'session'
       classVariableNames: ''
       poolDictionaries: 'CXStringFlag'
       package: 'Libclang'

except doing so crashes when calling....
getClangVersion
  ^ self ffiCall: #( CXString clang_getClangVersion () ) module: Libclang

So this worked...

 CXString >> resetData
     handle unsignedLongAt: 1 put: 0.

 CXString class >> startUp: resuming
     resuming
         ifTrue: [ self allInstances do: [ :cxs | cxs resetData ] ].

 CXString class >> initialize
     "self initialize"
     SessionManager default registerSystemClassNamed: self name


Now immediate after a save/restart, doing...
   CXString allInstances first getString   "==> UndefinedObject(nil)"
instead of crashing the VM.

Can you see/guess any traps hidden from me? Now I wonder early it is
practical to prioritise such a reset.  My first thought is at least
before #printString starts getting called ??

For traps, there's the assumption in resetData that pointer stored in handle is unsignedLong-sized.
Shouldn't there be auto-generated accessors for #data you can use instead to change the value to Pointer void?

Cheers,
Henry