[pypy-svn] pypy commit 0e3099e3cc33: svn merge -r80002:80045 ../trunk

Bitbucket commits-noreply at bitbucket.org
Tue Dec 14 11:41:54 CET 2010


# HG changeset patch -- Bitbucket.org
# Project pypy
# URL http://bitbucket.org/pypy/pypy/overview
# User Amaury Forgeot d'Arc <amauryfa at gmail.com>
# Date 1292281506 0
# Node ID 0e3099e3cc33d9036ee057e45c1040add5299f97
# Parent  5385e710b33f751664f42473ecb7f498350fee66
svn merge -r80002:80045 ../trunk

--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -103,9 +103,9 @@ class Arguments(object):
             make_sure_not_resized(self.keywords_w)
 
         make_sure_not_resized(self.arguments_w)
-        if w_stararg is not None and space.is_true(w_stararg):
+        if w_stararg is not None:
             self._combine_starargs_wrapped(w_stararg)
-        if w_starstararg is not None and space.is_true(w_starstararg):
+        if w_starstararg is not None:
             self._combine_starstarargs_wrapped(w_starstararg)
             # if we have a call where **args are used at the callsite
             # we shouldn't let the JIT see the argument matching

--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -71,6 +71,8 @@ corresponding Unix manual entries for mo
 
     if hasattr(os, 'chown'):
         interpleveldefs['chown'] = 'interp_posix.chown'
+    if hasattr(os, 'lchown'):
+        interpleveldefs['lchown'] = 'interp_posix.lchown'
     if hasattr(os, 'ftruncate'):
         interpleveldefs['ftruncate'] = 'interp_posix.ftruncate'
     if hasattr(os, 'fsync'):
@@ -86,6 +88,8 @@ corresponding Unix manual entries for mo
     if hasattr(os, 'kill') and sys.platform != 'win32':
         interpleveldefs['kill'] = 'interp_posix.kill'
         interpleveldefs['abort'] = 'interp_posix.abort'
+    if hasattr(os, 'killpg'):
+        interpleveldefs['killpg'] = 'interp_posix.killpg'
     if hasattr(os, 'getpid'):
         interpleveldefs['getpid'] = 'interp_posix.getpid'
     if hasattr(os, 'link'):
@@ -117,6 +121,12 @@ corresponding Unix manual entries for mo
         interpleveldefs['ttyname'] = 'interp_posix.ttyname'
     if hasattr(os, 'getloadavg'):
         interpleveldefs['getloadavg'] = 'interp_posix.getloadavg'
+    if hasattr(os, 'mkfifo'):
+        interpleveldefs['mkfifo'] = 'interp_posix.mkfifo'
+    if hasattr(os, 'mknod'):
+        interpleveldefs['mknod'] = 'interp_posix.mknod'
+    if hasattr(os, 'nice'):
+        interpleveldefs['nice'] = 'interp_posix.nice'
 
     for name in ['setsid', 'getuid', 'geteuid', 'getgid', 'getegid', 'setuid',
                  'seteuid', 'setgid', 'setegid', 'getpgrp', 'setpgrp',

--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -16,6 +16,7 @@ class TestW_DictObject:
         space = self.space
         d = self.space.newdict()
         assert not self.space.is_true(d)
+        assert d.r_dict_content is None
 
     def test_nonempty(self):
         space = self.space

--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -11,27 +11,17 @@
  * It is needed to have RPyThreadStaticTLS, too. */
 #include "thread.h"
 
+extern char *_LLstacktoobig_stack_start;
+
 void LL_stack_unwind(void);
-int LL_stack_too_big_slowpath(void);
+char LL_stack_too_big_slowpath(long);    /* returns 0 (ok) or 1 (too big) */
 
-extern volatile char *_LLstacktoobig_stack_base_pointer;
-extern long _LLstacktoobig_stack_min;
-extern long _LLstacktoobig_stack_max;
+/* some macros referenced from pypy.rlib.rstack */
+#define OP_STACK_CURRENT(r)  r = (long)&r
+#define LL_stack_get_start() ((long)_LLstacktoobig_stack_start)
+#define LL_stack_get_length() MAX_STACK_SIZE
+#define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start)  /* JIT */
 
-static int LL_stack_too_big(void)
-{
-	/* The fast path of stack_too_big, called extremely often.
-	   Making it static makes an *inlinable* copy of this small
-	   function's implementation in each compilation unit. */
-	char local;
-	long diff = &local - _LLstacktoobig_stack_base_pointer;
-	/* common case: we are still in the same thread as last time
-	   we checked, and still in the allowed part of the stack */
-	return ((diff < _LLstacktoobig_stack_min ||
-		 diff > _LLstacktoobig_stack_max)
-		/* if not, call the slow path */
-		&& LL_stack_too_big_slowpath());
-}
 
 #ifdef __GNUC__
 #  define PYPY_INHIBIT_TAIL_CALL()   asm("/* inhibit_tail_call */")
@@ -61,68 +51,75 @@ long PYPY_NOINLINE _LL_stack_growing_dir
 		return &local - parent;
 }
 
-volatile char *_LLstacktoobig_stack_base_pointer = NULL;
-long _LLstacktoobig_stack_min = 0;
-long _LLstacktoobig_stack_max = 0;
-RPyThreadStaticTLS _LLstacktoobig_stack_base_pointer_key;
+char *_LLstacktoobig_stack_start = NULL;
+int stack_direction = 0;
+RPyThreadStaticTLS start_tls_key;
 
-int LL_stack_too_big_slowpath(void)
+char LL_stack_too_big_slowpath(long current)
 {
-	char local;
 	long diff;
-	char *baseptr;
-	/* Check that the stack is less than MAX_STACK_SIZE bytes bigger
-	   than the value recorded in stack_base_pointer.  The base
-	   pointer is updated to the current value if it is still NULL
-	   or if we later find a &local that is below it.  The real
-	   stack base pointer is stored in thread-local storage, but we
-	   try to minimize its overhead by keeping a local copy in
-	   stack_pointer_pointer. */
+	char *baseptr, *curptr = (char*)current;
 
-	if (_LLstacktoobig_stack_min == _LLstacktoobig_stack_max /* == 0 */) {
+	/* The stack_start variable is updated to match the current value
+	   if it is still 0 or if we later find a 'curptr' position
+	   that is below it.  The real stack_start pointer is stored in
+	   thread-local storage, but we try to minimize its overhead by
+	   keeping a local copy in _LLstacktoobig_stack_start. */
+
+	if (stack_direction == 0) {
 		/* not initialized */
 		/* XXX We assume that initialization is performed early,
 		   when there is still only one thread running.  This
 		   allows us to ignore race conditions here */
-		char *errmsg = RPyThreadStaticTLS_Create(
-			&_LLstacktoobig_stack_base_pointer_key);
+		char *errmsg = RPyThreadStaticTLS_Create(&start_tls_key);
 		if (errmsg) {
 			/* XXX should we exit the process? */
 			fprintf(stderr, "Internal PyPy error: %s\n", errmsg);
 			return 1;
 		}
 		if (_LL_stack_growing_direction(NULL) > 0)
-			_LLstacktoobig_stack_max = MAX_STACK_SIZE;
+			stack_direction = +1;
 		else
-			_LLstacktoobig_stack_min = -MAX_STACK_SIZE;
+			stack_direction = -1;
 	}
 
-	baseptr = (char *) RPyThreadStaticTLS_Get(
-			_LLstacktoobig_stack_base_pointer_key);
+	baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key);
 	if (baseptr != NULL) {
-		diff = &local - baseptr;
-		if (_LLstacktoobig_stack_min <= diff &&
-		    diff <= _LLstacktoobig_stack_max) {
-			/* within bounds */
-			_LLstacktoobig_stack_base_pointer = baseptr;
+		diff = curptr - baseptr;
+		if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) {
+			/* within bounds, probably just had a thread switch */
+			_LLstacktoobig_stack_start = baseptr;
 			return 0;
 		}
 
-		if ((_LLstacktoobig_stack_min == 0 && diff < 0) ||
-		    (_LLstacktoobig_stack_max == 0 && diff > 0)) {
-			/* we underflowed the stack, which means that
-			   the initial estimation of the stack base must
-			   be revised (see below) */
+		if (stack_direction > 0) {
+			if (diff < 0 && diff > -MAX_STACK_SIZE)
+				;           /* stack underflow */
+			else
+				return 1;   /* stack overflow (probably) */
 		}
 		else {
-			return 1;   /* stack overflow */
+			if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE)
+				;           /* stack underflow */
+			else
+				return 1;   /* stack overflow (probably) */
 		}
+		/* else we underflowed the stack, which means that
+		   the initial estimation of the stack base must
+		   be revised */
 	}
 
 	/* update the stack base pointer to the current value */
-	baseptr = &local;
-	RPyThreadStaticTLS_Set(_LLstacktoobig_stack_base_pointer_key, baseptr);
-	_LLstacktoobig_stack_base_pointer = baseptr;
+	if (stack_direction > 0) {
+		/* the valid range is [curptr:curptr+MAX_STACK_SIZE] */
+		baseptr = curptr;
+	}
+	else {
+		/* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */
+		baseptr = curptr - MAX_STACK_SIZE + 1;
+	}
+	RPyThreadStaticTLS_Set(start_tls_key, baseptr);
+	_LLstacktoobig_stack_start = baseptr;
 	return 0;
 }
 

--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -56,9 +56,8 @@ class W_DictMultiObject(W_Object):
         else:
             if w_type is None:
                 w_type = space.w_dict
-            w_self = space.allocate_instance(W_DictMultiObject, w_type)
-            W_DictMultiObject.__init__(w_self, space)
-            w_self.initialize_as_rdict()
+            w_self = space.allocate_instance(EmptyDictImplementation, w_type)
+            EmptyDictImplementation.__init__(w_self, space)
             return w_self
 
     def __init__(self, space):
@@ -108,7 +107,7 @@ class W_DictMultiObject(W_Object):
     def impl_setitem_str(self, key, w_value):
         raise NotImplementedError("abstract base class")
 
-    def impl_setitem(self,  w_key, w_value):
+    def impl_setitem(self, w_key, w_value):
         raise NotImplementedError("abstract base class")
 
     def impl_delitem(self, w_key):
@@ -409,6 +408,45 @@ class WaryDictImplementation(StrDictImpl
         return self.shadowed[i]
 
 
+class EmptyDictImplementation(W_DictMultiObject):
+    def __init__(self, space):
+        self.space = space
+
+    def impl_setitem(self, w_key, w_value):
+        self._as_rdict().impl_fallback_setitem(w_key, w_value)
+
+    def impl_setitem_str(self, key, w_value):
+        self._as_rdict().impl_fallback_setitem_str(key, w_value)
+
+    def impl_delitem(self, w_key):
+        raise KeyError
+
+    def impl_length(self):
+        return 0
+
+    def impl_getitem_str(self, key):
+        return None
+
+    def impl_getitem(self, w_key):
+        # in case the key is unhashable, try to hash it
+        self.space.hash(w_key)
+        # return None anyway
+        return None
+
+    def impl_iter(self):
+        # XXX I guess it's not important to be fast in this case?
+        return self._as_rdict().impl_fallback_iter()
+
+    def impl_clear(self):
+        self.r_dict_content = None
+
+    def _as_rdict(self):
+        r_dict_content = self.initialize_as_rdict()
+        return self
+
+    def _clear_fields(self):
+        pass
+
 class RDictIteratorImplementation(IteratorImplementation):
     def __init__(self, space, dictimplementation):
         IteratorImplementation.__init__(self, space, dictimplementation)

--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -101,7 +101,6 @@ class X86FrameManager(FrameManager):
             return StackLoc(i, get_ebp_ofs(i), 1, box_type)
 
 class RegAlloc(object):
-    exc = False
 
     def __init__(self, assembler, translate_support_code=False):
         assert isinstance(translate_support_code, bool)
@@ -428,7 +427,10 @@ class RegAlloc(object):
         locs = [self.loc(op.getarg(i)) for i in range(op.numargs())]
         locs_are_ref = [op.getarg(i).type == REF for i in range(op.numargs())]
         fail_index = self.assembler.cpu.get_fail_descr_number(op.getdescr())
-        self.assembler.generate_failure(fail_index, locs, self.exc,
+        # note: no exception should currently be set in llop.get_exception_addr
+        # even if this finish may be an exit_frame_with_exception (in this case
+        # the exception instance is in locs[0]).
+        self.assembler.generate_failure(fail_index, locs, False,
                                         locs_are_ref)
         self.possibly_free_vars_for_op(op)
 

--- a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
+++ b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
@@ -3,6 +3,7 @@ from pypy.jit.backend.llsupport.asmmemmg
 from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
 from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import debug
 
 
 def test_get_index():
@@ -184,9 +185,11 @@ class TestAsmMemoryManager:
 
 def test_blockbuildermixin(translated=True):
     mc = BlockBuilderMixin(translated)
+    writtencode = []
     for i in range(mc.SUBBLOCK_SIZE * 2 + 3):
         assert mc.get_relative_pos() == i
         mc.writechar(chr(i % 255))
+        writtencode.append(chr(i % 255))
     if translated:
         assert mc._cursubindex == 3
         assert mc._cursubblock
@@ -196,16 +199,26 @@ def test_blockbuildermixin(translated=Tr
     #
     for i in range(0, mc.SUBBLOCK_SIZE * 2 + 3, 2):
         mc.overwrite(i, chr((i + 63) % 255))
+        writtencode[i] = chr((i + 63) % 255)
     #
     p = lltype.malloc(rffi.CCHARP.TO, mc.SUBBLOCK_SIZE * 2 + 3, flavor='raw')
     addr = rffi.cast(lltype.Signed, p)
     mc.copy_to_raw_memory(addr)
     #
     for i in range(mc.SUBBLOCK_SIZE * 2 + 3):
-        if i & 1:
-            assert p[i] == chr(i % 255)
-        else:
-            assert p[i] == chr((i + 63) % 255)
+        assert p[i] == writtencode[i]
+    #
+    debug._log = debug.DebugLog()
+    try:
+        mc._dump(addr, 'test-logname-section')
+        log = list(debug._log)
+    finally:
+        debug._log = None
+    encoded = ''.join(writtencode).encode('hex').upper()
+    ataddr = '@%x' % addr
+    assert log == [('test-logname-section',
+                    [('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
+    #
     lltype.free(p, flavor='raw')
 
 def test_blockbuildermixin2():

--- a/pypy/jit/backend/llsupport/asmmemmgr.py
+++ b/pypy/jit/backend/llsupport/asmmemmgr.py
@@ -2,6 +2,8 @@ import sys
 from pypy.rlib.rarithmetic import intmask, r_uint, LONG_BIT
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import rmmap
+from pypy.rlib.debug import debug_start, debug_print, debug_stop
+from pypy.rlib.debug import have_debug_prints
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 
 
@@ -265,6 +267,31 @@ class BlockBuilderMixin(object):
             targetindex -= self.SUBBLOCK_SIZE
         assert not block
 
+    def _dump(self, addr, logname, backend=None):
+        debug_start(logname)
+        if have_debug_prints():
+            #
+            if backend is not None:
+                debug_print('BACKEND', backend)
+            #
+            from pypy.jit.backend.hlinfo import highleveljitinfo
+            if highleveljitinfo.sys_executable:
+                debug_print('SYS_EXECUTABLE', highleveljitinfo.sys_executable)
+            #
+            HEX = '0123456789ABCDEF'
+            dump = []
+            src = rffi.cast(rffi.CCHARP, addr)
+            for p in range(self.get_relative_pos()):
+                o = ord(src[p])
+                dump.append(HEX[o >> 4])
+                dump.append(HEX[o & 15])
+            debug_print('CODE_DUMP',
+                        '@%x' % addr,
+                        '+0 ',     # backwards compatibility
+                        ''.join(dump))
+            #
+        debug_stop(logname)
+
     def materialize(self, asmmemmgr, allblocks, gcrootmap=None):
         size = self.get_relative_pos()
         malloced = asmmemmgr.malloc(size, size)

--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -99,7 +99,7 @@ class UnicodeTraits:
         return 'll_os.ll_os_w' + name
 
 def registering_str_unicode(posixfunc, condition=True):
-    if not condition:
+    if not condition or posixfunc is None:
         return registering(None, condition=False)
 
     func_name = posixfunc.__name__
@@ -1129,6 +1129,19 @@ class RegisterOs(BaseLazyRegistering):
         return extdef([str, int, int], None, "ll_os.ll_os_chown",
                       llimpl=os_chown_llimpl)
 
+    @registering_if(os, 'lchown')
+    def register_os_lchown(self):
+        os_lchown = self.llexternal('lchown',[rffi.CCHARP, rffi.INT, rffi.INT],
+                                    rffi.INT)
+
+        def os_lchown_llimpl(path, uid, gid):
+            res = os_lchown(path, uid, gid)
+            if res == -1:
+                raise OSError(rposix.get_errno(), "os_lchown failed")
+
+        return extdef([str, int, int], None, "ll_os.ll_os_lchown",
+                      llimpl=os_lchown_llimpl)
+
     @registering_if(os, 'readlink')
     def register_os_readlink(self):
         os_readlink = self.llexternal('readlink',
@@ -1323,6 +1336,33 @@ class RegisterOs(BaseLazyRegistering):
         return extdef([traits.str, traits.str], s_None, llimpl=rename_llimpl,
                       export_name=traits.ll_os_name('rename'))
 
+    @registering_str_unicode(getattr(os, 'mkfifo', None))
+    def register_os_mkfifo(self, traits):
+        os_mkfifo = self.llexternal(traits.posix_function_name('mkfifo'),
+                                    [traits.CCHARP, rffi.MODE_T], rffi.INT)
+
+        def mkfifo_llimpl(path, mode):
+            res = rffi.cast(lltype.Signed, os_mkfifo(path, mode))
+            if res < 0:
+                raise OSError(rposix.get_errno(), "os_mkfifo failed")
+
+        return extdef([traits.str, int], s_None, llimpl=mkfifo_llimpl,
+                      export_name=traits.ll_os_name('mkfifo'))
+
+    @registering_str_unicode(getattr(os, 'mknod', None))
+    def register_os_mknod(self, traits):
+        os_mknod = self.llexternal(traits.posix_function_name('mknod'),
+                                   [traits.CCHARP, rffi.MODE_T, rffi.INT],
+                                   rffi.INT)      # xxx: actually ^^^ dev_t
+
+        def mknod_llimpl(path, mode, dev):
+            res = rffi.cast(lltype.Signed, os_mknod(path, mode, dev))
+            if res < 0:
+                raise OSError(rposix.get_errno(), "os_mknod failed")
+
+        return extdef([traits.str, int, int], s_None, llimpl=mknod_llimpl,
+                      export_name=traits.ll_os_name('mknod'))
+
     @registering(os.umask)
     def register_os_umask(self):
         os_umask = self.llexternal(underscore_on_windows+'umask', [rffi.MODE_T], rffi.MODE_T)
@@ -1348,6 +1388,20 @@ class RegisterOs(BaseLazyRegistering):
         return extdef([int, int], s_None, llimpl=kill_llimpl,
                       export_name="ll_os.ll_os_kill")
 
+    @registering_if(os, 'killpg')
+    def register_os_killpg(self):
+        os_killpg = self.llexternal('killpg', [rffi.INT, rffi.INT],
+                                    rffi.INT)
+
+        def killpg_llimpl(pid, sig):
+            res = rffi.cast(lltype.Signed, os_killpg(rffi.cast(rffi.INT, pid),
+                                                     rffi.cast(rffi.INT, sig)))
+            if res < 0:
+                raise OSError(rposix.get_errno(), "os_killpg failed")
+
+        return extdef([int, int], s_None, llimpl=killpg_llimpl,
+                      export_name="ll_os.ll_os_killpg")
+
     @registering_if(os, 'link')
     def register_os_link(self):
         os_link = self.llexternal('link', [rffi.CCHARP, rffi.CCHARP],
@@ -1444,6 +1498,25 @@ class RegisterOs(BaseLazyRegistering):
         return extdef([int], s_None, llimpl=_exit_llimpl,
                       export_name="ll_os.ll_os__exit")
 
+    @registering_if(os, 'nice')
+    def register_os_nice(self):
+        os_nice = self.llexternal('nice', [rffi.INT], rffi.INT)
+
+        def nice_llimpl(inc):
+            # Assume that the system provides a standard-compliant version
+            # of nice() that returns the new priority.  Nowadays, FreeBSD
+            # might be the last major non-compliant system (xxx check me).
+            rposix.set_errno(0)
+            res = rffi.cast(lltype.Signed, os_nice(inc))
+            if res == -1:
+                err = rposix.get_errno()
+                if err != 0:
+                    raise OSError(err, "os_nice failed")
+            return res
+
+        return extdef([int], int, llimpl=nice_llimpl,
+                      export_name="ll_os.ll_os_nice")
+
 # --------------------------- os.stat & variants ---------------------------
 
     @registering(os.fstat)

--- a/pypy/translator/c/test/test_extfunc.py
+++ b/pypy/translator/c/test/test_extfunc.py
@@ -4,6 +4,7 @@ import os, time, sys
 from pypy.tool.udir import udir
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.translator.c.test.test_genc import compile
+from pypy.translator.c.test.test_standalone import StandaloneTests
 posix = __import__(os.name)
 
 # note: clock synchronizes itself!
@@ -404,6 +405,28 @@ def test_os_rename():
     assert os.path.exists(tmpfile2)
     assert not os.path.exists(tmpfile1)
 
+if hasattr(os, 'mkfifo'):
+    def test_os_mkfifo():
+        tmpfile = str(udir.join('test_os_mkfifo.txt'))
+        def does_stuff():
+            os.mkfifo(tmpfile, 0666)
+        f1 = compile(does_stuff, [])
+        f1()
+        import stat
+        st = os.lstat(tmpfile)
+        assert stat.S_ISFIFO(st.st_mode)
+
+if hasattr(os, 'mknod'):
+    def test_os_mknod():
+        import stat
+        tmpfile = str(udir.join('test_os_mknod.txt'))
+        def does_stuff():
+            os.mknod(tmpfile, 0600 | stat.S_IFIFO, 0)
+        f1 = compile(does_stuff, [])
+        f1()
+        st = os.lstat(tmpfile)
+        assert stat.S_ISFIFO(st.st_mode)
+
 def test_os_umask():
     def does_stuff():
         mask1 = os.umask(0660)
@@ -516,6 +539,62 @@ elif hasattr(os, 'waitpid'):
         # for what reason do they want us to shift by 8? See the doc
         assert status1 >> 8 == 4
 
+if hasattr(os, 'kill'):
+    def test_kill_to_send_sigusr1():
+        import signal
+        from pypy.module.signal import interp_signal
+        def does_stuff():
+            interp_signal.pypysig_setflag(signal.SIGUSR1)
+            os.kill(os.getpid(), signal.SIGUSR1)
+            interp_signal.pypysig_ignore(signal.SIGUSR1)
+            while True:
+                n = interp_signal.pypysig_poll()
+                if n < 0 or n == signal.SIGUSR1:
+                    break
+            return n
+        f1 = compile(does_stuff, [])
+        got_signal = f1()
+        assert got_signal == signal.SIGUSR1
+
+if hasattr(os, 'killpg'):
+    def test_killpg():
+        import signal
+        from pypy.module.signal import interp_signal
+        def does_stuff():
+            interp_signal.pypysig_setflag(signal.SIGUSR1)
+            os.killpg(os.getpgrp(), signal.SIGUSR1)
+            interp_signal.pypysig_ignore(signal.SIGUSR1)
+            while True:
+                n = interp_signal.pypysig_poll()
+                if n < 0 or n == signal.SIGUSR1:
+                    break
+            return n
+        f1 = compile(does_stuff, [])
+        got_signal = f1()
+        assert got_signal == signal.SIGUSR1
+
+if hasattr(os, 'chown') and hasattr(os, 'lchown'):
+    def test_os_chown_lchown():
+        path1 = udir.join('test_os_chown_lchown-1.txt')
+        path2 = udir.join('test_os_chown_lchown-2.txt')
+        path1.write('foobar')
+        path2.mksymlinkto('some-broken-symlink')
+        tmpfile1 = str(path1)
+        tmpfile2 = str(path2)
+        def does_stuff():
+            # xxx not really a test, just checks that they are callable
+            os.chown(tmpfile1, os.getuid(), os.getgid())
+            os.lchown(tmpfile1, os.getuid(), os.getgid())
+            os.lchown(tmpfile2, os.getuid(), os.getgid())
+            try:
+                os.chown(tmpfile2, os.getuid(), os.getgid())
+            except OSError:
+                pass
+            else:
+                raise AssertionError("os.chown(broken symlink) should raise")
+        f1 = compile(does_stuff, [])
+        f1()
+
 # ____________________________________________________________
 
 def _real_getenv(var):
@@ -783,3 +862,19 @@ if hasattr(os, 'fchdir'):
         finally:
             os.chdir(localdir)
         assert res == True
+
+# ____________________________________________________________
+
+
+class TestExtFuncStandalone(StandaloneTests):
+
+    if hasattr(os, 'nice'):
+        def test_os_nice(self):
+            def does_stuff(argv):
+                res =  os.nice(3)
+                print 'os.nice returned', res
+                return 0
+            t, cbuilder = self.compile(does_stuff)
+            data = cbuilder.cmdexec('')
+            res = os.nice(0) + 3
+            assert data.startswith('os.nice returned %d\n' % res)

--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -98,6 +98,39 @@ def get_subversion_info(space):
                            space.wrap(svnbranch),
                            space.wrap(str(svn_revision()))])
 
+def get_mercurial_info(space):
+    '''Obtain Mercurial version information by invoking the 'hg' command.'''
+    # TODO: support extracting from .hg_archival.txt
+    import py
+    from subprocess import Popen, PIPE
+
+    pypyroot = os.path.abspath(os.path.join(pypydir, '..'))
+    hgexe = py.path.local.sysfind('hg')
+
+    if hgexe and os.path.isdir(os.path.join(pypyroot, '.hg')):
+        env = dict(os.environ)
+        # get Mercurial into scripting mode
+        env['HGPLAIN'] = '1'
+        # disable user configuration, extensions, etc.
+        env['HGRCPATH'] = os.devnull
+
+        p = Popen([str(hgexe), 'id', '-i', pypyroot], stdout=PIPE, env=env)
+        hgid = p.stdout.read().strip()
+
+        p = Popen([str(hgexe), 'id', '-t', pypyroot], stdout=PIPE, env=env)
+        hgtag = p.stdout.read().strip().split()[0]
+
+        if hgtag == 'tip':
+            # use the branch instead
+            p = Popen([str(hgexe), 'id', '-b', pypyroot], stdout=PIPE, env=env)
+            hgtag = p.stdout.read().strip()
+
+        return space.newtuple([space.wrap('PyPy'),
+                               space.wrap(hgtag),
+                               space.wrap(hgid)])
+    else:
+        return space.w_None
+
 def tuple2hex(ver):
     d = {'alpha':     0xA,
          'beta':      0xB,

--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -161,6 +161,7 @@ def ftruncate(space, fd, length):
 ftruncate.unwrap_spec = [ObjSpace, "c_int", r_longlong]
 
 def fsync(space, w_fd):
+    """Force write of file with filedescriptor to disk."""
     fd = space.c_filedescriptor_w(w_fd)
     try:
         os.fsync(fd)
@@ -169,6 +170,8 @@ def fsync(space, w_fd):
 fsync.unwrap_spec = [ObjSpace, W_Root]
 
 def fdatasync(space, w_fd):
+    """Force write of file with filedescriptor to disk.
+Does not force update of metadata."""
     fd = space.c_filedescriptor_w(w_fd)
     try:
         os.fdatasync(fd)
@@ -177,6 +180,8 @@ def fdatasync(space, w_fd):
 fdatasync.unwrap_spec = [ObjSpace, W_Root]
 
 def fchdir(space, w_fd):
+    """Change to the directory of the given file descriptor.  fildes must be
+opened on a directory, not a file."""
     fd = space.c_filedescriptor_w(w_fd)
     try:
         os.fchdir(fd)
@@ -557,6 +562,27 @@ def rename(space, w_old, w_new):
         raise wrap_oserror(space, e) 
 rename.unwrap_spec = [ObjSpace, W_Root, W_Root]
 
+def mkfifo(space, w_filename, mode=0666):
+    """Create a FIFO (a POSIX named pipe)."""
+    try:
+        dispatch_filename(rposix.mkfifo)(space, w_filename, mode)
+    except OSError, e: 
+        raise wrap_oserror2(space, e, w_filename)
+mkfifo.unwrap_spec = [ObjSpace, W_Root, "c_int"]
+
+def mknod(space, w_filename, mode=0600, device=0):
+    """Create a filesystem node (file, device special file or named pipe)
+named filename. mode specifies both the permissions to use and the
+type of node to be created, being combined (bitwise OR) with one of
+S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,
+device defines the newly created device special file (probably using
+os.makedev()), otherwise it is ignored."""
+    try:
+        dispatch_filename(rposix.mknod)(space, w_filename, mode, device)
+    except OSError, e: 
+        raise wrap_oserror2(space, e, w_filename)
+mknod.unwrap_spec = [ObjSpace, W_Root, "c_int", "c_int"]
+
 def umask(space, mask):
     "Set the current numeric umask and return the previous umask."
     prevmask = os.umask(mask)
@@ -580,6 +606,14 @@ def kill(space, pid, sig):
         raise wrap_oserror(space, e)
 kill.unwrap_spec = [ObjSpace, "c_int", "c_int"]
 
+def killpg(space, pgid, sig):
+    "Kill a process group with a signal."
+    try:
+        os.killpg(pgid, sig)
+    except OSError, e:
+        raise wrap_oserror(space, e)
+killpg.unwrap_spec = [ObjSpace, "c_int", "c_int"]
+
 def abort(space):
     """Abort the interpreter immediately.  This 'dumps core' or otherwise fails
 in the hardest way possible on the hosting operating system."""
@@ -1034,6 +1068,14 @@ def chown(space, path, uid, gid):
     return space.w_None
 chown.unwrap_spec = [ObjSpace, str, "c_nonnegint", "c_nonnegint"]
 
+def lchown(space, path, uid, gid):
+    try:
+        os.lchown(path, uid, gid)
+    except OSError, e:
+        raise wrap_oserror(space, e, path)
+    return space.w_None
+lchown.unwrap_spec = [ObjSpace, str, "c_nonnegint", "c_nonnegint"]
+
 def getloadavg(space):
     try:
         load = os.getloadavg()
@@ -1045,6 +1087,15 @@ def getloadavg(space):
                            space.wrap(load[2])])
 getloadavg.unwrap_spec = [ObjSpace]
 
+def nice(space, inc):
+    "Decrease the priority of process by inc and return the new priority."
+    try:
+        res = os.nice(inc)
+    except OSError, e:
+        raise wrap_oserror(space, e)
+    return space.wrap(res)
+nice.unwrap_spec = [ObjSpace, "c_int"]
+
 if _WIN:
     from pypy.rlib import rwin32
 

--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1294,6 +1294,10 @@ class MetaInterpStaticData(object):
             num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
             setattr(self.cpu, 'done_with_this_frame_%s_v' % name, num)
         #
+        tokens = self.loop_tokens_exit_frame_with_exception_ref
+        num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
+        self.cpu.exit_frame_with_exception_v = num
+        #
         self.globaldata = MetaInterpGlobalData(self)
 
     def _setup_once(self):

--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -672,6 +672,67 @@ class AppTestPosix:
             f.close()
             os.chown(self.path, os.getuid(), os.getgid())
 
+    if hasattr(os, 'lchown'):
+        def test_lchown(self):
+            os = self.posix
+            os.unlink(self.path)
+            raises(OSError, os.lchown, self.path, os.getuid(), os.getgid())
+            os.symlink('foobar', self.path)
+            os.lchown(self.path, os.getuid(), os.getgid())
+
+    if hasattr(os, 'mkfifo'):
+        def test_mkfifo(self):
+            os = self.posix
+            os.mkfifo(self.path2 + 'test_mkfifo', 0666)
+            st = os.lstat(self.path2 + 'test_mkfifo')
+            import stat
+            assert stat.S_ISFIFO(st.st_mode)
+
+    if hasattr(os, 'mknod'):
+        def test_mknod(self):
+            import stat
+            os = self.posix
+            # not very useful: os.mknod() without specifying 'mode'
+            os.mknod(self.path2 + 'test_mknod-1')
+            st = os.lstat(self.path2 + 'test_mknod-1')
+            assert stat.S_ISREG(st.st_mode)
+            # os.mknod() with S_IFIFO
+            os.mknod(self.path2 + 'test_mknod-2', 0600 | stat.S_IFIFO)
+            st = os.lstat(self.path2 + 'test_mknod-2')
+            assert stat.S_ISFIFO(st.st_mode)
+
+        def test_mknod_with_ifchr(self):
+            # os.mknod() with S_IFCHR
+            # -- usually requires root priviledges --
+            os = self.posix
+            if hasattr(os.lstat('.'), 'st_rdev'):
+                import stat
+                try:
+                    os.mknod(self.path2 + 'test_mknod-3', 0600 | stat.S_IFCHR,
+                             0x105)
+                except OSError, e:
+                    skip("os.mknod() with S_IFCHR: got %r" % (e,))
+                else:
+                    st = os.lstat(self.path2 + 'test_mknod-3')
+                    assert stat.S_ISCHR(st.st_mode)
+                    assert st.st_rdev == 0x105
+
+    if hasattr(os, 'nice') and hasattr(os, 'fork') and hasattr(os, 'waitpid'):
+        def test_nice(self):
+            os = self.posix
+            myprio = os.nice(0)
+            #
+            pid = os.fork()
+            if pid == 0:    # in the child
+                res = os.nice(3)
+                os._exit(res)
+            #
+            pid1, status1 = os.waitpid(pid, 0)
+            assert pid1 == pid
+            assert os.WIFEXITED(status1)
+            assert os.WEXITSTATUS(status1) == myprio + 3
+
+
 class AppTestEnvironment(object):
     def setup_class(cls): 
         cls.space = space 

--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -64,6 +64,7 @@ class Module(MixedModule):
         'pypy_version_info'     : 'version.get_pypy_version_info(space)',
         'pypy_svn_url'          : 'version.get_svn_url(space)',
         'subversion'            : 'version.get_subversion_info(space)',
+        '_mercurial'            : 'version.get_mercurial_info(space)',
         'hexversion'            : 'version.get_hexversion(space)',
 
         'displayhook'           : 'hook.displayhook', 

--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -347,6 +347,8 @@ def common_modes(group):
     INSN_rr = insn(rex_w, chr(base+1), register(2,8), register(1,1), '\xC0')
     INSN_br = insn(rex_w, chr(base+1), register(2,8), stack_bp(1))
     INSN_rb = insn(rex_w, chr(base+3), register(1,8), stack_bp(2))
+    INSN_rm = insn(rex_w, chr(base+3), register(1,8), mem_reg_plus_const(2))
+    INSN_rj = insn(rex_w, chr(base+3), register(1,8), '\x05', immediate(2))
     INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b'))
     INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2))
 
@@ -364,7 +366,7 @@ def common_modes(group):
             INSN_bi32(mc, offset, immed)
     INSN_bi._always_inline_ = True      # try to constant-fold single_byte()
 
-    return INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br
+    return INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj
 
 def select_8_or_32_bit_immed(insn_8, insn_32):
     def INSN(*args):
@@ -442,24 +444,22 @@ class AbstractX86CodeBuilder(object):
 
     # ------------------------------ Arithmetic ------------------------------
 
-    ADD_ri, ADD_rr, ADD_rb, _, _ = common_modes(0)
-    OR_ri,  OR_rr,  OR_rb,  _, _ = common_modes(1)
-    AND_ri, AND_rr, AND_rb, _, _ = common_modes(4)
-    SUB_ri, SUB_rr, SUB_rb, _, _ = common_modes(5)
-    XOR_ri, XOR_rr, XOR_rb, _, _ = common_modes(6)
-    CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br = common_modes(7)
+    ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj = common_modes(0)
+    OR_ri,  OR_rr,  OR_rb,  _, _, OR_rm,  OR_rj  = common_modes(1)
+    AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj = common_modes(4)
+    SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj = common_modes(5)
+    XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj = common_modes(6)
+    CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj = common_modes(7)
 
     CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b'))
     CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
     CMP_mi = select_8_or_32_bit_immed(CMP_mi8, CMP_mi32)
 
-    CMP_rm = insn(rex_w, '\x3B', register(1, 8), mem_reg_plus_const(2))
     CMP_mr = insn(rex_w, '\x39', register(2, 8), mem_reg_plus_const(1))
 
     CMP_ji8 = insn(rex_w, '\x83', '\x3D', immediate(1), immediate(2, 'b'))
     CMP_ji32 = insn(rex_w, '\x81', '\x3D', immediate(1), immediate(2))
     CMP_ji = select_8_or_32_bit_immed(CMP_ji8, CMP_ji32)
-    CMP_rj = insn(rex_w, '\x3B', register(1, 8), '\x05', immediate(2))
 
     CMP32_mi = insn(rex_nw, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
 

--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -6,21 +6,22 @@ RPython-compliant way, intended mostly f
 import inspect
 
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.rarithmetic import r_uint
+from pypy.rlib import rgc
 from pypy.rpython.extregistry import ExtRegistryEntry
-from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.controllerentry import Controller, SomeControlledInstance
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 def stack_unwind():
     if we_are_translated():
-        from pypy.rpython.lltypesystem.lloperation import llop
         return llop.stack_unwind(lltype.Void)
     raise RuntimeError("cannot unwind stack in non-translated versions")
 
 
 def stack_capture():
     if we_are_translated():
-        from pypy.rpython.lltypesystem.lloperation import llop
         ptr = llop.stack_capture(OPAQUE_STATE_HEADER_PTR)
         return frame_stack_top_controller.box(ptr)
     raise RuntimeError("cannot unwind stack in non-translated versions")
@@ -28,26 +29,57 @@ def stack_capture():
 
 def stack_frames_depth():
     if we_are_translated():
-        from pypy.rpython.lltypesystem.lloperation import llop
         return llop.stack_frames_depth(lltype.Signed)
     else:
         return len(inspect.stack())
 
+# ____________________________________________________________
+
 compilation_info = ExternalCompilationInfo(includes=['src/stack.h'])
 
-stack_too_big = rffi.llexternal('LL_stack_too_big', [], rffi.INT,
-                                compilation_info=compilation_info,
-                                _nowrapper=True,
-                                _callable=lambda: _zero,
-                                sandboxsafe=True)
-_zero = rffi.cast(rffi.INT, 0)
+def llexternal(name, args, res):
+    return rffi.llexternal(name, args, res, compilation_info=compilation_info,
+                           sandboxsafe=True, _nowrapper=True)
+
+_stack_get_start = llexternal('LL_stack_get_start', [], lltype.Signed)
+_stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed)
+_stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath',
+                                     [lltype.Signed], lltype.Char)
+# the following is used by the JIT
+_stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed)
+
 
 def stack_check():
-    if rffi.cast(lltype.Signed, stack_too_big()):
+    if not we_are_translated():
+        return
+    #
+    # Load the "current" stack position, or at least some address that
+    # points close to the current stack head
+    current = llop.stack_current(lltype.Signed)
+    #
+    # Load these variables from C code
+    start = _stack_get_start()
+    length = _stack_get_length()
+    #
+    # Common case: if 'current' is within [start:start+length], everything
+    # is fine
+    ofs = r_uint(current - start)
+    if ofs < r_uint(length):
+        return
+    #
+    # Else call the slow path
+    stack_check_slowpath(current)
+stack_check._always_inline_ = True
+
+ at rgc.no_collect
+def stack_check_slowpath(current):
+    if ord(_stack_too_big_slowpath(current)):
+        # Now we are sure that the stack is really too big.  Note that the
         # stack_unwind implementation is different depending on if stackless
         # is enabled. If it is it unwinds the stack, otherwise it simply
         # raises a RuntimeError.
         stack_unwind()
+stack_check_slowpath._dont_inline_ = True
 
 # ____________________________________________________________
 

--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -115,6 +115,7 @@ class AbstractLLCPU(AbstractCPU):
         self.pos_exception = pos_exception
         self.pos_exc_value = pos_exc_value
         self.save_exception = save_exception
+        self.insert_stack_check = lambda: (0, 0, 0)
 
 
     def _setup_exception_handling_translated(self):
@@ -138,9 +139,20 @@ class AbstractLLCPU(AbstractCPU):
             # in the assignment to self.saved_exc_value, as needed.
             self.saved_exc_value = exc_value
 
+        from pypy.rlib import rstack
+        STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed],
+                                                          lltype.Void))
+        def insert_stack_check():
+            startaddr = rstack._stack_get_start_adr()
+            length = rstack._stack_get_length()
+            f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath)
+            slowpathaddr = rffi.cast(lltype.Signed, f)
+            return startaddr, length, slowpathaddr
+
         self.pos_exception = pos_exception
         self.pos_exc_value = pos_exc_value
         self.save_exception = save_exception
+        self.insert_stack_check = insert_stack_check
 
     def _setup_on_leave_jitted_untranslated(self):
         # assume we don't need a backend leave in this case

--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -528,6 +528,8 @@ LL_OPERATIONS = {
     'get_stack_depth_limit':LLOp(sideeffects=False),
     'set_stack_depth_limit':LLOp(),
 
+    'stack_current':        LLOp(sideeffects=False),
+
     # __________ misc operations __________
 
     'keepalive':            LLOp(),

--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -93,6 +93,9 @@ class TestTranslationX86(CCompiledMixin)
         assert res == expected
 
     def test_direct_assembler_call_translates(self):
+        """Test CALL_ASSEMBLER and the recursion limit"""
+        from pypy.rlib.rstackovf import StackOverflow
+
         class Thing(object):
             def __init__(self, val):
                 self.val = val
@@ -135,9 +138,35 @@ class TestTranslationX86(CCompiledMixin)
                 i += 1
             return frame.thing.val
 
-        res = self.meta_interp(main, [0], inline=True,
+        driver2 = JitDriver(greens = [], reds = ['n'])
+
+        def main2(bound):
+            try:
+                while portal2(bound) == -bound+1:
+                    bound *= 2
+            except StackOverflow:
+                pass
+            return bound
+
+        def portal2(n):
+            while True:
+                driver2.jit_merge_point(n=n)
+                n -= 1
+                if n <= 0:
+                    return n
+                n = portal2(n)
+        assert portal2(10) == -9
+
+        def mainall(codeno, bound):
+            return main(codeno) + main2(bound)
+
+        res = self.meta_interp(mainall, [0, 1], inline=True,
                                policy=StopAtXPolicy(change))
-        assert res == main(0)
+        print hex(res)
+        assert res & 255 == main(0)
+        bound = res & ~255
+        assert 1024 <= bound <= 131072
+        assert bound & (bound-1) == 0       # a power of two
 
 
 class TestTranslationRemoveTypePtrX86(CCompiledMixin):

--- a/pypy/jit/backend/x86/codebuf.py
+++ b/pypy/jit/backend/x86/codebuf.py
@@ -10,8 +10,10 @@ from pypy.jit.backend.x86 import valgrin
 # like this
 if IS_X86_32:
     codebuilder_cls = X86_32_CodeBuilder
+    backend_name = 'x86'
 elif IS_X86_64:
     codebuilder_cls = X86_64_CodeBuilder
+    backend_name = 'x86_64'
 
 
 class MachineCodeBlockWrapper(BlockBuilderMixin,
@@ -34,3 +36,4 @@ class MachineCodeBlockWrapper(BlockBuild
             adr = rffi.cast(rffi.LONGP, p - WORD)
             adr[0] = intmask(adr[0] - p)
         valgrind.discard_translations(addr, self.get_relative_pos())
+        self._dump(addr, "jit-backend-dump", backend_name)

--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -8,6 +8,7 @@ class AbstractCPU(object):
     done_with_this_frame_int_v = -1
     done_with_this_frame_ref_v = -1
     done_with_this_frame_float_v = -1
+    exit_frame_with_exception_v = -1
     total_compiled_loops = 0
     total_compiled_bridges = 0
     total_freed_loops = 0

--- a/pypy/rlib/rposix.py
+++ b/pypy/rlib/rposix.py
@@ -135,6 +135,20 @@ def rmdir(path):
     else:
         return os.rmdir(path.as_bytes())
 
+ at specialize.argtype(0)
+def mkfifo(path, mode):
+    if isinstance(path, str):
+        os.mkfifo(path, mode)
+    else:
+        os.mkfifo(path.as_bytes(), mode)
+
+ at specialize.argtype(0)
+def mknod(path, mode, device):
+    if isinstance(path, str):
+        os.mknod(path, mode, device)
+    else:
+        os.mknod(path.as_bytes(), mode, device)
+
 if os.name == 'nt':
     import nt
     def _getfullpathname(path):

--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -1,11 +1,11 @@
 #! /usr/bin/env python
 """
-Viewer for the CODE_DUMP output of compiled programs generating code.
+Viewer for the output of compiled programs generating code.
+Use on the log files created with 'PYPYLOG=jit-backend-dump:log'.
 
 Try:
-    ./viewcode.py dumpfile.txt
-or
-    /tmp/usession-xxx/testing_1/testing_1 -var 4  2>&1  |  ./viewcode.py
+    ./viewcode.py --text log        # text only disassembly
+    ./viewcode.py log               # also includes a pygame viewer
 """
 
 import autopath
@@ -179,6 +179,7 @@ class World(object):
         self.symbols = {}
         self.logentries = {}
         self.backend_name = None
+        self.executable_name = None
 
     def parse(self, f, textonly=True):
         for line in f:
@@ -214,7 +215,9 @@ class World(object):
                 self.logentries[addr] = pieces[3]
             elif line.startswith('SYS_EXECUTABLE '):
                 filename = line[len('SYS_EXECUTABLE '):].strip()
-                self.symbols.update(load_symbols(filename))
+                if filename != self.executable_name:
+                    self.symbols.update(load_symbols(filename))
+                    self.executable_name = filename
 
     def find_cross_references(self):
         # find cross-references between blocks
@@ -375,10 +378,19 @@ if __name__ == '__main__':
         showgraph = False
     else:
         showgraph = True
-    if len(sys.argv) == 1:
-        f = sys.stdin
-    else:
-        f = open(sys.argv[1], 'r')
+    if len(sys.argv) != 2:
+        print >> sys.stderr, __doc__
+        sys.exit(2)
+    #
+    import cStringIO
+    from pypy.tool import logparser
+    log1 = logparser.parse_log_file(sys.argv[1])
+    text1 = logparser.extract_category(log1, catprefix='jit-backend-dump')
+    f = cStringIO.StringIO()
+    f.writelines(text1)
+    f.seek(0)
+    del log1, text1
+    #
     world = World()
     world.parse(f)
     if showgraph:

--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -84,6 +84,7 @@ class Assembler386(object):
         self.fail_boxes_count = 0
         self._current_depths_cache = (0, 0)
         self.datablockwrapper = None
+        self.stack_check_slowpath_imm = imm0
         self.teardown()
 
     def leave_jitted_hook(self):
@@ -122,6 +123,7 @@ class Assembler386(object):
             self._build_float_constants()
         if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
             self._build_malloc_fixedsize_slowpath()
+        self._build_stack_check_slowpath()
         debug_start('jit-backend-counts')
         self.set_debug(have_debug_prints())
         debug_stop('jit-backend-counts')
@@ -194,6 +196,82 @@ class Assembler386(object):
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         self.malloc_fixedsize_slowpath2 = rawstart
 
+    _STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed],
+                                                       lltype.Void))
+    def _build_stack_check_slowpath(self):
+        from pypy.rlib import rstack
+        mc = codebuf.MachineCodeBlockWrapper()
+        mc.PUSH_r(ebp.value)
+        mc.MOV_rr(ebp.value, esp.value)
+        #
+        if IS_X86_64:
+            # on the x86_64, we have to save all the registers that may
+            # have been used to pass arguments
+            for reg in [edi, esi, edx, ecx, r8, r9]:
+                mc.PUSH_r(reg.value)
+            mc.SUB_ri(esp.value, 8*8)
+            for i in range(8):
+                mc.MOVSD_sx(8*i, i)     # xmm0 to xmm7
+        #
+        if IS_X86_32:
+            mc.LEA_rb(eax.value, +8)
+            mc.PUSH_r(eax.value)
+        elif IS_X86_64:
+            mc.LEA_rb(edi.value, +16)
+            mc.AND_ri(esp.value, -16)
+        #
+        f = llhelper(self._STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath)
+        addr = rffi.cast(lltype.Signed, f)
+        mc.CALL(imm(addr))
+        #
+        mc.MOV(eax, heap(self.cpu.pos_exception()))
+        mc.TEST_rr(eax.value, eax.value)
+        mc.J_il8(rx86.Conditions['NZ'], 0)
+        jnz_location = mc.get_relative_pos()
+        #
+        if IS_X86_64:
+            # restore the registers
+            for i in range(7, -1, -1):
+                mc.MOVSD_xs(i, 8*i)
+            for i, reg in [(6, r9), (5, r8), (4, ecx),
+                           (3, edx), (2, esi), (1, edi)]:
+                mc.MOV_rb(reg.value, -8*i)
+        #
+        mc.MOV_rr(esp.value, ebp.value)
+        mc.POP_r(ebp.value)
+        mc.RET()
+        #
+        # patch the JNZ above
+        offset = mc.get_relative_pos() - jnz_location
+        assert 0 < offset <= 127
+        mc.overwrite(jnz_location-1, chr(offset))
+        # clear the exception from the global position
+        mc.MOV(eax, heap(self.cpu.pos_exc_value()))
+        mc.MOV(heap(self.cpu.pos_exception()), imm0)
+        mc.MOV(heap(self.cpu.pos_exc_value()), imm0)
+        # save the current exception instance into fail_boxes_ptr[0]
+        adr = self.fail_boxes_ptr.get_addr_for_num(0)
+        mc.MOV(heap(adr), eax)
+        # call the helper function to set the GC flag on the fail_boxes_ptr
+        # array (note that there is no exception any more here)
+        addr = self.cpu.get_on_leave_jitted_int(save_exception=False)
+        mc.CALL(imm(addr))
+        #
+        assert self.cpu.exit_frame_with_exception_v >= 0
+        mc.MOV_ri(eax.value, self.cpu.exit_frame_with_exception_v)
+        #
+        # footer -- note the ADD, which skips the return address of this
+        # function, and will instead return to the caller's caller.  Note
+        # also that we completely ignore the saved arguments, because we
+        # are interrupting the function.
+        mc.MOV_rr(esp.value, ebp.value)
+        mc.POP_r(ebp.value)
+        mc.ADD_ri(esp.value, WORD)
+        mc.RET()
+        #
+        rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+        self.stack_check_slowpath_imm = imm(rawstart)
+
     def assemble_loop(self, inputargs, operations, looptoken, log):
         '''adds the following attributes to looptoken:
                _x86_loop_code       (an integer giving an address)
@@ -468,6 +546,24 @@ class Assembler386(object):
         for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
             self.mc.PUSH_r(regloc.value)
 
+    def _call_header_with_stack_check(self):
+        startaddr, length, slowpathaddr = self.cpu.insert_stack_check()
+        if slowpathaddr == 0:
+            pass                # no stack check (e.g. not translated)
+        else:
+            self.mc.MOV(eax, esp)                       # MOV eax, current
+            self.mc.SUB(eax, heap(startaddr))           # SUB eax, [startaddr]
+            self.mc.CMP(eax, imm(length))               # CMP eax, length
+            self.mc.J_il8(rx86.Conditions['B'], 0)      # JB .skip
+            jb_location = self.mc.get_relative_pos()
+            self.mc.CALL(self.stack_check_slowpath_imm) # CALL slowpath
+            # patch the JB above                        # .skip:
+            offset = self.mc.get_relative_pos() - jb_location
+            assert 0 < offset <= 127
+            self.mc.overwrite(jb_location-1, chr(offset))
+            #
+        self._call_header()
+
     def _call_footer(self):
         self.mc.LEA_rb(esp.value, -len(self.cpu.CALLEE_SAVE_REGISTERS) * WORD)
 
@@ -485,7 +581,7 @@ class Assembler386(object):
         # XXX this can be improved greatly. Right now it'll behave like
         #     a normal call
         nonfloatlocs, floatlocs = arglocs
-        self._call_header()
+        self._call_header_with_stack_check()
         self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth))
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
@@ -526,7 +622,7 @@ class Assembler386(object):
         unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0]
 
         nonfloatlocs, floatlocs = arglocs
-        self._call_header()
+        self._call_header_with_stack_check()
         self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth))
 
         # The lists are padded with Nones

--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,53 @@
+syntax:glob
+*.py[co]
+
+testresult
+site-packages
+pypy/module/cpyext/src/*.o
+pypy/bin/pypy-c
+pypy/translator/jvm/src/pypy/*.class
+pypy/module/_stackless/test/
+pypy/module/cpyext/test/*.errors
+pypy/doc/*.html
+pypy/doc/basicblock.asc
+pypy/doc/*.svninfo
+pypy/translator/jvm/.project
+pypy/translator/jvm/.classpath
+pypy/translator/jvm/eclipse-bin
+pypy/translator/benchmark/docutils
+pypy/translator/benchmark/templess
+pypy/translator/benchmark/gadfly
+pypy/translator/benchmark/mako
+pypy/translator/benchmark/bench-custom.benchmark_result
+pypy/translator/benchmark/shootout_benchmarks
+pypy/module/_stackless/
+pypy/translator/goal/pypy-translation-snapshot
+pypy/translator/goal/pypy-c*
+pypy/translator/goal/*.exe
+pypy/translator/goal/target*-c
+pypy/_cache
+site-packages/*.egg
+site-packages/*.pth
+pypy/doc/statistic/*.html
+pypy/doc/statistic/*.eps
+pypy/doc/statistic/*.pdf
+pypy/translator/cli/src/pypylib.dll
+pypy/translator/cli/src/query.exe
+pypy/translator/cli/src/main.exe
+lib_pypy/ctypes_config_cache/_*_cache.py
+lib_pypy/ctypes_config_cache/_*_*_.py
+pypy/translator/cli/query-descriptions
+pypy/doc/discussion/*.html
+pypy/doc/discussion/
+include/*.h
+include/*.inl
+pypy/doc/config/*.html
+pypy/doc/config/style.css
+pypy/doc/config/
+pypy/doc/jit/*.html
+pypy/doc/jit/style.css
+pypy/doc/image/lattice1.png
+pypy/doc/image/lattice2.png
+pypy/doc/image/lattice3.png
+pypy/doc/image/stackless_informal.png
+pypy/doc/image/parsing_example*.png



More information about the Pypy-commit mailing list