Cleanup and fixes

git-svn-id: http://llvm-py.googlecode.com/svn/trunk@68 8d1e9007-1d4e-0410-b67e-1979fd6579aa
This commit is contained in:
mdevan.foobar 2009-02-24 10:02:19 +00:00
commit 10843ec2ec
4 changed files with 103 additions and 58 deletions

View file

@ -32,7 +32,9 @@
"""
VERSION = '0.3'
VERSION = '0.6'
from weakref import WeakValueDictionary
#===----------------------------------------------------------------------===
@ -78,3 +80,70 @@ class Ownable(object):
if not self.owner:
self.del_fn(self.ptr)
#===----------------------------------------------------------------------===
# Dummy owner, will not delete ownee. Be careful.
#===----------------------------------------------------------------------===
class DummyOwner(object):
pass
#===----------------------------------------------------------------------===
# A metaclass to prevent aliasing. It stores a (weak) reference to objects
# constructed based on a PyCObject. If an object is constructed based on a
# PyCObject with the same underlying pointer as a previous object, a reference
# to the previous object is returned rather than a new one.
#===----------------------------------------------------------------------===
class _ObjectCache(type):
"""A metaclass to prevent aliasing.
Classes using 'ObjectCache' as a metaclass must have constructors
that take a PyCObject as their first argument. When the class is
called (to create a new instance of the class), the value of the
pointer wrapped by the PyCObj is checked:
If no previous object has been created based on the same
underlying pointer (note that different PyCObject objects can
wrap the same pointer), the object will be initialized as
usual and returned.
If a previous has been created based on the same pointer,
then a reference to that object will be returned, and no
object initialization is performed.
"""
__instances = WeakValueDictionary()
def __call__(cls, ptr, *args, **kwargs):
objid = _core.PyCObjectVoidPtrToPyLong(ptr)
obj = _ObjectCache.__instances.get(objid)
if obj is None:
obj = super(_ObjectCache, cls).__call__(ptr, *args, **kwargs)
_ObjectCache.__instances[objid] = obj
return obj
@staticmethod
def forget(obj):
objid = _core.PyCObjectVoidPtrToPyLong(obj.ptr)
if objid in _ObjectCache.__instances:
del _ObjectCache.__instances[objid]
#===----------------------------------------------------------------------===
# Cacheables
#===----------------------------------------------------------------------===
class Cacheable(object):
"""Objects that can be cached.
Objects that wrap a PyCObject are cached to avoid "aliasing", i.e.,
two Python objects each containing a PyCObject which internally points
to the same C pointer."""
__metaclass__ = _ObjectCache
def forget(self):
_ObjectCache.forget(self)

View file

@ -34,7 +34,6 @@ Used only in other modules, not for public use."""
import llvm
import llvm._core as _core # for PyCObjectVoidPtrToPyLong
from weakref import WeakValueDictionary
#===----------------------------------------------------------------------===
@ -42,10 +41,10 @@ from weakref import WeakValueDictionary
# failures.
#===----------------------------------------------------------------------===
def check_gen(obj, type):
if not isinstance(obj, type):
type_str = type.__name__
msg = "argument not an instance of llvm.core.%s" % type_str
def check_gen(obj, typ):
if not isinstance(obj, typ):
typ_str = typ.__name__
msg = "argument not an instance of llvm.core.%s" % typ_str
raise TypeError, msg
def check_is_unowned(ownable):
@ -70,51 +69,11 @@ def unpack_gen(objlist, check_fn):
# we now return a list.
#===----------------------------------------------------------------------===
def wrapiter(first, next, container, wrapper, extra=[]):
# ptr = first(container)
# while ptr:
# yield wrapper(ptr)
# ptr = next(ptr)
def wrapiter(first, next, container, wrapper):
ret = []
ptr = first(container)
while ptr:
ret.append(wrapper(ptr, *extra))
ret.append(wrapper(ptr))
ptr = next(ptr)
return ret
#===----------------------------------------------------------------------===
# A metaclass to prevent aliasing. It stores a (weak) reference to objects
# constructed based on a PyCObject. If an object is constructed based on a
# PyCObject with the same underlying pointer as a previous object, a reference
# to the previous object is returned rather than a new one.
#===----------------------------------------------------------------------===
class ObjectCache(type):
"""A metaclass to prevent aliasing.
Classes using 'ObjectCache' as a metaclass must have constructors
that take a PyCObject as their first argument. When the class is
called (to create a new instance of the class), the value of the
pointer wrapped by the PyCObj is checked:
If no previous object has been created based on the same
underlying pointer (note that different PyCObject objects can
wrap the same pointer), the object will be initialized as
usual and returned.
If a previous has been created based on the same pointer,
then a reference to that object will be returned, and no
object initialization is performed.
"""
__instances = WeakValueDictionary()
def __call__(cls, ptr, *args, **kwargs):
id = _core.PyCObjectVoidPtrToPyLong(ptr)
obj = ObjectCache.__instances.get(id)
if obj is None:
obj = super(ObjectCache, cls).__call__(ptr, *args, **kwargs)
ObjectCache.__instances[id] = obj
return obj

View file

@ -37,7 +37,6 @@ in-memory intermediate representation (IR) data structures."""
import llvm # top-level, for common stuff
import llvm._core as _core # C wrappers
import llvm._util as _util # utility functions
import weakref # global list of modules
#===----------------------------------------------------------------------===
@ -272,7 +271,7 @@ def _to_int(v):
# Module
#===----------------------------------------------------------------------===
class Module(llvm.Ownable):
class Module(llvm.Ownable, llvm.Cacheable):
"""A Module instance stores all the information related to an LLVM module.
Modules are the top level container of all other LLVM Intermediate
@ -287,8 +286,6 @@ class Module(llvm.Ownable):
module_obj = Module.new('my_module')
"""
__metaclass__ = _util.ObjectCache
@staticmethod
def new(id):
"""Create a new Module instance.
@ -392,12 +389,18 @@ class Module(llvm.Ownable):
global variables, function, etc. are matched and resolved.
The `other' module is no longer valid after this method is
invoked, and will behave in undefined ways.
invoked, all refs to it should be dropped.
In future, this API might be replaced with a full-fledged
Linker class.
"""
check_is_module(other)
other.forget() # remove it from object cache
ret = _core.LLVMLinkModules(self.ptr, other.ptr)
if isinstance(ret, str):
raise llvm.LLVMException, ret
# Do not try to destroy the other module's llvm::Module*.
other._own(llvm.DummyOwner())
def add_type_name(self, name, ty):
"""Map a string to a type.
@ -848,9 +851,7 @@ class TypeHandle(object):
# Values
#===----------------------------------------------------------------------===
class Value(object):
__metaclass__ = _util.ObjectCache
class Value(llvm.Cacheable):
def __init__(self, ptr):
self.ptr = ptr
@ -1233,6 +1234,7 @@ class GlobalVariable(GlobalValue):
def delete(self):
self._delete()
_core.LLVMDeleteGlobal(self.ptr)
self.forget()
self.ptr = None
def _get_initializer(self):
@ -1310,6 +1312,7 @@ class Function(GlobalValue):
def delete(self):
self._delete()
_core.LLVMDeleteFunction(self.ptr)
self.forget()
self.ptr = None
@property
@ -1498,6 +1501,7 @@ class BasicBlock(Value):
def delete(self):
_core.LLVMDeleteBasicBlock(self.ptr)
self.forget()
self.ptr = None
@property

View file

@ -8,6 +8,12 @@ def check(a, b):
else:
print "FAIL"
def check_isnot(a, b):
if not (a is b):
print "OK"
else:
print "FAIL"
print "Testing module aliasing ..",
m1 = Module.new('a')
t = Type.int()
@ -19,11 +25,18 @@ check(m1, m2)
print "Testing global vairable aliasing 1 .. ",
gv1 = GlobalVariable.new(m1, t, "gv")
gv2 = GlobalVariable.get(m1, "gv")
check(gv2, gv2)
check(gv1, gv2)
print "Testing global vairable aliasing 2 .. ",
gv3 = m1.global_variables[0]
check(gv3, gv1)
check(gv1, gv3)
print "Testing global vairable aliasing 3 .. ",
gv2 = None
gv3 = None
gv1.delete()
gv4 = GlobalVariable.new(m1, t, "gv")
check_isnot(gv1, gv4)
print "Testing function aliasing 1 ..",
b1 = f1.append_basic_block('entry')