[pypy-commit] pypy ffi-backend: Tweak tweak tweaks to add the correct immutable hints.
arigo
noreply at buildbot.pypy.org
Sat Jul 28 15:55:23 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r56491:1300a891621d
Date: 2012-07-28 15:54 +0200
http://bitbucket.org/pypy/pypy/changeset/1300a891621d/
Log: Tweak tweak tweaks to add the correct immutable hints.
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -6,6 +6,7 @@
class LLBuffer(RWBuffer):
+ _immutable_ = True
def __init__(self, raw_cdata, size):
self.raw_cdata = raw_cdata
diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -10,6 +10,7 @@
from pypy.module._cffi_backend.cdataobj import W_CData, W_CDataApplevelOwning
from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
from pypy.module._cffi_backend import cerrno, misc
@@ -32,7 +33,7 @@
self.w_callable = w_callable
self.w_error = w_error
#
- fresult = self.ctype.ctitem
+ fresult = self.getfunctype().ctitem
size = fresult.size
if size > 0:
if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG:
@@ -45,7 +46,7 @@
self.unique_id = compute_unique_id(self)
global_callback_mapping.set(self.unique_id, self)
#
- cif_descr = ctype.cif_descr
+ cif_descr = self.getfunctype().cif_descr
if not cif_descr:
raise OperationError(space.w_NotImplementedError,
space.wrap("callbacks with '...'"))
@@ -69,9 +70,17 @@
space = self.space
return 'calling ' + space.str_w(space.repr(self.w_callable))
+ def getfunctype(self):
+ ctype = self.ctype
+ if not isinstance(ctype, W_CTypeFunc):
+ space = self.space
+ raise OperationError(space.w_TypeError,
+ space.wrap("expected a function ctype"))
+ return ctype
+
def invoke(self, ll_args, ll_res):
space = self.space
- ctype = self.ctype
+ ctype = self.getfunctype()
args_w = []
for i, farg in enumerate(ctype.fargs):
ll_arg = rffi.cast(rffi.CCHARP, ll_args[i])
@@ -87,7 +96,7 @@
operr.write_unraisable(space, "in cffi callback", self.w_callable)
def write_error_return_value(self, ll_res):
- fresult = self.ctype.ctitem
+ fresult = self.getfunctype().ctitem
if fresult.size > 0:
# push push push at the llmemory interface (with hacks that
# are all removed after translation)
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -18,6 +18,7 @@
class W_CTypeArray(W_CTypePtrOrArray):
+ _immutable_ = True
def __init__(self, space, ctptr, length, arraysize, extra):
W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
@@ -151,6 +152,7 @@
class W_CDataIter(Wrappable):
+ _immutable_fields_ = ['ctitem', 'cdata', '_stop'] # but not '_next'
def __init__(self, space, ctitem, cdata):
self.space = space
diff --git a/pypy/module/_cffi_backend/ctypeenum.py b/pypy/module/_cffi_backend/ctypeenum.py
--- a/pypy/module/_cffi_backend/ctypeenum.py
+++ b/pypy/module/_cffi_backend/ctypeenum.py
@@ -12,6 +12,7 @@
class W_CTypeEnum(W_CTypePrimitiveSigned):
+ _immutable_ = True
def __init__(self, space, name, enumerators, enumvalues):
from pypy.module._cffi_backend.newtype import alignment
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -12,15 +12,19 @@
from pypy.module._cffi_backend.ctypeobj import W_CType
from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase
from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct
from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
-from pypy.module._cffi_backend import ctypeprim, ctypestruct, ctypearray
-from pypy.module._cffi_backend import cdataobj, cerrno
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveCharOrUniChar
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveFloat
+from pypy.module._cffi_backend import ctypearray, cdataobj, cerrno
class W_CTypeFunc(W_CTypePtrBase):
+ _immutable_ = True
def __init__(self, space, fargs, fresult, ellipsis):
- self.cif_descr = lltype.nullptr(CIF_DESCRIPTION)
extra = self._compute_extra_text(fargs, fresult, ellipsis)
size = rffi.sizeof(rffi.VOIDP)
W_CTypePtrBase.__init__(self, space, size, extra, 2, fresult,
@@ -110,7 +114,7 @@
argtype = self.fargs[i]
#
# special-case for strings. xxx should avoid copying
- if argtype.is_char_ptr_or_array:
+ if argtype.is_char_ptr_or_array():
try:
s = space.str_w(w_obj)
except OperationError, e:
@@ -127,7 +131,7 @@
# set the "must free" flag to 0
set_mustfree_flag(data, 0)
#
- if argtype.is_unichar_ptr_or_array:
+ if argtype.is_unichar_ptr_or_array():
try:
space.unicode_w(w_obj)
except OperationError, e:
@@ -170,7 +174,7 @@
finally:
for i in range(mustfree_max_plus_1):
argtype = self.fargs[i]
- if argtype.is_char_ptr_or_array:
+ if argtype.is_char_ptr_or_array():
data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
if get_mustfree_flag(data):
raw_string = rffi.cast(rffi.CCHARPP, data)[0]
@@ -227,15 +231,64 @@
('exchange_args', rffi.CArray(lltype.Signed)))
CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
+W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION) # default value
-# We attach (lazily or not) to the classes or instances a 'ffi_type' attribute
-W_CType.ffi_type = lltype.nullptr(FFI_TYPE_P.TO)
-W_CTypePtrBase.ffi_type = clibffi.ffi_type_pointer
-W_CTypeVoid.ffi_type = clibffi.ffi_type_void
-def _settype(ctype, ffi_type):
- ctype.ffi_type = ffi_type
- return ffi_type
+# ----------
+# We attach to the classes small methods that return a 'ffi_type'
+def _missing_ffi_type(self, cifbuilder):
+ space = self.space
+ if self.size < 0:
+ raise operationerrfmt(space.w_TypeError,
+ "ctype '%s' has incomplete type",
+ self.name)
+ raise operationerrfmt(space.w_NotImplementedError,
+ "ctype '%s' (size %d) not supported as argument"
+ " or return value",
+ self.name, self.size)
+
+def _struct_ffi_type(self, cifbuilder):
+ if self.size >= 0:
+ return cifbuilder.fb_struct_ffi_type(self)
+ return _missing_ffi_type(self, cifbuilder)
+
+def _primsigned_ffi_type(self, cifbuilder):
+ size = self.size
+ if size == 1: return clibffi.ffi_type_sint8
+ elif size == 2: return clibffi.ffi_type_sint16
+ elif size == 4: return clibffi.ffi_type_sint32
+ elif size == 8: return clibffi.ffi_type_sint64
+ return _missing_ffi_type(self, cifbuilder)
+
+def _primunsigned_ffi_type(self, cifbuilder):
+ size = self.size
+ if size == 1: return clibffi.ffi_type_uint8
+ elif size == 2: return clibffi.ffi_type_uint16
+ elif size == 4: return clibffi.ffi_type_uint32
+ elif size == 8: return clibffi.ffi_type_uint64
+ return _missing_ffi_type(self, cifbuilder)
+
+def _primfloat_ffi_type(self, cifbuilder):
+ size = self.size
+ if size == 4: return clibffi.ffi_type_float
+ elif size == 8: return clibffi.ffi_type_double
+ return _missing_ffi_type(self, cifbuilder)
+
+def _ptr_ffi_type(self, cifbuilder):
+ return clibffi.ffi_type_pointer
+
+def _void_ffi_type(self, cifbuilder):
+ return clibffi.ffi_type_void
+
+W_CType._get_ffi_type = _missing_ffi_type
+W_CTypeStruct._get_ffi_type = _struct_ffi_type
+W_CTypePrimitiveSigned._get_ffi_type = _primsigned_ffi_type
+W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type
+W_CTypePrimitiveUnsigned._get_ffi_type = _primunsigned_ffi_type
+W_CTypePrimitiveFloat._get_ffi_type = _primfloat_ffi_type
+W_CTypePtrBase._get_ffi_type = _ptr_ffi_type
+W_CTypeVoid._get_ffi_type = _void_ffi_type
+# ----------
class CifDescrBuilder(object):
@@ -257,84 +310,53 @@
def fb_fill_type(self, ctype):
- if ctype.ffi_type: # common case: the ffi_type was already computed
- return ctype.ffi_type
+ return ctype._get_ffi_type(self)
+ def fb_struct_ffi_type(self, ctype):
+ # We can't pass a struct that was completed by verify().
+ # Issue: assume verify() is given "struct { long b; ...; }".
+ # Then it will complete it in the same way whether it is actually
+ # "struct { long a, b; }" or "struct { double a; long b; }".
+ # But on 64-bit UNIX, these two structs are passed by value
+ # differently: e.g. on x86-64, "b" ends up in register "rsi" in
+ # the first case and "rdi" in the second case.
space = self.space
- size = ctype.size
- if size < 0:
- raise operationerrfmt(space.w_TypeError,
- "ctype '%s' has incomplete type",
- ctype.name)
+ if ctype.custom_field_pos:
+ raise OperationError(space.w_TypeError,
+ space.wrap(
+ "cannot pass as an argument a struct that was completed "
+ "with verify() (see pypy/module/_cffi_backend/ctypefunc.py "
+ "for details)"))
- if isinstance(ctype, ctypestruct.W_CTypeStruct):
+ # allocate an array of (n + 1) ffi_types
+ n = len(ctype.fields_list)
+ elements = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * (n + 1))
+ elements = rffi.cast(FFI_TYPE_PP, elements)
- # We can't pass a struct that was completed by verify().
- # Issue: assume verify() is given "struct { long b; ...; }".
- # Then it will complete it in the same way whether it is actually
- # "struct { long a, b; }" or "struct { double a; long b; }".
- # But on 64-bit UNIX, these two structs are passed by value
- # differently: e.g. on x86-64, "b" ends up in register "rsi" in
- # the first case and "rdi" in the second case.
- if ctype.custom_field_pos:
- raise OperationError(space.w_TypeError,
- space.wrap(
- "cannot pass as an argument a struct that was completed "
- "with verify() (see pypy/module/_cffi_backend/ctypefunc.py "
- "for details)"))
+ # fill it with the ffi types of the fields
+ for i, cf in enumerate(ctype.fields_list):
+ if cf.is_bitfield():
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("cannot pass as argument a struct "
+ "with bit fields"))
+ ffi_subtype = self.fb_fill_type(cf.ctype)
+ if elements:
+ elements[i] = ffi_subtype
- # allocate an array of (n + 1) ffi_types
- n = len(ctype.fields_list)
- elements = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * (n + 1))
- elements = rffi.cast(FFI_TYPE_PP, elements)
+ # zero-terminate the array
+ if elements:
+ elements[n] = lltype.nullptr(FFI_TYPE_P.TO)
- # fill it with the ffi types of the fields
- for i, cf in enumerate(ctype.fields_list):
- if cf.is_bitfield():
- raise OperationError(space.w_NotImplementedError,
- space.wrap("cannot pass as argument a struct "
- "with bit fields"))
- ffi_subtype = self.fb_fill_type(cf.ctype)
- if elements:
- elements[i] = ffi_subtype
+ # allocate and fill an ffi_type for the struct itself
+ ffistruct = self.fb_alloc(rffi.sizeof(FFI_TYPE))
+ ffistruct = rffi.cast(FFI_TYPE_P, ffistruct)
+ if ffistruct:
+ rffi.setintfield(ffistruct, 'c_size', ctype.size)
+ rffi.setintfield(ffistruct, 'c_alignment', ctype.alignof())
+ rffi.setintfield(ffistruct, 'c_type', clibffi.FFI_TYPE_STRUCT)
+ ffistruct.c_elements = elements
- # zero-terminate the array
- if elements:
- elements[n] = lltype.nullptr(FFI_TYPE_P.TO)
-
- # allocate and fill an ffi_type for the struct itself
- ffistruct = self.fb_alloc(rffi.sizeof(FFI_TYPE))
- ffistruct = rffi.cast(FFI_TYPE_P, ffistruct)
- if ffistruct:
- rffi.setintfield(ffistruct, 'c_size', size)
- rffi.setintfield(ffistruct, 'c_alignment', ctype.alignof())
- rffi.setintfield(ffistruct, 'c_type', clibffi.FFI_TYPE_STRUCT)
- ffistruct.c_elements = elements
-
- return ffistruct
-
- elif isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
- # compute lazily once the ffi_type
- if size == 1: return _settype(ctype, clibffi.ffi_type_sint8)
- elif size == 2: return _settype(ctype, clibffi.ffi_type_sint16)
- elif size == 4: return _settype(ctype, clibffi.ffi_type_sint32)
- elif size == 8: return _settype(ctype, clibffi.ffi_type_sint64)
-
- elif (isinstance(ctype, ctypeprim.W_CTypePrimitiveCharOrUniChar) or
- isinstance(ctype, ctypeprim.W_CTypePrimitiveUnsigned)):
- if size == 1: return _settype(ctype, clibffi.ffi_type_uint8)
- elif size == 2: return _settype(ctype, clibffi.ffi_type_uint16)
- elif size == 4: return _settype(ctype, clibffi.ffi_type_uint32)
- elif size == 8: return _settype(ctype, clibffi.ffi_type_uint64)
-
- elif isinstance(ctype, ctypeprim.W_CTypePrimitiveFloat):
- if size == 4: return _settype(ctype, clibffi.ffi_type_float)
- elif size == 8: return _settype(ctype, clibffi.ffi_type_double)
-
- raise operationerrfmt(space.w_NotImplementedError,
- "ctype '%s' (size %d) not supported as argument"
- " or return value",
- ctype.name, size)
+ return ffistruct
def fb_build(self):
@@ -375,7 +397,7 @@
# loop over args
for i, farg in enumerate(self.fargs):
- if farg.is_char_ptr_or_array:
+ if farg.is_char_ptr_or_array():
exchange_offset += 1 # for the "must free" flag
exchange_offset = self.align_arg(exchange_offset)
cif_descr.exchange_args[i] = exchange_offset
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -10,10 +10,10 @@
class W_CType(Wrappable):
- #_immutable_ = True XXX newtype.complete_struct_or_union()?
+ _attrs_ = ['space', 'size', 'name', 'name_position']
+ _immutable_fields_ = _attrs_
+
cast_anything = False
- is_char_ptr_or_array = False
- is_unichar_ptr_or_array = False
is_primitive_integer = False
def __init__(self, space, size, name, name_position):
@@ -34,6 +34,12 @@
else:
return 'NULL'
+ def is_char_ptr_or_array(self):
+ return False
+
+ def is_unichar_ptr_or_array(self):
+ return False
+
def newp(self, w_init):
space = self.space
raise operationerrfmt(space.w_TypeError,
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -12,6 +12,7 @@
class W_CTypePrimitive(W_CType):
+ _immutable_ = True
def __init__(self, space, size, name, name_position, align):
W_CType.__init__(self, space, size, name, name_position)
@@ -70,10 +71,12 @@
class W_CTypePrimitiveCharOrUniChar(W_CTypePrimitive):
+ _immutable_ = True
is_primitive_integer = True
class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
+ _immutable_ = True
cast_anything = True
def int(self, cdata):
@@ -105,6 +108,7 @@
class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar):
+ _immutable_ = True
def int(self, cdata):
unichardata = rffi.cast(rffi.CWCHARP, cdata)
@@ -138,6 +142,7 @@
class W_CTypePrimitiveSigned(W_CTypePrimitive):
+ _immutable_ = True
is_primitive_integer = True
def __init__(self, *args):
@@ -174,6 +179,7 @@
class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
+ _immutable_ = True
is_primitive_integer = True
def __init__(self, *args):
@@ -202,6 +208,7 @@
class W_CTypePrimitiveFloat(W_CTypePrimitive):
+ _immutable_ = True
def cast(self, w_ob):
space = self.space
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -11,11 +11,10 @@
class W_CTypePtrOrArray(W_CType):
+ _immutable_ = True
def __init__(self, space, size, extra, extra_position, ctitem,
could_cast_anything=True):
- from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveChar
- from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUniChar
from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
name, name_position = ctitem.insert_name(extra, extra_position)
W_CType.__init__(self, space, size, name, name_position)
@@ -25,10 +24,20 @@
# - for functions, it is the return type
self.ctitem = ctitem
self.can_cast_anything = could_cast_anything and ctitem.cast_anything
- self.is_char_ptr_or_array = isinstance(ctitem, W_CTypePrimitiveChar)
- self.is_unichar_ptr_or_array=isinstance(ctitem,W_CTypePrimitiveUniChar)
self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
+ def is_char_ptr_or_array(self):
+ from pypy.module._cffi_backend import ctypeprim
+ return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
+
+ def is_unichar_ptr_or_array(self):
+ from pypy.module._cffi_backend import ctypeprim
+ return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
+
+ def is_char_or_unichar_ptr_or_array(self):
+ from pypy.module._cffi_backend import ctypeprim
+ return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveCharOrUniChar)
+
def cast(self, w_ob):
# cast to a pointer, to a funcptr, or to an array.
# Note that casting to an array is an extension to the C language,
@@ -49,6 +58,7 @@
class W_CTypePtrBase(W_CTypePtrOrArray):
# base class for both pointers and pointers-to-functions
+ _immutable_ = True
def convert_to_object(self, cdata):
ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
@@ -78,6 +88,7 @@
class W_CTypePointer(W_CTypePtrBase):
+ _immutable_ = True
def __init__(self, space, ctitem):
from pypy.module._cffi_backend import ctypearray
@@ -89,7 +100,7 @@
W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
def str(self, cdataobj):
- if self.is_char_ptr_or_array:
+ if self.is_char_ptr_or_array():
if not cdataobj._cdata:
space = self.space
raise operationerrfmt(space.w_RuntimeError,
@@ -101,7 +112,7 @@
return W_CTypePtrOrArray.str(self, cdataobj)
def unicode(self, cdataobj):
- if self.is_unichar_ptr_or_array:
+ if self.is_unichar_ptr_or_array():
if not cdataobj._cdata:
space = self.space
raise operationerrfmt(space.w_RuntimeError,
@@ -130,7 +141,7 @@
cdatastruct._cdata,
self, cdatastruct)
else:
- if self.is_char_ptr_or_array or self.is_unichar_ptr_or_array:
+ if self.is_char_or_unichar_ptr_or_array():
datasize *= 2 # forcefully add a null character
cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
#
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -14,6 +14,7 @@
class W_CTypeStructOrUnion(W_CType):
+ # not an _immutable_ class!
# fields added by complete_struct_or_union():
alignment = -1
fields_list = None
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
--- a/pypy/module/_cffi_backend/ctypevoid.py
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -6,6 +6,7 @@
class W_CTypeVoid(W_CType):
+ _immutable_ = True
cast_anything = True
def __init__(self, space):
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -3,7 +3,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module._cffi_backend import ctypeobj, cdataobj, ctypefunc
+from pypy.module._cffi_backend import ctypeobj, cdataobj
# ____________________________________________________________
@@ -20,7 +20,7 @@
# ____________________________________________________________
- at unwrap_spec(ctype=ctypefunc.W_CTypeFunc)
+ at unwrap_spec(ctype=ctypeobj.W_CType)
def callback(space, ctype, w_callable, w_error=None):
from pypy.module._cffi_backend.ccallback import W_CDataCallback
return W_CDataCallback(space, ctype, w_callable, w_error)
diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py
--- a/pypy/module/_cffi_backend/libraryobj.py
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -12,6 +12,7 @@
class W_Library(Wrappable):
+ _immutable_ = True
handle = rffi.cast(DLLHANDLE, 0)
def __init__(self, space, filename, is_global):
More information about the pypy-commit
mailing list