[pypy-commit] pypy gcstress-hypothesis: added some tests to ensure bytecode generation considers the top elements on the stack
plan_rich
pypy.commits at gmail.com
Fri Mar 4 09:59:09 EST 2016
Author: Richard Plangger <planrichi at gmail.com>
Branch: gcstress-hypothesis
Changeset: r82769:13234c967ffc
Date: 2016-03-04 10:40 +0100
http://bitbucket.org/pypy/pypy/changeset/13234c967ffc/
Log: added some tests to ensure bytecode generation considers the top
elements on the stack
diff --git a/rpython/jit/backend/llsupport/tl/code.py b/rpython/jit/backend/llsupport/tl/code.py
--- a/rpython/jit/backend/llsupport/tl/code.py
+++ b/rpython/jit/backend/llsupport/tl/code.py
@@ -10,6 +10,14 @@
pt = getattr(self.__init__, '_param_types', [])
return self(*[draw(get_strategy_for(t)) for t in pt])
+ def filter_bytecode(self, stack):
+ """ filter this byte code if the stack does
+ not contain the right values on the stack.
+ This should only be used for values hypothesis
+ cannot forsee (like list manipulation)
+ """
+ return False
+
_c = 0
LIST_TYP = 'l'
@@ -154,6 +162,12 @@
BYTE_CODE = unique_code()
def __init__(self):
pass
+ def filter_bytecode(self, stack):
+ w_idx = stack.peek(1)
+ w_list = stack.peek(2)
+ if w_idx.value >= len(w_list.items):
+ return True
+ return False
@requires_stack(LIST_TYP, IDX_TYP)
@leaves_on_stack(LIST_TYP)
@@ -161,6 +175,12 @@
BYTE_CODE = unique_code()
def __init__(self):
pass
+ def filter_bytecode(self, stack):
+ w_idx = stack.peek(0)
+ w_list = stack.peek(1)
+ if w_idx.value >= len(w_list.items):
+ return True
+ return False
@requires_stack(LIST_TYP, INT_TYP) # TODO VAL_TYP)
@leaves_on_stack(LIST_TYP)
@@ -169,6 +189,8 @@
def __init__(self):
pass
+def op_modifies_list(clazz):
+ return clazz in (DelList, InsertList)
# remove comment one by one!
diff --git a/rpython/jit/backend/llsupport/tl/interp.py b/rpython/jit/backend/llsupport/tl/interp.py
--- a/rpython/jit/backend/llsupport/tl/interp.py
+++ b/rpython/jit/backend/llsupport/tl/interp.py
@@ -8,6 +8,8 @@
pass
class W_ListObject(W_Root):
+ TYPE = code.LIST_TYP
+
def __init__(self, items):
self.items = items
@@ -17,9 +19,11 @@
def is_of_type(self, type):
""" NOT_RPYTHON """
- return type in (LIST_TYP,)
+ return type in (code.LIST_TYP,)
class W_IntObject(W_Root):
+ TYPE = code.INT_TYP
+
def __init__(self, value):
self.value = value
@@ -37,6 +41,8 @@
code.BYTE_TYP)
class W_StrObject(W_Root):
+ TYPE = code.STR_TYP
+
def __init__(self, value):
self.value = value
@@ -79,8 +85,6 @@
def entry_point(argv):
bytecode = _read_bytecode_from_file(argv[1])
consts = _read_consts_from_file(argv[2])
- print(bytecode)
- print(consts)
pc = 0
end = len(bytecode)
stack = Stack(16)
diff --git a/rpython/jit/backend/llsupport/tl/stack.py b/rpython/jit/backend/llsupport/tl/stack.py
--- a/rpython/jit/backend/llsupport/tl/stack.py
+++ b/rpython/jit/backend/llsupport/tl/stack.py
@@ -19,6 +19,13 @@
def size(self):
return self.stackpos
+ def copy(self):
+ """ NOT_RPYTHON """
+ copy = Stack(self.size())
+ for item in self.stack:
+ copy.append(item)
+ return copy
+
def append(self, elem):
while len(self.stack) <= self.stackpos:
self.stack.append(None)
@@ -72,3 +79,9 @@
n = self.stackpos - 1
assert n >= 0
self.stack[n] = elem
+
+ def __repr__(self):
+ """ NOT_RPYTHON """
+ entry_types = [e.TYPE for e in self.stack]
+ return "Stack(%s)" % ','.join(entry_types)
+
diff --git a/rpython/jit/backend/llsupport/tl/test/code_strategies.py b/rpython/jit/backend/llsupport/tl/test/code_strategies.py
--- a/rpython/jit/backend/llsupport/tl/test/code_strategies.py
+++ b/rpython/jit/backend/llsupport/tl/test/code_strategies.py
@@ -28,29 +28,15 @@
STD_SPACE = interp.Space()
-#@composite
-#def runtime_stack(draw, clazz):
-# strats = [get_strategy_for(t) for t in clazz._stack_types]
-# stack_obj = stack.Stack(len(strats))
-# for i,strat in enumerate(strats):
-# if clazz._stack_types[i] == IDX_TYP:
-# # it is only valid to access a list with a valid index!
-# w_list = stack_obj.peek(i-1)
-# l = len(w_list.items)
-# assume(l > 0)
-# integrals = st.integers(min_value=0, max_value=l-1)
-# stack_obj.append(STD_SPACE.wrap(draw(integrals)))
-# continue
-# stack_obj.append(STD_SPACE.wrap(draw(strat)))
-# return stack_obj
-
@defines_strategy
def stack_entry(types=all_types):
- return st.sampled_from([get_strategy_for(t) for t in types])
+ return st.one_of(*[get_strategy_for(t) for t in types])
@defines_strategy
def runtime_stack(min_size=0, average_size=5, max_size=4096,
types=all_types):
+ if max_size < average_size:
+ average_size = max_size // 2
stack_entries = st.lists(stack_entry(all_types), min_size,
average_size, max_size)
return stack_entries.map(lambda elems: \
@@ -67,30 +53,50 @@
return clazz
return None
+def find_next(stack, type, off=0):
+ i = off
+ while i < stack.size():
+ if stack.peek(i).is_of_type(LIST_TYP):
+ break
+ i += 1
+ else:
+ return None
+ return stack.peek(i)
@defines_strategy
def bytecode_class(stack):
def filter_using_stack(bytecode_class):
- required_types = bytecode_class.requires_stack
- if len(required_types) < stack.size():
+ required_types = bytecode_class._stack_types
+ if len(required_types) > stack.size():
return False
- j = len(required_types)-1
- for i in range(stack.size()):
+ for i in range(len(required_types)):
item = stack.peek(i)
- if not item.is_of_type(required_types[j]):
+ j = len(required_types) - i - 1
+ rt = required_types[j]
+ if not item.is_of_type(rt):
return False
- j -= 1
- if j < 0:
- break
+ if code.op_modifies_list(bytecode_class):
+ w_list = find_next(stack, LIST_TYP)
+ if w_list is None or len(w_list.items) == 0:
+ # on an empty list we cannot insert or delete
+ return False
return True
- return st.sampled_from(byte_code_classes()).filter(filter_using_stack)
+ clazzes = filter(filter_using_stack, byte_code_classes())
+ return st.sampled_from(clazzes)
@composite
def bytecode(draw, max_stack_size=4096):
# get a stack that is the same for one test run
- rs = runtime_stack(max_size=max_stack_size)
- stack = draw(st.shared(rs, 'stack'))
- clazz = draw(bytecode_class(stack))
+ stack_strat = runtime_stack(max_size=max_stack_size)
+ run_stack = draw(st.shared(stack_strat, 'stack'))
+
+ # get a byte code class
+ clazz = draw(bytecode_class(run_stack))
inst = clazz.create_from(draw, get_strategy_for)
+ assume(not inst.filter_bytecode(run_stack))
bytecode, consts = code.Context().transform([inst])
- return bytecode, consts, stack
+
+ # propagate the changes to the stack
+ orig_stack = run_stack.copy()
+ interp.dispatch_once(STD_SPACE, 0, bytecode, consts, run_stack)
+ return inst, orig_stack
diff --git a/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py b/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
--- a/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
+++ b/rpython/jit/backend/llsupport/tl/test/test_tl_interp.py
@@ -1,6 +1,6 @@
import py
from hypothesis import given
-from hypothesis.strategies import lists
+from hypothesis.strategies import lists, data
from rpython.jit.backend.llsupport.tl import code, interp
from rpython.jit.backend.llsupport.tl.stack import Stack
from rpython.jit.backend.llsupport.tl.test import code_strategies as st
@@ -22,19 +22,88 @@
assert c.get_byte(4) == code.AddStr.BYTE_CODE
assert c.get_short(3) == 1
+class TestCodeStrategies(object):
+
+ DEFAULT_ACTION_CLASSES = (code.CreateList, code.PutInt,
+ code.LoadStr)
+
+ @given(data())
+ def test_bytecode_class_generation(self, data):
+ space = interp.Space()
+ stack = Stack(0)
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES)
+
+ @given(data())
+ def test_bytecode_class_generation_int(self, data):
+ space = interp.Space()
+ stack = Stack(0)
+ stack.append(space.wrap(0))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES)
+ stack.append(space.wrap(0))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES + \
+ (code.CompareInt,))
+
+ @given(data())
+ def test_bytecode_class_generation_str(self, data):
+ space = interp.Space()
+ stack = Stack(0)
+ stack.append(space.wrap("hello"))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES)
+ stack.append(space.wrap("world"))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES + \
+ (code.AddStr,))
+
+ @given(data())
+ def test_bytecode_class_generation_list(self, data):
+ space = interp.Space()
+ stack = Stack(0)
+ stack.append(space.wrap([]))
+ stack.append(space.wrap(0))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz not in (code.InsertList, code.DelList))
+ stack.append(space.wrap([space.wrap(1)]))
+ stack.append(space.wrap(0))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES + \
+ (code.DelList, code.AppendList))
+ stack.append(space.wrap("haskell"))
+ for i in range(10):
+ clazz = data.draw(st.bytecode_class(stack))
+ assert(clazz in self.DEFAULT_ACTION_CLASSES + \
+ (code.InsertList, code.AppendList))
+
+
class TestInterp(object):
@given(st.bytecode())
def test_consume_stack(self, args):
- bytecode, consts, stack = args
+ bc_obj, stack = args
+ bytecode, consts = code.Context().transform([bc_obj])
space = interp.Space()
i = interp.dispatch_once(space, 0, bytecode, consts, stack)
assert i == len(bytecode)
clazz = st.get_byte_code_class(ord(bytecode[0]))
- assert stack.size() == len(clazz._return_on_stack_types)
+ assert stack.size() >= len(clazz._return_on_stack_types)
+ for i,type in enumerate(clazz._return_on_stack_types):
+ j = len(clazz._return_on_stack_types) - i - 1
+ assert stack.peek(j).is_of_type(type)
- @given(lists(st.bytecode(max_stack_size=0)))
- def test_execute_bytecode_block(self, args):
- bytecode, consts, _ = args
+ @given(lists(st.bytecode(max_stack_size=0), min_size=1))
+ def test_execute_bytecode_block(self, codes):
+ bc_obj_list = [bc for bc,stack in codes]
+ _, stack = codes[0]
+ bytecode, consts = code.Context().transform(bc_obj_list)
space = interp.Space()
stack = Stack(16)
pc = 0
More information about the pypy-commit
mailing list