diff --git a/newbinding/capsule.py b/newbinding/capsule.py index 8c2f10e..e29948d 100644 --- a/newbinding/capsule.py +++ b/newbinding/capsule.py @@ -92,8 +92,12 @@ _cache = defaultdict(WeakValueDictionary) def release_ownership(old): logger.debug('Release %s', old) addr = Capsule.getPointer(old) - if _addr2dtor[addr] is None: - # Guard deduplicated release + + if _addr2dtor.get(addr) is None: + clsname = Capsule.getClassName(old) + if not _pyclasses[clsname]._has_dtor(): + return + # Guard duplicated release raise Exception("Already released") _addr2dtor[addr] = None @@ -117,7 +121,7 @@ def wrap(cap, owned=False): try: # lookup cached object return _cache[cls][addr] except KeyError: - if not owned and hasattr(cls, '_delete_'): + if not owned and cls._has_dtor(): _addr2dtor[addr] = cls._delete_ obj = cap.instantiate() _cache[cls][addr] = obj # cache it @@ -164,6 +168,10 @@ class Wrapper(object): def _downcast(self, newcls): return downcast(self, newcls) + @classmethod + def _has_dtor(cls): + return hasattr(cls, '_delete_') + def downcast(obj, cls): import _api if type(obj) is cls: diff --git a/newbinding/gen/binding.py b/newbinding/gen/binding.py index 09cd9bf..1c7c7ca 100644 --- a/newbinding/gen/binding.py +++ b/newbinding/gen/binding.py @@ -283,6 +283,7 @@ class Method(object): self.signatures = [] self.includes = set() self._add_signature(return_type, *args) + self.disowning = False def _add_signature(self, return_type, *args): prev_lens = set(map(len, self.signatures)) @@ -350,6 +351,8 @@ class Method(object): decl = writer.function(self.name, args=('self',), varargs='args') with decl as (this, varargs): unwrap_this = writer.unwrap(this) + if self.disowning: + writer.release_ownership(unwrap_this) unwrapped = writer.unwrap_many(varargs) self.process_ownedptr_args(writer, unwrapped) diff --git a/newbinding/include/llvm_binding/extra.h b/newbinding/include/llvm_binding/extra.h index 85e1ea5..0d9ba16 100644 --- a/newbinding/include/llvm_binding/extra.h +++ b/newbinding/include/llvm_binding/extra.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "auto_pyobject.h" @@ -694,3 +695,21 @@ PyObject* ConstantVector_get(PyObject* Elems) return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); } +static +PyObject* Intrinsic_getDeclaration(llvm::Module* Mod, + unsigned ID, + PyObject* Types=NULL) +{ + using namespace llvm; + Function* Fn = NULL; + if (Types) { + std::vector types; + bool ok = extract::from_py_sequence(types, Types, "llvm::Type"); + if (!ok) return NULL; + Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID, types); + } else { + Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID); + } + return pycapsule_new(Fn, "llvm::Value", "llvm::Function"); +} + diff --git a/newbinding/src/Function.py b/newbinding/src/Function.py index ee59990..d82b5d3 100644 --- a/newbinding/src/Function.py +++ b/newbinding/src/Function.py @@ -1,6 +1,8 @@ from binding import * from namespace import llvm from Value import GlobalValue, Constant, Function, Argument +from BasicBlock import BasicBlock +from Attributes import Attributes from Type import Type from DerivedTypes import FunctionType from LLVMContext import LLVMContext @@ -21,6 +23,33 @@ class Function: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) + hasGC = Method(cast(bool, Bool)) + getGC = Method(cast(ConstCharPtr, str)) + setGC = Method(Void, cast(str, ConstCharPtr)) + getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) + getEntryBlock = Method(ref(BasicBlock)) + + copyAttributesFrom = Method(Void, ptr(GlobalValue)) + + setDoesNotThrow = Method() + doesNotThrow = Method(cast(Bool, bool)) + setDoesNotReturn = Method() + doesNotReturn = Method(cast(Bool, bool)) + setOnlyReadsMemory = Method() + onlyReadsMemory = Method(cast(Bool, bool)) + setDoesNotAccessMemory = Method() + doesNotAccessMemory = Method(cast(Bool, bool)) + + deleteBody = Method() + viewCFG = Method() + viewCFGOnly = Method() + + addFnAttr = Method(Void, Attributes.AttrVal) + removeFnAttr = Method(Void, ref(Attributes)) + + eraseFromParent = Method() + eraseFromParent.disowning = True + diff --git a/newbinding/src/GlobalValue.py b/newbinding/src/GlobalValue.py index 02ba4ea..f21d5af 100644 --- a/newbinding/src/GlobalValue.py +++ b/newbinding/src/GlobalValue.py @@ -44,4 +44,6 @@ class GlobalValue: isDeclaration = Method(cast(Bool, bool)) removeFromParent = Method() eraseFromParent = Method() + eraseFromParent.disowning = True + getParent = Method(ptr(Module)) diff --git a/newbinding/src/GlobalVariable.py b/newbinding/src/GlobalVariable.py index a11f259..4ee91fb 100644 --- a/newbinding/src/GlobalVariable.py +++ b/newbinding/src/GlobalVariable.py @@ -45,5 +45,5 @@ class GlobalVariable: # isExternallyInitialized = Method(cast(Bool, bool)) # setExternallyinitialized = Method(Void, cast(bool, Bool)) - eraseFromParent = Method() + \ No newline at end of file diff --git a/newbinding/src/Intrinsics.py b/newbinding/src/Intrinsics.py new file mode 100644 index 0000000..0f1bcb4 --- /dev/null +++ b/newbinding/src/Intrinsics.py @@ -0,0 +1,17 @@ +from binding import * +from namespace import llvm + +from Module import Module +from Function import Function + + +Intrinsic = llvm.Class() # fake class (actually a namespace) + +@Intrinsic +class Intrinsic: + getDeclaration = CustomStaticMethod('Intrinsic_getDeclaration', + PyObjectPtr, # Function* + ptr(Module), + cast(int, Unsigned), # intrinsic id + PyObjectPtr, # list of Type + ).require_only(2) diff --git a/newbinding/test_binding.py b/newbinding/test_binding.py index 5b51ecb..9003f7d 100644 --- a/newbinding/test_binding.py +++ b/newbinding/test_binding.py @@ -319,6 +319,16 @@ def test_constants(): aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4) assert str(aryconst.getAggregateElement(0)) == str(intconst) +def test_intrinsic(): + context = api.getGlobalContext() + m = api.Module.new("modname", context) + INTR_SIN = 1652 + floatty = api.Type.getFloatTy(context) + fn = api.Intrinsic.getDeclaration(m, INTR_SIN, [floatty]) + assert 'llvm.sin.f32' in str(fn) + fn.eraseFromParent() + assert 'llvm.sin.f32' not in str(m) + def main(): for name, value in globals().items(): if name.startswith('test_') and callable(value):