@@ -190,6 +190,11 @@ export class Callback {
190190 * C PyObject.
191191 */
192192export class PyObject {
193+ /**
194+ * A Python callabale object as Uint8Array
195+ * This is used with `PyCFunction_NewEx` in order to extend its liftime and not allow v8 to release it before its actually used
196+ */
197+ #pyMethodDef?: Uint8Array ;
193198 constructor ( public handle : Deno . PointerValue ) { }
194199
195200 /**
@@ -447,8 +452,8 @@ export class PyObject {
447452 }
448453 return new PyObject ( list ) ;
449454 } else if ( v instanceof Callback ) {
450- const struct = new Uint8Array ( 8 + 8 + 4 + 8 ) ;
451- const view = new DataView ( struct . buffer ) ;
455+ const pyMethodDef = new Uint8Array ( 8 + 8 + 4 + 8 ) ;
456+ const view = new DataView ( pyMethodDef . buffer ) ;
452457 const LE =
453458 new Uint8Array ( new Uint32Array ( [ 0x12345678 ] ) . buffer ) [ 0 ] !== 0x7 ;
454459 const nameBuf = new TextEncoder ( ) . encode (
@@ -471,11 +476,16 @@ export class PyObject {
471476 LE ,
472477 ) ;
473478 const fn = py . PyCFunction_NewEx (
474- struct ,
479+ pyMethodDef ,
475480 PyObject . from ( null ) . handle ,
476481 null ,
477482 ) ;
478- return new PyObject ( fn ) ;
483+
484+ // NOTE: we need to extend `pyMethodDef` lifetime
485+ // Otherwise V8 can release it before the callback is called
486+ const pyObject = new PyObject ( fn ) ;
487+ pyObject . #pyMethodDef = pyMethodDef ;
488+ return pyObject ;
479489 } else if ( v instanceof PyObject ) {
480490 return v ;
481491 } else if ( v instanceof Set ) {
0 commit comments