def callAtom(self, atom, arguments, namedArgsMap): """ This method is used to reuse atoms without having to rebuild them. """ # Promote the atom, on the basis that atoms are generally reused. atom = promote(atom) # Log the atom to the JIT log. Don't do this if the atom's not # promoted; it'll be slow. jit_debug(atom.repr) try: return self.recvNamed(atom, arguments, namedArgsMap) except Refused as r: addTrail(r, self, atom, arguments) raise except UserException as ue: addTrail(ue, self, atom, arguments) raise except MemoryError: ue = userError(u"Memory corruption or exhausted heap") addTrail(ue, self, atom, arguments) raise ue except StackOverflow: check_stack_overflow() ue = userError(u"Stack overflow") addTrail(ue, self, atom, arguments) raise ue
def _interpret(self, space, pc, frame, bytecode): prev_instr = frame.last_instr frame.last_instr = pc if (space.getexecutioncontext().hastraceproc() and bytecode.lineno_table[pc] != bytecode.lineno_table[prev_instr]): space.getexecutioncontext().invoke_trace_proc(space, "line", None, None, frame=frame) try: pc = self.handle_bytecode(space, pc, frame, bytecode) except RubyError as e: pc = self.handle_ruby_error(space, pc, frame, bytecode, e) except RaiseReturn as e: pc = self.handle_raise_return(space, pc, frame, bytecode, e) except RaiseBreak as e: pc = self.handle_raise_break(space, pc, frame, bytecode, e) except Throw as e: pc = self.handle_throw(space, pc, frame, bytecode, e) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() pc = self.handle_ruby_error( space, pc, frame, bytecode, space.error(space.w_SystemStackError, "stack level too deep")) return pc
def dump_w_obj(self, w_obj): space = self.space try: self.put_w_obj(w_obj) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() self._overflow()
def dump_w_obj(self, w_obj): space = self.space if (space.type(w_obj).is_heaptype() and space.lookup(w_obj, "__buffer__") is None): w_err = space.wrap("only builtins can be marshaled") raise OperationError(space.w_ValueError, w_err) try: self.put_w_obj(w_obj) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() self._overflow()
def handle_exception(self, space, e): try: if not we_are_translated(): raise raise e except KeyboardInterrupt: raise OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: raise OperationError(space.w_MemoryError, space.w_None) except rstackovf.StackOverflow, e: rstackovf.check_stack_overflow() raise OperationError(space.w_RuntimeError, space.wrap("maximum recursion depth exceeded"))
def load_w_obj(self, allow_null=False): try: return self._get_w_obj(allow_null) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() self._overflow() except OperationError as e: if not e.match(self.space, self.space.w_RecursionError): raise # somebody else has already converted the rpython overflow error to # an OperationError (e.g. one of che space.call* calls in # marshal_impl), turn it into a ValueError self._overflow()
def handle_exception(self, space, e): try: if not we_are_translated(): raise raise e except KeyboardInterrupt: raise OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: raise OperationError(space.w_MemoryError, space.w_None) except rstackovf.StackOverflow, e: rstackovf.check_stack_overflow() raise OperationError( space.w_RuntimeError, space.wrap("maximum recursion depth exceeded"))
def dump_w_obj(self, w_obj): space = self.space if space.type(w_obj).is_heaptype(): try: buf = space.readbuf_w(w_obj) except OperationError as e: if not e.match(space, space.w_TypeError): raise self.raise_exc("unmarshallable object") else: w_obj = space.newbuffer(buf) try: self.put_w_obj(w_obj) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() self._overflow()
def stack_frame(self, s_frame, s_sender, may_context_switch=True): if self.is_tracing(): self.stack_depth += 1 vref = s_frame.enter_virtual_frame(s_sender) try: self.loop_bytecodes(s_frame, may_context_switch) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() raise StackOverflow(s_frame) except LocalReturn, ret: if s_frame.get_state() is DirtyContext: s_new_sender = s_frame.s_sender() # The sender has changed! s_frame._activate_unwind_context(self) raise NonVirtualReturn(s_new_sender, s_new_sender, ret.value(self.space)) else: s_frame._activate_unwind_context(self) raise ret
def stack_frame(self, s_frame, s_sender, may_context_switch): if self.is_tracing(): self.stack_depth += 1 vref = s_frame.enter_virtual_frame(s_sender) try: self.loop_bytecodes(s_frame, may_context_switch) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() raise StackOverflow(s_frame) except LocalReturn, ret: if s_frame.get_state() is DirtyContext: s_new_sender = s_frame.s_sender() # The sender has changed! s_frame._activate_unwind_context(self) raise NonVirtualReturn(s_new_sender, s_new_sender, ret.value(self.space)) else: s_frame._activate_unwind_context(self) raise ret
def get_converted_unexpected_exception(space, e): """This is used in two places when we get an non-OperationError RPython exception: from gateway.py when calling an interp-level function raises; and from pyopcode.py when we're exiting the interpretation of the frame with an exception. Note that it *cannot* be used in pyopcode.py: that place gets a ContinueRunningNormally exception from the JIT, which must not end up here! """ try: if not we_are_translated(): raise raise e except KeyboardInterrupt: return OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: return OperationError(space.w_MemoryError, space.w_None) except rstackovf.StackOverflow as e: # xxx twisted logic which happens to give the result that we # want: when untranslated, a RuntimeError or its subclass # NotImplementedError is caught here. Then # check_stack_overflow() will re-raise it directly. We see # the result as this exception propagates directly. But when # translated, an RPython-level RuntimeError is turned into # an app-level RuntimeError by the next case. rstackovf.check_stack_overflow() return oefmt(space.w_RecursionError, "maximum recursion depth exceeded") except RuntimeError: # not on top of py.py return OperationError(space.w_RuntimeError, space.w_None) except: if we_are_translated(): from rpython.rlib.debug import debug_print_traceback debug_print_traceback() extra = '; internal traceback was dumped to stderr' else: # when untranslated, we don't wrap into an app-level # SystemError (this makes debugging tests harder) raise return OperationError( space.w_SystemError, space.newtext( "unexpected internal exception (please report a bug): %r%s" % (e, extra)))
def get_converted_unexpected_exception(space, e): """This is used in two places when we get an non-OperationError RPython exception: from gateway.py when calling an interp-level function raises; and from pyopcode.py when we're exiting the interpretation of the frame with an exception. Note that it *cannot* be used in pyopcode.py: that place gets a ContinueRunningNormally exception from the JIT, which must not end up here! """ try: if not we_are_translated(): raise raise e except KeyboardInterrupt: return OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: return OperationError(space.w_MemoryError, space.w_None) except rstackovf.StackOverflow as e: # xxx twisted logic which happens to give the result that we # want: when untranslated, a RuntimeError or its subclass # NotImplementedError is caught here. Then # check_stack_overflow() will re-raise it directly. We see # the result as this exception propagates directly. But when # translated, an RPython-level RuntimeError is turned into # an app-level RuntimeError by the next case. rstackovf.check_stack_overflow() return oefmt(space.w_RuntimeError, "maximum recursion depth exceeded") except RuntimeError: # not on top of py.py return OperationError(space.w_RuntimeError, space.w_None) except: if we_are_translated(): from rpython.rlib.debug import debug_print_traceback debug_print_traceback() extra = "; internal traceback was dumped to stderr" else: # when untranslated, we don't wrap into an app-level # SystemError (this makes debugging tests harder) raise return OperationError( space.w_SystemError, space.wrap("unexpected internal exception (please report a bug): %r%s" % (e, extra)) )
def _interpret(self, space, pc, frame, bytecode): prev_instr = frame.last_instr frame.last_instr = pc if (space.getexecutioncontext().hastraceproc() and bytecode.lineno_table[pc] != bytecode.lineno_table[prev_instr]): space.getexecutioncontext().invoke_trace_proc(space, "line", None, None, frame=frame) try: pc = self.handle_bytecode(space, pc, frame, bytecode) except RubyError as e: pc = self.handle_ruby_error(space, pc, frame, bytecode, e) except RaiseReturn as e: pc = self.handle_raise_return(space, pc, frame, bytecode, e) except RaiseBreak as e: pc = self.handle_raise_break(space, pc, frame, bytecode, e) except Throw as e: pc = self.handle_throw(space, pc, frame, bytecode, e) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() pc = self.handle_ruby_error(space, pc, frame, bytecode, space.error(space.w_SystemStackError, "stack level too deep")) return pc
def stack_frame(self, s_frame, s_sender, may_context_switch=True): try: if self.is_tracing(): self.stack_depth += 1 if s_frame._s_sender is None and s_sender is not None: s_frame.store_s_sender(s_sender) # Now (continue to) execute the context bytecodes # assert s_frame.state is InactiveContext s_frame.state = ActiveContext self.loop_bytecodes(s_frame, may_context_switch) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() raise StackOverflow(s_frame) except LocalReturn, ret: if s_frame.state is DirtyContext: s_sender = s_frame.s_sender() # The sender has changed! s_frame._activate_unwind_context(self) raise NonVirtualReturn(s_sender, s_sender, ret.value(self.space)) else: s_frame._activate_unwind_context(self) raise ret
def callAtom(self, atom, arguments, namedArgsMap=None, span=None): """ This method is used to reuse atoms without having to rebuild them. This is the correct method to call if you have an atom. """ # Promote the atom, on the basis that atoms are generally reused. atom = promote(atom) # Log the atom to the JIT log. Don't do this if the atom's not # promoted; it'll be slow. jit_debug(atom.repr) if namedArgsMap is None or namedArgsMap.isEmpty(): namedArgsMap = MIRANDA_MAP else: from typhon.objects.collections.maps import ConstMap namedArgsMap = ConstMap(namedArgsMap._or(MIRANDA_ARGS)) try: return self.recvNamed(atom, arguments, namedArgsMap) except Refused as r: r.addTrail(self, atom, arguments, span) raise except UserException as ue: ue.addTrail(self, atom, arguments, span) raise except MemoryError: ue = userError(u"Memory corruption or exhausted heap") ue.addTrail(self, atom, arguments, span) raise ue except StackOverflow: check_stack_overflow() ue = userError(u"Stack overflow") ue.addTrail(self, atom, arguments, span) raise ue
def stack_frame(self, s_frame, s_sender, may_context_switch=True): try: if self.is_tracing(): self.stack_depth += 1 if s_frame._s_sender is None and s_sender is not None: s_frame.store_s_sender(s_sender) # Now (continue to) execute the context bytecodes # assert s_frame.state is InactiveContext s_frame.state = ActiveContext self.loop_bytecodes(s_frame, may_context_switch) except rstackovf.StackOverflow: rstackovf.check_stack_overflow() raise StackOverflow(s_frame) except Return, ret: if s_frame.state is DirtyContext: s_sender = s_frame.s_sender() # The sender has changed! s_frame._activate_unwind_context(self) target_context = s_sender if ret.is_local else ret.s_target_context raise NonVirtualReturn(target_context, s_sender, ret.value) else: s_frame._activate_unwind_context(self) if ret.is_local or ret.s_target_context is s_sender: ret.arrived_at_target = True raise ret
def load_w_obj(self): try: return self.get_w_obj() except rstackovf.StackOverflow: rstackovf.check_stack_overflow() self._overflow()
def callAtom(self, atom, arguments, namedArgsMap): """ This method is used to reuse atoms without having to rebuild them. """ from typhon.objects.collections.maps import EMPTY_MAP # Promote the atom, on the basis that atoms are generally reused. atom = promote(atom) # Log the atom to the JIT log. Don't do this if the atom's not # promoted; it'll be slow. jit_debug(atom.repr) try: return self.recvNamed(atom, arguments, namedArgsMap) except Refused as r: # This block of method implementations is Typhon's Miranda # protocol. ~ C. if atom is _CONFORMTO_1: # Welcome to _conformTo/1. # to _conformTo(_): return self return self if atom is _GETALLEGEDINTERFACE_0: # Welcome to _getAllegedInterface/0. interface = self.optInterface() if interface is None: from typhon.objects.interfaces import ComputedInterface interface = ComputedInterface(self) return interface if atom is _PRINTON_1: # Welcome to _printOn/1. from typhon.objects.constants import NullObject self.printOn(arguments[0]) return NullObject if atom is _RESPONDSTO_2: from typhon.objects.constants import wrapBool from typhon.objects.data import unwrapInt, unwrapStr verb = unwrapStr(arguments[0]) arity = unwrapInt(arguments[1]) atom = getAtom(verb, arity) result = (atom in self.respondingAtoms() or atom in mirandaAtoms) return wrapBool(result) if atom is _SEALEDDISPATCH_1: # to _sealedDispatch(_): return null from typhon.objects.constants import NullObject return NullObject if atom is _UNCALL_0: from typhon.objects.constants import NullObject return NullObject if atom is _WHENMORERESOLVED_1: # Welcome to _whenMoreResolved. # This method's implementation, in Monte, should be: # to _whenMoreResolved(callback): callback<-(self) from typhon.vats import currentVat vat = currentVat.get() vat.sendOnly(arguments[0], RUN_1, [self], EMPTY_MAP) from typhon.objects.constants import NullObject return NullObject addTrail(r, self, atom, arguments) raise except UserException as ue: addTrail(ue, self, atom, arguments) raise except MemoryError: ue = userError(u"Memory corruption or exhausted heap") addTrail(ue, self, atom, arguments) raise ue except StackOverflow: check_stack_overflow() ue = userError(u"Stack overflow") addTrail(ue, self, atom, arguments) raise ue
class LLFrame(object): def __init__(self, graph, args, llinterpreter): assert not graph or isinstance(graph, FunctionGraph) self.graph = graph self.args = args self.llinterpreter = llinterpreter self.heap = llinterpreter.heap self.bindings = {} self.curr_block = None self.curr_operation_index = 0 self.alloca_objects = [] def newsubframe(self, graph, args): return self.__class__(graph, args, self.llinterpreter) # _______________________________________________________ # variable setters/getters helpers def clear(self): self.bindings.clear() def fillvars(self, block, values): vars = block.inputargs assert len(vars) == len(values), ( "block %s received %d args, expected %d" % (block, len(values), len(vars))) for var, val in zip(vars, values): self.setvar(var, val) def setvar(self, var, val): if var.concretetype is not lltype.Void: try: val = lltype.enforce(var.concretetype, val) except TypeError: assert False, "type error: input value of type:\n\n\t%r\n\n===> variable of type:\n\n\t%r\n" % ( lltype.typeOf(val), var.concretetype) assert isinstance(var, Variable) self.bindings[var] = val def setifvar(self, var, val): if isinstance(var, Variable): self.setvar(var, val) def getval(self, varorconst): try: val = varorconst.value except AttributeError: val = self.bindings[varorconst] if isinstance(val, ComputedIntSymbolic): val = val.compute_fn() if varorconst.concretetype is not lltype.Void: try: val = lltype.enforce(varorconst.concretetype, val) except TypeError: assert False, "type error: %r val from %r var/const" % ( lltype.typeOf(val), varorconst.concretetype) return val # _______________________________________________________ # other helpers def getoperationhandler(self, opname): ophandler = getattr(self, 'op_' + opname, None) if ophandler is None: # try to import the operation from opimpl.py ophandler = lloperation.LL_OPERATIONS[opname].fold setattr(self.__class__, 'op_' + opname, staticmethod(ophandler)) return ophandler # _______________________________________________________ # evaling functions def eval(self): graph = self.graph tracer = self.llinterpreter.tracer if tracer: tracer.enter(graph) self.llinterpreter.frame_stack.append(self) try: try: nextblock = graph.startblock args = self.args while 1: self.clear() self.fillvars(nextblock, args) nextblock, args = self.eval_block(nextblock) if nextblock is None: for obj in self.alloca_objects: obj._obj._free() return args except Exception: self.llinterpreter.traceback_frames.append(self) raise finally: leavingframe = self.llinterpreter.frame_stack.pop() assert leavingframe is self if tracer: tracer.leave() def eval_block(self, block): """ return (nextblock, values) tuple. If nextblock is None, values is the concrete return value. """ self.curr_block = block e = None try: for i, op in enumerate(block.operations): self.curr_operation_index = i self.eval_operation(op) except LLException, e: if op is not block.raising_op: raise except RuntimeError, e: rstackovf.check_stack_overflow() # xxx fish fish fish for proper etype and evalue to use rtyper = self.llinterpreter.typer bk = rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(rstackovf._StackOverflow) exdata = rtyper.exceptiondata evalue = exdata.get_standard_ll_exc_instance(rtyper, classdef) etype = exdata.fn_type_of_exc_inst(evalue) e = LLException(etype, evalue) if op is not block.raising_op: raise e
def eval_block(self, block): """ return (nextblock, values) tuple. If nextblock is None, values is the concrete return value. """ self.curr_block = block e = None try: for i, op in enumerate(block.operations): self.curr_operation_index = i self.eval_operation(op) except LLException as e: if op is not block.raising_op: raise except RuntimeError as e: rstackovf.check_stack_overflow() # xxx fish fish fish for proper etype and evalue to use rtyper = self.llinterpreter.typer bk = rtyper.annotator.bookkeeper classdef = bk.getuniqueclassdef(rstackovf._StackOverflow) exdata = rtyper.exceptiondata evalue = exdata.get_standard_ll_exc_instance(rtyper, classdef) etype = exdata.fn_type_of_exc_inst(evalue) e = LLException(etype, evalue) if op is not block.raising_op: raise e # determine nextblock and/or return value if len(block.exits) == 0: # return block tracer = self.llinterpreter.tracer if len(block.inputargs) == 2: # exception if tracer: tracer.dump('raise') etypevar, evaluevar = block.getvariables() etype = self.getval(etypevar) evalue = self.getval(evaluevar) # watch out, these are _ptr's raise LLException(etype, evalue) resultvar, = block.getvariables() result = self.getval(resultvar) exc_data = self.llinterpreter.get_transformed_exc_data(self.graph) if exc_data: # re-raise the exception set by this graph, if any etype = exc_data.exc_type if etype: evalue = exc_data.exc_value if tracer: tracer.dump('raise') exc_data.exc_type = lltype.typeOf(etype)._defl() exc_data.exc_value = lltype.typeOf(evalue)._defl() from rpython.translator import exceptiontransform T = resultvar.concretetype errvalue = exceptiontransform.error_value(T) # check that the exc-transformed graph returns the error # value when it returns with an exception set assert result == errvalue raise LLException(etype, evalue) if tracer: tracer.dump('return') return None, result elif block.exitswitch is None: # single-exit block assert len(block.exits) == 1 link = block.exits[0] elif block.canraise: link = block.exits[0] if e: exdata = self.llinterpreter.typer.exceptiondata cls = e.args[0] inst = e.args[1] for link in block.exits[1:]: assert issubclass(link.exitcase, py.builtin.BaseException) if self.op_direct_call(exdata.fn_exception_match, cls, link.llexitcase): self.setifvar(link.last_exception, cls) self.setifvar(link.last_exc_value, inst) break else: # no handler found, pass on raise e else: llexitvalue = self.getval(block.exitswitch) if block.exits[-1].exitcase == "default": defaultexit = block.exits[-1] nondefaultexits = block.exits[:-1] assert defaultexit.llexitcase is None else: defaultexit = None nondefaultexits = block.exits for link in nondefaultexits: if link.llexitcase == llexitvalue: break # found -- the result is in 'link' else: if defaultexit is None: raise ValueError("exit case %r not found in the exit links " "of %r" % (llexitvalue, block)) else: link = defaultexit return link.target, [self.getval(x) for x in link.args]