[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