[pypy-svn] r74236 - in pypy/trunk/pypy: . _interfaces annotation annotation/test config doc/config interpreter interpreter/test lib module/cpyext module/cpyext/include module/cpyext/src module/cpyext/test module/imp objspace/std objspace/std/test rlib rlib/test rpython rpython/lltypesystem rpython/lltypesystem/test tool translator translator/c translator/c/gcc translator/c/gcc/test translator/c/src translator/c/test translator/goal translator/platform translator/test translator/tool translator/tool/test
fijal at codespeak.net
fijal at codespeak.net
Thu Apr 29 20:37:20 CEST 2010
Author: fijal
Date: Thu Apr 29 20:37:15 2010
New Revision: 74236
Added:
pypy/trunk/pypy/_interfaces/ (props changed)
- copied from r74235, pypy/branch/cpython-extension/pypy/_interfaces/
pypy/trunk/pypy/doc/config/objspace.usemodules.cpyext.txt
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/doc/config/objspace.usemodules.cpyext.txt
pypy/trunk/pypy/doc/config/translation.shared.txt
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/doc/config/translation.shared.txt
pypy/trunk/pypy/module/cpyext/ (props changed)
- copied from r74235, pypy/branch/cpython-extension/pypy/module/cpyext/
pypy/trunk/pypy/rlib/_rweakkeydict.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/_rweakkeydict.py
pypy/trunk/pypy/rlib/_rweakvaldict.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/_rweakvaldict.py
pypy/trunk/pypy/rlib/entrypoint.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/entrypoint.py
pypy/trunk/pypy/rlib/exports.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/exports.py
pypy/trunk/pypy/rlib/test/test_rweakkeydict.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/test/test_rweakkeydict.py
pypy/trunk/pypy/rlib/test/test_rweakvaldict.py
- copied unchanged from r74235, pypy/branch/cpython-extension/pypy/rlib/test/test_rweakvaldict.py
Removed:
pypy/trunk/pypy/rlib/rweakrefimpl.py
pypy/trunk/pypy/rlib/test/test_rweakref.py
Modified:
pypy/trunk/pypy/annotation/annrpython.py
pypy/trunk/pypy/annotation/description.py
pypy/trunk/pypy/annotation/test/test_annrpython.py
pypy/trunk/pypy/config/pypyoption.py
pypy/trunk/pypy/config/translationoption.py
pypy/trunk/pypy/conftest.py
pypy/trunk/pypy/interpreter/argument.py
pypy/trunk/pypy/interpreter/test/test_argument.py
pypy/trunk/pypy/interpreter/test/test_typedef.py
pypy/trunk/pypy/interpreter/typedef.py
pypy/trunk/pypy/lib/identity_dict.py
pypy/trunk/pypy/module/cpyext/include/ (props changed)
pypy/trunk/pypy/module/cpyext/src/ (props changed)
pypy/trunk/pypy/module/cpyext/test/ (props changed)
pypy/trunk/pypy/module/imp/importing.py
pypy/trunk/pypy/objspace/std/fake.py
pypy/trunk/pypy/objspace/std/objspace.py
pypy/trunk/pypy/objspace/std/test/test_setobject.py
pypy/trunk/pypy/objspace/std/typeobject.py
pypy/trunk/pypy/rlib/rarithmetic.py
pypy/trunk/pypy/rlib/rstring.py
pypy/trunk/pypy/rlib/rweakref.py
pypy/trunk/pypy/rlib/test/test_rarithmetic.py
pypy/trunk/pypy/rlib/test/test_rstring.py
pypy/trunk/pypy/rpython/annlowlevel.py
pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py
pypy/trunk/pypy/rpython/lltypesystem/lltype.py
pypy/trunk/pypy/rpython/lltypesystem/rdict.py
pypy/trunk/pypy/rpython/lltypesystem/rffi.py
pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
pypy/trunk/pypy/tool/fixeol
pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py
pypy/trunk/pypy/translator/c/gcc/trackgcroot.py
pypy/trunk/pypy/translator/c/genc.py
pypy/trunk/pypy/translator/c/node.py
pypy/trunk/pypy/translator/c/src/commondefs.h
pypy/trunk/pypy/translator/c/src/main.h
pypy/trunk/pypy/translator/c/src/obmalloc.c
pypy/trunk/pypy/translator/c/test/test_genc.py
pypy/trunk/pypy/translator/c/test/test_newgc.py
pypy/trunk/pypy/translator/c/test/test_standalone.py
pypy/trunk/pypy/translator/driver.py
pypy/trunk/pypy/translator/goal/ann_override.py
pypy/trunk/pypy/translator/platform/__init__.py
pypy/trunk/pypy/translator/platform/darwin.py
pypy/trunk/pypy/translator/platform/linux.py
pypy/trunk/pypy/translator/platform/posix.py
pypy/trunk/pypy/translator/platform/windows.py
pypy/trunk/pypy/translator/test/test_unsimplify.py
pypy/trunk/pypy/translator/tool/cbuild.py
pypy/trunk/pypy/translator/tool/test/test_cbuild.py
pypy/trunk/pypy/translator/unsimplify.py
Log:
(xoraxax, afa, agaynor, arigo, benjamin, exarkun, fijal, jandem, lucian,
trundle, zooko)
Merge the cpyext branch - this branch adds an ability to load cpython
extension modules written in C (.so). Work in progress, has known bugs.
Right now the module is disabled since it adds an attribute on W_Root
(_pyolifeline) which is not a desired behavior.
Modified: pypy/trunk/pypy/annotation/annrpython.py
==============================================================================
--- pypy/trunk/pypy/annotation/annrpython.py (original)
+++ pypy/trunk/pypy/annotation/annrpython.py Thu Apr 29 20:37:15 2010
@@ -87,12 +87,12 @@
"""Recursively build annotations about the specific entry point."""
assert isinstance(function, types.FunctionType), "fix that!"
+ from pypy.annotation.policy import AnnotatorPolicy
+ policy = AnnotatorPolicy()
# make input arguments and set their type
- inputcells = [self.typeannotation(t) for t in input_arg_types]
+ args_s = [self.typeannotation(t) for t in input_arg_types]
- desc = self.bookkeeper.getdesc(function)
- desc.getcallfamily() # record this implicit call (hint for back-ends)
- flowgraph = desc.specialize(inputcells)
+ flowgraph, inputcells = self.get_call_parameters(function, args_s, policy)
if not isinstance(flowgraph, FunctionGraph):
assert isinstance(flowgraph, annmodel.SomeObject)
return flowgraph
Modified: pypy/trunk/pypy/annotation/description.py
==============================================================================
--- pypy/trunk/pypy/annotation/description.py (original)
+++ pypy/trunk/pypy/annotation/description.py Thu Apr 29 20:37:15 2010
@@ -209,8 +209,9 @@
if len(self._cache) != 1:
raise NoStandardGraph(self)
[graph] = self._cache.values()
+ relax_sig_check = getattr(self.pyobj, "relax_sig_check", False)
if (graph.signature != self.signature or
- graph.defaults != self.defaults):
+ graph.defaults != self.defaults) and not relax_sig_check:
raise NoStandardGraph(self)
return graph
Modified: pypy/trunk/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/trunk/pypy/annotation/test/test_annrpython.py (original)
+++ pypy/trunk/pypy/annotation/test/test_annrpython.py Thu Apr 29 20:37:15 2010
@@ -3185,6 +3185,13 @@
assert isinstance(s, annmodel.SomeList)
assert s.listdef.listitem.resized
+ def test_varargs(self):
+ def f(*args):
+ return args[0] + 42
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int, int])
+ assert isinstance(s, annmodel.SomeInteger)
+
def test_listitem_no_mutating(self):
from pypy.rlib.debug import check_annotation
called = []
@@ -3304,6 +3311,15 @@
s = a.build_types(f, [int])
assert s.knowntype is int
+ def test_relax(self):
+ def f(*args):
+ return args[0] + args[1]
+ f.relax_sig_check = True
+ def g(x):
+ return f(x, x - x)
+ a = self.RPythonAnnotator()
+ s = a.build_types(g, [int])
+ assert a.bookkeeper.getdesc(f).getuniquegraph()
def g(n):
return [0,1,2,n]
Modified: pypy/trunk/pypy/config/pypyoption.py
==============================================================================
--- pypy/trunk/pypy/config/pypyoption.py (original)
+++ pypy/trunk/pypy/config/pypyoption.py Thu Apr 29 20:37:15 2010
@@ -29,7 +29,8 @@
"rctime" , "select", "zipimport", "_lsprof",
"crypt", "signal", "_rawffi", "termios", "zlib",
"struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO",
- "thread", "itertools", "pyexpat", "_ssl"]
+ "thread", "itertools", "pyexpat", "_ssl"] # "cpyext"] commented out until
+ # it stops adding _pyolifeline on W_Root
))
working_oo_modules = default_modules.copy()
@@ -62,11 +63,14 @@
module_dependencies = {}
-module_suggests = { # the reason you want _rawffi is for ctypes, which
- # itself needs the interp-level struct module
- # because 'P' is missing from the app-level one
- '_rawffi': [("objspace.usemodules.struct", True)],
- }
+module_suggests = {
+ # the reason you want _rawffi is for ctypes, which
+ # itself needs the interp-level struct module
+ # because 'P' is missing from the app-level one
+ "_rawffi": [("objspace.usemodules.struct", True)],
+ "cpyext": [("translation.secondaryentrypoints", "cpyext"),
+ ("translation.shared", sys.platform == "win32")],
+ }
module_import_dependencies = {
# no _rawffi if importing pypy.rlib.libffi raises ImportError
Modified: pypy/trunk/pypy/config/translationoption.py
==============================================================================
--- pypy/trunk/pypy/config/translationoption.py (original)
+++ pypy/trunk/pypy/config/translationoption.py Thu Apr 29 20:37:15 2010
@@ -42,6 +42,9 @@
},
cmdline="-b --backend"),
+ BoolOption("shared", "Build as a shared library",
+ default=False, cmdline="--shared"),
+
BoolOption("log", "Include debug prints in the translation (PYPYLOG=...)",
default=True, cmdline="--log"),
@@ -138,6 +141,9 @@
ArbitraryOption("instrumentctl", "internal",
default=None),
StrOption("output", "Output file name", cmdline="--output"),
+ StrOption("secondaryentrypoints",
+ "Comma separated list of keys choosing secondary entrypoints",
+ cmdline="--entrypoints", default=""),
BoolOption("dump_static_data_info", "Dump static data info",
cmdline="--dump_static_data_info",
Modified: pypy/trunk/pypy/conftest.py
==============================================================================
--- pypy/trunk/pypy/conftest.py (original)
+++ pypy/trunk/pypy/conftest.py Thu Apr 29 20:37:15 2010
@@ -59,7 +59,7 @@
try:
return _SPACECACHE[key]
except KeyError:
- if option.runappdirect:
+ if getattr(option, 'runappdirect', None):
if name not in (None, 'std'):
myname = getattr(sys, 'pypy_objspaceclass', '')
if not myname.lower().startswith(name):
Modified: pypy/trunk/pypy/interpreter/argument.py
==============================================================================
--- pypy/trunk/pypy/interpreter/argument.py (original)
+++ pypy/trunk/pypy/interpreter/argument.py Thu Apr 29 20:37:15 2010
@@ -128,19 +128,6 @@
kwds_w[self.keywords[i]] = self.keywords_w[i]
return self.arguments_w, kwds_w
- def unpack_cpy(self, starting_at=0):
- assert starting_at >= 0
- space = self.space
- args_w = self.arguments_w
- w_kw = space.newdict()
- if self.keywords:
- for i in range(len(self.keywords)):
- space.setitem(w_kw, space.wrap(self.keywords[i]), self.keywords_w[i])
- if starting_at != 0:
- args_w = args_w[starting_at:]
- args_tuple = space.newtuple([space.wrap(args_w), w_kw])
- return args_tuple
-
def replace_arguments(self, args_w):
"Return a new Arguments with a args_w as positional arguments."
return Arguments(self.space, args_w, self.keywords, self.keywords_w)
Modified: pypy/trunk/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_argument.py (original)
+++ pypy/trunk/pypy/interpreter/test/test_argument.py Thu Apr 29 20:37:15 2010
@@ -135,12 +135,6 @@
assert args1.keywords is args.keywords
assert args1.keywords_w is args.keywords_w
- def test_unpack_cpy(self):
- space = DummySpace()
- args = Arguments(space, ["0"])
- assert space.eq_w(args.unpack_cpy(), space.newtuple([space.newlist([space.wrap("0")]), space.newdict()]))
- assert space.eq_w(args.unpack_cpy(1), space.newtuple([space.newlist(), space.newdict()]))
-
def test_fixedunpacked(self):
space = DummySpace()
Modified: pypy/trunk/pypy/interpreter/test/test_typedef.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_typedef.py (original)
+++ pypy/trunk/pypy/interpreter/test/test_typedef.py Thu Apr 29 20:37:15 2010
@@ -1,5 +1,6 @@
from pypy.interpreter import typedef
from pypy.tool.udir import udir
+from pypy.interpreter.baseobjspace import Wrappable
# this test isn't so much to test that the objspace interface *works*
# -- it's more to test that it's *there*
@@ -132,6 +133,17 @@
assert len(set) <= 6, "%s has %d subclasses:\n%r" % (
cls, len(set), [subcls.__name__ for subcls in set])
+ def test_getsetproperty(self):
+ class W_SomeType(Wrappable):
+ pass
+ def fget(self, space, w_self):
+ assert self is prop
+ W_SomeType.typedef = typedef.TypeDef(
+ 'some_type',
+ x=typedef.GetSetProperty(fget, use_closure=True))
+ w_obj = self.space.wrap(W_SomeType())
+ assert self.space.getattr(w_obj, self.space.wrap('x')) is None
+
class AppTestTypeDef:
Modified: pypy/trunk/pypy/interpreter/typedef.py
==============================================================================
--- pypy/trunk/pypy/interpreter/typedef.py (original)
+++ pypy/trunk/pypy/interpreter/typedef.py Thu Apr 29 20:37:15 2010
@@ -9,7 +9,7 @@
DescrMismatch
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.tool.sourcetools import compile2, func_with_new_name
-from pypy.rlib.objectmodel import instantiate, compute_identity_hash
+from pypy.rlib.objectmodel import instantiate, compute_identity_hash, specialize
from pypy.rlib.jit import hint
class TypeDef:
@@ -301,44 +301,63 @@
# ____________________________________________________________
-def make_descr_typecheck_wrapper(func, extraargs=(), cls=None):
+ at specialize.arg(0)
+def make_descr_typecheck_wrapper(tag, func, extraargs=(), cls=None,
+ use_closure=False):
if func is None:
return None
- if cls is None:
+ return _make_descr_typecheck_wrapper(tag, func, extraargs, cls, use_closure)
+
+ at specialize.memo()
+def _make_descr_typecheck_wrapper(tag, func, extraargs, cls, use_closure):
+ # - if cls is None, the wrapped object is passed to the function
+ # - if cls is a class, an unwrapped instance is passed
+ # - if cls is a string, XXX unused?
+ if cls is None and use_closure:
return func
if hasattr(func, 'im_func'):
assert func.im_class is cls
func = func.im_func
-
+
miniglobals = {
func.__name__: func,
'OperationError': OperationError
}
if isinstance(cls, str):
+ assert 0, "unused?"
#print "<CHECK", func.__module__ or '?', func.__name__
assert cls.startswith('<'),"pythontype typecheck should begin with <"
source = """
- def descr_typecheck_%(name)s(space, w_obj, %(extra)s):
+ def descr_typecheck_%(name)s(closure, space, w_obj, %(extra)s):
if not space.is_true(space.isinstance(w_obj, space.w_%(cls_name)s)):
# xxx improve msg
msg = "descriptor is for '%(expected)s'"
raise OperationError(space.w_TypeError, space.wrap(msg))
- return %(name)s(space, w_obj, %(extra)s)
+ return %(name)s(%(closure)s space, w_obj, %(extra)s)
"""
cls_name = cls[1:]
expected = repr(cls_name)
+ elif cls is None:
+ source = """
+ def descr_typecheck_%(name)s(closure, space, w_obj, %(extra)s):
+ return %(name)s(%(closure)s space, w_obj, %(extra)s)
+ """
else:
cls_name = cls.__name__
assert issubclass(cls, Wrappable)
source = """
- def descr_typecheck_%(name)s(space, w_obj, %(extra)s):
+ def descr_typecheck_%(name)s(closure, space, w_obj, %(extra)s):
obj = space.descr_self_interp_w(%(cls_name)s, w_obj)
- return %(name)s(space, obj, %(extra)s)
+ return %(name)s(%(closure)s space, obj, %(extra)s)
"""
miniglobals[cls_name] = cls
name = func.__name__
extra = ', '.join(extraargs)
+ if use_closure:
+ closure = "closure,"
+ else:
+ closure = ""
source = py.code.Source(source % locals())
exec source.compile() in miniglobals
return miniglobals['descr_typecheck_%s' % func.__name__]
@@ -348,16 +367,17 @@
raise OperationError(space.w_AttributeError,
space.wrap("generic property has no __objclass__"))
-def make_objclass_getter(func, cls, cache={}):
- if hasattr(func, 'im_func'):
+ at specialize.arg(0)
+def make_objclass_getter(tag, func, cls):
+ if func and hasattr(func, 'im_func'):
assert not cls or cls is func.im_class
cls = func.im_class
+ return _make_objclass_getter(cls)
+
+ at specialize.memo()
+def _make_objclass_getter(cls):
if not cls:
return unknown_objclass_getter, cls
- try:
- return cache[cls]
- except KeyError:
- pass
miniglobals = {}
if isinstance(cls, str):
assert cls.startswith('<'),"pythontype typecheck should begin with <"
@@ -372,16 +392,19 @@
\n""" % (typeexpr,)
exec compile2(source) in miniglobals
res = miniglobals['objclass_getter'], cls
- cache[cls] = res
return res
class GetSetProperty(Wrappable):
- def __init__(self, fget, fset=None, fdel=None, doc=None, cls=None):
- "NOT_RPYTHON: initialization-time only"
- objclass_getter, cls = make_objclass_getter(fget, cls)
- fget = make_descr_typecheck_wrapper(fget, cls=cls)
- fset = make_descr_typecheck_wrapper(fset, ('w_value',), cls=cls)
- fdel = make_descr_typecheck_wrapper(fdel, cls=cls)
+ @specialize.arg(7)
+ def __init__(self, fget, fset=None, fdel=None, doc=None,
+ cls=None, use_closure=False, tag=None):
+ objclass_getter, cls = make_objclass_getter(tag, fget, cls)
+ fget = make_descr_typecheck_wrapper((tag, 0), fget,
+ cls=cls, use_closure=use_closure)
+ fset = make_descr_typecheck_wrapper((tag, 1), fset, ('w_value',),
+ cls=cls, use_closure=use_closure)
+ fdel = make_descr_typecheck_wrapper((tag, 2), fdel,
+ cls=cls, use_closure=use_closure)
self.fget = fget
self.fset = fset
self.fdel = fdel
@@ -389,7 +412,8 @@
self.reqcls = cls
self.name = '<generic property>'
self.objclass_getter = objclass_getter
-
+ self.use_closure = use_closure
+
def descr_property_get(space, property, w_obj, w_cls=None):
"""property.__get__(obj[, type]) -> value
Read the value of the property of the given obj."""
@@ -400,7 +424,7 @@
return space.wrap(property)
else:
try:
- return property.fget(space, w_obj)
+ return property.fget(property, space, w_obj)
except DescrMismatch, e:
return w_obj.descr_call_mismatch(space, '__getattribute__',\
property.reqcls, Arguments(space, [w_obj,
@@ -414,7 +438,7 @@
raise OperationError(space.w_TypeError,
space.wrap("readonly attribute"))
try:
- fset(space, w_obj, w_value)
+ fset(property, space, w_obj, w_value)
except DescrMismatch, e:
w_obj.descr_call_mismatch(space, '__setattr__',\
property.reqcls, Arguments(space, [w_obj,
@@ -428,7 +452,7 @@
raise OperationError(space.w_AttributeError,
space.wrap("cannot delete attribute"))
try:
- fdel(space, w_obj)
+ fdel(property, space, w_obj)
except DescrMismatch, e:
w_obj.descr_call_mismatch(space, '__delattr__',\
property.reqcls, Arguments(space, [w_obj,
Modified: pypy/trunk/pypy/lib/identity_dict.py
==============================================================================
--- pypy/trunk/pypy/lib/identity_dict.py (original)
+++ pypy/trunk/pypy/lib/identity_dict.py Thu Apr 29 20:37:15 2010
@@ -30,6 +30,12 @@
def __contains__(self, arg):
return id(arg) in self._dict
+ def copy(self):
+ d = type(self)()
+ d.update(self.iteritems())
+ assert len(d) == len(self)
+ return d
+
class IdentityDictPyPy(object, DictMixin):
__slots__ = ["_dict"]
@@ -52,6 +58,11 @@
def __contains__(self, arg):
return arg in self._dict
+ def copy(self):
+ d = type(self)()
+ d.update(self.iteritems())
+ assert len(d) == len(self)
+ return d
if idict is None:
identity_dict = IdentityDictPurePython
Modified: pypy/trunk/pypy/module/imp/importing.py
==============================================================================
--- pypy/trunk/pypy/module/imp/importing.py (original)
+++ pypy/trunk/pypy/module/imp/importing.py Thu Apr 29 20:37:15 2010
@@ -25,6 +25,11 @@
# PY_CODERESOURCE = 8
IMP_HOOK = 9
+if sys.platform.startswith('win'):
+ so_extension = ".pyd"
+else:
+ so_extension = ".so"
+
def find_modtype(space, filepart):
"""Check which kind of module to import for the given filepart,
which is a path without extension. Returns PY_SOURCE, PY_COMPILED or
@@ -40,16 +45,18 @@
# look for a lone .pyc file.
# The "imp" module does not respect this, and is allowed to find
# lone .pyc files.
- if not space.config.objspace.lonepycfiles:
- return SEARCH_ERROR, None, None
-
# check the .pyc file
- if space.config.objspace.usepycfiles:
+ if space.config.objspace.usepycfiles and space.config.objspace.lonepycfiles:
pycfile = filepart + ".pyc"
if os.path.exists(pycfile) and case_ok(pycfile):
# existing .pyc file
return PY_COMPILED, ".pyc", "rb"
+ if space.config.objspace.usemodules.cpyext:
+ pydfile = filepart + so_extension
+ if os.path.exists(pydfile) and case_ok(pydfile):
+ return C_EXTENSION, so_extension, "rb"
+
return SEARCH_ERROR, None, None
if sys.platform in ['linux2', 'freebsd']:
@@ -332,6 +339,9 @@
except:
stream.close()
raise
+ if modtype == C_EXTENSION:
+ filename = filepart + suffix
+ return FindInfo(modtype, filename, None, suffix, filemode)
except StreamErrors:
pass
@@ -356,7 +366,7 @@
if find_info.modtype == C_BUILTIN:
return space.getbuiltinmodule(find_info.filename, force_init=True)
- if find_info.modtype in (PY_SOURCE, PY_COMPILED, PKG_DIRECTORY):
+ if find_info.modtype in (PY_SOURCE, PY_COMPILED, C_EXTENSION, PKG_DIRECTORY):
w_mod = None
if reuse:
try:
@@ -397,6 +407,12 @@
# fetch the module again, in case of "substitution"
w_mod = check_sys_modules(space, w_modulename)
return w_mod
+ elif find_info.modtype == C_EXTENSION and space.config.objspace.usemodules.cpyext:
+ # the next line is mandantory to init cpyext
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.api import load_extension_module
+ load_extension_module(space, find_info.filename, space.str_w(w_modulename))
+ return check_sys_modules(space, w_modulename)
except OperationError:
w_mods = space.sys.get('modules')
space.call_method(w_mods, 'pop', w_modulename, space.w_None)
Modified: pypy/trunk/pypy/objspace/std/fake.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/fake.py (original)
+++ pypy/trunk/pypy/objspace/std/fake.py Thu Apr 29 20:37:15 2010
@@ -114,6 +114,9 @@
cpy_type.__name__, base, **kw)
def __init__(w_self, space, val):
w_self.val = val
+ w_self.space = space
+ def getdict(w_self):
+ return w_self.space.wrap(w_self.val.__dict__)
def unwrap(w_self, space):
return w_self.val
W_Fake.__name__ = 'W_Fake%s'%(cpy_type.__name__.capitalize())
Modified: pypy/trunk/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/objspace.py (original)
+++ pypy/trunk/pypy/objspace/std/objspace.py Thu Apr 29 20:37:15 2010
@@ -7,7 +7,7 @@
from pypy.objspace.std import (builtinshortcut, stdtypedef, frame, model,
transparent, callmethod, proxyobject)
from pypy.objspace.descroperation import DescrOperation, raiseattrerror
-from pypy.rlib.objectmodel import instantiate
+from pypy.rlib.objectmodel import instantiate, r_dict
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib.rarithmetic import base_int
from pypy.rlib.objectmodel import we_are_translated
@@ -206,8 +206,11 @@
return W_ComplexObject(x.real, x.imag)
if isinstance(x, set):
- wrappeditems = [self.wrap(item) for item in x]
- return W_SetObject(self, wrappeditems)
+ rdict_w = r_dict(self.eq_w, self.hash_w)
+ for item in x:
+ rdict_w[self.wrap(item)] = None
+ res = W_SetObject(self, rdict_w)
+ return res
if isinstance(x, frozenset):
wrappeditems = [self.wrap(item) for item in x]
Modified: pypy/trunk/pypy/objspace/std/test/test_setobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_setobject.py (original)
+++ pypy/trunk/pypy/objspace/std/test/test_setobject.py Thu Apr 29 20:37:15 2010
@@ -46,6 +46,8 @@
t = W_SetObject(self.space, None)
_initialize_set(self.space, t, self.word)
assert self.space.eq_w(s,t)
+ u = self.space.wrap(set('simsalabim'))
+ assert self.space.eq_w(s,u)
class AppTestAppSetTest:
def test_subtype(self):
Modified: pypy/trunk/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typeobject.py (original)
+++ pypy/trunk/pypy/objspace/std/typeobject.py Thu Apr 29 20:37:15 2010
@@ -14,6 +14,7 @@
from pypy.rlib.rarithmetic import intmask, r_uint
from copy_reg import _HEAPTYPE
+_CPYTYPE = 1 # used for non-heap types defined in C
# from compiler/misc.py
@@ -96,7 +97,7 @@
w_self.needsdel = False
w_self.weakrefable = False
w_self.weak_subclasses = []
- w_self.__flags__ = 0 # or _HEAPTYPE
+ w_self.__flags__ = 0 # or _HEAPTYPE or _CPYTYPE
w_self.instancetypedef = overridetypedef
if overridetypedef is not None:
@@ -353,6 +354,9 @@
def is_heaptype(w_self):
return w_self.__flags__&_HEAPTYPE
+ def is_cpytype(w_self):
+ return w_self.__flags__ & _CPYTYPE
+
def get_module(w_self):
space = w_self.space
if w_self.is_heaptype() and '__module__' in w_self.dict_w:
Modified: pypy/trunk/pypy/rlib/rarithmetic.py
==============================================================================
--- pypy/trunk/pypy/rlib/rarithmetic.py (original)
+++ pypy/trunk/pypy/rlib/rarithmetic.py Thu Apr 29 20:37:15 2010
@@ -126,6 +126,8 @@
raise OverflowError
def compute_restype(self_type, other_type):
+ if self_type is other_type:
+ return self_type
if other_type in (bool, int, long):
if self_type is bool:
return int
Modified: pypy/trunk/pypy/rlib/rstring.py
==============================================================================
--- pypy/trunk/pypy/rlib/rstring.py (original)
+++ pypy/trunk/pypy/rlib/rstring.py Thu Apr 29 20:37:15 2010
@@ -1,11 +1,49 @@
-
-""" String builder interface
+""" String builder interface and string functions
"""
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.annotation.model import SomeObject, SomeString, s_None,\
SomeChar, SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString
+
+# -------------- public API for string functions -----------------------
+def split(value, by, maxsplit=-1):
+ bylen = len(by)
+ if bylen == 0:
+ raise ValueError("empty separator")
+
+ res = []
+ start = 0
+ while maxsplit != 0:
+ next = value.find(by, start)
+ if next < 0:
+ break
+ res.append(value[start:next])
+ start = next + bylen
+ maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+
+ res.append(value[start:len(value)])
+ return res
+
+def rsplit(value, by, maxsplit=-1):
+ res = []
+ end = len(value)
+ bylen = len(by)
+ if bylen == 0:
+ raise ValueError("empty separator")
+
+ while maxsplit != 0:
+ next = value.rfind(by, 0, end)
+ if next < 0:
+ break
+ res.append(value[next+bylen:end])
+ end = next
+ maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+
+ res.append(value[:end])
+ res.reverse()
+ return res
+
# -------------- public API ---------------------------------
INIT_SIZE = 100 # XXX tweak
Modified: pypy/trunk/pypy/rlib/rweakref.py
==============================================================================
--- pypy/trunk/pypy/rlib/rweakref.py (original)
+++ pypy/trunk/pypy/rlib/rweakref.py Thu Apr 29 20:37:15 2010
@@ -1,6 +1,7 @@
"""
Weakref support in RPython. Supports ref() without callbacks,
-and a limited version of WeakValueDictionary. LLType only for now!
+a form of WeakKeyDictionary, and a limited version of WeakValueDictionary.
+LLType only for now!
"""
import weakref
@@ -27,6 +28,36 @@
self._dict[key] = value
+class RWeakKeyDictionary(object):
+ """A dictionary containing weak keys.
+ Keys and values must be instances.
+ Prebuilt RWeakKeyDictionaries must be empty.
+ """
+
+ def __init__(self, keyclass, valueclass):
+ self._dict = weakref.WeakKeyDictionary()
+ self._keyclass = keyclass
+ self._valueclass = valueclass
+
+ def get(self, key):
+ """Get the value associated to 'key', or None by default."""
+ assert isinstance(key, self._keyclass)
+ return self._dict.get(key, None)
+
+ def set(self, key, value):
+ """Set the key/value pair (or delete it if value is None)."""
+ assert isinstance(key, self._keyclass)
+ if value is None:
+ self._dict.pop(key, None)
+ else:
+ assert isinstance(value, self._valueclass)
+ self._dict[key] = value
+
+ def length(self):
+ """Mostly for debugging. Slow, don't use in real code."""
+ return len(self._dict)
+
+
# ____________________________________________________________
from pypy.rpython import extregistry
@@ -41,8 +72,8 @@
self.valueclassdef = valueclassdef
def rtyper_makerepr(self, rtyper):
- from pypy.rlib import rweakrefimpl
- return rweakrefimpl.WeakValueDictRepr(rtyper)
+ from pypy.rlib import _rweakvaldict
+ return _rweakvaldict.WeakValueDictRepr(rtyper)
def rtyper_makekey_ex(self, rtyper):
return self.__class__,
@@ -65,14 +96,11 @@
_about_ = RWeakValueDictionary
def compute_result_annotation(self, s_valueclass):
- assert isinstance(s_valueclass, annmodel.SomePBC)
- assert s_valueclass.is_constant()
- [desc] = s_valueclass.descriptions
- return SomeWeakValueDict(desc.getuniqueclassdef())
+ return SomeWeakValueDict(_getclassdef(s_valueclass))
def specialize_call(self, hop):
- from pypy.rlib import rweakrefimpl
- return rweakrefimpl.specialize_make_weakdict(hop)
+ from pypy.rlib import _rweakvaldict
+ return _rweakvaldict.specialize_make_weakdict(hop)
class Entry(extregistry.ExtRegistryEntry):
_type_ = RWeakValueDictionary
@@ -81,3 +109,65 @@
bk = self.bookkeeper
x = self.instance
return SomeWeakValueDict(bk.getuniqueclassdef(x._valueclass))
+
+def _getclassdef(s_instance):
+ assert isinstance(s_instance, annmodel.SomePBC)
+ assert s_instance.is_constant()
+ [desc] = s_instance.descriptions
+ return desc.getuniqueclassdef()
+
+# ____________________________________________________________
+
+class SomeWeakKeyDict(annmodel.SomeObject):
+ knowntype = RWeakKeyDictionary
+
+ def __init__(self, keyclassdef, valueclassdef):
+ self.keyclassdef = keyclassdef
+ self.valueclassdef = valueclassdef
+
+ def rtyper_makerepr(self, rtyper):
+ from pypy.rlib import _rweakkeydict
+ return _rweakkeydict.WeakKeyDictRepr(rtyper)
+
+ def rtyper_makekey_ex(self, rtyper):
+ return self.__class__,
+
+ def method_get(self, s_key):
+ assert isinstance(s_key, annmodel.SomeInstance)
+ assert s_key.classdef.issubclass(self.keyclassdef)
+ return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)
+
+ def method_set(self, s_key, s_value):
+ s_oldvalue = self.method_get(s_key)
+ assert s_oldvalue.contains(s_value)
+
+ def method_length(self):
+ return annmodel.SomeInteger(nonneg=True)
+
+class __extend__(pairtype(SomeWeakKeyDict, SomeWeakKeyDict)):
+ def union((s_wkd1, s_wkd2)):
+ if s_wkd1.keyclassdef is not s_wkd2.keyclassdef:
+ return SomeObject() # not the same key class! complain...
+ if s_wkd1.valueclassdef is not s_wkd2.valueclassdef:
+ return SomeObject() # not the same value class! complain...
+ return SomeWeakKeyDict(s_wkd1.keyclassdef, s_wkd1.valueclassdef)
+
+class Entry(extregistry.ExtRegistryEntry):
+ _about_ = RWeakKeyDictionary
+
+ def compute_result_annotation(self, s_keyclass, s_valueclass):
+ return SomeWeakKeyDict(_getclassdef(s_keyclass),
+ _getclassdef(s_valueclass))
+
+ def specialize_call(self, hop):
+ from pypy.rlib import _rweakkeydict
+ return _rweakkeydict.specialize_make_weakdict(hop)
+
+class Entry(extregistry.ExtRegistryEntry):
+ _type_ = RWeakKeyDictionary
+
+ def compute_annotation(self):
+ bk = self.bookkeeper
+ x = self.instance
+ return SomeWeakKeyDict(bk.getuniqueclassdef(x._keyclass),
+ bk.getuniqueclassdef(x._valueclass))
Modified: pypy/trunk/pypy/rlib/test/test_rarithmetic.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rarithmetic.py (original)
+++ pypy/trunk/pypy/rlib/test/test_rarithmetic.py Thu Apr 29 20:37:15 2010
@@ -365,3 +365,7 @@
def test_isnan():
assert isnan(NAN)
+
+def test_int_real_union():
+ from pypy.rpython.lltypesystem.rffi import r_int_real
+ assert compute_restype(r_int_real, r_int_real) is r_int_real
Modified: pypy/trunk/pypy/rlib/test/test_rstring.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rstring.py (original)
+++ pypy/trunk/pypy/rlib/test/test_rstring.py Thu Apr 29 20:37:15 2010
@@ -1,5 +1,26 @@
-from pypy.rlib.rstring import StringBuilder, UnicodeBuilder
+from pypy.rlib.rstring import StringBuilder, UnicodeBuilder, split, rsplit
+
+def test_split():
+ assert split("", 'x') == ['']
+ assert split("a", "a", 1) == ['', '']
+ assert split(" ", " ", 1) == ['', '']
+ assert split("aa", "a", 2) == ['', '', '']
+ assert split('a|b|c|d', '|') == ['a', 'b', 'c', 'd']
+ assert split('a|b|c|d', '|', 2) == ['a', 'b', 'c|d']
+ assert split('a//b//c//d', '//') == ['a', 'b', 'c', 'd']
+ assert split('endcase test', 'test') == ['endcase ', '']
+ raises(ValueError, split, 'abc', '')
+
+def test_rsplit():
+ assert rsplit("a", "a", 1) == ['', '']
+ assert rsplit(" ", " ", 1) == ['', '']
+ assert rsplit("aa", "a", 2) == ['', '', '']
+ assert rsplit('a|b|c|d', '|') == ['a', 'b', 'c', 'd']
+ assert rsplit('a|b|c|d', '|', 2) == ['a|b', 'c', 'd']
+ assert rsplit('a//b//c//d', '//') == ['a', 'b', 'c', 'd']
+ assert rsplit('endcase test', 'test') == ['endcase ', '']
+ raises(ValueError, rsplit, "abc", '')
def test_string_builder():
s = StringBuilder()
Modified: pypy/trunk/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/trunk/pypy/rpython/annlowlevel.py (original)
+++ pypy/trunk/pypy/rpython/annlowlevel.py Thu Apr 29 20:37:15 2010
@@ -34,6 +34,7 @@
else:
s = compact()
return s + 'Const'
+ __repr__ = __str__
class LowLevelAnnotatorPolicy(AnnotatorPolicy):
allow_someobjects = False
Modified: pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py Thu Apr 29 20:37:15 2010
@@ -675,7 +675,8 @@
if T is lltype.Void:
return None
if isinstance(T, lltype.Ptr):
- if not cobj: # NULL pointer
+ if not cobj or not ctypes.cast(cobj, ctypes.c_void_p).value: # NULL pointer
+ # CFunctionType.__nonzero__ is broken before Python 2.6
return lltype.nullptr(T.TO)
if isinstance(T.TO, lltype.Struct):
REAL_TYPE = T.TO
@@ -963,7 +964,7 @@
def invoke_via_ctypes(*argvalues):
global _callback_exc_info
cargs = []
- for i in range(len(FUNCTYPE.ARGS)):
+ for i in range(len(argvalues)):
if i not in void_arguments:
cvalue = lltype2ctypes(argvalues[i])
if i in container_arguments:
Modified: pypy/trunk/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lltype.py Thu Apr 29 20:37:15 2010
@@ -1,3 +1,8 @@
+import StringIO
+import traceback
+import sys
+
+import py
from pypy.rlib.rarithmetic import (r_int, r_uint, intmask, r_singlefloat,
r_ulonglong, r_longlong, base_int,
normalizedinttype)
@@ -11,6 +16,7 @@
import weakref
TLS = tlsobject()
+TRACK_ALLOCATIONS = False
class _uninitialized(object):
def __init__(self, TYPE):
@@ -1312,27 +1318,49 @@
def _was_freed(self):
return False
+ALLOCATED = identity_dict()
+
class _parentable(_container):
_kind = "?"
__slots__ = ('_TYPE',
'_parent_type', '_parent_index', '_keepparent',
'_wrparent',
- '__weakref__',
- '_storage')
+ '__weakref__', '_traceback',
+ '__storage')
- def __init__(self, TYPE):
+ def __init__(self, TYPE, track_allocation=None):
self._wrparent = None
self._TYPE = TYPE
self._storage = True # means "use default storage", as opposed to:
# None - container was freed
# <ctypes object> - using ctypes
# (see ll2ctypes.py)
+ if track_allocation is not False and TRACK_ALLOCATIONS:
+ self._traceback = self._get_traceback()
+ ALLOCATED[self] = None
+ else:
+ self._traceback = None
+
+ def _get_traceback(self):
+ frame = sys._getframe().f_back.f_back.f_back.f_back
+ sio = StringIO.StringIO()
+ traceback.print_stack(frame, file=sio)
+ return sio.getvalue()
def _free(self):
self._check() # no double-frees
self._storage = None
+ def _storage_get(self):
+ return self.__storage
+
+ def _storage_set(self, value):
+ self.__storage = value
+ if value is not True and self in ALLOCATED:
+ del ALLOCATED[self]
+ _storage = property(_storage_get, _storage_set)
+
def _was_freed(self):
if self._storage is None:
return True
@@ -1409,14 +1437,14 @@
class _struct(_parentable):
_kind = "structure"
- __slots__ = ('_hash_cache_',)
+ __slots__ = ('_hash_cache_', '_compilation_info')
- def __new__(self, TYPE, n=None, initialization=None, parent=None, parentindex=None):
+ def __new__(self, TYPE, n=None, initialization=None, parent=None, parentindex=None, track_allocation=None):
my_variety = _struct_variety(TYPE._names)
return object.__new__(my_variety)
- def __init__(self, TYPE, n=None, initialization=None, parent=None, parentindex=None):
- _parentable.__init__(self, TYPE)
+ def __init__(self, TYPE, n=None, initialization=None, parent=None, parentindex=None, track_allocation=None):
+ _parentable.__init__(self, TYPE, track_allocation)
if n is not None and TYPE._arrayfld is None:
raise TypeError("%r is not variable-sized" % (TYPE,))
if n is None and TYPE._arrayfld is not None:
@@ -1485,12 +1513,12 @@
__slots__ = ('items',)
- def __init__(self, TYPE, n, initialization=None, parent=None, parentindex=None):
+ def __init__(self, TYPE, n, initialization=None, parent=None, parentindex=None, track_allocation=None):
if not isinstance(n, int):
raise TypeError, "array length must be an int"
if n < 0:
raise ValueError, "negative array length"
- _parentable.__init__(self, TYPE)
+ _parentable.__init__(self, TYPE, track_allocation)
try:
myrange = range(n)
except OverflowError:
@@ -1557,7 +1585,7 @@
_cache = weakref.WeakKeyDictionary() # parentarray -> {subarrays}
def __init__(self, TYPE, parent, baseoffset_or_fieldname):
- _parentable.__init__(self, TYPE)
+ _parentable.__init__(self, TYPE, track_allocation=False)
self._setparentstructure(parent, baseoffset_or_fieldname)
# Keep the parent array alive, we share the same allocation.
# Don't do it if we are inside a GC object, though -- it's someone
@@ -1787,9 +1815,9 @@
else:
initialization = 'malloc'
if isinstance(T, Struct):
- o = _struct(T, n, initialization=initialization)
+ o = _struct(T, n, initialization=initialization, track_allocation=flavor == "raw" and not immortal)
elif isinstance(T, Array):
- o = _array(T, n, initialization=initialization)
+ o = _array(T, n, initialization=initialization, track_allocation=flavor == "raw" and not immortal)
elif isinstance(T, OpaqueType):
assert n is None
o = _opaque(T, initialization=initialization)
Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rdict.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rdict.py Thu Apr 29 20:37:15 2010
@@ -508,12 +508,14 @@
def ll_dict_lookup(d, key, hash):
entries = d.entries
+ ENTRIES = lltype.typeOf(entries).TO
+ direct_compare = not hasattr(ENTRIES, 'no_direct_compare')
mask = len(entries) - 1
i = hash & mask
# do the first try before any looping
if entries.valid(i):
checkingkey = entries[i].key
- if checkingkey == key:
+ if direct_compare and checkingkey == key:
return i # found the entry
if d.keyeq is not None and entries.hash(i) == hash:
# correct hash, maybe the key is e.g. a different pointer to
@@ -548,7 +550,7 @@
return freeslot
elif entries.valid(i):
checkingkey = entries[i].key
- if checkingkey == key:
+ if direct_compare and checkingkey == key:
return i
if d.keyeq is not None and entries.hash(i) == hash:
# correct hash, maybe the key is e.g. a different pointer to
Modified: pypy/trunk/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rffi.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rffi.py Thu Apr 29 20:37:15 2010
@@ -48,6 +48,7 @@
result = isinstance(s_p, annmodel.SomePtr)
return self.bookkeeper.immutablevalue(result)
def specialize_call(self, hop):
+ hop.exception_cannot_occur()
return hop.inputconst(lltype.Bool, hop.s_result.const)
def llexternal(name, args, result, _callable=None,
@@ -388,6 +389,7 @@
r_int_real = rarithmetic.build_int("r_int_real", r_int.SIGN, r_int.BITS, True)
INT_real = lltype.build_number("INT", r_int_real)
platform.numbertype_to_rclass[INT_real] = r_int_real
+NUMBER_TYPES.append(INT_real)
# ^^^ this creates at least the following names:
# --------------------------------------------------------------------
Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Thu Apr 29 20:37:15 2010
@@ -432,6 +432,29 @@
rffi.free_charp(p)
assert not ALLOCATED # detects memory leaks in the test
+ def test_funcptr_cast(self):
+ eci = ExternalCompilationInfo(
+ separate_module_sources=["""
+ long mul(long x, long y) { return x*y; }
+ long(*get_mul(long x)) () { return &mul; }
+ """],
+ export_symbols=['get_mul'])
+ get_mul = rffi.llexternal(
+ 'get_mul', [],
+ lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)),
+ compilation_info=eci)
+ # This call returns a pointer to a function taking one argument
+ funcptr = get_mul()
+ # cast it to the "real" function type
+ FUNCTYPE2 = lltype.FuncType([lltype.Signed, lltype.Signed],
+ lltype.Signed)
+ cmul = rffi.cast(lltype.Ptr(FUNCTYPE2), funcptr)
+ # and it can be called with the expected number of arguments
+ res = cmul(41, 42)
+ assert res == 41 * 42
+ raises(TypeError, cmul, 41)
+ raises(TypeError, cmul, 41, 42, 43)
+
def test_qsort(self):
CMPFUNC = lltype.FuncType([rffi.VOIDP, rffi.VOIDP], rffi.INT)
qsort = rffi.llexternal('qsort', [rffi.VOIDP,
Modified: pypy/trunk/pypy/tool/fixeol
==============================================================================
--- pypy/trunk/pypy/tool/fixeol (original)
+++ pypy/trunk/pypy/tool/fixeol Thu Apr 29 20:37:15 2010
@@ -48,7 +48,7 @@
return True
def checkeolfile(path):
- return path.ext in ('.txt', '.py', '.asc')
+ return path.ext in ('.txt', '.py', '.asc', '.h', '.c')
def fixdirectory(path):
print "+ checking directory", path,
Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py (original)
+++ pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py Thu Apr 29 20:37:15 2010
@@ -1,10 +1,14 @@
import py
-import sys, os
+import sys, os, gc
from pypy.translator.c.test import test_newgc
from pypy.translator.translator import TranslationContext
from pypy.translator.c.genc import CStandaloneBuilder
from pypy.annotation.listdef import s_list_of_strings
from pypy import conftest
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.entrypoint import entrypoint, secondary_entrypoints
+from pypy.rpython.lltypesystem.lloperation import llop
class AbstractTestAsmGCRoot:
# the asmgcroot gc transformer doesn't generate gc_reload_possibly_moved
@@ -34,11 +38,14 @@
config = cls.make_config()
t = TranslationContext(config=config)
a = t.buildannotator()
+ for f, inputtypes in cls.secondary_entrypoints:
+ a.build_types(f, inputtypes, False)
a.build_types(main, [s_list_of_strings])
t.buildrtyper().specialize()
t.checkgraphs()
- cbuilder = CStandaloneBuilder(t, main, config=config)
+ cbuilder = CStandaloneBuilder(t, main, config=config,
+ secondary_entrypoints=cls.secondary_entrypoints)
c_source_filename = cbuilder.generate_source(
defines = cbuilder.DEBUG_DEFINES)
cls._patch_makefile(cbuilder.targetdir)
@@ -53,7 +60,12 @@
redirect = ' 2> NUL'
else:
redirect = ''
- g = os.popen('"%s" %s %d%s' % (exe_name, arg0, arg1, redirect), 'r')
+ if config.translation.shared and os.name == 'posix':
+ env = 'LD_LIBRARY_PATH="%s" ' % (exe_name.dirpath(),)
+ else:
+ env = ''
+ g = os.popen(
+ '%s"%s" %s %d%s' % (env, exe_name, arg0, arg1, redirect), 'r')
for line in g:
print >> sys.stderr, 'RUN:', line.rstrip()
lines.append(line)
@@ -101,6 +113,7 @@
test_newgc.TestSemiSpaceGC):
# for the individual tests see
# ====> ../../test/test_newgc.py
+ secondary_entrypoints = []
def define_large_function(cls):
class A(object):
@@ -123,11 +136,6 @@
assert res == 1000
def define_callback_simple(cls):
- import gc
- from pypy.rpython.lltypesystem import lltype, rffi
- from pypy.rpython.annlowlevel import llhelper
- from pypy.translator.tool.cbuild import ExternalCompilationInfo
-
c_source = py.code.Source("""
int mystuff(int(*cb)(int, int))
{
@@ -153,11 +161,44 @@
return f
-
def test_callback_simple(self):
res = self.run('callback_simple')
assert res == 4900
+ def define_secondary_entrypoint_callback(self):
+ @entrypoint("x42", [lltype.Signed, lltype.Signed], c_name='callback')
+ def mycallback(a, b):
+ llop.gc_stack_bottom(lltype.Void)
+ rffi.stackcounter.stacks_counter += 1
+ gc.collect()
+ rffi.stackcounter.stacks_counter -= 1
+ return a + b
+
+ c_source = py.code.Source("""
+ int mystuff2()
+ {
+ return callback(40, 2) + callback(3, 4);
+ }
+ """)
+
+ eci = ExternalCompilationInfo(separate_module_sources=[c_source])
+ z = rffi.llexternal('mystuff2', [], lltype.Signed,
+ compilation_info=eci)
+ S = lltype.GcStruct('S', ('x', lltype.Signed))
+
+ self.secondary_entrypoints.extend(secondary_entrypoints["x42"])
+
+ def f():
+ p = lltype.malloc(S)
+ p.x = 100
+ result = z()
+ return result * p.x
+
+ return f
+
+ def test_secondary_entrypoint_callback(self):
+ res = self.run('secondary_entrypoint_callback')
+ assert res == 4900
class TestAsmGCRootWithSemiSpaceGC_Mingw32(TestAsmGCRootWithSemiSpaceGC):
# for the individual tests see
@@ -186,6 +227,13 @@
def define_callback_with_collect(cls):
return lambda: 0
+class TestAsmGCRootWithSemiSpaceGC_Shared(TestAsmGCRootWithSemiSpaceGC):
+ @classmethod
+ def make_config(cls):
+ config = TestAsmGCRootWithSemiSpaceGC.make_config()
+ config.translation.shared = True
+ return config
+
class TestAsmGCRootWithHybridTagged(AbstractTestAsmGCRoot,
test_newgc.TestHybridTaggedPointers):
pass
Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original)
+++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Thu Apr 29 20:37:15 2010
@@ -1640,6 +1640,7 @@
format = 'mingw32'
else:
format = 'elf'
+ entrypoint = 'main'
while len(sys.argv) > 1:
if sys.argv[1] == '-v':
del sys.argv[1]
@@ -1653,6 +1654,9 @@
elif sys.argv[1].startswith('-f'):
format = sys.argv[1][2:]
del sys.argv[1]
+ elif sys.argv[1].startswith('-m'):
+ entrypoint = sys.argv[1][2:]
+ del sys.argv[1]
else:
break
tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format)
@@ -1669,7 +1673,7 @@
lblfn = fn[:-2] + '.lbl.s'
g = open(lblfn, 'w')
try:
- tracker.process(f, g, filename=fn)
+ tracker.process(f, g, entrypoint=entrypoint, filename=fn)
except:
g.close()
os.unlink(lblfn)
Modified: pypy/trunk/pypy/translator/c/genc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/genc.py (original)
+++ pypy/trunk/pypy/translator/c/genc.py Thu Apr 29 20:37:15 2010
@@ -13,6 +13,7 @@
from pypy.translator.c.support import log, c_string_constant
from pypy.rpython.typesystem import getfunctionptr
from pypy.translator.c import gc
+from pypy.rlib import exports
def import_module_from_directory(dir, modname):
file, pathname, description = imp.find_module(modname, [str(dir)])
@@ -77,14 +78,22 @@
self.outputfilename = outputfilename
self.profbased = profbased
- def _build(self, eci=ExternalCompilationInfo()):
+ def _build(self, eci=ExternalCompilationInfo(), shared=False):
+ outputfilename = self.outputfilename
+ if shared:
+ if outputfilename:
+ basename = outputfilename
+ else:
+ basename = self.cfiles[0].purebasename
+ outputfilename = 'lib' + basename
return self.platform.compile(self.cfiles, self.eci.merge(eci),
- outputfilename=self.outputfilename)
+ outputfilename=outputfilename,
+ standalone=not shared)
- def build(self):
+ def build(self, shared=False):
if self.profbased:
return self._do_profbased()
- return self._build()
+ return self._build(shared=shared)
def _do_profbased(self):
ProfDriver, args = self.profbased
@@ -103,7 +112,8 @@
modulename = None
split = False
- def __init__(self, translator, entrypoint, config, gcpolicy=None):
+ def __init__(self, translator, entrypoint, config, gcpolicy=None,
+ secondary_entrypoints=()):
self.translator = translator
self.entrypoint = entrypoint
self.entrypoint_name = getattr(self.entrypoint, 'func_name', None)
@@ -113,6 +123,7 @@
if gcpolicy is not None and gcpolicy.requires_stackless:
config.translation.stackless = True
self.eci = self.get_eci()
+ self.secondary_entrypoints = secondary_entrypoints
def get_eci(self):
pypy_include_dir = py.path.local(autopath.pypydir).join('translator', 'c')
@@ -159,7 +170,16 @@
self.c_entrypoint_name = None
else:
pfname = db.get(pf)
+
+ for func, _ in self.secondary_entrypoints:
+ bk = translator.annotator.bookkeeper
+ db.get(getfunctionptr(bk.getdesc(func).getuniquegraph()))
+
self.c_entrypoint_name = pfname
+
+ for obj in exports.EXPORTS_obj2name.keys():
+ db.getcontainernode(obj)
+ exports.clear()
db.complete()
self.collect_compilation_info(db)
@@ -240,6 +260,10 @@
if CBuilder.have___thread:
if not self.config.translation.no__thread:
defines['USE___THREAD'] = 1
+ if self.config.translation.shared:
+ defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup"
+ self.eci = self.eci.merge(ExternalCompilationInfo(
+ export_symbols=["pypy_main_startup"]))
self.eci, cfile, extra = gen_source_standalone(db, modulename,
targetdir,
self.eci,
@@ -404,12 +428,13 @@
if isinstance(self._module, isolate.Isolate):
isolate.close_isolate(self._module)
- def gen_makefile(self, targetdir):
+ def gen_makefile(self, targetdir, exe_name=None):
pass
class CStandaloneBuilder(CBuilder):
standalone = True
executable_name = None
+ shared_library_name = None
def getprofbased(self):
profbased = None
@@ -450,9 +475,40 @@
return res.out, res.err
return res.out
- def compile(self):
+ def build_main_for_shared(self, shared_library_name, entrypoint, exe_name):
+ import time
+ time.sleep(1)
+ self.shared_library_name = shared_library_name
+ # build main program
+ eci = self.get_eci()
+ kw = {}
+ if self.translator.platform.so_ext == 'so':
+ kw['libraries'] = [self.shared_library_name.purebasename[3:]]
+ kw['library_dirs'] = [self.targetdir]
+ else:
+ kw['libraries'] = [self.shared_library_name.new(ext='')]
+ eci = eci.merge(ExternalCompilationInfo(
+ separate_module_sources=['''
+ int %s(int argc, char* argv[]);
+
+ int main(int argc, char* argv[])
+ { return %s(argc, argv); }
+ ''' % (entrypoint, entrypoint)
+ ],
+ **kw
+ ))
+ eci = eci.convert_sources_to_files(
+ cache_dir=self.targetdir)
+ return self.translator.platform.compile(
+ [], eci,
+ outputfilename=exe_name)
+
+ def compile(self, exe_name=None):
assert self.c_source_filename
assert not self._compiled
+
+ shared = self.config.translation.shared
+
if (self.config.translation.gcrootfinder == "asmgcc" or
self.config.translation.force_make):
extra_opts = []
@@ -463,16 +519,23 @@
else:
compiler = CCompilerDriver(self.translator.platform,
[self.c_source_filename] + self.extrafiles,
- self.eci, profbased=self.getprofbased())
- self.executable_name = compiler.build()
+ self.eci, profbased=self.getprofbased(),
+ outputfilename=exe_name)
+ self.executable_name = compiler.build(shared=shared)
+ if shared:
+ self.executable_name = self.build_main_for_shared(
+ self.executable_name, "pypy_main_startup", exe_name)
assert self.executable_name
self._compiled = True
return self.executable_name
- def gen_makefile(self, targetdir):
+ def gen_makefile(self, targetdir, exe_name=None):
cfiles = [self.c_source_filename] + self.extrafiles
- mk = self.translator.platform.gen_makefile(cfiles, self.eci,
- path=targetdir)
+ mk = self.translator.platform.gen_makefile(
+ cfiles, self.eci,
+ path=targetdir, exe_name=exe_name,
+ shared=self.config.translation.shared)
+
if self.has_profopt():
profopt = self.config.translation.profopt
mk.definition('ABS_TARGET', '$(shell python -c "import sys,os; print os.path.abspath(sys.argv[1])" $(TARGET))')
@@ -516,6 +579,11 @@
mk.definition('GCMAPFILES', gcmapfiles)
mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g')
+ if self.config.translation.shared:
+ mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup")
+ else:
+ mk.definition('PYPY_MAIN_FUNCTION', "main")
+
if sys.platform == 'win32':
python = sys.executable.replace('\\', '/') + ' '
else:
@@ -541,7 +609,7 @@
'cmd /c $(MASM) /nologo /Cx /Cp /Zm /coff /Fo$@ /c $< $(INCLUDEDIRS)')
mk.rule('.c.gcmap', '',
['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)',
- 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@']
+ 'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -m$(PYPY_MAIN_FUNCTION) -t $*.s > $@']
)
mk.rule('gcmaptable.c', '$(GCMAPFILES)',
'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@')
@@ -550,7 +618,7 @@
mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s')
mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)')
mk.rule('%.lbl.s %.gcmap', '%.s',
- python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $*.gcmap')
+ python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -m$(PYPY_MAIN_FUNCTION) -t $< > $*.gcmap')
mk.rule('gcmaptable.s', '$(GCMAPFILES)',
python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@')
Modified: pypy/trunk/pypy/translator/c/node.py
==============================================================================
--- pypy/trunk/pypy/translator/c/node.py (original)
+++ pypy/trunk/pypy/translator/c/node.py Thu Apr 29 20:37:15 2010
@@ -10,6 +10,7 @@
from pypy.translator.c.support import cdecl, forward_cdecl, somelettersfrom
from pypy.translator.c.support import c_char_array_constant, barebonearray
from pypy.translator.c.primitive import PrimitiveType, name_signed
+from pypy.rlib import exports
from pypy.rlib.rarithmetic import isinf, isnan
from pypy.rlib.rstackovf import _StackOverflow
from pypy.translator.c import extfunc
@@ -468,7 +469,7 @@
if USESLOTS:
__slots__ = """db T obj
typename implementationtypename
- name ptrname
+ name ptrname compilation_info
globalcontainer""".split()
def __init__(self, db, T, obj):
@@ -479,7 +480,10 @@
self.typename = db.gettype(T) #, who_asks=self)
self.implementationtypename = db.gettype(T, varlength=self.getlength())
parent, parentindex = parentlink(obj)
- if parent is None:
+ if obj in exports.EXPORTS_obj2name:
+ self.name = exports.EXPORTS_obj2name[obj]
+ self.globalcontainer = True
+ elif parent is None:
self.name = db.namespace.uniquename('g_' + self.basename())
self.globalcontainer = True
else:
@@ -490,6 +494,7 @@
if self.typename != self.implementationtypename:
if db.gettypedefnode(T).extra_union_for_varlength:
self.name += '.b'
+ self.compilation_info = getattr(obj, '_compilation_info', None)
self.ptrname = '(&%s)' % self.name
def is_thread_local(self):
@@ -922,6 +927,8 @@
else:
assert fnobj.external == 'CPython'
return [CExternalFunctionCodeGenerator(fnobj, db)]
+ elif hasattr(fnobj._callable, "c_name"):
+ return []
else:
raise ValueError, "don't know how to generate code for %r" % (fnobj,)
Modified: pypy/trunk/pypy/translator/c/src/commondefs.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/commondefs.h (original)
+++ pypy/trunk/pypy/translator/c/src/commondefs.h Thu Apr 29 20:37:15 2010
@@ -15,6 +15,13 @@
#include <limits.h>
+#ifndef LLONG_MAX
+#define LLONG_MAX __LONG_LONG_MAX__
+#endif
+#ifndef LLONG_MIN
+#define LLONG_MIN (-LLONG_MAX - 1LL)
+#endif
+
#if INT_MAX != 2147483647
# error "unsupported value for INT_MAX"
#endif
@@ -62,9 +69,6 @@
/********************************************************/
-typedef long Py_intptr_t;
-typedef unsigned long Py_uintptr_t;
-
#if ((-1) >> 1) > 0
# define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \
((I) < 0 ? -1-((-1-(I)) >> (J)) : (I) >> (J))
Modified: pypy/trunk/pypy/translator/c/src/main.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/main.h (original)
+++ pypy/trunk/pypy/translator/c/src/main.h Thu Apr 29 20:37:15 2010
@@ -15,11 +15,15 @@
#ifndef PYPY_NOT_MAIN_FILE
+#ifndef PYPY_MAIN_FUNCTION
+#define PYPY_MAIN_FUNCTION main
+#endif
+
#ifdef MS_WINDOWS
#include "src/winstuff.c"
#endif
-int main(int argc, char *argv[])
+int PYPY_MAIN_FUNCTION(int argc, char *argv[])
{
char *errmsg;
int i, exitcode;
Modified: pypy/trunk/pypy/translator/c/src/obmalloc.c
==============================================================================
--- pypy/trunk/pypy/translator/c/src/obmalloc.c (original)
+++ pypy/trunk/pypy/translator/c/src/obmalloc.c Thu Apr 29 20:37:15 2010
@@ -225,7 +225,7 @@
#define ulong unsigned long /* assuming >= 32 bits */
#undef uptr
-#define uptr Py_uintptr_t
+#define uptr unsigned long
/* When you say memory, my mind reasons in terms of (pointers to) blocks */
typedef uchar block;
@@ -439,7 +439,7 @@
arenabase = bp;
nfreepools = ARENA_SIZE / POOL_SIZE;
assert(POOL_SIZE * nfreepools == ARENA_SIZE);
- excess = (uint) ((Py_uintptr_t)bp & POOL_SIZE_MASK);
+ excess = (uint) ((uint)bp & POOL_SIZE_MASK);
if (excess != 0) {
--nfreepools;
arenabase += POOL_SIZE - excess;
Modified: pypy/trunk/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_genc.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_genc.py Thu Apr 29 20:37:15 2010
@@ -12,6 +12,7 @@
from pypy.translator.gensupp import uniquemodulename
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.interactive import Translation
+from pypy.rlib.entrypoint import entrypoint
def compile(fn, argtypes, view=False, gcpolicy="ref", backendopt=True,
annotatorpolicy=None):
@@ -396,3 +397,85 @@
if py.test.config.option.view:
t.view()
assert 'pypy_xyz_f' in t.driver.cbuilder.c_source_filename.read()
+
+def test_entrypoints():
+ def f():
+ return 3
+
+ key = "test_entrypoints42"
+ @entrypoint(key, [int], "foobar")
+ def g(x):
+ return x + 42
+
+ t = Translation(f, [], backend="c", secondaryentrypoints="test_entrypoints42")
+ t.annotate()
+ compiled_fn = t.compile_c()
+ if py.test.config.option.view:
+ t.view()
+ assert 'foobar' in t.driver.cbuilder.c_source_filename.read()
+
+def test_exportstruct():
+ from pypy.rlib.exports import export_struct
+ def f():
+ return 42
+ FOO = Struct("FOO", ("field1", Signed))
+ foo = malloc(FOO, flavor="raw")
+ foo.field1 = 43
+ export_struct("BarStruct", foo._obj)
+ t = Translation(f, [], backend="c")
+ t.annotate()
+ compiled_fn = t.compile_c()
+ if py.test.config.option.view:
+ t.view()
+ assert ' BarStruct ' in t.driver.cbuilder.c_source_filename.read()
+
+def test_recursive_llhelper():
+ from pypy.rpython.annlowlevel import llhelper
+ from pypy.rpython.lltypesystem import lltype
+ from pypy.rlib.objectmodel import specialize
+ from pypy.rlib.nonconst import NonConstant
+ FT = lltype.ForwardReference()
+ FTPTR = lltype.Ptr(FT)
+ STRUCT = lltype.Struct("foo", ("bar", FTPTR))
+ FT.become(lltype.FuncType([lltype.Ptr(STRUCT)], lltype.Signed))
+
+ class A:
+ def __init__(self, func, name):
+ self.func = func
+ self.name = name
+ def _freeze_(self):
+ return True
+ @specialize.memo()
+ def make_func(self):
+ f = getattr(self, "_f", None)
+ if f is not None:
+ return f
+ f = lambda *args: self.func(*args)
+ f.c_name = self.name
+ f.relax_sig_check = True
+ f.__name__ = "WRAP%s" % (self.name, )
+ self._f = f
+ return f
+ def get_llhelper(self):
+ return llhelper(FTPTR, self.make_func())
+ def f(s):
+ if s.bar == t.bar:
+ lltype.free(s, flavor="raw")
+ return 1
+ lltype.free(s, flavor="raw")
+ return 0
+ def g(x):
+ return 42
+ def chooser(x):
+ s = lltype.malloc(STRUCT, flavor="raw")
+ if x:
+ s.bar = llhelper(FTPTR, a_f.make_func())
+ else:
+ s.bar = llhelper(FTPTR, a_g.make_func())
+ return f(s)
+ a_f = A(f, "f")
+ a_g = A(g, "g")
+ t = lltype.malloc(STRUCT, flavor="raw")
+ t.bar = llhelper(FTPTR, a_f.make_func())
+ fn = compile(chooser, [bool])
+ assert fn(True)
Modified: pypy/trunk/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_newgc.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_newgc.py Thu Apr 29 20:37:15 2010
@@ -66,6 +66,12 @@
for fullname in dir(cls):
if not fullname.startswith('define'):
continue
+ keyword = conftest.option.keyword
+ if keyword:
+ if keyword.startswith('test_'):
+ keyword = keyword[len('test_'):]
+ if keyword not in fullname:
+ continue
prefix, name = fullname.split('_', 1)
definefunc = getattr(cls, fullname)
func = definefunc.im_func(cls)
Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_standalone.py Thu Apr 29 20:37:15 2010
@@ -16,11 +16,13 @@
class StandaloneTests(object):
config = None
- def compile(self, entry_point, debug=True):
+ def compile(self, entry_point, debug=True, shared=False):
t = TranslationContext(self.config)
t.buildannotator().build_types(entry_point, [s_list_of_strings])
t.buildrtyper().specialize()
+ t.config.translation.shared = shared
+
cbuilder = CStandaloneBuilder(t, entry_point, t.config)
if debug:
cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
@@ -587,6 +589,19 @@
# The traceback stops at f() because it's the first function that
# captures the AssertionError, which makes the program abort.
+ def test_shared(self, monkeypatch):
+ def f(argv):
+ print len(argv)
+ def entry_point(argv):
+ f(argv)
+ return 0
+ t, cbuilder = self.compile(entry_point, shared=True)
+ assert cbuilder.shared_library_name is not None
+ assert cbuilder.shared_library_name != cbuilder.executable_name
+ monkeypatch.setenv('LD_LIBRARY_PATH',
+ cbuilder.shared_library_name.dirpath())
+ out, err = cbuilder.cmdexec("a b")
+ assert out == "3"
class TestMaemo(TestStandalone):
def setup_class(cls):
Modified: pypy/trunk/pypy/translator/driver.py
==============================================================================
--- pypy/trunk/pypy/translator/driver.py (original)
+++ pypy/trunk/pypy/translator/driver.py Thu Apr 29 20:37:15 2010
@@ -12,6 +12,7 @@
import optparse
from pypy.tool.udir import udir
from pypy.rlib.jit import DEBUG_OFF, DEBUG_DETAILED, DEBUG_PROFILE, DEBUG_STEPS
+from pypy.rlib.entrypoint import secondary_entrypoints
import py
from pypy.tool.ansi_print import ansi_log
@@ -93,7 +94,7 @@
if setopts is not None:
self.config.set(**setopts)
-
+
self.exe_name = exe_name
self.extmod_name = extmod_name
@@ -210,12 +211,25 @@
self.entry_point = entry_point
self.translator = translator
self.libdef = None
+ self.secondary_entrypoints = []
+
+ if self.config.translation.secondaryentrypoints:
+ for key in self.config.translation.secondaryentrypoints.split(","):
+ try:
+ points = secondary_entrypoints[key]
+ except KeyError:
+ raise KeyError(
+ "Entrypoints not found. I only know the keys %r." %
+ (", ".join(secondary_entrypoints.keys()), ))
+ self.secondary_entrypoints.extend(points)
self.translator.driver_instrument_result = self.instrument_result
def setup_library(self, libdef, policy=None, extra={}, empty_translator=None):
+ """ Used by carbon python only. """
self.setup(None, None, policy, extra, empty_translator)
self.libdef = libdef
+ self.secondary_entrypoints = libdef.functions
def instrument_result(self, args):
backend, ts = self.get_backend_and_type_system()
@@ -304,23 +318,25 @@
annmodel.DEBUG = self.config.translation.debug
annotator = translator.buildannotator(policy=policy)
+ if self.secondary_entrypoints is not None:
+ for func, inputtypes in self.secondary_entrypoints:
+ if inputtypes == Ellipsis:
+ continue
+ rettype = annotator.build_types(func, inputtypes, False)
+
if self.entry_point:
s = annotator.build_types(self.entry_point, self.inputtypes)
-
- self.sanity_check_annotation()
- if self.standalone and s.knowntype != int:
- raise Exception("stand-alone program entry point must return an "
- "int (and not, e.g., None or always raise an "
- "exception).")
- annotator.simplify()
- return s
+ translator.entry_point_graph = annotator.bookkeeper.getdesc(self.entry_point).getuniquegraph()
else:
- assert self.libdef is not None
- for func, inputtypes in self.libdef.functions:
- annotator.build_types(func, inputtypes)
- func.c_name = func.func_name
- self.sanity_check_annotation()
- annotator.simplify()
+ s = None
+
+ self.sanity_check_annotation()
+ if self.entry_point and self.standalone and s.knowntype != int:
+ raise Exception("stand-alone program entry point must return an "
+ "int (and not, e.g., None or always raise an "
+ "exception).")
+ annotator.simplify()
+
#
task_annotate = taskdef(task_annotate, [], "Annotating&simplifying")
@@ -471,7 +487,8 @@
else:
from pypy.translator.c.genc import CExtModuleBuilder as CBuilder
cbuilder = CBuilder(self.translator, self.entry_point,
- config=self.config)
+ config=self.config,
+ secondary_entrypoints=self.secondary_entrypoints)
cbuilder.stackless = self.config.translation.stackless
if not standalone: # xxx more messy
cbuilder.modulename = self.extmod_name
@@ -521,6 +538,10 @@
exename = mkexename(self.c_entryp)
newexename = self.compute_exe_name()
shutil.copy(str(exename), str(newexename))
+ if self.cbuilder.shared_library_name is not None:
+ soname = self.cbuilder.shared_library_name
+ newsoname = newexename.new(basename=soname.basename)
+ shutil.copy(str(soname), str(newsoname))
self.c_entryp = newexename
self.log.info("created: %s" % (self.c_entryp,))
@@ -529,7 +550,10 @@
translator/platform
"""
cbuilder = self.cbuilder
- cbuilder.compile()
+ kwds = {}
+ if self.standalone:
+ kwds['exe_name'] = self.compute_exe_name().basename
+ cbuilder.compile(**kwds)
if self.standalone:
self.c_entryp = cbuilder.executable_name
Modified: pypy/trunk/pypy/translator/goal/ann_override.py
==============================================================================
--- pypy/trunk/pypy/translator/goal/ann_override.py (original)
+++ pypy/trunk/pypy/translator/goal/ann_override.py Thu Apr 29 20:37:15 2010
@@ -81,7 +81,7 @@
def attach_lookup(pol, t, attr):
cached = "cached_%s" % attr
- if not t.is_heaptype():
+ if not t.is_heaptype() and not t.is_cpytype():
pol._remember_immutable(t, cached)
setattr(t, cached, t._lookup(attr))
return True
@@ -89,7 +89,7 @@
def attach_lookup_in_type_where(pol, t, attr):
cached = "cached_where_%s" % attr
- if not t.is_heaptype():
+ if not t.is_heaptype() and not t.is_cpytype():
pol._remember_immutable(t, cached)
setattr(t, cached, t._lookup_where(attr))
return True
@@ -177,14 +177,14 @@
CACHED_LOOKUP = """
def lookup_%(attr)s(space, w_obj, name):
w_type = space.type(w_obj)
- if not w_type.is_heaptype():
+ if not w_type.is_heaptype() and not w_type.is_cpytype():
return w_type.cached_%(attr)s
return w_type.lookup("%(attr)s")
"""
CACHED_LOOKUP_IN_TYPE_WHERE = """
def lookup_in_type_where_%(attr)s(space, w_type, name):
- if not w_type.is_heaptype():
+ if not w_type.is_heaptype() and not w_type.is_cpytype():
return w_type.cached_where_%(attr)s
return w_type.lookup_where("%(attr)s")
"""
Modified: pypy/trunk/pypy/translator/platform/__init__.py
==============================================================================
--- pypy/trunk/pypy/translator/platform/__init__.py (original)
+++ pypy/trunk/pypy/translator/platform/__init__.py Thu Apr 29 20:37:15 2010
@@ -70,7 +70,8 @@
env)
return ExecutionResult(returncode, stdout, stderr)
- def gen_makefile(self, cfiles, eci, exe_name=None, path=None):
+ def gen_makefile(self, cfiles, eci, exe_name=None, path=None,
+ shared=False):
raise NotImplementedError("Pure abstract baseclass")
def __repr__(self):
@@ -105,10 +106,8 @@
errorfile = outname.new(ext='errors')
errorfile.write(stderr, 'wb')
stderrlines = stderr.splitlines()
- for line in stderrlines[:50]:
+ for line in stderrlines:
log.ERROR(line)
- if len(stderrlines) > 50:
- log.ERROR('...')
raise CompilationError(stdout, stderr)
else:
for line in stderr.splitlines():
Modified: pypy/trunk/pypy/translator/platform/darwin.py
==============================================================================
--- pypy/trunk/pypy/translator/platform/darwin.py (original)
+++ pypy/trunk/pypy/translator/platform/darwin.py Thu Apr 29 20:37:15 2010
@@ -18,7 +18,7 @@
self.cc = cc
def _args_for_shared(self, args):
- return (self.shared_only + ['-bundle', '-undefined', 'dynamic_lookup']
+ return (self.shared_only + ['-dynamiclib', '-undefined', 'dynamic_lookup']
+ args)
def include_dirs_for_libffi(self):
Modified: pypy/trunk/pypy/translator/platform/linux.py
==============================================================================
--- pypy/trunk/pypy/translator/platform/linux.py (original)
+++ pypy/trunk/pypy/translator/platform/linux.py Thu Apr 29 20:37:15 2010
@@ -7,7 +7,7 @@
name = "linux"
link_flags = ['-pthread', '-lrt']
- cflags = ['-O3', '-pthread', '-fomit-frame-pointer', '-Wall']
+ cflags = ['-O3', '-pthread', '-fomit-frame-pointer', '-Wall', '-Wno-unused']
standalone_only = []
shared_only = ['-fPIC']
so_ext = 'so'
Modified: pypy/trunk/pypy/translator/platform/posix.py
==============================================================================
--- pypy/trunk/pypy/translator/platform/posix.py (original)
+++ pypy/trunk/pypy/translator/platform/posix.py Thu Apr 29 20:37:15 2010
@@ -36,6 +36,10 @@
cwd=str(cfile.dirpath()))
return oname
+ def _link_args_from_eci(self, eci, standalone):
+ eci = eci.convert_exportsymbols_to_file()
+ return Platform._link_args_from_eci(self, eci, standalone)
+
def _link(self, cc, ofiles, link_args, standalone, exe_name):
args = [str(ofile) for ofile in ofiles] + link_args
args += ['-o', str(exe_name)]
@@ -55,7 +59,9 @@
# strip compiler flags
return [entry[2:] for entry in out.split()]
- def gen_makefile(self, cfiles, eci, exe_name=None, path=None):
+ def gen_makefile(self, cfiles, eci, exe_name=None, path=None,
+ shared=False):
+ eci = eci.convert_exportsymbols_to_file()
cfiles = [py.path.local(f) for f in cfiles]
cfiles += [py.path.local(f) for f in eci.separate_module_files]
@@ -67,6 +73,16 @@
if exe_name is None:
exe_name = cfiles[0].new(ext=self.exe_ext)
+ linkflags = self.link_flags
+ if shared:
+ linkflags = self._args_for_shared(linkflags)
+
+ if shared:
+ libname = exe_name.new(ext='').basename
+ target_name = 'lib' + exe_name.new(ext=self.so_ext).basename
+ else:
+ target_name = exe_name.basename
+
m = GnuMakefile(path)
m.exe_name = exe_name
m.eci = eci
@@ -88,8 +104,8 @@
m.comment('automatically generated makefile')
definitions = [
('PYPYDIR', autopath.pypydir),
- ('TARGET', exe_name.basename),
- ('DEFAULT_TARGET', '$(TARGET)'),
+ ('TARGET', target_name),
+ ('DEFAULT_TARGET', exe_name.basename),
('SOURCES', rel_cfiles),
('OBJECTS', rel_ofiles),
('LIBS', self._libs(eci.libraries)),
@@ -97,7 +113,7 @@
('INCLUDEDIRS', self._includedirs(rel_includedirs)),
('CFLAGS', self.cflags),
('CFLAGSEXTRA', list(eci.compile_extra)),
- ('LDFLAGS', self.link_flags),
+ ('LDFLAGS', linkflags),
('LDFLAGSEXTRA', list(eci.link_extra)),
('CC', self.cc),
('CC_LINK', eci.use_cpp_linker and 'g++' or '$(CC)'),
@@ -115,6 +131,16 @@
for rule in rules:
m.rule(*rule)
+ if shared:
+ m.definition('SHARED_IMPORT_LIB', libname),
+ m.rule('main.c', '',
+ 'echo "'
+ 'int $(PYPY_MAIN_FUNCTION)(int, char*[]); '
+ 'int main(int argc, char* argv[]) '
+ '{ return $(PYPY_MAIN_FUNCTION)(argc, argv); }" > $@')
+ m.rule('$(DEFAULT_TARGET)', ['$(TARGET)', 'main.o'],
+ '$(CC_LINK) main.o -L. -l$(SHARED_IMPORT_LIB) -o $@')
+
return m
def execute_makefile(self, path_to_makefile, extra_opts=[]):
Modified: pypy/trunk/pypy/translator/platform/windows.py
==============================================================================
--- pypy/trunk/pypy/translator/platform/windows.py (original)
+++ pypy/trunk/pypy/translator/platform/windows.py Thu Apr 29 20:37:15 2010
@@ -186,7 +186,8 @@
raise CompilationError(stdout, stderr)
- def gen_makefile(self, cfiles, eci, exe_name=None, path=None):
+ def gen_makefile(self, cfiles, eci, exe_name=None, path=None,
+ shared=False):
cfiles = [py.path.local(f) for f in cfiles]
cfiles += [py.path.local(f) for f in eci.separate_module_files]
@@ -202,6 +203,17 @@
m.exe_name = exe_name
m.eci = eci
+ linkflags = self.link_flags
+ if shared:
+ linkflags = self._args_for_shared(linkflags) + [
+ '/EXPORT:$(PYPY_MAIN_FUNCTION)']
+
+ if shared:
+ so_name = exe_name.new(ext=self.so_ext)
+ target_name = so_name.basename
+ else:
+ target_name = exe_name.basename
+
def pypyrel(fpath):
rel = py.path.local(fpath).relto(pypypath)
if rel:
@@ -218,8 +230,8 @@
m.comment('automatically generated makefile')
definitions = [
('PYPYDIR', autopath.pypydir),
- ('TARGET', exe_name.basename),
- ('DEFAULT_TARGET', '$(TARGET)'),
+ ('TARGET', target_name),
+ ('DEFAULT_TARGET', exe_name.basename),
('SOURCES', rel_cfiles),
('OBJECTS', rel_ofiles),
('LIBS', self._libs(eci.libraries)),
@@ -227,12 +239,13 @@
('INCLUDEDIRS', self._includedirs(rel_includedirs)),
('CFLAGS', self.cflags),
('CFLAGSEXTRA', list(eci.compile_extra)),
- ('LDFLAGS', self.link_flags),
+ ('LDFLAGS', linkflags),
('LDFLAGSEXTRA', list(eci.link_extra)),
('CC', self.cc),
('CC_LINK', self.link),
('MASM', self.masm),
]
+
for args in definitions:
m.definition(*args)
@@ -253,6 +266,16 @@
'mt.exe -nologo -manifest $*.manifest -outputresource:$@;1',
])
+ if shared:
+ m.definition('SHARED_IMPORT_LIB', so_name.new(ext='lib').basename),
+ m.rule('main.c', '',
+ 'echo '
+ 'int $(PYPY_MAIN_FUNCTION)(int, char*[]); '
+ 'int main(int argc, char* argv[]) '
+ '{ return $(PYPY_MAIN_FUNCTION)(argc, argv); } > $@')
+ m.rule('$(DEFAULT_TARGET)', ['$(TARGET)', 'main.obj'],
+ '$(CC_LINK) /nologo main.obj $(SHARED_IMPORT_LIB) /out:$@')
+
return m
def execute_makefile(self, path_to_makefile, extra_opts=[]):
Modified: pypy/trunk/pypy/translator/test/test_unsimplify.py
==============================================================================
--- pypy/trunk/pypy/translator/test/test_unsimplify.py (original)
+++ pypy/trunk/pypy/translator/test/test_unsimplify.py Thu Apr 29 20:37:15 2010
@@ -9,6 +9,7 @@
def translate(func, argtypes, type_system="lltype"):
t = TranslationContext()
t.buildannotator().build_types(func, argtypes)
+ t.entry_point_graph = graphof(t, func)
t.buildrtyper(type_system=type_system).specialize()
return graphof(t, func), t
Modified: pypy/trunk/pypy/translator/tool/cbuild.py
==============================================================================
--- pypy/trunk/pypy/translator/tool/cbuild.py (original)
+++ pypy/trunk/pypy/translator/tool/cbuild.py Thu Apr 29 20:37:15 2010
@@ -260,24 +260,49 @@
d['separate_module_files'] += tuple(files)
return ExternalCompilationInfo(**d)
+ def convert_exportsymbols_to_file(self):
+ if not self.export_symbols:
+ return self
+ num = 0
+ while 1:
+ file_name = udir.join('dynamic-symbols-%i' % num)
+ num += 1
+ if not file_name.check():
+ break
+
+ f = file_name.open("w")
+ f.write("{\n")
+ for sym in self.export_symbols:
+ f.write("%s;\n" % (sym,))
+ f.write("};")
+ f.close()
+ d = self._copy_attributes()
+ d['link_extra'] += ("-Wl,--dynamic-list=" + str(file_name), )
+ d['export_symbols'] = ()
+ return ExternalCompilationInfo(**d)
+
+
def get_module_files(self):
d = self._copy_attributes()
files = d['separate_module_files']
d['separate_module_files'] = ()
return files, ExternalCompilationInfo(**d)
- def compile_shared_lib(self):
+ def compile_shared_lib(self, outputfilename=None):
self = self.convert_sources_to_files()
if not self.separate_module_files:
return self
- # find more or less unique name there
- basepath = py.path.local(self.separate_module_files[0]).dirpath()
- pth = basepath.join('externmod').new(ext=host.so_ext)
- num = 0
- while pth.check():
- pth = basepath.join('externmod_%d' % (num,)).new(ext=host.so_ext)
- num += 1
- lib = str(host.compile([], self, outputfilename=pth.purebasename,
+ if outputfilename is None:
+ # find more or less unique name there
+ basepath = py.path.local(self.separate_module_files[0]).dirpath()
+ pth = basepath.join('externmod').new(ext=host.so_ext)
+ num = 0
+ while pth.check():
+ pth = basepath.join(
+ 'externmod_%d' % (num,)).new(ext=host.so_ext)
+ num += 1
+ outputfilename=pth.purebasename
+ lib = str(host.compile([], self, outputfilename=outputfilename,
standalone=False))
d = self._copy_attributes()
d['libraries'] += (lib,)
Modified: pypy/trunk/pypy/translator/tool/test/test_cbuild.py
==============================================================================
--- pypy/trunk/pypy/translator/tool/test/test_cbuild.py (original)
+++ pypy/trunk/pypy/translator/tool/test/test_cbuild.py Thu Apr 29 20:37:15 2010
@@ -71,6 +71,17 @@
e = ExternalCompilationInfo()
assert e.convert_sources_to_files() is e
+ def test_convert_sources_to_c_files(self):
+ eci = ExternalCompilationInfo(
+ export_symbols=("foo", )
+ )
+ neweci = eci.convert_exportsymbols_to_file()
+ le = neweci.link_extra[-1]
+ assert "foo;" in file(le.rsplit("=", 1)[1]).read()
+ e = ExternalCompilationInfo()
+ assert e.convert_exportsymbols_to_file() is e
+
+
def test_make_shared_lib(self):
eci = ExternalCompilationInfo(
separate_module_sources = ['''
Modified: pypy/trunk/pypy/translator/unsimplify.py
==============================================================================
--- pypy/trunk/pypy/translator/unsimplify.py (original)
+++ pypy/trunk/pypy/translator/unsimplify.py Thu Apr 29 20:37:15 2010
@@ -168,7 +168,7 @@
if own_annhelper:
annhelper.finish()
- entry_point = translator.graphs[0]
+ entry_point = translator.entry_point_graph
v = copyvar(translator.annotator, entry_point.getreturnvar())
extrablock = Block([v])
v_none = varoftype(lltype.Void)
More information about the Pypy-commit
mailing list