diff --git a/newbinding/Makefile b/newbinding/Makefile index 77a012b..49e244b 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,4 +1,5 @@ -PYMODS = _Debug raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module +PYTHON = python +PYMODS = raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module all: _api.so _capsule.so diff --git a/newbinding/binding.py b/newbinding/binding.py index ab0e1c0..63fcf9e 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -45,13 +45,15 @@ def mangle(name): name = name.replace('_', '__').replace(' ', '_') return name.replace('::', '_').rstrip('*&') -def pycapsule_new(println, ptr, name, clsname, dtor='capsule_destructor'): +def pycapsule_new(println, ptr, name, clsname, dtor=NULL): # build capsule name_soften = mangle(name) var = new_symbol('pycap_%s' % name_soften) fmt = 'PyObject* %(var)s = PyCapsule_New(%(ptr)s, "%(name)s", %(dtor)s);' println(fmt % locals()) + println('if (!%(var)s) return NULL;' % locals()) + # build context fmt = 'new CapsuleContext("%(clsname)s")' context = declare(println, 'CapsuleContext*', fmt % locals()) diff --git a/newbinding/capsule.cpp b/newbinding/capsule.cpp index 40d135b..e7e4932 100644 --- a/newbinding/capsule.cpp +++ b/newbinding/capsule.cpp @@ -66,34 +66,6 @@ PyObject* getClassName(PyObject* self, PyObject* args) { } } -static -PyObject* setDestructor(PyObject* self, PyObject* args) { - PyObject* cap; - PyObject* callable; - if (!PyArg_ParseTuple(args, "OO", &cap, &callable)) { - return NULL; - } - PyObject* arglist = Py_BuildValue("(O)", cap); - CapsuleContext* context = getContext(self, arglist); - Py_DECREF(arglist); - if (!context) { - return NULL; - } else { - void* ptr; - if (callable != Py_None) { - if (PyCallable_Check(callable)) { - ptr = callable; - } else { - PyErr_SetString(PyExc_TypeError, "Argument is not callable."); - return NULL; - } - } else { - ptr = NULL; - } - context->destructor = (Destructor_Fn)ptr; - } - Py_RETURN_NONE; -} static PyMethodDef core_methods[] = { #define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } @@ -101,7 +73,6 @@ static PyMethodDef core_methods[] = { declmethod(getPointer), declmethod(check), declmethod(getClassName), - declmethod(setDestructor), { NULL }, #undef declmethod }; diff --git a/newbinding/capsule.py b/newbinding/capsule.py index b82154b..509b4c4 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -1,18 +1,44 @@ import _capsule -from weakref import WeakValueDictionary +from weakref import WeakValueDictionary, ref +import logging +logger = logging.getLogger(__name__) + +def set_debug(enabled): + ''' + Side-effect: configure logger with it is not configured. + ''' + if enabled: + # If no handlers are configured for the root logger, + # build a default handler for debugging. + # Can we do better? + if not logger.root.handlers: + logging.basicConfig() + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.WARNING) + + +class WeakRef(ref): + __slots__ = 'capsule', 'dtor' _pyclasses = {} _addr2obj = WeakValueDictionary() - +_owners = {} def _sentry(ptr): assert _capsule.check(ptr) - def classof(cap): cls = _capsule.getClassName(cap) return _pyclasses[cls] +def _capsule_destructor(weak): + cap = weak.capsule + addr = _capsule.getPointer(cap) + cls = _capsule.getClassName(cap) + logger.debug("destroy pointer %s to %s", addr, cls) + weak.dtor(cap) + del _owners[addr] def wrap(cap): '''Wrap a PyCapsule with the corresponding Wrapper class. @@ -29,9 +55,12 @@ def wrap(cap): cls = classof(cap) obj = cls(cap) _addr2obj[addr] = obj # cache object by address - # set destructor if cls.delete is defined + # set ownership if *cls* defines *_delete_* if hasattr(cls, '_delete_'): - _capsule.setDestructor(cap, cls._delete_) + weak = WeakRef(obj, _capsule_destructor) + _owners[addr] = weak + weak.capsule = cap + weak.dtor = cls._delete_ else: assert classof(obj._ptr) is classof(cap) # Unset destructor for capsules that are repeated diff --git a/newbinding/include/llvm_binding/capsule_context.h b/newbinding/include/llvm_binding/capsule_context.h index bb45566..dacfc89 100644 --- a/newbinding/include/llvm_binding/capsule_context.h +++ b/newbinding/include/llvm_binding/capsule_context.h @@ -1,48 +1,19 @@ #ifndef LLVMPY_CAPSULE_CONTEXT_H_ #define LLVMPY_CAPSULE_CONTEXT_H_ + #include #include typedef PyObject* Destructor_Fn; -static bool CapsuleContextDebug = false; - struct CapsuleContext { const char* className; - Destructor_Fn destructor; - - CapsuleContext(const char* cn, Destructor_Fn dtor=NULL) - : className(cn), destructor(dtor) { } + + CapsuleContext(const char* cn) + : className(cn) + { } }; -void capsule_destructor(PyObject* capsule){ - using std::cerr; - using std::endl; - CapsuleContext* context = (CapsuleContext*)PyCapsule_GetContext(capsule); - if (context->destructor) { - if (CapsuleContextDebug) { - cerr << clock() - << " == DEBUG ==" - << " destroy pointer: " - << context->className - << endl; - } - PyObject_CallMethodObjArgs(context->destructor, capsule, NULL); - } else { - if (CapsuleContextDebug) { - cerr << clock() - << " == DEBUG ==" - << " keep pointer alive: " - << context->className - << endl; - } - } - delete context; -} - -void enable_capsule_dtor_debug(bool enabled){ - CapsuleContextDebug = enabled; -} #endif //LLVMPY_CAPSULE_CONTEXT_H_ diff --git a/newbinding/src/_Debug.py b/newbinding/src/_Debug.py deleted file mode 100644 index be092f3..0000000 --- a/newbinding/src/_Debug.py +++ /dev/null @@ -1,3 +0,0 @@ -from binding import * - -enable_capsule_dtor_debug = Function('', Void, Bool.From(bool)) diff --git a/newbinding/test2.py b/newbinding/test2.py index 25a59d7..872dfc0 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,20 +1,44 @@ import api -#api.enable_capsule_dtor_debug(True) +#api.capsule.set_debug(True) context = api.getGlobalContext() +def test(): + print '*' * 80 + m = api.Module.new("modname", context) + print m.getModuleIdentifier() + m.setModuleIdentifier('modname2') + print m.getModuleIdentifier() + print 'endianness', m.getEndianness() + assert m.getEndianness() == api.Module.Endianness.AnyEndianness + print 'pointer-size', m.getPointerSize() + assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize + m.dump() + m = api.Module.new("modname", context) print m.getModuleIdentifier() m.setModuleIdentifier('modname2') print m.getModuleIdentifier() +print 'endianness', m.getEndianness() +assert m.getEndianness() == api.Module.Endianness.AnyEndianness +print 'pointer-size', m.getPointerSize() +assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() + + + os = api.raw_svector_ostream_helper.create() m.print_(os, None) print os.str() + int1ty = api.Type.getInt1Ty(context) int1ty.dump() print int1ty.isIntegerTy(1) +fnty = api.FunctionType.get(int1ty, False) +os2 = api.raw_svector_ostream_helper.create() +fnty.print_(os2) +print os2.str()