""" This file defines utilities for manipulating the stack in an RPython-compliant way. It is mainly about the stack_check() function. """ import py from rpython.rlib.objectmodel import we_are_translated from rpython.rlib.rarithmetic import r_uint from rpython.rlib import rgc from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop # ____________________________________________________________ def llexternal(name, args, res, _callable=None): return rffi.llexternal(name, args, res, sandboxsafe=True, _nowrapper=True, _callable=_callable) _stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed, 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_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed) _stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed) # the following is also used by the JIT: "critical code" paths are paths in # which we should not raise StackOverflow at all, but just ignore the stack limit _stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [], lltype.Void, lambda: None) _stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [], lltype.Void, lambda: None) def stack_check(): 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 end = _stack_get_end() length = _stack_get_length() # # Common case: if 'current' is within [end-length:end], everything # is fine ofs = r_uint(end - current) if ofs <= r_uint(length): return # # Else call the slow path stack_check_slowpath(current) stack_check._always_inline_ = True stack_check._dont_insert_stackcheck_ = True @rgc.no_collect def stack_check_slowpath(current): if ord(_stack_too_big_slowpath(current)): from rpython.rlib.rstackovf import _StackOverflow raise _StackOverflow stack_check_slowpath._dont_inline_ = True stack_check_slowpath._dont_insert_stackcheck_ = True def stack_almost_full(): """Return True if the stack is more than 15/16th full.""" if not we_are_translated(): return False # see stack_check() current = llop.stack_current(lltype.Signed) end = _stack_get_end() length = 15 * (r_uint(_stack_get_length()) >> 4) ofs = r_uint(end - current) if ofs <= length: return False # fine else: _stack_too_big_slowpath(current) # this might update the stack end end = _stack_get_end() ofs = r_uint(end - current) return ofs > length stack_almost_full._dont_insert_stackcheck_ = True stack_almost_full._jit_look_inside_ = False