Author: Armin Rigo <[email protected]>
Branch:
Changeset: r76742:1c3d074e06b7
Date: 2015-04-07 20:17 +0200
http://bitbucket.org/pypy/pypy/changeset/1c3d074e06b7/
Log: Add a new EF_ELIDABLE_OR_MEMORYERROR for elidable functions that
could raise, but only MemoryError
diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py
--- a/rpython/jit/codewriter/call.py
+++ b/rpython/jit/codewriter/call.py
@@ -31,6 +31,8 @@
self.rtyper = cpu.rtyper
translator = self.rtyper.annotator.translator
self.raise_analyzer = RaiseAnalyzer(translator)
+ self.raise_analyzer_ignore_memoryerror = RaiseAnalyzer(translator)
+ self.raise_analyzer_ignore_memoryerror.do_ignore_memory_error()
self.readwrite_analyzer = ReadWriteAnalyzer(translator)
self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
self.quasiimmut_analyzer = QuasiImmutAnalyzer(translator)
@@ -260,11 +262,14 @@
elif loopinvariant:
extraeffect = EffectInfo.EF_LOOPINVARIANT
elif elidable:
- if self._canraise(op):
+ cr = self._canraise(op)
+ if cr == "mem":
+ extraeffect = EffectInfo.EF_ELIDABLE_OR_MEMORYERROR
+ elif cr:
extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE
else:
extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE
- elif self._canraise(op):
+ elif self._canraise(op): # True or "mem"
extraeffect = EffectInfo.EF_CAN_RAISE
else:
extraeffect = EffectInfo.EF_CANNOT_RAISE
@@ -278,6 +283,7 @@
" effects): EF=%s" % (op, extraeffect))
if elidable:
if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
+ EffectInfo.EF_ELIDABLE_OR_MEMORYERROR,
EffectInfo.EF_ELIDABLE_CAN_RAISE):
raise Exception(
"in operation %r: this calls an _elidable_function_,"
@@ -301,10 +307,17 @@
effectinfo)
def _canraise(self, op):
+ """Returns True, False, or "mem" to mean 'only MemoryError'."""
if op.opname == 'pseudo_call_cannot_raise':
return False
try:
- return self.raise_analyzer.can_raise(op)
+ if self.raise_analyzer.can_raise(op):
+ if self.raise_analyzer_ignore_memoryerror.can_raise(op):
+ return True
+ else:
+ return "mem"
+ else:
+ return False
except lltype.DelayedPointer:
return True # if we need to look into the delayed ptr that is
# the portal, then it's certainly going to raise
diff --git a/rpython/jit/codewriter/effectinfo.py
b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -11,10 +11,11 @@
EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot
raise)
EF_LOOPINVARIANT = 1 #special: call it only once per loop
EF_CANNOT_RAISE = 2 #a function which cannot raise
- EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise)
- EF_CAN_RAISE = 4 #normal function (can raise)
- EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables
- EF_RANDOM_EFFECTS = 6 #can do whatever
+ EF_ELIDABLE_OR_MEMORYERROR = 3 #elidable, can only raise
MemoryError
+ EF_ELIDABLE_CAN_RAISE = 4 #elidable function (but can raise)
+ EF_CAN_RAISE = 5 #normal function (can raise)
+ EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 6 #can raise and force virtualizables
+ EF_RANDOM_EFFECTS = 7 #can do whatever
# the 'oopspecindex' field is one of the following values:
OS_NONE = 0 # normal case, no oopspec
@@ -139,6 +140,7 @@
result.readonly_descrs_interiorfields = readonly_descrs_interiorfields
if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \
+ extraeffect == EffectInfo.EF_ELIDABLE_OR_MEMORYERROR or \
extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE:
result.write_descrs_fields = []
result.write_descrs_arrays = []
@@ -152,19 +154,23 @@
result.oopspecindex = oopspecindex
result.extradescrs = extradescrs
result.call_release_gil_target = call_release_gil_target
- if result.check_can_raise():
+ if result.check_can_raise(ignore_memoryerror=True):
assert oopspecindex in cls._OS_CANRAISE
cls._cache[key] = result
return result
- def check_can_raise(self):
- return self.extraeffect > self.EF_CANNOT_RAISE
+ def check_can_raise(self, ignore_memoryerror=False):
+ if ignore_memoryerror:
+ return self.extraeffect > self.EF_ELIDABLE_OR_MEMORYERROR
+ else:
+ return self.extraeffect > self.EF_CANNOT_RAISE
def check_can_invalidate(self):
return self.can_invalidate
def check_is_elidable(self):
return (self.extraeffect == self.EF_ELIDABLE_CAN_RAISE or
+ self.extraeffect == self.EF_ELIDABLE_OR_MEMORYERROR or
self.extraeffect == self.EF_ELIDABLE_CANNOT_RAISE)
def check_forces_virtual_or_virtualizable(self):
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1847,6 +1847,13 @@
def _handle_stroruni_call(self, op, oopspec_name, args):
SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
+ can_raise_memoryerror = {
+ "stroruni.concat": True,
+ "stroruni.slice": True,
+ "stroruni.equal": False,
+ "stroruni.cmp": False,
+ "stroruni.copy_string_to_raw": False,
+ }
if SoU.TO == rstr.STR:
dict = {"stroruni.concat": EffectInfo.OS_STR_CONCAT,
"stroruni.slice": EffectInfo.OS_STR_SLICE,
@@ -1913,8 +1920,11 @@
argtypes, resulttype,
EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
#
- return self._handle_oopspec_call(op, args, dict[oopspec_name],
- EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
+ if can_raise_memoryerror[oopspec_name]:
+ extra = EffectInfo.EF_ELIDABLE_OR_MEMORYERROR
+ else:
+ extra = EffectInfo.EF_ELIDABLE_CANNOT_RAISE
+ return self._handle_oopspec_call(op, args, dict[oopspec_name], extra)
def _handle_str2unicode_call(self, op, oopspec_name, args):
# ll_str2unicode can raise UnicodeDecodeError
diff --git a/rpython/jit/codewriter/test/test_call.py
b/rpython/jit/codewriter/test/test_call.py
--- a/rpython/jit/codewriter/test/test_call.py
+++ b/rpython/jit/codewriter/test/test_call.py
@@ -6,6 +6,7 @@
from rpython.rlib import jit
from rpython.jit.codewriter import support, call
from rpython.jit.codewriter.call import CallControl
+from rpython.jit.codewriter.effectinfo import EffectInfo
class FakePolicy:
@@ -279,3 +280,39 @@
call_descr = cc.getcalldescr(op)
assert not call_descr.extrainfo.has_random_effects()
assert call_descr.extrainfo.check_is_elidable()
+
+def test_elidable_kinds():
+ from rpython.jit.backend.llgraph.runner import LLGraphCPU
+
+ @jit.elidable
+ def f1(n, m):
+ return n + m
+ @jit.elidable
+ def f2(n, m):
+ return [n, m] # may raise MemoryError
+ @jit.elidable
+ def f3(n, m):
+ if n > m:
+ raise ValueError
+ return n + m
+
+ def f(n, m):
+ a = f1(n, m)
+ b = f2(n, m)
+ c = f3(n, m)
+ return a + len(b) + c
+
+ rtyper = support.annotate(f, [7, 9])
+ jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
+ cc = CallControl(LLGraphCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
+ res = cc.find_all_graphs(FakePolicy())
+ [f_graph] = [x for x in res if x.func is f]
+
+ for index, expected in [
+ (0, EffectInfo.EF_ELIDABLE_CANNOT_RAISE),
+ (1, EffectInfo.EF_ELIDABLE_OR_MEMORYERROR),
+ (2, EffectInfo.EF_ELIDABLE_CAN_RAISE)]:
+ call_op = f_graph.startblock.operations[index]
+ assert call_op.opname == 'direct_call'
+ call_descr = cc.getcalldescr(call_op)
+ assert call_descr.extrainfo.extraeffect == expected
diff --git a/rpython/jit/codewriter/test/test_jtransform.py
b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -161,6 +161,9 @@
assert extraeffect == EI.EF_CANNOT_RAISE
elif oopspecindex == EI.OS_THREADLOCALREF_GET:
assert extraeffect ==
self.expected_effect_of_threadlocalref_get
+ elif oopspecindex in (EI.OS_STR_CONCAT, EI.OS_UNI_CONCAT,
+ EI.OS_STR_SLICE, EI.OS_UNI_SLICE):
+ assert extraeffect == EI.EF_ELIDABLE_OR_MEMORYERROR
else:
assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
return 'calldescr-%d' % oopspecindex
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit