intermediate checkin: use rule_in_location in continuations

bit of a mess
3 files changed, 77 insertions(+), 44 deletions(-)

M prolog/interpreter/continuation.py
M prolog/interpreter/error.py
M prolog/interpreter/function.py
M prolog/interpreter/continuation.py +55 -40
@@ 5,7 5,7 @@ from rpython.rlib.objectmodel import we_
 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 @@ Signature.register_extr_attr("function",
 # ___________________________________________________________________
 # 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 @@ predsig = Signature.getsignature(":-", 2
 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 @@ jitdriver = jit.JitDriver(
 
 
 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 @@ def driver(scont, fcont, heap):
                     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 @@ class Engine(object):
             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 @@ class Engine(object):
         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 @@ class Engine(object):
                 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 @@ class Engine(object):
     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 @@ class Continuation(object):
 
     _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 @@ class DoneFailureContinuation(FailureCon
         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 @@ class BodyContinuation(ContinuationWithR
     def __repr__(self):
         return "<BodyContinuation %r>" % (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 @@ class BuiltinContinuation(ContinuationWi
 
 @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 "<UserCallContinuation query=%r rule=%r>" % (
-                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 "<RuleContinuation rule=%r query=%r>" % (self.rule, self.query)
+        return "<RuleContinuation rule=%r query=%r>" % (self.rule_in_location.rule, self.query)
 
 class CutScopeNotifier(Continuation):
     def __init__(self, engine, nextcont, fcont_after_cut):

          
@@ 532,9 546,10 @@ class CutScopeNotifier(Continuation):
         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

          
M prolog/interpreter/error.py +3 -3
@@ 122,13 122,13 @@ class TraceFrame(object):
             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
 

          
M prolog/interpreter/function.py +19 -1
@@ 14,7 14,7 @@ class Rule(object):
     _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 @@ class Rule(object):
         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 @@ class Rule(object):
     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