From cfbolz at codespeak.net Tue Apr 1 00:28:30 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Apr 2008 00:28:30 +0200 (CEST) Subject: [pypy-svn] r53221 - in pypy/branch/jit-hotpath/pypy/jit/rainbow: . test Message-ID: <20080331222830.8DE1816844B@codespeak.net> Author: cfbolz Date: Tue Apr 1 00:28:29 2008 New Revision: 53221 Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py Log: fix a bug in the fallback interp Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py Tue Apr 1 00:28:29 2008 @@ -36,6 +36,25 @@ jitstate.residual_ll_exception(ll_exc) +def make_colororder(graph, hannotator): + # if the graph takes both red and green arguments, we need + # a way for the fallback interp to rezip the two lists + # 'greenargs' and 'redargs' into a single one + colororder = "" + in_order = True # "in order" means allgreens+allreds + for v in graph.getargs(): + if v.concretetype is lltype.Void: + continue + if hannotator.binding(v).is_green(): + if "r" in colororder: + in_order = False + colororder += "g" + else: + colororder += "r" + if in_order: + colororder = None + return colororder + class CallDesc: __metaclass__ = cachedtype @@ -131,6 +150,9 @@ fnptr = codewriter.rtyper.getcallable(graph) keys.append(llmemory.cast_ptr_to_adr(fnptr)) values.append(codewriter.get_jitcode(tsgraph)) + # arbitrarily use the last graph to make the colororder - + # normalization should ensure that all colors are the same + colororder = make_colororder(tsgraph, codewriter.hannotator) def bytecode_for_address(fnaddress): # XXX optimize @@ -143,7 +165,7 @@ self.graphs = [graph for (graph, tsgraph) in graph2tsgraph] self.jitcodes = values self.calldesc = CallDesc(codewriter.RGenOp, codewriter.exceptiondesc, - lltype.typeOf(fnptr)) + lltype.typeOf(fnptr), colororder) class BytecodeWriter(object): @@ -301,22 +323,7 @@ RESULT = graph.getreturnvar().concretetype FUNCTYPE = lltype.FuncType(ARGS, RESULT) - # if the graph takes both red and green arguments, we need - # a way for the fallback interp to rezip the two lists - # 'greenargs' and 'redargs' into a single one - colororder = "" - in_order = True # "in order" means allgreens+allreds - for v in graph.getargs(): - if v.concretetype is lltype.Void: - continue - if self.hannotator.binding(v).is_green(): - if "r" in colororder: - in_order = False - colororder += "g" - else: - colororder += "r" - if in_order: - colororder = None + colororder = make_colororder(graph, self.hannotator) owncalldesc = CallDesc(self.RGenOp, self.exceptiondesc, lltype.Ptr(FUNCTYPE), colororder) # detect the special ts_stub or ts_metacall graphs and replace Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py Tue Apr 1 00:28:29 2008 @@ -3,7 +3,8 @@ from pypy.rlib.jit import JitDriver, hint, JitHintError from pypy.jit.rainbow.test import test_interpreter from pypy.jit.rainbow.hotpath import HotRunnerDesc -from pypy.jit.hintannotator.policy import HintAnnotatorPolicy +from pypy.jit.hintannotator.policy import HintAnnotatorPolicy, \ + StopAtXPolicy from pypy.rpython.llinterp import LLInterpreter from pypy import conftest @@ -587,3 +588,33 @@ res = self.run(ll_function, [40], threshold=2) assert "".join(res.chars) == " ".join([str(i) for i in range(1, 80)]) self.check_insns(malloc=1) + + def test_indirect_call_fallback_color_order(self): + class A(object): + def g(self, green, red): + return red + green + + class B(A): + def g(self, green, red): + return red - green + + myjitdriver = JitDriver(greens = ['x'], + reds = ['a', 'i', 'tot']) + def g(isnotnone): + if isnotnone: + return A() + return B() + def f(isnotnone, x): + a = g(isnotnone) + i = 1024 * 1024 + tot = 0 + while i > 0: + i >>= 1 + tot += a.g(x, i) + hint(x, concrete=True) + myjitdriver.jit_merge_point(tot=tot, i=i, a=a, x=x) + myjitdriver.can_enter_jit(tot=tot, i=i, a=a, x=x) + return tot + res = self.run(f, [False, 5], threshold=4, policy=StopAtXPolicy(g)) + assert res == f(False, 5) + From fijal at codespeak.net Tue Apr 1 01:26:22 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Apr 2008 01:26:22 +0200 (CEST) Subject: [pypy-svn] r53222 - in pypy/branch/js-refactoring/pypy/lang/js: . test Message-ID: <20080331232622.E9EF216845C@codespeak.net> Author: fijal Date: Tue Apr 1 01:26:21 2008 New Revision: 53222 Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/test_parser.py Log: some general progress in area of assignments. Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py Tue Apr 1 01:26:21 2008 @@ -40,16 +40,10 @@ #'!': operations.Not, '+': operations.UPlus, '-': operations.UMinus, - '++': operations.PreIncrement, - '--': operations.PreDecrement, #'typeof': operations.Typeof, #'void': operations.Void, #'delete': operations.Delete, } - POSTFIX_TO_CLS = { - '++': operations.PostIncrement, - '--': operations.PostDecrement, - } LISTOP_TO_CLS = { '[': operations.Array, '{': operations.ObjectInit, @@ -161,14 +155,35 @@ op = node.children[0] pos = self.get_pos(op) child = self.dispatch(node.children[1]) + if op.additional_info in ['++', '--']: + return self._dispatch_assignment(pos, child, op.additional_info, + 'pre') return self.UNOP_TO_CLS[op.additional_info](pos, child) + def _dispatch_assignment(self, pos, left, atype, prepost): + from pypy.lang.js.operations import Identifier, Member, MemberDot,\ + VariableIdentifier + + if isinstance(left, Identifier): + return operations.SimpleAssignment(pos, left, None, atype, prepost) + elif isinstance(left, VariableIdentifier): + return operations.VariableAssignment(pos, left, None, atype, + prepost) + elif isinstance(left, Member): + return operations.MemberAssignment(pos, left.left, left.expr, + None, atype, prepost) + elif isinstance(left, MemberDot): + return operations.MemberDotAssignment(pos, left.left, left.name, + None, atype, prepost) + else: + return operations.SimpleIncrement(pos, left, atype) + def visit_postfixexpression(self, node): op = node.children[1] pos = self.get_pos(op) child = self.dispatch(node.children[0]) - return self.POSTFIX_TO_CLS[op.additional_info](pos, child) - + # all postfix expressions are assignments + return self._dispatch_assignment(pos, child, op.additional_info, 'post') def listop(self, node): op = node.children[0] Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/jscode.py Tue Apr 1 01:26:21 2008 @@ -241,21 +241,46 @@ def __repr__(self): return 'LOAD_FUNCTION' # XXX -class STORE_MEMBER(Opcode): +class BaseStoreMember(Opcode): pass #def eval(self, ctx, ): # XXX -class STORE(Opcode): +class STORE_MEMBER(Opcode): + pass + +class STORE_MEMBER_POSTINCR(Opcode): + pass + +class STORE_MEMBER_PREINCR(Opcode): + pass + +class STORE_MEMBER_SUB(Opcode): + pass + +class BaseStore(Opcode): def __init__(self, name): self.name = name def eval(self, ctx, stack): value = stack[-1] + value = self.process(ctx, self.name, value) ctx.assign(self.name, value) def __repr__(self): - return 'STORE "%s"' % self.name + return '%s "%s"' % (self.__class__.__name__, self.name) + +class STORE(BaseStore): + def process(self, ctx, name, value): + return value + +class STORE_ADD(BaseStore): + def process(self, ctx, name, value): + xxx + +class STORE_POSTINCR(BaseStore): + def process(self, ctx, name, value): + xxx class STORE_VAR(Opcode): def __init__(self, depth, name): @@ -338,17 +363,11 @@ class UMINUS(BaseUnaryOperation): pass -#class PREINCR(BaseUnaryOperation): -# pass - -#class POSTINCR(BaseUnaryOperation): -# pass - -#class PREDECR(BaseUnaryOperation): -# pass +class INCR(BaseUnaryOperation): + pass -#class POSTDECR(BaseUnaryOperation): -# pass +class DECR(BaseUnaryOperation): + pass class GT(BaseBinaryComparison): def decision(self, ctx, op1, op2): Modified: pypy/branch/js-refactoring/pypy/lang/js/operations.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/operations.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/operations.py Tue Apr 1 01:26:21 2008 @@ -121,18 +121,48 @@ bytecode.emit('LOAD_ARRAY', len(self.nodes)) class Assignment(Expression): - pass + def _get_name(self): + addoper = OPERANDS[self.operand] + if addoper: + addoper = '_' + self.prefix.upper() + addoper + return addoper + +OPERANDS = { + '=' : '', + '+=' : 'ADD', + '-=' : 'SUB', + '*=' : 'MUL', + '/=' : 'DIV', + '++' : 'INCR', + '--' : 'DECR', + } + +class SimpleIncrement(Expression): + def __init__(self, pos, left, atype): + self.pos = pos + self.left = left + self.atype = atype + + def emit(self, bytecode): + self.left.emit(bytecode) + if self.atype == '++': + bytecode.emit('INCR') + elif self.atype == '--': + bytecode.emit('DECR') class SimpleAssignment(Assignment): - def __init__(self, pos, left, right, operand): + def __init__(self, pos, left, right, operand, prefix=''): self.identifier = left.get_literal() self.right = right self.pos = pos self.operand = operand + self.prefix = prefix def emit(self, bytecode): - self.right.emit(bytecode) - bytecode.emit('STORE', self.identifier) + if self.right is not None: + self.right.emit(bytecode) + bytecode_name = 'STORE' + self._get_name() + bytecode.emit(bytecode_name, self.identifier) class VariableAssignment(Assignment): def __init__(self, pos, left, right, operand): @@ -147,7 +177,7 @@ bytecode.emit('STORE_VAR', self.depth, self.identifier) class MemberAssignment(Assignment): - def __init__(self, pos, what, item, right, operand): + def __init__(self, pos, what, item, right, operand, prefix=''): # XXX we can optimise here what happens if what is identifier, # but let's leave it alone for now self.pos = pos @@ -155,26 +185,30 @@ self.item = item self.right = right self.operand = operand + self.prefix = prefix def emit(self, bytecode): - self.right.emit(bytecode) + if self.right is not None: + self.right.emit(bytecode) self.item.emit(bytecode) self.what.emit(bytecode) - bytecode.emit('STORE_MEMBER') + bytecode.emit('STORE_MEMBER' + self._get_name()) class MemberDotAssignment(Assignment): - def __init__(self, pos, what, name, right, operand): + def __init__(self, pos, what, name, right, operand, prefix=''): self.pos = pos self.what = what self.itemname = name self.right = right self.operand = operand + self.prefix = prefix def emit(self, bytecode): - self.right.emit(bytecode) + if self.right is not None: + self.right.emit(bytecode) bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) self.what.emit(bytecode) - bytecode.emit('STORE_MEMBER') + bytecode.emit('STORE_MEMBER' + self._get_name()) class StuffAssignment(Expression): def __init__(self, pos, left, right, operand): @@ -507,11 +541,6 @@ # r4 = r1.GetPropertyName() # return W_Boolean(r3.Delete(r4)) -PreIncrement = create_unary_op('PREINCR') -PostIncrement = create_unary_op('POSTINCR') -PreDecrement = create_unary_op('PREDECRE') -PostDecrement = create_unary_op('POSTDECR') - #class Index(BinaryOp): # def eval(self, ctx): # w_obj = self.left.eval(ctx).GetValue().ToObject(ctx) Modified: pypy/branch/js-refactoring/pypy/lang/js/test/test_parser.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/test_parser.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/test_parser.py Tue Apr 1 01:26:21 2008 @@ -360,10 +360,10 @@ 'SUB']) self.check('++5', [ 'LOAD_INTCONSTANT 5', - 'PREINCR']) + 'INCR']) self.check('5--', [ 'LOAD_INTCONSTANT 5', - 'POSTDECR']) + 'DECR']) self.check('"hello " + \'world\'', ['LOAD_STRINGCONSTANT "hello "', 'LOAD_STRINGCONSTANT "world"', @@ -478,6 +478,25 @@ 'STORE_MEMBER', 'POP']) + def test_different_assignments(self): + self.check('x += y', [ + 'LOAD_VARIABLE "y"', + 'STORE_ADD "x"', + 'POP']) + self.check('x++', ['STORE_POSTINCR "x"', + 'POP']) + self.check('++x[2]', [ + 'LOAD_INTCONSTANT 2', + 'LOAD_VARIABLE "x"', + 'STORE_MEMBER_PREINCR', + 'POP']) + self.check('x.y -= 2', + ['LOAD_INTCONSTANT 2', + 'LOAD_STRINGCONSTANT "y"', + 'LOAD_VARIABLE "x"', + 'STORE_MEMBER_SUB', + 'POP']) + from pypy.lang.js.jsparser import parse def test_simplesemicolon(): From fijal at codespeak.net Tue Apr 1 04:39:44 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Apr 2008 04:39:44 +0200 (CEST) Subject: [pypy-svn] r53223 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080401023944.5523E168439@codespeak.net> Author: fijal Date: Tue Apr 1 04:39:42 2008 New Revision: 53223 Modified: pypy/branch/js-refactoring/pypy/lang/js/baseop.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Log: * Fix reprs * First assignments work Modified: pypy/branch/js-refactoring/pypy/lang/js/baseop.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/baseop.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/baseop.py Tue Apr 1 04:39:42 2008 @@ -24,6 +24,12 @@ fright = nright.ToNumber() return W_FloatNumber(fleft + fright) +def increment(ctx, nleft, constval=1): + if isinstance(nleft, W_IntNumber): + return W_IntNumber(nleft.intval + constval) + else: + return plus(ctx, nleft, W_IntNumber(constval)) + def sub(ctx, nleft, nright): if isinstance(nleft, W_IntNumber) and isinstance(nright, W_IntNumber): ileft = nleft.ToInt32() Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/jscode.py Tue Apr 1 04:39:42 2008 @@ -6,7 +6,7 @@ from pypy.lang.js.execution import JsTypeError, ReturnException, ThrowException from pypy.rlib.unroll import unrolling_iterable from pypy.lang.js.baseop import plus, sub, compare, AbstractEC, StrictEC,\ - compare_e + compare_e, increment from pypy.rlib.jit import hint class AlreadyRun(Exception): @@ -28,6 +28,10 @@ if check_stack: assert not stack +class T(list): + def append(self, element): + assert element is not None + super(T, self).append(element) class JsCode(object): """ That object stands for code of a single javascript function @@ -36,7 +40,7 @@ self.opcodes = [] self.label_count = 0 self.has_labels = True - self.stack = [] + self.stack = T() def emit_label(self): num = self.prealocate_label() @@ -121,8 +125,8 @@ class BaseBinaryComparison(Opcode): def eval(self, ctx, stack): - s4 = stack.pop()#.GetValue() - s2 = stack.pop()#.GetValue() + s4 = stack.pop() + s2 = stack.pop() stack.append(self.decision(ctx, s2, s4)) def decision(self, ctx, op1, op2): @@ -130,8 +134,8 @@ class BaseBinaryBitwiseOp(Opcode): def eval(self, ctx, stack): - s5 = stack.pop().ToInt32()#.GetValue().ToInt32() - s6 = stack.pop().ToInt32()#.GetValue().ToInt32() + s5 = stack.pop().ToInt32() + s6 = stack.pop().ToInt32() stack.append(self.operation(ctx, s5, s6)) def operation(self, ctx, op1, op2): @@ -139,8 +143,8 @@ class BaseBinaryOperation(Opcode): def eval(self, ctx, stack): - right = stack.pop()#.GetValue() - left = stack.pop()#.GetValue() + right = stack.pop() + left = stack.pop() stack.append(self.operation(ctx, left, right)) class BaseUnaryOperation(Opcode): @@ -218,7 +222,7 @@ proto = ctx.get_global().Get('Array').Get('prototype') array = W_Array(ctx, Prototype=proto, Class = proto.Class) for i in range(self.counter): - array.Put(str(self.counter - i - 1), stack.pop())#.GetValue()) + array.Put(str(self.counter - i - 1), stack.pop()) stack.append(array) def __repr__(self): @@ -263,24 +267,26 @@ self.name = name def eval(self, ctx, stack): - value = stack[-1] - value = self.process(ctx, self.name, value) + value = self.process(ctx, self.name, stack) ctx.assign(self.name, value) def __repr__(self): return '%s "%s"' % (self.__class__.__name__, self.name) class STORE(BaseStore): - def process(self, ctx, name, value): - return value + def process(self, ctx, name, stack): + return stack[-1] class STORE_ADD(BaseStore): - def process(self, ctx, name, value): + def process(self, ctx, name, stack): xxx class STORE_POSTINCR(BaseStore): - def process(self, ctx, name, value): - xxx + def process(self, ctx, name, stack): + value = ctx.resolve_identifier(name) + newval = increment(ctx, value) + stack.append(newval) + return newval class STORE_VAR(Opcode): def __init__(self, depth, name): @@ -301,8 +307,8 @@ def eval(self, ctx, stack): w_obj = create_object(ctx, 'Object') for _ in range(self.counter): - name = stack.pop().ToString(ctx)#.GetValue().ToString(ctx) - w_elem = stack.pop()#.GetValue() + name = stack.pop().ToString(ctx) + w_elem = stack.pop() w_obj.Put(name, w_elem) stack.append(w_obj) @@ -314,7 +320,7 @@ self.name = name def eval(self, ctx, stack): - w_obj = stack.pop().ToObject(ctx)#GetValue().ToObject(ctx) + w_obj = stack.pop().ToObject(ctx) stack.append(w_obj.Get(self.name)) #stack.append(W_Reference(self.name, w_obj)) @@ -323,8 +329,8 @@ class LOAD_ELEMENT(Opcode): def eval(self, ctx, stack): - name = stack.pop().ToString(ctx)#GetValue().ToString(ctx) - w_obj = stack.pop().ToObject(ctx)#GetValue().ToObject(ctx) + name = stack.pop().ToString(ctx) + w_obj = stack.pop().ToObject(ctx) stack.append(w_obj.Get(name)) #stack.append(W_Reference(name, w_obj)) @@ -508,8 +514,7 @@ def eval(self, ctx, stack): r1 = stack.pop() args = stack.pop() - r3 = r1#.GetValue() - if not isinstance(r3, W_PrimitiveObject): + if not isinstance(r1, W_PrimitiveObject): raise ThrowException(W_String("it is not a callable")) if isinstance(r1, W_Reference): @@ -521,7 +526,7 @@ else: r7 = r6 try: - res = r3.Call(ctx=ctx, args=args.tolist(), this=r7) + res = r1.Call(ctx=ctx, args=args.tolist(), this=r7) except JsTypeError: raise ThrowException(W_String('it is not a function')) stack.append(res) Modified: pypy/branch/js-refactoring/pypy/lang/js/jsobj.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/jsobj.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Tue Apr 1 04:39:42 2008 @@ -413,9 +413,6 @@ def __init__(self, intval): self.intval = intmask(intval) - def __str__(self): - return str(self.intval)+"W" - def ToString(self, ctx=None): return str(self.intval) @@ -435,14 +432,14 @@ def GetPropertyName(self): return self.ToString() + def __repr__(self): + return 'W_IntNumber(%s)' % (self.intval,) + class W_FloatNumber(W_BaseNumber): """ Number known to be a float """ def __init__(self, floatval): self.floatval = floatval - - def __str__(self): - return str(self.floatval)+"W" def ToString(self, ctx = None): if isnan(self.floatval): @@ -474,6 +471,9 @@ if isnan(self.floatval) or isinf(self.floatval): return r_uint(0) return r_uint(self.floatval) + + def __repr__(self): + return 'W_FloatNumber(%s)' % (self.floatval,) class W_List(W_Root): def __init__(self, list_w): @@ -487,10 +487,10 @@ def get_args(self): return self.list_w - - def __str__(self): - return str(self.list_w) + def __repr__(self): + return 'W_List(%s)' % (self.list_w,) + class ExecutionContext(object): def __init__(self, scope, this=None, variable=None, debug=False, jsproperty=None): From fijal at codespeak.net Tue Apr 1 04:53:14 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Apr 2008 04:53:14 +0200 (CEST) Subject: [pypy-svn] r53224 - in pypy/branch/js-refactoring/pypy/lang/js: . test Message-ID: <20080401025314.58EE516843A@codespeak.net> Author: fijal Date: Tue Apr 1 04:53:13 2008 New Revision: 53224 Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: * disable variable assignment, it's not working anyway * make more operations pass Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py Tue Apr 1 04:53:13 2008 @@ -167,7 +167,8 @@ if isinstance(left, Identifier): return operations.SimpleAssignment(pos, left, None, atype, prepost) elif isinstance(left, VariableIdentifier): - return operations.VariableAssignment(pos, left, None, atype, + # XXX exchange to VariableAssignment + return operations.SimpleAssignment(pos, left, None, atype, prepost) elif isinstance(left, Member): return operations.MemberAssignment(pos, left.left, left.expr, @@ -326,7 +327,8 @@ if isinstance(left, Identifier): return operations.SimpleAssignment(pos, left, right, atype) elif isinstance(left, VariableIdentifier): - return operations.VariableAssignment(pos, left, right, atype) + # XXX exchange to VariableAssignment + return operations.SimpleAssignment(pos, left, right, atype) elif isinstance(left, Member): return operations.MemberAssignment(pos, left.left, left.expr, right, atype) Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/jscode.py Tue Apr 1 04:53:13 2008 @@ -245,60 +245,17 @@ def __repr__(self): return 'LOAD_FUNCTION' # XXX -class BaseStoreMember(Opcode): - pass - #def eval(self, ctx, ): - # XXX - -class STORE_MEMBER(Opcode): - pass - -class STORE_MEMBER_POSTINCR(Opcode): - pass - -class STORE_MEMBER_PREINCR(Opcode): - pass - -class STORE_MEMBER_SUB(Opcode): - pass - -class BaseStore(Opcode): - def __init__(self, name): - self.name = name - - def eval(self, ctx, stack): - value = self.process(ctx, self.name, stack) - ctx.assign(self.name, value) - - def __repr__(self): - return '%s "%s"' % (self.__class__.__name__, self.name) - -class STORE(BaseStore): - def process(self, ctx, name, stack): - return stack[-1] - -class STORE_ADD(BaseStore): - def process(self, ctx, name, stack): - xxx - -class STORE_POSTINCR(BaseStore): - def process(self, ctx, name, stack): - value = ctx.resolve_identifier(name) - newval = increment(ctx, value) - stack.append(newval) - return newval - -class STORE_VAR(Opcode): - def __init__(self, depth, name): - self.name = name - self.depth = depth - - def eval(self, ctx, stack): - value = stack[-1] - ctx.scope[self.depth].Put(self.name, value) +# class STORE_VAR(Opcode): +# def __init__(self, depth, name): +# self.name = name +# self.depth = depth + +# def eval(self, ctx, stack): +# value = stack[-1] +# ctx.scope[self.depth].Put(self.name, value) - def __repr__(self): - return 'STORE "%s"' % self.name +# def __repr__(self): +# return 'STORE_VAR "%s"' % self.name class LOAD_OBJECT(Opcode): def __init__(self, counter): @@ -342,15 +299,18 @@ # XXX class SUB(BaseBinaryOperation): - def operation(self, ctx, left, right): + @staticmethod + def operation(ctx, left, right): return sub(ctx, left, right) class ADD(BaseBinaryOperation): - def operation(self, ctx, left, right): + @staticmethod + def operation(ctx, left, right): return plus(ctx, left, right) class BITAND(BaseBinaryBitwiseOp): - def operation(self, ctx, op1, op2): + @staticmethod + def operation(ctx, op1, op2): return W_IntNumber(op1&op2) @@ -407,6 +367,60 @@ def decision(self, ctx, op1, op2): return newbool(not StrictEC(ctx, op1, op2)) + +class BaseStoreMember(Opcode): + pass + #def eval(self, ctx, ): + # XXX + +class STORE_MEMBER(Opcode): + pass + +class STORE_MEMBER_POSTINCR(Opcode): + pass + +class STORE_MEMBER_PREINCR(Opcode): + pass + +class STORE_MEMBER_SUB(Opcode): + pass + +class BaseStore(Opcode): + def __init__(self, name): + self.name = name + + def eval(self, ctx, stack): + value = self.process(ctx, self.name, stack) + ctx.assign(self.name, value) + + def __repr__(self): + return '%s "%s"' % (self.__class__.__name__, self.name) + +class STORE(BaseStore): + def process(self, ctx, name, stack): + return stack[-1] + +class BaseAssignOper(BaseStore): + def process(self, ctx, name, stack): + right = stack.pop() + left = ctx.resolve_identifier(name) + result = self.operation(ctx, left, right) + stack.append(result) + return result + +class STORE_ADD(BaseAssignOper): + operation = staticmethod(ADD.operation) + +class STORE_SUB(BaseAssignOper): + operation = staticmethod(SUB.operation) + +class STORE_POSTINCR(BaseStore): + def process(self, ctx, name, stack): + value = ctx.resolve_identifier(name) + newval = increment(ctx, value) + stack.append(newval) + return newval + class LABEL(Opcode): def __init__(self, num): self.num = num Modified: pypy/branch/js-refactoring/pypy/lang/js/operations.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/operations.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/operations.py Tue Apr 1 04:53:13 2008 @@ -166,6 +166,7 @@ class VariableAssignment(Assignment): def __init__(self, pos, left, right, operand): + xxx # shall never land here for now self.identifier = left.identifier self.right = right self.pos = pos Modified: pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Tue Apr 1 04:53:13 2008 @@ -266,6 +266,10 @@ print(i); """, ["0","1","2","3"]) +def test_assignments(): + yield assertv, "var x = 3; x += 4; x;", 7 + yield assertv, "x = 8; x -= 3; x;", 5 + def test_object_creation(): yield assertv, """ o = new Object(); From fijal at codespeak.net Tue Apr 1 06:41:53 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Apr 2008 06:41:53 +0200 (CEST) Subject: [pypy-svn] r53225 - in pypy/branch/js-refactoring/pypy/lang/js: . test Message-ID: <20080401044153.A26551684D3@codespeak.net> Author: fijal Date: Tue Apr 1 06:41:51 2008 New Revision: 53225 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: implement exceptions. They're not that great, but I think better than before (catching of finally blocks works better) Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/jscode.py Tue Apr 1 06:41:51 2008 @@ -19,7 +19,8 @@ opcode = opcodes[i] opcode = hint(opcode, deepfreeze=True) if isinstance(opcode, op): - opcode.eval(ctx, stack) + result = opcode.eval(ctx, stack) + assert result is None break if isinstance(opcode, BaseJump): i = opcode.do_jump(stack, i) @@ -549,6 +550,45 @@ def eval(self, ctx, stack): stack.append(stack[-1]) +class THROW(Opcode): + def eval(self, ctx, stack): + val = stack.pop() + raise ThrowException(val) + +class TRYCATCHBLOCK(Opcode): + def __init__(self, trycode, catchparam, catchcode, finallycode): + self.trycode = trycode + self.catchcode = catchcode + self.catchparam = catchparam + self.finallycode = finallycode + + def eval(self, ctx, stack): + try: + try: + self.trycode.run(ctx) + except ThrowException, e: + if self.catchcode is not None: + # XXX just copied, I don't know if it's right + obj = W_Object() + obj.Put(self.catchparam, e.exception) + ctx.push_object(obj) + try: + self.catchcode.run(ctx) + finally: + ctx.pop_object() + if self.finallycode is not None: + self.finallycode.run(ctx) + if not self.catchcode: + raise + except ReturnException: + # we run finally block here and re-raise the exception + if self.finallycode is not None: + self.finallycode.run(ctx) + raise + + def __repr__(self): + return "TRYCATCHBLOCK" # XXX shall we add stuff here??? + OpcodeMap = {} for name, value in locals().items(): Modified: pypy/branch/js-refactoring/pypy/lang/js/operations.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/operations.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/operations.py Tue Apr 1 06:41:51 2008 @@ -725,9 +725,10 @@ def __init__(self, pos, exp): self.pos = pos self.exp = exp - - def execute(self, ctx): - raise ThrowException(self.exp.eval(ctx).GetValue()) + + def emit(self, bytecode): + self.exp.emit(bytecode) + bytecode.emit('THROW') class Try(Statement): def __init__(self, pos, tryblock, catchparam, catchblock, finallyblock): @@ -736,30 +737,23 @@ self.catchparam = catchparam self.catchblock = catchblock self.finallyblock = finallyblock - - def execute(self, ctx): - e = None - tryresult = w_Undefined - try: - tryresult = self.tryblock.execute(ctx) - except ThrowException, excpt: - e = excpt - if self.catchblock is not None: - obj = W_Object() - obj.Put(self.catchparam.get_literal(), e.exception) - ctx.push_object(obj) - tryresult = self.catchblock.execute(ctx) - ctx.pop_object() - - if self.finallyblock is not None: - tryresult = self.finallyblock.execute(ctx) - - #if there is no catchblock reraise the exception - if (e is not None) and (self.catchblock is None): - raise e - - return tryresult - + + def emit(self, bytecode): + # a bit naive operator for now + trycode = JsCode() + self.tryblock.emit(trycode) + if self.catchblock: + catchcode = JsCode() + self.catchblock.emit(catchcode) + else: + catchcode = None + if self.finallyblock: + finallycode = JsCode() + self.finallyblock.emit(finallycode) + else: + finallycode = None + bytecode.emit('TRYCATCHBLOCK', trycode, self.catchparam.get_literal(), + catchcode, finallycode) #class Typeof(UnaryOp): # def eval(self, ctx): Modified: pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Tue Apr 1 06:41:51 2008 @@ -175,7 +175,6 @@ """, ['', '0']) def test_throw(): - py.test.skip("Not implemented") assertp("throw(3);", "uncaught exception: 3") def test_group(): @@ -189,7 +188,6 @@ yield assertp, "{3; print(5);}", '5' def test_try_catch_finally(): - py.test.skip("Not implemented") yield assertp, """ try { throw(3); From antocuni at codespeak.net Tue Apr 1 10:15:25 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 1 Apr 2008 10:15:25 +0200 (CEST) Subject: [pypy-svn] r53226 - in pypy/branch/jit-hotpath/pypy/rpython/ootypesystem: . test Message-ID: <20080401081525.8B7C616847A@codespeak.net> Author: antocuni Date: Tue Apr 1 10:15:23 2008 New Revision: 53226 Modified: pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/test/test_ootype.py Log: attach the name of the method to the _bound_meth object (only for builtin types so far) Modified: pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py Tue Apr 1 10:15:23 2008 @@ -1163,7 +1163,9 @@ TYPE = object.__getattribute__(self, "_TYPE") _, meth = TYPE._lookup(name) if meth is not None: - return meth._bound(TYPE, self) + res = meth._bound(TYPE, self) + res._name = name + return res return object.__getattribute__(self, name) Modified: pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/test/test_ootype.py Tue Apr 1 10:15:23 2008 @@ -213,6 +213,12 @@ METH = typeOf(meth) assert METH.SELFTYPE is LIST +def test_bound_method_name(): + LIST = List(Signed) + lst = new(LIST) + meth = lst.ll_getitem_fast + assert meth._name == 'll_getitem_fast' + def test_explicit_name_clash(): C = Instance("test", ROOT, {}) From cfbolz at codespeak.net Tue Apr 1 10:51:17 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Apr 2008 10:51:17 +0200 (CEST) Subject: [pypy-svn] r53227 - in pypy/branch/jit-merging-logic/pypy/jit/timeshifter: . test Message-ID: <20080401085117.33971168436@codespeak.net> Author: cfbolz Date: Tue Apr 1 10:51:16 2008 New Revision: 53227 Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/support.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Log: (arigo, cfbolz yesterday) Intermediate check-in breaking everything, I'd like to expriment a bit differently from there. Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py Tue Apr 1 10:51:16 2008 @@ -165,7 +165,11 @@ except rcontainer.SegfaultException: pass else: - return fielddesc.makebox(jitstate, resgv) + result = fielddesc.makebox(jitstate, resgv) + if argbox.future_usage is not None: + future_usage = argbox.future_usage.retrieve_child_usage(fielddesc) + result.future_usage = future_usage + return result return argbox.op_getfield(jitstate, fielddesc) def gensetfield(jitstate, fielddesc, destbox, valuebox): Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py Tue Apr 1 10:51:16 2008 @@ -47,12 +47,22 @@ return gv.revealconst(ootype.Object) class FutureUsage(object): - promote_timestamp = 0 + def __init__(self): + self.promote_timestamp = 0 + self.children = {} def see_promote(self, timestamp): if timestamp > self.promote_timestamp: self.promote_timestamp = timestamp + def retrieve_child_usage(self, fielddesc): + try: + return self.children[fielddesc] + except KeyError: + future_usage = FutureUsage() + self.children[fielddesc] = future_usage + return future_usage + class RedBox(object): _attrs_ = ['genvar', 'future_usage'] @@ -350,23 +360,25 @@ try: return boxmemo[self] except KeyError: + future_usage = self.retrieve_future_usage() content = self.content if not self.genvar: from pypy.jit.timeshifter import rcontainer assert isinstance(content, rcontainer.VirtualContainer) - result = self.FrozenPtrVirtual() + result = self.FrozenPtrVirtual(future_usage) boxmemo[self] = result result.fz_content = content.freeze(memo) return result elif self.genvar.is_const: - result = self.FrozenPtrConst(self.genvar) + result = self.FrozenPtrConst(future_usage, self.genvar) elif content is None: - result = self.FrozenPtrVar(self.known_nonzero) + result = self.FrozenPtrVar(future_usage, self.known_nonzero) else: # if self.content is not None, it's a PartialDataStruct from pypy.jit.timeshifter import rcontainer assert isinstance(content, rcontainer.PartialDataStruct) - result = self.FrozenPtrVarWithPartialData(known_nonzero=True) + result = self.FrozenPtrVarWithPartialData(future_usage, + known_nonzero=True) boxmemo[self] = result result.fz_partialcontent = content.partialfreeze(memo) return result @@ -473,9 +485,20 @@ return False def check_timestamp(self, box, memo): - if (box.is_constant() and - self.future_usage.promote_timestamp > memo.frozen_timestamp): - raise DontMerge + fu = self.future_usage + if fu is not None: + if (box.is_constant() and + fu.promote_timestamp > memo.frozen_timestamp): + raise DontMerge + if fu.children: + assert isinstance(box, AbstractPtrRedBox) + for fielddesc, fuchild in fu.children.items(): + frozenchild = self.maybe_get_child_box(fielddesc) + boxchild = box.maybe_get_child_box(fielddesc) + if frozenchild is not None and boxchild is not None: + assert frozenchild.future_usage is fuchild + frozenchild.check_timestamp(boxchild, memo) + # XXX use the memo here too! class FrozenConst(FrozenValue): @@ -589,7 +612,8 @@ class FrozenAbstractPtrConst(FrozenConst): - def __init__(self, gv_const): + def __init__(self, future_usage, gv_const): + FrozenConst.__init__(self, future_usage) self.gv_const = gv_const def is_constant_equal(self, box): @@ -606,15 +630,19 @@ if self.is_constant_nullptr(): memo.forget_nonzeroness[box] = None match = FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) - if not memo.force_merge and not match: - from pypy.jit.timeshifter.rcontainer import VirtualContainer - if isinstance(box.content, VirtualContainer): - raise DontMerge # XXX recursive data structures? + #if not memo.force_merge and not match: + # from pypy.jit.timeshifter.rcontainer import VirtualContainer + # if isinstance(box.content, VirtualContainer): + # raise DontMerge # XXX recursive data structures? return match def unfreeze(self, incomingvarboxes, memo): return self.PtrRedBox(self.gv_const) + def maybe_get_child_box(self, fielddesc): + XXX # pfpfpfpfpf no fun at all! we make a non-frozen box and freeze it? uh how do we make the non-frozen box? + fielddesc.makebox(fielddesc.perform_getfield(rgenop:-(, self.gv_const)) # in theory + # :-( :-( :-( class FrozenPtrConst(FrozenAbstractPtrConst, LLTypeMixin): PtrRedBox = PtrRedBox @@ -625,7 +653,8 @@ class AbstractFrozenPtrVar(FrozenVar): - def __init__(self, known_nonzero): + def __init__(self, future_usage, known_nonzero): + FrozenVar.__init__(self, future_usage) self.known_nonzero = known_nonzero def exactmatch(self, box, outgoingvarboxes, memo): Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/support.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/support.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/support.py Tue Apr 1 10:51:16 2008 @@ -33,6 +33,9 @@ def constPrebuiltGlobal(value): return FakeGenConst(value) + def genconst(self, value): + return FakeGenConst(value) + class FakeBuilder(object): ops_with_no_retval = set(['setfield']) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Tue Apr 1 10:51:16 2008 @@ -1,20 +1,17 @@ -""" [merge point including x] - promote(x) - then the frozen x has a futureusage - yes - isn't this example too easy? - I mean, in which case would we want to prevent a merge? - it's a start - no, it shows the essential bit - if x was initially a constant(5), then we don't want to merge with any other value - if x was initially a variable, then we don't want to merge with any constant at all +""" + so, we have a frozen _variable_ s + and do promote(s.x) + and try to merge it with a virtual s + it looks a bit strange but I suppose that 's.x' should also create {'x': FutureUsage()} in the FutureUsage() of s + yes, I fear so + so, we get a virtual s to merge... """ import py from pypy.rpython.lltypesystem import lltype -from pypy.jit.timeshifter import rvalue, rcontainer +from pypy.jit.timeshifter import rvalue, rcontainer, rtimeshift from pypy.jit.timeshifter.test.support import FakeJITState, FakeGenVar -from pypy.jit.timeshifter.test.support import FakeGenConst +from pypy.jit.timeshifter.test.support import FakeGenConst, FakeRGenOp from pypy.jit.timeshifter.test.support import signed_kind from pypy.jit.timeshifter.test.support import vmalloc, makebox from pypy.jit.timeshifter.test.support import getfielddesc @@ -23,7 +20,8 @@ class TestMerging: def setup_class(cls): - cls.STRUCT = lltype.GcStruct("S", ("x", lltype.Signed)) + cls.STRUCT = lltype.GcStruct("S", ("x", lltype.Signed), + hints={'immutable': True}) cls.fielddesc = getfielddesc(cls.STRUCT, "x") FORWARD = lltype.GcForwardReference() cls.NESTEDSTRUCT = lltype.GcStruct('dummy', ("foo", lltype.Signed), @@ -31,6 +29,9 @@ FORWARD.become(cls.NESTEDSTRUCT) def test_promote_const(self): + """We have a frozen constant 42 which gets a (no-op) promotion after + it is frozen. Then it should fail to merge with a live constant 43. + """ gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) frozen = box.freeze(rvalue.freeze_memo()) @@ -49,6 +50,9 @@ py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) def test_promote_var(self): + """We have a frozen variable which gets promoted after + it is frozen. Then it should fail to merge with any live constant. + """ gv = FakeGenVar() box = rvalue.IntRedBox(gv) frozen = box.freeze(rvalue.freeze_memo()) @@ -67,6 +71,9 @@ py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) def test_promotebefore_freeze_const(self): + """In the merging logic, frozen boxes ignore promotions that + occurred before the freezing. + """ gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) box.freeze(rvalue.freeze_memo()) @@ -85,3 +92,40 @@ gc2 = FakeGenConst(43) newbox = rvalue.IntRedBox(gc2) assert not frozen.exactmatch(newbox, [], memo) + + def test_promote_field_of_constant_immutable(self): + """We freeze s then promote s.x. This should prevent a merge where + there is an incoming live s2 for which we already know the value of + s2.x, and for which the merge would loose that information. + """ + prebuilt_s = lltype.malloc(self.STRUCT) + prebuilt_s.x = 42 + + gc = FakeGenConst(prebuilt_s) + box = rvalue.PtrRedBox(gc) + frozen = box.freeze(rvalue.freeze_memo()) + assert box.future_usage is not None # attached by freeze + frozen_timestamp = 0 + + jitstate = FakeJITState() + + x_box = rtimeshift.gengetfield(jitstate, False, self.fielddesc, box) + assert x_box.genvar.revealconst(lltype.Signed) == 42 + assert x_box.future_usage is not None # attached by gengetfield() + x_box.future_usage.see_promote(timestamp=1) + + memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + assert frozen.exactmatch(box, [], memo) + + prebuilt_s2 = lltype.malloc(self.STRUCT) + prebuilt_s2.x = 42 + box2 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s2)) + memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + assert not frozen.exactmatch(box2, [], memo) + # ^^^no DontMerge because box2.x is equal, so we don't loose its value + + prebuilt_s3 = lltype.malloc(self.STRUCT) + prebuilt_s3.x = 43 + box3 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s3)) + memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + py.test.raises(rvalue.DontMerge, frozen.exactmatch, box3, [], memo) From arigo at codespeak.net Tue Apr 1 11:01:33 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Apr 2008 11:01:33 +0200 (CEST) Subject: [pypy-svn] r53228 - in pypy/branch/jit-merging-logic/pypy/jit/timeshifter: . test Message-ID: <20080401090133.027A61684D9@codespeak.net> Author: arigo Date: Tue Apr 1 11:01:32 2008 New Revision: 53228 Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Log: Trying a simpler approach: remembering the most recent frozen copy of a box and attaching a flag to the frozen copy when the box gets promoted. Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py Tue Apr 1 11:01:32 2008 @@ -14,9 +14,8 @@ def freeze_memo(): return Memo() -def exactmatch_memo(frozen_timestamp, force_merge=False): +def exactmatch_memo(force_merge=False): memo = Memo() - memo.frozen_timestamp = frozen_timestamp memo.partialdatamatch = {} memo.forget_nonzeroness = {} memo.force_merge=force_merge @@ -46,27 +45,10 @@ def _revealconst(self, gv): return gv.revealconst(ootype.Object) -class FutureUsage(object): - def __init__(self): - self.promote_timestamp = 0 - self.children = {} - - def see_promote(self, timestamp): - if timestamp > self.promote_timestamp: - self.promote_timestamp = timestamp - - def retrieve_child_usage(self, fielddesc): - try: - return self.children[fielddesc] - except KeyError: - future_usage = FutureUsage() - self.children[fielddesc] = future_usage - return future_usage - class RedBox(object): - _attrs_ = ['genvar', 'future_usage'] - future_usage = None + _attrs_ = ['genvar', 'most_recent_frozen'] + most_recent_frozen = None def __init__(self, genvar=None): self.genvar = genvar # None or a genvar @@ -115,10 +97,10 @@ memo = memo.boxes return memo.setdefault(self, self) - def retrieve_future_usage(self): - if self.future_usage is None: - self.future_usage = FutureUsage() - return self.future_usage + def see_promote(self): + if self.most_recent_frozen is not None: + self.most_recent_frozen.will_be_promoted = True + self.most_recent_frozen = None def ll_redboxcls(TYPE): @@ -194,11 +176,13 @@ try: return memo[self] except KeyError: - future_usage = self.retrieve_future_usage() - if self.is_constant(): - result = FrozenIntConst(future_usage, self.genvar) - else: - result = FrozenIntVar(future_usage) + result = self.most_recent_frozen + if result is None: + if self.is_constant(): + result = FrozenIntConst(self.genvar) + else: + result = FrozenIntVar() + self.most_recent_frozen = result memo[self] = result return result @@ -475,8 +459,7 @@ class FrozenValue(object): """An abstract value frozen in a saved state. """ - def __init__(self, future_usage): - self.future_usage = future_usage + will_be_promoted = False def is_constant_equal(self, box): return False @@ -484,22 +467,6 @@ def is_constant_nullptr(self): return False - def check_timestamp(self, box, memo): - fu = self.future_usage - if fu is not None: - if (box.is_constant() and - fu.promote_timestamp > memo.frozen_timestamp): - raise DontMerge - if fu.children: - assert isinstance(box, AbstractPtrRedBox) - for fielddesc, fuchild in fu.children.items(): - frozenchild = self.maybe_get_child_box(fielddesc) - boxchild = box.maybe_get_child_box(fielddesc) - if frozenchild is not None and boxchild is not None: - assert frozenchild.future_usage is fuchild - frozenchild.check_timestamp(boxchild, memo) - # XXX use the memo here too! - class FrozenConst(FrozenValue): @@ -507,7 +474,8 @@ if self.is_constant_equal(box): return True else: - self.check_timestamp(box, memo) + if self.will_be_promoted and box.is_constant(): + raise DontMerge outgoingvarboxes.append(box) return False @@ -515,7 +483,8 @@ class FrozenVar(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): - self.check_timestamp(box, memo) + if self.will_be_promoted and box.is_constant(): + raise DontMerge memo = memo.boxes if self not in memo: memo[self] = box @@ -530,8 +499,7 @@ class FrozenIntConst(FrozenConst): - def __init__(self, future_usage, gv_const): - FrozenConst.__init__(self, future_usage) + def __init__(self, gv_const): self.gv_const = gv_const def is_constant_equal(self, box): @@ -639,10 +607,6 @@ def unfreeze(self, incomingvarboxes, memo): return self.PtrRedBox(self.gv_const) - def maybe_get_child_box(self, fielddesc): - XXX # pfpfpfpfpf no fun at all! we make a non-frozen box and freeze it? uh how do we make the non-frozen box? - fielddesc.makebox(fielddesc.perform_getfield(rgenop:-(, self.gv_const)) # in theory - # :-( :-( :-( class FrozenPtrConst(FrozenAbstractPtrConst, LLTypeMixin): PtrRedBox = PtrRedBox Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Tue Apr 1 11:01:32 2008 @@ -35,20 +35,24 @@ gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) frozen = box.freeze(rvalue.freeze_memo()) - frozen_timestamp = 0 - assert box.future_usage is not None # attached by freeze() - box.future_usage.see_promote(timestamp=1) + assert box.most_recent_frozen is not None # attached by freeze() + box.see_promote() - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gv = FakeGenVar() newbox = rvalue.IntRedBox(gv) assert not frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gc2 = FakeGenConst(43) newbox = rvalue.IntRedBox(gc2) py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) + memo = rvalue.exactmatch_memo() + gc3 = FakeGenConst(42) + newbox = rvalue.IntRedBox(gc3) + assert frozen.exactmatch(newbox, [], memo) + def test_promote_var(self): """We have a frozen variable which gets promoted after it is frozen. Then it should fail to merge with any live constant. @@ -56,16 +60,15 @@ gv = FakeGenVar() box = rvalue.IntRedBox(gv) frozen = box.freeze(rvalue.freeze_memo()) - frozen_timestamp = 0 - assert box.future_usage is not None # attached by freeze() - box.future_usage.see_promote(timestamp=1) + assert box.most_recent_frozen is not None # attached by freeze() + box.see_promote() - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gv2 = FakeGenVar() newbox = rvalue.IntRedBox(gv2) assert frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gc = FakeGenConst(43) newbox = rvalue.IntRedBox(gc) py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) @@ -77,18 +80,17 @@ gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) box.freeze(rvalue.freeze_memo()) - assert box.future_usage is not None # attached by freeze() - box.future_usage.see_promote(timestamp=1) + assert box.most_recent_frozen is not None # attached by freeze() + box.see_promote() - frozen_timestamp = 2 frozen = box.freeze(rvalue.freeze_memo()) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gv = FakeGenVar() newbox = rvalue.IntRedBox(gv) assert not frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() gc2 = FakeGenConst(43) newbox = rvalue.IntRedBox(gc2) assert not frozen.exactmatch(newbox, [], memo) From arigo at codespeak.net Tue Apr 1 11:16:04 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Apr 2008 11:16:04 +0200 (CEST) Subject: [pypy-svn] r53229 - in pypy/branch/jit-merging-logic/pypy/jit/timeshifter: . test Message-ID: <20080401091604.C072D168437@codespeak.net> Author: arigo Date: Tue Apr 1 11:16:04 2008 New Revision: 53229 Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Log: Update the last test too (still failing). Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py Tue Apr 1 11:16:04 2008 @@ -218,6 +218,7 @@ try: return memo[self] except KeyError: + xxx # use self.most_recent_frozen if self.is_constant(): result = FrozenBoolConst(self.genvar) else: @@ -241,6 +242,7 @@ try: return memo[self] except KeyError: + xxx # use self.most_recent_frozen if self.is_constant(): result = FrozenDoubleConst(self.genvar) else: Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Tue Apr 1 11:16:04 2008 @@ -106,28 +106,27 @@ gc = FakeGenConst(prebuilt_s) box = rvalue.PtrRedBox(gc) frozen = box.freeze(rvalue.freeze_memo()) - assert box.future_usage is not None # attached by freeze - frozen_timestamp = 0 + assert box.most_recent_frozen is not None # attached by freeze jitstate = FakeJITState() x_box = rtimeshift.gengetfield(jitstate, False, self.fielddesc, box) assert x_box.genvar.revealconst(lltype.Signed) == 42 assert x_box.future_usage is not None # attached by gengetfield() - x_box.future_usage.see_promote(timestamp=1) + x_box.see_promote() - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() assert frozen.exactmatch(box, [], memo) prebuilt_s2 = lltype.malloc(self.STRUCT) prebuilt_s2.x = 42 box2 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s2)) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() assert not frozen.exactmatch(box2, [], memo) # ^^^no DontMerge because box2.x is equal, so we don't loose its value prebuilt_s3 = lltype.malloc(self.STRUCT) prebuilt_s3.x = 43 box3 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s3)) - memo = rvalue.exactmatch_memo(frozen_timestamp=frozen_timestamp) + memo = rvalue.exactmatch_memo() py.test.raises(rvalue.DontMerge, frozen.exactmatch, box3, [], memo) From cfbolz at codespeak.net Tue Apr 1 14:04:28 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Apr 2008 14:04:28 +0200 (CEST) Subject: [pypy-svn] r53230 - in pypy/branch/jit-merging-logic/pypy/jit/timeshifter: . test Message-ID: <20080401120428.E0E5D168422@codespeak.net> Author: cfbolz Date: Tue Apr 1 14:04:26 2008 New Revision: 53230 Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py Log: (cfbolz, arigo): use the new approach of remembering the last frozen box on each box to pass the new merging tests Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py Tue Apr 1 14:04:26 2008 @@ -23,7 +23,8 @@ _attrs_ = [] def op_getfield(self, jitstate, fielddesc): - raise NotImplementedError + rgenop = jitstate.curbuilder.rgenop + return self.getfield_dont_generate_code(rgenop, fielddesc) def op_setfield(self, jitstate, fielddesc, valuebox): raise NotImplementedError @@ -31,6 +32,9 @@ def op_getsubstruct(self, jitstate, fielddesc): raise NotImplementedError + def getfield_dont_generate_code(self, rgenop, fielddesc): + raise NotImplementedError + class VirtualContainer(AbstractContainer): _attrs_ = ('ownbox',) @@ -639,6 +643,9 @@ if self.virtualizable: self.structdesc = StructTypeDesc(RGenOp, T) self.redboxcls = rvalue.ll_redboxcls(RESTYPE) + # fish for the FrozenConst subclass + dummybox = self.redboxcls(self.gv_default) + self.frozenconstcls = dummybox.FrozenConstCls self.immutable = deref(PTRTYPE)._hints.get('immutable', False) @@ -909,15 +916,15 @@ content_boxes[i] = content_boxes[i].replace(memo) self.ownbox = self.ownbox.replace(memo) - def op_getfield(self, jitstate, fielddesc): - return self.content_boxes[fielddesc.fieldindex] - def op_setfield(self, jitstate, fielddesc, valuebox): self.content_boxes[fielddesc.fieldindex] = valuebox def op_getsubstruct(self, jitstate, fielddesc): return self.ownbox + def getfield_dont_generate_code(self, rgenop, fielddesc): + return self.content_boxes[fielddesc.fieldindex] + def make_rti(self, jitstate, memo): try: return memo.containers[self] @@ -1284,6 +1291,9 @@ fielddesc.generate_set(jitstate, gv_ptr, valuebox.getgenvar(jitstate)) + def getfield_dont_generate_code(self, rgenop, fielddesc): + xxx + def op_ptreq(self, jitstate, otherbox, reverse): if self is otherbox.content: answer = True @@ -1346,7 +1356,7 @@ def __init__(self): self.data = [] - def op_getfield(self, jitstate, fielddesc): + def getfield_dont_generate_code(self, rgenop, fielddesc): searchindex = fielddesc.fieldindex for index, box in self.data: if index == searchindex: Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py Tue Apr 1 14:04:26 2008 @@ -166,9 +166,10 @@ pass else: result = fielddesc.makebox(jitstate, resgv) - if argbox.future_usage is not None: - future_usage = argbox.future_usage.retrieve_child_usage(fielddesc) - result.future_usage = future_usage + fz = argbox.most_recent_frozen + if fz is not None: + newfz = fz.get_const_child(fielddesc, resgv) + result.most_recent_frozen = newfz return result return argbox.op_getfield(jitstate, fielddesc) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py Tue Apr 1 14:04:26 2008 @@ -14,8 +14,9 @@ def freeze_memo(): return Memo() -def exactmatch_memo(force_merge=False): +def exactmatch_memo(rgenop, force_merge=False): memo = Memo() + memo.rgenop = rgenop memo.partialdatamatch = {} memo.forget_nonzeroness = {} memo.force_merge=force_merge @@ -346,30 +347,41 @@ try: return boxmemo[self] except KeyError: - future_usage = self.retrieve_future_usage() content = self.content - if not self.genvar: - from pypy.jit.timeshifter import rcontainer - assert isinstance(content, rcontainer.VirtualContainer) - result = self.FrozenPtrVirtual(future_usage) + if content is None: + result = self.most_recent_frozen + if result is None: + if self.genvar.is_const: + result = self.FrozenPtrConst(self.genvar) + elif content is None: + result = self.FrozenPtrVar(self.known_nonzero) + self.most_recent_frozen = result + else: + # sanity-check the most_recent_frozen object + if self.genvar.is_const: + assert isinstance(result, self.FrozenPtrConst) + else: + assert isinstance(result, self.FrozenPtrVar) boxmemo[self] = result - result.fz_content = content.freeze(memo) - return result - elif self.genvar.is_const: - result = self.FrozenPtrConst(future_usage, self.genvar) - elif content is None: - result = self.FrozenPtrVar(future_usage, self.known_nonzero) else: - # if self.content is not None, it's a PartialDataStruct - from pypy.jit.timeshifter import rcontainer - assert isinstance(content, rcontainer.PartialDataStruct) - result = self.FrozenPtrVarWithPartialData(future_usage, - known_nonzero=True) - boxmemo[self] = result - result.fz_partialcontent = content.partialfreeze(memo) - return result - result.fz_access_info = self.access_info.copy() - boxmemo[self] = result + self.most_recent_frozen = None # for now + if not self.genvar: + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) + result = self.FrozenPtrVirtual() + # store the result in the memo before content.freeze(), + # for recursive data structures + boxmemo[self] = result + result.fz_content = content.freeze(memo) + else: + # if self.content is not None, it's a PartialDataStruct + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.PartialDataStruct) + result = self.FrozenPtrVarWithPartialData(known_nonzero=True) + # store the result in the memo before content.freeze(), + # for recursive data structures + boxmemo[self] = result + result.fz_partialcontent = content.partialfreeze(memo) return result def getgenvar(self, jitstate): @@ -431,6 +443,19 @@ assert self.content is not None self.content.op_setfield(jitstate, fielddesc, valuebox) + def getfield_dont_generate_code(self, rgenop, fielddesc): + if self.content is not None: + return self.content.getfield_dont_generate_code(rgenop, fielddesc) + elif self.genvar.is_const: + # this raises if something's wrong, never returns None right + try: + gv_result = fielddesc.perform_getfield(rgenop, self.genvar) + except rcontainer.SegfaultException: + return None + return fielddesc.redboxcls(gv_result) + else: + return None + def remember_field(self, fielddesc, box): if self.genvar.is_const: return # no point in remembering field then @@ -481,6 +506,11 @@ outgoingvarboxes.append(box) return False + def check_future_promotions(self, box, memo): + if (self.will_be_promoted and box.is_constant() + and not self.is_constant_equal(box)): + raise DontMerge + class FrozenVar(FrozenValue): @@ -513,6 +543,8 @@ # XXX could return directly the original IntRedBox return IntRedBox(self.gv_const) +IntRedBox.FrozenConstCls = FrozenIntConst + class FrozenIntVar(FrozenVar): @@ -540,6 +572,8 @@ def unfreeze(self, incomingvarboxes, memo): return BoolRedBox(self.gv_const) +BoolRedBox.FrozenConstCls = FrozenBoolConst + class FrozenBoolVar(FrozenVar): @@ -566,6 +600,8 @@ def unfreeze(self, incomingvarboxes, memo): return DoubleRedBox(self.gv_const) +DoubleRedBox.FrozenConstCls = FrozenDoubleConst + class FrozenDoubleVar(FrozenVar): @@ -582,8 +618,8 @@ class FrozenAbstractPtrConst(FrozenConst): - def __init__(self, future_usage, gv_const): - FrozenConst.__init__(self, future_usage) + def __init__(self, gv_const): + FrozenConst.__init__(self) self.gv_const = gv_const def is_constant_equal(self, box): @@ -600,6 +636,8 @@ if self.is_constant_nullptr(): memo.forget_nonzeroness[box] = None match = FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) + if not match: + self.check_future_promotions(box, memo) #if not memo.force_merge and not match: # from pypy.jit.timeshifter.rcontainer import VirtualContainer # if isinstance(box.content, VirtualContainer): @@ -609,18 +647,46 @@ def unfreeze(self, incomingvarboxes, memo): return self.PtrRedBox(self.gv_const) + const_children = None + + def get_const_child(self, fielddesc, gv_value): + # constant children of a constant immutable FrozenPtrConst + # are only used to track future promotions; they have no + # other effect on exactmatch(). + if self.const_children is None: + self.const_children = {} + else: + try: + return self.const_children[fielddesc] + except KeyError: + pass + newfz = fielddesc.frozenconstcls(gv_value) + self.const_children[fielddesc] = newfz + return newfz + + def check_future_promotions(self, box, memo): + FrozenConst.check_future_promotions(self, box, memo) + if self.const_children is not None: + for fielddesc, fz_child in self.const_children.items(): + box_child = box.getfield_dont_generate_code(memo.rgenop, + fielddesc) + if box_child is not None: + fz_child.check_future_promotions(box_child, memo) + class FrozenPtrConst(FrozenAbstractPtrConst, LLTypeMixin): PtrRedBox = PtrRedBox +PtrRedBox.FrozenConstCls = FrozenPtrConst class FrozenInstanceConst(FrozenAbstractPtrConst, OOTypeMixin): PtrRedBox = InstanceRedBox +InstanceRedBox.FrozenConstCls = FrozenInstanceConst class AbstractFrozenPtrVar(FrozenVar): - def __init__(self, future_usage, known_nonzero): - FrozenVar.__init__(self, future_usage) + def __init__(self, known_nonzero): + FrozenVar.__init__(self) self.known_nonzero = known_nonzero def exactmatch(self, box, outgoingvarboxes, memo): Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Tue Apr 1 14:04:26 2008 @@ -32,23 +32,25 @@ """We have a frozen constant 42 which gets a (no-op) promotion after it is frozen. Then it should fail to merge with a live constant 43. """ + rgenop = FakeRGenOp() + gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) frozen = box.freeze(rvalue.freeze_memo()) assert box.most_recent_frozen is not None # attached by freeze() box.see_promote() - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gv = FakeGenVar() newbox = rvalue.IntRedBox(gv) assert not frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gc2 = FakeGenConst(43) newbox = rvalue.IntRedBox(gc2) py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gc3 = FakeGenConst(42) newbox = rvalue.IntRedBox(gc3) assert frozen.exactmatch(newbox, [], memo) @@ -57,18 +59,20 @@ """We have a frozen variable which gets promoted after it is frozen. Then it should fail to merge with any live constant. """ + rgenop = FakeRGenOp() + gv = FakeGenVar() box = rvalue.IntRedBox(gv) frozen = box.freeze(rvalue.freeze_memo()) assert box.most_recent_frozen is not None # attached by freeze() box.see_promote() - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gv2 = FakeGenVar() newbox = rvalue.IntRedBox(gv2) assert frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gc = FakeGenConst(43) newbox = rvalue.IntRedBox(gc) py.test.raises(rvalue.DontMerge, frozen.exactmatch, newbox, [], memo) @@ -77,6 +81,8 @@ """In the merging logic, frozen boxes ignore promotions that occurred before the freezing. """ + rgenop = FakeRGenOp() + gc = FakeGenConst(42) box = rvalue.IntRedBox(gc) box.freeze(rvalue.freeze_memo()) @@ -85,12 +91,12 @@ frozen = box.freeze(rvalue.freeze_memo()) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gv = FakeGenVar() newbox = rvalue.IntRedBox(gv) assert not frozen.exactmatch(newbox, [], memo) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) gc2 = FakeGenConst(43) newbox = rvalue.IntRedBox(gc2) assert not frozen.exactmatch(newbox, [], memo) @@ -100,6 +106,8 @@ there is an incoming live s2 for which we already know the value of s2.x, and for which the merge would loose that information. """ + rgenop = FakeRGenOp() + prebuilt_s = lltype.malloc(self.STRUCT) prebuilt_s.x = 42 @@ -112,21 +120,21 @@ x_box = rtimeshift.gengetfield(jitstate, False, self.fielddesc, box) assert x_box.genvar.revealconst(lltype.Signed) == 42 - assert x_box.future_usage is not None # attached by gengetfield() + assert x_box.most_recent_frozen is not None # attached by gengetfield() x_box.see_promote() - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) assert frozen.exactmatch(box, [], memo) prebuilt_s2 = lltype.malloc(self.STRUCT) prebuilt_s2.x = 42 box2 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s2)) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) assert not frozen.exactmatch(box2, [], memo) # ^^^no DontMerge because box2.x is equal, so we don't loose its value prebuilt_s3 = lltype.malloc(self.STRUCT) prebuilt_s3.x = 43 box3 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s3)) - memo = rvalue.exactmatch_memo() + memo = rvalue.exactmatch_memo(rgenop) py.test.raises(rvalue.DontMerge, frozen.exactmatch, box3, [], memo) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py Tue Apr 1 14:04:26 2008 @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.timeshifter import rvalue, rcontainer from pypy.jit.timeshifter.test.support import FakeJITState, FakeGenVar -from pypy.jit.timeshifter.test.support import FakeGenConst +from pypy.jit.timeshifter.test.support import FakeGenConst, FakeRGenOp from pypy.jit.timeshifter.test.support import signed_kind from pypy.jit.timeshifter.test.support import vmalloc, makebox from pypy.jit.timeshifter.test.support import getfielddesc @@ -42,9 +42,10 @@ # of 'box' that correspond to FrozenVar placeholders in frozenbox. # Otherwise, it is the list of subboxes of 'box' that should be # generalized to become variables. + rgenop = FakeRGenOp() outgoingvarboxes = [] res = frozenbox.exactmatch(box, outgoingvarboxes, - rvalue.exactmatch_memo()) + rvalue.exactmatch_memo(rgenop)) assert outgoingvarboxes == expected_outgoing return res From cfbolz at codespeak.net Tue Apr 1 15:24:01 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Apr 2008 15:24:01 +0200 (CEST) Subject: [pypy-svn] r53231 - in pypy/branch/jit-merging-logic/pypy/jit/timeshifter: . test Message-ID: <20080401132401.9E4F5168450@codespeak.net> Author: cfbolz Date: Tue Apr 1 15:24:00 2008 New Revision: 53231 Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py Log: (cfbolz, arigo) One more test passing. Trying to refactor along the way. Kill the access_info stuff again Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rcontainer.py Tue Apr 1 15:24:00 2008 @@ -643,9 +643,9 @@ if self.virtualizable: self.structdesc = StructTypeDesc(RGenOp, T) self.redboxcls = rvalue.ll_redboxcls(RESTYPE) - # fish for the FrozenConst subclass + # fish for the getfrozen() static method dummybox = self.redboxcls(self.gv_default) - self.frozenconstcls = dummybox.FrozenConstCls + self.getfrozen = dummybox.getfrozen self.immutable = deref(PTRTYPE)._hints.get('immutable', False) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rtimeshift.py Tue Apr 1 15:24:00 2008 @@ -168,7 +168,7 @@ result = fielddesc.makebox(jitstate, resgv) fz = argbox.most_recent_frozen if fz is not None: - newfz = fz.get_const_child(fielddesc, resgv) + newfz = fz.get_ghost_child(fielddesc, resgv) result.most_recent_frozen = newfz return result return argbox.op_getfield(jitstate, fielddesc) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/rvalue.py Tue Apr 1 15:24:00 2008 @@ -64,8 +64,7 @@ return bool(self.genvar) and self.genvar.is_const def getkind(self): - if self.genvar is None: - return None + assert self.genvar is not None return self.genvar.getkind() def getgenvar(self, jitstate): @@ -84,6 +83,25 @@ incoming.append(self) memo[self] = None + def freeze(self, memo): + memo = memo.boxes + try: + return memo[self] + except KeyError: + assert self.genvar is not None + result = self.most_recent_frozen + if result is None: + result = self.getfrozen(self.genvar) + self.most_recent_frozen = result + else: + # sanity-check the most_recent_frozen object + if self.genvar.is_const: + assert isinstance(result, FrozenConst) + else: + assert isinstance(result, FrozenVar) + memo[self] = result + return result + def forcevar(self, jitstate, memo, forget_nonzeroness): if self.is_constant(): # cannot mutate constant boxes in-place @@ -172,20 +190,13 @@ result = memo[self] = IntRedBox(self.genvar) return result - def freeze(self, memo): - memo = memo.boxes - try: - return memo[self] - except KeyError: - result = self.most_recent_frozen - if result is None: - if self.is_constant(): - result = FrozenIntConst(self.genvar) - else: - result = FrozenIntVar() - self.most_recent_frozen = result - memo[self] = result - return result + @staticmethod + def getfrozen(gv_value): + if gv_value.is_const: + return FrozenIntConst(gv_value) + else: + return FrozenIntVar() + class BoolRedBox(RedBox): # XXX make true and false singletons? @@ -214,18 +225,13 @@ result.iftrue = [effect.copy(memo) for effect in self.iftrue] return result - def freeze(self, memo): - memo = memo.boxes - try: - return memo[self] - except KeyError: - xxx # use self.most_recent_frozen - if self.is_constant(): - result = FrozenBoolConst(self.genvar) - else: - result = FrozenBoolVar() - memo[self] = result - return result + @staticmethod + def getfrozen(gv_value): + if gv_value.is_const: + return FrozenBoolConst(gv_value) + else: + return FrozenBoolVar() + class DoubleRedBox(RedBox): "A red box that contains a constant double-precision floating point value." @@ -238,34 +244,12 @@ result = memo[self] = DoubleRedBox(self.genvar) return result - def freeze(self, memo): - memo = memo.boxes - try: - return memo[self] - except KeyError: - xxx # use self.most_recent_frozen - if self.is_constant(): - result = FrozenDoubleConst(self.genvar) - else: - result = FrozenDoubleVar() - memo[self] = result - return result - - -class AccessInfo(object): - def __init__(self): - self.read_fields = 0 - self.write_fields = 0 - # XXX what else is needed? - - def __repr__(self): - return "" % ( - self.read_fields, self.write_fields) - - def copy(self): - result = AccessInfo() - result.read_fields = self.read_fields - result.write_fields = self.write_fields + @staticmethod + def getfrozen(gv_value): + if gv_value.is_const: + return FrozenDoubleConst(gv_value) + else: + return FrozenDoubleVar() class AbstractPtrRedBox(RedBox): @@ -280,7 +264,6 @@ if genvar is not None and genvar.is_const: known_nonzero = bool(self._revealconst(genvar)) self.known_nonzero = known_nonzero - self.access_info = AccessInfo() def setgenvar(self, newgenvar): RedBox.setgenvar(self, newgenvar) @@ -325,8 +308,6 @@ boxmemo[self] = result if self.content: result.content = self.content.copy(memo) - # XXX is this correct? - result.access_info = self.access_info assert isinstance(result, AbstractPtrRedBox) return result @@ -349,11 +330,12 @@ except KeyError: content = self.content if content is None: + assert self.genvar is not None result = self.most_recent_frozen if result is None: if self.genvar.is_const: result = self.FrozenPtrConst(self.genvar) - elif content is None: + else: result = self.FrozenPtrVar(self.known_nonzero) self.most_recent_frozen = result else: @@ -362,26 +344,25 @@ assert isinstance(result, self.FrozenPtrConst) else: assert isinstance(result, self.FrozenPtrVar) + return result + self.most_recent_frozen = None # for now + if not self.genvar: + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) + result = self.FrozenPtrVirtual() + # store the result in the memo before content.freeze(), + # for recursive data structures boxmemo[self] = result + result.fz_content = content.freeze(memo) else: - self.most_recent_frozen = None # for now - if not self.genvar: - from pypy.jit.timeshifter import rcontainer - assert isinstance(content, rcontainer.VirtualContainer) - result = self.FrozenPtrVirtual() - # store the result in the memo before content.freeze(), - # for recursive data structures - boxmemo[self] = result - result.fz_content = content.freeze(memo) - else: - # if self.content is not None, it's a PartialDataStruct - from pypy.jit.timeshifter import rcontainer - assert isinstance(content, rcontainer.PartialDataStruct) - result = self.FrozenPtrVarWithPartialData(known_nonzero=True) - # store the result in the memo before content.freeze(), - # for recursive data structures - boxmemo[self] = result - result.fz_partialcontent = content.partialfreeze(memo) + # if self.content is not None, it's a PartialDataStruct + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.PartialDataStruct) + result = self.FrozenPtrVarWithPartialData(known_nonzero=True) + # store the result in the memo before content.freeze(), + # for recursive data structures + boxmemo[self] = result + result.fz_partialcontent = content.partialfreeze(memo) return result def getgenvar(self, jitstate): @@ -420,7 +401,6 @@ self.content.enter_block(incoming, memo) def op_getfield(self, jitstate, fielddesc): - self.access_info.read_fields += 1 self.learn_nonzeroness(jitstate, True) if self.content is not None: box = self.content.op_getfield(jitstate, fielddesc) @@ -430,10 +410,13 @@ box = fielddesc.generate_get(jitstate, gv_ptr) if fielddesc.immutable: self.remember_field(fielddesc, box) + fz = self.most_recent_frozen + if fz is not None: + newfz = fz.get_ghost_child(fielddesc, box.genvar) + box.most_recent_frozen = newfz return box def op_setfield(self, jitstate, fielddesc, valuebox): - self.access_info.write_fields += 1 self.learn_nonzeroness(jitstate, True) gv_ptr = self.genvar if gv_ptr: @@ -476,9 +459,22 @@ assert self.content is not None return self.content.op_getsubstruct(jitstate, fielddesc) + @staticmethod + def getfrozen(gv_value): + if gv_value.is_const: + return FrozenPtrConst(gv_value) + else: + return FrozenPtrVar(known_nonzero=False) + class InstanceRedBox(AbstractPtrRedBox, OOTypeMixin): - pass + + @staticmethod + def getfrozen(gv_value): + if gv_value.is_const: + return FrozenInstanceConst(gv_value) + else: + return FrozenInstanceVar() # ____________________________________________________________ @@ -486,6 +482,7 @@ class FrozenValue(object): """An abstract value frozen in a saved state. """ + _attrs_ = ['will_be_promoted'] will_be_promoted = False def is_constant_equal(self, box): @@ -494,6 +491,11 @@ def is_constant_nullptr(self): return False + def check_future_promotions(self, box, memo): + if (self.will_be_promoted and box.is_constant() + and not self.is_constant_equal(box)): + raise DontMerge + class FrozenConst(FrozenValue): @@ -506,11 +508,6 @@ outgoingvarboxes.append(box) return False - def check_future_promotions(self, box, memo): - if (self.will_be_promoted and box.is_constant() - and not self.is_constant_equal(box)): - raise DontMerge - class FrozenVar(FrozenValue): @@ -543,8 +540,6 @@ # XXX could return directly the original IntRedBox return IntRedBox(self.gv_const) -IntRedBox.FrozenConstCls = FrozenIntConst - class FrozenIntVar(FrozenVar): @@ -572,8 +567,6 @@ def unfreeze(self, incomingvarboxes, memo): return BoolRedBox(self.gv_const) -BoolRedBox.FrozenConstCls = FrozenBoolConst - class FrozenBoolVar(FrozenVar): @@ -600,8 +593,6 @@ def unfreeze(self, incomingvarboxes, memo): return DoubleRedBox(self.gv_const) -DoubleRedBox.FrozenConstCls = FrozenDoubleConst - class FrozenDoubleVar(FrozenVar): @@ -616,7 +607,36 @@ return memo[self] -class FrozenAbstractPtrConst(FrozenConst): +class FrozenPtrMixin(object): + _mixin_ = True + ghost_children = None + + def get_ghost_child(self, fielddesc, gv_value): + # ghost children of a constant immutable FrozenPtrConst + # are only used to track future promotions; they have no + # other effect on exactmatch(). + if self.ghost_children is None: + self.ghost_children = {} + else: + try: + return self.ghost_children[fielddesc] + except KeyError: + pass + newfz = fielddesc.getfrozen(gv_value) + self.ghost_children[fielddesc] = newfz + return newfz + + def check_future_promotions(self, box, memo): + FrozenValue.check_future_promotions(self, box, memo) + if self.ghost_children is not None: + for fielddesc, fz_child in self.ghost_children.items(): + box_child = box.getfield_dont_generate_code(memo.rgenop, + fielddesc) + if box_child is not None: + fz_child.check_future_promotions(box_child, memo) + + +class FrozenAbstractPtrConst(FrozenPtrMixin, FrozenConst): def __init__(self, gv_const): FrozenConst.__init__(self) @@ -647,43 +667,15 @@ def unfreeze(self, incomingvarboxes, memo): return self.PtrRedBox(self.gv_const) - const_children = None - - def get_const_child(self, fielddesc, gv_value): - # constant children of a constant immutable FrozenPtrConst - # are only used to track future promotions; they have no - # other effect on exactmatch(). - if self.const_children is None: - self.const_children = {} - else: - try: - return self.const_children[fielddesc] - except KeyError: - pass - newfz = fielddesc.frozenconstcls(gv_value) - self.const_children[fielddesc] = newfz - return newfz - - def check_future_promotions(self, box, memo): - FrozenConst.check_future_promotions(self, box, memo) - if self.const_children is not None: - for fielddesc, fz_child in self.const_children.items(): - box_child = box.getfield_dont_generate_code(memo.rgenop, - fielddesc) - if box_child is not None: - fz_child.check_future_promotions(box_child, memo) - class FrozenPtrConst(FrozenAbstractPtrConst, LLTypeMixin): PtrRedBox = PtrRedBox -PtrRedBox.FrozenConstCls = FrozenPtrConst class FrozenInstanceConst(FrozenAbstractPtrConst, OOTypeMixin): PtrRedBox = InstanceRedBox -InstanceRedBox.FrozenConstCls = FrozenInstanceConst -class AbstractFrozenPtrVar(FrozenVar): +class AbstractFrozenPtrVar(FrozenPtrMixin, FrozenVar): def __init__(self, known_nonzero): FrozenVar.__init__(self) @@ -698,13 +690,7 @@ match = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) if self.known_nonzero and not box.known_nonzero: match = False - if not memo.force_merge: - if isinstance(box.content, VirtualContainer): - # heuristic: if a virtual is neither written to, nor read from - # it might not be "important enough" to keep it virtual - if not box.access_info.read_fields: - return match - raise DontMerge # XXX recursive data structures? + self.check_future_promotions(box, memo) return match def unfreeze(self, incomingvarboxes, memo): @@ -736,12 +722,8 @@ exact = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) match = exact and partialdatamatch if not memo.force_merge and not match: - # heuristic: if a virtual is neither written to, nor read from - # it might not be "important enough" to keep it virtual from pypy.jit.timeshifter.rcontainer import VirtualContainer if isinstance(box.content, VirtualContainer): - if not box.access_info.read_fields: - return match raise DontMerge # XXX recursive data structures? return match @@ -751,7 +733,6 @@ def exactmatch(self, box, outgoingvarboxes, memo): assert isinstance(box, PtrRedBox) if box.genvar: - # XXX should we consider self.access_info here too? raise DontMerge else: assert box.content is not None Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_merging.py Tue Apr 1 15:24:00 2008 @@ -138,3 +138,34 @@ box3 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s3)) memo = rvalue.exactmatch_memo(rgenop) py.test.raises(rvalue.DontMerge, frozen.exactmatch, box3, [], memo) + + def test_promote_field_of_variable_immutable(self): + rgenop = FakeRGenOp() + gv = FakeGenVar() + box = rvalue.PtrRedBox(gv) + frozen = box.freeze(rvalue.freeze_memo()) + assert box.most_recent_frozen is not None # attached by freeze + + jitstate = FakeJITState() + + x_box = rtimeshift.gengetfield(jitstate, False, self.fielddesc, box) + assert not x_box.genvar.is_const + assert x_box.most_recent_frozen is not None # attached by gengetfield() + x_box.see_promote() + + memo = rvalue.exactmatch_memo(rgenop) + assert frozen.exactmatch(box, [], memo) + + prebuilt_s2 = lltype.malloc(self.STRUCT) + prebuilt_s2.x = 42 + box2 = rvalue.PtrRedBox(FakeGenConst(prebuilt_s2)) + memo = rvalue.exactmatch_memo(rgenop) + py.test.raises(rvalue.DontMerge, frozen.exactmatch, box2, [], memo) + + gv2 = FakeGenVar() + box3 = rvalue.PtrRedBox(gv2) + x_box3 = rtimeshift.gengetfield(jitstate, False, self.fielddesc, box3) + x_box3.see_promote() + x_box3.setgenvar(FakeGenConst(42)) + memo = rvalue.exactmatch_memo(rgenop) + py.test.raises(rvalue.DontMerge, frozen.exactmatch, box3, [], memo) Modified: pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py ============================================================================== --- pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py (original) +++ pypy/branch/jit-merging-logic/pypy/jit/timeshifter/test/test_rcontainer.py Tue Apr 1 15:24:00 2008 @@ -99,27 +99,6 @@ # constbox20 in oldbox. - def test_merge_with_ptrvar(self): - DontMerge = rvalue.DontMerge - V0 = FakeGenVar() - ptrbox = rvalue.PtrRedBox(V0) - jitstate = FakeJITState() - S = self.STRUCT - constbox20 = makebox(20) - oldbox = vmalloc(S, constbox20) - - # do a getfield to prevent a merge - box2 = oldbox.op_getfield(jitstate, self.fielddesc) - assert box2 is constbox20 - assert oldbox.access_info.read_fields == 1 - frozenbox = oldbox.freeze(rvalue.freeze_memo()) - # check that ptrbox does not match the frozen virtual struct ever - py.test.raises(DontMerge, self.match, frozenbox, ptrbox, [ptrbox]) - - # try it the other way round - frozenptrbox = ptrbox.freeze(rvalue.freeze_memo()) - py.test.raises(DontMerge, self.match, frozenptrbox, oldbox, [oldbox]) - def test_merge_with_ptrvar_virtual_never_read(self): DontMerge = rvalue.DontMerge V0 = FakeGenVar() From antocuni at codespeak.net Tue Apr 1 16:38:06 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 1 Apr 2008 16:38:06 +0200 (CEST) Subject: [pypy-svn] r53232 - in pypy/branch/jit-hotpath/pypy: jit/rainbow jit/rainbow/test jit/timeshifter rpython/ootypesystem translator Message-ID: <20080401143806.3CB421684F0@codespeak.net> Author: antocuni Date: Tue Apr 1 16:38:05 2008 New Revision: 53232 Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_vlist.py pypy/branch/jit-hotpath/pypy/jit/rainbow/typesystem.py pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py pypy/branch/jit-hotpath/pypy/jit/timeshifter/vlist.py pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py pypy/branch/jit-hotpath/pypy/translator/exceptiontransform.py Log: port oopspec and vlist to ootype. First test passes Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/rainbow/codewriter.py Tue Apr 1 16:38:05 2008 @@ -5,6 +5,7 @@ from pypy.objspace.flow import model as flowmodel from pypy.rpython.annlowlevel import cachedtype from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.ootypesystem import ootype from pypy.jit.hintannotator.model import originalconcretetype from pypy.jit.hintannotator import model as hintmodel from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer, exception @@ -732,13 +733,13 @@ self.exceptioninstance_positions[exc_class] = result return result - def oopspecdesc_position(self, fnobj, canraise): - key = fnobj, canraise + def oopspecdesc_position(self, opname, oparg, canraise): + key = opname, oparg, canraise if key in self.oopspecdesc_positions: return self.oopspecdesc_positions[key] oopspecdesc = oop.OopSpecDesc(self.RGenOp, self.rtyper, self.exceptiondesc, - fnobj, canraise) + opname, oparg, canraise) result = len(self.oopspecdescs) self.oopspecdescs.append(oopspecdesc) self.oopspecdesc_positions[key] = result @@ -1053,7 +1054,7 @@ def handle_oopspec_call(self, op, withexc): from pypy.jit.timeshifter.oop import Index fnobj = get_funcobj(op.args[0].value) - oopspecdescindex = self.oopspecdesc_position(fnobj, withexc) + oopspecdescindex = self.oopspecdesc_position('call', fnobj, withexc) oopspecdesc = self.oopspecdescs[oopspecdescindex] opargs = op.args[1:] args_v = [] @@ -1591,10 +1592,55 @@ return self.serialize_op_setfield_impl(op) def serialize_op_new(self, op): + TYPE = op.args[0].value + if TYPE.oopspec_name is not None: + # XXX: works only for List + oopspecdescindex = self.oopspecdesc_position('new', TYPE, False) + oopspecdesc = self.oopspecdescs[oopspecdescindex] + deepfrozen = False + index = self.serialize_oparg("red", flowmodel.Constant(0, lltype.Signed)) + self.emit('red_oopspec_call_1') + self.emit(oopspecdescindex) + self.emit(deepfrozen) + self.emit(index) + self.register_redvar(op.result) + return + index = self.structtypedesc_position(op.args[0].value) self.emit("red_new", index) self.register_redvar(op.result) + def serialize_op_oosend(self, op): + if self.hannotator.bookkeeper.is_green_call(op): + assert False, 'TODO' + + withexc = self.can_raise(op) + name = op.args[0].value + opargs = op.args[1:] + SELFTYPE = opargs[0].concretetype + if SELFTYPE.oopspec_name is not None: + hasresult = op.result.concretetype != lltype.Void + _, meth = SELFTYPE._lookup(name) + oopspecdescindex = self.oopspecdesc_position('send', meth, withexc) + oopspecdesc = self.oopspecdescs[oopspecdescindex] + args_v = [] + args = [] + for v in opargs: + args_v.append(v) + args.append(self.serialize_oparg("red", v)) + + hs_self = self.hannotator.binding(opargs[0]) + deepfrozen = hs_self.deepfrozen + + self.emit("red_oopspec_call%s_%s" % ("_noresult" * (not hasresult), + len(args))) + self.emit(oopspecdescindex) + self.emit(deepfrozen) + self.emit(*args) + + else: + assert False, 'TODO' + class GraphTransformer(object): def __init__(self, hannotator): Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_vlist.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_vlist.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_vlist.py Tue Apr 1 16:38:05 2008 @@ -5,7 +5,7 @@ -class TestVList(InterpretationTest): +class VListTest(InterpretationTest): type_system = "lltype" def test_vlist(self): @@ -187,3 +187,24 @@ res = self.interpret(f, [2], [0], policy=P_OOPSPEC) assert res == -7 + + +class TestLLType(VListTest): + type_system = "lltype" + +class TestOOType(VListTest): + type_system = "ootype" + + def _skip(self): + py.test.skip('in progress') + + test_enter_block = _skip + test_merge = _skip + test_replace = _skip + test_force = _skip + test_oop_vlist = _skip + test_alloc_and_set = _skip + test_lists_deepfreeze = _skip + test_frozen_list = _skip + test_frozen_list_indexerror = _skip + test_bogus_index_while_compiling = _skip Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/typesystem.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/rainbow/typesystem.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/rainbow/typesystem.py Tue Apr 1 16:38:05 2008 @@ -4,7 +4,7 @@ def deref(T): if isinstance(T, lltype.Ptr): return T.TO - assert isinstance(T, (ootype.Instance, ootype.Record)) + assert isinstance(T, (ootype.Instance, ootype.BuiltinType)) return T def fieldType(T, name): Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py Tue Apr 1 16:38:05 2008 @@ -5,98 +5,59 @@ from pypy.rpython.llinterp import LLInterpreter from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rpython.lltypesystem import lltype +from pypy.rpython.ootypesystem import ootype from pypy.tool.sourcetools import func_with_new_name from pypy.translator import exceptiontransform from pypy.translator.simplify import get_funcobj, get_functype +from pypy.jit.rainbow.typesystem import deref + +def OopSpecDesc(RGenOp, rtyper, exceptiondesc, opname, oparg, can_raise): + if opname == 'new': + cls = NewOopSpecDesc + elif opname == 'send': + cls = SendOopSpecDesc + elif opname == 'call': + cls = CallOopSpecDesc + return cls(RGenOp, rtyper, exceptiondesc, oparg, can_raise) class Index: def __init__(self, n): self.n = n - -class OopSpecDesc: +class AbstractOopSpecDesc: __metaclass__ = cachedtype def __init__(self, RGenOp, rtyper, exceptiondesc, fnobj, can_raise): self.rtyper = rtyper - ll_func = fnobj._callable - FUNCTYPE = lltype.typeOf(fnobj) - nb_args = len(FUNCTYPE.ARGS) - self.can_raise = can_raise + self._setup_oopdesc(RGenOp, fnobj) - # parse the oopspec and fill in the arguments - operation_name, args = ll_func.oopspec.split('(', 1) - assert args.endswith(')') - args = args[:-1] + ',' # trailing comma to force tuple syntax - if args.strip() == ',': - args = '()' - argnames = ll_func.func_code.co_varnames[:nb_args] - argname2index = dict(zip(argnames, [Index(n) for n in range(nb_args)])) - self.argtuple = eval(args, argname2index) - # end of rather XXX'edly hackish parsing - - OOPARGTYPES = [] - arg_llsig_to_oopsig = {} - for i, obj in enumerate(self.argtuple): - if isinstance(obj, Index): - arg_llsig_to_oopsig[obj.n] = i - OOPARG = FUNCTYPE.ARGS[obj.n] - else: - OOPARG = lltype.typeOf(obj) - OOPARGTYPES.append(OOPARG) - - self.residualargsources = [] - for i in range(nb_args): - ARGTYPE = FUNCTYPE.ARGS[i] - if ARGTYPE is not lltype.Void: - self.residualargsources.append(arg_llsig_to_oopsig[i]) - - self.args_gv = [None] * nb_args - fnptr = fnobj._as_ptr() - self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnptr) - result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) - self.result_kind = result_kind - if FUNCTYPE.RESULT is lltype.Void: + if self.RESULT is lltype.Void: self.errorbox = None self.gv_whatever_return_value = None else: - error_value = exceptiontransform.error_value(FUNCTYPE.RESULT) + error_value = exceptiontransform.error_value(self.RESULT) self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp, error_value) self.gv_whatever_return_value = self.errorbox.genvar - redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT) + redboxbuilder = rvalue.ll_redboxbuilder(self.RESULT) self.redboxbuilder = redboxbuilder - self.sigtoken = RGenOp.sigToken(FUNCTYPE) - - if operation_name == 'newlist': - typename, method = 'list', 'oop_newlist' - SELFTYPE = FUNCTYPE.RESULT.TO - is_method = False - elif operation_name == 'newdict': - typename, method = 'dict', 'oop_newdict' - SELFTYPE = FUNCTYPE.RESULT.TO - is_method = False - else: - typename, method = operation_name.split('.') - method = 'oop_%s_%s' % (typename, method) - SELFTYPE = FUNCTYPE.ARGS[self.argtuple[0].n].TO - is_method = True - self.is_method = is_method # hack! to avoid confusion between the .typedesc attribute # of oopspecdescs of different types (lists, dicts, etc.) # let's use different subclasses for the oopspecdesc too. - self.__class__ = myrealclass = globals()['OopSpecDesc_%s' % typename] + thisclass = self.__class__.__name__ + self.__class__ = myrealclass = globals()['%s_%s' % (thisclass, self.typename)] - vmodule = __import__('pypy.jit.timeshifter.v%s' % (typename,), - None, None, [method]) + vmodule = __import__('pypy.jit.timeshifter.v%s' % (self.typename,), + None, None, [self.method]) self.typedesc = vmodule.TypeDesc(RGenOp, rtyper, exceptiondesc, - SELFTYPE) - handler = getattr(vmodule, method) + self.SELFTYPE) + handler = getattr(vmodule, self.method) boxargcount_max = handler.func_code.co_argcount - 3 boxargcount_min = boxargcount_max - len(handler.func_defaults or ()) + is_method = self.is_method def ll_handler(jitstate, oopspecdesc, deepfrozen, *argboxes): # an indirection to support the fact that the handler() can @@ -114,7 +75,7 @@ assert isinstance(oopspecdesc, myrealclass) if is_method: selfbox = argboxes[0] - assert isinstance(selfbox, rvalue.PtrRedBox) + assert isinstance(selfbox, rvalue.AbstractPtrRedBox) return handler(jitstate, oopspecdesc, deepfrozen, selfbox, *argboxes[1:]) else: @@ -124,21 +85,25 @@ self.couldfold = getattr(handler, 'couldfold', False) if self.couldfold: + # XXX: works only with lltype + ll_func = fnobj._callable oopargcheck = ll_func.oopargcheck # required if couldfold=True # make a copy of the function, for specialization purposes oopargcheck = func_with_new_name(oopargcheck, - 'argcheck_%s' % (method,)) + 'argcheck_%s' % (self.method,)) else: oopargcheck = None if True: # preserve indentation for svn history. # This used to be only if couldfold, but it is now # always required, for the fallback interp - ARGS = FUNCTYPE.ARGS + ARGS = self.ARGS residualargsources = self.residualargsources unrolling_ARGS = unrolling_iterable(ARGS) - unrolling_OOPARGS = unrolling_iterable(enumerate(OOPARGTYPES)) + unrolling_OOPARGS = unrolling_iterable(enumerate(self.OOPARGTYPES)) + RESULT = self.RESULT + fnptr = self.fnptr def do_call(rgenop, args_gv): oopargs = () for i, ARG in unrolling_OOPARGS: @@ -158,7 +123,7 @@ v = oopargs[argsrc] args += (v,) result = maybe_on_top_of_llinterp(exceptiondesc, fnptr)(*args) - if FUNCTYPE.RESULT == lltype.Void: + if RESULT == lltype.Void: return None return rgenop.genconst(result) @@ -179,8 +144,7 @@ jitstate.residual_exception(e) return self.errorbox else: - gv_result = builder.genop_call(self.sigtoken, - self.gv_fnptr, args_gv) + gv_result = self.generate_call(builder, args_gv) if self.can_raise: jitstate.generated_oop_residual_can_raise = True return self.redboxbuilder(gv_result) @@ -195,11 +159,127 @@ return self.errorbox residual_exception._annspecialcase_ = 'specialize:arg(2)' + def __repr__(self): + return '<%s(%s)>' % (self.__class__.__name__, self.method) + +class CallOopSpecDesc(AbstractOopSpecDesc): + + def _setup_oopdesc(self, RGenOp, fnobj): + FUNCTYPE = lltype.typeOf(fnobj) + self.ARGS = FUNCTYPE.ARGS + self.RESULT = FUNCTYPE.RESULT + ll_func = fnobj._callable + nb_args = len(FUNCTYPE.ARGS) + + # parse the oopspec and fill in the arguments + operation_name, args = ll_func.oopspec.split('(', 1) + assert args.endswith(')') + args = args[:-1] + ',' # trailing comma to force tuple syntax + if args.strip() == ',': + args = '()' + argnames = ll_func.func_code.co_varnames[:nb_args] + argname2index = dict(zip(argnames, [Index(n) for n in range(nb_args)])) + self.argtuple = eval(args, argname2index) + # end of rather XXX'edly hackish parsing + + self.OOPARGTYPES = [] + arg_llsig_to_oopsig = {} + for i, obj in enumerate(self.argtuple): + if isinstance(obj, Index): + arg_llsig_to_oopsig[obj.n] = i + OOPARG = FUNCTYPE.ARGS[obj.n] + else: + OOPARG = lltype.typeOf(obj) + self.OOPARGTYPES.append(OOPARG) + + self.residualargsources = [] + for i in range(nb_args): + ARGTYPE = FUNCTYPE.ARGS[i] + if ARGTYPE is not lltype.Void: + self.residualargsources.append(arg_llsig_to_oopsig[i]) + + if operation_name == 'newlist': + self.typename = 'list' + self.method = 'oop_newlist' + self.SELFTYPE = deref(FUNCTYPE.RESULT) + self.is_method = False + elif operation_name == 'newdict': + self.typename = 'dict' + self.method = 'oop_newdict' + self.SELFTYPE = deref(FUNCTYPE.RESULT) + is_method = False + else: + self.typename, method = operation_name.split('.') + self.method = 'oop_%s_%s' % (self.typename, method) + self.SELFTYPE = deref(FUNCTYPE.ARGS[self.argtuple[0].n]) + self.is_method = True + + self.fnptr = fnobj._as_ptr() + self.gv_fnptr = RGenOp.constPrebuiltGlobal(self.fnptr) + self.sigtoken = RGenOp.sigToken(FUNCTYPE) + + # the following attributes seem to be unused +## result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) +## self.result_kind = result_kind +## self.args_gv = [None] * nb_args + + def generate_call(self, builder, args_gv): + return builder.genop_call(self.sigtoken, self.gv_fnptr, args_gv) + + +class CallOopSpecDesc_list(CallOopSpecDesc): + pass + +class CallOopSpecDesc_dict(CallOopSpecDesc): + pass + + +class NewOopSpecDesc(AbstractOopSpecDesc): + def _setup_oopdesc(self, RGenOp, TYPE): + self.SELFTYPE = TYPE + self.ARGS = [] + self.RESULT = TYPE + self.OOPARGTYPES = [] + self.residualargsources = [] + self.typename = TYPE.oopspec_name + self.method = 'oop_new%s' % self.typename + self.is_method = False + + def allocate(): + return ootype.new(TYPE) + self.fnptr = self.rtyper.annotate_helper_fn(allocate, []) + +class NewOopSpecDesc_list(NewOopSpecDesc): + pass + +class NewOopSpecDesc_dict(NewOopSpecDesc): + pass + + +class SendOopSpecDesc(AbstractOopSpecDesc): + def _setup_oopdesc(self, RGenOp, meth): + METH = ootype.typeOf(meth) + assert METH.SELFTYPE is not None, 'fix ootype' + self.SELFTYPE = METH.SELFTYPE + self.ARGS = METH.ARGS + self.RESULT = METH.RESULT + + # we assume the number and position of the arguments are the + # same as in the original oosend + self.OOPARGTYPES = [self.SELFTYPE] + list(METH.ARGS) + self.residualargsources = range(len(self.OOPARGTYPES)) + self.typename = self.SELFTYPE.oopspec_name + methname = meth._name.lstrip('_') + methname = methname.lstrip('ll_') + self.method = 'oop_%s_method_%s' % (self.typename, methname) + self.is_method = True + self.fnptr = meth + -class OopSpecDesc_list(OopSpecDesc): +class SendOopSpecDesc_list(SendOopSpecDesc): pass -class OopSpecDesc_dict(OopSpecDesc): +class SendOopSpecDesc_dict(SendOopSpecDesc): pass Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py Tue Apr 1 16:38:05 2008 @@ -86,8 +86,9 @@ self.name = self._get_type_name(TYPE) self.ptrkind = RGenOp.kindToken(self.PTRTYPE) - self.immutable = TYPE._hints.get('immutable', False) - self.noidentity = TYPE._hints.get('noidentity', False) + hints = getattr(TYPE, '_hints', {}) + self.immutable = hints.get('immutable', False) + self.noidentity = hints.get('noidentity', False) fixsize = not TYPE._is_varsize() @@ -260,14 +261,19 @@ pass def _iter_fields(self, TYPE): - for name, (FIELDTYPE, defl) in TYPE._fields.iteritems(): + try: + fields = TYPE._fields + except AttributeError: + return + for name, (FIELDTYPE, defl) in fields.iteritems(): yield name, FIELDTYPE def _get_type_name(self, TYPE): - if isinstance(TYPE, ootype.Record): - return TYPE._short_name() - else: + try: return TYPE._name + except AttributeError: + return TYPE._short_name() + def create_varsize(jitstate, contdesc, sizebox): gv_size = sizebox.getgenvar(jitstate) Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/timeshifter/vlist.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/vlist.py Tue Apr 1 16:38:05 2008 @@ -6,6 +6,12 @@ from pypy.rpython.lltypesystem import lloperation debug_print = lloperation.llop.debug_print +def TypeDesc(RGenOp, rtyper, exceptiondesc, LIST): + if rtyper.type_system.name == 'lltypesystem': + return LLTypeListTypeDesc(RGenOp, rtyper, exceptiondesc, LIST) + else: + return OOTypeListTypeDesc(RGenOp, rtyper, exceptiondesc, LIST) + class ItemDesc(object): __metaclass__ = cachedtype @@ -24,17 +30,59 @@ if not T._is_varsize(): self.canbevirtual = True -class ListTypeDesc(object): +class AbstractListTypeDesc(object): __metaclass__ = cachedtype def __init__(self, RGenOp, rtyper, exceptiondesc, LIST): self.LIST = LIST - self.LISTPTR = lltype.Ptr(LIST) + self.LISTPTR = self.Ptr(LIST) self.ptrkind = RGenOp.kindToken(self.LISTPTR) self.null = self.LISTPTR._defl() self.gv_null = RGenOp.constPrebuiltGlobal(self.null) self.exceptiondesc = exceptiondesc + self._setup(RGenOp, rtyper, LIST) + self._define_devirtualize() + self._define_allocate() + + def _define_allocate(self): + LIST = self.LIST + LISTPTR = self.LISTPTR + + def allocate(rgenop, n): + l = LIST.ll_newlist(n) + return rgenop.genconst(l) + + def populate(item_boxes, gv_lst, box_gv_reader): + l = gv_lst.revealconst(LISTPTR) + # NB. len(item_boxes) may be l.ll_length()+1 if need_reshaping :-( + for i in range(l.ll_length()): + box = item_boxes[i] + if box is not None: + gv_value = box_gv_reader(box) + v = gv_value.revealconst(LIST.ITEM) + l.ll_setitem_fast(i, v) + + self.allocate = allocate + self.populate = populate + + def _freeze_(self): + return True + + def factory(self, length, itembox): + vlist = VirtualList(self, length, itembox) + box = self.PtrRedBox(known_nonzero=True) + box.content = vlist + vlist.ownbox = box + return box + + +class LLTypeListTypeDesc(AbstractListTypeDesc): + + Ptr = staticmethod(lltype.Ptr) + PtrRedBox = rvalue.PtrRedBox + + def _setup(self, RGenOp, rtyper, LIST): argtypes = [lltype.Signed] ll_newlist_ptr = rtyper.annotate_helper_fn(LIST.ll_newlist, argtypes) @@ -48,9 +96,6 @@ self.tok_ll_setitem_fast = RGenOp.sigToken( lltype.typeOf(ll_setitem_fast).TO) - self._define_devirtualize() - self._define_allocate() - def _define_devirtualize(self): LIST = self.LIST LISTPTR = self.LISTPTR @@ -70,39 +115,18 @@ self.devirtualize = make, fill_into - def _define_allocate(self): - LIST = self.LIST - LISTPTR = self.LISTPTR - - def allocate(rgenop, n): - l = LIST.ll_newlist(n) - return rgenop.genconst(l) - - def populate(item_boxes, gv_lst, box_gv_reader): - l = gv_lst.revealconst(LISTPTR) - # NB. len(item_boxes) may be l.ll_length()+1 if need_reshaping :-( - for i in range(l.ll_length()): - box = item_boxes[i] - if box is not None: - gv_value = box_gv_reader(box) - v = gv_value.revealconst(LIST.ITEM) - l.ll_setitem_fast(i, v) + - self.allocate = allocate - self.populate = populate +class OOTypeListTypeDesc(AbstractListTypeDesc): - def _freeze_(self): - return True - - def factory(self, length, itembox): - vlist = VirtualList(self, length, itembox) - box = rvalue.PtrRedBox(known_nonzero=True) - box.content = vlist - vlist.ownbox = box - return box + Ptr = staticmethod(lambda T: T) + PtrRedBox = rvalue.InstanceRedBox -TypeDesc = ListTypeDesc + def _setup(self, RGenOp, rtyper, LIST): + pass + def _define_devirtualize(self): + pass # XXX class FrozenVirtualList(FrozenContainer): @@ -163,6 +187,7 @@ def __init__(self, typedesc, length=0, itembox=None): self.typedesc = typedesc + self.itembox = itembox self.item_boxes = [itembox] * length # self.ownbox = ... set in factory() @@ -355,6 +380,18 @@ deepfrozen=deepfrozen) oop_list_nonzero.couldfold = True +def oop_list_method_resize(jitstate, oopspecdesc, deepfrozen, selfbox, lengthbox): + content = selfbox.content + if isinstance(content, VirtualList): + item_boxes = content.item_boxes + length = rvalue.ll_getvalue(lengthbox, lltype.Signed) + if len(item_boxes) < length: + diff = length - len(item_boxes) + item_boxes += [itembox] * diff + else: + oopspecdesc.residual_call(jitstate, [selfbox], + deepfrozen=deepfrozen) + def oop_list_append(jitstate, oopspecdesc, deepfrozen, selfbox, itembox): content = selfbox.content if isinstance(content, VirtualList): Modified: pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/jit-hotpath/pypy/rpython/ootypesystem/ootype.py Tue Apr 1 16:38:05 2008 @@ -13,6 +13,8 @@ class OOType(LowLevelType): + oopspec_name = None + def _is_compatible(TYPE1, TYPE2): if TYPE1 == TYPE2: return True @@ -476,6 +478,7 @@ # placeholder, because we w