Reverse finalizer

This commit is contained in:
Siu Kwan Lam 2013-01-07 14:25:58 -06:00
commit 371e940c83
7 changed files with 41 additions and 111 deletions

View file

@ -6,9 +6,7 @@ __version__ = '0.9.1'
from weakref import WeakValueDictionary from weakref import WeakValueDictionary
from llvm._utils.finalizer import track as track_resource import _core
from llvm._utils.finalizer import OwnerMixin as _OwnerMixin
from llvm import _core
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
# LLVM Version # LLVM Version
@ -33,26 +31,11 @@ class LLVMException(Exception):
Exception.__init__(self, msg) Exception.__init__(self, msg)
#===----------------------------------------------------------------------===
# Resource Handle
#===----------------------------------------------------------------------===
class Handle(_OwnerMixin):
_finalizer = NotImplemented
def __init__(self, ptr):
self.ptr = ptr
self._finalizer_track(self.ptr)
@classmethod
def _finalize(cls, ptr):
cls._finalizer(ptr)
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
# Ownables # Ownables
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class Ownable(Handle): class Ownable(object):
"""Objects that can be owned. """Objects that can be owned.
Modules and Module Providers can be owned, i.e., the responsibility of Modules and Module Providers can be owned, i.e., the responsibility of
@ -61,21 +44,25 @@ class Ownable(Handle):
is NOT intended for public use. is NOT intended for public use.
""" """
def __init__(self, ptr): def __init__(self, ptr, del_fn):
Handle.__init__(self, ptr) self.ptr = ptr
self.owner = None self.owner = None
self.del_fn = del_fn
def _own(self, owner): def _own(self, owner):
if self.owner: if self.owner:
raise LLVMException("object already owned") raise LLVMException("object already owned")
self.owner = owner self.owner = owner
self._finalizer_untrack(self.ptr)
def _disown(self): def _disown(self):
if not self.owner: if not self.owner:
raise LLVMException("not owned") raise LLVMException("not owned")
self.owner = None self.owner = None
self._finalizer_track(self.ptr)
def __del__(self):
if not self.owner:
self.del_fn(self.ptr)
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
# Dummy owner, will not delete ownee. Be careful. # Dummy owner, will not delete ownee. Be careful.

View file

@ -1,58 +0,0 @@
'''
Modified C-level finalizer by Benjamin Peterson <benjamin@python.org>
Available at http://code.activestate.com/recipes/577242-calling-c-level-finalizers-without-__del__/
'''
import sys
import traceback
import weakref
class OwnerRef(weakref.ref):
"""A simple weakref.ref subclass, so attributes can be added."""
pass
def _run_finalizer(ref):
"""Internal weakref callback to run finalizers"""
del _finalize_refs[ref.owner]
for item, finalizer in ref.items:
try:
finalizer(item)
except Exception:
print>>sys.stderr, "Exception running {}:".format(finalizer)
traceback.print_exc()
_finalize_refs = {}
def track(owner, item, finalizer):
"""Register an object for finalization.
``owner`` is the the object which is responsible for ``item``.
``finalizer`` will be called with ``item`` as its only argument when
``owner`` is destroyed by the garbage collector.
"""
if id(owner) in _finalize_refs:
ref = _finalize_refs[id(owner)]
else:
ref = OwnerRef(owner, _run_finalizer)
ref.owner = id(owner)
ref.items = []
ref.items.append((item, finalizer))
_finalize_refs[id(owner)] = ref
def untrack(owner, item):
ref = _finalize_refs[id(owner)]
# search and remove the item from the ref
for i, (item_i, _) in enumerate(ref.items):
if item_i is item:
del ref.items[i]
# remove the ref if it is empty
if not ref.items:
del _finalize_refs[id(owner)]
class OwnerMixin(object):
def _finalizer_track(self, item):
if not hasattr(self, '_finalize'):
raise AttributeError("%s must define a _finalize method" % self)
track(self, item, type(self)._finalize)
def _finalizer_untrack(self, item):
untrack(self, item)

View file

@ -397,9 +397,7 @@ class Module(llvm.Ownable, llvm.Cacheable):
Use the static method `Module.new' instead. Use the static method `Module.new' instead.
""" """
llvm.Ownable.__init__(self, ptr) llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule)
_finalizer = _core.LLVMDisposeModule
def __str__(self): def __str__(self):
"""Text representation of a module. """Text representation of a module.
@ -1801,7 +1799,7 @@ def _make_value(ptr):
# Builder # Builder
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class Builder(llvm.Handle): class Builder(object):
@staticmethod @staticmethod
def new(basic_block): def new(basic_block):
@ -1811,9 +1809,10 @@ class Builder(llvm.Handle):
return b return b
def __init__(self, ptr): def __init__(self, ptr):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
_finalizer = _core.LLVMDisposeBuilder def __del__(self):
_core.LLVMDisposeBuilder(self.ptr)
def position_at_beginning(self, bblk): def position_at_beginning(self, bblk):
"""Position the builder at the beginning of the given block. """Position the builder at the beginning of the given block.
@ -2302,7 +2301,7 @@ class Builder(llvm.Handle):
# Memory buffer # Memory buffer
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class MemoryBuffer(llvm.Handle): class MemoryBuffer(object):
@staticmethod @staticmethod
def from_file(fname): def from_file(fname):
@ -2323,9 +2322,10 @@ class MemoryBuffer(llvm.Handle):
return (obj, "") return (obj, "")
def __init__(self, ptr): def __init__(self, ptr):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
_finalizer = _core.LLVMDisposeMemoryBuffer def __del__(self):
_core.LLVMDisposeMemoryBuffer(self.ptr)
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===

View file

@ -63,7 +63,7 @@ CM_LARGE = 5
# Generic value # Generic value
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class GenericValue(llvm.Handle): class GenericValue(object):
@staticmethod @staticmethod
def int(ty, intval): def int(ty, intval):
@ -106,9 +106,10 @@ class GenericValue(llvm.Handle):
return GenericValue(ptr) return GenericValue(ptr)
def __init__(self, ptr): def __init__(self, ptr):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
_finalizer = _core.LLVMDisposeGenericValue def __del__(self):
_core.LLVMDisposeGenericValue(self.ptr)
def as_int(self): def as_int(self):
return _core.LLVMGenericValueToInt(self.ptr, 0) return _core.LLVMGenericValueToInt(self.ptr, 0)
@ -134,7 +135,7 @@ def _unpack_generic_values(objlist):
# Engine builder # Engine builder
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class EngineBuilder(llvm.Handle): class EngineBuilder(object):
@staticmethod @staticmethod
def new(module): def new(module):
core.check_is_module(module) core.check_is_module(module)
@ -143,10 +144,11 @@ class EngineBuilder(llvm.Handle):
return EngineBuilder(obj, module) return EngineBuilder(obj, module)
def __init__(self, ptr, module): def __init__(self, ptr, module):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
self._module = module self._module = module
_finalizer = _core.LLVMDisposeEngineBuilder def __del__(self):
_core.LLVMDisposeEngineBuilder(self.ptr)
def force_jit(self): def force_jit(self):
_core.LLVMEngineBuilderForceJIT(self.ptr) _core.LLVMEngineBuilderForceJIT(self.ptr)
@ -199,7 +201,7 @@ class EngineBuilder(llvm.Handle):
# Execution engine # Execution engine
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class ExecutionEngine(llvm.Handle): class ExecutionEngine(object):
@staticmethod @staticmethod
def new(module, force_interpreter=False): def new(module, force_interpreter=False):
@ -211,10 +213,11 @@ class ExecutionEngine(llvm.Handle):
return ExecutionEngine(ret, module) return ExecutionEngine(ret, module)
def __init__(self, ptr, module): def __init__(self, ptr, module):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
module._own(self) module._own(self)
_finalizer = _core.LLVMDisposeExecutionEngine def __del__(self):
_core.LLVMDisposeExecutionEngine(self.ptr)
def run_function(self, fn, args): def run_function(self, fn, args):
core.check_is_function(fn) core.check_is_function(fn)
@ -313,9 +316,7 @@ class TargetMachine(llvm.Ownable):
return TargetMachine(ptr) return TargetMachine(ptr)
def __init__(self, ptr): def __init__(self, ptr):
llvm.Ownable.__init__(self, ptr) llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeTargetMachine)
_finalizer = _core.LLVMDisposeTargetMachine
def emit_assembly(self, module): def emit_assembly(self, module):
'''returns byte string of the module as assembly code of the target machine '''returns byte string of the module as assembly code of the target machine

View file

@ -45,15 +45,16 @@ import warnings
# Pass manager builder # Pass manager builder
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class PassManagerBuilder(llvm.Handle): class PassManagerBuilder(object):
@staticmethod @staticmethod
def new(): def new():
return PassManagerBuilder(_core.LLVMPassManagerBuilderCreate()) return PassManagerBuilder(_core.LLVMPassManagerBuilderCreate())
def __init__(self, ptr): def __init__(self, ptr):
llvm.Handle.__init__(self, ptr) self.ptr = ptr
_finalizer = _core.LLVMPassManagerBuilderDispose def __del__(self):
_core.LLVMPassManagerBuilderDispose(self.ptr)
def populate(self, pm): def populate(self, pm):
if isinstance(pm, FunctionPassManager): if isinstance(pm, FunctionPassManager):
@ -141,7 +142,7 @@ class PassManagerBuilder(llvm.Handle):
# Pass manager # Pass manager
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class PassManager(llvm.Handle): class PassManager(object):
@staticmethod @staticmethod
def new(): def new():
@ -150,7 +151,8 @@ class PassManager(llvm.Handle):
def __init__(self, ptr): def __init__(self, ptr):
self.ptr = ptr self.ptr = ptr
_finalizer = _core.LLVMDisposePassManager def __del__(self):
_core.LLVMDisposePassManager(self.ptr)
def add(self, pass_obj): def add(self, pass_obj):
'''Add a pass to the pass manager. '''Add a pass to the pass manager.
@ -206,11 +208,9 @@ class Pass(llvm.Ownable):
'''Pass Inferface '''Pass Inferface
''' '''
def __init__(self, ptr): def __init__(self, ptr):
llvm.Ownable.__init__(self, ptr) llvm.Ownable.__init__(self, ptr, _core.LLVMDisposePass)
self.__name = '' self.__name = ''
_finalizer = _core.LLVMDisposePass
@staticmethod @staticmethod
def new(name): def new(name):
'''Create a new pass by name. '''Create a new pass by name.

View file

@ -131,7 +131,7 @@ setup(
maintainer = 'Continuum Analytics, Inc.', maintainer = 'Continuum Analytics, Inc.',
maintainer_email = 'llvmpy@continuum.io', maintainer_email = 'llvmpy@continuum.io',
url = 'http://www.llvmpy.org/', url = 'http://www.llvmpy.org/',
packages = ['llvm', 'llvm_cbuilder', 'llpython', 'llvm._utils'], packages = ['llvm', 'llvm_cbuilder', 'llpython'],
py_modules = ['llvm.core'], py_modules = ['llvm.core'],
license = "BSD", license = "BSD",
classifiers = [ classifiers = [