Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r44533:e4f57b789ca5 Date: 2011-05-27 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/e4f57b789ca5/
Log: merge heads diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py --- a/pypy/jit/backend/llsupport/llmodel.py +++ b/pypy/jit/backend/llsupport/llmodel.py @@ -144,10 +144,10 @@ lltype.Void)) def insert_stack_check(): startaddr = rstack._stack_get_start_adr() - length = rstack._stack_get_length() + lengthaddr = rstack._stack_get_length_adr() f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath) slowpathaddr = rffi.cast(lltype.Signed, f) - return startaddr, length, slowpathaddr + return startaddr, lengthaddr, slowpathaddr self.pos_exception = pos_exception self.pos_exc_value = pos_exc_value diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -621,10 +621,10 @@ if self.stack_check_slowpath == 0: pass # no stack check (e.g. not translated) else: - startaddr, length, _ = self.cpu.insert_stack_check() + startaddr, lengthaddr, _ = self.cpu.insert_stack_check() 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.SUB(eax, heap(startaddr)) # SUB eax, [start] + self.mc.CMP(eax, heap(lengthaddr)) # CMP eax, [length] self.mc.J_il8(rx86.Conditions['B'], 0) # JB .skip jb_location = self.mc.get_relative_pos() self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -43,21 +43,20 @@ return space.wrap(f) def setrecursionlimit(space, w_new_limit): - """setrecursionlimit() is ignored (and not needed) on PyPy. - -On CPython it would set the maximum number of nested calls that can -occur before a RuntimeError is raised. On PyPy overflowing the stack -also causes RuntimeErrors, but the limit is checked at a lower level. -(The limit is currenty hard-coded at 768 KB, corresponding to roughly -1480 Python calls on Linux.)""" + """setrecursionlimit() sets the maximum number of nested calls that +can occur before a RuntimeError is raised. On PyPy the limit is +approximative and checked at a lower level. The default 1000 +reserves 768KB of stack space, which should suffice (on Linux, +depending on the compiler settings) for ~1400 calls. Setting the +value to N reserves N/1000 times 768KB of stack space. +""" + from pypy.rlib.rstack import _stack_set_length_fraction new_limit = space.int_w(w_new_limit) if new_limit <= 0: raise OperationError(space.w_ValueError, space.wrap("recursion limit must be positive")) - # for now, don't rewrite a warning but silently ignore the - # recursion limit. - #space.warn('setrecursionlimit() is ignored (and not needed) on PyPy', space.w_RuntimeWarning) space.sys.recursionlimit = new_limit + _stack_set_length_fraction(new_limit * 0.001) def getrecursionlimit(space): """Return the last value set by setrecursionlimit(). diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py --- a/pypy/rlib/rstack.py +++ b/pypy/rlib/rstack.py @@ -46,11 +46,15 @@ lambda: 0) _stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed, lambda: 1) +_stack_set_length_fraction = llexternal('LL_stack_set_length_fraction', + [lltype.Float], lltype.Void, + lambda frac: None) _stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath', [lltype.Signed], lltype.Char, lambda cur: '\x00') # the following is used by the JIT _stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed) +_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed) def stack_check(): diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h --- a/pypy/translator/c/src/stack.h +++ b/pypy/translator/c/src/stack.h @@ -12,14 +12,17 @@ #include "thread.h" extern char *_LLstacktoobig_stack_start; +extern long _LLstacktoobig_stack_length; void LL_stack_unwind(void); char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */ +void LL_stack_set_length_fraction(double); /* some macros referenced from pypy.rlib.rstack */ #define LL_stack_get_start() ((long)_LLstacktoobig_stack_start) -#define LL_stack_get_length() MAX_STACK_SIZE +#define LL_stack_get_length() _LLstacktoobig_stack_length #define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start) /* JIT */ +#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */ #ifdef __GNUC__ @@ -51,12 +54,18 @@ } char *_LLstacktoobig_stack_start = NULL; +long _LLstacktoobig_stack_length = MAX_STACK_SIZE; int stack_direction = 0; RPyThreadStaticTLS start_tls_key; +void LL_stack_set_length_fraction(double fraction) +{ + _LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction); +} + char LL_stack_too_big_slowpath(long current) { - long diff; + long diff, max_stack_size; char *baseptr, *curptr = (char*)current; /* The stack_start variable is updated to match the current value @@ -83,22 +92,23 @@ } baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key); + max_stack_size = _LLstacktoobig_stack_length; if (baseptr != NULL) { diff = curptr - baseptr; - if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) { + if (((unsigned long)diff) < (unsigned long)max_stack_size) { /* within bounds, probably just had a thread switch */ _LLstacktoobig_stack_start = baseptr; return 0; } if (stack_direction > 0) { - if (diff < 0 && diff > -MAX_STACK_SIZE) + if (diff < 0 && diff > -max_stack_size) ; /* stack underflow */ else return 1; /* stack overflow (probably) */ } else { - if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE) + if (diff >= max_stack_size && diff < 2*max_stack_size) ; /* stack underflow */ else return 1; /* stack overflow (probably) */ @@ -115,7 +125,7 @@ } else { /* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */ - baseptr = curptr - MAX_STACK_SIZE + 1; + baseptr = curptr - max_stack_size + 1; } RPyThreadStaticTLS_Set(start_tls_key, baseptr); _LLstacktoobig_stack_start = baseptr; diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py --- a/pypy/translator/c/test/test_standalone.py +++ b/pypy/translator/c/test/test_standalone.py @@ -689,6 +689,39 @@ out = cbuilder.cmdexec("") assert out.strip() == "hi!" + def test_set_length_fraction(self): + # check for pypy.rlib.rstack._stack_set_length_fraction() + from pypy.rlib.rstack import _stack_set_length_fraction + from pypy.rlib.rstackovf import StackOverflow + class A: + n = 0 + glob = A() + def f(n): + glob.n += 1 + if n <= 0: + return 42 + return f(n+1) + def entry_point(argv): + _stack_set_length_fraction(float(argv[1])) + try: + return f(1) + except StackOverflow: + print glob.n + return 0 + t, cbuilder = self.compile(entry_point, stackcheck=True) + counts = {} + for fraction in [0.1, 0.4, 1.0]: + out = cbuilder.cmdexec(str(fraction)) + print 'counts[%s]: %r' % (fraction, out) + counts[fraction] = int(out.strip()) + # + assert counts[1.0] >= 1000 + # ^^^ should actually be much more than 1000 for this small test + assert counts[0.1] < counts[0.4] / 3 + assert counts[0.4] < counts[1.0] / 2 + assert counts[0.1] > counts[0.4] / 7 + assert counts[0.4] > counts[1.0] / 4 + class TestMaemo(TestStandalone): def setup_class(cls): py.test.skip("TestMaemo: tests skipped for now") _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit