Author: Carl Friedrich Bolz-Tereick <cfb...@gmx.de> Branch: fix-sre-problems Changeset: r94135:b3264f1f3592 Date: 2018-03-26 18:01 +0200 http://bitbucket.org/pypy/pypy/changeset/b3264f1f3592/
Log: fix issue 2777: before this commit, the following problem could occur: when the tags of the opencoder overflow, it raises SwitchToBlackHole in the middle of a jitcode opcode. Potentially, in the middle of a guard, *before* the guard changed the pc on the MIFrame! That way, the blackhole interpreter would continue in the wrong branch :-(. Fix this by changing the interface slightly: opencoder.Trace.record will now just not record anything, if the tags overflow. Instead, it will set a flag on itself, which the metatracer needs to check after every opcode, to find out whether to stop tracing. diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -701,6 +701,9 @@ def length(self): return self.trace._count - len(self.trace.inputargs) + def trace_tag_overflow(self): + return self.trace.tag_overflow + def get_trace_position(self): return self.trace.cut_point() diff --git a/rpython/jit/metainterp/opencoder.py b/rpython/jit/metainterp/opencoder.py --- a/rpython/jit/metainterp/opencoder.py +++ b/rpython/jit/metainterp/opencoder.py @@ -293,6 +293,7 @@ self._start = len(inputargs) self._pos = self._start self.inputargs = inputargs + self.tag_overflow = False def append(self, v): model = get_model(self) @@ -300,7 +301,8 @@ # grow by 2X self._ops = self._ops + [rffi.cast(model.STORAGE_TP, 0)] * len(self._ops) if not model.MIN_VALUE <= v <= model.MAX_VALUE: - raise frontend_tag_overflow() + v = 0 # broken value, but that's fine, tracing will stop soon + self.tag_overflow = True self._ops[self._pos] = rffi.cast(model.STORAGE_TP, v) self._pos += 1 @@ -379,6 +381,7 @@ def record_op(self, opnum, argboxes, descr=None): pos = self._index + old_pos = self._pos self.append(opnum) expected_arity = oparity[opnum] if expected_arity == -1: @@ -397,6 +400,10 @@ self._count += 1 if opclasses[opnum].type != 'v': self._index += 1 + if self.tag_overflow: + # potentially a broken op is left behind + # clean it up + self._pos = old_pos return pos def _encode_descr(self, descr): @@ -424,10 +431,11 @@ vref_array = self._list_of_boxes(vref_boxes) s = TopSnapshot(combine_uint(jitcode.index, pc), array, vable_array, vref_array) - assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0 # guards have no descr self._snapshots.append(s) - self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1) + if not self.tag_overflow: # otherwise we're broken anyway + assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0 + self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1) return s def create_empty_top_snapshot(self, vable_boxes, vref_boxes): @@ -436,10 +444,11 @@ vref_array = self._list_of_boxes(vref_boxes) s = TopSnapshot(combine_uint(2**16 - 1, 0), [], vable_array, vref_array) - assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0 # guards have no descr self._snapshots.append(s) - self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1) + if not self.tag_overflow: # otherwise we're broken anyway + assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0 + self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1) return s def create_snapshot(self, jitcode, pc, frame, flag): diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -2384,7 +2384,8 @@ def blackhole_if_trace_too_long(self): warmrunnerstate = self.jitdriver_sd.warmstate - if self.history.length() > warmrunnerstate.trace_limit: + if (self.history.length() > warmrunnerstate.trace_limit or + self.history.trace_tag_overflow()): jd_sd, greenkey_of_huge_function = self.find_biggest_function() self.history.trace.done() self.staticdata.stats.record_aborted(greenkey_of_huge_function) diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py --- a/rpython/jit/metainterp/test/test_ajit.py +++ b/rpython/jit/metainterp/test/test_ajit.py @@ -4661,3 +4661,36 @@ f() # finishes self.meta_interp(f, []) + + def test_trace_too_long_bug(self): + driver = JitDriver(greens=[], reds=['i']) + @unroll_safe + def match(s): + l = len(s) + p = 0 + for i in range(2500): # produces too long trace + c = s[p] + if c != 'a': + return False + p += 1 + if p >= l: + return True + c = s[p] + if c != '\n': + p += 1 + if p >= l: + return True + else: + return False + return True + + def f(i): + while i > 0: + driver.jit_merge_point(i=i) + match('a' * (500 * i)) + i -= 1 + return i + + res = self.meta_interp(f, [10]) + assert res == f(10) + diff --git a/rpython/jit/metainterp/test/test_opencoder.py b/rpython/jit/metainterp/test/test_opencoder.py --- a/rpython/jit/metainterp/test/test_opencoder.py +++ b/rpython/jit/metainterp/test/test_opencoder.py @@ -209,5 +209,8 @@ def test_tag_overflow(self): t = Trace([], metainterp_sd) i0 = FakeOp(100000) - py.test.raises(SwitchToBlackhole, t.record_op, rop.FINISH, [i0]) - assert t.unpack() == ([], []) + # if we overflow, we can keep recording + for i in range(10): + t.record_op(rop.FINISH, [i0]) + assert t.unpack() == ([], []) + assert t.tag_overflow diff --git a/rpython/rlib/rsre/test/test_zjit.py b/rpython/rlib/rsre/test/test_zjit.py --- a/rpython/rlib/rsre/test/test_zjit.py +++ b/rpython/rlib/rsre/test/test_zjit.py @@ -11,6 +11,8 @@ match = None for i in range(repeat): match = rsre_core.match(r, string) + if match is None: + return -1 if match is None: return -1 else: @@ -166,3 +168,9 @@ res = self.meta_interp_search(r"b+", "a"*30 + "b") assert res == 30 self.check_resops(call=0) + + def test_match_jit_bug(self): + pattern = ".a" * 2500 + text = "a" * 6000 + res = self.meta_interp_match(pattern, text, repeat=10) + assert res != -1 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit