I've tried to convert <https://github.com/pragmagic/godot-nim> for use with 
orc. And while it's been working for the most part, I'm getting a crash in a 
destructor that I've mechanically converted from a finalizer. godot-nim relies 
on gc:refc and when converting to orc I had to convert the finalizer for this 
ref type:
    
    
    type
      NimGodotObject* = ref object of RootObj
        ## The base type all Godot types inherit from.
        ## Manages lifecycle of the wrapped ``GodotObject``.
        godotObject: ptr GodotObject
        linkedObjectPtr: pointer
          ## Wrapper around native object that is the container of the Nim 
"script"
          ## This is needed for `of` checks and `as` conversions to work as
          ## expected. For example, Nim type may inherit from ``Spatial``, but 
the
          ## script is attached to ``Particles``. In this case conversion to
          ## ``Particles`` is valid, but Nim type system is not aware of that.
          ## This works in both directions - for linked native object this
          ## reference points to Nim object.
          ## This is stored as a raw pointer to avoid reference cycles and 
therefore
          ## improve GC performance.
        isRef*: bool
        isFinalized: bool
        isNative: bool
    
    
    proc deinit*(obj: NimGodotObject) =
      ## Destroy the object. You only need to call this for objects not 
inherited
      ## from Reference, where manual lifecycle control is necessary.
      assert(not obj.godotObject.isNil)
      obj.godotObject.deinit()
      obj.godotObject = ni
    
    proc linkedObject(obj: NimGodotObject): NimGodotObject {.inline.} =
      cast[NimGodotObject](obj.linkedObjectPtr)
    
    proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) =
      if obj.godotObject.isNil or obj.isNative: return
      # important to set it before so that ``unreference`` is aware
      obj.isFinalized = true
      if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) 
and
         obj.godotObject.unreference():
        obj.deinit()
    
    
    
    Run

Here's my conversion:
    
    
    type
      NimGodotObject* = ref NimGodotObj
      NimGodotObj = object of RootObj
        ## The base type all Godot types inherit from.
        ## Manages lifecycle of the wrapped ``GodotObject``.
        godotObject: ptr GodotObject
        linkedObjectPtr: pointer
          ## Wrapper around native object that is the container of the Nim 
"script"
          ## This is needed for `of` checks and `as` conversions to work as
          ## expected. For example, Nim type may inherit from ``Spatial``, but 
the
          ## script is attached to ``Particles``. In this case conversion to
          ## ``Particles`` is valid, but Nim type system is not aware of that.
          ## This works in both directions - for linked native object this
          ## reference points to Nim object.
          ## This is stored as a raw pointer to avoid reference cycles and 
therefore
          ## improve GC performance.
        isRef*: bool
        isFinalized: bool
        isNative: bool
    
    proc `=destroy`*(obj: var NimGodotObj) =
      if obj.godotObject.isNil or obj.isNative: return
      # important to set it before so that ``unreference`` is aware
      obj.isFinalized = true
      
      let linkedGodotObject = cast[NimGodotObject](obj.linkedObjectPtr)
      if (obj.isRef or not linkedGodotObject.isNil and linkedGodotObject.isRef) 
and obj.godotObject.unreference():
        obj.godotObject.deinit()
        obj.godotObject = nil
    
    
    Run

In the code with the finalizer using gc:refc no crash occurs. With the 
destructor code and orc, I get a crash around the line where I create the `let 
linkedGodotObject` variable. Here's what the top of stacktrace looks like: 
    
    
    CrashHandlerException: Program crashed
    Dumping the backtrace. Please include this when reporting the bug on 
https://github.com/godotengine/godot/issues
    [0] unregisterCycle__rR8fldvW9aUfvKydORzL1RA (C:\nim\lib\system\orc.nim:140)
    [1] rememberCycle__LoYD9cYK9aJvrcDizBN64qaQ (C:\nim\lib\system\orc.nim:448)
    [2] nimDecRefIsLastCyclicDyn (C:\nim\lib\system\orc.nim:465)
    [3] eqdestroy___SAYng9cJoF6y4ebaA9cSvwLg 
(C:\godot\gdnim\deps\godot\nim\godotnim.nim:196)
    [4] removeGodotObject__t3kHGTvDIkuUnCL9ab87QOAgodotnim 
(C:\godot\gdnim\deps\godot\nim\godotnim.nim:197)
    [5] nimDestroyFunc__FMVhGprKRYmCSltkbHn4rw 
(C:\godot\gdnim\deps\godot\nim\godotmacros.nim:516)
    [6] NativeScriptInstance::`scalar deleting destructor'
    ...
    
    
    Run
    
    
    #orc.nim
    proc unregisterCycle(s: Cell) =
      # swap with the last element. O(1)
      let idx = s.rootIdx-1
      when false:
        if idx >= roots.len or idx < 0:
          cprintf("[Bug!] %ld\n", idx)
          quit 1
      roots.d[idx] = roots.d[roots.len-1]  # <-- crash here
      roots.d[idx][0].rootIdx = idx+1
      dec roots.len
      s.rootIdx = 0
    
    
    Run

So am I doing something bad in the destructor, or is this a problem elsewhere?

Reply via email to