# HG changeset patch # User Carl Friedrich Bolz-Tereick # Date 1588521797 -7200 # Sun May 03 18:03:17 2020 +0200 # Branch call-site-specialization # Node ID 5f5357609ee3f286a788f384775d00982e0ae5c4 # Parent 91b83b614960feaad43e2b2f81946ea963714727 intermediate checkin: use rule_in_location in continuations bit of a mess diff --git a/prolog/interpreter/continuation.py b/prolog/interpreter/continuation.py --- a/prolog/interpreter/continuation.py +++ b/prolog/interpreter/continuation.py @@ -5,7 +5,7 @@ from prolog.interpreter import error from prolog.interpreter import helper from prolog.interpreter.term import Term, Atom, BindingVar, Callable, Var -from prolog.interpreter.function import Function, Rule +from prolog.interpreter.function import Function, Rule, RuleInLocation from prolog.interpreter.heap import Heap from prolog.interpreter.signature import Signature from prolog.interpreter.module import Module, ModuleWrapper @@ -18,12 +18,18 @@ # ___________________________________________________________________ # JIT stuff -def get_printable_location(rule, sconttype): +def get_printable_location(rule_in_location, sconttype): + rule = None + if rule_in_location: + rule = rule_in_location.rule if rule: s = rule.signature.string() else: s = "No rule" - return "%s %s" % (s, sconttype) + res = "%s %s" % (s, sconttype) + if rule_in_location and rule_in_location.location and rule_in_location.location.repr: + res = "%s from %s" % (res, rule_in_location.location.repr) + return res def get_jitcell_at(where, rule): # XXX can be vastly simplified @@ -37,7 +43,7 @@ callsig = Signature.getsignature(":-", 1) jitdriver = jit.JitDriver( - greens=["rule", "sconttype"], + greens=["rule_in_location", "sconttype"], reds=["scont", "fcont", "heap"], get_printable_location=get_printable_location, #get_jitcell_at=get_jitcell_at, @@ -49,17 +55,17 @@ def driver(scont, fcont, heap): - rule = None + rule_in_location = None while not scont.is_done(): #view(scont=scont, fcont=fcont, heap=heap) sconttype = scont.cont_type_name - if isinstance(scont, ContinuationWithRule): - rule = scont.rule - if isinstance(scont, RuleContinuation) and rule.body is not None: - jitdriver.can_enter_jit(rule=rule, sconttype=sconttype, scont=scont, fcont=fcont, + if isinstance(scont, ContinuationWithRuleInLocation): + rule_in_location = scont.rule_in_location + if isinstance(scont, RuleContinuation) and rule_in_location.rule.body is not None: + jitdriver.can_enter_jit(rule_in_location=rule_in_location, sconttype=sconttype, scont=scont, fcont=fcont, heap=heap) try: - jitdriver.jit_merge_point(rule=rule, sconttype=sconttype, scont=scont, fcont=fcont, + jitdriver.jit_merge_point(rule_in_location=rule_in_location, sconttype=sconttype, scont=scont, fcont=fcont, heap=heap) oldscont = scont scont, fcont, heap = scont.activate(fcont, heap) @@ -70,6 +76,9 @@ raise scont, fcont, heap = fcont.fail(heap) except error.CatchableError, exc: + rule = None + if rule_in_location is not None: + rule = rule_in_location.rule scont, fcont, heap = scont.engine.throw(exc, scont, fcont, heap, rule) else: scont, fcont, heap = _process_hooks(scont, fcont, heap) @@ -224,8 +233,9 @@ raise error.throw_type_error('callable', query) signature = query.signature() builtin = self.get_builtin(signature) + rule_in_location = rule.get_rule_in_location(query.location()) if builtin is not None: - return BuiltinContinuation(self, rule, scont, builtin, query), fcont, heap + return BuiltinContinuation(self, rule_in_location, scont, builtin, query), fcont, heap # do a real call module = rule.module @@ -235,7 +245,8 @@ rulechain = startrulechain.find_applicable_rule(query) if rulechain is None: raise error.UnificationFailed - scont, fcont, heap = _make_rule_conts(self, scont, fcont, heap, query, rulechain) + rule_in_location = rulechain.get_rule_in_location(query.location()) + scont, fcont, heap = _make_rule_conts(self, scont, fcont, heap, query, rule_in_location) return scont, fcont, heap def call_in_module(self, query, module, scont, fcont, heap): @@ -285,7 +296,7 @@ scont = scont.nextcont else: return self.call( - scont.recover, scont.rule, scont.nextcont, scont.fcont, heap) + scont.recover, scont.rule_in_location.rule, scont.nextcont, scont.fcont, heap) raise error.UncaughtError(exc_term, exc.sig_context, rule_likely_source, orig_scont) @@ -293,21 +304,23 @@ def __freeze__(self): return True -def _make_rule_conts(engine, scont, fcont, heap, query, rulechain): - rule = jit.hint(rulechain, promote=True) +def _make_rule_conts(engine, scont, fcont, heap, query, rule_in_location): + rule = jit.promote(rule_in_location).rule if rule.contains_cut: scont = CutScopeNotifier.insert_scope_notifier( engine, scont, fcont) restchain = rule.find_next_applicable_rule(query) if restchain is not None: - fcont = UserCallContinuation.make(query.arguments(), engine, scont, fcont, heap, restchain) + restchain_in_location = restchain.get_rule_in_location(query.location()) + fcont = UserCallContinuation.make(query.arguments(), engine, scont, fcont, heap, restchain_in_location) heap = heap.branch() try: shared_env = rule.unify_and_standardize_apart_head(heap, query) except error.UnificationFailed: return fcont.fail(heap) - scont = RuleContinuation.make(shared_env, engine, scont, rule) + rule_in_location = rule.get_rule_in_location(query.location()) + scont = RuleContinuation.make(shared_env, engine, scont, rule_in_location) return scont, fcont, heap # ___________________________________________________________________ @@ -356,15 +369,15 @@ _dot = _dot -class ContinuationWithRule(Continuation): +class ContinuationWithRuleInLocation(Continuation): """ This class represents continuations which need to have a reference to the current rule (e.g. to get at the module). """ - def __init__(self, engine, nextcont, rule): + def __init__(self, engine, nextcont, rule_in_location): + assert isinstance(rule_in_location, RuleInLocation) Continuation.__init__(self, engine, nextcont) - assert isinstance(rule, Rule) - self.rule = rule + self.rule_in_location = rule_in_location def view(*objects, **names): from dotviewer import graphclient @@ -445,11 +458,12 @@ return True -class BodyContinuation(ContinuationWithRule): +class BodyContinuation(Continuation): """ Represents a bit of Prolog code that is still to be called. """ def __init__(self, engine, rule, nextcont, body): - ContinuationWithRule.__init__(self, engine, nextcont, rule) + Continuation.__init__(self, engine, nextcont) self.body = body + self.rule = rule def activate(self, fcont, heap): return self.engine.call(self.body, self.rule, self.nextcont, fcont, heap) @@ -457,15 +471,15 @@ def __repr__(self): return "" % (self.body, ) -class BuiltinContinuation(ContinuationWithRule): +class BuiltinContinuation(ContinuationWithRuleInLocation): """ Represents the call to a builtin. """ def __init__(self, engine, rule, nextcont, builtin, query): - ContinuationWithRule.__init__(self, engine, nextcont, rule) + ContinuationWithRuleInLocation.__init__(self, engine, nextcont, rule) self.builtin = builtin self.query = query def activate(self, fcont, heap): - return self.builtin.call(self.engine, self.query, self.rule, + return self.builtin.call(self.engine, self.query, self.rule_in_location.rule, self.nextcont, fcont, heap) def __repr__(self): @@ -474,45 +488,45 @@ @inline_small_list(immutable=True) class UserCallContinuation(FailureContinuation): - def __init__(self, engine, nextcont, orig_fcont, heap, rulechain): + def __init__(self, engine, nextcont, orig_fcont, heap, rule_in_location): FailureContinuation.__init__(self, engine, nextcont, orig_fcont, heap) - self.rulechain = rulechain + self.rule_in_location = rule_in_location def fail(self, heap): heap = heap.revert_upto(self.undoheap, discard_choicepoint=True) - query = self.rulechain.build_query(self._get_full_list()) + query = self.rule_in_location.rule.build_query(self._get_full_list()) return _make_rule_conts(self.engine, self.nextcont, self.orig_fcont, - heap, query, self.rulechain) + heap, query, self.rule_in_location) def __repr__(self): - query = self.rulechain.build_query(self._get_full_list()) + query = self.rule_in_location.rule.build_query(self._get_full_list()) return "" % ( - query, self.rulechain) + query, self.rule_in_location.rule) @inline_small_list(immutable=True) -class RuleContinuation(ContinuationWithRule): +class RuleContinuation(ContinuationWithRuleInLocation): """ A Continuation that represents the application of a rule, i.e.: - standardizing apart of the rule - unifying the rule head with the query - calling the body of the rule """ - def __init__(self, engine, nextcont, rule): - ContinuationWithRule.__init__(self, engine, nextcont, rule) + def __init__(self, engine, nextcont, rule_in_location): + ContinuationWithRuleInLocation.__init__(self, engine, nextcont, rule_in_location) def activate(self, fcont, heap): nextcont = self.nextcont - rule = jit.promote(self.rule) + rule = jit.promote(self.rule_in_location).rule nextcall = rule.clone_body_from_rulecont(heap, self) if nextcall is not None: - return self.engine.call(nextcall, self.rule, nextcont, fcont, heap) + return self.engine.call(nextcall, rule, nextcont, fcont, heap) else: cont = nextcont return cont, fcont, heap def __repr__(self): - return "" % (self.rule, self.query) + return "" % (self.rule_in_location.rule, self.query) class CutScopeNotifier(Continuation): def __init__(self, engine, nextcont, fcont_after_cut): @@ -532,9 +546,10 @@ return self.nextcont, fcont, heap -class CatchingDelimiter(ContinuationWithRule): +class CatchingDelimiter(ContinuationWithRuleInLocation): def __init__(self, engine, rule, nextcont, fcont, catcher, recover, heap): - ContinuationWithRule.__init__(self, engine, nextcont, rule) + rule_in_location = rule.get_rule_in_location(recover.location()) + ContinuationWithRuleInLocation.__init__(self, engine, nextcont, rule_in_location) self.catcher = catcher self.recover = recover self.fcont = fcont diff --git a/prolog/interpreter/error.py b/prolog/interpreter/error.py --- a/prolog/interpreter/error.py +++ b/prolog/interpreter/error.py @@ -122,13 +122,13 @@ self.next._format(out) def _construct_traceback(scont): - from prolog.interpreter.continuation import ContinuationWithRule + from prolog.interpreter.continuation import ContinuationWithRuleInLocation if scont is None: return None next = None while not scont.is_done(): - if isinstance(scont, ContinuationWithRule): - next = TraceFrame(scont.rule, next) + if isinstance(scont, ContinuationWithRuleInLocation): + next = TraceFrame(scont.rule_in_location.rule, next) scont = scont.nextcont return next diff --git a/prolog/interpreter/function.py b/prolog/interpreter/function.py --- a/prolog/interpreter/function.py +++ b/prolog/interpreter/function.py @@ -14,7 +14,7 @@ _attrs_ = ['next', 'head', 'headargs', 'groundargs', 'contains_cut', 'body', 'env_size_shared', 'env_size_body', 'env_size_head', 'signature', 'module', 'file_name', - 'line_range', 'source'] + 'line_range', 'source', 'location_cache'] unrolling_attrs = unroll.unrolling_iterable(_attrs_) def __init__(self, head, body, module, next = None): @@ -50,8 +50,18 @@ self.line_range = None self.source = None + self.location_cache = {} + self._does_contain_cut() + @jit.elidable + def get_rule_in_location(self, location): + if location in self.location_cache: + return self.location_cache[location] + self.location_cache[location] = res = RuleInLocation(self, location) + return res + + def _init_source_info(self, tree, source_info): from rpython.rlib.parsing.tree import Nonterminal, Symbol start_source_pos = tree.getsourcepos() @@ -187,6 +197,14 @@ def __ne__(self, other): return not self == other +class RuleInLocation(object): + _immutable_fields_ = ["rule", "location"] + + def __init__(self, rule, location): + self.rule = rule + self.location = location + + def _make_toplevel_rule(module): # this is a rule object that is used for error messages when running # toplevel goals