From fijal at codespeak.net Sun Jun 1 17:13:57 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 1 Jun 2008 17:13:57 +0200 (CEST) Subject: [pypy-svn] r55470 - pypy/branch/judy-trees Message-ID: <20080601151357.E3BCD168543@codespeak.net> Author: fijal Date: Sun Jun 1 17:13:56 2008 New Revision: 55470 Added: pypy/branch/judy-trees/ - copied from r55469, pypy/dist/ Log: Create a branch to experiment with judy trees From fijal at codespeak.net Sun Jun 1 17:32:15 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 1 Jun 2008 17:32:15 +0200 (CEST) Subject: [pypy-svn] r55471 - in pypy/branch/judy-trees/pypy: rlib rpython rpython/test Message-ID: <20080601153215.9CA2D168067@codespeak.net> Author: fijal Date: Sun Jun 1 17:32:12 2008 New Revision: 55471 Added: pypy/branch/judy-trees/pypy/rlib/rjudy.py (contents, props changed) pypy/branch/judy-trees/pypy/rpython/rjudy.py (contents, props changed) pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py (contents, props changed) Log: Add a sample rjudy implementation start. Added: pypy/branch/judy-trees/pypy/rlib/rjudy.py ============================================================================== --- (empty file) +++ pypy/branch/judy-trees/pypy/rlib/rjudy.py Sun Jun 1 17:32:12 2008 @@ -0,0 +1,23 @@ + +from pypy.rpython.extregistry import ExtRegistryEntry +from pypy.annotation import model as annmodel + +class JudyTree(dict): + pass + +class SomeJudyTree(annmodel.SomeObject): + def rtyper_makerepr(self, rtyper): + from pypy.rpython.rjudy import JudyRepr + return JudyRepr(rtyper) + +class JudyTreeEntry(ExtRegistryEntry): + """ This registers JudyTree to be special-treated by a translation + toolchain + """ + _about_ = JudyTree + + def compute_result_annotation(self): + return SomeJudyTree() + + def specialize_call(self, hop): + return hop.r_result.rtype_new(hop) Added: pypy/branch/judy-trees/pypy/rpython/rjudy.py ============================================================================== --- (empty file) +++ pypy/branch/judy-trees/pypy/rpython/rjudy.py Sun Jun 1 17:32:12 2008 @@ -0,0 +1,54 @@ + +from pypy.tool.pairtype import pairtype +from pypy.annotation import model as annmodel +from pypy.objspace.flow.model import Constant +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rffi +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rpython.rtyper import Repr +from pypy.rpython import rmodel + +eci = ExternalCompilationInfo( + includes = ['Judy.h'], + libraries = ['Judy'] + ) + +LL_DICT = rffi.VOIDPP +VALUE_TP = rffi.CArrayPtr(lltype.Signed) + +JudyLIns = rffi.llexternal('JudyLIns', [LL_DICT, lltype.Signed, lltype.Signed], + VALUE_TP, compilation_info=eci) +JudyLCount = rffi.llexternal('JudyLCount', [rffi.VOIDP, lltype.Signed, + lltype.Signed, + lltype.Signed], lltype.Signed, + compilation_info=eci) + +class JudyRepr(Repr): + lowleveltype = LL_DICT + def __init__(self, rtyper): + self.rtyper = rtyper + + def rtype_len(self, hop): + v_dict, = hop.inputargs(self) + return hop.gendirectcall(ll_dict_len, v_dict) + + def rtype_new(self, hop): + return hop.gendirectcall(ll_newdict) + +class __extend__(pairtype(JudyRepr, rmodel.Repr)): + def rtype_setitem((r_dict, r_key), hop): + v_dict, v_key, v_value = hop.inputargs(r_dict, lltype.Signed, lltype.Signed) + hop.exception_cannot_occur() + hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value) + +def ll_newdict(): + carray = lltype.malloc(LL_DICT.TO, 1, flavor='raw') + carray[0] = lltype.nullptr(rffi.VOIDP.TO) + return carray + +def ll_dict_setitem(dict, key, value): + addr = JudyLIns(dict, rffi.cast(rffi.VOIDP, key), 0) + addr[0] = value + +def ll_dict_len(dict): + return JudyLCount(dict[0], 0, -1, 0) Added: pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py ============================================================================== --- (empty file) +++ pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py Sun Jun 1 17:32:12 2008 @@ -0,0 +1,15 @@ + +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin + +from pypy.rlib.rjudy import JudyTree + +class BaseTest(BaseRtypingTest): + def test_creation(self): + def f(): + x = JudyTree() + return len(x) + assert self.interpret(f, []) == 0 + +class TestLLtype(BaseTest, LLRtypeMixin): + pass + From fijal at codespeak.net Sun Jun 1 17:35:32 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 1 Jun 2008 17:35:32 +0200 (CEST) Subject: [pypy-svn] r55472 - in pypy/branch/judy-trees/pypy: rlib rpython rpython/test Message-ID: <20080601153532.F1A54168436@codespeak.net> Author: fijal Date: Sun Jun 1 17:35:31 2008 New Revision: 55472 Modified: pypy/branch/judy-trees/pypy/rlib/rjudy.py pypy/branch/judy-trees/pypy/rpython/rjudy.py pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py Log: * Add an explicit free and pass a test * Add exception_is_here/cannot_occur Modified: pypy/branch/judy-trees/pypy/rlib/rjudy.py ============================================================================== --- pypy/branch/judy-trees/pypy/rlib/rjudy.py (original) +++ pypy/branch/judy-trees/pypy/rlib/rjudy.py Sun Jun 1 17:35:31 2008 @@ -10,6 +10,9 @@ from pypy.rpython.rjudy import JudyRepr return JudyRepr(rtyper) + def method_free(self): + return annmodel.s_None + class JudyTreeEntry(ExtRegistryEntry): """ This registers JudyTree to be special-treated by a translation toolchain Modified: pypy/branch/judy-trees/pypy/rpython/rjudy.py ============================================================================== --- pypy/branch/judy-trees/pypy/rpython/rjudy.py (original) +++ pypy/branch/judy-trees/pypy/rpython/rjudy.py Sun Jun 1 17:35:31 2008 @@ -30,11 +30,18 @@ def rtype_len(self, hop): v_dict, = hop.inputargs(self) + hop.exception_cannot_occur() return hop.gendirectcall(ll_dict_len, v_dict) def rtype_new(self, hop): + hop.exception_is_here() return hop.gendirectcall(ll_newdict) + def rtype_method_free(self, hop): + v_j, = hop.inputargs(self) + hop.exception_is_here() + return hop.gendirectcall(ll_free, v_j) + class __extend__(pairtype(JudyRepr, rmodel.Repr)): def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, lltype.Signed, lltype.Signed) @@ -52,3 +59,6 @@ def ll_dict_len(dict): return JudyLCount(dict[0], 0, -1, 0) + +def ll_free(dict): + lltype.free(dict, flavor='raw') Modified: pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py ============================================================================== --- pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py (original) +++ pypy/branch/judy-trees/pypy/rpython/test/test_rjudy.py Sun Jun 1 17:35:31 2008 @@ -7,7 +7,9 @@ def test_creation(self): def f(): x = JudyTree() - return len(x) + res = len(x) + x.free() + return res assert self.interpret(f, []) == 0 class TestLLtype(BaseTest, LLRtypeMixin): From fijal at codespeak.net Sun Jun 1 18:13:36 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 1 Jun 2008 18:13:36 +0200 (CEST) Subject: [pypy-svn] r55473 - pypy/dist/pypy/objspace/std/test Message-ID: <20080601161336.DFC041684D2@codespeak.net> Author: fijal Date: Sun Jun 1 18:13:34 2008 New Revision: 55473 Modified: pypy/dist/pypy/objspace/std/test/test_unicodeobject.py Log: A failing test for unicode subclasses Modified: pypy/dist/pypy/objspace/std/test/test_unicodeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_unicodeobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_unicodeobject.py Sun Jun 1 18:13:34 2008 @@ -603,3 +603,15 @@ # the following two cases are really there to emulate a CPython bug. _test_concat(str, unicode) # uses hack in add__String_Unicode() _test_concat(unicode, str) # uses hack in descroperation.binop_impl() + + def test_returns_subclass(self): + skip("Failing") + class X(unicode): + pass + + class Y(object): + def __unicode__(self): + return X("stuff") + + assert unicode(Y()).__class__ is X + From afa at codespeak.net Sun Jun 1 23:03:16 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Sun, 1 Jun 2008 23:03:16 +0200 (CEST) Subject: [pypy-svn] r55474 - pypy/branch/build-external/pypy/lib Message-ID: <20080601210316.6A39A16853B@codespeak.net> Author: afa Date: Sun Jun 1 23:03:11 2008 New Revision: 55474 Modified: pypy/branch/build-external/pypy/lib/_locale.py Log: Implement getdefaultlocale() for windows. The function does work, but the module still cannot be imported... Modified: pypy/branch/build-external/pypy/lib/_locale.py ============================================================================== --- pypy/branch/build-external/pypy/lib/_locale.py (original) +++ pypy/branch/build-external/pypy/lib/_locale.py Sun Jun 1 23:03:11 2008 @@ -286,9 +286,42 @@ return buf.value def getdefaultlocale(): - # TODO: Port code from CPython for Windows and Mac OS + # TODO: Port code from CPython for Mac OS raise NotImplementedError() +if sys.platform == 'nt': + def getdefaultlocale(): + kernel32 = ctypes.WinDLL('kernel32') + encoding = "cp%d" % (kernel32.GetACP()) + + GetLocaleInfo = kernel32.GetLocaleInfoA + GetLocaleInfo.argtypes = [ctypes.c_long, ctypes.c_long, + ctypes.c_char_p, ctypes.c_int] + GetLocaleInfo.restype = ctypes.c_int + + LOCALE_USER_DEFAULT = 0 + LOCALE_SISO639LANGNAME = 0x00000059 # ISO abbreviated language name + LOCALE_SISO3166CTRYNAME = 0x0000005A # ISO abbreviated country name + # according to MSDN, the maximum length of these strings is 9 + + language = create_string_buffer(10) + if not GetLocaleInfo( + LOCALE_USER_DEFAULT, + LOCALE_SISO639LANGNAME, + language, 10): + return None, encoding + + country = create_string_buffer(10) + if not GetLocaleInfo( + LOCALE_USER_DEFAULT, + LOCALE_SISO3166CTRYNAME, + country, 10): + return None, encoding + + locale = "%s_%s" % (language, country) + return locale, encoding + + if HAS_LANGINFO: _nl_langinfo = libc.nl_langinfo _nl_langinfo.argtypes = (nl_item,) From santagada at codespeak.net Mon Jun 2 00:37:31 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Mon, 2 Jun 2008 00:37:31 +0200 (CEST) Subject: [pypy-svn] r55476 - in pypy/branch/js-refactoring/pypy/lang/js: . test test/ecma Message-ID: <20080601223731.16E49398007@codespeak.net> Author: santagada Date: Mon Jun 2 00:37:28 2008 New Revision: 55476 Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: lots of bugfixes. A new for, forin, forinvar, with, some more methods on standard objects, and a rewrite to make scopes grow like a normal stack. also a bugfix on some code for bytecode dipatch that was much slower than it should 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 Mon Jun 2 00:37:28 2008 @@ -426,7 +426,15 @@ else: target = None return operations.Break(pos, target) - + + def visit_continuestatement(self, node): + pos = self.get_pos(node) + if len(node.children) > 0: + target = self.dispatch(node.children[0]) + else: + target = None + return operations.Continue(pos, target) + def visit_returnstatement(self, node): pos = self.get_pos(node) if len(node.children) > 0: @@ -463,7 +471,7 @@ def visit_withstatement(self, node): pos = self.get_pos(node) - identifier = self.dispatch(node.children[0]) + withpart = self.dispatch(node.children[0]) body = self.dispatch(node.children[1]) - return operations.With(pos, identifier, body) - + return operations.With(pos, withpart, body) + Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Mon Jun 2 00:37:28 2008 @@ -11,7 +11,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.streamio import open_file_as_stream from pypy.lang.js.jscode import JsCode -from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf +from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf, r_uint ASTBUILDER = ASTBuilder() @@ -307,15 +307,25 @@ raise JsTypeError('Wrong type') return W_String(this.Value.ToString(ctx)) - class W_NumberValueToString(W_ValueToString): mytype = 'number' class W_BooleanValueToString(W_ValueToString): mytype = 'boolean' -class W_StringValueToString(W_ValueToString): - mytype = 'string' +class W_StringValueToString(W_NewBuiltin): + "this is the toString function for objects with Value" + def Call(self, ctx, args=[], this=None): + if this.type() != 'string': + raise JsTypeError('Wrong type') + return this + +class W_StringValueOf(W_NewBuiltin): + "this is the toString function for objects with Value" + def Call(self, ctx, args=[], this=None): + if this.type() != 'string': + raise JsTypeError('Wrong type') + return this def get_value_of(type, ctx): @@ -398,6 +408,7 @@ return W_String(common_join(ctx, this, sep=',')) class W_ArrayJoin(W_NewBuiltin): + length = 1 def Call(self, ctx, args=[], this=None): if len(args) >= 1 and not args[0] is w_Undefined: sep = args[0].ToString(ctx) @@ -406,6 +417,28 @@ return W_String(common_join(ctx, this, sep)) +class W_ArrayReverse(W_NewBuiltin): + length = 0 + def Call(self, ctx, args=[], this=None): + r2 = this.Get(ctx, 'length').ToUInt32(ctx) + k = r_uint(0) + r3 = r_uint(math.floor( float(r2)/2.0 )) + if r3 == k: + return this + + while k < r3: + r6 = r2 - k - 1 + r7 = str(k) + r8 = str(r6) + + r9 = this.Get(ctx, r7) + r10 = this.Get(ctx, r8) + + this.Put(ctx, r7, r10) + this.Put(ctx, r8, r9) + k += 1 + + return this class W_DateFake(W_NewBuiltin): # XXX This is temporary def Call(self, ctx, args=[], this=None): @@ -433,13 +466,15 @@ w_Function = W_Function(ctx, Class='Function', Prototype=w_ObjPrototype) - w_Global.Put(ctx, 'Function', w_Function) + w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon) w_Object = W_ObjectObject('Object', w_Function) w_Object.Put(ctx, 'prototype', w_ObjPrototype, flags = allon) w_Global.Put(ctx, 'Object', w_Object) + w_Global.Prototype = w_ObjPrototype + w_FncPrototype = w_Function.Call(ctx, this=w_Function) w_Function.Put(ctx, 'prototype', w_FncPrototype, flags = allon) w_Function.Put(ctx, 'constructor', w_Function) @@ -450,7 +485,7 @@ put_values(w_ObjPrototype, { 'constructor': w_Object, - '__proto__': w_Null, + '__proto__': w_FncPrototype, 'toString': toString, 'toLocaleString': toString, 'valueOf': W_ValueOf(ctx), @@ -461,11 +496,12 @@ #properties of the function prototype put_values(w_FncPrototype, { - 'constructor': w_FncPrototype, - '__proto__': w_ObjPrototype, + 'constructor': w_Function, + '__proto__': w_FncPrototype, 'toString': W_FToString(ctx), 'apply': W_Apply(ctx), - 'call': W_Call(ctx), + 'call': W_Call(ctx), + 'arguments': w_Null, }) w_Boolean = W_BooleanObject('Boolean', w_FncPrototype) @@ -528,7 +564,7 @@ 'constructor': w_FncPrototype, '__proto__': w_StrPrototype, 'toString': W_StringValueToString(ctx), - 'valueOf': get_value_of('String', ctx), + 'valueOf': W_StringValueOf(ctx), 'charAt': W_CharAt(ctx), 'concat': W_Concat(ctx), 'indexOf': W_IndexOf(ctx), @@ -536,6 +572,7 @@ }) w_String.Put(ctx, 'prototype', w_StrPrototype) + w_String.Put(ctx, 'fromCharCode', w_String) #dummy w_Global.Put(ctx, 'String', w_String) w_Array = W_ArrayObject('Array', w_FncPrototype) @@ -546,7 +583,9 @@ 'constructor': w_FncPrototype, '__proto__': w_ArrPrototype, 'toString': W_ArrayToString(ctx), - 'join': W_ArrayJoin(ctx) + 'join': W_ArrayJoin(ctx), + 'reverse': W_ArrayReverse(ctx), + 'sort': w_FncPrototype, #dummy }) w_Array.Put(ctx, 'prototype', w_ArrPrototype, flags = allon) @@ -574,9 +613,9 @@ w_Date = W_DateFake(ctx, Class='Date') w_Global.Put(ctx, 'Date', w_Date) - w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN)) - w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY)) - w_Global.Put(ctx, 'undefined', w_Undefined) + w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN), flags = DE|DD) + w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY), flags = DE|DD) + w_Global.Put(ctx, 'undefined', w_Undefined, flags = DE|DD) w_Global.Put(ctx, 'eval', W_Builtin(evaljs)) w_Global.Put(ctx, 'parseInt', W_Builtin(parseIntjs)) w_Global.Put(ctx, 'parseFloat', W_Builtin(parseFloatjs)) @@ -585,7 +624,6 @@ w_Global.Put(ctx, 'print', W_Builtin(printjs)) w_Global.Put(ctx, 'unescape', W_Builtin(unescapejs)) - w_Global.Put(ctx, 'this', w_Global) # DEBUGGING if 0: Modified: pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py Mon Jun 2 00:37:28 2008 @@ -33,7 +33,7 @@ def loadjs(ctx, args, this): - filename = args[0].ToString() + filename = args[0].ToString(ctx) t = load_file(filename) return t.execute(ctx) @@ -106,7 +106,7 @@ def showtraceback(self, exc): # XXX format exceptions nicier - print exc.exception.ToString() + print exc.exception.ToString(None) #XXX should not be none def showsyntaxerror(self, filename, exc): # XXX format syntax errors nicier 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 Mon Jun 2 00:37:28 2008 @@ -10,6 +10,7 @@ compare_e, increment, commonnew, mult, division, uminus, mod from pypy.rlib.jit import hint from pypy.rlib.rarithmetic import intmask +from pypy.rlib.objectmodel import we_are_translated class AlreadyRun(Exception): pass @@ -25,13 +26,21 @@ to_pop = 0 try: while i < len(opcodes): - for name, op in opcode_unrolling: + if we_are_translated(): + #this is an optimization strategy for translated code + #on top of cpython it destroys the performance + #besides, this code might be completely wrong opcode = opcodes[i] - opcode = hint(opcode, deepfreeze=True) - if isinstance(opcode, op): - result = opcode.eval(ctx, stack) - assert result is None - break + for name, op in opcode_unrolling: + opcode = hint(opcode, deepfreeze=True) + if isinstance(opcode, op): + result = opcode.eval(ctx, stack) + assert result is None + break + else: + opcode = opcodes[i] + result = opcode.eval(ctx, stack) + assert result is None if isinstance(opcode, BaseJump): i = opcode.do_jump(stack, i) else: @@ -110,7 +119,7 @@ def emit_continue(self): if not self.startlooplabel: - raise ThrowError(W_String("Continue outside loop")) + raise ThrowException(W_String("Continue outside loop")) self.emit('JUMP', self.startlooplabel[-1]) def emit(self, operation, *args): @@ -174,6 +183,9 @@ self.code.run(ctx) except ReturnException, e: return e.value + except: + print "unhandled exception in function:", self.name + raise return w_Undefined class Opcode(object): @@ -275,7 +287,11 @@ self.identifier = identifier def eval(self, ctx, stack): - stack.append(ctx.resolve_identifier(self.identifier)) + try: + stack.append(ctx.resolve_identifier(ctx, self.identifier)) + except: + print self.identifier + raise def __repr__(self): return 'LOAD_VARIABLE "%s"' % (self.identifier,) @@ -371,7 +387,11 @@ def eval(self, ctx, stack): w_obj = stack.pop().ToObject(ctx) - stack.append(w_obj.Get(ctx, self.name)) + try: + stack.append(w_obj.Get(ctx, self.name)) + except: + print w_obj, self.name + raise #stack.append(W_Reference(self.name, w_obj)) def __repr__(self): @@ -415,7 +435,7 @@ def eval(self, ctx, stack): try: - var = ctx.resolve_identifier(self.name) + var = ctx.resolve_identifier(ctx, self.name) stack.append(W_String(var.type())) except ThrowException: stack.append(W_String('undefined')) @@ -541,7 +561,7 @@ left = stack.pop() elem = stack.pop() value = stack.pop() - name = elem.ToString() + name = elem.ToString(ctx) value = self.operation(ctx, left, name, value) left.ToObject(ctx).Put(ctx, name, value) stack.append(value) @@ -588,7 +608,7 @@ class BaseAssignOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop() - left = ctx.resolve_identifier(name) + left = ctx.resolve_identifier(ctx, name) result = self.operation(ctx, left, right) stack.append(result) return result @@ -596,7 +616,7 @@ class BaseAssignBitOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop().ToInt32(ctx) - left = ctx.resolve_identifier(name).ToInt32(ctx) + left = ctx.resolve_identifier(ctx, name).ToInt32(ctx) result = self.operation(ctx, left, right) stack.append(result) return result @@ -627,14 +647,14 @@ class STORE_POSTINCR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(name) + value = ctx.resolve_identifier(ctx, name) newval = increment(ctx, value) stack.append(value) return newval class STORE_POSTDECR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(name) + value = ctx.resolve_identifier(ctx, name) newval = increment(ctx, value, -1) stack.append(value) return newval @@ -742,31 +762,31 @@ def eval(self, ctx, stack): stack.pop() +def common_call(ctx, r1, args, this, name): + if not isinstance(r1, W_PrimitiveObject): + raise ThrowException(W_String("%s is not a callable (%s)"%(r1.ToString(ctx), name))) + try: + res = r1.Call(ctx=ctx, args=args.tolist(), this=this) + except JsTypeError: + raise ThrowException(W_String("%s is not a function (%s)"%(r1.ToString(ctx), name))) + return res + class CALL(Opcode): def eval(self, ctx, stack): r1 = stack.pop() args = stack.pop() - if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("it is not a callable")) - try: - res = r1.Call(ctx=ctx, args=args.tolist(), this=None) - except JsTypeError: - raise ThrowException(W_String('it is not a function')) - stack.append(res) + name = r1.ToString(ctx) + #XXX hack, this should be comming from context + stack.append(common_call(ctx, r1, args, ctx.scope[-1], name)) class CALL_METHOD(Opcode): def eval(self, ctx, stack): method = stack.pop() what = stack.pop().ToObject(ctx) args = stack.pop() - r1 = what.Get(ctx, method.ToString()) - if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("it is not a callable")) - try: - res = r1.Call(ctx=ctx, args=args.tolist(), this=what) - except JsTypeError: - raise ThrowException(W_String('it is not a function')) - stack.append(res) + name = method.ToString(ctx) #XXX missing ctx? + r1 = what.Get(ctx, name) + stack.append(common_call(ctx, r1, args, what, name)) class DUP(Opcode): @@ -856,11 +876,8 @@ # ---------------- with support --------------------- class WITH_START(Opcode): - def __init__(self, name): - self.name = name - def eval(self, ctx, stack): - ctx.push_object(ctx.resolve_identifier(self.name).ToObject(ctx)) + ctx.push_object(stack.pop().ToObject(ctx)) class WITH_END(Opcode): def eval(self, ctx, stack): @@ -877,7 +894,7 @@ class DELETE_MEMBER(Opcode): def eval(self, ctx, stack): - what = stack.pop().ToString() + what = stack.pop().ToString(ctx) obj = stack.pop().ToObject(ctx) stack.append(newbool(obj.Delete(what))) 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 Mon Jun 2 00:37:28 2008 @@ -256,8 +256,10 @@ if Prototype is None: proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype') Prototype = proto - + W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc) + if hasattr(self, 'length'): + self.Put(ctx, 'length', W_IntNumber(self.length), flags = DD|RO) def Call(self, ctx, args=[], this = None): raise NotImplementedError @@ -364,7 +366,7 @@ def ToObject(self, ctx): return create_object(ctx, 'Boolean', Value=self) - def ToString(self, ctx=None): + def ToString(self, ctx): if self.boolval == True: return "true" return "false" @@ -386,6 +388,7 @@ class W_String(W_Primitive): def __init__(self, strval): super(W_String, self).__init__() + self.Class = 'string' #hack self.strval = strval def __repr__(self): @@ -398,10 +401,13 @@ proto = ctx.get_global().Get(ctx, 'String').Get(ctx, 'prototype') return proto.Get(ctx, P) + def Put(self, ctx, P, V, flags=0): + pass + def ToObject(self, ctx): return self #create_object(ctx, 'String', Value=self) - def ToString(self, ctx=None): + def ToString(self, ctx): return self.strval def ToBoolean(self): @@ -414,7 +420,7 @@ return 'string' def GetPropertyName(self): - return self.ToString() + return self.strval def ToNumber(self, ctx): if not self.strval: @@ -444,7 +450,7 @@ super(W_IntNumber, self).__init__() self.intval = intmask(intval) - def ToString(self, ctx=None): + def ToString(self, ctx): # XXX incomplete, this doesn't follow the 9.8.1 recommendation return str(self.intval) @@ -462,7 +468,7 @@ return r_uint(self.intval) def GetPropertyName(self): - return self.ToString() + return str(self.intval) def __repr__(self): return 'W_IntNumber(%s)' % (self.intval,) @@ -474,7 +480,7 @@ super(W_FloatNumber, self).__init__() self.floatval = float(floatval) - def ToString(self, ctx = None): + def ToString(self, ctx): # XXX incomplete, this doesn't follow the 9.8.1 recommendation if isnan(self.floatval): return 'NaN' @@ -517,7 +523,7 @@ def __init__(self, list_w): self.list_w = list_w - def ToString(self, ctx = None): + def ToString(self, ctx): raise SeePage(42) def ToBoolean(self): @@ -538,7 +544,7 @@ assert scope is not None self.scope = scope if this is None: - self.this = scope[-1] + self.this = scope[0] else: self.this = this if variable is None: @@ -557,7 +563,7 @@ def assign(self, name, value): assert name is not None - for obj in self.scope: + for obj in reversed(self.scope): assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -571,7 +577,7 @@ self.variable.Put(self.get_global(), name, value) def delete_identifier(self, name): - for obj in self.scope: + for obj in reversed(self.scope): assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -588,26 +594,25 @@ self.variable.Put(ctx, name, value, flags = flags) def get_global(self): - return self.scope[-1] + return self.scope[0] def push_object(self, obj): """push object into scope stack""" assert isinstance(obj, W_PrimitiveObject) - # XXX O(n^2) - self.scope.insert(0, obj) + self.scope.append(obj) self.variable = obj def pop_object(self): """remove the last pushed object""" - return self.scope.pop(0) + return self.scope.pop() - def resolve_identifier(self, identifier): - for obj in self.scope: + def resolve_identifier(self, ctx, identifier): + if identifier == 'this': + return self.this + for obj in reversed(self.scope): assert isinstance(obj, W_PrimitiveObject) - try: - return obj.propdict[identifier].value - except KeyError: - pass + if obj.HasProperty(identifier): + return obj.Get(ctx, identifier) raise ThrowException(W_String("ReferenceError: %s is not defined" % identifier)) def global_context(w_global): 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 Mon Jun 2 00:37:28 2008 @@ -712,14 +712,14 @@ bytecode.emit('LOAD_UNDEFINED') class With(Statement): - def __init__(self, pos, identifier, body): + def __init__(self, pos, withpart, body): self.pos = pos - assert isinstance(identifier, VariableIdentifier) - self.identifier = identifier.identifier + self.withpart = withpart self.body = body def emit(self, bytecode): - bytecode.emit('WITH_START', self.identifier) + self.withpart.emit(bytecode) + bytecode.emit('WITH_START') self.body.emit(bytecode) bytecode.emit('WITH_END') @@ -750,17 +750,15 @@ bytecode.emit('JUMP', startlabel) bytecode.emit_endloop_label(endlabel) -class ForVarIn(Statement): - def __init__(self, pos, vardecl, lobject, body): +class ForIn(Statement): + def __init__(self, pos, name, lobject, body): self.pos = pos - assert isinstance(vardecl, VariableDeclaration) - self.iteratorname = vardecl.identifier + #assert isinstance(iterator, Node) + self.iteratorname = name self.object = lobject self.body = body - def emit(self, bytecode): - bytecode.emit('DECLARE_VAR', self.iteratorname) self.object.emit(bytecode) bytecode.emit('LOAD_ITERATOR') precond = bytecode.emit_startloop_label() @@ -770,27 +768,19 @@ self.body.emit(bytecode) bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) - bytecode.emit('POP') + bytecode.emit('POP') -class ForIn(Statement): - def __init__(self, pos, name, lobject, body): +class ForVarIn(ForIn): + def __init__(self, pos, vardecl, lobject, body): self.pos = pos - #assert isinstance(iterator, Node) - self.iteratorname = name + assert isinstance(vardecl, VariableDeclaration) + self.iteratorname = vardecl.identifier self.object = lobject self.body = body def emit(self, bytecode): - self.object.emit(bytecode) - bytecode.emit('LOAD_ITERATOR') - precond = bytecode.emit_startloop_label() - finish = bytecode.prealocate_endloop_label() - bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) - bytecode.emit('NEXT_ITERATOR', self.iteratorname) - self.body.emit(bytecode) - bytecode.emit('JUMP', precond) - bytecode.emit_endloop_label(finish) - bytecode.emit('POP') + bytecode.emit('DECLARE_VAR', self.iteratorname) + ForIn.emit(self, bytecode) class For(Statement): def __init__(self, pos, setup, condition, update, body): @@ -804,13 +794,17 @@ self.setup.emit(bytecode) if isinstance(self.setup, Expression): bytecode.emit('POP') + + firstep = bytecode.prealocate_label() + bytecode.emit('JUMP', firstep) precond = bytecode.emit_startloop_label() finish = bytecode.prealocate_endloop_label() + self.update.emit(bytecode) + bytecode.emit('POP') + bytecode.emit_label(firstep) self.condition.emit(bytecode) bytecode.emit('JUMP_IF_FALSE', finish) self.body.emit(bytecode) - self.update.emit(bytecode) - bytecode.emit('POP') bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Mon Jun 2 00:37:28 2008 @@ -44,8 +44,8 @@ if not hasattr(cls, 'shellfile'): cls.shellfile = load_file(str(shellpath)) cls.interp.run(cls.shellfile) - cls.testcases = cls.interp.global_context.resolve_identifier('testcases') - cls.tc = cls.interp.global_context.resolve_identifier('tc') + cls.testcases = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'testcases') + cls.tc = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'tc') # override eval cls.interp.w_Global.Put(cls.interp.global_context, 'eval', W_Builtin(overriden_evaljs)) @@ -71,10 +71,11 @@ except JsBaseExcept: raise Failed(msg="Javascript Error", excinfo=py.code.ExceptionInfo()) except: + #print self.interp._code raise Failed(excinfo=py.code.ExceptionInfo()) ctx = self.interp.global_context - testcases = ctx.resolve_identifier('testcases') - self.tc = ctx.resolve_identifier('tc') + testcases = ctx.resolve_identifier(ctx, 'testcases') + self.tc = ctx.resolve_identifier(ctx, 'tc') testcount = testcases.Get(ctx, 'length').ToInt32(ctx) self.testcases = testcases return range(testcount) @@ -89,9 +90,9 @@ def run(self): ctx = JSTestFile.interp.global_context - r3 = ctx.resolve_identifier('run_test') + r3 = ctx.resolve_identifier(ctx, 'run_test') w_test_number = W_IntNumber(self.number) - result = r3.Call(ctx=ctx, args=[w_test_number]).ToString() + result = r3.Call(ctx=ctx, args=[w_test_number]).ToString(ctx) __tracebackhide__ = True if result != "passed": raise Failed(msg=result) Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js Mon Jun 2 00:37:28 2008 @@ -120,9 +120,9 @@ // print out bugnumber - if ( BUGNUMBER ) { - print ("BUGNUMBER: " + BUGNUMBER ); - } + // if ( BUGNUMBER ) { + // print ("BUGNUMBER: " + BUGNUMBER ); + // } } function test() { 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 Mon Jun 2 00:37:28 2008 @@ -341,6 +341,15 @@ } print('out');""", "out") +def test_continue(): + assertp(""" + for(x = 0; x < 3; x++) { + print(x); + continue; + print('error'); + } + print('out');""", ["0","1","2","out"]) + def test_typeof(): assertv(""" var x = 3; @@ -501,7 +510,7 @@ yield assertv, "2 !== 2;", False def test_with(): - assertp(""" + yield assertp, """ var mock = {x:2}; var x=4; print(x); @@ -516,7 +525,13 @@ print(y); } print(x); - """, ['4', '2', '3', '4']) + """, ['4', '2', '3', '4'] + + yield assertp, """ + with(new Array(1,2,3)) { + print(join('.')) + } + """, "1.2.3" def test_bitops(): yield assertv, "2 ^ 2;", 0 From cami at codespeak.net Mon Jun 2 13:24:43 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Mon, 2 Jun 2008 13:24:43 +0200 (CEST) Subject: [pypy-svn] r55493 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080602112443.99C942A00E3@codespeak.net> Author: cami Date: Mon Jun 2 13:24:41 2008 New Revision: 55493 Modified: pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Log: added test for subtract_a fixed wrong flags for subtract_a Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Mon Jun 2 13:24:41 2008 @@ -519,8 +519,11 @@ def subtract_a(self, getCaller, setCaller=None): # 1 cycle - self.compare_a(getCaller) # 1 cycle - self.a.sub(getCaller.get(use_cycles=False), False) + data = getCaller.get() + #self.compare_a(data) # 1 cycle + self.compare_a_simple(data) + self.a.sub(data, False) + #self.a.sub(getCaller.get(use_cycles=False), False) def fetch_subtract_a(self): data = self.fetch() @@ -530,10 +533,10 @@ def compare_a(self, getCaller, setCaller=None): # 1 cycle - self.compare_a_simple(self.a.get() - getCaller.get()) + self.compare_a_simple(getCaller.get()) def compare_a_simple(self, s): - s = s & 0xFF + s = (self.a.get() - s) & 0xFF self.f.reset() self.f.n_flag = True self.f.z_flag_compare(s) Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Mon Jun 2 13:24:41 2008 @@ -206,13 +206,30 @@ assert_flags(cpu, z=False, n=False, h=True, c=True) def test_add_sp(): - py.test.skip("not yet implemented") cpu = get_cpu() + cpu.f.set(0x00) + for i in range(0, 0x7F): + cpu.sp.set(0x00) + prepare_for_fetch(cpu, i); + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == i + assert_flags(cpu, z=False, n=False, h=False, c=False) + + for i in range(1, 0x7F): + cpu.sp.set(0xFF) + prepare_for_fetch(cpu, 0xFF - i+1); + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0xFF - i + assert_flags(cpu, z=False, n=False, h=False, c=False) + +def test_add_sp_cary_flags(): + cpu = get_cpu() + py.test.skip("test not yet implemented") def test_and_a(): cpu = get_cpu() cpu.f.set(0xFF) - cpu.a.set(0xFF) + cpu.sp.set(0xFF) method_value_call(cpu, CPU.and_a, 0x00) assert cpu.a.get() == 0x00 assert_flags(cpu, z=True, n=False, h=True, c=False) @@ -811,7 +828,39 @@ # FIXME add separated Test for each flag - +def test_subtract_a(): + cpu = get_cpu() + cpu.f.set(0xFF) + cpu.a.set(0xFF) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0xFE + assert_flags(cpu, z=False, n=True, h=False, c=False) + + cpu.f.set(0x00) + cpu.a.set(0xFF) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0xFE + assert_flags(cpu, z=False, n=True, h=False, c=False) + + cpu.f.set(0xFF) + cpu.a.set(0x01) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0x00 + assert_flags(cpu, z=True, n=True, h=False, c=False) + + cpu.f.set(0xFF) + cpu.a.set(0x10) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0x0F + assert_flags(cpu, z=False, n=True, h=True, c=False) + + cpu.f.set(0xFF) + cpu.a.set(0x00) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0xFF + assert_flags(cpu, z=False, n=True, h=True, c=True) + + def test_swap(): cpu = get_cpu() cpu.f.set(0xFF) From afa at codespeak.net Mon Jun 2 14:35:31 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 2 Jun 2008 14:35:31 +0200 (CEST) Subject: [pypy-svn] r55494 - pypy/branch/build-external/pypy/module/zipimport Message-ID: <20080602123531.A48692A018A@codespeak.net> Author: afa Date: Mon Jun 2 14:35:29 2008 New Revision: 55494 Modified: pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py Log: Translation fix Modified: pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py ============================================================================== --- pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py (original) +++ pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py Mon Jun 2 14:35:29 2008 @@ -322,7 +322,7 @@ except OSError: # back up one path element pos = filename.rfind('/') - if pos == -1: + if pos < 0: break filename = filename[:pos] continue From tverwaes at codespeak.net Mon Jun 2 15:26:36 2008 From: tverwaes at codespeak.net (tverwaes at codespeak.net) Date: Mon, 2 Jun 2008 15:26:36 +0200 (CEST) Subject: [pypy-svn] r55495 - pypy/dist/pypy/lang/gameboy Message-ID: <20080602132636.510612D8001@codespeak.net> Author: tverwaes Date: Mon Jun 2 15:26:32 2008 New Revision: 55495 Modified: pypy/dist/pypy/lang/gameboy/constants.py Log: removing java end-comments Modified: pypy/dist/pypy/lang/gameboy/constants.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/constants.py (original) +++ pypy/dist/pypy/lang/gameboy/constants.py Mon Jun 2 15:26:32 2008 @@ -101,44 +101,44 @@ # ___________________________________________________________________________ # LCD Register Addresses -LCDC = 0xFF40 # LCD Control */ -STAT = 0xFF41 # LCD Status */ -SCY = 0xFF42 # BG Scroll Y (0-255) */ -SCX = 0xFF43 # BG Scroll X (0-255) */ -LY = 0xFF44 # LCDC Y-Coordinate (0-153) */ -LYC = 0xFF45 # LY Compare */ -DMA = 0xFF46 # OAM DMA Transfer */ -BGP = 0xFF47 # BG Palette Data */ -OBP0 = 0xFF48 # Object Palette 0 Data */ -OBP1 = 0xFF49 # Object Palette 1 Data */ -WY = 0xFF4A # Window Y Position (0-143) */ -WX = 0xFF4B # Window X Position (0-166) */ +LCDC = 0xFF40 # LCD Control +STAT = 0xFF41 # LCD Status +SCY = 0xFF42 # BG Scroll Y (0-255) +SCX = 0xFF43 # BG Scroll X (0-255) +LY = 0xFF44 # LCDC Y-Coordinate (0-153) +LYC = 0xFF45 # LY Compare +DMA = 0xFF46 # OAM DMA Transfer +BGP = 0xFF47 # BG Palette Data +OBP0 = 0xFF48 # Object Palette 0 Data +OBP1 = 0xFF49 # Object Palette 1 Data +WY = 0xFF4A # Window Y Position (0-143) +WX = 0xFF4B # Window X Position (0-166) # OAM Register Addresses -OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) */ +OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) OAM_SIZE = 0xA0 # Video RAM Addresses -VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) */ +VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) VRAM_SIZE = 0x2000 # VRAM Tile Data/Maps Addresses -VRAM_DATA_A = 0x0000 # 4KB Tile Data (8000..8FFF) */ -VRAM_DATA_B = 0x0800 # 4KB Tile Data (8800..97FF) */ +VRAM_DATA_A = 0x0000 # 4KB Tile Data (8000..8FFF) +VRAM_DATA_B = 0x0800 # 4KB Tile Data (8800..97FF) -VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) */ -VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) */ +VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) +VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) #LCD Mode Durations -MODE_0_TICKS = 50 # H-Blank */ -MODE_1_TICKS = 114 # V-Blank */ +MODE_0_TICKS = 50 # H-Blank +MODE_1_TICKS = 114 # V-Blank MODE_2_TICKS = 20 # OAM#/ -MODE_3_BEGIN_TICKS = 12 # Display */ -MODE_3_END_TICKS = 32 # Display */ +MODE_3_BEGIN_TICKS = 12 # Display +MODE_3_END_TICKS = 32 # Display -MODE_1_BEGIN_TICKS = 8 # V-Blank Line 144 */ -MODE_1_END_TICKS = 1 # V-Blank Line 153 */ +MODE_1_BEGIN_TICKS = 8 # V-Blank Line 144 +MODE_1_END_TICKS = 1 # V-Blank Line 153 # Objects per Line OBJECTS_PER_LINE = 10 @@ -201,31 +201,31 @@ SOUND_CLOCK = 256 # Sound Register Addresses -NR10 = 0xFF10 # AUD1SWEEP */ -NR11 = 0xFF11 # AUD1LEN */ -NR12 = 0xFF12 # AUD1ENV */ -NR13 = 0xFF13 # AUD1LOW */ -NR14 = 0xFF14 # AUD1HIGH */ - -NR21 = 0xFF16 # AUD2LEN */ -NR22 = 0xFF17 # AUD2ENV */ -NR23 = 0xFF18 # AUD2LOW */ -NR24 = 0xFF19 # AUD2HIGH */ - -NR30 = 0xFF1A # AUD3ENA */ -NR31 = 0xFF1B # AUD3LEN */ -NR32 = 0xFF1C # AUD3LEVEL */ -NR33 = 0xFF1D # AUD3LOW */ -NR34 = 0xFF1E # AUD3HIGH */ - -NR41 = 0xFF20 # AUD4LEN */ -NR42 = 0xFF21 # AUD4ENV */ -NR43 = 0xFF22 # AUD4POLY */ -NR44 = 0xFF23 # AUD4GO */ - -NR50 = 0xFF24 # AUDVOL */ -NR51 = 0xFF25 # AUDTERM */ -NR52 = 0xFF26 # AUDENA */ +NR10 = 0xFF10 # AUD1SWEEP +NR11 = 0xFF11 # AUD1LEN +NR12 = 0xFF12 # AUD1ENV +NR13 = 0xFF13 # AUD1LOW +NR14 = 0xFF14 # AUD1HIGH + +NR21 = 0xFF16 # AUD2LEN +NR22 = 0xFF17 # AUD2ENV +NR23 = 0xFF18 # AUD2LOW +NR24 = 0xFF19 # AUD2HIGH + +NR30 = 0xFF1A # AUD3ENA +NR31 = 0xFF1B # AUD3LEN +NR32 = 0xFF1C # AUD3LEVEL +NR33 = 0xFF1D # AUD3LOW +NR34 = 0xFF1E # AUD3HIGH + +NR41 = 0xFF20 # AUD4LEN +NR42 = 0xFF21 # AUD4ENV +NR43 = 0xFF22 # AUD4POLY +NR44 = 0xFF23 # AUD4GO + +NR50 = 0xFF24 # AUDVOL +NR51 = 0xFF25 # AUDTERM +NR52 = 0xFF26 # AUDENA AUD3WAVERAM = 0xFF30 From tverwaes at codespeak.net Mon Jun 2 15:40:56 2008 From: tverwaes at codespeak.net (tverwaes at codespeak.net) Date: Mon, 2 Jun 2008 15:40:56 +0200 (CEST) Subject: [pypy-svn] r55496 - pypy/dist/pypy/lang/gameboy Message-ID: <20080602134056.7881C2A0184@codespeak.net> Author: tverwaes Date: Mon Jun 2 15:40:53 2008 New Revision: 55496 Modified: pypy/dist/pypy/lang/gameboy/video.py Log: removing constants. Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Mon Jun 2 15:40:53 2008 @@ -53,7 +53,7 @@ value += int(self.h_blank_interrupt) << 6 value += int(self.oam_interrupt) << 5 value += int(self.h_blank_interrupt) << 4 - value += int(self.vblank_interrupt) << 3 + value += int(self.vblank_interrupt) << 3 value += int(self.coincidence_flag) << 2 value += self.mode & 0x03 return value @@ -633,10 +633,10 @@ def update_palette(self): if not self.dirty: return - # bit 4/0 = constants.BG color, - # bit 5/1 = constants.OBJ color, - # bit 2 = constants.OBJ palette, - # bit 3 = constants.OBJ priority + # bit 4/0 = BG color, + # bit 5/1 = OBJ color, + # bit 2 = OBJ palette, + # bit 3 = OBJ priority for pattern in range(0, 64): #color if (pattern & 0x22) == 0 or ((pattern & 0x08) != 0 and \ @@ -679,4 +679,4 @@ def update_display(self): self.clear_pixels() - \ No newline at end of file + From afa at codespeak.net Mon Jun 2 16:00:58 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 2 Jun 2008 16:00:58 +0200 (CEST) Subject: [pypy-svn] r55497 - in pypy/branch/build-external/pypy/module/__builtin__: . test Message-ID: <20080602140058.C40562A805E@codespeak.net> Author: afa Date: Mon Jun 2 16:00:55 2008 New Revision: 55497 Modified: pypy/branch/build-external/pypy/module/__builtin__/importing.py pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py Log: Properly populate sys.path_importer_cache: when a zip file was in front of sys.path, all remaining entries were filled with the same zipimporter... Modified: pypy/branch/build-external/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/importing.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/importing.py Mon Jun 2 16:00:55 2008 @@ -584,8 +584,8 @@ path = sys.path path_hooks = sys.path_hooks importer_cache = sys.path_importer_cache - importer = None for p in path: + importer = None if importer_cache.get(p,None): importer = importer_cache.get(p) else: Modified: pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py Mon Jun 2 16:00:55 2008 @@ -533,6 +533,31 @@ sys.meta_path.append(Importer()) import datetime assert len(tried_imports) == 1 - tried_imports[0][0] == "datetime" + assert tried_imports[0][0] == "datetime" finally: sys.meta_path.pop() + + def test_importer_cache(self): + class FooImporter(object): + def __init__(self, name): + if not name.startswith("foo_"): + raise ImportError + def find_module(self, fullname, path=None): + return None + + import sys + sys.path_hooks.append(FooImporter) + sys.path.insert(0, "foo_something") + try: + import datetime + finally: + sys.path_hooks.pop() + sys.path.pop(0) + + cache = sys.path_importer_cache + assert isinstance(cache['foo_something'], FooImporter) + for path, importer in sys.path_importer_cache.items(): + if path == 'foo_something': + assert isinstance(importer, FooImporter) + else: + assert importer is None From afa at codespeak.net Mon Jun 2 16:59:11 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 2 Jun 2008 16:59:11 +0200 (CEST) Subject: [pypy-svn] r55500 - in pypy/branch/build-external/pypy/translator: c tool Message-ID: <20080602145911.4CB2E2A0184@codespeak.net> Author: afa Date: Mon Jun 2 16:59:08 2008 New Revision: 55500 Modified: pypy/branch/build-external/pypy/translator/c/gc.py pypy/branch/build-external/pypy/translator/c/genc.py pypy/branch/build-external/pypy/translator/tool/cbuild.py Log: pypy can compile boehm-gc from sources on Linux Modified: pypy/branch/build-external/pypy/translator/c/gc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/c/gc.py (original) +++ pypy/branch/build-external/pypy/translator/c/gc.py Mon Jun 2 16:59:08 2008 @@ -196,12 +196,23 @@ if gc_home.check(dir=True): from pypy.tool.udir import udir udir.join('gc', 'gc.h').ensure() - udir.join('gc', 'gc.h').write('#include "%s/include/gc.h"' % gc_home) + udir.join('gc', 'gc.h').write('#include "%s/include/gc.h"\n' % gc_home) + + if sys.platform == 'linux2': + ccflags = ['-D_REENTRANT', '-DGC_LINUX_THREADS', '-DTHREAD_LOCAL_ALLOC'] + libraries = [] + elif sys.platform == 'win32': + ccflags = ['-DGC_WIN32_THREADS', '-DGC_NOT_DLL'] + libraries = ['user32'] + + if sys.platform != "win32": + # GC_REDIRECT_TO_LOCAL is not supported on Win32 by gc6.8 + ccflags.append('-DGC_REDIRECT_TO_LOCAL') gc_eci = ExternalCompilationInfo( include_dirs=[gc_home.join('include')], - compile_extra=['-DGC_WIN32_THREADS', '-DGC_NOT_DLL'], - libraries=['user32'], + compile_extra=ccflags + ['-DSILENT'], + libraries=libraries, ) cs = CompilationSet(gc_eci, @@ -214,13 +225,15 @@ 'misc.c', 'os_dep.c', 'mach_dep.c', 'dyn_load.c', 'win32_threads.c', + 'pthread_support.c', 'pthread_stop_world.c', + 'specific.c', ]]) eci = ExternalCompilationInfo( include_dirs=[udir], - compile_extra=['-DGC_WIN32_THREADS', '-DGC_NOT_DLL'], + compile_extra=ccflags, extra_objects=cs.compile_objects(), - libraries=['user32'], + libraries=libraries, ) else: @@ -238,12 +251,6 @@ def pre_pre_gc_code(self): for line in BasicGcPolicy.pre_pre_gc_code(self): yield line - if sys.platform == "linux2": - yield "#define _REENTRANT 1" - yield "#define GC_LINUX_THREADS 1" - if sys.platform != "win32": - # GC_REDIRECT_TO_LOCAL is not supported on Win32 by gc6.8 - yield "#define GC_REDIRECT_TO_LOCAL 1" yield '#include ' yield '#define USING_BOEHM_GC' Modified: pypy/branch/build-external/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/c/genc.py (original) +++ pypy/branch/build-external/pypy/translator/c/genc.py Mon Jun 2 16:59:08 2008 @@ -827,6 +827,7 @@ f = targetdir.join('setup.py').open('w') include_dirs = eci.include_dirs library_dirs = eci.library_dirs + extra_objects = eci.extra_objects libraries = eci.libraries f.write(SETUP_PY % locals()) f.close() @@ -850,6 +851,7 @@ ext_modules = [Extension(name = "%(modulename)s", sources = ["%(modulename)s.c"], extra_compile_args = extra_compile_args, + extra_objects = %(extra_objects)s, include_dirs = (PYPY_INCLUDE_DIR,) + %(include_dirs)r, library_dirs = %(library_dirs)r, libraries = %(libraries)r)]) Modified: pypy/branch/build-external/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/build-external/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/build-external/pypy/translator/tool/cbuild.py Mon Jun 2 16:59:08 2008 @@ -289,11 +289,16 @@ files = [py.path.local(f).relto(udir) for f in cs.files] files = [str(f) for f in cs.files] + if sys.platform == 'win32': + ccflags = [] + else: + ccflags = ['-fPIC'] # XXX + old = udir.chdir() try: objects = compiler.compile( files, - extra_preargs=list(self.eci.compile_extra), + extra_preargs=list(self.eci.compile_extra) + ccflags, include_dirs=self.eci.include_dirs, ) objects = [str(py.path.local(o)) for o in objects] From arigo at codespeak.net Mon Jun 2 20:04:40 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 2 Jun 2008 20:04:40 +0200 (CEST) Subject: [pypy-svn] r55501 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20080602180440.B6F81168419@codespeak.net> Author: arigo Date: Mon Jun 2 20:04:33 2008 New Revision: 55501 Modified: pypy/dist/pypy/objspace/std/test/test_unicodeobject.py pypy/dist/pypy/objspace/std/unicodetype.py Log: Fix test, add more tests. Modified: pypy/dist/pypy/objspace/std/test/test_unicodeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_unicodeobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_unicodeobject.py Mon Jun 2 20:04:33 2008 @@ -262,6 +262,11 @@ assert unicode(None) == u'None' assert unicode(123) == u'123' assert unicode([2, 3]) == u'[2, 3]' + class U(unicode): + pass + assert unicode(U()).__class__ is unicode + assert U(u'test') == u'test' + assert U(u'test').__class__ is U def test_call_unicode(self): skip("does not work") @@ -605,7 +610,6 @@ _test_concat(unicode, str) # uses hack in descroperation.binop_impl() def test_returns_subclass(self): - skip("Failing") class X(unicode): pass Modified: pypy/dist/pypy/objspace/std/unicodetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/unicodetype.py (original) +++ pypy/dist/pypy/objspace/std/unicodetype.py Mon Jun 2 20:04:33 2008 @@ -251,25 +251,25 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.ropeunicodeobject import W_RopeUnicodeObject w_obj = w_string - w_obj_type = space.type(w_obj) encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) - if space.is_w(w_obj_type, space.w_unicode): + if space.is_true(space.isinstance(w_obj, space.w_unicode)): if encoding is not None or errors is not None: raise OperationError(space.w_TypeError, space.wrap('decoding Unicode is not supported')) - if space.is_w(w_unicodetype, space.w_unicode): - return w_obj w_value = w_obj - elif encoding is None and errors is None: - if space.is_true(space.isinstance(w_obj, space.w_str)): - w_value = unicode_from_string(space, w_obj) - elif space.is_true(space.isinstance(w_obj, space.w_unicode)): - w_value = w_obj - else: - w_value = unicode_from_object(space, w_obj) else: - w_value = unicode_from_encoded_object(space, w_obj, encoding, errors) + if encoding is None and errors is None: + if space.is_true(space.isinstance(w_obj, space.w_str)): + w_value = unicode_from_string(space, w_obj) + else: + w_value = unicode_from_object(space, w_obj) + else: + w_value = unicode_from_encoded_object(space, w_obj, + encoding, errors) + if space.is_w(w_unicodetype, space.w_unicode): + return w_value + if space.config.objspace.std.withropeunicode: assert isinstance(w_value, W_RopeUnicodeObject) w_newobj = space.allocate_instance(W_RopeUnicodeObject, w_unicodetype) From cami at codespeak.net Mon Jun 2 22:25:50 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Mon, 2 Jun 2008 22:25:50 +0200 (CEST) Subject: [pypy-svn] r55507 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080602202550.95025168074@codespeak.net> Author: cami Date: Mon Jun 2 22:25:47 2008 New Revision: 55507 Added: pypy/dist/pypy/lang/gameboy/gameboy_implementation.py - copied unchanged from r55500, pypy/dist/pypy/lang/gameboy/gameboyImplementation.py Removed: pypy/dist/pypy/lang/gameboy/gameboyImplementation.py Modified: pypy/dist/pypy/lang/gameboy/constants.py pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/gameboy.py pypy/dist/pypy/lang/gameboy/gameboyTest.py pypy/dist/pypy/lang/gameboy/test/test_timer.py pypy/dist/pypy/lang/gameboy/timer.py pypy/dist/pypy/lang/gameboy/video.py Log: renamed gameboyImplementation package with use of underscore extenede timer tests tried to refactor timer_emulate_divide method Modified: pypy/dist/pypy/lang/gameboy/constants.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/constants.py (original) +++ pypy/dist/pypy/lang/gameboy/constants.py Mon Jun 2 22:25:47 2008 @@ -34,7 +34,7 @@ TYPE_MBC5_RAM_BATTERY = 0x1B TYPE_MBC5_RUMBLE = 0x1C -TYPE_MBC5_RUMBLE_RAM = 0x1D +TYPE_MBC5_RUMBLE_RAM = 0x1D TYPE_MBC5_RUMBLE_RAM_BATTERY = 0x1E TYPE_HUC3_RTC_RAM = 0xFE @@ -157,11 +157,11 @@ # ___________________________________________________________________________ # Joypad Registers P+ -JOYP = 0xFF00 +JOYP = 0xFF00 # Joypad Poll Speed (64 Hz) -JOYPAD_CLOCK = GAMEBOY_CLOCK >> 6 +JOYPAD_CLOCK = GAMEBOY_CLOCK >> 6 BUTTON_DOWN = 0x08 Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Mon Jun 2 22:25:47 2008 @@ -117,7 +117,7 @@ def __init__(self, cpu, reset_value): assert isinstance(cpu, CPU) - self.cpu = cpu + self.cpu = cpu self.reset_value = reset_value self.reset() @@ -141,7 +141,7 @@ self.lower = 0x00 def get(self, use_cycles=True): - value = 0 + value = 0 value += (int(self.c_flag) << 4) value += (int(self.h_flag) << 5) value += (int(self.n_flag) << 6) @@ -153,7 +153,7 @@ self.h_flag = bool(value & (1 << 5)) self.n_flag = bool(value & (1 << 6)) self.z_flag = bool(value & (1 << 7)) - self.lower = value & 0x0F + self.lower = value & 0x0F if use_cycles: self.cpu.cycles -= 1 @@ -574,12 +574,6 @@ # DEC rr register.dec() -# def inc_double_register(self, doubleRegister): -# doubleRegister.set((doubleRegister.get() + 1) & 0xFF) -# -# def dec_double_register(self, doubleRegister): -# doubleRegister.set((doubleRegister.get() - 1) & 0xFF) - def inc(self, getCaller, setCaller): # 1 cycle data = (getCaller.get() + 1) & 0xFF @@ -910,7 +904,7 @@ def disable_interrups(self): # DI/EI 1 cycle - self.ime = False + self.ime = False self.cycles -= 1 def enable_interrupts(self): Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Mon Jun 2 22:25:47 2008 @@ -81,9 +81,11 @@ #self.draw_logo() def get_cycles(self): - return min(min(min(min( self.video.get_cycles(), self.serial.get_cycles()), - self.timer.get_cycles()), self.sound.get_cycles()), - self.joypad.get_cycles()) + return min(min(min(min( self.video.get_cycles(), + self.serial.get_cycles()), + self.timer.get_cycles()), + self.sound.get_cycles()), + self.joypad.get_cycles()) def emulate(self, ticks): while ticks > 0: @@ -185,11 +187,9 @@ pattern0 = ((bits >> 0) & 0x80) + ((bits >> 1) & 0x60) + \ ((bits >> 2) & 0x18) + ((bits >> 3) & 0x06) + \ ((bits >> 4) & 0x01) - pattern1 = ((bits << 4) & 0x80) + ((bits << 3) & 0x60) + \ ((bits << 2) & 0x18) + ((bits << 1) & 0x06) + \ ((bits << 0) & 0x01) - self.video.write(0x8010 + (index << 3), pattern0) self.video.write(0x8012 + (index << 3), pattern0) self.video.write(0x8014 + (index << 3), pattern1) Modified: pypy/dist/pypy/lang/gameboy/gameboyTest.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboyTest.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboyTest.py Mon Jun 2 22:25:47 2008 @@ -1,4 +1,4 @@ -from pypy.lang.gameboy.gameboyImplementation import * +from pypy.lang.gameboy.gameboy_implementation import * import sys from AppKit import NSApplication Modified: pypy/dist/pypy/lang/gameboy/test/test_timer.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_timer.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_timer.py Mon Jun 2 22:25:47 2008 @@ -85,38 +85,129 @@ timer.timer_cycles = value assert timer.get_cycles() == timer.timer_cycles -def test_emulate_divider_normal(): +def test_emulate_divider(): timer = get_timer() - value = 2 - timer.timer_cycles = 0 - timer.emulate_timer(value) - -def test_test_emulate_divider_zero(): - timer = get_timer() - value = 2 - timer.timer_cycles = value - timer.emulate_timer(value) - assert timer.timer_cycles == value + timer.divider_cycles = 10 + timer.div = 1 + timer.emulate_divider(2) + assert timer.div == 1 + assert timer.divider_cycles == 8 + +def test_test_emulate_divider_below_zero(): + timer = get_timer() + timer.divider_cycles = 0 + timer.div = 1 + timer.emulate_divider(2) + assert timer.divider_cycles == constants.DIV_CLOCK - 2 + assert timer.div == 2 + + timer.divider_cycles = 0 + timer.div = 1 + timer.emulate_divider(0) + assert timer.divider_cycles == constants.DIV_CLOCK + assert timer.div == 2 + + timer.divider_cycles = 0 + timer.div = 0xFF + timer.emulate_divider(2) + assert timer.divider_cycles == constants.DIV_CLOCK - 2 + assert timer.div == 0 + + timer.divider_cycles = 0 + timer.div = 0 + timer.emulate_divider(2*constants.DIV_CLOCK) + assert timer.divider_cycles == constants.DIV_CLOCK + assert timer.div == 3 def test_emulate_timer_tac_return(): timer = get_timer() - timer.tac = 0 + timer.tac = 0 timer.timer_cycles = -10 - cycles = timer.timer_cycles + timer.tima = 3 timer.emulate_timer(10) - assert timer.timer_cycles == cycles + assert timer.timer_cycles == -10 + assert timer.tima == 3 def test_emulate_timer_timer_cycles_return(): timer = get_timer() - timer.tac = 0x04 - value = 10 - timer.timer_cycles = value+1 - cycles = timer.timer_cycles - timer.emulate_timer(value) + timer.tac = 0x04 + timer.timer_cycles = 11 + cycles = timer.timer_cycles + timer.emulate_timer(10) assert timer.timer_cycles == 1 +def test_emulate_timer_timer_cycles_tima(): timer = get_timer() - timer.tac = 0x04 + timer.tac = 0x04 + timer.tima = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.tima == 3 + assert timer.timer_cycles == 5 + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = 5 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.tima == 2+5 + assert timer.timer_cycles == 5 + +def test_emulate_timer_timer_cycles_tima_single_0_pass(): + timer = get_timer() + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.tima == 2 + assert timer.timer_cycles == 5 + + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = 1 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.tima == 2+1 + assert timer.timer_cycles == 5 + + +def test_emulate_timer_timer_cycles_tima_mutli_0_pass(): + timer = get_timer() + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = 0 + timer.timer_cycles = 0 + timer.timer_clock = 1 + # emulate 0xFF + 1+1 times => 2 zero passes + timer.emulate_timer(0xFF+1) + assert timer.tima == 0 + assert timer.timer_cycles == 1 + + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = 1 + timer.timer_cycles = 0 + timer.timer_clock = 1 + # emulate 0xFF + 1+1 times => 2 zero passes + timer.emulate_timer(0xFF+1) + assert timer.tima == 2*1 + assert timer.timer_cycles == 1 + + # emulate n zero passes + for i in range(1,10): + timer.tac = 0x04 + timer.tima = 0xFF + timer.tma = i + timer.timer_cycles = 0 + timer.timer_clock = 1 + timer.emulate_timer((0xFF+1)*(i-1)) + assert timer.tima == i*i + assert timer.timer_cycles == 1 + def test_emulate_timer_interrupt(): Modified: pypy/dist/pypy/lang/gameboy/timer.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/timer.py (original) +++ pypy/dist/pypy/lang/gameboy/timer.py Mon Jun 2 22:25:47 2008 @@ -9,6 +9,7 @@ from math import ceil from pypy.lang.gameboy.ram import iMemory import time +import math class Timer(iMemory): @@ -91,9 +92,9 @@ self.divider_cycles -= ticks if self.divider_cycles > 0: return - while self.divider_cycles <= 0: - self.div = (self.div + 1) & 0xFF; - self.divider_cycles += constants.DIV_CLOCK; + count = int(math.ceil(-self.divider_cycles / constants.DIV_CLOCK)+1) + self.divider_cycles += count*constants.DIV_CLOCK + self.div = (self.div + count) % (0xFF+1); def emulate_timer(self, ticks): if (self.tac & 0x04) == 0: @@ -105,7 +106,21 @@ if self.tima == 0x00: self.tima = self.tma self.interrupt.raise_interrupt(constants.TIMER) - + + #def emulate_timer(self, ticks): + # if (self.tac & 0x04) == 0: + # return + # self.timer_cycles -= ticks + # if self.timer_cycles > 0: return + # count = int(math.ceil(-self.timer_cycles / self.timer_clock)) + 1 + # self.timer_cycles += self.timer_clock*count + # # check for zero pass + # if (self.tima + count) > 0xFF: + # self.interrupt.raise_interrupt(constants.TIMER) + # zero_passes = math.ceil(self.tima / count) + # self.tima = (self.tma + count - zero_passes ) % (0xFF +1) + # else: + # self.tima = (self.tima + count) % (0xFF +1) # CLOCK DRIVER ----------------------------------------------------------------- class Clock(object): Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Mon Jun 2 22:25:47 2008 @@ -33,12 +33,22 @@ # ----------------------------------------------------------------------------- def VideoStatus(object): + # used for enabled or disabled window or background + # Bit 7 - LCD Display Enable (0=Off, 1=On) + # Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) + # Bit 5 - Window Display Enable (0=Off, 1=On) + # Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF) + # Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) + # Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16) + # Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On) + # Bit 0 - BG Display (for CGB see below) (0=Off, 1=On) + def __init__(self, video): self.video = video self.reset() def reset(self): - self.mode = False + self.mode = 0x02 self.lyc_ly_coincidence = False self.h_blank_interrupt = False self.oam_interrupt = False @@ -65,13 +75,6 @@ # ----------------------------------------------------------------------------- class Video(iMemory): - #frames = 0 - #frame_skip = 0 - - # Line Buffer, OAM Cache and Color Palette - #line = []#= new int[8 + 160 + 8] - #objects = []#= new int[OBJECTS_PER_LINE] - #palette = []#= new int[1024] def __init__(self, video_driver, interrupt, memory): assert isinstance(video_driver, VideoDriver) @@ -88,15 +91,6 @@ def reset(self): self.cycles = constants.MODE_2_TICKS - # used for enabled or disabled window or background - # Bit 7 - LCD Display Enable (0=Off, 1=On) - # Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) - # Bit 5 - Window Display Enable (0=Off, 1=On) - # Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF) - # Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) - # Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16) - # Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On) - # Bit 0 - BG Display (for CGB see below) (0=Off, 1=On) self.control = 0x91 self.stat = 2 self.line_y = 0 @@ -403,8 +397,8 @@ self.emulate_vblank_other() def emulate_vblank_vblank(self): - self.vblank = False - self.stat = (self.stat & 0xFC) | 0x01 + self.vblank = False + self.stat = (self.stat & 0xFC) | 0x01 self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS # V-Blank interrupt if (self.stat & 0x10) != 0: @@ -413,7 +407,7 @@ self.interrupt.raise_interrupt(constants.VBLANK) def emulate_vblank_first_y_line(self): - self.stat = (self.stat & 0xFC) | 0x02 + self.stat = (self.stat & 0xFC) | 0x02 self.cycles += constants.MODE_2_TICKS #OAM interrupt if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: @@ -421,8 +415,8 @@ def emulate_vblank_other(self): if self.line_y < 153: - self.line_y+=1 - self.stat = (self.stat & 0xFC) | 0x01 + self.line_y += 1 + self.stat = (self.stat & 0xFC) | 0x01 if self.line_y == 153: self.cycles += constants.MODE_1_END_TICKS else: @@ -462,9 +456,9 @@ self.line[x] = 0x00 def draw_background(self): - y = (self.scroll_y + self.line_y) & 0xFF - x = self.scroll_x & 0xFF - tileMap = constants.VRAM_MAP_A + y = (self.scroll_y + self.line_y) & 0xFF + x = self.scroll_x & 0xFF + tileMap = constants.VRAM_MAP_A if (self.control & 0x08) != 0: tileMap = constants.VRAM_MAP_B tileData = constants.VRAM_DATA_B @@ -513,9 +507,7 @@ continue tile = self.oam[offset + 2] & 0xFF flags = self.oam[offset + 3] & 0xFF - y = self.line_y - y + 16 - if ((self.control & 0x04) != 0): # 8x16 tile size if (y < 0 or y > 15): From antocuni at codespeak.net Tue Jun 3 14:45:02 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 14:45:02 +0200 (CEST) Subject: [pypy-svn] r55514 - pypy/branch/oo-jit/pypy/jit/codegen/cli Message-ID: <20080603124502.B4ABB168551@codespeak.net> Author: antocuni Date: Tue Jun 3 14:45:00 2008 New Revision: 55514 Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py Log: add a new operations that prints a string, useful when debugging the backend Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py Tue Jun 3 14:45:00 2008 @@ -194,6 +194,19 @@ self.gv_value.load(self.builder) self.builder.graphbuilder.il.Emit(OpCodes.Stfld, self.fieldinfo) + +class WriteLine(Operation): + + def __init__(self, builder, message): + self.builder = builder + self.message = message + + def restype(self): + return None + + def emit(self): + self.builder.graphbuilder.il.EmitWriteLine(self.message) + def opcode2attrname(opcode): if opcode == 'ldc.r8 0': return 'Ldc_R8, 0' # XXX this is a hack From antocuni at codespeak.net Tue Jun 3 14:47:20 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 14:47:20 +0200 (CEST) Subject: [pypy-svn] r55515 - in pypy/branch/oo-jit/pypy/jit: codegen/llgraph rainbow rainbow/test timeshifter Message-ID: <20080603124720.74E06168551@codespeak.net> Author: antocuni Date: Tue Jun 3 14:47:18 2008 New Revision: 55515 Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Log: introduce a new rainbow bytecode for oosend whose receiver is a virtual struct, and generate a residual oosend in the general case. test_portal.test_method_call_nonpromote passes Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py Tue Jun 3 14:47:18 2008 @@ -376,6 +376,13 @@ vars_gv = [gv_ptr, gv_fieldname] return genop(block, "getfield", vars_gv, RESULTTYPE) +def genoosend(block, gv_OBJTYPE, args_gv, gv_RESULT_TYPE): + OBJTYPE = _from_opaque(gv_OBJTYPE).value + gv_obj = args_gv[1] + gv_obj = cast(block, gv_OBJTYPE, gv_obj.v) + args_gv[1] = gv_obj + return genop(block, "oosend", args_gv, gv_RESULT_TYPE) + def genoosetfield(block, gv_obj, gv_OBJTYPE, gv_fieldname, gv_value): v_obj = _from_opaque(gv_obj) gv_obj = cast(block, gv_OBJTYPE, gv_obj) Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py Tue Jun 3 14:47:18 2008 @@ -170,12 +170,12 @@ v = llimpl.genop(self.b, 'indirect_call', vars_gv, gv_RESULT.v) return LLVar(v) - def genop_oosend(self, (gv_methname, (ARGS_gv, gv_RESULT, _)), gv_self, args_gv): + def genop_oosend(self, (gv_TYPE, gv_methname, (ARGS_gv, gv_RESULT, _)), gv_self, args_gv): ll_assert(self.rgenop.currently_writing is self, "genop_oosend: bad currently_writing") vars_gv = [gv_methname, gv_self] vars_gv += self._cast_args_gv(ARGS_gv, args_gv) - v = llimpl.genop(self.b, 'oosend', vars_gv, gv_RESULT.v) + v = llimpl.genoosend(self.b, gv_TYPE.v, vars_gv, gv_RESULT.v) return LLVar(v) def genop_getfield(self, (gv_name, gv_PTRTYPE, gv_FIELDTYPE), gv_ptr): @@ -490,7 +490,7 @@ _, meth = TYPE._lookup(methname) METH = ootype.typeOf(meth) gv_methname = LLConst(llimpl.constFieldName(methname)) - return (gv_methname, RGenOp.sigToken(METH)) + return (gv_TYPE(TYPE), gv_methname, RGenOp.sigToken(METH)) constPrebuiltGlobal = genconst Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py Tue Jun 3 14:47:18 2008 @@ -1539,7 +1539,7 @@ return 'green', self.can_raise(spaceop) return 'oopspec', self.can_raise(spaceop) if not SELFTYPE._lookup_graphs(methname): - return 'builtin', self.can_raise(spaceop) + return 'residual', self.can_raise(spaceop) hs_self = self.hannotator.binding(spaceop.args[1]) if hs_self.is_green(): return 'direct', self.can_raise(spaceop) @@ -1767,7 +1767,7 @@ if has_result: self.register_redvar(op.result) - def handle_builtin_oosend(self, op, withexc): + def handle_residual_oosend(self, op, withexc): SELFTYPE, name, opargs = self.decompose_oosend(op) has_result = self.has_result(op) emitted_args = [] @@ -1775,29 +1775,52 @@ if v.concretetype == lltype.Void: continue emitted_args.append(self.serialize_oparg("red", v)) - self.emit("builtin_oosend") + self.emit_residual_oosend(SELFTYPE, name, emitted_args, + has_result) + if has_result: + self.register_redvar(op.result) + + def emit_residual_oosend(self, SELFTYPE, name, emitted_args, + has_result): + self.emit("residual_oosend") self.emit(len(emitted_args)) self.emit(*emitted_args) methdescindex = self.methdesc_position(SELFTYPE, name) self.emit(methdescindex) self.emit(has_result) - if has_result: - self.register_redvar(op.result) def handle_red_oosend(self, op, withexc): SELFTYPE, name, opargs = self.decompose_oosend(op) has_result = self.has_result(op) graph2tsgraph = dict(self.graphs_from(op)) self.fill_methodcodes(SELFTYPE, name, graph2tsgraph) + + emitted_args = [] + for v in op.args[1:]: + if v.concretetype == lltype.Void: + continue + emitted_args.append(self.serialize_oparg("red", v)) + + self.emit("goto_if_vstruct", emitted_args[0], + tlabel(("virtual struct oosend", op))) + self.emit_residual_oosend(SELFTYPE, name, emitted_args, + has_result) + self.emit("goto", tlabel(("after oosend", op))) + + # virtual struct case + self.emit(label(("virtual struct oosend", op))) args = graph2tsgraph.values()[0].getargs() emitted_args = self.args_of_call(op.args[1:], args) - self.emit("red_oosend") + self.emit("vstruct_oosend") self.emit(*emitted_args) methnameindex = self.string_position(name) self.emit(methnameindex) + if has_result: self.register_redvar(op.result) + self.emit(label(("after oosend", op))) + def handle_direct_oosend(self, op, withexc): SELFTYPE, name, opargs = self.decompose_oosend(op) has_result = self.has_result(op) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Tue Jun 3 14:47:18 2008 @@ -1084,10 +1084,16 @@ return rtimeshift.genptreq(self.jitstate, ptrbox1, ptrbox2, False) + @arguments("red", "jumptarget") + def opimpl_goto_if_vstruct(self, objbox, target): + if objbox.content is not None: + self.frame.pc = target + @arguments("green_varargs", "red_varargs", "string") - def opimpl_red_oosend(self, greenargs, redargs, methname): + def opimpl_vstruct_oosend(self, greenargs, redargs, methname): selfbox = redargs[0] vstruct = selfbox.content + assert vstruct is not None assert isinstance(vstruct, rcontainer.VirtualStruct), 'TODO???' bytecode = vstruct.typedesc.methodcodes[methname] self.run(self.jitstate, bytecode, greenargs, redargs, @@ -1104,8 +1110,8 @@ methdesc.green_call(self, None, greenargs) @arguments("red_varargs", "methdesc", "bool") - def opimpl_builtin_oosend(self, redargs, methdesc, has_result): - result = rtimeshift.gen_external_oosend(self.jitstate, redargs, + def opimpl_residual_oosend(self, redargs, methdesc, has_result): + result = rtimeshift.gen_residual_oosend(self.jitstate, redargs, methdesc) if has_result: self.red_result(result) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Tue Jun 3 14:47:18 2008 @@ -1035,6 +1035,15 @@ assert res == 42 self.check_insns({'direct_call': 1}) + def test_builtin_oosend_with_green_args(self): + def fn(ch1, ch2): + s = 'hello World' + ch3 = hint(ch2, concrete=True) + s = s.replace(ch1, ch3) + return s[6] + res = self.interpret(fn, ['W', 'w'], []) + assert res == 'w' + def test_residual_red_call(self): def g(x): return x+1 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Tue Jun 3 14:47:18 2008 @@ -221,11 +221,11 @@ res = self.timeshift_from_portal(ll_main, ll_function, [5], policy=P_NOVIRTUAL) assert res == 10 - self.check_insns(indirect_call=2) + self.check_method_calls(2) res = self.timeshift_from_portal(ll_main, ll_function, [0], policy=P_NOVIRTUAL) assert res == ord('2') - self.check_insns(indirect_call=2) + self.check_method_calls(2) def test_method_call_promote(self): class Base(object): @@ -627,10 +627,12 @@ class TestPortalOOType(BaseTestPortal): type_system = 'ootype' + def check_method_calls(self, n): + self.check_insns(oosend=2) + def _skip(self): py.test.skip('in progress') - test_method_call_nonpromote = _skip test_method_call_promote = _skip test_float_promote = _skip test_isinstance = _skip @@ -641,3 +643,5 @@ class TestPortalLLType(BaseTestPortal): type_system = 'lltype' + def check_method_calls(self, n): + self.check_insns(indirect_call=2) Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Tue Jun 3 14:47:18 2008 @@ -594,7 +594,7 @@ ##def ll_gvar_from_constant(jitstate, ll_value): ## return jitstate.curbuilder.rgenop.genconst(ll_value) -def gen_external_oosend(jitstate, argboxes, methdesc): +def gen_residual_oosend(jitstate, argboxes, methdesc): builder = jitstate.curbuilder selfbox = argboxes[0] gv_selfbox = selfbox.getgenvar(jitstate) From antocuni at codespeak.net Tue Jun 3 16:00:06 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 16:00:06 +0200 (CEST) Subject: [pypy-svn] r55516 - in pypy/branch/oo-jit/pypy/jit/rainbow: . test Message-ID: <20080603140006.CAB472A00DB@codespeak.net> Author: antocuni Date: Tue Jun 3 16:00:03 2008 New Revision: 55516 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Log: emit yellow_retrieve_result_as_red only just after vstruct_oosend. This fixes a bug that prevented test_greenmethod_call_nonpromote to run Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py Tue Jun 3 16:00:03 2008 @@ -1789,7 +1789,7 @@ self.emit(methdescindex) self.emit(has_result) - def handle_red_oosend(self, op, withexc): + def handle_red_or_yellow_oosend(self, op, withexc, kind): SELFTYPE, name, opargs = self.decompose_oosend(op) has_result = self.has_result(op) graph2tsgraph = dict(self.graphs_from(op)) @@ -1815,12 +1815,21 @@ self.emit(*emitted_args) methnameindex = self.string_position(name) self.emit(methnameindex) - + if kind == 'yellow': + self.emit("yellow_retrieve_result_as_red") + self.emit(self.type_position(op.result.concretetype)) + if has_result: self.register_redvar(op.result) self.emit(label(("after oosend", op))) + def handle_yellow_oosend(self, op, withexc): + return self.handle_red_or_yellow_oosend(op, withexc, 'yellow') + + def handle_red_oosend(self, op, withexc): + return self.handle_red_or_yellow_oosend(op, withexc, 'red') + def handle_direct_oosend(self, op, withexc): SELFTYPE, name, opargs = self.decompose_oosend(op) has_result = self.has_result(op) @@ -1838,10 +1847,6 @@ if has_result: self.register_redvar(op.result) - def handle_yellow_oosend(self, op, withexc): - self.handle_red_oosend(op, withexc) - self.emit("yellow_retrieve_result_as_red") - self.emit(self.type_position(op.result.concretetype)) def fill_methodcodes(self, INSTANCE, methname, graph2tsgraph): TYPES = [INSTANCE] + INSTANCE._subclasses Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Tue Jun 3 16:00:03 2008 @@ -352,7 +352,7 @@ res = self.timeshift_from_portal(ll_main, ll_function, [5], policy=P_NOVIRTUAL) assert res == 123 - self.check_insns(indirect_call=1) + self.check_method_calls(1) def test_cast_ptr_to_int(self): GCS1 = lltype.GcStruct('s1', ('x', lltype.Signed)) @@ -628,7 +628,7 @@ type_system = 'ootype' def check_method_calls(self, n): - self.check_insns(oosend=2) + self.check_insns(oosend=n) def _skip(self): py.test.skip('in progress') @@ -636,7 +636,6 @@ test_method_call_promote = _skip test_float_promote = _skip test_isinstance = _skip - test_greenmethod_call_nonpromote = _skip test_virt_obj_method_call_promote = _skip test_simple_recursive_portal_call_with_exc = _skip @@ -644,4 +643,4 @@ type_system = 'lltype' def check_method_calls(self, n): - self.check_insns(indirect_call=2) + self.check_insns(indirect_call=n) From antocuni at codespeak.net Tue Jun 3 16:45:24 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 16:45:24 +0200 (CEST) Subject: [pypy-svn] r55519 - in pypy/branch/oo-jit/pypy/jit: codegen/llgraph rainbow/test Message-ID: <20080603144524.AED8016844A@codespeak.net> Author: antocuni Date: Tue Jun 3 16:45:23 2008 New Revision: 55519 Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Log: this is a terrible hack to make test_isinstance passing. The comment in llimpl.genconst() says that it should not be used for Void constants, but it's very old (from r23049) and I'm not sure it's still up to date. Things seem to work, though. Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py Tue Jun 3 16:45:23 2008 @@ -238,6 +238,11 @@ return lltype.typeOf(result) def genconst(llvalue): + # XXX: it conflicts with the comment below :-/ + if isinstance(llvalue, lltype.LowLevelType): + v = flowmodel.Constant(llvalue) + v.concretetype = lltype.Void + return _to_opaque(v) T = lltype.typeOf(llvalue) T1 = lltype.erasedType(T) if T1 != T: @@ -256,7 +261,9 @@ return _to_opaque(c) def _generalcast(T, value): - if lltype.typeOf(value) == T: + if T is lltype.Void: + return value + elif lltype.typeOf(value) == T: return value elif isinstance(T, lltype.Ptr): return lltype.cast_pointer(T, value) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Tue Jun 3 16:45:23 2008 @@ -635,7 +635,6 @@ test_method_call_promote = _skip test_float_promote = _skip - test_isinstance = _skip test_virt_obj_method_call_promote = _skip test_simple_recursive_portal_call_with_exc = _skip From antocuni at codespeak.net Tue Jun 3 17:05:39 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 17:05:39 +0200 (CEST) Subject: [pypy-svn] r55520 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080603150539.48FDD16843D@codespeak.net> Author: antocuni Date: Tue Jun 3 17:05:38 2008 New Revision: 55520 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Log: I *love* tests that pass ouf of the box :-) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Tue Jun 3 17:05:38 2008 @@ -636,7 +636,6 @@ test_method_call_promote = _skip test_float_promote = _skip test_virt_obj_method_call_promote = _skip - test_simple_recursive_portal_call_with_exc = _skip class TestPortalLLType(BaseTestPortal): type_system = 'lltype' From antocuni at codespeak.net Tue Jun 3 17:12:22 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 17:12:22 +0200 (CEST) Subject: [pypy-svn] r55521 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080603151222.3AC3316843D@codespeak.net> Author: antocuni Date: Tue Jun 3 17:12:21 2008 New Revision: 55521 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Log: more passing tests Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Tue Jun 3 17:12:21 2008 @@ -47,7 +47,8 @@ self.check_insns(int_add=10, int_mul=0) def test_promote_after_call(self): - S = lltype.GcStruct('S', ('x', lltype.Signed)) + S = self.GcStruct('S', ('x', lltype.Signed)) + malloc = self.malloc def ll_two(k, s): if k > 5: s.x = 20 @@ -55,7 +56,7 @@ s.x = 10 def ll_function(n): hint(None, global_merge_point=True) - s = lltype.malloc(S) + s = malloc(S) ll_two(n, s) k = hint(n, promote=True) k *= 17 @@ -66,7 +67,8 @@ self.check_insns(int_mul=0, int_add=1) def test_promote_after_yellow_call(self): - S = lltype.GcStruct('S', ('x', lltype.Signed)) + S = self.GcStruct('S', ('x', lltype.Signed)) + malloc = self.malloc def ll_two(k, s): if k > 5: s.x = 20*k @@ -77,7 +79,7 @@ def ll_function(n): hint(None, global_merge_point=True) - s = lltype.malloc(S) + s = malloc(S) c = ll_two(n, s) k = hint(s.x, promote=True) k += c @@ -139,9 +141,10 @@ self.check_insns(int_add=0) def test_merge_then_promote(self): - S = lltype.GcStruct('S', ('x', lltype.Signed)) + S = self.GcStruct('S', ('x', lltype.Signed)) + malloc = self.malloc def ll_two(n): - s = lltype.malloc(S) + s = malloc(S) if n < 0: s.x = 10 else: @@ -158,12 +161,13 @@ self.check_insns(int_lt=1, int_mul=0) def test_vstruct_unfreeze(self): - S = lltype.GcStruct('S', ('x', lltype.Signed)) + S = self.GcStruct('S', ('x', lltype.Signed)) + malloc = self.malloc def ll_two(k): return (k+1)*2 def ll_function(n): hint(None, global_merge_point=True) - s = lltype.malloc(S) + s = malloc(S) s.x = n k = hint(n, promote=True) k = ll_two(k) @@ -180,7 +184,8 @@ self.check_insns(int_add=0, int_mul=0) def test_more_promotes(self): - S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + S = self.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + malloc = self.malloc def ll_two(s, i, m): if i > 4: s.x += i @@ -196,7 +201,7 @@ else: return hint(1, concrete=True) def ll_function(n, m): - s = lltype.malloc(S) + s = malloc(S) s.x = 0 s.y = 0 i = 0 @@ -275,11 +280,12 @@ hint(x.field, promote=True) return m + x.field - S = lltype.GcStruct('S', ('field', lltype.Signed), + S = self.GcStruct('S', ('field', lltype.Signed), hints={'immutable': True}) + malloc = self.malloc def struct_S(string): - s = lltype.malloc(S) + s = malloc(S) s.field = int(string) return s ll_function.convert_arguments = [struct_S, int] @@ -471,11 +477,11 @@ def skip(self): py.test.skip('in progress') - test_promote_after_call = skip - test_promote_after_yellow_call = skip - test_merge_then_promote = skip - test_vstruct_unfreeze = skip - test_more_promotes = skip + #test_promote_after_call = skip + #test_promote_after_yellow_call = skip + #test_merge_then_promote = skip + #test_vstruct_unfreeze = skip + #test_more_promotes = skip test_remembers_across_mp = skip test_virtual_list_copy = skip test_raise_result_mixup = skip From antocuni at codespeak.net Tue Jun 3 17:16:28 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 3 Jun 2008 17:16:28 +0200 (CEST) Subject: [pypy-svn] r55522 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080603151628.1E972168527@codespeak.net> Author: antocuni Date: Tue Jun 3 17:16:27 2008 New Revision: 55522 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Log: another test that passes Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Tue Jun 3 17:16:27 2008 @@ -290,7 +290,7 @@ for block in residual_graph.iterblocks(): for op in block.operations: if op.opname == 'direct_call': - f = getattr(op.args[0].value._obj, "_callable", None) + f = getattr(get_funcobj(op.args[0].value), "_callable", None) if hasattr(f, 'oopspec'): name, _ = f.oopspec.split('(', 1) oops[name] = oops.get(name, 0) + 1 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Tue Jun 3 17:16:27 2008 @@ -477,12 +477,6 @@ def skip(self): py.test.skip('in progress') - #test_promote_after_call = skip - #test_promote_after_yellow_call = skip - #test_merge_then_promote = skip - #test_vstruct_unfreeze = skip - #test_more_promotes = skip test_remembers_across_mp = skip - test_virtual_list_copy = skip test_raise_result_mixup = skip test_raise_result_mixup_some_more = skip From cami at codespeak.net Tue Jun 3 19:40:18 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Tue, 3 Jun 2008 19:40:18 +0200 (CEST) Subject: [pypy-svn] r55525 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080603174018.238B716844A@codespeak.net> Author: cami Date: Tue Jun 3 19:40:14 2008 New Revision: 55525 Added: pypy/dist/pypy/lang/gameboy/test/test_gameboy_implementaton.py Modified: pypy/dist/pypy/lang/gameboy/gameboy_implementation.py pypy/dist/pypy/lang/gameboy/joypad.py Log: added interactive test for the joypad implementation fixed a possible bug in joypad.py Modified: pypy/dist/pypy/lang/gameboy/gameboy_implementation.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy_implementation.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy_implementation.py Tue Jun 3 19:40:14 2008 @@ -32,15 +32,9 @@ def mainLoop(self): - #self.reset() try: isRunning = True - while isRunning: - while self.poll_event(): - if self.check_for_escape(): - isRunning = False - break - self.joypad_driver.update(self.event) + while isRunning and self.handle_events(): self.emulate(constants.GAMEBOY_CLOCK >> 2) #RSDL.Delay(1) finally: @@ -48,6 +42,14 @@ RSDL.Quit() return 0 + def handle_events(self): + isRunning = True + while self.poll_event(): + if self.check_for_escape(): + isRunning = False + self.joypad_driver.update(self.event) + return isRunning + def poll_event(self): ok = rffi.cast(lltype.Signed, RSDL.PollEvent(self.event)) @@ -129,11 +131,9 @@ self.last_key = rffi.getintfield(p.c_keysym, 'c_sym') def on_key_down(self): - print "press" self.toggleButton(self.get_button_handler(self.last_key), True) def on_key_up(self): - print "release" self.toggleButton(self.get_button_handler(self.last_key), False) def toggleButton(self, pressButtonFunction, enabled): @@ -142,28 +142,20 @@ def get_button_handler(self, key): if key == RSDL.K_UP: - print " up" return JoypadDriver.button_up elif key == RSDL.K_RIGHT: - print " right" return JoypadDriver.button_right elif key == RSDL.K_DOWN: - print " down" return JoypadDriver.button_down elif key == RSDL.K_LEFT: - print " left" return JoypadDriver.button_left elif key == RSDL.K_RETURN: - print " start" return JoypadDriver.button_start elif key == RSDL.K_SPACE: - print " select" return JoypadDriver.button_select elif key == RSDL.K_a: - print " A" return JoypadDriver.button_a elif key == RSDL.K_b: - print " B" return JoypadDriver.button_b return None Modified: pypy/dist/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/joypad.py Tue Jun 3 19:40:14 2008 @@ -44,9 +44,9 @@ def update(self): oldButtons = self.button_code - if self.joyp == 0x1: + if self.joyp & 0xF0 == 0x10: self.button_code = self.driver.get_button_code() - elif self.joyp == 0x2: + elif self.joyp & 0xF0 == 0x20: self.button_code = self.driver.get_direction_code() else: self.button_code = 0xF Added: pypy/dist/pypy/lang/gameboy/test/test_gameboy_implementaton.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/gameboy/test/test_gameboy_implementaton.py Tue Jun 3 19:40:14 2008 @@ -0,0 +1,75 @@ +import py +from pypy.lang.gameboy.gameboy_implementation import * +from pypy.lang.gameboy import constants + +import py, sys +from pypy import conftest + +# +# This test file is skipped unless run with "py.test --view". +# If it is run as "py.test --view -s", then it interactively asks +# for confirmation that the window looks as expected. +# + +if sys.platform == 'darwin': + from AppKit import NSApplication + NSApplication.sharedApplication() + +class TestGameBoyImplementation(object): + + def setup_method(self, meth): + if not conftest.option.view: + py.test.skip("'--view' not specified, " + "skipping tests that open a window") + self.gameboy = GameBoyImplementation() + self.is_interactive = sys.stdout.isatty() + + def check(self, msg): + if self.is_interactive: + print + answer = raw_input('Interactive test: %s - ok? [Y] ' % msg) + if answer and not answer.upper().startswith('Y'): + py.test.fail(msg) + else: + print msg + + def test_buttons(self): + for i in [("A", constants.BUTTON_A), + ("B", constants.BUTTON_B), + ("START", constants.BUTTON_START), + ("SELECT", constants.BUTTON_SELECT), + ("A and B", constants.BUTTON_A | constants.BUTTON_B),]: + print "press ", i[0] + isRunning = True + while isRunning: + while self.gameboy.poll_event(): + if self.gameboy.check_for_escape(): + isRunning = False + break + self.gameboy.joypad_driver.update(self.gameboy.event) + if self.gameboy.joypad_driver.get_button_code() == i[1]: + isRunning = False + + def test_directions(self): + for i in [("up", constants.BUTTON_UP), + ("left", constants.BUTTON_LEFT), + ("down", constants.BUTTON_DOWN), + ("right", constants.BUTTON_RIGHT), + ("down + right", constants.BUTTON_DOWN | constants.BUTTON_RIGHT)]: + print "press ", i[0] + isRunning = True + while isRunning: + while self.gameboy.poll_event(): + if self.gameboy.check_for_escape(): + isRunning = False + break + self.gameboy.joypad_driver.update(self.gameboy.event) + if self.gameboy.joypad_driver.get_direction_code() == i[1]: + isRunning = False + + + + + def teardown_method(self, meth): + RSDL.Quit() + From fijal at codespeak.net Tue Jun 3 20:57:09 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 20:57:09 +0200 (CEST) Subject: [pypy-svn] r55526 - pypy/dist/lib-python/modified-2.4.1 Message-ID: <20080603185709.C04B3168434@codespeak.net> Author: fijal Date: Tue Jun 3 20:57:07 2008 New Revision: 55526 Modified: pypy/dist/lib-python/modified-2.4.1/socket.py Log: Debatable commit. Some stuff (urllib) puts something else as socket, with no _drop there, so ignore it in that case Modified: pypy/dist/lib-python/modified-2.4.1/socket.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/socket.py (original) +++ pypy/dist/lib-python/modified-2.4.1/socket.py Tue Jun 3 20:57:07 2008 @@ -239,7 +239,8 @@ if self._sock: s = self._sock self._sock = None - s._drop() + if hasattr(s, '_drop'): + s._drop() def __del__(self): try: From fijal at codespeak.net Tue Jun 3 21:08:42 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 21:08:42 +0200 (CEST) Subject: [pypy-svn] r55529 - in pypy/dist/pypy/module/zipimport: . test Message-ID: <20080603190842.77B2B2A0152@codespeak.net> Author: fijal Date: Tue Jun 3 21:08:41 2008 New Revision: 55529 Modified: pypy/dist/pypy/module/zipimport/interp_zipimport.py pypy/dist/pypy/module/zipimport/test/test_zipimport.py Log: A test and a fix for __iter__ on zip_directory_cache Modified: pypy/dist/pypy/module/zipimport/interp_zipimport.py ============================================================================== --- pypy/dist/pypy/module/zipimport/interp_zipimport.py (original) +++ pypy/dist/pypy/module/zipimport/interp_zipimport.py Tue Jun 3 21:08:41 2008 @@ -106,6 +106,7 @@ 'zip_dict', __getitem__ = interp2app(W_ZipCache.getitem), __contains__ = interp2app(W_ZipCache.contains), + __iter__ = interp2app(W_ZipCache.iterkeys), items = interp2app(W_ZipCache.items), iteritems = interp2app(W_ZipCache.iteritems), keys = interp2app(W_ZipCache.keys), Modified: pypy/dist/pypy/module/zipimport/test/test_zipimport.py ============================================================================== --- pypy/dist/pypy/module/zipimport/test/test_zipimport.py (original) +++ pypy/dist/pypy/module/zipimport/test/test_zipimport.py Tue Jun 3 21:08:41 2008 @@ -233,6 +233,16 @@ assert archive == self.zipfile assert importer.prefix == prefix + def test_zip_directory_cache(self): + """ Check full dictionary interface + """ + import os + import zipimport + self.writefile( + self, os.sep.join(("directory", "package", "__init__.py")), "") + importer = zipimport.zipimporter(self.zipfile + "/directory") + l = [i for i in zipimport._zip_directory_cache] + assert len(l) class AppTestZipimportDeflated(AppTestZipimport): compression = ZIP_DEFLATED From fijal at codespeak.net Tue Jun 3 21:46:05 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 21:46:05 +0200 (CEST) Subject: [pypy-svn] r55530 - in pypy/branch/js-refactoring/pypy/lang/js: . test test/ecma Message-ID: <20080603194605.20EEF16844B@codespeak.net> Author: fijal Date: Tue Jun 3 21:46:02 2008 New Revision: 55530 Modified: pypy/branch/js-refactoring/pypy/lang/js/astbuilder.py pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: Revert 55476. Besides introducing new features, it also changes things in a way that broke tests. It's a bit hard to follow all changes which happened, so I'm just reverting. 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 Jun 3 21:46:02 2008 @@ -426,15 +426,7 @@ else: target = None return operations.Break(pos, target) - - def visit_continuestatement(self, node): - pos = self.get_pos(node) - if len(node.children) > 0: - target = self.dispatch(node.children[0]) - else: - target = None - return operations.Continue(pos, target) - + def visit_returnstatement(self, node): pos = self.get_pos(node) if len(node.children) > 0: @@ -471,7 +463,7 @@ def visit_withstatement(self, node): pos = self.get_pos(node) - withpart = self.dispatch(node.children[0]) + identifier = self.dispatch(node.children[0]) body = self.dispatch(node.children[1]) - return operations.With(pos, withpart, body) - + return operations.With(pos, identifier, body) + Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Tue Jun 3 21:46:02 2008 @@ -11,7 +11,7 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.streamio import open_file_as_stream from pypy.lang.js.jscode import JsCode -from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf, r_uint +from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf ASTBUILDER = ASTBuilder() @@ -307,25 +307,15 @@ raise JsTypeError('Wrong type') return W_String(this.Value.ToString(ctx)) + class W_NumberValueToString(W_ValueToString): mytype = 'number' class W_BooleanValueToString(W_ValueToString): mytype = 'boolean' -class W_StringValueToString(W_NewBuiltin): - "this is the toString function for objects with Value" - def Call(self, ctx, args=[], this=None): - if this.type() != 'string': - raise JsTypeError('Wrong type') - return this - -class W_StringValueOf(W_NewBuiltin): - "this is the toString function for objects with Value" - def Call(self, ctx, args=[], this=None): - if this.type() != 'string': - raise JsTypeError('Wrong type') - return this +class W_StringValueToString(W_ValueToString): + mytype = 'string' def get_value_of(type, ctx): @@ -408,7 +398,6 @@ return W_String(common_join(ctx, this, sep=',')) class W_ArrayJoin(W_NewBuiltin): - length = 1 def Call(self, ctx, args=[], this=None): if len(args) >= 1 and not args[0] is w_Undefined: sep = args[0].ToString(ctx) @@ -417,28 +406,6 @@ return W_String(common_join(ctx, this, sep)) -class W_ArrayReverse(W_NewBuiltin): - length = 0 - def Call(self, ctx, args=[], this=None): - r2 = this.Get(ctx, 'length').ToUInt32(ctx) - k = r_uint(0) - r3 = r_uint(math.floor( float(r2)/2.0 )) - if r3 == k: - return this - - while k < r3: - r6 = r2 - k - 1 - r7 = str(k) - r8 = str(r6) - - r9 = this.Get(ctx, r7) - r10 = this.Get(ctx, r8) - - this.Put(ctx, r7, r10) - this.Put(ctx, r8, r9) - k += 1 - - return this class W_DateFake(W_NewBuiltin): # XXX This is temporary def Call(self, ctx, args=[], this=None): @@ -466,15 +433,13 @@ w_Function = W_Function(ctx, Class='Function', Prototype=w_ObjPrototype) + w_Global.Put(ctx, 'Function', w_Function) - w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon) w_Object = W_ObjectObject('Object', w_Function) w_Object.Put(ctx, 'prototype', w_ObjPrototype, flags = allon) w_Global.Put(ctx, 'Object', w_Object) - w_Global.Prototype = w_ObjPrototype - w_FncPrototype = w_Function.Call(ctx, this=w_Function) w_Function.Put(ctx, 'prototype', w_FncPrototype, flags = allon) w_Function.Put(ctx, 'constructor', w_Function) @@ -485,7 +450,7 @@ put_values(w_ObjPrototype, { 'constructor': w_Object, - '__proto__': w_FncPrototype, + '__proto__': w_Null, 'toString': toString, 'toLocaleString': toString, 'valueOf': W_ValueOf(ctx), @@ -496,12 +461,11 @@ #properties of the function prototype put_values(w_FncPrototype, { - 'constructor': w_Function, - '__proto__': w_FncPrototype, + 'constructor': w_FncPrototype, + '__proto__': w_ObjPrototype, 'toString': W_FToString(ctx), 'apply': W_Apply(ctx), - 'call': W_Call(ctx), - 'arguments': w_Null, + 'call': W_Call(ctx), }) w_Boolean = W_BooleanObject('Boolean', w_FncPrototype) @@ -564,7 +528,7 @@ 'constructor': w_FncPrototype, '__proto__': w_StrPrototype, 'toString': W_StringValueToString(ctx), - 'valueOf': W_StringValueOf(ctx), + 'valueOf': get_value_of('String', ctx), 'charAt': W_CharAt(ctx), 'concat': W_Concat(ctx), 'indexOf': W_IndexOf(ctx), @@ -572,7 +536,6 @@ }) w_String.Put(ctx, 'prototype', w_StrPrototype) - w_String.Put(ctx, 'fromCharCode', w_String) #dummy w_Global.Put(ctx, 'String', w_String) w_Array = W_ArrayObject('Array', w_FncPrototype) @@ -583,9 +546,7 @@ 'constructor': w_FncPrototype, '__proto__': w_ArrPrototype, 'toString': W_ArrayToString(ctx), - 'join': W_ArrayJoin(ctx), - 'reverse': W_ArrayReverse(ctx), - 'sort': w_FncPrototype, #dummy + 'join': W_ArrayJoin(ctx) }) w_Array.Put(ctx, 'prototype', w_ArrPrototype, flags = allon) @@ -613,9 +574,9 @@ w_Date = W_DateFake(ctx, Class='Date') w_Global.Put(ctx, 'Date', w_Date) - w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN), flags = DE|DD) - w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY), flags = DE|DD) - w_Global.Put(ctx, 'undefined', w_Undefined, flags = DE|DD) + w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN)) + w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY)) + w_Global.Put(ctx, 'undefined', w_Undefined) w_Global.Put(ctx, 'eval', W_Builtin(evaljs)) w_Global.Put(ctx, 'parseInt', W_Builtin(parseIntjs)) w_Global.Put(ctx, 'parseFloat', W_Builtin(parseFloatjs)) @@ -624,6 +585,7 @@ w_Global.Put(ctx, 'print', W_Builtin(printjs)) w_Global.Put(ctx, 'unescape', W_Builtin(unescapejs)) + w_Global.Put(ctx, 'this', w_Global) # DEBUGGING if 0: Modified: pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/js_interactive.py Tue Jun 3 21:46:02 2008 @@ -33,7 +33,7 @@ def loadjs(ctx, args, this): - filename = args[0].ToString(ctx) + filename = args[0].ToString() t = load_file(filename) return t.execute(ctx) @@ -106,7 +106,7 @@ def showtraceback(self, exc): # XXX format exceptions nicier - print exc.exception.ToString(None) #XXX should not be none + print exc.exception.ToString() def showsyntaxerror(self, filename, exc): # XXX format syntax errors nicier 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 Jun 3 21:46:02 2008 @@ -10,7 +10,6 @@ compare_e, increment, commonnew, mult, division, uminus, mod from pypy.rlib.jit import hint from pypy.rlib.rarithmetic import intmask -from pypy.rlib.objectmodel import we_are_translated class AlreadyRun(Exception): pass @@ -26,21 +25,13 @@ to_pop = 0 try: while i < len(opcodes): - if we_are_translated(): - #this is an optimization strategy for translated code - #on top of cpython it destroys the performance - #besides, this code might be completely wrong + for name, op in opcode_unrolling: opcode = opcodes[i] - for name, op in opcode_unrolling: - opcode = hint(opcode, deepfreeze=True) - if isinstance(opcode, op): - result = opcode.eval(ctx, stack) - assert result is None - break - else: - opcode = opcodes[i] - result = opcode.eval(ctx, stack) - assert result is None + opcode = hint(opcode, deepfreeze=True) + if isinstance(opcode, op): + result = opcode.eval(ctx, stack) + assert result is None + break if isinstance(opcode, BaseJump): i = opcode.do_jump(stack, i) else: @@ -119,7 +110,7 @@ def emit_continue(self): if not self.startlooplabel: - raise ThrowException(W_String("Continue outside loop")) + raise ThrowError(W_String("Continue outside loop")) self.emit('JUMP', self.startlooplabel[-1]) def emit(self, operation, *args): @@ -183,9 +174,6 @@ self.code.run(ctx) except ReturnException, e: return e.value - except: - print "unhandled exception in function:", self.name - raise return w_Undefined class Opcode(object): @@ -287,11 +275,7 @@ self.identifier = identifier def eval(self, ctx, stack): - try: - stack.append(ctx.resolve_identifier(ctx, self.identifier)) - except: - print self.identifier - raise + stack.append(ctx.resolve_identifier(self.identifier)) def __repr__(self): return 'LOAD_VARIABLE "%s"' % (self.identifier,) @@ -387,11 +371,7 @@ def eval(self, ctx, stack): w_obj = stack.pop().ToObject(ctx) - try: - stack.append(w_obj.Get(ctx, self.name)) - except: - print w_obj, self.name - raise + stack.append(w_obj.Get(ctx, self.name)) #stack.append(W_Reference(self.name, w_obj)) def __repr__(self): @@ -435,7 +415,7 @@ def eval(self, ctx, stack): try: - var = ctx.resolve_identifier(ctx, self.name) + var = ctx.resolve_identifier(self.name) stack.append(W_String(var.type())) except ThrowException: stack.append(W_String('undefined')) @@ -561,7 +541,7 @@ left = stack.pop() elem = stack.pop() value = stack.pop() - name = elem.ToString(ctx) + name = elem.ToString() value = self.operation(ctx, left, name, value) left.ToObject(ctx).Put(ctx, name, value) stack.append(value) @@ -608,7 +588,7 @@ class BaseAssignOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop() - left = ctx.resolve_identifier(ctx, name) + left = ctx.resolve_identifier(name) result = self.operation(ctx, left, right) stack.append(result) return result @@ -616,7 +596,7 @@ class BaseAssignBitOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop().ToInt32(ctx) - left = ctx.resolve_identifier(ctx, name).ToInt32(ctx) + left = ctx.resolve_identifier(name).ToInt32(ctx) result = self.operation(ctx, left, right) stack.append(result) return result @@ -647,14 +627,14 @@ class STORE_POSTINCR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(ctx, name) + value = ctx.resolve_identifier(name) newval = increment(ctx, value) stack.append(value) return newval class STORE_POSTDECR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(ctx, name) + value = ctx.resolve_identifier(name) newval = increment(ctx, value, -1) stack.append(value) return newval @@ -762,31 +742,31 @@ def eval(self, ctx, stack): stack.pop() -def common_call(ctx, r1, args, this, name): - if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("%s is not a callable (%s)"%(r1.ToString(ctx), name))) - try: - res = r1.Call(ctx=ctx, args=args.tolist(), this=this) - except JsTypeError: - raise ThrowException(W_String("%s is not a function (%s)"%(r1.ToString(ctx), name))) - return res - class CALL(Opcode): def eval(self, ctx, stack): r1 = stack.pop() args = stack.pop() - name = r1.ToString(ctx) - #XXX hack, this should be comming from context - stack.append(common_call(ctx, r1, args, ctx.scope[-1], name)) + if not isinstance(r1, W_PrimitiveObject): + raise ThrowException(W_String("it is not a callable")) + try: + res = r1.Call(ctx=ctx, args=args.tolist(), this=None) + except JsTypeError: + raise ThrowException(W_String('it is not a function')) + stack.append(res) class CALL_METHOD(Opcode): def eval(self, ctx, stack): method = stack.pop() what = stack.pop().ToObject(ctx) args = stack.pop() - name = method.ToString(ctx) #XXX missing ctx? - r1 = what.Get(ctx, name) - stack.append(common_call(ctx, r1, args, what, name)) + r1 = what.Get(ctx, method.ToString()) + if not isinstance(r1, W_PrimitiveObject): + raise ThrowException(W_String("it is not a callable")) + try: + res = r1.Call(ctx=ctx, args=args.tolist(), this=what) + except JsTypeError: + raise ThrowException(W_String('it is not a function')) + stack.append(res) class DUP(Opcode): @@ -876,8 +856,11 @@ # ---------------- with support --------------------- class WITH_START(Opcode): + def __init__(self, name): + self.name = name + def eval(self, ctx, stack): - ctx.push_object(stack.pop().ToObject(ctx)) + ctx.push_object(ctx.resolve_identifier(self.name).ToObject(ctx)) class WITH_END(Opcode): def eval(self, ctx, stack): @@ -894,7 +877,7 @@ class DELETE_MEMBER(Opcode): def eval(self, ctx, stack): - what = stack.pop().ToString(ctx) + what = stack.pop().ToString() obj = stack.pop().ToObject(ctx) stack.append(newbool(obj.Delete(what))) 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 Jun 3 21:46:02 2008 @@ -256,10 +256,8 @@ if Prototype is None: proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype') Prototype = proto - + W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc) - if hasattr(self, 'length'): - self.Put(ctx, 'length', W_IntNumber(self.length), flags = DD|RO) def Call(self, ctx, args=[], this = None): raise NotImplementedError @@ -366,7 +364,7 @@ def ToObject(self, ctx): return create_object(ctx, 'Boolean', Value=self) - def ToString(self, ctx): + def ToString(self, ctx=None): if self.boolval == True: return "true" return "false" @@ -388,7 +386,6 @@ class W_String(W_Primitive): def __init__(self, strval): super(W_String, self).__init__() - self.Class = 'string' #hack self.strval = strval def __repr__(self): @@ -401,13 +398,10 @@ proto = ctx.get_global().Get(ctx, 'String').Get(ctx, 'prototype') return proto.Get(ctx, P) - def Put(self, ctx, P, V, flags=0): - pass - def ToObject(self, ctx): return self #create_object(ctx, 'String', Value=self) - def ToString(self, ctx): + def ToString(self, ctx=None): return self.strval def ToBoolean(self): @@ -420,7 +414,7 @@ return 'string' def GetPropertyName(self): - return self.strval + return self.ToString() def ToNumber(self, ctx): if not self.strval: @@ -450,7 +444,7 @@ super(W_IntNumber, self).__init__() self.intval = intmask(intval) - def ToString(self, ctx): + def ToString(self, ctx=None): # XXX incomplete, this doesn't follow the 9.8.1 recommendation return str(self.intval) @@ -468,7 +462,7 @@ return r_uint(self.intval) def GetPropertyName(self): - return str(self.intval) + return self.ToString() def __repr__(self): return 'W_IntNumber(%s)' % (self.intval,) @@ -480,7 +474,7 @@ super(W_FloatNumber, self).__init__() self.floatval = float(floatval) - def ToString(self, ctx): + def ToString(self, ctx = None): # XXX incomplete, this doesn't follow the 9.8.1 recommendation if isnan(self.floatval): return 'NaN' @@ -523,7 +517,7 @@ def __init__(self, list_w): self.list_w = list_w - def ToString(self, ctx): + def ToString(self, ctx = None): raise SeePage(42) def ToBoolean(self): @@ -544,7 +538,7 @@ assert scope is not None self.scope = scope if this is None: - self.this = scope[0] + self.this = scope[-1] else: self.this = this if variable is None: @@ -563,7 +557,7 @@ def assign(self, name, value): assert name is not None - for obj in reversed(self.scope): + for obj in self.scope: assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -577,7 +571,7 @@ self.variable.Put(self.get_global(), name, value) def delete_identifier(self, name): - for obj in reversed(self.scope): + for obj in self.scope: assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -594,25 +588,26 @@ self.variable.Put(ctx, name, value, flags = flags) def get_global(self): - return self.scope[0] + return self.scope[-1] def push_object(self, obj): """push object into scope stack""" assert isinstance(obj, W_PrimitiveObject) - self.scope.append(obj) + # XXX O(n^2) + self.scope.insert(0, obj) self.variable = obj def pop_object(self): """remove the last pushed object""" - return self.scope.pop() + return self.scope.pop(0) - def resolve_identifier(self, ctx, identifier): - if identifier == 'this': - return self.this - for obj in reversed(self.scope): + def resolve_identifier(self, identifier): + for obj in self.scope: assert isinstance(obj, W_PrimitiveObject) - if obj.HasProperty(identifier): - return obj.Get(ctx, identifier) + try: + return obj.propdict[identifier].value + except KeyError: + pass raise ThrowException(W_String("ReferenceError: %s is not defined" % identifier)) def global_context(w_global): 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 Jun 3 21:46:02 2008 @@ -712,14 +712,14 @@ bytecode.emit('LOAD_UNDEFINED') class With(Statement): - def __init__(self, pos, withpart, body): + def __init__(self, pos, identifier, body): self.pos = pos - self.withpart = withpart + assert isinstance(identifier, VariableIdentifier) + self.identifier = identifier.identifier self.body = body def emit(self, bytecode): - self.withpart.emit(bytecode) - bytecode.emit('WITH_START') + bytecode.emit('WITH_START', self.identifier) self.body.emit(bytecode) bytecode.emit('WITH_END') @@ -750,15 +750,17 @@ bytecode.emit('JUMP', startlabel) bytecode.emit_endloop_label(endlabel) -class ForIn(Statement): - def __init__(self, pos, name, lobject, body): +class ForVarIn(Statement): + def __init__(self, pos, vardecl, lobject, body): self.pos = pos - #assert isinstance(iterator, Node) - self.iteratorname = name + assert isinstance(vardecl, VariableDeclaration) + self.iteratorname = vardecl.identifier self.object = lobject self.body = body + def emit(self, bytecode): + bytecode.emit('DECLARE_VAR', self.iteratorname) self.object.emit(bytecode) bytecode.emit('LOAD_ITERATOR') precond = bytecode.emit_startloop_label() @@ -768,19 +770,27 @@ self.body.emit(bytecode) bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) - bytecode.emit('POP') + bytecode.emit('POP') -class ForVarIn(ForIn): - def __init__(self, pos, vardecl, lobject, body): +class ForIn(Statement): + def __init__(self, pos, name, lobject, body): self.pos = pos - assert isinstance(vardecl, VariableDeclaration) - self.iteratorname = vardecl.identifier + #assert isinstance(iterator, Node) + self.iteratorname = name self.object = lobject self.body = body def emit(self, bytecode): - bytecode.emit('DECLARE_VAR', self.iteratorname) - ForIn.emit(self, bytecode) + self.object.emit(bytecode) + bytecode.emit('LOAD_ITERATOR') + precond = bytecode.emit_startloop_label() + finish = bytecode.prealocate_endloop_label() + bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) + bytecode.emit('NEXT_ITERATOR', self.iteratorname) + self.body.emit(bytecode) + bytecode.emit('JUMP', precond) + bytecode.emit_endloop_label(finish) + bytecode.emit('POP') class For(Statement): def __init__(self, pos, setup, condition, update, body): @@ -794,17 +804,13 @@ self.setup.emit(bytecode) if isinstance(self.setup, Expression): bytecode.emit('POP') - - firstep = bytecode.prealocate_label() - bytecode.emit('JUMP', firstep) precond = bytecode.emit_startloop_label() finish = bytecode.prealocate_endloop_label() - self.update.emit(bytecode) - bytecode.emit('POP') - bytecode.emit_label(firstep) self.condition.emit(bytecode) bytecode.emit('JUMP_IF_FALSE', finish) self.body.emit(bytecode) + self.update.emit(bytecode) + bytecode.emit('POP') bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Tue Jun 3 21:46:02 2008 @@ -44,8 +44,8 @@ if not hasattr(cls, 'shellfile'): cls.shellfile = load_file(str(shellpath)) cls.interp.run(cls.shellfile) - cls.testcases = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'testcases') - cls.tc = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'tc') + cls.testcases = cls.interp.global_context.resolve_identifier('testcases') + cls.tc = cls.interp.global_context.resolve_identifier('tc') # override eval cls.interp.w_Global.Put(cls.interp.global_context, 'eval', W_Builtin(overriden_evaljs)) @@ -71,11 +71,10 @@ except JsBaseExcept: raise Failed(msg="Javascript Error", excinfo=py.code.ExceptionInfo()) except: - #print self.interp._code raise Failed(excinfo=py.code.ExceptionInfo()) ctx = self.interp.global_context - testcases = ctx.resolve_identifier(ctx, 'testcases') - self.tc = ctx.resolve_identifier(ctx, 'tc') + testcases = ctx.resolve_identifier('testcases') + self.tc = ctx.resolve_identifier('tc') testcount = testcases.Get(ctx, 'length').ToInt32(ctx) self.testcases = testcases return range(testcount) @@ -90,9 +89,9 @@ def run(self): ctx = JSTestFile.interp.global_context - r3 = ctx.resolve_identifier(ctx, 'run_test') + r3 = ctx.resolve_identifier('run_test') w_test_number = W_IntNumber(self.number) - result = r3.Call(ctx=ctx, args=[w_test_number]).ToString(ctx) + result = r3.Call(ctx=ctx, args=[w_test_number]).ToString() __tracebackhide__ = True if result != "passed": raise Failed(msg=result) Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js Tue Jun 3 21:46:02 2008 @@ -120,9 +120,9 @@ // print out bugnumber - // if ( BUGNUMBER ) { - // print ("BUGNUMBER: " + BUGNUMBER ); - // } + if ( BUGNUMBER ) { + print ("BUGNUMBER: " + BUGNUMBER ); + } } function test() { 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 Jun 3 21:46:02 2008 @@ -341,15 +341,6 @@ } print('out');""", "out") -def test_continue(): - assertp(""" - for(x = 0; x < 3; x++) { - print(x); - continue; - print('error'); - } - print('out');""", ["0","1","2","out"]) - def test_typeof(): assertv(""" var x = 3; @@ -510,7 +501,7 @@ yield assertv, "2 !== 2;", False def test_with(): - yield assertp, """ + assertp(""" var mock = {x:2}; var x=4; print(x); @@ -525,13 +516,7 @@ print(y); } print(x); - """, ['4', '2', '3', '4'] - - yield assertp, """ - with(new Array(1,2,3)) { - print(join('.')) - } - """, "1.2.3" + """, ['4', '2', '3', '4']) def test_bitops(): yield assertv, "2 ^ 2;", 0 From fijal at codespeak.net Tue Jun 3 21:50:19 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 21:50:19 +0200 (CEST) Subject: [pypy-svn] r55531 - pypy/branch/js-refactoring/pypy/lang/js/test/ecma Message-ID: <20080603195019.19C141684FD@codespeak.net> Author: fijal Date: Tue Jun 3 21:50:16 2008 New Revision: 55531 Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Log: Always run Number tests. They should *always* pass. Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Tue Jun 3 21:50:16 2008 @@ -18,11 +18,17 @@ except JsBaseExcept: return W_String("error") +passing_tests = ['Number'] + class JSDirectory(py.test.collect.Directory): def filefilter(self, path): if not py.test.config.option.ecma: - return False + for i in passing_tests: + if i in str(path): + break + else: + return False if path.check(file=1): return (path.basename not in exclusionlist) and (path.ext == '.js') @@ -58,7 +64,11 @@ def run(self): if not py.test.config.option.ecma: - py.test.skip("ECMA tests disabled, run with --ecma") + for i in passing_tests: + if i in self.listnames(): + break + else: + py.test.skip("ECMA tests disabled, run with --ecma") if py.test.config.option.collectonly: return self.init_interp() From fijal at codespeak.net Tue Jun 3 22:04:07 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 22:04:07 +0200 (CEST) Subject: [pypy-svn] r55532 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080603200407.750D3168053@codespeak.net> Author: fijal Date: Tue Jun 3 22:04:05 2008 New Revision: 55532 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Log: * Kill some dead code * Fix one test (in a bit different way though) Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Tue Jun 3 22:04:05 2008 @@ -541,18 +541,19 @@ w_Array = W_ArrayObject('Array', w_FncPrototype) w_ArrPrototype = W_Array(Prototype=w_ObjPrototype) + w_arr_join = W_ArrayJoin(ctx) + w_arr_join.Put(ctx, 'length', W_IntNumber(1), flags=allon) put_values(w_ArrPrototype, { 'constructor': w_FncPrototype, '__proto__': w_ArrPrototype, 'toString': W_ArrayToString(ctx), - 'join': W_ArrayJoin(ctx) + 'join': w_arr_join, }) w_Array.Put(ctx, 'prototype', w_ArrPrototype, flags = allon) w_Array.Put(ctx, '__proto__', w_FncPrototype, flags = allon) w_Array.Put(ctx, 'length', W_IntNumber(1), flags = allon) - w_Global.Put(ctx, 'Array', w_Array) @@ -603,25 +604,6 @@ # debugging self._code = bytecode if interactive: - print bytecode return bytecode.run(self.global_context, retlast=True) else: bytecode.run(self.global_context) - -def wrap_arguments(pyargs): - "receives a list of arguments and wrap then in their js equivalents" - res = [] - for arg in pyargs: - if isinstance(arg, W_Root): - res.append(arg) - elif isinstance(arg, str): - res.append(W_String(arg)) - elif isinstance(arg, int): - res.append(W_IntNumber(arg)) - elif isinstance(arg, float): - res.append(W_FloatNumber(arg)) - elif isinstance(arg, bool): - res.append(newbool(arg)) - else: - raise Exception("Cannot wrap %s" % (arg,)) - return res From cfbolz at codespeak.net Tue Jun 3 22:29:40 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 3 Jun 2008 22:29:40 +0200 (CEST) Subject: [pypy-svn] r55533 - pypy/extradoc/talk/ep2008 Message-ID: <20080603202940.89BA71684CE@codespeak.net> Author: cfbolz Date: Tue Jun 3 22:29:37 2008 New Revision: 55533 Modified: pypy/extradoc/talk/ep2008/abstract_obscure.txt Log: (fijal, cfbolz, pedronis watching): re-work the GC talk proposal Modified: pypy/extradoc/talk/ep2008/abstract_obscure.txt ============================================================================== --- pypy/extradoc/talk/ep2008/abstract_obscure.txt (original) +++ pypy/extradoc/talk/ep2008/abstract_obscure.txt Tue Jun 3 22:29:37 2008 @@ -1,25 +1,33 @@ Title ===== -PyPy - garbage collection details. +Writing Python code for different GCs + +(was: PyPy - garbage collection details.) Summary ======= -Obscure, naked, details of garbage collection strategies available in pypy. -Will contain performance difference of various operations depending on -chosen GC. +This talk will pick PyPy's GC as an example and discuss +how to write Python code that does not rely on the underlying GC +implementation. Abstract ======== -In this talk, we'll cover garbage collection strategies present in PyPy. -We'll not go into implementation details of those, but instead we'll -try to explain how certain operations behave and especially how they -present different performance characteristics than cpython's reference -counting strategy. We'll also explain why certain programming patterns -work well on some garbage collectors and doesn't work too well on others -and how to avoid such obstacles. +Almost all of the newer Python implementation depart from CPython's reference +counting as a memory management strategy and use more recent garbage +collection strategies. IronPython and Jython use the GCs of the .NET platform +and of the JVM respectively, PyPy contains several GCs, among them a moving +generational garbage collector. All these GCs have in common that they behave +slightly differently than reference counting in some places. Existing Python +code often uses patterns that only works well with reference counting. + +In this talk we will explain one of the PyPy GCs in detail as an example of +the sort of GC techniques that are used. Then we will describe common mistakes +that are made and explain ways how to work around them. Specifically we will +talk about the different semantics of finalizers and the varying cost of some +operations on a moving GC (like id). Proposed Length of talk required ================================ @@ -29,8 +37,11 @@ Brief Biography =============== -Maciej Fijalkowski is a core pypy developer, particularly interested -in obscure details of various parts. - -Armin Rigo is the author of psyco JIT, as well as key person behind -most pypy's obscure advanced details. +Maciej Fijalkowski is a core PyPy developer, particularly interested +in the obscure details of various parts. He is always annoyed with existing code +relying on reference counting, as well as lack of knowledge about how +things like finalizers work. + +Armin Rigo is the author of the Psyco JIT, as well as the key person behind +many of PyPy's advanced details. He is one of the main implementors of PyPy's +GCs. From cfbolz at codespeak.net Tue Jun 3 22:33:37 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 3 Jun 2008 22:33:37 +0200 (CEST) Subject: [pypy-svn] r55534 - pypy/extradoc/talk/ep2008 Message-ID: <20080603203337.156A11684CE@codespeak.net> Author: cfbolz Date: Tue Jun 3 22:33:35 2008 New Revision: 55534 Added: pypy/extradoc/talk/ep2008/abstract_gc.txt - copied unchanged from r55533, pypy/extradoc/talk/ep2008/abstract_obscure.txt Removed: pypy/extradoc/talk/ep2008/abstract_obscure.txt Log: give the file a better name ? no spelling mistakes found From fijal at codespeak.net Tue Jun 3 22:57:57 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 22:57:57 +0200 (CEST) Subject: [pypy-svn] r55537 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080603205757.8949F168446@codespeak.net> Author: fijal Date: Tue Jun 3 22:57:54 2008 New Revision: 55537 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Log: Implement unescape. It messes up with unicode right now (otherwise there is no way os passing the test) Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Tue Jun 3 22:57:54 2008 @@ -194,8 +194,32 @@ def versionjs(ctx, args, this): return w_Undefined +def _ishex(ch): + return ((ch >= 'a' and ch <= 'f') or (ch >= '0' and ch <= '9') or + (ch >= 'A' and ch <= 'F')) + def unescapejs(ctx, args, this): - return args[0] + # XXX consider using StringBuilder here + res = [] + if not isinstance(args[0], W_String): + raise JsTypeError(W_String("Expected string")) + strval = args[0].strval + lgt = len(strval) + i = 0 + while i < lgt: + ch = strval[i] + if ch == '%': + if (i + 2 < lgt and _ishex(strval[i+1]) and _ishex(strval[i+2])): + ch = ord(int(strval[i + 1] + strval[i + 2], 16)) + i += 2 + elif (i + 5 < lgt and strval[i + 1] == 'u' and + _ishex(strval[i + 2]) and _ishex(strval[i + 3]) and + _ishex(strval[i + 4]) and _ishex(strval[i + 5])): + ch = unichr(int(strval[i+2:i+6], 16)) + i += 5 + i += 1 + res.append(ch) + return W_String(''.join(res)) class W_ToString(W_NewBuiltin): def Call(self, ctx, args=[], this=None): From fijal at codespeak.net Tue Jun 3 23:25:51 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 3 Jun 2008 23:25:51 +0200 (CEST) Subject: [pypy-svn] r55538 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080603212551.5B99716806D@codespeak.net> Author: fijal Date: Tue Jun 3 23:25:50 2008 New Revision: 55538 Modified: pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Log: Hack to make printing floats correct. 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 Jun 3 23:25:50 2008 @@ -489,8 +489,11 @@ return str(intval) except OverflowError: pass - - return str(self.floatval) + + res = str(self.floatval) + if (res[-3] == '+' or res[-3] == '-') and res[-2] == '0': + res = res[:-2] + res[-1] + return res def ToBoolean(self): if isnan(self.floatval): From santagada at codespeak.net Wed Jun 4 00:57:25 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 00:57:25 +0200 (CEST) Subject: [pypy-svn] r55540 - in pypy/branch/js-refactoring/pypy/lang/js: . test test/ecma Message-ID: <20080603225725.2AEC916850D@codespeak.net> Author: santagada Date: Wed Jun 4 00:57:23 2008 New Revision: 55540 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/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/operations.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js pypy/branch/js-refactoring/pypy/lang/js/test/test_astbuilder.py Log: added Boolean to passing tests, and some translation fixes 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 Wed Jun 4 00:57:23 2008 @@ -1,4 +1,4 @@ -from pypy.rlib.rarithmetic import intmask, ovfcheck +from pypy.rlib.rarithmetic import intmask, ovfcheck, ovfcheck_float_to_int from pypy.rlib.parsing.tree import RPythonVisitor, Symbol, Nonterminal from pypy.lang.js import operations from pypy.rlib.parsing.parsing import ParseError @@ -87,10 +87,15 @@ def visit_DECIMALLITERAL(self, node): pos = self.get_pos(node) try: - ovfcheck(int(node.additional_info)) + + f = float(node.additional_info) + i = ovfcheck_float_to_int(f) + if i != f: + return operations.FloatNumber(pos, f) + else: + return operations.IntNumber(pos, i) except (ValueError, OverflowError): return operations.FloatNumber(pos, float(node.additional_info)) - return operations.IntNumber(pos, intmask(node.additional_info)) def visit_HEXINTEGERLITERAL(self, node): pos = self.get_pos(node) @@ -347,7 +352,8 @@ visit_assignmentexpressionnoin = visit_assignmentexpression def visit_emptystatement(self, node): - pass + pos = self.get_pos(node) + return operations.Empty(pos) def visit_newexpression(self, node): if len(node.children) == 1: 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 Wed Jun 4 00:57:23 2008 @@ -10,6 +10,7 @@ compare_e, increment, commonnew, mult, division, uminus, mod from pypy.rlib.jit import hint from pypy.rlib.rarithmetic import intmask +from pypy.rlib.objectmodel import we_are_translated class AlreadyRun(Exception): pass @@ -25,13 +26,21 @@ to_pop = 0 try: while i < len(opcodes): - for name, op in opcode_unrolling: - opcode = opcodes[i] - opcode = hint(opcode, deepfreeze=True) - if isinstance(opcode, op): - result = opcode.eval(ctx, stack) - assert result is None - break + opcode = opcodes[i] + if we_are_translated(): + #this is an optimization strategy for translated code + #on top of cpython it destroys the performance + #besides, this code might be completely wrong + for name, op in opcode_unrolling: + opcode = hint(opcode, deepfreeze=True) + if isinstance(opcode, op): + result = opcode.eval(ctx, stack) + assert result is None + break + else: + result = opcode.eval(ctx, stack) + assert result is None + if isinstance(opcode, BaseJump): i = opcode.do_jump(stack, i) else: @@ -73,7 +82,10 @@ self.opcodes = [] self.label_count = 0 self.has_labels = True - self.stack = T() + if we_are_translated(): + self.stack = [] + else: + self.stack = T() self.startlooplabel = [] self.endlooplabel = [] @@ -105,7 +117,7 @@ def emit_break(self): if not self.endlooplabel: - raise ThrowError(W_String("Break outside loop")) + raise ThrowException(W_String("Break outside loop")) self.emit('JUMP', self.endlooplabel[-1]) def emit_continue(self): @@ -487,7 +499,7 @@ return if isinstance(stack[-1], W_FloatNumber): return - stack.append(stack.pop().ToNumber(ctx)) + stack.append(W_FloatNumber(stack.pop().ToNumber(ctx))) class UMINUS(BaseUnaryOperation): def eval(self, ctx, stack): 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 Wed Jun 4 00:57:23 2008 @@ -30,7 +30,7 @@ # return self def ToBoolean(self, ctx): - raise NotImplementedError() + raise NotImplementedError(self.__class__) def ToPrimitive(self, ctx, hint=""): return self @@ -52,25 +52,25 @@ return r_uint(0) def Get(self, ctx, P): - raise NotImplementedError() + raise NotImplementedError(self.__class__) def Put(self, ctx, P, V, flags = 0): - raise NotImplementedError() + raise NotImplementedError(self.__class__) def PutValue(self, w, ctx): pass def Call(self, ctx, args=[], this=None): - raise NotImplementedError() + raise NotImplementedError(self.__class__) def __str__(self): return self.ToString(ctx=None) def type(self): - raise NotImplementedError + raise NotImplementedError(self.__class__) def GetPropertyName(self): - raise NotImplementedError + raise NotImplementedError(self.__class__) class W_Undefined(W_Root): def __str__(self): 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 Wed Jun 4 00:57:23 2008 @@ -124,6 +124,8 @@ addoper = OPERANDS[self.operand] if addoper: addoper = '_' + self.prefix.upper() + addoper + else: + addoper = '' return addoper OPERANDS = { @@ -454,6 +456,8 @@ what = self.what if isinstance(what, Identifier): bytecode.emit('DELETE', what.name) + elif isinstance(what, VariableIdentifier): + bytecode.emit('DELETE', what.identifier) elif isinstance(what, MemberDot): what.left.emit(bytecode) # XXX optimize @@ -668,8 +672,6 @@ if self.expr is not None: self.expr.emit(bytecode) bytecode.emit('STORE', self.identifier) - else: - return True class VariableIdentifier(Expression): def __init__(self, pos, depth, identifier): @@ -690,7 +692,8 @@ def emit(self, bytecode): for node in self.nodes: - if node.emit(bytecode) is None: + node.emit(bytecode) + if isinstance(node, VariableDeclaration) and node.expr is not None: bytecode.emit('POP') class Variable(Statement): @@ -701,6 +704,13 @@ def emit(self, bytecode): self.body.emit(bytecode) +class Empty(Expression): + def __init__(self, pos): + self.pos = pos + + def emit(self, bytecode): + pass + class Void(Expression): def __init__(self, pos, expr): self.pos = pos Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Wed Jun 4 00:57:23 2008 @@ -18,7 +18,7 @@ except JsBaseExcept: return W_String("error") -passing_tests = ['Number'] +passing_tests = ['Number', 'Boolean'] class JSDirectory(py.test.collect.Directory): Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js Wed Jun 4 00:57:23 2008 @@ -223,6 +223,11 @@ } /* end of print functions */ +var TIME_1970 = 0; +var TIME_2000 = 946684800000; +var TIME_1900 = -2208988800000; +var TIME_YEAR_0 = -62167219200000; + /* * When running in the shell, run the garbage collector after the Modified: pypy/branch/js-refactoring/pypy/lang/js/test/test_astbuilder.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/test_astbuilder.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/test_astbuilder.py Wed Jun 4 00:57:23 2008 @@ -37,3 +37,6 @@ def test_sourcename(): p = to_ast('x()()').body assert p.sourcename == 'test' + +def test_empty(): + p = to_ast(';') From santagada at codespeak.net Wed Jun 4 01:14:22 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 01:14:22 +0200 (CEST) Subject: [pypy-svn] r55541 - pypy/branch/js-refactoring/pypy/translator/goal Message-ID: <20080603231422.CBA571684E0@codespeak.net> Author: santagada Date: Wed Jun 4 01:14:21 2008 New Revision: 55541 Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Log: don't know why this was there, but it was breaking translation Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py ============================================================================== --- pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py (original) +++ pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Wed Jun 4 01:14:21 2008 @@ -4,7 +4,7 @@ import sys from pypy.lang.js.interpreter import * -from pypy.lang.js.jsobj import ExecutionReturned +#from pypy.lang.js.jsobj import ExecutionReturned # __________ Entry point __________ @@ -15,8 +15,8 @@ t = load_file(argv[1]) interp.run(t) return 0 - elif argv[0] == 'foo': - raise ExecutionReturned(None) + # elif argv[0] == 'foo': + # raise ExecutionReturned(None) else: print "Usage: %s jsourcefile" % argv[0] return 1 From santagada at codespeak.net Wed Jun 4 01:36:48 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 01:36:48 +0200 (CEST) Subject: [pypy-svn] r55542 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080603233648.F0446168528@codespeak.net> Author: santagada Date: Wed Jun 4 01:36:46 2008 New Revision: 55542 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Log: removed super, a specialization, and added array reverse and some flags to constants on globals Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Wed Jun 4 01:36:46 2008 @@ -430,6 +430,28 @@ return W_String(common_join(ctx, this, sep)) +class W_ArrayReverse(W_NewBuiltin): + length = 0 + def Call(self, ctx, args=[], this=None): + r2 = this.Get(ctx, 'length').ToUInt32(ctx) + k = r_uint(0) + r3 = r_uint(math.floor( float(r2)/2.0 )) + if r3 == k: + return this + + while k < r3: + r6 = r2 - k - 1 + r7 = str(k) + r8 = str(r6) + + r9 = this.Get(ctx, r7) + r10 = this.Get(ctx, r8) + + this.Put(ctx, r7, r10) + this.Put(ctx, r8, r9) + k += 1 + + return this class W_DateFake(W_NewBuiltin): # XXX This is temporary def Call(self, ctx, args=[], this=None): @@ -573,6 +595,7 @@ '__proto__': w_ArrPrototype, 'toString': W_ArrayToString(ctx), 'join': w_arr_join, + 'reverse': W_ArrayReverse(ctx), }) w_Array.Put(ctx, 'prototype', w_ArrPrototype, flags = allon) @@ -599,9 +622,9 @@ w_Date = W_DateFake(ctx, Class='Date') w_Global.Put(ctx, 'Date', w_Date) - w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN)) - w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY)) - w_Global.Put(ctx, 'undefined', w_Undefined) + w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN), flags = DE|DD) + w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY), flags = DE|DD) + w_Global.Put(ctx, 'undefined', w_Undefined, flags = DE|DD) w_Global.Put(ctx, 'eval', W_Builtin(evaljs)) w_Global.Put(ctx, 'parseInt', W_Builtin(parseIntjs)) w_Global.Put(ctx, 'parseFloat', W_Builtin(parseFloatjs)) 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 Wed Jun 4 01:36:46 2008 @@ -133,7 +133,7 @@ self.opcodes.append(opcode) return opcode raise ValueError("Unknown opcode %s" % (operation,)) - emit._annspecialcase_ = 'specialize:arg(1)' + #emit._annspecialcase_ = 'specialize:arg(1)' def run(self, ctx, check_stack=True, retlast=False): if self.has_labels: 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 Wed Jun 4 01:36:46 2008 @@ -313,7 +313,7 @@ class W_Array(W_ListObject): def __init__(self, ctx=None, Prototype=None, Class='Array', Value=w_Undefined, callfunc=None): - super(W_Array, self).__init__(ctx, Prototype, Class, Value, callfunc) + W_ListObject.__init__(self, ctx, Prototype, Class, Value, callfunc) self.Put(ctx, 'length', W_IntNumber(0), flags = DD) self.length = r_uint(0) @@ -358,7 +358,7 @@ class W_Boolean(W_Primitive): def __init__(self, boolval): - super(W_Boolean, self).__init__() + W_Primitive.__init__(self) self.boolval = bool(boolval) def ToObject(self, ctx): @@ -385,7 +385,7 @@ class W_String(W_Primitive): def __init__(self, strval): - super(W_String, self).__init__() + W_Primitive.__init__(self) self.strval = strval def __repr__(self): @@ -441,7 +441,7 @@ """ Number known to be an integer """ def __init__(self, intval): - super(W_IntNumber, self).__init__() + W_BaseNumber.__init__(self) self.intval = intmask(intval) def ToString(self, ctx=None): @@ -471,7 +471,7 @@ """ Number known to be a float """ def __init__(self, floatval): - super(W_FloatNumber, self).__init__() + W_BaseNumber.__init__(self) self.floatval = float(floatval) def ToString(self, ctx = None): From santagada at codespeak.net Wed Jun 4 01:55:44 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 01:55:44 +0200 (CEST) Subject: [pypy-svn] r55543 - in pypy/branch/js-refactoring/pypy/lang/js: . test/ecma Message-ID: <20080603235544.9546B1683DB@codespeak.net> Author: santagada Date: Wed Jun 4 01:55:41 2008 New Revision: 55543 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js Log: small changes on Function, Object types, and commented out some prints on shell.js Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Wed Jun 4 01:55:41 2008 @@ -472,31 +472,31 @@ allon = DE | DD | RO w_Global = W_Object(Class="global") - + ctx = global_context(w_Global) w_ObjPrototype = W_Object(Prototype=None, Class='Object') w_Function = W_Function(ctx, Class='Function', Prototype=w_ObjPrototype) - + w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon) w_Global.Put(ctx, 'Function', w_Function) w_Object = W_ObjectObject('Object', w_Function) w_Object.Put(ctx, 'prototype', w_ObjPrototype, flags = allon) - + w_Object.Put(ctx, 'length', W_IntNumber(1), flags = RO | DD) w_Global.Put(ctx, 'Object', w_Object) + w_Global.Prototype = w_ObjPrototype + w_FncPrototype = w_Function.Call(ctx, this=w_Function) w_Function.Put(ctx, 'prototype', w_FncPrototype, flags = allon) w_Function.Put(ctx, 'constructor', w_Function) - w_Object.Put(ctx, 'length', W_IntNumber(1), flags = RO | DD) - toString = W_ToString(ctx) put_values(w_ObjPrototype, { 'constructor': w_Object, - '__proto__': w_Null, + '__proto__': w_FncPrototype, 'toString': toString, 'toLocaleString': toString, 'valueOf': W_ValueOf(ctx), @@ -507,11 +507,12 @@ #properties of the function prototype put_values(w_FncPrototype, { - 'constructor': w_FncPrototype, - '__proto__': w_ObjPrototype, + 'constructor': w_Function, + '__proto__': w_FncPrototype, 'toString': W_FToString(ctx), 'apply': W_Apply(ctx), - 'call': W_Call(ctx), + 'call': W_Call(ctx), + 'arguments': w_Null, }) w_Boolean = W_BooleanObject('Boolean', w_FncPrototype) @@ -529,7 +530,6 @@ }) w_Boolean.Put(ctx, 'prototype', w_BoolPrototype, flags = allon) - w_Global.Put(ctx, 'Boolean', w_Boolean) #Number Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/shell.js Wed Jun 4 01:55:41 2008 @@ -120,9 +120,9 @@ // print out bugnumber - if ( BUGNUMBER ) { - print ("BUGNUMBER: " + BUGNUMBER ); - } + // if ( BUGNUMBER ) { + // print ("BUGNUMBER: " + BUGNUMBER ); + // } } function test() { From santagada at codespeak.net Wed Jun 4 04:31:22 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 04:31:22 +0200 (CEST) Subject: [pypy-svn] r55544 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604023122.5E92916852B@codespeak.net> Author: santagada Date: Wed Jun 4 04:31:06 2008 New Revision: 55544 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py Log: emit needs to be specialized, and popped needs to be set before 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 Wed Jun 4 04:31:06 2008 @@ -16,12 +16,12 @@ pass def run_bytecode(opcodes, ctx, stack, check_stack=True, retlast=False): + popped = False if retlast: if opcodes[-1] == 'POP': opcodes.pop() popped = True - else: - popped = False + i = 0 to_pop = 0 try: @@ -133,7 +133,7 @@ self.opcodes.append(opcode) return opcode raise ValueError("Unknown opcode %s" % (operation,)) - #emit._annspecialcase_ = 'specialize:arg(1)' + emit._annspecialcase_ = 'specialize:arg(1)' def run(self, ctx, check_stack=True, retlast=False): if self.has_labels: From santagada at codespeak.net Wed Jun 4 04:42:12 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 04:42:12 +0200 (CEST) Subject: [pypy-svn] r55545 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604024212.CF307168535@codespeak.net> Author: santagada Date: Wed Jun 4 04:42:07 2008 New Revision: 55545 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Log: inverted the scope stack 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 Wed Jun 4 04:42:07 2008 @@ -298,9 +298,10 @@ self.identifier = identifier def eval(self, ctx, stack): - xxx - scope = ctx.scope[self.depth] - stack.append(scope.Get(ctx, self.identifier)) + raise NotImplementedError() + # XXX + # scope = ctx.scope[self.depth] + # stack.append(scope.Get(ctx, self.identifier)) #stack.append(W_Reference(self.identifier, scope)) def __repr__(self): 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 Wed Jun 4 04:42:07 2008 @@ -541,11 +541,11 @@ assert scope is not None self.scope = scope if this is None: - self.this = scope[-1] + self.this = scope[0] else: self.this = this if variable is None: - self.variable = self.scope[0] + self.variable = self.scope[-1] else: self.variable = variable self.debug = debug @@ -560,7 +560,8 @@ def assign(self, name, value): assert name is not None - for obj in self.scope: + for i in range(len(self.scope)-1, -1, -1): + obj = self.scope[i] assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -574,7 +575,8 @@ self.variable.Put(self.get_global(), name, value) def delete_identifier(self, name): - for obj in self.scope: + for i in range(len(self.scope)-1, -1, -1): + obj = self.scope[i] assert isinstance(obj, W_PrimitiveObject) try: P = obj.propdict[name] @@ -591,21 +593,21 @@ self.variable.Put(ctx, name, value, flags = flags) def get_global(self): - return self.scope[-1] + return self.scope[0] def push_object(self, obj): """push object into scope stack""" assert isinstance(obj, W_PrimitiveObject) - # XXX O(n^2) - self.scope.insert(0, obj) + self.scope.append(obj) self.variable = obj def pop_object(self): """remove the last pushed object""" - return self.scope.pop(0) + return self.scope.pop() def resolve_identifier(self, identifier): - for obj in self.scope: + for i in range(len(self.scope)-1, -1, -1): + obj = self.scope[i] assert isinstance(obj, W_PrimitiveObject) try: return obj.propdict[identifier].value From santagada at codespeak.net Wed Jun 4 04:50:19 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 04:50:19 +0200 (CEST) Subject: [pypy-svn] r55546 - in pypy/branch/js-refactoring/pypy/lang/js: . test/ecma Message-ID: <20080604025019.CDCA41683FC@codespeak.net> Author: santagada Date: Wed Jun 4 04:50:16 2008 New Revision: 55546 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Log: proper resolve_identifier semantics 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 Wed Jun 4 04:50:16 2008 @@ -287,7 +287,7 @@ self.identifier = identifier def eval(self, ctx, stack): - stack.append(ctx.resolve_identifier(self.identifier)) + stack.append(ctx.resolve_identifier(ctx, self.identifier)) def __repr__(self): return 'LOAD_VARIABLE "%s"' % (self.identifier,) @@ -428,7 +428,7 @@ def eval(self, ctx, stack): try: - var = ctx.resolve_identifier(self.name) + var = ctx.resolve_identifier(ctx, self.name) stack.append(W_String(var.type())) except ThrowException: stack.append(W_String('undefined')) @@ -601,7 +601,7 @@ class BaseAssignOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop() - left = ctx.resolve_identifier(name) + left = ctx.resolve_identifier(ctx, name) result = self.operation(ctx, left, right) stack.append(result) return result @@ -609,7 +609,7 @@ class BaseAssignBitOper(BaseStore): def process(self, ctx, name, stack): right = stack.pop().ToInt32(ctx) - left = ctx.resolve_identifier(name).ToInt32(ctx) + left = ctx.resolve_identifier(ctx, name).ToInt32(ctx) result = self.operation(ctx, left, right) stack.append(result) return result @@ -640,14 +640,14 @@ class STORE_POSTINCR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(name) + value = ctx.resolve_identifier(ctx, name) newval = increment(ctx, value) stack.append(value) return newval class STORE_POSTDECR(BaseStore): def process(self, ctx, name, stack): - value = ctx.resolve_identifier(name) + value = ctx.resolve_identifier(ctx, name) newval = increment(ctx, value, -1) stack.append(value) return newval @@ -873,7 +873,7 @@ self.name = name def eval(self, ctx, stack): - ctx.push_object(ctx.resolve_identifier(self.name).ToObject(ctx)) + ctx.push_object(ctx.resolve_identifier(ctx, self.name).ToObject(ctx)) class WITH_END(Opcode): def eval(self, ctx, stack): 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 Wed Jun 4 04:50:16 2008 @@ -605,14 +605,12 @@ """remove the last pushed object""" return self.scope.pop() - def resolve_identifier(self, identifier): + def resolve_identifier(self, ctx, identifier): for i in range(len(self.scope)-1, -1, -1): obj = self.scope[i] assert isinstance(obj, W_PrimitiveObject) - try: - return obj.propdict[identifier].value - except KeyError: - pass + if obj.HasProperty(identifier): + return obj.Get(ctx, identifier) raise ThrowException(W_String("ReferenceError: %s is not defined" % identifier)) def global_context(w_global): Modified: pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/test/ecma/conftest.py Wed Jun 4 04:50:16 2008 @@ -50,8 +50,8 @@ if not hasattr(cls, 'shellfile'): cls.shellfile = load_file(str(shellpath)) cls.interp.run(cls.shellfile) - cls.testcases = cls.interp.global_context.resolve_identifier('testcases') - cls.tc = cls.interp.global_context.resolve_identifier('tc') + cls.testcases = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'testcases') + cls.tc = cls.interp.global_context.resolve_identifier(cls.interp.global_context, 'tc') # override eval cls.interp.w_Global.Put(cls.interp.global_context, 'eval', W_Builtin(overriden_evaljs)) @@ -83,8 +83,8 @@ except: raise Failed(excinfo=py.code.ExceptionInfo()) ctx = self.interp.global_context - testcases = ctx.resolve_identifier('testcases') - self.tc = ctx.resolve_identifier('tc') + testcases = ctx.resolve_identifier(ctx, 'testcases') + self.tc = ctx.resolve_identifier(ctx, 'tc') testcount = testcases.Get(ctx, 'length').ToInt32(ctx) self.testcases = testcases return range(testcount) @@ -99,7 +99,7 @@ def run(self): ctx = JSTestFile.interp.global_context - r3 = ctx.resolve_identifier('run_test') + r3 = ctx.resolve_identifier(ctx, 'run_test') w_test_number = W_IntNumber(self.number) result = r3.Call(ctx=ctx, args=[w_test_number]).ToString() __tracebackhide__ = True From fijal at codespeak.net Wed Jun 4 05:56:05 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 05:56:05 +0200 (CEST) Subject: [pypy-svn] r55547 - pypy/branch/js-refactoring/pypy/translator/goal Message-ID: <20080604035605.89AFB16841A@codespeak.net> Author: fijal Date: Wed Jun 4 05:56:02 2008 New Revision: 55547 Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Log: This is surely not needed Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py ============================================================================== --- pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py (original) +++ pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Wed Jun 4 05:56:02 2008 @@ -4,7 +4,6 @@ import sys from pypy.lang.js.interpreter import * -#from pypy.lang.js.jsobj import ExecutionReturned # __________ Entry point __________ @@ -15,8 +14,6 @@ t = load_file(argv[1]) interp.run(t) return 0 - # elif argv[0] == 'foo': - # raise ExecutionReturned(None) else: print "Usage: %s jsourcefile" % argv[0] return 1 From fijal at codespeak.net Wed Jun 4 07:27:24 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 07:27:24 +0200 (CEST) Subject: [pypy-svn] r55548 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604052724.E396816842D@codespeak.net> Author: fijal Date: Wed Jun 4 07:27:23 2008 New Revision: 55548 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/operations.py Log: * Fight a bit with translation * I'm not sure if having that many opcodes for assignements makes sense * Try to support code pbc's does not work yet 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 Wed Jun 4 07:27:23 2008 @@ -82,10 +82,6 @@ self.opcodes = [] self.label_count = 0 self.has_labels = True - if we_are_translated(): - self.stack = [] - else: - self.stack = T() self.startlooplabel = [] self.endlooplabel = [] @@ -139,12 +135,21 @@ if self.has_labels: self.remove_labels() if 1: - return run_bytecode(self.opcodes, ctx, self.stack, check_stack, + if we_are_translated(): + stack = [] + else: + stack = T() + return run_bytecode(self.opcodes, ctx, stack, check_stack, retlast) else: return run_bytecode_unguarded(self.opcodes, ctx, self,stack, check_stack, retlast) + def _freeze_(self): + if self.has_labels: + self.remove_labels() + return True + def remove_labels(self): """ Basic optimization to remove all labels and change jumps to addresses. Necessary to run code at all @@ -327,6 +332,7 @@ def eval(self, ctx, stack): to_cut = len(stack)-self.counter + assert to_cut >= 0 list_w = stack[to_cut:] del stack[to_cut:] stack.append(W_List(list_w)) @@ -462,19 +468,22 @@ return W_IntNumber(op1|op2) class URSH(BaseBinaryBitwiseOp): - def eval(self, ctx, stack): + @staticmethod + def eval(ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToUInt32(ctx) stack.append(W_IntNumber(op1 >> (op2 & 0x1F))) class RSH(BaseBinaryBitwiseOp): - def eval(self, ctx, stack): + @staticmethod + def eval(ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToInt32(ctx) stack.append(W_IntNumber(op1 >> intmask(op2 & 0x1F))) class LSH(BaseBinaryBitwiseOp): - def eval(self, ctx, stack): + @staticmethod + def eval(ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToInt32(ctx) stack.append(W_IntNumber(op1 << intmask(op2 & 0x1F))) 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 Wed Jun 4 07:27:23 2008 @@ -13,6 +13,7 @@ from pypy.lang.js.jscode import JsCode, JsFunction from constants import unescapedict from pypy.rlib.unroll import unrolling_iterable +from pypy.rlib.objectmodel import specialize import sys import os @@ -119,14 +120,14 @@ element.emit(bytecode) bytecode.emit('LOAD_ARRAY', len(self.nodes)) -class Assignment(Expression): - def _get_name(self): - addoper = OPERANDS[self.operand] - if addoper: - addoper = '_' + self.prefix.upper() + addoper - else: - addoper = '' - return addoper + at specialize.memo() +def _get_name(prefix, operand): + addoper = OPERANDS[operand] + if addoper: + addoper = '_' + prefix.upper() + addoper + else: + addoper = '' + return addoper OPERANDS = { '=' : '', @@ -155,21 +156,32 @@ elif self.atype == '--': bytecode.emit('DECR') -class SimpleAssignment(Assignment): - 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): - if self.right is not None: - self.right.emit(bytecode) - bytecode_name = 'STORE' + self._get_name() - bytecode.emit(bytecode_name, self.identifier) +def new_simple_assignment(operand, prefix=''): + bytecode_name = 'STORE' + _get_name(prefix, operand) + class SimpleAssignment(Expression): + def __init__(self, pos, left, right): + self.identifier = left.get_literal() + self.right = right + self.pos = pos -class VariableAssignment(Assignment): + def emit(self, bytecode): + if self.right is not None: + self.right.emit(bytecode) + bytecode.emit(bytecode_name, self.identifier) + return SimpleAssignment + +SIMPLE_ASSIGNMENTS = {} + +for operand in OPERANDS: + for prefix in ['', 'pre', 'post']: + SIMPLE_ASSIGNMENTS[(operand, prefix)] = new_simple_assignment(operand, prefix) + +def SimpleAssignment(pos, left, right, operand, prefix=''): + return SIMPLE_ASSIGNMENTS[(operand, prefix)](pos, left, right) + +# XXX VariableAssignment is not used at all, even should explode when +# translating, fix it with STORE_FAST and LOAD_FAST +class VariableAssignment(Expression): def __init__(self, pos, left, right, operand): xxx # shall never land here for now self.identifier = left.identifier @@ -182,40 +194,60 @@ self.right.emit(bytecode) bytecode.emit('STORE_VAR', self.depth, self.identifier) -class MemberAssignment(Assignment): - 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 - self.what = what - self.item = item - self.right = right - self.operand = operand - self.prefix = prefix +def new_member_assignment(operand, prefix): + bytecode_name = 'STORE_MEMBER' + _get_name(prefix, operand) + class MemberAssignment(Expression): + def __init__(self, pos, what, item, right): + # XXX we can optimise here what happens if what is identifier, + # but let's leave it alone for now + self.pos = pos + self.what = what + self.item = item + self.right = right - def emit(self, bytecode): - if self.right is not None: - self.right.emit(bytecode) - self.item.emit(bytecode) - self.what.emit(bytecode) - bytecode.emit('STORE_MEMBER' + self._get_name()) + def emit(self, bytecode): + if self.right is not None: + self.right.emit(bytecode) + self.item.emit(bytecode) + self.what.emit(bytecode) + bytecode.emit(bytecode_name) + return MemberAssignment + +MEMBER_ASSIGNMENTS = {} + +for operand in OPERANDS: + for prefix in ['', 'pre', 'post']: + MEMBER_ASSIGNMENTS[(operand, prefix)] = new_member_assignment(operand, prefix) + +def MemberAssignment(pos, what, item, right, operand, prefix=''): + return MEMBER_ASSIGNMENTS[(operand, prefix)](pos, what, item, right) + +def new_member_dot_assignment(operand, prefix): + bytecode_name = 'STORE_MEMBER' + _get_name(prefix, operand) + class MemberDotAssignment(Expression): + def __init__(self, pos, what, name, right): + self.pos = pos + self.what = what + self.itemname = name + self.right = right -class MemberDotAssignment(Assignment): - 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): + # XXX optimize this a bit + if self.right is not None: + self.right.emit(bytecode) + bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) + self.what.emit(bytecode) + bytecode.emit(bytecode_name) + return MemberDotAssignment + +MEMBER_DOT_ASSIGNMENTS = {} + +for operand in OPERANDS: + for prefix in ['', 'pre', 'post']: + MEMBER_DOT_ASSIGNMENTS[(operand, prefix)] = new_member_dot_assignment(operand, prefix) - def emit(self, bytecode): - # XXX optimize this a bit - if self.right is not None: - self.right.emit(bytecode) - bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) - self.what.emit(bytecode) - bytecode.emit('STORE_MEMBER' + self._get_name()) +def MemberDotAssignment(pos, what, item, right, operand, prefix=''): + return MEMBER_DOT_ASSIGNMENTS[(operand, prefix)](pos, what, item, right) class Block(Statement): def __init__(self, pos, nodes): From antocuni at codespeak.net Wed Jun 4 10:02:06 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 4 Jun 2008 10:02:06 +0200 (CEST) Subject: [pypy-svn] r55550 - in pypy/branch/oo-jit/pypy/jit: rainbow/test timeshifter Message-ID: <20080604080206.34D9C168439@codespeak.net> Author: antocuni Date: Wed Jun 4 10:02:04 2008 New Revision: 55550 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py pypy/branch/oo-jit/pypy/jit/timeshifter/rvalue.py Log: implement FrozenInstanceVarWithPartialData, the equivalent of FrozenPtrVarWithPartialData for ootype. test_promotion.test_remembers_across_mp passes Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Wed Jun 4 10:02:04 2008 @@ -477,6 +477,5 @@ def skip(self): py.test.skip('in progress') - test_remembers_across_mp = skip test_raise_result_mixup = skip test_raise_result_mixup_some_more = skip Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rvalue.py Wed Jun 4 10:02:04 2008 @@ -617,12 +617,12 @@ PtrRedBox = InstanceRedBox -class FrozenPtrVarWithPartialData(FrozenPtrVar): +class AbstractFrozenPtrVarWithPartialData(AbstractFrozenPtrVar): def exactmatch(self, box, outgoingvarboxes, memo): if self.fz_partialcontent is None: - return FrozenPtrVar.exactmatch(self, box, outgoingvarboxes, memo) - assert isinstance(box, PtrRedBox) + return AbstractFrozenPtrVar.exactmatch(self, box, outgoingvarboxes, memo) + assert isinstance(box, AbstractPtrRedBox) partialdatamatch = self.fz_partialcontent.match(box, memo.partialdatamatch) # skip the parent's exactmatch()! @@ -635,6 +635,15 @@ return match +class FrozenPtrVarWithPartialData(AbstractFrozenPtrVarWithPartialData, LLTypeMixin): + PtrRedBox = PtrRedBox + FrozenPtrVar = FrozenPtrVar + +class FrozenInstanceVarWithPartialData(AbstractFrozenPtrVarWithPartialData, OOTypeMixin): + PtrRedBox = InstanceRedBox + FrozenPtrVar = FrozenInstanceVar + + class FrozenPtrVirtual(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): @@ -673,4 +682,4 @@ InstanceRedBox.FrozenPtrVirtual = FrozenPtrVirtual InstanceRedBox.FrozenPtrConst = FrozenInstanceConst InstanceRedBox.FrozenPtrVar = FrozenInstanceVar -InstanceRedBox.FrozenPtrVarWithPartialData = None +InstanceRedBox.FrozenPtrVarWithPartialData = FrozenInstanceVarWithPartialData From antocuni at codespeak.net Wed Jun 4 12:21:09 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 4 Jun 2008 12:21:09 +0200 (CEST) Subject: [pypy-svn] r55551 - pypy/branch/oo-jit/pypy/translator Message-ID: <20080604102109.217AB1684BF@codespeak.net> Author: antocuni Date: Wed Jun 4 12:21:07 2008 New Revision: 55551 Modified: pypy/branch/oo-jit/pypy/translator/simplify.py Log: prevent eliminate_empty_blocks() from hanging if the graph contains two empty blocks which link each other Modified: pypy/branch/oo-jit/pypy/translator/simplify.py ============================================================================== --- pypy/branch/oo-jit/pypy/translator/simplify.py (original) +++ pypy/branch/oo-jit/pypy/translator/simplify.py Wed Jun 4 12:21:07 2008 @@ -84,6 +84,9 @@ exit = block1.exits[0] assert block1 is not exit.target, ( "the graph contains an empty infinite loop") + if exit.target.exits: + assert block1 is not exit.target.exits[0].target, ( + "the graph contains an empty infinite loop") outputargs = [] for v in exit.args: if isinstance(v, Variable): From fijal at codespeak.net Wed Jun 4 19:22:40 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 19:22:40 +0200 (CEST) Subject: [pypy-svn] r55568 - pypy/branch/js-refactoring/pypy/lang/js/test Message-ID: <20080604172240.B1D4316842E@codespeak.net> Author: fijal Date: Wed Jun 4 19:22:37 2008 New Revision: 55568 Modified: pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: Fix tests 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 Wed Jun 4 19:22:37 2008 @@ -12,8 +12,9 @@ bytecode.emit('LOAD_FLOATCONSTANT', 2) bytecode.emit('LOAD_FLOATCONSTANT', 4) bytecode.emit('ADD') - bytecode.run(ExecutionContext([W_Object()]), check_stack=False) - assert bytecode.stack[0].ToNumber(None) == 6.0 + bytecode.emit('POP') + res = bytecode.run(ExecutionContext([W_Object()]), check_stack=False, retlast=True) + assert res.ToNumber(None) == 6.0 def assertp(code, prints): l = [] @@ -561,6 +562,10 @@ yield assertv, "x=0; x|=1; x;", 1 yield assertv, "x=2; x^=2; x;", 0 +def test_not(): + py.test.skip("not supported") + assertv("~1", -2) + def test_twoarray(): assertp(""" a1 = new Array(); From fijal at codespeak.net Wed Jun 4 19:24:28 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 19:24:28 +0200 (CEST) Subject: [pypy-svn] r55569 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604172428.9BE3F168431@codespeak.net> Author: fijal Date: Wed Jun 4 19:24:27 2008 New Revision: 55569 Modified: pypy/branch/js-refactoring/pypy/lang/js/baseop.py pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/operations.py Log: * Make annotator happier by supporting different emit_xxx * Revert 55548, hack differently * Minor translation fixes 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 Wed Jun 4 19:24:27 2008 @@ -7,6 +7,7 @@ from pypy.rlib.rarithmetic import r_uint, intmask, INFINITY, NAN, ovfcheck,\ isnan, isinf from pypy.lang.js.execution import ThrowException, JsTypeError +import math def plus(ctx, nleft, nright): if isinstance(nleft, W_String) or isinstance(nright, W_String): @@ -59,7 +60,7 @@ def mod(ctx, nleft, nright): # XXX this one is really not following spec fleft = nleft.ToNumber(ctx) fright = nright.ToNumber(ctx) - return W_FloatNumber(fleft % fright) + return W_FloatNumber(math.fmod(fleft, fright)) def division(ctx, nleft, nright): # XXX optimise for ints and floats Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Wed Jun 4 19:24:27 2008 @@ -11,7 +11,8 @@ from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.streamio import open_file_as_stream from pypy.lang.js.jscode import JsCode -from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf +from pypy.rlib.rarithmetic import NAN, INFINITY, isnan, isinf, r_uint +from pypy.rlib.objectmodel import specialize ASTBUILDER = ASTBuilder() @@ -342,14 +343,15 @@ mytype = 'string' -def get_value_of(type, ctx): + at specialize.memo() +def get_value_of(type): class W_ValueValueOf(W_NewBuiltin): "this is the valueOf function for objects with Value" def Call(self, ctx, args=[], this=None): if type != this.Class: raise JsTypeError('%s.prototype.valueOf called with incompatible type' % self.type()) return this.Value - return W_ValueValueOf(ctx) + return W_ValueValueOf class W_CharAt(W_NewBuiltin): def Call(self, ctx, args=[], this=None): @@ -463,13 +465,13 @@ def pypy_repr(ctx, repr, w_arg): return W_String(w_arg.__class__.__name__) +def put_values(ctx, obj, dictvalues): + for key,value in dictvalues.iteritems(): + obj.Put(ctx, key, value) + class Interpreter(object): """Creates a js interpreter""" - def __init__(self): - def put_values(obj, dictvalues): - for key,value in dictvalues.iteritems(): - obj.Put(ctx, key, value) - + def __init__(self): allon = DE | DD | RO w_Global = W_Object(Class="global") @@ -494,7 +496,7 @@ toString = W_ToString(ctx) - put_values(w_ObjPrototype, { + put_values(ctx, w_ObjPrototype, { 'constructor': w_Object, '__proto__': w_FncPrototype, 'toString': toString, @@ -506,7 +508,7 @@ }) #properties of the function prototype - put_values(w_FncPrototype, { + put_values(ctx, w_FncPrototype, { 'constructor': w_Function, '__proto__': w_FncPrototype, 'toString': W_FToString(ctx), @@ -522,11 +524,11 @@ w_BoolPrototype = create_object(ctx, 'Object', Value=newbool(False)) w_BoolPrototype.Class = 'Boolean' - put_values(w_BoolPrototype, { + put_values(ctx, w_BoolPrototype, { 'constructor': w_FncPrototype, '__proto__': w_ObjPrototype, 'toString': W_BooleanValueToString(ctx), - 'valueOf': get_value_of('Boolean', ctx), + 'valueOf': get_value_of('Boolean')(ctx), }) w_Boolean.Put(ctx, 'prototype', w_BoolPrototype, flags = allon) @@ -539,14 +541,14 @@ w_NumPrototype = create_object(ctx, 'Object', Value=W_FloatNumber(0.0)) w_NumPrototype.Class = 'Number' - put_values(w_NumPrototype, { + put_values(ctx, w_NumPrototype, { 'constructor': w_Number, '__proto__': w_empty_fun, 'toString': W_NumberValueToString(ctx), - 'valueOf': get_value_of('Number', ctx), + 'valueOf': get_value_of('Number')(ctx), }) - put_values(w_Number, { + put_values(ctx, w_Number, { 'constructor': w_FncPrototype, 'prototype': w_NumPrototype, '__proto__': w_empty_fun, @@ -570,11 +572,11 @@ w_StrPrototype = create_object(ctx, 'Object', Value=W_String('')) w_StrPrototype.Class = 'String' - put_values(w_StrPrototype, { + put_values(ctx, w_StrPrototype, { 'constructor': w_FncPrototype, '__proto__': w_StrPrototype, 'toString': W_StringValueToString(ctx), - 'valueOf': get_value_of('String', ctx), + 'valueOf': get_value_of('String')(ctx), 'charAt': W_CharAt(ctx), 'concat': W_Concat(ctx), 'indexOf': W_IndexOf(ctx), @@ -590,7 +592,7 @@ w_arr_join = W_ArrayJoin(ctx) w_arr_join.Put(ctx, 'length', W_IntNumber(1), flags=allon) - put_values(w_ArrPrototype, { + put_values(ctx, w_ArrPrototype, { 'constructor': w_FncPrototype, '__proto__': w_ArrPrototype, 'toString': W_ArrayToString(ctx), 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 Wed Jun 4 19:24:27 2008 @@ -84,6 +84,7 @@ self.has_labels = True self.startlooplabel = [] self.endlooplabel = [] + self.stack = [] def emit_label(self, num = -1): if num == -1: @@ -122,15 +123,21 @@ self.emit('JUMP', self.startlooplabel[-1]) def emit(self, operation, *args): - opcode = None - for name, opcodeclass in opcode_unrolling: - if operation == name: - opcode = opcodeclass(*args) - self.opcodes.append(opcode) - return opcode - raise ValueError("Unknown opcode %s" % (operation,)) + opcode = getattr(opcodes, operation)(*args) + self.opcodes.append(opcode) + return opcode emit._annspecialcase_ = 'specialize:arg(1)' + def emit_store(self, operation, identifier): + opcode = store_opcodes[operation](identifier) + self.opcodes.append(opcode) + return opcode + + def emit_store_member(self, operation): + opcode = store_member_opcodes[operation]() + self.opcodes.append(opcode) + return opcode + def run(self, ctx, check_stack=True, retlast=False): if self.has_labels: self.remove_labels() @@ -222,8 +229,9 @@ s5 = stack.pop().ToInt32(ctx) s6 = stack.pop().ToInt32(ctx) stack.append(self.operation(ctx, s5, s6)) - - def operation(self, ctx, op1, op2): + + @staticmethod + def operation(ctx, op1, op2): raise NotImplementedError class BaseBinaryOperation(Opcode): @@ -563,7 +571,7 @@ left = stack.pop() elem = stack.pop() value = stack.pop() - name = elem.ToString() + name = elem.ToString(ctx) value = self.operation(ctx, left, name, value) left.ToObject(ctx).Put(ctx, name, value) stack.append(value) @@ -903,6 +911,8 @@ obj = stack.pop().ToObject(ctx) stack.append(newbool(obj.Delete(what))) +# different opcode mappings, to make annotator happy + OpcodeMap = {} for name, value in locals().items(): @@ -910,3 +920,16 @@ OpcodeMap[name] = value opcode_unrolling = unrolling_iterable(OpcodeMap.items()) + +class Opcodes: + pass + +opcodes = Opcodes() +store_opcodes = {} +store_member_opcodes = {} +for name, value in OpcodeMap.items(): + if name.startswith('STORE_MEMBER'): + store_member_opcodes[name] = value + elif name.startswith('STORE'): + store_opcodes[name] = value + setattr(opcodes, name, value) 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 Wed Jun 4 19:24:27 2008 @@ -29,7 +29,7 @@ #def GetValue(self): # return self - def ToBoolean(self, ctx): + def ToBoolean(self): raise NotImplementedError(self.__class__) def ToPrimitive(self, ctx, hint=""): @@ -358,7 +358,6 @@ class W_Boolean(W_Primitive): def __init__(self, boolval): - W_Primitive.__init__(self) self.boolval = bool(boolval) def ToObject(self, ctx): @@ -492,7 +491,9 @@ res = str(self.floatval) if (res[-3] == '+' or res[-3] == '-') and res[-2] == '0': - res = res[:-2] + res[-1] + cut = len(res) - 2 + assert cut >= 0 + res = res[:cut] + res[-1] return res def ToBoolean(self): 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 Wed Jun 4 19:24:27 2008 @@ -13,7 +13,6 @@ from pypy.lang.js.jscode import JsCode, JsFunction from constants import unescapedict from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.objectmodel import specialize import sys import os @@ -120,14 +119,14 @@ element.emit(bytecode) bytecode.emit('LOAD_ARRAY', len(self.nodes)) - at specialize.memo() -def _get_name(prefix, operand): - addoper = OPERANDS[operand] - if addoper: - addoper = '_' + prefix.upper() + addoper - else: - addoper = '' - return addoper +class Assignment(Expression): + def _get_name(self): + addoper = OPERANDS[self.operand] + if addoper: + addoper = '_' + self.prefix.upper() + addoper + else: + addoper = '' + return addoper OPERANDS = { '=' : '', @@ -156,32 +155,21 @@ elif self.atype == '--': bytecode.emit('DECR') -def new_simple_assignment(operand, prefix=''): - bytecode_name = 'STORE' + _get_name(prefix, operand) - class SimpleAssignment(Expression): - def __init__(self, pos, left, right): - self.identifier = left.get_literal() - self.right = right - self.pos = pos +class SimpleAssignment(Assignment): + 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): - if self.right is not None: - self.right.emit(bytecode) - bytecode.emit(bytecode_name, self.identifier) - return SimpleAssignment - -SIMPLE_ASSIGNMENTS = {} - -for operand in OPERANDS: - for prefix in ['', 'pre', 'post']: - SIMPLE_ASSIGNMENTS[(operand, prefix)] = new_simple_assignment(operand, prefix) - -def SimpleAssignment(pos, left, right, operand, prefix=''): - return SIMPLE_ASSIGNMENTS[(operand, prefix)](pos, left, right) - -# XXX VariableAssignment is not used at all, even should explode when -# translating, fix it with STORE_FAST and LOAD_FAST -class VariableAssignment(Expression): + def emit(self, bytecode): + if self.right is not None: + self.right.emit(bytecode) + bytecode_name = 'STORE' + self._get_name() + bytecode.emit_store(bytecode_name, self.identifier) + +class VariableAssignment(Assignment): def __init__(self, pos, left, right, operand): xxx # shall never land here for now self.identifier = left.identifier @@ -194,60 +182,40 @@ self.right.emit(bytecode) bytecode.emit('STORE_VAR', self.depth, self.identifier) -def new_member_assignment(operand, prefix): - bytecode_name = 'STORE_MEMBER' + _get_name(prefix, operand) - class MemberAssignment(Expression): - def __init__(self, pos, what, item, right): - # XXX we can optimise here what happens if what is identifier, - # but let's leave it alone for now - self.pos = pos - self.what = what - self.item = item - self.right = right +class MemberAssignment(Assignment): + 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 + self.what = what + self.item = item + self.right = right + self.operand = operand + self.prefix = prefix - def emit(self, bytecode): - if self.right is not None: - self.right.emit(bytecode) - self.item.emit(bytecode) - self.what.emit(bytecode) - bytecode.emit(bytecode_name) - return MemberAssignment - -MEMBER_ASSIGNMENTS = {} - -for operand in OPERANDS: - for prefix in ['', 'pre', 'post']: - MEMBER_ASSIGNMENTS[(operand, prefix)] = new_member_assignment(operand, prefix) - -def MemberAssignment(pos, what, item, right, operand, prefix=''): - return MEMBER_ASSIGNMENTS[(operand, prefix)](pos, what, item, right) - -def new_member_dot_assignment(operand, prefix): - bytecode_name = 'STORE_MEMBER' + _get_name(prefix, operand) - class MemberDotAssignment(Expression): - def __init__(self, pos, what, name, right): - self.pos = pos - self.what = what - self.itemname = name - self.right = right + def emit(self, bytecode): + if self.right is not None: + self.right.emit(bytecode) + self.item.emit(bytecode) + self.what.emit(bytecode) + bytecode.emit_store_member('STORE_MEMBER' + self._get_name()) - def emit(self, bytecode): - # XXX optimize this a bit - if self.right is not None: - self.right.emit(bytecode) - bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) - self.what.emit(bytecode) - bytecode.emit(bytecode_name) - return MemberDotAssignment - -MEMBER_DOT_ASSIGNMENTS = {} - -for operand in OPERANDS: - for prefix in ['', 'pre', 'post']: - MEMBER_DOT_ASSIGNMENTS[(operand, prefix)] = new_member_dot_assignment(operand, prefix) +class MemberDotAssignment(Assignment): + 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 MemberDotAssignment(pos, what, item, right, operand, prefix=''): - return MEMBER_DOT_ASSIGNMENTS[(operand, prefix)](pos, what, item, right) + def emit(self, bytecode): + # XXX optimize this a bit + if self.right is not None: + self.right.emit(bytecode) + bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) + self.what.emit(bytecode) + bytecode.emit_store_member('STORE_MEMBER' + self._get_name()) class Block(Statement): def __init__(self, pos, nodes): From santagada at codespeak.net Wed Jun 4 19:27:25 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 19:27:25 +0200 (CEST) Subject: [pypy-svn] r55570 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604172725.C79ED168431@codespeak.net> Author: santagada Date: Wed Jun 4 19:27:24 2008 New Revision: 55570 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py Log: common_call to simplify calling of functions 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 Wed Jun 4 19:27:24 2008 @@ -772,32 +772,31 @@ def eval(self, ctx, stack): stack.pop() +def common_call(ctx, r1, args, this, name): + if not isinstance(r1, W_PrimitiveObject): + raise ThrowException(W_String("%s is not a callable (%s)"%(r1.ToString(ctx), name))) + try: + res = r1.Call(ctx=ctx, args=args.tolist(), this=this) + except JsTypeError: + raise ThrowException(W_String("%s is not a function (%s)"%(r1.ToString(ctx), name))) + return res + class CALL(Opcode): def eval(self, ctx, stack): r1 = stack.pop() args = stack.pop() - if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("it is not a callable")) - try: - res = r1.Call(ctx=ctx, args=args.tolist(), this=None) - except JsTypeError: - raise ThrowException(W_String('it is not a function')) - stack.append(res) + name = r1.ToString(ctx) + #XXX hack, this should be comming from context + stack.append(common_call(ctx, r1, args, ctx.scope[-1], name)) class CALL_METHOD(Opcode): def eval(self, ctx, stack): method = stack.pop() what = stack.pop().ToObject(ctx) args = stack.pop() - r1 = what.Get(ctx, method.ToString()) - if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("it is not a callable")) - try: - res = r1.Call(ctx=ctx, args=args.tolist(), this=what) - except JsTypeError: - raise ThrowException(W_String('it is not a function')) - stack.append(res) - + name = method.ToString(ctx) + r1 = what.Get(ctx, name) + stack.append(common_call(ctx, r1, args, what, name)) class DUP(Opcode): def eval(self, ctx, stack): From fijal at codespeak.net Wed Jun 4 19:40:38 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 19:40:38 +0200 (CEST) Subject: [pypy-svn] r55572 - in pypy/branch/js-refactoring/pypy/lang/js: . test Message-ID: <20080604174038.8563E16847A@codespeak.net> Author: fijal Date: Wed Jun 4 19:40:36 2008 New Revision: 55572 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py pypy/branch/js-refactoring/pypy/lang/js/test/test_interp.py Log: Some translation fixes, one additional test. 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 Wed Jun 4 19:40:36 2008 @@ -476,22 +476,19 @@ return W_IntNumber(op1|op2) class URSH(BaseBinaryBitwiseOp): - @staticmethod - def eval(ctx, stack): + def eval(self, ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToUInt32(ctx) stack.append(W_IntNumber(op1 >> (op2 & 0x1F))) class RSH(BaseBinaryBitwiseOp): - @staticmethod - def eval(ctx, stack): + def eval(self, ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToInt32(ctx) stack.append(W_IntNumber(op1 >> intmask(op2 & 0x1F))) class LSH(BaseBinaryBitwiseOp): - @staticmethod - def eval(ctx, stack): + def eval(self, ctx, stack): op2 = stack.pop().ToUInt32(ctx) op1 = stack.pop().ToInt32(ctx) stack.append(W_IntNumber(op1 << intmask(op2 & 0x1F))) @@ -589,15 +586,15 @@ decision = staticmethod(ADD.operation) class STORE_MEMBER_POSTINCR(BaseStoreMember): - def operation(self): + def operation(self, *args): raise NotImplementedError class STORE_MEMBER_PREINCR(BaseStoreMember): - def operation(self): + def operation(self, *args): raise NotImplementedError class STORE_MEMBER_SUB(BaseStoreMember): - def operation(self): + def operation(self, *args): raise NotImplementedError class BaseStore(Opcode): @@ -906,7 +903,7 @@ class DELETE_MEMBER(Opcode): def eval(self, ctx, stack): - what = stack.pop().ToString() + what = stack.pop().ToString(ctx) obj = stack.pop().ToObject(ctx) stack.append(newbool(obj.Delete(what))) 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 Wed Jun 4 19:40:36 2008 @@ -572,8 +572,7 @@ return except KeyError: pass - # if not, we need to put this thing in current scope - self.variable.Put(self.get_global(), name, value) + self.variable.Put(self, name, value) def delete_identifier(self, name): for i in range(len(self.scope)-1, -1, -1): 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 Wed Jun 4 19:40:36 2008 @@ -566,6 +566,9 @@ py.test.skip("not supported") assertv("~1", -2) +def test_delete_member(): + assertv("x = 3; delete this.x", "true") + def test_twoarray(): assertp(""" a1 = new Array(); From fijal at codespeak.net Wed Jun 4 20:44:23 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 4 Jun 2008 20:44:23 +0200 (CEST) Subject: [pypy-svn] r55576 - pypy/branch/js-refactoring/pypy/translator/goal Message-ID: <20080604184423.971FD168445@codespeak.net> Author: fijal Date: Wed Jun 4 20:44:21 2008 New Revision: 55576 Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Log: Update the target to avoid interpreter PBC Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py ============================================================================== --- pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py (original) +++ pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Wed Jun 4 20:44:21 2008 @@ -7,11 +7,11 @@ # __________ Entry point __________ -interp = Interpreter() def entry_point(argv): if len(argv) == 2: t = load_file(argv[1]) + interp = Interpreter() interp.run(t) return 0 else: From santagada at codespeak.net Wed Jun 4 21:16:55 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 21:16:55 +0200 (CEST) Subject: [pypy-svn] r55577 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604191655.B6794168422@codespeak.net> Author: santagada Date: Wed Jun 4 21:16:52 2008 New Revision: 55577 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py pypy/branch/js-refactoring/pypy/lang/js/jsobj.py Log: new string operations, removal of ctx.Put and string objects and primitives are different things Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Wed Jun 4 21:16:52 2008 @@ -94,15 +94,23 @@ return create_object(ctx, 'String', Value = Value) return create_object(ctx, 'String', Value = W_String('')) +def create_array(ctx, elements=[]): + proto = ctx.get_global().Get(ctx, 'Array').Get(ctx, 'prototype') + array = W_Array(ctx, Prototype=proto, Class = proto.Class) + i = 0 + while i < len(elements): + array.Put(ctx, str(i), elements[i]) + i += 1 + + return array + class W_ArrayObject(W_NativeObject): def Call(self, ctx, args=[], this=None): - proto = ctx.get_global().Get(ctx, 'Array').Get(ctx, 'prototype') - array = W_Array(ctx, Prototype=proto, Class = proto.Class) if len(args) == 1 and isinstance(args[0], W_BaseNumber): + array = create_array(ctx) array.Put(ctx, 'length', args[0]) else: - for i in range(len(args)): - array.Put(ctx, str(i), args[i]) + array = create_array(ctx, args) return array def Construct(self, ctx, args=[]): @@ -353,6 +361,14 @@ return this.Value return W_ValueValueOf +class W_FromCharCode(W_NewBuiltin): + def Call(self, ctx, args=[], this=None): + temp = [] + for arg in args: + temp.append(chr(arg.ToInt32(ctx))) + + return W_String(''.join(temp)) + class W_CharAt(W_NewBuiltin): def Call(self, ctx, args=[], this=None): string = this.ToString(ctx) @@ -404,6 +420,32 @@ end = max(tmp1, tmp2) return W_String(string[start:end]) +class W_Split(W_NewBuiltin): + def Call(self, ctx, args=[], this=None): + string = this.ToString(ctx) + + if len(args) < 1 or args[0] is w_Undefined: + return create_array(ctx, [W_String(string)]) + else: + separator = args[0].ToString(ctx) + + if len(args) >= 2: + limit = args[1].ToUInt32(ctx) + raise ThrowException(W_String("limit not implemented")) + # array = string.split(separator, limit) + else: + array = string.split(separator) + + w_array = create_array(ctx) + i = 0 + while i < len(array): + w_str = W_String(array[i]) + w_array.Put(ctx, str(i), w_str) + i += 1 + + return w_array + + def common_join(ctx, this, sep=','): length = this.Get(ctx, 'length').ToUInt32(ctx) l = [] @@ -581,9 +623,11 @@ 'concat': W_Concat(ctx), 'indexOf': W_IndexOf(ctx), 'substring': W_Substring(ctx), + 'split': W_Split(ctx), }) w_String.Put(ctx, 'prototype', w_StrPrototype) + w_String.Put(ctx, 'fromCharCode', W_FromCharCode(ctx)) w_Global.Put(ctx, 'String', w_String) w_Array = W_ArrayObject('Array', w_FncPrototype) 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 Wed Jun 4 21:16:52 2008 @@ -740,7 +740,7 @@ w_obj.Put(ctx, 'constructor', w_func, flags = DE) w_func.Put(ctx, 'prototype', w_obj) if self.funcobj.name is not None: - ctx.Put(ctx, self.funcobj.name, w_func) + ctx.scope[-1].Put(ctx, self.funcobj.name, w_func) def __repr__(self): funcobj = self.funcobj @@ -756,7 +756,7 @@ self.name = name def eval(self, ctx, stack): - ctx.Put(ctx, self.name, w_Undefined, flags = DD) + ctx.scope[-1].Put(ctx, self.name, w_Undefined, flags = DD) def __repr__(self): return 'DECLARE_VAR "%s"' % (self.name,) 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 Wed Jun 4 21:16:52 2008 @@ -3,7 +3,6 @@ ovfcheck_float_to_int, NAN from pypy.lang.js.execution import ThrowException, JsTypeError,\ RangeError, ReturnException - DE = 1 DD = 2 RO = 4 @@ -390,15 +389,10 @@ def __repr__(self): return 'W_String(%s)' % (self.strval,) - def Get(self, ctx, P): #as hackinsh as can get - if P == 'length': - return W_FloatNumber(len(self.strval)) - else: - proto = ctx.get_global().Get(ctx, 'String').Get(ctx, 'prototype') - return proto.Get(ctx, P) - def ToObject(self, ctx): - return self #create_object(ctx, 'String', Value=self) + o = create_object(ctx, 'String', Value=self) + o.Put(ctx, 'length', W_IntNumber(len(self.strval)), flags = RO|DD) + return o def ToString(self, ctx=None): return self.strval @@ -588,10 +582,6 @@ pass return False - def Put(self, ctx, name, value, flags = 0): - assert name is not None - self.variable.Put(ctx, name, value, flags = flags) - def get_global(self): return self.scope[0] From santagada at codespeak.net Wed Jun 4 23:10:44 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Wed, 4 Jun 2008 23:10:44 +0200 (CEST) Subject: [pypy-svn] r55580 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080604211044.1095D16841B@codespeak.net> Author: santagada Date: Wed Jun 4 23:10:43 2008 New Revision: 55580 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/operations.py Log: 3 simple blocked blocks solved Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Wed Jun 4 23:10:43 2008 @@ -219,7 +219,7 @@ ch = strval[i] if ch == '%': if (i + 2 < lgt and _ishex(strval[i+1]) and _ishex(strval[i+2])): - ch = ord(int(strval[i + 1] + strval[i + 2], 16)) + ch = chr(int(strval[i + 1] + strval[i + 2], 16)) i += 2 elif (i + 5 < lgt and strval[i + 1] == 'u' and _ishex(strval[i + 2]) and _ishex(strval[i + 3]) and @@ -261,7 +261,7 @@ def Call(self, ctx, args=[], this=None): if len(args) >= 1: propname = args[0].ToString(ctx) - if propname in this.propdict and not this.propdict[propname].de: + if propname in this.propdict and not this.propdict[propname].flags & DE: return newbool(True) return newbool(False) 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 Wed Jun 4 23:10:43 2008 @@ -465,7 +465,7 @@ bytecode.emit('DELETE_MEMBER') elif isinstance(what, Member): what.left.emit(bytecode) - what.right.emit(bytecode) + what.expr.emit(bytecode) bytecode.emit('DELETE_MEMBER') else: what.left.emit(bytecode) From santagada at codespeak.net Thu Jun 5 04:37:26 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Thu, 5 Jun 2008 04:37:26 +0200 (CEST) Subject: [pypy-svn] r55583 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080605023726.34308168414@codespeak.net> Author: santagada Date: Thu Jun 5 04:37:23 2008 New Revision: 55583 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py pypy/branch/js-refactoring/pypy/lang/js/jscode.py Log: bugs related to tranlation, and reverted an adition to OpcodeMap generation Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Thu Jun 5 04:37:23 2008 @@ -224,6 +224,7 @@ elif (i + 5 < lgt and strval[i + 1] == 'u' and _ishex(strval[i + 2]) and _ishex(strval[i + 3]) and _ishex(strval[i + 4]) and _ishex(strval[i + 5])): + raise ThrowException(W_String('not implemented')) ch = unichr(int(strval[i+2:i+6], 16)) i += 5 i += 1 @@ -365,7 +366,12 @@ def Call(self, ctx, args=[], this=None): temp = [] for arg in args: - temp.append(chr(arg.ToInt32(ctx))) + i = arg.ToInt32(ctx) % 65536 # XXX should be uint16 + if i > 255: + raise ThrowException(W_String('not implemented')) + temp.append(unichr(i)) + else: + temp.append(chr(i)) return W_String(''.join(temp)) 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 Thu Jun 5 04:37:23 2008 @@ -2,8 +2,8 @@ from pypy.lang.js.jsobj import W_IntNumber, W_FloatNumber, W_String,\ W_Array, W_PrimitiveObject, ActivationObject,\ create_object, W_Object, w_Undefined, newbool,\ - w_True, w_False, W_List, w_Null, W_Iterator, W_Root,\ - DD, DE, RO + w_True, w_False, W_List, w_Null, W_Iterator, W_Root +import pypy.lang.js.jsobj as jsobj 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,\ @@ -18,7 +18,7 @@ def run_bytecode(opcodes, ctx, stack, check_stack=True, retlast=False): popped = False if retlast: - if opcodes[-1] == 'POP': + if isinstance(opcodes[-1], POP): opcodes.pop() popped = True @@ -358,7 +358,7 @@ callfunc=self.funcobj) w_func.Put(ctx, 'length', W_IntNumber(len(self.funcobj.params))) w_obj = create_object(ctx, 'Object') - w_obj.Put(ctx, 'constructor', w_func, flags = DE) + w_obj.Put(ctx, 'constructor', w_func, flags = jsobj.DE) w_func.Put(ctx, 'prototype', w_obj) stack.append(w_func) @@ -737,7 +737,7 @@ w_func = W_Object(ctx=ctx, Prototype=proto, Class='Function', callfunc=self.funcobj) w_func.Put(ctx, 'length', W_IntNumber(len(self.funcobj.params))) w_obj = create_object(ctx, 'Object') - w_obj.Put(ctx, 'constructor', w_func, flags = DE) + w_obj.Put(ctx, 'constructor', w_func, flags = jsobj.DE) w_func.Put(ctx, 'prototype', w_obj) if self.funcobj.name is not None: ctx.scope[-1].Put(ctx, self.funcobj.name, w_func) @@ -756,7 +756,7 @@ self.name = name def eval(self, ctx, stack): - ctx.scope[-1].Put(ctx, self.name, w_Undefined, flags = DD) + ctx.scope[-1].Put(ctx, self.name, w_Undefined, flags = jsobj.DD) def __repr__(self): return 'DECLARE_VAR "%s"' % (self.name,) @@ -856,7 +856,7 @@ class LOAD_ITERATOR(Opcode): def eval(self, ctx, stack): obj = stack.pop().ToObject(ctx) - props = [prop.value for prop in obj.propdict.values() if not prop.flags & DE] + props = [prop.value for prop in obj.propdict.values() if not prop.flags & jsobj.DE] stack.append(W_Iterator(props)) class JUMP_IF_ITERATOR_EMPTY(BaseJump): @@ -912,7 +912,7 @@ OpcodeMap = {} for name, value in locals().items(): - if name.upper() == name and type(value) == type(Opcode) and issubclass(value, Opcode): + if name.upper() == name and issubclass(value, Opcode): OpcodeMap[name] = value opcode_unrolling = unrolling_iterable(OpcodeMap.items()) From fijal at codespeak.net Thu Jun 5 04:52:51 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 04:52:51 +0200 (CEST) Subject: [pypy-svn] r55584 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080605025251.C215E16843E@codespeak.net> Author: fijal Date: Thu Jun 5 04:52:47 2008 New Revision: 55584 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py Log: This one was here for a purpose 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 Thu Jun 5 04:52:47 2008 @@ -912,7 +912,7 @@ OpcodeMap = {} for name, value in locals().items(): - if name.upper() == name and issubclass(value, Opcode): + if name.upper() == name and type(value) == type(Opcode) and issubclass(value, Opcode): OpcodeMap[name] = value opcode_unrolling = unrolling_iterable(OpcodeMap.items()) From fijal at codespeak.net Thu Jun 5 19:43:04 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 19:43:04 +0200 (CEST) Subject: [pypy-svn] r55595 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080605174304.EC4E1168406@codespeak.net> Author: fijal Date: Thu Jun 5 19:43:02 2008 New Revision: 55595 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/test/test_gateway.py Log: Add bool to unwrap_spec, feel free to revert Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Thu Jun 5 19:43:02 2008 @@ -213,7 +213,7 @@ def visit__object(self, typ): name = int_unwrapping_space_method(typ) - self.run_args.append("space.%s_w(%s)" % + self.run_args.append("space.%s(%s)" % (name, self.scopenext())) def visit_index(self, typ): @@ -328,7 +328,7 @@ def visit__object(self, typ): name = int_unwrapping_space_method(typ) - self.unwrap.append("space.%s_w(%s)" % (name, + self.unwrap.append("space.%s(%s)" % (name, self.nextarg())) def visit_index(self, typ): @@ -368,13 +368,15 @@ make_fastfunc = staticmethod(make_fastfunc) def int_unwrapping_space_method(typ): - assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong) + assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong, bool) if typ is r_int is r_longlong: - return 'r_longlong' + return 'r_longlong_w' elif typ is r_uint: - return 'uint' + return 'uint_w' + elif typ is bool: + return 'is_true' else: - return typ.__name__ + return typ.__name__ + '_w' class BuiltinCode(eval.Code): "The code object implementing a built-in (interpreter-level) hook." Modified: pypy/dist/pypy/interpreter/test/test_gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_gateway.py (original) +++ pypy/dist/pypy/interpreter/test/test_gateway.py Thu Jun 5 19:43:02 2008 @@ -155,6 +155,16 @@ space.call_function(w_app_g3, w('foo'), w('bar')), w('foobar')) + def test_interp2app_unwrap_spec_bool(self): + space = self.space + w = space.wrap + def g(space, b): + return space.wrap(b) + app_g = gateway.interp2app(g, unwrap_spec=[gateway.ObjSpace, bool]) + w_app_g = space.wrap(app_g) + assert self.space.eq_w(space.call_function(w_app_g, space.wrap(True)), + space.wrap(True)) + def test_interp2app_unwrap_spec_args_w(self): space = self.space w = space.wrap From fijal at codespeak.net Thu Jun 5 20:17:58 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 20:17:58 +0200 (CEST) Subject: [pypy-svn] r55596 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080605181758.963C016840C@codespeak.net> Author: fijal Date: Thu Jun 5 20:17:58 2008 New Revision: 55596 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/test/test_executioncontext.py Log: Support for low level profiling Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Jun 5 20:17:58 2008 @@ -5,6 +5,11 @@ def new_framestack(): return Stack() +def app_profile_call(space, w_callable, frame, event, w_arg): + w_result = space.call_function(w_callable, + space.wrap(frame), + space.wrap(event), w_arg) + class ExecutionContext: """An ExecutionContext holds the state of an execution thread in the Python interpreter.""" @@ -13,11 +18,12 @@ self.space = space self.framestack = new_framestack() self.w_tracefunc = None - self.w_profilefunc = None self.is_tracing = 0 self.ticker = 0 self.pending_actions = [] self.compiler = space.createcompiler() + self.profilefunc = None + self.w_profilefuncarg = None def enter(self, frame): if self.framestack.depth() > self.space.sys.recursionlimit: @@ -32,7 +38,7 @@ self.framestack.push(frame) def leave(self, frame): - if self.w_profilefunc: + if self.profilefunc: self._trace(frame, 'leaveframe', None) if not frame.hide(): @@ -45,19 +51,22 @@ def __init__(self): self.framestack = new_framestack() self.w_tracefunc = None - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None self.is_tracing = 0 def enter(self, ec): ec.framestack = self.framestack ec.w_tracefunc = self.w_tracefunc - ec.w_profilefunc = self.w_profilefunc + ec.profilefunc = self.profilefunc + ec.w_profilefuncarg = self.w_profilefuncarg ec.is_tracing = self.is_tracing def leave(self, ec): self.framestack = ec.framestack self.w_tracefunc = ec.w_tracefunc - self.w_profilefunc = ec.w_profilefunc + self.profilefunc = ec.profilefunc + self.w_profilefuncarg = ec.w_profilefuncarg self.is_tracing = ec.is_tracing # the following interface is for pickling and unpickling @@ -182,9 +191,17 @@ def setprofile(self, w_func): """Set the global trace function.""" if self.space.is_w(w_func, self.space.w_None): - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None else: - self.w_profilefunc = w_func + self.w_profilefuncarg = w_func + self.profilefunc = app_profile_call + + def setllprofile(self, func, w_arg): + self.profilefunc = func + if func is not None and w_arg is None: + raise ValueError("Cannot call setllprofile with real None") + self.w_profilefuncarg = w_arg def call_tracing(self, w_func, w_args): is_tracing = self.is_tracing @@ -229,7 +246,7 @@ frame.locals2fast() # Profile cases - if self.w_profilefunc is not None: + if self.profilefunc is not None: if event not in ['leaveframe', 'call']: return @@ -242,11 +259,11 @@ self.is_tracing += 1 try: try: - w_result = space.call_function(self.w_profilefunc, - space.wrap(frame), - space.wrap(event), w_arg) + self.profilefunc(space, self.w_profilefuncarg, + frame, event, w_arg) except: - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None raise finally: Modified: pypy/dist/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/dist/pypy/interpreter/test/test_executioncontext.py Thu Jun 5 20:17:58 2008 @@ -34,3 +34,19 @@ assert a1.counter == 1 assert a2.counter == 10 assert a3.counter == 1 + + def test_llprofile(self): + l = [] + + def profile_func(space, w_arg, event, frame, w_aarg): + assert w_arg is space.w_None + l.append(frame) + + space = self.space + space.getexecutioncontext().setllprofile(profile_func, space.w_None) + space.appexec([], """(): + pass + """) + space.getexecutioncontext().setllprofile(None, None) + assert l == ['call', 'return', 'call', 'return'] + From fijal at codespeak.net Thu Jun 5 21:57:54 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 21:57:54 +0200 (CEST) Subject: [pypy-svn] r55605 - in pypy/dist/pypy/module/_lsprof: . testing Message-ID: <20080605195754.C236D168418@codespeak.net> Author: fijal Date: Thu Jun 5 21:57:53 2008 New Revision: 55605 Added: pypy/dist/pypy/module/_lsprof/ (props changed) pypy/dist/pypy/module/_lsprof/__init__.py (contents, props changed) pypy/dist/pypy/module/_lsprof/interp_lsprof.py (contents, props changed) pypy/dist/pypy/module/_lsprof/testing/ (props changed) pypy/dist/pypy/module/_lsprof/testing/__init__.py (contents, props changed) pypy/dist/pypy/module/_lsprof/testing/test_cprofile.py (contents, props changed) Log: _lsprof module. Not enough to past test yet, but I'm not sure whether test is faulty or module is not doing well (ie if we track builtin calls or not) Added: pypy/dist/pypy/module/_lsprof/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_lsprof/__init__.py Thu Jun 5 21:57:53 2008 @@ -0,0 +1,12 @@ + +""" _lsprof module +""" + +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + applevelname = '_lsprof' + + interpleveldefs = {'Profiler':'interp_lsprof.W_Profiler'} + + appleveldefs = {} Added: pypy/dist/pypy/module/_lsprof/interp_lsprof.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_lsprof/interp_lsprof.py Thu Jun 5 21:57:53 2008 @@ -0,0 +1,232 @@ + +from pypy.interpreter.baseobjspace import (W_Root, ObjSpace, Wrappable, + Arguments) +from pypy.interpreter.typedef import (TypeDef, GetSetProperty, + interp_attrproperty) +from pypy.interpreter.gateway import interp2app +import time + +class W_StatsEntry(Wrappable): + def __init__(self, space, frame, callcount, reccallcount, tt, it, + w_sublist): + self.frame = frame + self.callcount = callcount + self.reccallcount = reccallcount + self.it = it + self.tt = tt + self.w_calls = w_sublist + + def get_calls(space, self): + return self.w_calls + +W_StatsEntry.typedef = TypeDef( + 'StatsEntry', + code = interp_attrproperty('frame', W_StatsEntry), + callcount = interp_attrproperty('callcount', W_StatsEntry), + reccallcount = interp_attrproperty('reccallcount', W_StatsEntry), + inlinetime = interp_attrproperty('it', W_StatsEntry), + totaltime = interp_attrproperty('tt', W_StatsEntry), + calls = GetSetProperty(W_StatsEntry.get_calls), +) + +class W_StatsSubEntry(Wrappable): + def __init__(self, space, frame, callcount, reccallcount, tt, it): + self.frame = frame + self.callcount = callcount + self.reccallcount = reccallcount + self.it = it + self.tt = tt + +W_StatsSubEntry.typedef = TypeDef( + 'SubStatsEntry', + code = interp_attrproperty('frame', W_StatsSubEntry), + callcount = interp_attrproperty('callcount', W_StatsSubEntry), + reccallcount = interp_attrproperty('reccallcount', W_StatsSubEntry), + inlinetime = interp_attrproperty('it', W_StatsSubEntry), + totaltime = interp_attrproperty('tt', W_StatsSubEntry), +) + +def stats(space, data, factor): + l_w = [] + for v in data.values(): + if v.callcount != 0: + l_w.append(v.stats(space, factor)) + return space.newlist(l_w) + +class ProfilerEntry(object): + def __init__(self, frame): + self.frame = frame + self.tt = 0 + self.it = 0 + self.callcount = 0 + self.recursivecallcount = 0 + self.recursionLevel = 0 + self.calls = {} + + def stats(self, space, factor): + if self.calls: + w_sublist = space.newlist([sub_entry.stats(space, self, factor) + for sub_entry in self.calls.values()]) + else: + w_sublist = space.w_None + w_se = W_StatsEntry(space, self.frame, self.callcount, + self.recursivecallcount, + factor * self.tt, factor * self.it, w_sublist) + return space.wrap(w_se) + +class ProfilerSubEntry(object): + def __init__(self, caller): + # self.key = caller # XXX why? + self.tt = 0 + self.it = 0 + self.callcount = 0 + self.recursivecallcount = 0 + self.recursionLevel = 0 + + def stats(self, space, parent, factor): + w_sse = W_StatsSubEntry(space, parent.frame, + self.callcount, self.recursivecallcount, + factor * self.tt, factor * self.it) + return space.wrap(w_sse) + +class ProfilerContext(object): + def __init__(self, profobj, entry): + self.entry = entry + self.subt = 0 + self.previous = profobj.current_context + entry.recursionLevel += 1 + if profobj.subcalls and self.previous: + subentry = ProfilerSubEntry(entry) + entry.calls[entry] = subentry + subentry.recursionLevel += 1 + self.t0 = profobj.timer() + + def _stop(self, profobj, entry): + # XXX factor out two pieces of the same code + tt = profobj.timer() - self.t0 + it = tt - self.subt + if self.previous: + self.previous.subt += tt + entry.recursionLevel -= 1 + if entry.recursionLevel == 0: + entry.tt += tt + else: + entry.recursivecallcount += 1 + entry.it += it + entry.callcount += 1 + if profobj.subcalls and self.previous: + caller = self.previous.entry + try: + subentry = caller.calls[entry] + except KeyError: + pass + else: + subentry.recursionLevel -= 1 + if subentry.recursionLevel == 0: + subentry.tt += tt + else: + subentry.recursivecallcount += 1 + subentry.it += it + subentry.callcount += 1 + +def lsprof_call(space, w_self, frame, event, w_arg): + assert isinstance(w_self, W_Profiler) + if event == 'call': + w_self._enter_call(frame.getcode()) + elif event == 'return': + w_self._enter_return(frame.getcode()) + else: + raise NotImplementedError("Call to %s" % event) + # we don't support builtin calls here... + +class W_Profiler(Wrappable): + def __init__(self, space, w_callable, time_unit, subcalls, builtins): + self.subcalls = subcalls + self.builtins = builtins + self.current_context = None + self.w_callable = w_callable + self.time_unit = time_unit + # XXX _lsprof uses rotatingtree. We use plain dict here, + # not sure how big difference is, but we should probably + # implement rotating tree + self.data = {} + self.space = space + + def timer(self): + if self.w_callable: + space = self.space + return space.float_w(space.call_function(self.w_callable)) + return time.time() + + def enable(self, space, subcalls=True, builtins=True): + self.subcalls = subcalls + self.builtins = builtins + # set profiler hook + space.getexecutioncontext().setllprofile(lsprof_call, space.wrap(self)) + enable.unwrap_spec = ['self', ObjSpace, bool, bool] + + def _enter_call(self, f_code): + # we have superb gc, no point in freelist :) + try: + entry = self.data[f_code] + except KeyError: + entry = ProfilerEntry(f_code) + self.data[f_code] = entry + self.current_context = ProfilerContext(self, entry) + + def _enter_return(self, f_code): + context = self.current_context + if context is None: + return + try: + entry = self.data[f_code] + context._stop(self, entry) + except KeyError: + pass + self.current_context = context.previous + + def _flush_unmatched(self): + context = self.current_context + while context: + entry = context.entry + if entry: + context._stop(self, entry) + context = context.previous + self.current_context = None + + def disable(self, space): + # unset profiler hook + self._flush_unmatched() + space.getexecutioncontext().setllprofile(None, None) + disable.unwrap_spec = ['self', ObjSpace] + + def delete(self, space): + self._flush_unmatched() + space.getexecutioncontext().setllprofile(None, None) + delete.unwrap_spec = ['self', ObjSpace] + + def getstats(self, space): + if self.w_callable is None: + factor = 0.000001 + elif self.time_unit > 0.0: + factor = self.time_unit + else: + factor = 1.0 / sys.maxint + return stats(space, self.data, factor) + getstats.unwrap_spec = ['self', ObjSpace] + +def descr_new_profile(space, w_type, w_callable=None, time_unit=0.0, + subcalls=True, builtins=True): + p = space.allocate_instance(W_Profiler, w_type) + p.__init__(space, w_callable, time_unit, subcalls, builtins) + return space.wrap(p) +descr_new_profile.unwrap_spec = [ObjSpace, W_Root, W_Root, float, bool, bool] + +W_Profiler.typedef = TypeDef( + 'Profiler', + __new__ = interp2app(descr_new_profile), + enable = interp2app(W_Profiler.enable), + disable = interp2app(W_Profiler.disable), + getstats = interp2app(W_Profiler.getstats), + __del__ = interp2app(W_Profiler.delete), +) Added: pypy/dist/pypy/module/_lsprof/testing/__init__.py ============================================================================== Added: pypy/dist/pypy/module/_lsprof/testing/test_cprofile.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_lsprof/testing/test_cprofile.py Thu Jun 5 21:57:53 2008 @@ -0,0 +1,133 @@ + +from pypy.conftest import gettestobjspace + +class AppTestCProfile(object): + def setup_class(cls): + space = gettestobjspace(usemodules=('_lsprof',)) + cls.w_expected_output = space.wrap(expected_output) + cls.space = space + + def test_cprofile(self): + skip("fails") + import sys + from cProfile import Profile + from test.profilee import testfunc, timer + + methodnames = ['print_stats', 'print_callers', 'print_callees'] + + def do_profiling(cls): + results = [] + prof = cls(timer, 0.001) + start_timer = timer() + prof.runctx("testfunc()", {'testfunc':testfunc}, locals()) + results.append(timer() - start_timer) + for methodname in methodnames: + import pstats + from StringIO import StringIO + s = StringIO() + stats = pstats.Stats(prof, stream=s) + stats.strip_dirs().sort_stats("stdname") + getattr(stats, methodname)() + results.append(s.getvalue()) + return results + + res = do_profiling(Profile) + assert res[0] == 1000 + for i, method in enumerate(methodnames): + if not res[i + 1] == self.expected_output[method]: + print method + print res[i + 1] + print self.expected_output[method] + assert 0 + #assert res[i + 1] == self.expected_output[method] + +expected_output = {} +expected_output['print_stats'] = """\ + 127 function calls (107 primitive calls) in 999.749 CPU seconds + + Ordered by: standard name + + ncalls tottime percall cumtime percall filename:lineno(function) + 4 -0.004 -0.001 -0.004 -0.001 :0(append) + 4 -0.004 -0.001 -0.004 -0.001 :0(exc_info) + 12 -0.024 -0.002 11.964 0.997 :0(hasattr) + 8 -0.008 -0.001 -0.008 -0.001 :0(range) + 1 0.000 0.000 0.000 0.000 :0(setprofile) + 1 -0.002 -0.002 999.751 999.751 :1() + 0 0.000 0.000 profile:0(profiler) + 1 -0.002 -0.002 999.749 999.749 profile:0(testfunc()) + 28 27.972 0.999 27.972 0.999 profilee.py:110(__getattr__) + 1 269.996 269.996 999.753 999.753 profilee.py:25(testfunc) + 23/3 149.937 6.519 169.917 56.639 profilee.py:35(factorial) + 20 19.980 0.999 19.980 0.999 profilee.py:48(mul) + 2 39.986 19.993 599.814 299.907 profilee.py:55(helper) + 4 115.984 28.996 119.964 29.991 profilee.py:73(helper1) + 2 -0.006 -0.003 139.942 69.971 profilee.py:84(helper2_indirect) + 8 311.976 38.997 399.896 49.987 profilee.py:88(helper2) + 8 63.968 7.996 79.944 9.993 profilee.py:98(subhelper) + + +""" +expected_output['print_callers'] = """\ + Ordered by: standard name + +Function was called by... +:0(append) <- profilee.py:73(helper1)(4) 119.964 +:0(exc_info) <- profilee.py:73(helper1)(4) 119.964 +:0(hasattr) <- profilee.py:73(helper1)(4) 119.964 + profilee.py:88(helper2)(8) 399.896 +:0(range) <- profilee.py:98(subhelper)(8) 79.944 +:0(setprofile) <- profile:0(testfunc())(1) 999.749 +:1() <- profile:0(testfunc())(1) 999.749 +profile:0(profiler) <- +profile:0(testfunc()) <- profile:0(profiler)(1) 0.000 +profilee.py:110(__getattr__) <- :0(hasattr)(12) 11.964 + profilee.py:98(subhelper)(16) 79.944 +profilee.py:25(testfunc) <- :1()(1) 999.751 +profilee.py:35(factorial) <- profilee.py:25(testfunc)(1) 999.753 + profilee.py:35(factorial)(20) 169.917 + profilee.py:84(helper2_indirect)(2) 139.942 +profilee.py:48(mul) <- profilee.py:35(factorial)(20) 169.917 +profilee.py:55(helper) <- profilee.py:25(testfunc)(2) 999.753 +profilee.py:73(helper1) <- profilee.py:55(helper)(4) 599.814 +profilee.py:84(helper2_indirect) <- profilee.py:55(helper)(2) 599.814 +profilee.py:88(helper2) <- profilee.py:55(helper)(6) 599.814 + profilee.py:84(helper2_indirect)(2) 139.942 +profilee.py:98(subhelper) <- profilee.py:88(helper2)(8) 399.896 + + +""" +expected_output['print_callees'] = """\ + Ordered by: standard name + +Function called... +:0(append) -> +:0(exc_info) -> +:0(hasattr) -> profilee.py:110(__getattr__)(12) 27.972 +:0(range) -> +:0(setprofile) -> +:1() -> profilee.py:25(testfunc)(1) 999.753 +profile:0(profiler) -> profile:0(testfunc())(1) 999.749 +profile:0(testfunc()) -> :0(setprofile)(1) 0.000 + :1()(1) 999.751 +profilee.py:110(__getattr__) -> +profilee.py:25(testfunc) -> profilee.py:35(factorial)(1) 169.917 + profilee.py:55(helper)(2) 599.814 +profilee.py:35(factorial) -> profilee.py:35(factorial)(20) 169.917 + profilee.py:48(mul)(20) 19.980 +profilee.py:48(mul) -> +profilee.py:55(helper) -> profilee.py:73(helper1)(4) 119.964 + profilee.py:84(helper2_indirect)(2) 139.942 + profilee.py:88(helper2)(6) 399.896 +profilee.py:73(helper1) -> :0(append)(4) -0.004 + :0(exc_info)(4) -0.004 + :0(hasattr)(4) 11.964 +profilee.py:84(helper2_indirect) -> profilee.py:35(factorial)(2) 169.917 + profilee.py:88(helper2)(2) 399.896 +profilee.py:88(helper2) -> :0(hasattr)(8) 11.964 + profilee.py:98(subhelper)(8) 79.944 +profilee.py:98(subhelper) -> :0(range)(8) -0.008 + profilee.py:110(__getattr__)(16) 27.972 + + +""" From fijal at codespeak.net Thu Jun 5 22:15:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 22:15:31 +0200 (CEST) Subject: [pypy-svn] r55606 - pypy/dist/pypy/module/_lsprof Message-ID: <20080605201531.9D769168419@codespeak.net> Author: fijal Date: Thu Jun 5 22:15:31 2008 New Revision: 55606 Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py Log: Fix translation Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/interp_lsprof.py (original) +++ pypy/dist/pypy/module/_lsprof/interp_lsprof.py Thu Jun 5 22:15:31 2008 @@ -4,7 +4,7 @@ from pypy.interpreter.typedef import (TypeDef, GetSetProperty, interp_attrproperty) from pypy.interpreter.gateway import interp2app -import time +import time, sys class W_StatsEntry(Wrappable): def __init__(self, space, frame, callcount, reccallcount, tt, it, From fijal at codespeak.net Thu Jun 5 22:47:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 22:47:31 +0200 (CEST) Subject: [pypy-svn] r55609 - pypy/branch/interpreter-optimizations Message-ID: <20080605204731.5163F168404@codespeak.net> Author: fijal Date: Thu Jun 5 22:47:29 2008 New Revision: 55609 Removed: pypy/branch/interpreter-optimizations/ Log: Remove dead branch From fijal at codespeak.net Thu Jun 5 22:48:24 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 5 Jun 2008 22:48:24 +0200 (CEST) Subject: [pypy-svn] r55610 - pypy/branch/c-backend-fun Message-ID: <20080605204824.07441168413@codespeak.net> Author: fijal Date: Thu Jun 5 22:48:24 2008 New Revision: 55610 Added: pypy/branch/c-backend-fun/ - copied from r55609, pypy/dist/ Log: A branch to experiment a bit with C backend From afa at codespeak.net Thu Jun 5 23:57:41 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 5 Jun 2008 23:57:41 +0200 (CEST) Subject: [pypy-svn] r55613 - in pypy/branch/build-external/pypy: module/__builtin__/test rpython/lltypesystem Message-ID: <20080605215741.9A2F91683E8@codespeak.net> Author: afa Date: Thu Jun 5 23:57:40 2008 New Revision: 55613 Added: pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/ll2ctypes.py Log: First step towards extension modules for Pypy: This test compiles a shared library that uses some space operations, and runs them on top of an *interpreted* object space. The interesting thing it that it should be possible to use the same compiled .dll (or .so) on both a translated pypy-c or the interpreted bin/py.py. I learned a lot about various aspects of the translation. Very hard. Many aspects of the code could be improved... Comments are warmly welcome! My next step is to add more space operations, enough to build and load a module into the pypy interpreter. Added: pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py ============================================================================== --- (empty file) +++ pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py Thu Jun 5 23:57:40 2008 @@ -0,0 +1,182 @@ +from pypy.objspace.std.objspace import StdObjSpace, W_Object +from pypy.annotation.policy import AnnotatorPolicy +from pypy.annotation.binaryop import BINARY_OPERATIONS +from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes +from pypy.rlib.unroll import unrolling_iterable +from pypy.rlib.nonconst import NonConstant + +# XXX Most of this module is an assembly of various hacks + +# XXX Many space operations are missing + +# XXX Need a way to check that both sides actually compiled the same +# PyPyApi structure (e.g. a magic number) + +class PyPyObjectType(lltype.OpaqueType): + """An opaque object representing a Python object. + When interpreted, it wraps a PyObject* containing a W_Object. + When translated, it wraps a pointer to the translated W_Object structure. + It plays the same role as the PyObject* in the CPython API. + """ + _gckind = 'raw' + __name__ = 'PyPyObject' + def __init__(self): + lltype.OpaqueType.__init__(self, 'PyPyObject') + self.hints['external'] = 'C' + self.hints['c_name'] = 'struct PyPyObject' + self.hints['getsize'] = lambda: 4 + def __str__(self): + return "PyPyObject" + +PyPyObject = lltype.Ptr(PyPyObjectType()) + +BINARY_OP_TP = rffi.CCallback([PyPyObject, PyPyObject], PyPyObject) +UNARY_OP_TP = rffi.CCallback([PyPyObject], PyPyObject) +NEWINT_TP = rffi.CCallback([rffi.LONG], PyPyObject) +IS_TRUE_TP = rffi.CCallback([PyPyObject], lltype.Bool) + +# definition of the PyPy API. +# XXX should use the ObjSpace.MethodTable +API_FIELDS = [(op, BINARY_OP_TP) for op in BINARY_OPERATIONS if '_' not in op] + +# some of the ObjSpace.IrregularOpTable items +API_FIELDS.append(('newint', NEWINT_TP)) +API_FIELDS.append(('getattr', UNARY_OP_TP)) +API_FIELDS.append(('is_true', IS_TRUE_TP)) + +PyPyApiStruct = lltype.Struct('pypy_api', *API_FIELDS) + +class ExtensionObjSpace(StdObjSpace): + """This is the object space seen when external functions are annotated. + most space operations are directed to one member of the API structure. + """ + def __init__(self, apiptr): + StdObjSpace.__init__(self) + self.apiptr = apiptr + + def initialize(self): + StdObjSpace.initialize(self) + + for name, _ in API_FIELDS: + def wrapperFunc(name): + def f(*args): + return getattr(self.apiptr[0], name)(*args) + return f + + setattr(self, name, wrapperFunc(name)) + +class ExtensionAnnotatorPolicy(AnnotatorPolicy): + allow_someobjects = False + + def specialize__wrap(pol, funcdesc, args_s): + # Do not create frozen wrapped constant + typ = args_s[1].knowntype + return funcdesc.cachedgraph(typ) + +# The API structure is initialized in the main interpreter, with +# functions based on the standard ObjSpace. +# The fonctions pointers are then passed to the extension module, +# which may use them. + +# All the API is serialized into a single string: a commma-separated +# list of numbers, representing the functions pointers :-) +def serializeAPI(space): + import ctypes + + # XXX Could not find better + keepalives = [] + def objectToNumber(object): + keepalives.append(object) + return id(object) + def numberToObject(number): + return ctypes.cast(number, ctypes.py_object).value + + callbacks = [] + for name, FNTYPE in API_FIELDS: + def makefunc(name=name, FNTYPE=FNTYPE): + # Build a C callback into the main object space. + # The hard part is to convert a pypy.objspace.std.objspace.W_Object + # (a CPython pointer), into a PyPyObject (a lltype pointer) + def func(*args): + newargs = [] + for arg, ARG in zip(args, FNTYPE.TO.ARGS): + if ARG is PyPyObject: + arg = numberToObject(arg._obj._storage) + newargs.append(arg) + + cres = getattr(space, name)(*newargs) + + if FNTYPE.TO.RESULT is PyPyObject: + assert isinstance(cres, W_Object) + return rffi.cast(PyPyObject, objectToNumber(cres)) + else: + return cres + llfunc = rffi.llhelper(FNTYPE, func) + return ll2ctypes.lltype2ctypes(llfunc) + callbacks.append(makefunc()) + + addresses = ",".join(str(ctypes.cast(c, ctypes.c_void_p).value) + for c in callbacks) + + return addresses + +api_field_names = unrolling_iterable(enumerate(API_FIELDS)) +def unserializeAPI(addresses): + """This function is translated into the extension library. + it takes a list of numbers, considers they are function pointers, + and uses them to allocate a PyPyApi structure. + """ + apimembers = addresses.split(",") + api = lltype.malloc(PyPyApiStruct, flavor='raw') + for i, (name, FNTYPE) in api_field_names: + address = int(apimembers[i]) + funcptr = lltype.cast_int_to_ptr(FNTYPE, address) + setattr(api, name, funcptr) + return api + +def compile(apiptr, func): + stdobjspace = StdObjSpace() + stdobjspace.initialize() + + addresses = serializeAPI(stdobjspace) + + def exportedfunc(addresses): + api = unserializeAPI(addresses) + apiptr[0] = api + func() + + from pypy.translator.interactive import Translation + t = Translation(exportedfunc, [str], policy=ExtensionAnnotatorPolicy()) + t.annotate() + t.rtype() + f = t.compile_c() + + def returnedfunc(): + f(addresses) + + return returnedfunc + + +# Now the interesting part +def test_extension_function(): + apiptr = lltype.malloc(lltype.Array(lltype.Ptr(PyPyApiStruct)), + 1, immortal=True) + + space = ExtensionObjSpace(apiptr) + + def func(): + # (42 * 2) + 5 == 89 + w_x = space.wrap(42) + w_y = space.mul(w_x, space.wrap(2)) + w_res = space.add(w_y, space.wrap(5)) + + if space.is_true(space.eq(w_res, space.wrap(89))): + print "OK!" + + # Negative test, to be sure that space.is_true does not return garbage. + if space.is_true(space.eq(w_res, space.wrap(85))): + print "KO!" + + f = compile(apiptr, func) + + f() # XXX catch stdout and check the presence of the "OK!" string Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/ll2ctypes.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/ll2ctypes.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/ll2ctypes.py Thu Jun 5 23:57:40 2008 @@ -28,6 +28,7 @@ lltype.Signed: ctypes.c_long, lltype.Unsigned: ctypes.c_ulong, lltype.Char: ctypes.c_ubyte, + lltype.Bool: ctypes.c_ubyte, rffi.DOUBLE: ctypes.c_double, rffi.FLOAT: ctypes.c_float, rffi.SIGNEDCHAR: ctypes.c_byte, @@ -169,6 +170,8 @@ argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS] if T.TO.RESULT is lltype.Void: restype = None + elif isinstance(T.TO.RESULT, lltype.Ptr): + restype = ctypes.c_void_p else: restype = get_ctypes_type(T.TO.RESULT) return ctypes.CFUNCTYPE(restype, *argtypes) @@ -438,6 +441,11 @@ assert lltype.typeOf(llres) == T.TO.RESULT if T.TO.RESULT is lltype.Void: return None + elif (isinstance(T.TO.RESULT, lltype.Ptr) and + isinstance(T.TO.RESULT.TO, lltype.OpaqueType)): + # XXX not sure of this + ret = lltype2ctypes(llres) + return ctypes.cast(ret.contents, ctypes.c_void_p).value else: return lltype2ctypes(llres) res = ctypes_func_type(callback) @@ -521,6 +529,7 @@ _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): container = lltype._opaque(T.TO) + container._storage = cobj else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) From fijal at codespeak.net Fri Jun 6 01:13:59 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 01:13:59 +0200 (CEST) Subject: [pypy-svn] r55615 - pypy/branch/c-backend-fun/pypy/translator/oosupport Message-ID: <20080605231359.6781516843E@codespeak.net> Author: fijal Date: Fri Jun 6 01:13:58 2008 New Revision: 55615 Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Log: Force inlining more often Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py ============================================================================== --- pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py (original) +++ pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Fri Jun 6 01:13:58 2008 @@ -33,7 +33,12 @@ # TODO: analyze graphs to determine which functions calls could have # side effects and which can be inlined safely. -def can_be_inlined(op): +def can_be_inlined(op, block): + for exit in block.exits: + if op.result in exit.args: + break + else: + return True try: llop = LL_OPERATIONS[op.opname] return llop.canfold @@ -64,7 +69,7 @@ for i, v in enumerate(op.args): if var_count.get(v, None) == 1 and v not in block.inputargs: # "inline" the operation sub_i, sub_op = var_to_op[v] - if can_be_inlined(sub_op): + if can_be_inlined(sub_op, block): op.args[i] = SubOperation(sub_op) block.operations[sub_i] = None if block.operations != (): From afa at codespeak.net Fri Jun 6 01:17:20 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Fri, 6 Jun 2008 01:17:20 +0200 (CEST) Subject: [pypy-svn] r55616 - pypy/branch/build-external/pypy/module/__builtin__/test Message-ID: <20080605231720.42BE116845F@codespeak.net> Author: afa Date: Fri Jun 6 01:17:19 2008 New Revision: 55616 Modified: pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py Log: Export all regular methods of the object space Need a way to create PyPyApi functions that are not ObjSpace methods. Modified: pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/test/test_extension.py Fri Jun 6 01:17:19 2008 @@ -1,9 +1,8 @@ from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.annotation.policy import AnnotatorPolicy -from pypy.annotation.binaryop import BINARY_OPERATIONS from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.nonconst import NonConstant +from pypy.rlib.objectmodel import we_are_translated # XXX Most of this module is an assembly of various hacks @@ -30,19 +29,17 @@ PyPyObject = lltype.Ptr(PyPyObjectType()) -BINARY_OP_TP = rffi.CCallback([PyPyObject, PyPyObject], PyPyObject) -UNARY_OP_TP = rffi.CCallback([PyPyObject], PyPyObject) -NEWINT_TP = rffi.CCallback([rffi.LONG], PyPyObject) -IS_TRUE_TP = rffi.CCallback([PyPyObject], lltype.Bool) - # definition of the PyPy API. -# XXX should use the ObjSpace.MethodTable -API_FIELDS = [(op, BINARY_OP_TP) for op in BINARY_OPERATIONS if '_' not in op] +API_FIELDS = [] + +# regular part of the interface +for name, symbol, nbargs, special in StdObjSpace.MethodTable: + FUNCTYPE = rffi.CCallback([PyPyObject] * nbargs, PyPyObject) + API_FIELDS.append((name, FUNCTYPE)) # some of the ObjSpace.IrregularOpTable items -API_FIELDS.append(('newint', NEWINT_TP)) -API_FIELDS.append(('getattr', UNARY_OP_TP)) -API_FIELDS.append(('is_true', IS_TRUE_TP)) +API_FIELDS.append(('newint', rffi.CCallback([rffi.LONG], PyPyObject))) +API_FIELDS.append(('is_true', rffi.CCallback([PyPyObject], lltype.Bool))) PyPyApiStruct = lltype.Struct('pypy_api', *API_FIELDS) @@ -60,7 +57,10 @@ for name, _ in API_FIELDS: def wrapperFunc(name): def f(*args): - return getattr(self.apiptr[0], name)(*args) + if we_are_translated(): + return getattr(self.apiptr[0], name)(*args) + else: + return getattr(StdObjSpace, name)(self, *args) return f setattr(self, name, wrapperFunc(name)) @@ -180,3 +180,17 @@ f = compile(apiptr, func) f() # XXX catch stdout and check the presence of the "OK!" string + +def test_more_operations(): + return # in-progress + + apiptr = lltype.malloc(lltype.Array(lltype.Ptr(PyPyApiStruct)), + 1, immortal=True) + + space = ExtensionObjSpace(apiptr) + + def func(): + space.len(space.wrap("mmap")) + + f = compile(apiptr, func) + f() From fijal at codespeak.net Fri Jun 6 02:49:29 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 02:49:29 +0200 (CEST) Subject: [pypy-svn] r55617 - in pypy/dist/lib-python/modified-2.4.1: . test Message-ID: <20080606004929.8E132168415@codespeak.net> Author: fijal Date: Fri Jun 6 02:49:26 2008 New Revision: 55617 Added: pypy/dist/lib-python/modified-2.4.1/cProfile.py (contents, props changed) pypy/dist/lib-python/modified-2.4.1/pstats.py (contents, props changed) pypy/dist/lib-python/modified-2.4.1/test/profilee.py (contents, props changed) Log: Some CPython's stdlib parts which are not in 2.4.1 Not sure if this is a right directory for such stuff. Added: pypy/dist/lib-python/modified-2.4.1/cProfile.py ============================================================================== --- (empty file) +++ pypy/dist/lib-python/modified-2.4.1/cProfile.py Fri Jun 6 02:49:26 2008 @@ -0,0 +1,190 @@ +#! /usr/bin/env python + +"""Python interface for the 'lsprof' profiler. + Compatible with the 'profile' module. +""" + +__all__ = ["run", "runctx", "help", "Profile"] + +import _lsprof + +# ____________________________________________________________ +# Simple interface + +def run(statement, filename=None, sort=-1): + """Run statement under profiler optionally saving results in filename + + This function takes a single argument that can be passed to the + "exec" statement, and an optional file name. In all cases this + routine attempts to "exec" its first argument and gather profiling + statistics from the execution. If no file name is present, then this + function automatically prints a simple profiling report, sorted by the + standard name string (file/line/function-name) that is presented in + each line. + """ + prof = Profile() + result = None + try: + try: + prof = prof.run(statement) + except SystemExit: + pass + finally: + if filename is not None: + prof.dump_stats(filename) + else: + result = prof.print_stats(sort) + return result + +def runctx(statement, globals, locals, filename=None): + """Run statement under profiler, supplying your own globals and locals, + optionally saving results in filename. + + statement and filename have the same semantics as profile.run + """ + prof = Profile() + result = None + try: + try: + prof = prof.runctx(statement, globals, locals) + except SystemExit: + pass + finally: + if filename is not None: + prof.dump_stats(filename) + else: + result = prof.print_stats() + return result + +# Backwards compatibility. +def help(): + print "Documentation for the profile/cProfile modules can be found " + print "in the Python Library Reference, section 'The Python Profiler'." + +# ____________________________________________________________ + +class Profile(_lsprof.Profiler): + """Profile(custom_timer=None, time_unit=None, subcalls=True, builtins=True) + + Builds a profiler object using the specified timer function. + The default timer is a fast built-in one based on real time. + For custom timer functions returning integers, time_unit can + be a float specifying a scale (i.e. how long each integer unit + is, in seconds). + """ + + # Most of the functionality is in the base class. + # This subclass only adds convenient and backward-compatible methods. + + def print_stats(self, sort=-1): + import pstats + pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats() + + def dump_stats(self, file): + import marshal + f = open(file, 'wb') + self.create_stats() + marshal.dump(self.stats, f) + f.close() + + def create_stats(self): + self.disable() + self.snapshot_stats() + + def snapshot_stats(self): + entries = self.getstats() + self.stats = {} + callersdicts = {} + # call information + for entry in entries: + func = label(entry.code) + nc = entry.callcount # ncalls column of pstats (before '/') + cc = nc - entry.reccallcount # ncalls column of pstats (after '/') + tt = entry.inlinetime # tottime column of pstats + ct = entry.totaltime # cumtime column of pstats + callers = {} + callersdicts[id(entry.code)] = callers + self.stats[func] = cc, nc, tt, ct, callers + # subcall information + for entry in entries: + if entry.calls: + func = label(entry.code) + for subentry in entry.calls: + try: + callers = callersdicts[id(subentry.code)] + except KeyError: + continue + nc = subentry.callcount + cc = nc - subentry.reccallcount + tt = subentry.inlinetime + ct = subentry.totaltime + if func in callers: + prev = callers[func] + nc += prev[0] + cc += prev[1] + tt += prev[2] + ct += prev[3] + callers[func] = nc, cc, tt, ct + + # The following two methods can be called by clients to use + # a profiler to profile a statement, given as a string. + + def run(self, cmd): + import __main__ + dict = __main__.__dict__ + return self.runctx(cmd, dict, dict) + + def runctx(self, cmd, globals, locals): + self.enable() + try: + exec cmd in globals, locals + finally: + self.disable() + return self + + # This method is more useful to profile a single function call. + def runcall(self, func, *args, **kw): + self.enable() + try: + return func(*args, **kw) + finally: + self.disable() + +# ____________________________________________________________ + +def label(code): + if isinstance(code, str): + return ('~', 0, code) # built-in functions ('~' sorts at the end) + else: + return (code.co_filename, code.co_firstlineno, code.co_name) + +# ____________________________________________________________ + +def main(): + import os, sys + from optparse import OptionParser + usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..." + parser = OptionParser(usage=usage) + parser.allow_interspersed_args = False + parser.add_option('-o', '--outfile', dest="outfile", + help="Save stats to ", default=None) + parser.add_option('-s', '--sort', dest="sort", + help="Sort order when printing to stdout, based on pstats.Stats class", default=-1) + + if not sys.argv[1:]: + parser.print_usage() + sys.exit(2) + + (options, args) = parser.parse_args() + sys.argv[:] = args + + if (len(sys.argv) > 0): + sys.path.insert(0, os.path.dirname(sys.argv[0])) + run('execfile(%r)' % (sys.argv[0],), options.outfile, options.sort) + else: + parser.print_usage() + return parser + +# When invoked as main program, invoke the profiler on a script +if __name__ == '__main__': + main() Added: pypy/dist/lib-python/modified-2.4.1/pstats.py ============================================================================== --- (empty file) +++ pypy/dist/lib-python/modified-2.4.1/pstats.py Fri Jun 6 02:49:26 2008 @@ -0,0 +1,685 @@ +"""Class for printing reports on profiled python code.""" + +# Class for printing reports on profiled python code. rev 1.0 4/1/94 +# +# Based on prior profile module by Sjoerd Mullender... +# which was hacked somewhat by: Guido van Rossum +# +# see profile.doc and profile.py for more info. + +# Copyright 1994, by InfoSeek Corporation, all rights reserved. +# Written by James Roskind +# +# Permission to use, copy, modify, and distribute this Python software +# and its associated documentation for any purpose (subject to the +# restriction in the following sentence) without fee is hereby granted, +# provided that the above copyright notice appears in all copies, and +# that both that copyright notice and this permission notice appear in +# supporting documentation, and that the name of InfoSeek not be used in +# advertising or publicity pertaining to distribution of the software +# without specific, written prior permission. This permission is +# explicitly restricted to the copying and modification of the software +# to remain in Python, compiled Python, or other languages (such as C) +# wherein the modified or derived code is exclusively imported into a +# Python module. +# +# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY +# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +import sys +import os +import time +import marshal +import re + +__all__ = ["Stats"] + +class Stats: + """This class is used for creating reports from data generated by the + Profile class. It is a "friend" of that class, and imports data either + by direct access to members of Profile class, or by reading in a dictionary + that was emitted (via marshal) from the Profile class. + + The big change from the previous Profiler (in terms of raw functionality) + is that an "add()" method has been provided to combine Stats from + several distinct profile runs. Both the constructor and the add() + method now take arbitrarily many file names as arguments. + + All the print methods now take an argument that indicates how many lines + to print. If the arg is a floating point number between 0 and 1.0, then + it is taken as a decimal percentage of the available lines to be printed + (e.g., .1 means print 10% of all available lines). If it is an integer, + it is taken to mean the number of lines of data that you wish to have + printed. + + The sort_stats() method now processes some additional options (i.e., in + addition to the old -1, 0, 1, or 2). It takes an arbitrary number of + quoted strings to select the sort order. For example sort_stats('time', + 'name') sorts on the major key of 'internal function time', and on the + minor key of 'the name of the function'. Look at the two tables in + sort_stats() and get_sort_arg_defs(self) for more examples. + + All methods return self, so you can string together commands like: + Stats('foo', 'goo').strip_dirs().sort_stats('calls').\ + print_stats(5).print_callers(5) + """ + + def __init__(self, *args, **kwds): + # I can't figure out how to explictly specify a stream keyword arg + # with *args: + # def __init__(self, *args, stream=sys.stdout): ... + # so I use **kwds and sqauwk if something unexpected is passed in. + self.stream = sys.stdout + if "stream" in kwds: + self.stream = kwds["stream"] + del kwds["stream"] + if kwds: + keys = kwds.keys() + keys.sort() + extras = ", ".join(["%s=%s" % (k, kwds[k]) for k in keys]) + raise ValueError, "unrecognized keyword args: %s" % extras + if not len(args): + arg = None + else: + arg = args[0] + args = args[1:] + self.init(arg) + self.add(*args) + + def init(self, arg): + self.all_callees = None # calc only if needed + self.files = [] + self.fcn_list = None + self.total_tt = 0 + self.total_calls = 0 + self.prim_calls = 0 + self.max_name_len = 0 + self.top_level = {} + self.stats = {} + self.sort_arg_dict = {} + self.load_stats(arg) + trouble = 1 + try: + self.get_top_level_stats() + trouble = 0 + finally: + if trouble: + print >> self.stream, "Invalid timing data", + if self.files: print >> self.stream, self.files[-1], + print >> self.stream + + def load_stats(self, arg): + if not arg: self.stats = {} + elif isinstance(arg, basestring): + f = open(arg, 'rb') + self.stats = marshal.load(f) + f.close() + try: + file_stats = os.stat(arg) + arg = time.ctime(file_stats.st_mtime) + " " + arg + except: # in case this is not unix + pass + self.files = [ arg ] + elif hasattr(arg, 'create_stats'): + arg.create_stats() + self.stats = arg.stats + arg.stats = {} + if not self.stats: + raise TypeError, "Cannot create or construct a %r object from '%r''" % ( + self.__class__, arg) + return + + def get_top_level_stats(self): + for func, (cc, nc, tt, ct, callers) in self.stats.items(): + self.total_calls += nc + self.prim_calls += cc + self.total_tt += tt + if callers.has_key(("jprofile", 0, "profiler")): + self.top_level[func] = None + if len(func_std_string(func)) > self.max_name_len: + self.max_name_len = len(func_std_string(func)) + + def add(self, *arg_list): + if not arg_list: return self + if len(arg_list) > 1: self.add(*arg_list[1:]) + other = arg_list[0] + if type(self) != type(other) or self.__class__ != other.__class__: + other = Stats(other) + self.files += other.files + self.total_calls += other.total_calls + self.prim_calls += other.prim_calls + self.total_tt += other.total_tt + for func in other.top_level: + self.top_level[func] = None + + if self.max_name_len < other.max_name_len: + self.max_name_len = other.max_name_len + + self.fcn_list = None + + for func, stat in other.stats.iteritems(): + if func in self.stats: + old_func_stat = self.stats[func] + else: + old_func_stat = (0, 0, 0, 0, {},) + self.stats[func] = add_func_stats(old_func_stat, stat) + return self + + def dump_stats(self, filename): + """Write the profile data to a file we know how to load back.""" + f = file(filename, 'wb') + try: + marshal.dump(self.stats, f) + finally: + f.close() + + # list the tuple indices and directions for sorting, + # along with some printable description + sort_arg_dict_default = { + "calls" : (((1,-1), ), "call count"), + "cumulative": (((3,-1), ), "cumulative time"), + "file" : (((4, 1), ), "file name"), + "line" : (((5, 1), ), "line number"), + "module" : (((4, 1), ), "file name"), + "name" : (((6, 1), ), "function name"), + "nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"), + "pcalls" : (((0,-1), ), "call count"), + "stdname" : (((7, 1), ), "standard name"), + "time" : (((2,-1), ), "internal time"), + } + + def get_sort_arg_defs(self): + """Expand all abbreviations that are unique.""" + if not self.sort_arg_dict: + self.sort_arg_dict = dict = {} + bad_list = {} + for word, tup in self.sort_arg_dict_default.iteritems(): + fragment = word + while fragment: + if not fragment: + break + if fragment in dict: + bad_list[fragment] = 0 + break + dict[fragment] = tup + fragment = fragment[:-1] + for word in bad_list: + del dict[word] + return self.sort_arg_dict + + def sort_stats(self, *field): + if not field: + self.fcn_list = 0 + return self + if len(field) == 1 and type(field[0]) == type(1): + # Be compatible with old profiler + field = [ {-1: "stdname", + 0:"calls", + 1:"time", + 2: "cumulative" } [ field[0] ] ] + + sort_arg_defs = self.get_sort_arg_defs() + sort_tuple = () + self.sort_type = "" + connector = "" + for word in field: + sort_tuple = sort_tuple + sort_arg_defs[word][0] + self.sort_type += connector + sort_arg_defs[word][1] + connector = ", " + + stats_list = [] + for func, (cc, nc, tt, ct, callers) in self.stats.iteritems(): + stats_list.append((cc, nc, tt, ct) + func + + (func_std_string(func), func)) + + stats_list.sort(TupleComp(sort_tuple).compare) + + self.fcn_list = fcn_list = [] + for tuple in stats_list: + fcn_list.append(tuple[-1]) + return self + + def reverse_order(self): + if self.fcn_list: + self.fcn_list.reverse() + return self + + def strip_dirs(self): + oldstats = self.stats + self.stats = newstats = {} + max_name_len = 0 + for func, (cc, nc, tt, ct, callers) in oldstats.iteritems(): + newfunc = func_strip_path(func) + if len(func_std_string(newfunc)) > max_name_len: + max_name_len = len(func_std_string(newfunc)) + newcallers = {} + for func2, caller in callers.iteritems(): + newcallers[func_strip_path(func2)] = caller + + if newfunc in newstats: + newstats[newfunc] = add_func_stats( + newstats[newfunc], + (cc, nc, tt, ct, newcallers)) + else: + newstats[newfunc] = (cc, nc, tt, ct, newcallers) + old_top = self.top_level + self.top_level = new_top = {} + for func in old_top: + new_top[func_strip_path(func)] = None + + self.max_name_len = max_name_len + + self.fcn_list = None + self.all_callees = None + return self + + def calc_callees(self): + if self.all_callees: return + self.all_callees = all_callees = {} + for func, (cc, nc, tt, ct, callers) in self.stats.iteritems(): + if not func in all_callees: + all_callees[func] = {} + for func2, caller in callers.iteritems(): + if not func2 in all_callees: + all_callees[func2] = {} + all_callees[func2][func] = caller + return + + #****************************************************************** + # The following functions support actual printing of reports + #****************************************************************** + + # Optional "amount" is either a line count, or a percentage of lines. + + def eval_print_amount(self, sel, list, msg): + new_list = list + if type(sel) == type(""): + new_list = [] + for func in list: + if re.search(sel, func_std_string(func)): + new_list.append(func) + else: + count = len(list) + if type(sel) == type(1.0) and 0.0 <= sel < 1.0: + count = int(count * sel + .5) + new_list = list[:count] + elif type(sel) == type(1) and 0 <= sel < count: + count = sel + new_list = list[:count] + if len(list) != len(new_list): + msg = msg + " List reduced from %r to %r due to restriction <%r>\n" % ( + len(list), len(new_list), sel) + + return new_list, msg + + def get_print_list(self, sel_list): + width = self.max_name_len + if self.fcn_list: + list = self.fcn_list[:] + msg = " Ordered by: " + self.sort_type + '\n' + else: + list = self.stats.keys() + msg = " Random listing order was used\n" + + for selection in sel_list: + list, msg = self.eval_print_amount(selection, list, msg) + + count = len(list) + + if not list: + return 0, list + print >> self.stream, msg + if count < len(self.stats): + width = 0 + for func in list: + if len(func_std_string(func)) > width: + width = len(func_std_string(func)) + return width+2, list + + def print_stats(self, *amount): + for filename in self.files: + print >> self.stream, filename + if self.files: print >> self.stream + indent = ' ' * 8 + for func in self.top_level: + print >> self.stream, indent, func_get_function_name(func) + + print >> self.stream, indent, self.total_calls, "function calls", + if self.total_calls != self.prim_calls: + print >> self.stream, "(%d primitive calls)" % self.prim_calls, + print >> self.stream, "in %.3f CPU seconds" % self.total_tt + print >> self.stream + width, list = self.get_print_list(amount) + if list: + self.print_title() + for func in list: + self.print_line(func) + print >> self.stream + print >> self.stream + return self + + def print_callees(self, *amount): + width, list = self.get_print_list(amount) + if list: + self.calc_callees() + + self.print_call_heading(width, "called...") + for func in list: + if func in self.all_callees: + self.print_call_line(width, func, self.all_callees[func]) + else: + self.print_call_line(width, func, {}) + print >> self.stream + print >> self.stream + return self + + def print_callers(self, *amount): + width, list = self.get_print_list(amount) + if list: + self.print_call_heading(width, "was called by...") + for func in list: + cc, nc, tt, ct, callers = self.stats[func] + self.print_call_line(width, func, callers, "<-") + print >> self.stream + print >> self.stream + return self + + def print_call_heading(self, name_size, column_title): + print >> self.stream, "Function ".ljust(name_size) + column_title + # print sub-header only if we have new-style callers + subheader = False + for cc, nc, tt, ct, callers in self.stats.itervalues(): + if callers: + value = callers.itervalues().next() + subheader = isinstance(value, tuple) + break + if subheader: + print >> self.stream, " "*name_size + " ncalls tottime cumtime" + + def print_call_line(self, name_size, source, call_dict, arrow="->"): + print >> self.stream, func_std_string(source).ljust(name_size) + arrow, + if not call_dict: + print >> self.stream + return + clist = call_dict.keys() + clist.sort() + indent = "" + for func in clist: + name = func_std_string(func) + value = call_dict[func] + if isinstance(value, tuple): + nc, cc, tt, ct = value + if nc != cc: + substats = '%d/%d' % (nc, cc) + else: + substats = '%d' % (nc,) + substats = '%s %s %s %s' % (substats.rjust(7+2*len(indent)), + f8(tt), f8(ct), name) + left_width = name_size + 1 + else: + substats = '%s(%r) %s' % (name, value, f8(self.stats[func][3])) + left_width = name_size + 3 + print >> self.stream, indent*left_width + substats + indent = " " + + def print_title(self): + print >> self.stream, ' ncalls tottime percall cumtime percall', + print >> self.stream, 'filename:lineno(function)' + + def print_line(self, func): # hack : should print percentages + cc, nc, tt, ct, callers = self.stats[func] + c = str(nc) + if nc != cc: + c = c + '/' + str(cc) + print >> self.stream, c.rjust(9), + print >> self.stream, f8(tt), + if nc == 0: + print >> self.stream, ' '*8, + else: + print >> self.stream, f8(tt/nc), + print >> self.stream, f8(ct), + if cc == 0: + print >> self.stream, ' '*8, + else: + print >> self.stream, f8(ct/cc), + print >> self.stream, func_std_string(func) + +class TupleComp: + """This class provides a generic function for comparing any two tuples. + Each instance records a list of tuple-indices (from most significant + to least significant), and sort direction (ascending or decending) for + each tuple-index. The compare functions can then be used as the function + argument to the system sort() function when a list of tuples need to be + sorted in the instances order.""" + + def __init__(self, comp_select_list): + self.comp_select_list = comp_select_list + + def compare (self, left, right): + for index, direction in self.comp_select_list: + l = left[index] + r = right[index] + if l < r: + return -direction + if l > r: + return direction + return 0 + +#************************************************************************** +# func_name is a triple (file:string, line:int, name:string) + +def func_strip_path(func_name): + filename, line, name = func_name + return os.path.basename(filename), line, name + +def func_get_function_name(func): + return func[2] + +def func_std_string(func_name): # match what old profile produced + if func_name[:2] == ('~', 0): + # special case for built-in functions + name = func_name[2] + if name.startswith('<') and name.endswith('>'): + return '{%s}' % name[1:-1] + else: + return name + else: + return "%s:%d(%s)" % func_name + +#************************************************************************** +# The following functions combine statists for pairs functions. +# The bulk of the processing involves correctly handling "call" lists, +# such as callers and callees. +#************************************************************************** + +def add_func_stats(target, source): + """Add together all the stats for two profile entries.""" + cc, nc, tt, ct, callers = source + t_cc, t_nc, t_tt, t_ct, t_callers = target + return (cc+t_cc, nc+t_nc, tt+t_tt, ct+t_ct, + add_callers(t_callers, callers)) + +def add_callers(target, source): + """Combine two caller lists in a single list.""" + new_callers = {} + for func, caller in target.iteritems(): + new_callers[func] = caller + for func, caller in source.iteritems(): + if func in new_callers: + new_callers[func] = tuple([i[0] + i[1] for i in + zip(caller, new_callers[func])]) + else: + new_callers[func] = caller + return new_callers + +def count_calls(callers): + """Sum the caller statistics to get total number of calls received.""" + nc = 0 + for calls in callers.itervalues(): + nc += calls + return nc + +#************************************************************************** +# The following functions support printing of reports +#************************************************************************** + +def f8(x): + return "%8.3f" % x + +#************************************************************************** +# Statistics browser added by ESR, April 2001 +#************************************************************************** + +if __name__ == '__main__': + import cmd + try: + import readline + except ImportError: + pass + + class ProfileBrowser(cmd.Cmd): + def __init__(self, profile=None): + cmd.Cmd.__init__(self) + self.prompt = "% " + if profile is not None: + self.stats = Stats(profile) + self.stream = self.stats.stream + else: + self.stats = None + self.stream = sys.stdout + + def generic(self, fn, line): + args = line.split() + processed = [] + for term in args: + try: + processed.append(int(term)) + continue + except ValueError: + pass + try: + frac = float(term) + if frac > 1 or frac < 0: + print >> self.stream, "Fraction argument must be in [0, 1]" + continue + processed.append(frac) + continue + except ValueError: + pass + processed.append(term) + if self.stats: + getattr(self.stats, fn)(*processed) + else: + print >> self.stream, "No statistics object is loaded." + return 0 + def generic_help(self): + print >> self.stream, "Arguments may be:" + print >> self.stream, "* An integer maximum number of entries to print." + print >> self.stream, "* A decimal fractional number between 0 and 1, controlling" + print >> self.stream, " what fraction of selected entries to print." + print >> self.stream, "* A regular expression; only entries with function names" + print >> self.stream, " that match it are printed." + + def do_add(self, line): + self.stats.add(line) + return 0 + def help_add(self): + print >> self.stream, "Add profile info from given file to current statistics object." + + def do_callees(self, line): + return self.generic('print_callees', line) + def help_callees(self): + print >> self.stream, "Print callees statistics from the current stat object." + self.generic_help() + + def do_callers(self, line): + return self.generic('print_callers', line) + def help_callers(self): + print >> self.stream, "Print callers statistics from the current stat object." + self.generic_help() + + def do_EOF(self, line): + print >> self.stream, "" + return 1 + def help_EOF(self): + print >> self.stream, "Leave the profile brower." + + def do_quit(self, line): + return 1 + def help_quit(self): + print >> self.stream, "Leave the profile brower." + + def do_read(self, line): + if line: + try: + self.stats = Stats(line) + except IOError, args: + print >> self.stream, args[1] + return + self.prompt = line + "% " + elif len(self.prompt) > 2: + line = self.prompt[-2:] + else: + print >> self.stream, "No statistics object is current -- cannot reload." + return 0 + def help_read(self): + print >> self.stream, "Read in profile data from a specified file." + + def do_reverse(self, line): + self.stats.reverse_order() + return 0 + def help_reverse(self): + print >> self.stream, "Reverse the sort order of the profiling report." + + def do_sort(self, line): + abbrevs = self.stats.get_sort_arg_defs() + if line and not filter(lambda x,a=abbrevs: x not in a,line.split()): + self.stats.sort_stats(*line.split()) + else: + print >> self.stream, "Valid sort keys (unique prefixes are accepted):" + for (key, value) in Stats.sort_arg_dict_default.iteritems(): + print >> self.stream, "%s -- %s" % (key, value[1]) + return 0 + def help_sort(self): + print >> self.stream, "Sort profile data according to specified keys." + print >> self.stream, "(Typing `sort' without arguments lists valid keys.)" + def complete_sort(self, text, *args): + return [a for a in Stats.sort_arg_dict_default if a.startswith(text)] + + def do_stats(self, line): + return self.generic('print_stats', line) + def help_stats(self): + print >> self.stream, "Print statistics from the current stat object." + self.generic_help() + + def do_strip(self, line): + self.stats.strip_dirs() + return 0 + def help_strip(self): + print >> self.stream, "Strip leading path information from filenames in the report." + + def postcmd(self, stop, line): + if stop: + return stop + return None + + import sys + if len(sys.argv) > 1: + initprofile = sys.argv[1] + else: + initprofile = None + try: + browser = ProfileBrowser(initprofile) + print >> browser.stream, "Welcome to the profile statistics browser." + browser.cmdloop() + print >> browser.stream, "Goodbye." + except KeyboardInterrupt: + pass + +# That's all, folks. Added: pypy/dist/lib-python/modified-2.4.1/test/profilee.py ============================================================================== --- (empty file) +++ pypy/dist/lib-python/modified-2.4.1/test/profilee.py Fri Jun 6 02:49:26 2008 @@ -0,0 +1,115 @@ +""" +Input for test_profile.py and test_cprofile.py. + +IMPORTANT: This stuff is touchy. If you modify anything above the +test class you'll have to regenerate the stats by running the two +test files. + +*ALL* NUMBERS in the expected output are relevant. If you change +the formatting of pstats, please don't just regenerate the expected +output without checking very carefully that not a single number has +changed. +""" + +import sys + +# In order to have reproducible time, we simulate a timer in the global +# variable 'TICKS', which represents simulated time in milliseconds. +# (We can't use a helper function increment the timer since it would be +# included in the profile and would appear to consume all the time.) +TICKS = 42000 + +def timer(): + return TICKS + +def testfunc(): + # 1 call + # 1000 ticks total: 270 ticks local, 730 ticks in subfunctions + global TICKS + TICKS += 99 + helper() # 300 + helper() # 300 + TICKS += 171 + factorial(14) # 130 + +def factorial(n): + # 23 calls total + # 170 ticks total, 150 ticks local + # 3 primitive calls, 130, 20 and 20 ticks total + # including 116, 17, 17 ticks local + global TICKS + if n > 0: + TICKS += n + return mul(n, factorial(n-1)) + else: + TICKS += 11 + return 1 + +def mul(a, b): + # 20 calls + # 1 tick, local + global TICKS + TICKS += 1 + return a * b + +def helper(): + # 2 calls + # 300 ticks total: 20 ticks local, 260 ticks in subfunctions + global TICKS + TICKS += 1 + helper1() # 30 + TICKS += 2 + helper1() # 30 + TICKS += 6 + helper2() # 50 + TICKS += 3 + helper2() # 50 + TICKS += 2 + helper2() # 50 + TICKS += 5 + helper2_indirect() # 70 + TICKS += 1 + +def helper1(): + # 4 calls + # 30 ticks total: 29 ticks local, 1 tick in subfunctions + global TICKS + TICKS += 10 + hasattr(C(), "foo") # 1 + TICKS += 19 + lst = [] + lst.append(42) # 0 + sys.exc_info() # 0 + +def helper2_indirect(): + helper2() # 50 + factorial(3) # 20 + +def helper2(): + # 8 calls + # 50 ticks local: 39 ticks local, 11 ticks in subfunctions + global TICKS + TICKS += 11 + hasattr(C(), "bar") # 1 + TICKS += 13 + subhelper() # 10 + TICKS += 15 + +def subhelper(): + # 8 calls + # 10 ticks total: 8 ticks local, 2 ticks in subfunctions + global TICKS + TICKS += 2 + for i in range(2): # 0 + try: + C().foo # 1 x 2 + except AttributeError: + TICKS += 3 # 3 x 2 + +class C: + def __getattr__(self, name): + # 28 calls + # 1 tick, local + global TICKS + TICKS += 1 + raise AttributeError From fijal at codespeak.net Fri Jun 6 03:06:09 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 03:06:09 +0200 (CEST) Subject: [pypy-svn] r55618 - pypy/dist/pypy/module/_lsprof Message-ID: <20080606010609.76789168413@codespeak.net> Author: fijal Date: Fri Jun 6 03:06:09 2008 New Revision: 55618 Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py Log: Typo Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/interp_lsprof.py (original) +++ pypy/dist/pypy/module/_lsprof/interp_lsprof.py Fri Jun 6 03:06:09 2008 @@ -3,7 +3,7 @@ Arguments) from pypy.interpreter.typedef import (TypeDef, GetSetProperty, interp_attrproperty) -from pypy.interpreter.gateway import interp2app +from pypy.interpreter.gateway import interp2app, NoneNotWrapped import time, sys class W_StatsEntry(Wrappable): @@ -215,7 +215,7 @@ return stats(space, self.data, factor) getstats.unwrap_spec = ['self', ObjSpace] -def descr_new_profile(space, w_type, w_callable=None, time_unit=0.0, +def descr_new_profile(space, w_type, w_callable=NoneNotWrapped, time_unit=0.0, subcalls=True, builtins=True): p = space.allocate_instance(W_Profiler, w_type) p.__init__(space, w_callable, time_unit, subcalls, builtins) From fijal at codespeak.net Fri Jun 6 04:53:59 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 04:53:59 +0200 (CEST) Subject: [pypy-svn] r55619 - pypy/dist/pypy/module/_lsprof Message-ID: <20080606025359.8974316841D@codespeak.net> Author: fijal Date: Fri Jun 6 04:53:57 2008 New Revision: 55619 Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py Log: Ooops. This factor is really just 1. since we measure in floats. Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/interp_lsprof.py (original) +++ pypy/dist/pypy/module/_lsprof/interp_lsprof.py Fri Jun 6 04:53:57 2008 @@ -207,7 +207,7 @@ def getstats(self, space): if self.w_callable is None: - factor = 0.000001 + factor = 1. # we measure time.time in floats elif self.time_unit > 0.0: factor = self.time_unit else: From arigo at codespeak.net Fri Jun 6 09:38:16 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 09:38:16 +0200 (CEST) Subject: [pypy-svn] r55620 - pypy/dist/pypy/doc Message-ID: <20080606073816.41B191684D1@codespeak.net> Author: arigo Date: Fri Jun 6 09:38:14 2008 New Revision: 55620 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/faq.txt Log: Update some entries of the FAQ. Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Fri Jun 6 09:38:14 2008 @@ -10,6 +10,7 @@ .. _`pypy/annotation/model.py`: ../../pypy/annotation/model.py .. _`bin/`: ../../pypy/bin .. _`config/`: ../../pypy/config +.. _`pypy/config/pypyoption.py`: ../../pypy/config/pypyoption.py .. _`doc/`: ../../pypy/doc .. _`doc/config/`: ../../pypy/doc/config .. _`doc/discussion/`: ../../pypy/doc/discussion Modified: pypy/dist/pypy/doc/faq.txt ============================================================================== --- pypy/dist/pypy/doc/faq.txt (original) +++ pypy/dist/pypy/doc/faq.txt Fri Jun 6 09:38:14 2008 @@ -54,9 +54,7 @@ At the moment you need CPython 2.4 (with ctypes 0.9.9.6 or newer) or CPython 2.5 for the translation process. -Currently (due to time restrictions) we are not trying hard to support -PyPy in a 64 bit environment. While things seem to mostly work, a few -modules won't work on 64 bit machines, such as ``bz2``. +PyPy also basically works in a 64-bit Linux environment. ------------------------------------------------ Which Python version (2.x?) does PyPy implement? @@ -64,10 +62,8 @@ PyPy currently aims to be fully compatible with Python 2.4. That means that it contains the standard library of Python 2.4 and that it supports 2.4 -features (such as decorators) but not the 2.5 features (with statement, the ternary -operator). The 2.5 features will probably be eventually supported, the most -important reason why nobody is working on them is that we did not promise this -to the EU and have currently enough other tasks. +features (such as decorators). The 2.5 features (e.g. the ``with`` statement, +the ternary operator) are in progress. .. _threading: @@ -75,26 +71,24 @@ Do threads work? What are the modules that work? ------------------------------------------------- -Operating system-level threads work in a limited way. If you enable the ``thread`` -module then PyPy will get support for GIL based threading. One limitation is -that not that many IO operations actually release the GIL, which reduces the -usefulness of threads. On the other hand, PyPy fully supports `stackless-like +Operating system-level threads basically work. If you enable the ``thread`` +module then PyPy will get support for GIL based threading. +Note that PyPy also fully supports `stackless-like microthreads`_ (although both cannot be mixed yet). As for other modules: The general rule of thumb is that pure-Python modules -work, C extension modules don't. Some of the C extension modules of the standard +work, C extension modules don't. However, many of the C extension modules +of the standard library have been re-implemented in pure Python or as a mixed module (for some -there were also older pure-Python versions available). A (probably incomplete) -list: +there were also older pure-Python versions available). The list of supported +modules can be found as follows: - * pure Python implementations: binascii, cmath, collections, cPickle, - cStringIO, datetime, functional, imp, itertools, md5, operator, - sha, struct - - * mixed module implementations: exceptions, sys, __builtin__, posix - _codecs, gc, _weakref, array, marshal, errno, math, _sre, parser, symbol, - _random, socket, unicodedata, mmap, fcntl, time, select, bz2, crypt, - signal, readline (incomplete) + * pure Python implementations: all the modules found in the `pypy/lib/`_ + directory + + * mixed module implementations: all the modules listed in + ``essential_modules``, ``default_modules`` and ``working_modules`` + in `pypy/config/pypyoption.py`_. .. _`stackless-like microthreads`: stackless.html @@ -110,8 +104,7 @@ rely heavily on CPython's C API which contains a lot of implementation details like reference counting, exact C-level object implementation and layout etc. -Although if your module uses ctypes rather than C-level code, there is -a hope -- you can try to write a mixed module (see next question). +A module based on ctypes is a different matter -- we support these nowadays. The long-term answer might be different. In principle, it should be possible for PyPy to support the CPython C API (or at least a large subset of its @@ -122,11 +115,10 @@ How do I write extension modules for PyPy? ------------------------------------------ -PyPy extension modules are written in the form of `mixed modules`_, so -called because they can contain a mixture of compiled and interpreted -Python code. At the moment they all need to be translated together with the rest of PyPy. +See `Writing extension modules for PyPy`__. + +.. __: extending.html -.. _`mixed modules`: coding-guide.html#mixed-module-mechanism .. _`slower than CPython`: .. _`how fast is pypy`: @@ -141,17 +133,16 @@ CPython, the version of PyPy that still runs on top of CPython is slower by a factor of 2000. The first translated version was roughly 300 times slower than CPython, a number which we decreased release after release -to the current point, where PyPy is only between 1.7 and 4 times slower -than CPython. Note that the speed heavily depends on the options -enabled at compile time. +to the current point, where PyPy is somewhere between 1 and 2, i.e. it +is as fast as CPython in some cases, and up to twice as slow in other +cases. Note that the speed heavily depends on the options enabled at +compile time. The integration of the work on the Just-In-Time compiler has just -started; it can be `manually enabled`_ and gives good results on -functions doing integer arithmetic (60 times faster than CPython, -i.e. within 20% of recoding the function in C and compiling with ``gcc`` -without optimizations). +started; it is not yet ready enough to give useful speed-ups. See +status__. -.. _`manually enabled`: jit/status.html +.. __: jit/status.html .. _`prolog and javascript`: From arigo at codespeak.net Fri Jun 6 09:50:05 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 09:50:05 +0200 (CEST) Subject: [pypy-svn] r55621 - pypy/dist/pypy/doc Message-ID: <20080606075005.EF2911684CF@codespeak.net> Author: arigo Date: Fri Jun 6 09:50:04 2008 New Revision: 55621 Modified: pypy/dist/pypy/doc/faq.txt pypy/dist/pypy/doc/redirections Log: Add a faq entry with our (or at least my) position on this topic. Modified: pypy/dist/pypy/doc/faq.txt ============================================================================== --- pypy/dist/pypy/doc/faq.txt (original) +++ pypy/dist/pypy/doc/faq.txt Fri Jun 6 09:50:04 2008 @@ -281,6 +281,23 @@ an "entry point" function. The translation toolchain follows all calls recursively and discovers what belongs to the program and what not. +------------------------------------------------------------------------- +Can I use PyPy and RPython to compile smaller parts of my Python program? +------------------------------------------------------------------------- + +No. That would be possible, and we played with early attempts in that +direction, but there are many delicate issues: for example, how the +compiled and the non-compiled parts exchange data. Supporting this in a +nice way would be a lot of work. + +PyPy is certainly a good starting point for someone that would like to +work in that direction. Early attempts were dropped because they +conflicted with refactorings that we needed in order to progress on the +rest of PyPy; the currently active developers of PyPy have different +priorities. If someone wants to start working in that direction I +imagine that he might get a (very little) bit of support from us, +though. + ------------------------------------------------------ What's the ``"NOT_RPYTHON"`` I see in some docstrings? ------------------------------------------------------ Modified: pypy/dist/pypy/doc/redirections ============================================================================== --- pypy/dist/pypy/doc/redirections (original) +++ pypy/dist/pypy/doc/redirections Fri Jun 6 09:50:04 2008 @@ -4,6 +4,6 @@ 'news.html': 'home.html', 'contact.html': 'home.html', 'jit.html': 'jit/index.html', - 'standalone-howto.html': 'faq.html#can-pypy-compile-normal-python-programs', + 'standalone-howto.html': 'faq.html#pypy-translation-tool-chain', } From arigo at codespeak.net Fri Jun 6 10:05:52 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 10:05:52 +0200 (CEST) Subject: [pypy-svn] r55622 - pypy/dist/pypy/doc Message-ID: <20080606080552.7A8A2168415@codespeak.net> Author: arigo Date: Fri Jun 6 10:05:51 2008 New Revision: 55622 Modified: pypy/dist/pypy/doc/faq.txt Log: Add this precision (thanks anto). Modified: pypy/dist/pypy/doc/faq.txt ============================================================================== --- pypy/dist/pypy/doc/faq.txt (original) +++ pypy/dist/pypy/doc/faq.txt Fri Jun 6 10:05:51 2008 @@ -298,6 +298,12 @@ imagine that he might get a (very little) bit of support from us, though. +Alternatively, it's possible to write a mixed-module, i.e. an extension +module for PyPy in RPython, which you can then import from your Python +program when it runs on top of PyPy. This is similar to writing a C +extension module for CPython in term of investment of effort (without +all the INCREF/DECREF mess, though). + ------------------------------------------------------ What's the ``"NOT_RPYTHON"`` I see in some docstrings? ------------------------------------------------------ From arigo at codespeak.net Fri Jun 6 15:46:43 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 15:46:43 +0200 (CEST) Subject: [pypy-svn] r55634 - pypy/dist/pypy/translator/goal Message-ID: <20080606134643.DB0C816844D@codespeak.net> Author: arigo Date: Fri Jun 6 15:46:41 2008 New Revision: 55634 Removed: pypy/dist/pypy/translator/goal/targetgcbench2.py Modified: pypy/dist/pypy/translator/goal/gcbench.py pypy/dist/pypy/translator/goal/targetgcbench.py Log: Make gcbench optionally use threads. They only work when gcbench is run on top of CPython or pypy-c-with-threads, not when it is translated as a stand-alone executable. Modified: pypy/dist/pypy/translator/goal/gcbench.py ============================================================================== --- pypy/dist/pypy/translator/goal/gcbench.py (original) +++ pypy/dist/pypy/translator/goal/gcbench.py Fri Jun 6 15:46:41 2008 @@ -45,8 +45,11 @@ # check for proper locking import os, time +USAGE = """gcbench [num_repetitions] [--depths=N,N,N..] [--threads=N]""" +ENABLE_THREADS = True + def println(s): - os.write(1, s+"\n") + print s class Node(object): @@ -107,7 +110,25 @@ t_finish = time.time() println("\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.)) -def main(depths=range(kMinTreeDepth, kMaxTreeDepth+1, 2)): +DEFAULT_DEPTHS = range(kMinTreeDepth, kMaxTreeDepth+1, 2) + +def time_constructions(depths): + for d in depths: + time_construction(d) + +def time_parallel_constructions(depths, nthreads): + import threading + threadlist = [] + print "Starting %d parallel threads..." % (nthreads,) + for n in range(nthreads): + t = threading.Thread(target=time_constructions, args=(depths,)) + t.start() + threadlist.append(t) + for t in threadlist: + t.join() + print "All %d threads finished" % (nthreads,) + +def main(depths=DEFAULT_DEPTHS, threads=1): println("Garbage Collector Test") println(" Stretching memory with a binary tree of depth %d" % kStretchTreeDepth) print_diagnostics() @@ -129,8 +150,10 @@ i += 1 print_diagnostics() - for d in depths: - time_construction(d) + if threads > 1: + time_parallel_constructions(depths, threads) + else: + time_constructions(depths) if long_lived_tree is None or array[1024] != 1.0/1024: println("FAILED") @@ -141,10 +164,41 @@ println("Completed in %f ms." % ((t_finish-t_start)*1000.)) +def argerror(): + print "Usage:" + print " ", USAGE + return 2 + +def entry_point(argv): + depths = DEFAULT_DEPTHS + threads = 1 + repeatcount = 1 + for arg in argv[1:]: + if arg.startswith('--threads='): + arg = arg[len('--threads='):] + if not ENABLE_THREADS: + print "threads disabled (they cannot be translated)" + return 1 + try: + threads = int(arg) + except ValueError: + return argerror() + elif arg.startswith('--depths='): + arg = arg[len('--depths='):].split(',') + try: + depths = [int(s) for s in arg] + except ValueError: + return argerror() + else: + try: + repeatcount = int(arg) + except ValueError: + return argerror() + for i in range(repeatcount): + main(depths, threads) + return 0 + + if __name__ == '__main__': import sys - if len(sys.argv) > 1: - depths = [int(s) for s in sys.argv[1:]] - main(depths) - else: - main() + sys.exit(entry_point(sys.argv)) Modified: pypy/dist/pypy/translator/goal/targetgcbench.py ============================================================================== --- pypy/dist/pypy/translator/goal/targetgcbench.py (original) +++ pypy/dist/pypy/translator/goal/targetgcbench.py Fri Jun 6 15:46:41 2008 @@ -1,20 +1,11 @@ import os, sys from pypy.translator.goal import gcbench -def entry_point(argv): - if len(argv) > 1: - n = int(argv[1]) - else: - n = 1 - while n > 0: - gcbench.main() - n -= 1 - return 0 - # _____ Define and setup target ___ def target(*args): - return entry_point, None + gcbench.ENABLE_THREADS = False # not RPython + return gcbench.entry_point, None """ Why is this a stand-alone target? From arigo at codespeak.net Fri Jun 6 15:52:01 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 15:52:01 +0200 (CEST) Subject: [pypy-svn] r55635 - pypy/dist/pypy/translator/goal Message-ID: <20080606135201.53EA516843E@codespeak.net> Author: arigo Date: Fri Jun 6 15:52:00 2008 New Revision: 55635 Modified: pypy/dist/pypy/translator/goal/gcbench.py Log: For comparison purposes, let "--threads=1" mean that we want to have 1 background thread, instead of only running the logic in the main thread. This lets us measure e.g. the sys.checkinterval overhead. Modified: pypy/dist/pypy/translator/goal/gcbench.py ============================================================================== --- pypy/dist/pypy/translator/goal/gcbench.py (original) +++ pypy/dist/pypy/translator/goal/gcbench.py Fri Jun 6 15:52:00 2008 @@ -128,7 +128,7 @@ t.join() print "All %d threads finished" % (nthreads,) -def main(depths=DEFAULT_DEPTHS, threads=1): +def main(depths=DEFAULT_DEPTHS, threads=0): println("Garbage Collector Test") println(" Stretching memory with a binary tree of depth %d" % kStretchTreeDepth) print_diagnostics() @@ -150,7 +150,7 @@ i += 1 print_diagnostics() - if threads > 1: + if threads: time_parallel_constructions(depths, threads) else: time_constructions(depths) @@ -171,7 +171,7 @@ def entry_point(argv): depths = DEFAULT_DEPTHS - threads = 1 + threads = 0 repeatcount = 1 for arg in argv[1:]: if arg.startswith('--threads='): From arigo at codespeak.net Fri Jun 6 15:57:00 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 6 Jun 2008 15:57:00 +0200 (CEST) Subject: [pypy-svn] r55636 - pypy/dist/pypy/translator/goal Message-ID: <20080606135700.1D8D016843E@codespeak.net> Author: arigo Date: Fri Jun 6 15:56:59 2008 New Revision: 55636 Modified: pypy/dist/pypy/translator/goal/gcbench.py Log: "println() => print". Modified: pypy/dist/pypy/translator/goal/gcbench.py ============================================================================== --- pypy/dist/pypy/translator/goal/gcbench.py (original) +++ pypy/dist/pypy/translator/goal/gcbench.py Fri Jun 6 15:56:59 2008 @@ -48,8 +48,6 @@ USAGE = """gcbench [num_repetitions] [--depths=N,N,N..] [--threads=N]""" ENABLE_THREADS = True -def println(s): - print s class Node(object): @@ -95,20 +93,20 @@ def time_construction(depth): niters = num_iters(depth) - println("Creating %d trees of depth %d" % (niters, depth)) + print "Creating %d trees of depth %d" % (niters, depth) t_start = time.time() for i in range(niters): temp_tree = Node() populate(depth, temp_tree) temp_tree = None t_finish = time.time() - println("\tTop down constrution took %f ms" % ((t_finish-t_start)*1000.)) + print "\tTop down constrution took %f ms" % ((t_finish-t_start)*1000.) t_start = time.time() for i in range(niters): temp_tree = make_tree(depth) temp_tree = None t_finish = time.time() - println("\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.)) + print "\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.) DEFAULT_DEPTHS = range(kMinTreeDepth, kMaxTreeDepth+1, 2) @@ -129,20 +127,20 @@ print "All %d threads finished" % (nthreads,) def main(depths=DEFAULT_DEPTHS, threads=0): - println("Garbage Collector Test") - println(" Stretching memory with a binary tree of depth %d" % kStretchTreeDepth) + print "Garbage Collector Test" + print " Stretching memory with a binary tree of depth %d" % kStretchTreeDepth print_diagnostics() t_start = time.time() temp_tree = make_tree(kStretchTreeDepth) temp_tree = None # Create a long lived object - println(" Creating a long-lived binary tree of depth %d" % kLongLivedTreeDepth) + print " Creating a long-lived binary tree of depth %d" % kLongLivedTreeDepth long_lived_tree = Node() populate(kLongLivedTreeDepth, long_lived_tree) # Create long-lived array, filling half of it - println(" Creating a long-lived array of %d doubles" % kArraySize) + print " Creating a long-lived array of %d doubles" % kArraySize array = [0.0] * kArraySize i = 1 while i < kArraySize/2: @@ -156,12 +154,14 @@ time_constructions(depths) if long_lived_tree is None or array[1024] != 1.0/1024: - println("FAILED") - return + raise Failed t_finish = time.time() print_diagnostics() - println("Completed in %f ms." % ((t_finish-t_start)*1000.)) + print "Completed in %f ms." % ((t_finish-t_start)*1000.) + +class Failed(Exception): + pass def argerror(): From fijal at codespeak.net Fri Jun 6 21:18:23 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 21:18:23 +0200 (CEST) Subject: [pypy-svn] r55637 - pypy/branch/c-backend-fun/pypy/translator/oosupport Message-ID: <20080606191823.3AB251684F3@codespeak.net> Author: fijal Date: Fri Jun 6 21:18:20 2008 New Revision: 55637 Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Log: Complicate treebuilder some more. Inline operations which are immediately before. This assumes left-to-right parameter computation! Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py ============================================================================== --- pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py (original) +++ pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Fri Jun 6 21:18:20 2008 @@ -33,18 +33,21 @@ # TODO: analyze graphs to determine which functions calls could have # side effects and which can be inlined safely. -def can_be_inlined(op, block): - for exit in block.exits: - if op.result in exit.args: - break - else: - return True +def can_be_inlined(op): try: llop = LL_OPERATIONS[op.opname] return llop.canfold except KeyError: return False +def check_not_in_exit(v, block): + for exit in block.exits: + if v in exit.args: + break + else: + return True + return False + def build_op_map(block): var_count = {} var_to_op = {} @@ -69,12 +72,29 @@ for i, v in enumerate(op.args): if var_count.get(v, None) == 1 and v not in block.inputargs: # "inline" the operation sub_i, sub_op = var_to_op[v] - if can_be_inlined(sub_op, block): + if can_be_inlined(sub_op): op.args[i] = SubOperation(sub_op) block.operations[sub_i] = None + # another pass + for num_op, op in enumerate(block.operations): + if op is not None: + for i, v in enumerate(op.args): + if (var_count.get(v, None) == 1 and v not in block.inputargs + and check_not_in_exit(v, block)): + sub_i, sub_op = var_to_op[v] + safe = True + for k in range(sub_i + 1, num_op): + if block.operations[sub_i] is not None: + safe = False + break + if safe: + op.args[i] = SubOperation(sub_op) + block.operations[sub_i] = None + if block.operations != (): block.operations = [op for op in block.operations if op is not None] + def build_trees(graph): if not getattr(graph, 'tree_built', False): for block in graph.iterblocks(): From fijal at codespeak.net Fri Jun 6 21:21:47 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 21:21:47 +0200 (CEST) Subject: [pypy-svn] r55638 - pypy/branch/c-backend-fun/pypy/translator/oosupport/test Message-ID: <20080606192147.5207C1684F3@codespeak.net> Author: fijal Date: Fri Jun 6 21:21:46 2008 New Revision: 55638 Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/test/test_treebuilder.py Log: Adapt a test. Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/test/test_treebuilder.py ============================================================================== --- pypy/branch/c-backend-fun/pypy/translator/oosupport/test/test_treebuilder.py (original) +++ pypy/branch/c-backend-fun/pypy/translator/oosupport/test/test_treebuilder.py Fri Jun 6 21:21:46 2008 @@ -76,6 +76,7 @@ def fn(i): kind = i & 3 # 2 bits str = "%x" % (kind,) + # ^^^^ kind is inlined here if kind == 0: # 00 bits res = "0" elif kind == 1: # 01 bits @@ -87,7 +88,7 @@ return res, str graph, eval_func = check_trees(fn, [int], backendopt=True) block = graph.startblock - assert len(block.operations) == 5 + assert len(block.operations) == 4 v0 = block.operations[0].result assert block.exitswitch == v0 for x in range(4): From fijal at codespeak.net Fri Jun 6 21:23:10 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 6 Jun 2008 21:23:10 +0200 (CEST) Subject: [pypy-svn] r55640 - pypy/branch/c-backend-fun/pypy/translator/oosupport Message-ID: <20080606192310.E5E461684F3@codespeak.net> Author: fijal Date: Fri Jun 6 21:23:09 2008 New Revision: 55640 Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Log: Leave a comment Modified: pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py ============================================================================== --- pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py (original) +++ pypy/branch/c-backend-fun/pypy/translator/oosupport/treebuilder.py Fri Jun 6 21:23:09 2008 @@ -76,6 +76,10 @@ op.args[i] = SubOperation(sub_op) block.operations[sub_i] = None # another pass + # XXX this assumes left-to-right parameter order evaluation, + # we need to differentiate it depending on how backend solves + # the problem (for C and direct/indirect_call is right to left as + # far as I remember) for num_op, op in enumerate(block.operations): if op is not None: for i, v in enumerate(op.args): From fijal at codespeak.net Sat Jun 7 01:37:40 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 7 Jun 2008 01:37:40 +0200 (CEST) Subject: [pypy-svn] r55642 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080606233740.A94D8168452@codespeak.net> Author: fijal Date: Sat Jun 7 01:37:39 2008 New Revision: 55642 Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Log: Revert changes that prevented tests from running. We really need to make all strings unicode. Modified: pypy/branch/js-refactoring/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring/pypy/lang/js/interpreter.py Sat Jun 7 01:37:39 2008 @@ -224,7 +224,6 @@ elif (i + 5 < lgt and strval[i + 1] == 'u' and _ishex(strval[i + 2]) and _ishex(strval[i + 3]) and _ishex(strval[i + 4]) and _ishex(strval[i + 5])): - raise ThrowException(W_String('not implemented')) ch = unichr(int(strval[i+2:i+6], 16)) i += 5 i += 1 @@ -368,7 +367,6 @@ for arg in args: i = arg.ToInt32(ctx) % 65536 # XXX should be uint16 if i > 255: - raise ThrowException(W_String('not implemented')) temp.append(unichr(i)) else: temp.append(chr(i)) From fijal at codespeak.net Sat Jun 7 01:41:08 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 7 Jun 2008 01:41:08 +0200 (CEST) Subject: [pypy-svn] r55643 - pypy/branch/js-refactoring/pypy/translator/goal Message-ID: <20080606234108.DAC2F16845F@codespeak.net> Author: fijal Date: Sat Jun 7 01:41:08 2008 New Revision: 55643 Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Log: Adapt a bit target to work with -f Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py ============================================================================== --- pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py (original) +++ pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Sat Jun 7 01:41:08 2008 @@ -1,5 +1,7 @@ """ A simple standalone target for the javascript interpreter. + +Usage: js-c [-f] jsourcefile [-f] other_source ... """ import sys @@ -7,17 +9,29 @@ # __________ Entry point __________ +def run_file(interp, name): + t = load_file(name) + interp.run(t) def entry_point(argv): - if len(argv) == 2: - t = load_file(argv[1]) - interp = Interpreter() - interp.run(t) - return 0 - else: - print "Usage: %s jsourcefile" % argv[0] - return 1 - + i = 1 + interp = Interpreter() + while i < len(argv): + arg = argv[i] + if arg == '-f': + if i == len(argv) - 1: + print __doc__ + return 1 + i += 1 + run_file(interp, argv[i]) + elif arg.startswith('-'): + print "Unsupported option %s" % arg + print __doc__ + return 1 + else: + run_file(interp, argv[i]) + i += 1 + return 0 # _____ Define and setup target ___ def target(driver, args): From antocuni at codespeak.net Sat Jun 7 10:53:39 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 7 Jun 2008 10:53:39 +0200 (CEST) Subject: [pypy-svn] r55644 - pypy/dist/pypy/translator/goal Message-ID: <20080607085339.BA8A61684ED@codespeak.net> Author: antocuni Date: Sat Jun 7 10:53:37 2008 New Revision: 55644 Added: pypy/dist/pypy/translator/goal/runpystone.py (contents, props changed) Log: a short script to run pystone directly Added: pypy/dist/pypy/translator/goal/runpystone.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/goal/runpystone.py Sat Jun 7 10:53:37 2008 @@ -0,0 +1,2 @@ +from test import pystone +pystone.main() From arigo at codespeak.net Sat Jun 7 11:43:27 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 7 Jun 2008 11:43:27 +0200 (CEST) Subject: [pypy-svn] r55645 - in pypy/dist/pypy/rpython: lltypesystem test Message-ID: <20080607094327.D70EF1684EE@codespeak.net> Author: arigo Date: Sat Jun 7 11:43:25 2008 New Revision: 55645 Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: issue374 resolved Implement the last missing case for conversion between PBCs of functions involving SmallFunctionSetPBCRepr. Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rpbc.py Sat Jun 7 11:43:25 2008 @@ -16,6 +16,8 @@ SingleFrozenPBCRepr, none_frozen_pbc_repr, get_concrete_calltable from pypy.rpython.lltypesystem import rclass, llmemory from pypy.tool.sourcetools import has_varargs +from pypy.rlib.unroll import unrolling_iterable +from pypy.rlib.debug import ll_assert from pypy.rpython import callparse @@ -132,6 +134,7 @@ self.lowleveltype = Char self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc) self._conversion_tables = {} + self._compression_function = None self._dispatch_cache = {} def _setup_repr(self): @@ -269,11 +272,31 @@ return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int], resulttype=r_ptr.lowleveltype) +def compression_function(r_set): + if r_set._compression_function is None: + table = [] + for i, p in enumerate(r_set.c_pointer_table.value): + table.append((chr(i), p)) + last_c, last_p = table[-1] + unroll_table = unrolling_iterable(table[:-1]) + def ll_compress(fnptr): + for c, p in unroll_table: + if fnptr == p: + return c + else: + ll_assert(fnptr == last_p, "unexpected function pointer") + return last_c + r_set._compression_function = ll_compress + return r_set._compression_function + class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)): def convert_from_to((r_ptr, r_set), v, llops): - assert r_ptr.lowleveltype is Void - desc, = r_ptr.s_pbc.descriptions - return inputconst(Char, r_set.convert_desc(desc)) + if r_ptr.lowleveltype is Void: + desc, = r_ptr.s_pbc.descriptions + return inputconst(Char, r_set.convert_desc(desc)) + else: + ll_compress = compression_function(r_set) + return llops.gendirectcall(ll_compress, v) def conversion_table(r_from, r_to): if r_to in r_from._conversion_tables: Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Sat Jun 7 11:43:25 2008 @@ -1927,10 +1927,6 @@ kwds['config'] = self.config return TestLLtype.interpret(self, fn, args, **kwds) - def test_shrink_pbc_set(self): - # fails with config.translation.withsmallfuncsets == 3 - py.test.skip("XXX not implemented") - def test_smallfuncsets_basic(): from pypy.translator.translator import TranslationContext, graphof from pypy.config.pypyoption import get_pypy_config From antocuni at codespeak.net Sat Jun 7 11:59:23 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 7 Jun 2008 11:59:23 +0200 (CEST) Subject: [pypy-svn] r55646 - pypy/dist/pypy/doc/config Message-ID: <20080607095923.B4E441684F6@codespeak.net> Author: antocuni Date: Sat Jun 7 11:59:22 2008 New Revision: 55646 Added: pypy/dist/pypy/doc/config/objspace.usemodules._lsprof.txt (contents, props changed) Log: add missing doc for the new option Added: pypy/dist/pypy/doc/config/objspace.usemodules._lsprof.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/config/objspace.usemodules._lsprof.txt Sat Jun 7 11:59:22 2008 @@ -0,0 +1 @@ +Use the '_lsprof' module. From antocuni at codespeak.net Sat Jun 7 12:04:01 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 7 Jun 2008 12:04:01 +0200 (CEST) Subject: [pypy-svn] r55647 - pypy/dist/pypy/lib/test2 Message-ID: <20080607100401.B6EFB1684F3@codespeak.net> Author: antocuni Date: Sat Jun 7 12:04:01 2008 New Revision: 55647 Modified: pypy/dist/pypy/lib/test2/test_itertools.py Log: bad anto, this test was completely buggy Modified: pypy/dist/pypy/lib/test2/test_itertools.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_itertools.py (original) +++ pypy/dist/pypy/lib/test2/test_itertools.py Sat Jun 7 12:04:01 2008 @@ -5,7 +5,7 @@ cls.space = gettestobjspace() cls.w_itertools = cls.space.appexec([], "(): import itertools; return itertools") - def test_chain(): - it = itertools.chain([], [1, 2, 3]) + def test_chain(self): + it = self.itertools.chain([], [1, 2, 3]) lst = list(it) assert lst == [1, 2, 3] From arigo at codespeak.net Sat Jun 7 12:35:50 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 7 Jun 2008 12:35:50 +0200 (CEST) Subject: [pypy-svn] r55648 - in pypy/dist/pypy/module: signal thread Message-ID: <20080607103550.2D9051684F7@codespeak.net> Author: arigo Date: Sat Jun 7 12:35:48 2008 New Revision: 55648 Modified: pypy/dist/pypy/module/signal/interp_signal.py pypy/dist/pypy/module/thread/threadlocals.py Log: Two small tweaks that reduce a lot the overhead of using threads in a thread-aware pypy-c. Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Sat Jun 7 12:35:48 2008 @@ -31,7 +31,9 @@ pypysig_ignore = external('pypysig_ignore', [rffi.INT], lltype.Void) pypysig_default = external('pypysig_default', [rffi.INT], lltype.Void) pypysig_setflag = external('pypysig_setflag', [rffi.INT], lltype.Void) -pypysig_poll = external('pypysig_poll', [], rffi.INT) +pypysig_poll = external('pypysig_poll', [], rffi.INT, threadsafe=False) +# don't bother releasing the GIL around a call to pypysig_poll: it's +# pointless and a performance issue class CheckSignalAction(Action): """A repeatitive action at the space level, checking if the Modified: pypy/dist/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/dist/pypy/module/thread/threadlocals.py (original) +++ pypy/dist/pypy/module/thread/threadlocals.py Sat Jun 7 12:35:48 2008 @@ -9,10 +9,19 @@ def __init__(self): self._valuedict = {} # {thread_ident: ExecutionContext()} self._mainthreadident = 0 + self._mostrecentkey = 0 # fast minicaching for the common case + self._mostrecentvalue = None # fast minicaching for the common case def getvalue(self): ident = thread.get_ident() - return self._valuedict.get(ident, None) + if ident == self._mostrecentkey: + return self._mostrecentvalue + else: + value = self._valuedict.get(ident, None) + # slow path: update the minicache + self._mostrecentkey = ident + self._mostrecentvalue = value + return value def setvalue(self, value): ident = thread.get_ident() @@ -25,6 +34,9 @@ del self._valuedict[ident] except KeyError: pass + # update the minicache to prevent it from containing an outdated value + self._mostrecentkey = ident + self._mostrecentvalue = value def getmainthreadvalue(self): ident = self._mainthreadident From arigo at codespeak.net Sat Jun 7 13:01:22 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 7 Jun 2008 13:01:22 +0200 (CEST) Subject: [pypy-svn] r55649 - in pypy/dist/pypy/rpython: lltypesystem ootypesystem test Message-ID: <20080607110122.77A9F16841E@codespeak.net> Author: arigo Date: Sat Jun 7 13:01:20 2008 New Revision: 55649 Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/test/test_rstr.py Log: * Fix failures in test_runicode (test_(r)find_empty_string) * Improve the tests by hard-coding the expected results instead of relying on CPython's changing behavior * Typo in a test, meaning that rfind() was not really tested! * Fix bug in rfind() found by really testing it * Fix ootype to work around CPython 2.4 unicode.(r)find corner case bugs. Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Sat Jun 7 13:01:20 2008 @@ -514,6 +514,8 @@ if end > len(s1.chars): end = len(s1.chars) if len2 == 0: + if (end-start) < 0: + return -1 return end # Construct the array of possible restarting positions T = malloc( SIGNED_ARRAY, len2 ) Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Sat Jun 7 13:01:20 2008 @@ -1238,10 +1238,14 @@ def ll_find(self, s, start, end): # NOT_RPYTHON + if start > len(self._str): # workaround to cope with corner case + return -1 # bugs in CPython 2.4 unicode.find('') return self._str.find(s._str, start, end) def ll_rfind(self, s, start, end): # NOT_RPYTHON + if start > len(self._str): # workaround to cope with corner case + return -1 # bugs in CPython 2.4 unicode.rfind('') return self._str.rfind(s._str, start, end) def ll_count(self, s, start, end): Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Sat Jun 7 13:01:20 2008 @@ -281,9 +281,9 @@ x+= s.find(const(''), i, i)*100 x+= s.find(const(''), i, i+1)*1000 return x - for i in range(5): + for i, expected in enumerate([0, 1110, 2220, 3330, -1110, -1110]): res = self.interpret(f, [i]) - assert res == f(i) + assert res == expected def test_rfind(self): const = self.const @@ -306,14 +306,14 @@ def f(i): assert i >= 0 s = const("abc") - x = s.find(const('')) - x+= s.find(const(''), i)*10 - x+= s.find(const(''), i, i)*100 - x+= s.find(const(''), i, i+1)*1000 + x = s.rfind(const('')) + x+= s.rfind(const(''), i)*10 + x+= s.rfind(const(''), i, i)*100 + x+= s.rfind(const(''), i, i+1)*1000 return x - for i in range(5): + for i, expected in enumerate([1033, 2133, 3233, 3333, 3-1110, 3-1110]): res = self.interpret(f, [i]) - assert res == f(i) + assert res == expected def test_find_char(self): const = self.const From arigo at codespeak.net Sat Jun 7 13:03:30 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 7 Jun 2008 13:03:30 +0200 (CEST) Subject: [pypy-svn] r55650 - pypy/dist/pypy/tool/test Message-ID: <20080607110330.B372116841E@codespeak.net> Author: arigo Date: Sat Jun 7 13:03:29 2008 New Revision: 55650 Modified: pypy/dist/pypy/tool/test/test_tab.py Log: Don't follow symlinks to directories when checking for tabs. Modified: pypy/dist/pypy/tool/test/test_tab.py ============================================================================== --- pypy/dist/pypy/tool/test/test_tab.py (original) +++ pypy/dist/pypy/tool/test/test_tab.py Sat Jun 7 13:03:29 2008 @@ -23,7 +23,7 @@ data = f.read() f.close() assert '\t' not in data, "%r contains tabs!" % (reldir,) - elif os.path.isdir(path): + elif os.path.isdir(path) and not os.path.islink(path): for entry in os.listdir(path): if not entry.startswith('.'): walk('%s/%s' % (reldir, entry)) From pypy-svn at codespeak.net Sat Jun 7 13:51:06 2008 From: pypy-svn at codespeak.net (Viagra Inc. ®) Date: Sat, 7 Jun 2008 13:51:06 +0200 (CEST) Subject: [pypy-svn] June 71% Sale! Message-ID: <20080607024928.4688.qmail@goe242.internetdsl.tpnet.pl> An HTML attachment was scrubbed... URL: From cami at codespeak.net Sat Jun 7 14:48:45 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sat, 7 Jun 2008 14:48:45 +0200 (CEST) Subject: [pypy-svn] r55651 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080607124845.8A04216844C@codespeak.net> Author: cami Date: Sat Jun 7 14:48:43 2008 New Revision: 55651 Modified: pypy/dist/pypy/lang/gameboy/joypad.py pypy/dist/pypy/lang/gameboy/test/test_cartridge.py pypy/dist/pypy/lang/gameboy/test/test_joypad.py Log: fixed bug in joypad, returned value was incorrect Modified: pypy/dist/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/joypad.py Sat Jun 7 14:48:43 2008 @@ -18,9 +18,9 @@ self.reset() def reset(self): - self.joyp = 0xF - self.button_code = 0xF - self.cycles = constants.JOYPAD_CLOCK + self.read_control = 0xF + self.button_code = 0xF + self.cycles = constants.JOYPAD_CLOCK def get_cycles(self): return self.cycles @@ -34,21 +34,21 @@ def write(self, address, data): if address == constants.JOYP: - self.joyp = (self.joyp & 0xC) + (data & 0x3) + self.read_control = (self.read_control & 0xC) + ((data & 0x30)>>4) self.update() def read(self, address): if address == constants.JOYP: - return (self.joyp << 4) + self.button_code + return (self.read_control << 4) + self.button_code return 0xFF def update(self): oldButtons = self.button_code - if self.joyp & 0xF0 == 0x10: + if self.read_control & 0x3 == 1: self.button_code = self.driver.get_button_code() - elif self.joyp & 0xF0 == 0x20: + elif self.read_control & 0x3 == 2: self.button_code = self.driver.get_direction_code() - else: + elif self.read_control & 0x3 == 3: self.button_code = 0xF if oldButtons != self.button_code: self.interrupt.raise_interrupt(constants.JOYPAD) Modified: pypy/dist/pypy/lang/gameboy/test/test_cartridge.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cartridge.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cartridge.py Sat Jun 7 14:48:43 2008 @@ -18,7 +18,7 @@ def get_cartridge_managers(): pass -def get_cartridge(): +def get_cartridge_file(): ctrg = CartridgeFile() return ctrg @@ -41,63 +41,63 @@ # STORE MANAGER TEST ----------------------------------------------------------- -def test_cartridge_init(): - cartridge = get_cartridge() +def test_cartridge_file_init(): + cartridge_file = get_cartridge_file() - assert cartridge.cartridge_name is "" - assert cartridge.cartridge_stream is None - assert cartridge.cartridge_file_contents is None + assert cartridge_file.cartridge_name is "" + assert cartridge_file.cartridge_stream is None + assert cartridge_file.cartridge_file_contents is None - assert cartridge.battery_name is "" - assert cartridge.battery_stream is None - assert cartridge.battery_file_contents is None + assert cartridge_file.battery_name is "" + assert cartridge_file.battery_stream is None + assert cartridge_file.battery_file_contents is None -def rest_cartridge_load(): - cartridge = get_cartridge() +def test_cartridge_file_load(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH+"/rom1/"+romName - cartridge.load(romFilePath) - #assert cartridge.cartridge_name == romName - assert cartridge.cartridge_file_path == romFilePath + cartridge_file.load(romFilePath) + #assert cartridge_file.cartridge_name == romName + assert cartridge_file.cartridge_file_path == romFilePath - assert cartridge.battery_name == romFile+constants.BATTERY_FILE_EXTENSION - assert cartridge.battery_file_path == romFilePath+constants.BATTERY_FILE_EXTENSION - assert cartridge.has_battery() == False + #assert cartridge_file.battery_name == romFilePath+constants.BATTERY_FILE_EXTENSION + assert cartridge_file.battery_file_path == romFilePath+constants.BATTERY_FILE_EXTENSION + assert cartridge_file.has_battery() == False -def test_cartridge_hasBattery(): - cartridge = get_cartridge() +def test_cartridge_file_hasBattery(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH+"/rom1/"+romName - cartridge.load(romFilePath) - assert cartridge.has_battery() == False + cartridge_file.load(romFilePath) + assert cartridge_file.has_battery() == False -def test_cartridge_read(): - cartridge = get_cartridge() - assert cartridge.read() is None +def test_cartridge_file_read(): + cartridge_file = get_cartridge_file() + assert cartridge_file.read() is None -def test_cartridge_remove_write_read_Battery(): - cartridge = get_cartridge() +def test_cartridge_file_remove_write_read_Battery(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH + "/rom1/"+romName - cartridge.load(romFilePath) - cartridge.remove_battery() - assert cartridge.has_battery() == False - - cartridge.write_battery(MAPPED_CONTENT) - assert cartridge.has_battery() == True - assert cartridge.read_battery() == MAPPED_CONTENT + cartridge_file.load(romFilePath) + cartridge_file.remove_battery() + assert cartridge_file.has_battery() == False + + cartridge_file.write_battery(MAPPED_CONTENT) + assert cartridge_file.has_battery() == True + assert cartridge_file.read_battery() == MAPPED_CONTENT - cartridge.remove_battery() - assert cartridge.has_battery() == False + cartridge_file.remove_battery() + assert cartridge_file.has_battery() == False Modified: pypy/dist/pypy/lang/gameboy/test/test_joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_joypad.py Sat Jun 7 14:48:43 2008 @@ -200,66 +200,93 @@ def test_reset(joypad=None): if joypad is None: joypad = get_joypad() - assert joypad.joyp == 0xF + assert joypad.read_control == 0xF assert joypad.cycles == constants.JOYPAD_CLOCK + assert joypad.read(constants.JOYP) == 0xFF def test_emulate(): - joypad = get_joypad() - ticks = 2 - cycles = joypad.cycles - joypad.emulate(ticks) - assert cycles - joypad.cycles == ticks + joypad = get_joypad() + joypad.cycles = 10 + joypad.emulate(5) + assert joypad.cycles == 5 def test_emulate_zero_ticks(): joypad = get_joypad() joypad.cycles = 2 - ticks = 2 - joypad.emulate(ticks) + joypad.emulate(2) assert joypad.cycles == constants.JOYPAD_CLOCK def test_emulate_zero_ticks_update(): joypad = get_joypad() - value = 0x1 - joypad.joyp = value - joypad.driver.button_code = 0x4 - joypad.driver.raised = True - joypad.cycles = 2 - ticks = 2 - joypad.emulate(ticks) + joypad.read_control = 0x2 + joypad.driver.button_up() + assert joypad.driver.get_direction_code() == constants.BUTTON_UP + joypad.driver.raised = False + joypad.cycles = 2 + + assert joypad.button_code == 0xF + joypad.emulate(2) assert joypad.cycles == constants.JOYPAD_CLOCK - assert joypad.joyp == value - assert joypad.button_code == 0 + assert joypad.read_control == 2 + assert joypad.button_code == 0xF + assert joypad.interrupt.joypad.is_pending() == False + + joypad.driver.raised = True + joypad.cycles = 2 + assert joypad.button_code == 0xF + joypad.emulate(2) + assert joypad.cycles == constants.JOYPAD_CLOCK + assert joypad.read_control == 2 + assert joypad.button_code == constants.BUTTON_UP + assert joypad.interrupt.joypad.is_pending() == True def test_read_write(): joypad = get_joypad() - value = 0x2 - joypad.write(constants.JOYP, value) - joyp = 0xC + (value & 0x3) - assert joypad.joyp == joyp - joyp = (joyp << 4) + 0xF - assert joypad.read(constants.JOYP) == joyp + assert joypad.read(constants.JOYP) == 0xFF + joypad.write(constants.JOYP, 0x02) + assert joypad.read(constants.JOYP) == 0xCF assert joypad.read(constants.JOYP+1) == 0xFF - # no change on writing the wrong address - joypad.write(constants.JOYP+1, value+1) - assert joypad.read(constants.JOYP) == joyp + joypad.write(constants.JOYP, 0x00) + assert joypad.read(constants.JOYP) & 0xF0 == 0xC0 + + joypad.write(constants.JOYP, 0x10) + assert joypad.read(constants.JOYP) & 0xF0 == 0xD0 + + joypad.write(constants.JOYP, 0x20) + assert joypad.read(constants.JOYP) & 0xF0 == 0xE0 + + joypad.write(constants.JOYP, 0x30) + assert joypad.read(constants.JOYP) & 0xF0 == 0xF0 + + joypad.write(constants.JOYP, 0xFF) + assert joypad.read(constants.JOYP) & 0xF0 == 0xF0 def test_update(): joypad = get_joypad() + # toogle the buttons joypad.driver.button_select() assert joypad.driver.get_button_code() == constants.BUTTON_SELECT joypad.driver.button_up() assert joypad.driver.get_direction_code() == constants.BUTTON_UP assert joypad.button_code == 0xF - joypad.joyp = 0x1 + + joypad.write(constants.JOYP, 0x10) + joypad.update() + assert joypad.button_code == constants.BUTTON_SELECT + assert joypad.interrupt.joypad.is_pending() + + joypad.interrupt.joypad.set_pending(False) + joypad.write(constants.JOYP, 0x10) joypad.update() - assert joypad.button_code == (constants.BUTTON_SELECT | constants.BUTTON_UP) + assert joypad.button_code == constants.BUTTON_SELECT + assert joypad.interrupt.joypad.is_pending() == False - joypad.joyp = 0x2 + joypad.write(constants.JOYP, 0x20) joypad.update() - assert joypad.button_code == (constants.BUTTON_SELECT | constants.BUTTON_UP) + assert joypad.button_code == constants.BUTTON_UP - joypad.joyp = 0x3 + joypad.write(constants.JOYP, 0x30) joypad.update() assert joypad.button_code == 0xF From arigo at codespeak.net Sat Jun 7 15:36:01 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 7 Jun 2008 15:36:01 +0200 (CEST) Subject: [pypy-svn] r55652 - in pypy/dist/pypy: module/__pypy__ objspace/std Message-ID: <20080607133601.E509E1684E5@codespeak.net> Author: arigo Date: Sat Jun 7 15:35:59 2008 New Revision: 55652 Modified: pypy/dist/pypy/module/__pypy__/interp_magic.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/typeobject.py Log: Experimental check-in which could be reverted. This makes the method cache global instead of per-thread. It makes a pypy-c-thread almost as fast as a pypy-c-no-thread, when threads are not used (<2% difference). The reason is that getexecutioncontext() needs to call RPyThreadIdent(), which appears to be the main cause of a global slow-down of 4-5%. I don't know if there are real-world cases where the method cache would get significantly trashed by being shared between threads. An alternative to this check-in would be to improve getexecutioncontext(), e.g. by replacing the dict {thread_id: executioncontext} with a single executioncontext reference which is carefully saved and restored when the GIL is released. For now it would be too much cleverness for too little gain, so I'll skip. Modified: pypy/dist/pypy/module/__pypy__/interp_magic.py ============================================================================== --- pypy/dist/pypy/module/__pypy__/interp_magic.py (original) +++ pypy/dist/pypy/module/__pypy__/interp_magic.py Sat Jun 7 15:35:59 2008 @@ -24,15 +24,13 @@ """Return a tuple (method_cache_hits, method_cache_misses) for calls to methods with the name.""" assert space.config.objspace.std.withmethodcachecounter - ec = space.getexecutioncontext() - return space.newtuple([space.newint(ec.method_cache_hits.get(name, 0)), - space.newint(ec.method_cache_misses.get(name, 0)),]) + return space.newtuple([space.newint(space.method_cache_hits.get(name, 0)), + space.newint(space.method_cache_misses.get(name, 0)),]) method_cache_counter.unwrap_spec = [ObjSpace, str] def reset_method_cache_counter(space): """Reset the method cache counter to zero for all method names.""" assert space.config.objspace.std.withmethodcachecounter - ec = space.getexecutioncontext() - ec.method_cache_misses = {} - ec.method_cache_hits = {} + space.method_cache_misses = {} + space.method_cache_hits = {} Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sat Jun 7 15:35:59 2008 @@ -280,6 +280,16 @@ from pypy.objspace.std import builtinshortcut builtinshortcut.install_is_true(self, self.MM.nonzero, self.MM.len) + # set up the method cache + if self.config.objspace.std.withmethodcache: + SIZE = 1 << self.config.objspace.std.methodcachesizeexp + self.method_cache_versions = [None] * SIZE + self.method_cache_names = [None] * SIZE + self.method_cache_lookup_where = [(None, None)] * SIZE + if self.config.objspace.std.withmethodcachecounter: + self.method_cache_hits = {} + self.method_cache_misses = {} + # hack to avoid imports in the time-critical functions below for cls in self.model.typeorder: globals()[cls.__name__] = cls @@ -419,14 +429,6 @@ # execution context themselves (e.g. nearly all space methods) ec = ObjSpace.createexecutioncontext(self) ec._py_repr = None - if self.config.objspace.std.withmethodcache: - SIZE = 1 << self.config.objspace.std.methodcachesizeexp - ec.method_cache_versions = [None] * SIZE - ec.method_cache_names = [None] * SIZE - ec.method_cache_lookup_where = [(None, None)] * SIZE - if self.config.objspace.std.withmethodcachecounter: - ec.method_cache_hits = {} - ec.method_cache_misses = {} return ec def createframe(self, code, w_globals, closure=None): Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Sat Jun 7 15:35:59 2008 @@ -345,7 +345,6 @@ def lookup_where_with_method_cache(w_self, name): space = w_self.space assert space.config.objspace.std.withmethodcache - ec = space.getexecutioncontext() version_tag = w_self.version_tag if version_tag is None: tup = w_self._lookup_where(name) @@ -359,23 +358,23 @@ # the time - so using the fast current_object_addr_as_int() instead # of a slower solution like hash() is still a good trade-off. method_hash = r_uint(intmask(version_tag_as_int * hash(name))) >> SHIFT - cached_version_tag = ec.method_cache_versions[method_hash] + cached_version_tag = space.method_cache_versions[method_hash] if cached_version_tag is version_tag: - cached_name = ec.method_cache_names[method_hash] + cached_name = space.method_cache_names[method_hash] if cached_name is name: - tup = ec.method_cache_lookup_where[method_hash] + tup = space.method_cache_lookup_where[method_hash] if space.config.objspace.std.withmethodcachecounter: - ec.method_cache_hits[name] = \ - ec.method_cache_hits.get(name, 0) + 1 + space.method_cache_hits[name] = \ + space.method_cache_hits.get(name, 0) + 1 # print "hit", w_self, name return tup tup = w_self._lookup_where(name) - ec.method_cache_versions[method_hash] = version_tag - ec.method_cache_names[method_hash] = name - ec.method_cache_lookup_where[method_hash] = tup + space.method_cache_versions[method_hash] = version_tag + space.method_cache_names[method_hash] = name + space.method_cache_lookup_where[method_hash] = tup if space.config.objspace.std.withmethodcachecounter: - ec.method_cache_misses[name] = \ - ec.method_cache_misses.get(name, 0) + 1 + space.method_cache_misses[name] = \ + space.method_cache_misses.get(name, 0) + 1 # print "miss", w_self, name return tup From cami at codespeak.net Sat Jun 7 15:42:41 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sat, 7 Jun 2008 15:42:41 +0200 (CEST) Subject: [pypy-svn] r55653 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080607134241.62C691684ED@codespeak.net> Author: cami Date: Sat Jun 7 15:42:40 2008 New Revision: 55653 Modified: pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/gameboy.py pypy/dist/pypy/lang/gameboy/joypad.py pypy/dist/pypy/lang/gameboy/ram.py pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py pypy/dist/pypy/lang/gameboy/test/test_joypad.py pypy/dist/pypy/lang/gameboy/test/test_ram.py pypy/dist/pypy/lang/gameboy/video.py Log: tried to fix 2 complement bugs Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Sat Jun 7 15:42:40 2008 @@ -3,12 +3,21 @@ from pypy.lang.gameboy.ram import * from pypy.lang.gameboy.interrupt import * +# --------------------------------------------------------------------------- -class iRegister(object): +def process_2_complement(value): + # check if the left most bit is set + if (value >> 7) == 1: + return -((~value) & 0xFF) - 1 + else : + return value +# --------------------------------------------------------------------------- + +class AbstractRegister(object): def get(self, use_cycles=True): return 0xFF -class Register(iRegister): +class Register(AbstractRegister): def __init__(self, cpu, value=0): assert isinstance(cpu, CPU) @@ -36,7 +45,7 @@ #------------------------------------------------------------------------------ -class DoubleRegister(iRegister): +class DoubleRegister(AbstractRegister): def __init__(self, cpu, hi, lo, reset_value=0): assert isinstance(cpu, CPU) @@ -806,7 +815,7 @@ def get_fetchadded_sp(self): # 1 cycle - offset = self.process_2_complement(self.fetch()) # 1 cycle + offset = process_2_complement(self.fetch()) # 1 cycle s = (self.sp.get() + offset) & 0xFFFF self.f.reset() if (offset >= 0): @@ -821,12 +830,6 @@ self.f.h_flag = True return s - def process_2_complement(self, value): - # check if the left most bit is set - if (value >> 7) == 1: - return -((~value) & 0xFF) - 1 - else : - return value def complement_carry_flag(self): # CCF/SCF @@ -856,7 +859,7 @@ def relative_jump(self): # JR +nn, 3 cycles #pc = pc & 0xFF00 + ((pc & 0x00FF) + add) & 0xFF - self.pc.add(self.process_2_complement(self.fetch())) # 3 + 1 cycles + self.pc.add(process_2_complement(self.fetch())) # 3 + 1 cycles self.cycles += 1 def relative_conditional_jump(self, cc): Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Sat Jun 7 15:42:40 2008 @@ -16,7 +16,7 @@ from pypy.lang.gameboy.video import * from pypy.lang.gameboy.cartridge import * - + class GameBoy(object): def __init__(self): Modified: pypy/dist/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/joypad.py Sat Jun 7 15:42:40 2008 @@ -12,8 +12,8 @@ def __init__(self, joypad_driver, interrupt): assert isinstance(joypad_driver, JoypadDriver) - assert isinstance(interrupt, Interrupt ) - self.driver = joypad_driver + assert isinstance(interrupt, Interrupt) + self.driver = joypad_driver self.interrupt = interrupt self.reset() @@ -43,14 +43,14 @@ return 0xFF def update(self): - oldButtons = self.button_code + old_buttons = self.button_code if self.read_control & 0x3 == 1: self.button_code = self.driver.get_button_code() elif self.read_control & 0x3 == 2: self.button_code = self.driver.get_direction_code() elif self.read_control & 0x3 == 3: self.button_code = 0xF - if oldButtons != self.button_code: + if old_buttons != self.button_code: self.interrupt.raise_interrupt(constants.JOYPAD) @@ -107,7 +107,7 @@ return code def is_raised(self): - raised = self.raised + raised = self.raised self.raised = False return raised @@ -170,9 +170,9 @@ class Button(object): def __init__(self, code_value, opposite_button=None): - self.code_value = int(code_value) + self.code_value = int(code_value) self.opposite_button = opposite_button - self.pressed = False + self.pressed = False def get_code(self): if self.pressed: Modified: pypy/dist/pypy/lang/gameboy/ram.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/ram.py (original) +++ pypy/dist/pypy/lang/gameboy/ram.py Sat Jun 7 15:42:40 2008 @@ -33,10 +33,10 @@ # C000-DFFF Work RAM (8KB) # E000-FDFF Echo RAM if address >= 0xC000 and address <= 0xFDFF: - self.work_ram[address & 0x1FFF] = data + self.work_ram[address & 0x1FFF] = data & 0xFF # FF80-FFFE High RAM elif address >= 0xFF80 and address <= 0xFFFE: - self.hi_ram[address & 0x7F] = data + self.hi_ram[address & 0x7F] = data & 0xFF def read(self, address): # C000-DFFF Work RAM Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Sat Jun 7 15:42:40 2008 @@ -588,16 +588,14 @@ assert cpu.pc.get() == 0x1234+2 def test_process_2_complement(): - cpu = get_cpu() - - assert cpu.process_2_complement(0x00) == 0 - assert cpu.process_2_complement(0xFF) == -1 + assert process_2_complement(0x00) == 0 + assert process_2_complement(0xFF) == -1 for i in range(0x7E): - assert cpu.process_2_complement(i) == i + assert process_2_complement(i) == i for i in range(1, 0x7E): - assert cpu.process_2_complement(0xFF - i+1) == -i + assert process_2_complement(0xFF - i+1) == -i def test_relative_jump(): cpu = get_cpu() Modified: pypy/dist/pypy/lang/gameboy/test/test_joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_joypad.py Sat Jun 7 15:42:40 2008 @@ -75,20 +75,20 @@ # TEST JOYPAD DRIVER ----------------------------------------------------------- -def test_ini(): +def test_joypad_driver_ini(): driver = get_driver() assert driver.raised == False assert driver.get_button_code() == 0 assert driver.get_direction_code() == 0 -def test_isRaised(): +def test_joypad_driver_isRaised(): driver = get_driver() driver.raised = True assert driver.raised == True assert driver.is_raised() == True assert driver.raised == False -def test_button_code_values(): +def test_joypad_driver_button_code_values(): driver = get_driver() assert driver.up.code_value == constants.BUTTON_UP assert driver.right.code_value == constants.BUTTON_RIGHT @@ -99,6 +99,40 @@ assert driver.a.code_value == constants.BUTTON_A assert driver.b.code_value == constants.BUTTON_B +def test_joypad_driver_button_toggled_values(): + driver = get_driver() + driver.button_a() + assert driver.get_button_code() == 0x01 + + driver.reset() + driver.button_b() + assert driver.get_button_code() == 0x02 + + driver.reset() + driver.button_select() + assert driver.get_button_code() == 0x04 + + driver.reset() + driver.button_start() + assert driver.get_button_code() == 0x08 + +def test_joypad_driver_direction_toggled_values(): + driver = get_driver() + driver.button_up() + assert driver.get_direction_code() == 0x04 + + driver.reset() + driver.button_right() + assert driver.get_direction_code() == 0x01 + + driver.reset() + driver.button_down() + assert driver.get_direction_code() == 0x08 + + driver.reset() + driver.button_left() + assert driver.get_direction_code() == 0x02 + def test_toggle_opposite_directions(): driver = get_driver() Modified: pypy/dist/pypy/lang/gameboy/test/test_ram.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_ram.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_ram.py Sat Jun 7 15:42:40 2008 @@ -6,13 +6,27 @@ return RAM() +def test_ram_reset(): + ram = get_ram(); + assert len(ram.work_ram) == 8192 + assert len(ram.hi_ram) == 128 + ram.hi_ram = range(50) + ram.work_ram = range(50) + ram.reset() + + assert len(ram.work_ram) == 8192 + assert len(ram.hi_ram) == 128 + assert ram.work_ram == [0] * 8192 + assert ram.hi_ram == [0] * 128 + + + def test_ram_read_write(): ram = get_ram() - address = 0x00 value = 0x12 - ram.write(address, value) + ram.write(0x00, value) try: - ram.read(address) + ram.read(0x00) py.test.fail() except Exception: pass @@ -20,41 +34,50 @@ assert value not in ram.work_ram assert value not in ram.hi_ram - address = 0xC000 - ram.write(address, value) - assert ram.read(address) == value + ram.write(0xC000, value) + assert ram.read(0xC000) == value assert value in ram.work_ram assert value not in ram.hi_ram - address = 0xFDFF value += 1 - ram.write(address, value) - assert ram.read(address) == value + ram.write(0xFDFF, value) + assert ram.read(0xFDFF) == value assert value in ram.work_ram assert value not in ram.hi_ram - address = 0xFF80 value += 1 - ram.write(address, value) - assert ram.read(address) == value + ram.write(0xFF80, value) + assert ram.read(0xFF80) == value assert value in ram.hi_ram assert value not in ram.work_ram - address = 0xFFFE value += 1 - ram.write(address, value) - assert ram.read(address) == value + ram.write(0xFFFE, value) + assert ram.read(0xFFFE) == value assert value in ram.hi_ram assert value not in ram.work_ram - address += 1 value += 1 - ram.write(address, value) + ram.write(0xFFFF, value) try: - ram.read(address) + ram.read(0xFFFF) py.test.fail() except Exception: pass assert value not in ram.hi_ram - assert value not in ram.work_ram \ No newline at end of file + assert value not in ram.work_ram + +def test_read_write_work_ram(): + ram = get_ram(); + ram.hi_ram = None + for i in range(0xC000, 0xFDFF): + ram.write(i, i) + assert ram.read(i) == i & 0xFF + +def test_read_write_hi_ram(): + ram = get_ram(); + ram.work_ram = None + for i in range(0xFF80, 0xFFFE): + ram.write(i, i) + assert ram.read(i) == i & 0xFF \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Sat Jun 7 15:42:40 2008 @@ -5,6 +5,7 @@ from pypy.lang.gameboy import constants from pypy.lang.gameboy.ram import iMemory +from pypy.lang.gameboy.cpu import process_2_complement @@ -547,17 +548,20 @@ def draw_tiles(self, x, tileMap, tileData): while x < 168: if (self.control & 0x10) != 0: - tile = self.vram[tileMap] & 0xFF + tile = self.vram[tileMap] else: - tile = (self.vram[tileMap] ^ 0x80) & 0xFF + tile = (process_2_complement(self.vram[tileMap]) ^ 0x80) & 0xFF self.draw_tile(x, tileData + (tile << 4)) tileMap = (tileMap & 0x1FE0) + ((tileMap + 1) & 0x001F) x += 8 - + + def draw_tile(self, x, address): + pattern = self.get_pattern(address) + for i in range(0, 8): + self.line[x + i] = (pattern >> (7-i)) & 0x0101 + def get_pattern(self, address): - pattern = self.vram[address] & 0xFF - pattern += (self.vram[address + 1] & 0xFF) << 8 - return pattern + return self.vram[address] +(self.vram[address + 1]) << 8 def draw_object(self, caller, x, address, flags): pattern = self.get_pattern(address) @@ -590,11 +594,6 @@ color = pattern >> i if (color & 0x0202) != 0: caller.call(x + i + 1, color, mask) - - def draw_tile(self, x, address): - pattern = self.get_pattern(address) - for i in range(0, 8): - self.line[x + i] = (pattern >> (7-i)) & 0x0101 def draw_object_tile(self, x, address, flags): self.draw_object(set_tile_line_call_wrapper(self), x, address, flags) From santagada at codespeak.net Sat Jun 7 16:59:58 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sat, 7 Jun 2008 16:59:58 +0200 (CEST) Subject: [pypy-svn] r55654 - pypy/branch/js-refactoring/pypy/lang/js Message-ID: <20080607145958.05BAD1684E4@codespeak.net> Author: santagada Date: Sat Jun 7 16:59:56 2008 New Revision: 55654 Modified: pypy/branch/js-refactoring/pypy/lang/js/jscode.py Log: removed static methods 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 Sat Jun 7 16:59:56 2008 @@ -230,8 +230,7 @@ s6 = stack.pop().ToInt32(ctx) stack.append(self.operation(ctx, s5, s6)) - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): raise NotImplementedError class BaseBinaryOperation(Opcode): @@ -419,13 +418,11 @@ # XXX class SUB(BaseBinaryOperation): - @staticmethod - def operation(ctx, left, right): + def operation(self, ctx, left, right): return sub(ctx, left, right) class IN(BaseBinaryOperation): - @staticmethod - def operation(ctx, left, right): + def operation(self, ctx, left, right): if not isinstance(right, W_Object): raise ThrowException(W_String("TypeError")) name = left.ToString(ctx) @@ -456,23 +453,19 @@ class ADD(BaseBinaryOperation): - @staticmethod - def operation(ctx, left, right): + def operation(self, ctx, left, right): return plus(ctx, left, right) class BITAND(BaseBinaryBitwiseOp): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return W_IntNumber(op1&op2) class BITXOR(BaseBinaryBitwiseOp): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return W_IntNumber(op1^op2) class BITOR(BaseBinaryBitwiseOp): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return W_IntNumber(op1|op2) class URSH(BaseBinaryBitwiseOp): @@ -494,18 +487,15 @@ stack.append(W_IntNumber(op1 << intmask(op2 & 0x1F))) class MUL(BaseBinaryOperation): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return mult(ctx, op1, op2) class DIV(BaseBinaryOperation): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return division(ctx, op1, op2) class MOD(BaseBinaryOperation): - @staticmethod - def operation(ctx, op1, op2): + def operation(self, ctx, op1, op2): return mod(ctx, op1, op2) class UPLUS(BaseUnaryOperation): @@ -583,7 +573,8 @@ return self.decision(ctx, value, prev) class STORE_MEMBER_ADD(BaseStoreMemberAssign): - decision = staticmethod(ADD.operation) + def decision(self, ctx, value, prev): + return plus(ctx, value, prev) class STORE_MEMBER_POSTINCR(BaseStoreMember): def operation(self, *args): @@ -629,28 +620,36 @@ return result class STORE_ADD(BaseAssignOper): - operation = staticmethod(ADD.operation) + def operation(self, ctx, left, right): + return plus(ctx, left, right) class STORE_SUB(BaseAssignOper): - operation = staticmethod(SUB.operation) + def operation(self, ctx, left, right): + return sub(ctx, left, right) class STORE_MUL(BaseAssignOper): - operation = staticmethod(MUL.operation) + def operation(self, ctx, left, right): + return mult(ctx, left, right) class STORE_DIV(BaseAssignOper): - operation = staticmethod(DIV.operation) + def operation(self, ctx, left, right): + return division(ctx, left, right) class STORE_MOD(BaseAssignOper): - operation = staticmethod(MOD.operation) + def operation(self, ctx, left, right): + return mod(ctx, left, right) class STORE_BITAND(BaseAssignBitOper): - operation = staticmethod(BITAND.operation) + def operation(self, ctx, op1, op2): + return W_IntNumber(op1&op2) class STORE_BITOR(BaseAssignBitOper): - operation = staticmethod(BITOR.operation) + def operation(self, ctx, op1, op2): + return W_IntNumber(op1|op2) class STORE_BITXOR(BaseAssignBitOper): - operation = staticmethod(BITXOR.operation) + def operation(self, ctx, op1, op2): + return W_IntNumber(op1^op2) class STORE_POSTINCR(BaseStore): def process(self, ctx, name, stack): From cami at codespeak.net Sun Jun 8 14:55:14 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sun, 8 Jun 2008 14:55:14 +0200 (CEST) Subject: [pypy-svn] r55663 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080608125514.DF9C5168461@codespeak.net> Author: cami Date: Sun Jun 8 14:55:12 2008 New Revision: 55663 Modified: pypy/dist/pypy/lang/gameboy/constants.py pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/interrupt.py pypy/dist/pypy/lang/gameboy/joypad.py pypy/dist/pypy/lang/gameboy/ram.py pypy/dist/pypy/lang/gameboy/serial.py pypy/dist/pypy/lang/gameboy/test/test_cpu.py pypy/dist/pypy/lang/gameboy/test/test_interrupt.py pypy/dist/pypy/lang/gameboy/test/test_serial.py pypy/dist/pypy/lang/gameboy/test/test_timer.py pypy/dist/pypy/lang/gameboy/timer.py Log: renamed constants of timer and serlial for better readability adaoted tests fixed bug in interrupt: enable is not a bool its an int! adapted tests minor refactoring: mostly code formattinh Modified: pypy/dist/pypy/lang/gameboy/constants.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/constants.py (original) +++ pypy/dist/pypy/lang/gameboy/constants.py Sun Jun 8 14:55:12 2008 @@ -14,48 +14,48 @@ # ___________________________________________________________________________ -TYPE_ROM_ONLY = 0x00 +TYPE_ROM_ONLY = 0x00 -TYPE_MBC1 = 0x01 -TYPE_MBC1_RAM = 0x02 -TYPE_MBC1_RAM_BATTERY = 0x03 - -TYPE_MBC2 = 0x05 -TYPE_MBC2_BATTERY = 0x06 - -TYPE_MBC3_RTC_BATTERY = 0x0F -TYPE_MBC3_RTC_RAM_BATTERY = 0x10 -TYPE_MBC3 = 0x11 -TYPE_MBC3_RAM = 0x12 -TYPE_MBC3_RAM_BATTERY = 0x13 - -TYPE_MBC5 = 0x19 -TYPE_MBC5_RAM = 0x1A -TYPE_MBC5_RAM_BATTERY = 0x1B +TYPE_MBC1 = 0x01 +TYPE_MBC1_RAM = 0x02 +TYPE_MBC1_RAM_BATTERY = 0x03 + +TYPE_MBC2 = 0x05 +TYPE_MBC2_BATTERY = 0x06 + +TYPE_MBC3_RTC_BATTERY = 0x0F +TYPE_MBC3_RTC_RAM_BATTERY = 0x10 +TYPE_MBC3 = 0x11 +TYPE_MBC3_RAM = 0x12 +TYPE_MBC3_RAM_BATTERY = 0x13 + +TYPE_MBC5 = 0x19 +TYPE_MBC5_RAM = 0x1A +TYPE_MBC5_RAM_BATTERY = 0x1B TYPE_MBC5_RUMBLE = 0x1C TYPE_MBC5_RUMBLE_RAM = 0x1D TYPE_MBC5_RUMBLE_RAM_BATTERY = 0x1E -TYPE_HUC3_RTC_RAM = 0xFE -TYPE_HUC1_RAM_BATTERY = 0xFF +TYPE_HUC3_RTC_RAM = 0xFE +TYPE_HUC1_RAM_BATTERY = 0xFF -CARTRIDGE_TYPE_ADDRESS = 0x0147 -CARTRIDGE_ROM_SIZE_ADDRESS = 0x0148 -CARTRIDGE_RAM_SIZE_ADDRESS = 0x0149 -CARTRIDGE_RAM_SIZE_MAPPING = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768} -DESTINATION_CODE_ADDRESS = 0x014A -LICENSEE_ADDRESS = 0x014B -ROM_VERSION_ADDRESS = 0x014C -HEADER_CHECKSUM_ADDRESS = 0x014D -CHECKSUM_A_ADDRESS = 0x014E -CHECKSUM_B_ADDRESS = 0x014F +CARTRIDGE_TYPE_ADDRESS = 0x0147 +CARTRIDGE_ROM_SIZE_ADDRESS = 0x0148 +CARTRIDGE_RAM_SIZE_ADDRESS = 0x0149 +CARTRIDGE_RAM_SIZE_MAPPING = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768} +DESTINATION_CODE_ADDRESS = 0x014A +LICENSEE_ADDRESS = 0x014B +ROM_VERSION_ADDRESS = 0x014C +HEADER_CHECKSUM_ADDRESS = 0x014D +CHECKSUM_A_ADDRESS = 0x014E +CHECKSUM_B_ADDRESS = 0x014F # ROM Bank Size (16KB) -ROM_BANK_SIZE = 0x4000 +ROM_BANK_SIZE = 0x4000 # constants.RAM Bank Size (8KB) -RAM_BANK_SIZE = 0x2000 +RAM_BANK_SIZE = 0x2000 CARTRIDGE_FILE_EXTENSION = ".gb" CARTRIDGE_COLOR_FILE_EXTENSION = ".gbc" @@ -65,13 +65,13 @@ # CPU FLAGS # ___________________________________________________________________________ -Z_FLAG = 0x80 -N_FLAG = 0x40 -H_FLAG = 0x20 -C_FLAG = 0x10 +Z_FLAG = 0x80 +N_FLAG = 0x40 +H_FLAG = 0x20 +C_FLAG = 0x10 RESET_A = 0x01 -#RESET_F = 0xB0 +#RESET_F = 0xB0 RESET_F = 0x80 RESET_BC = 0x0013 RESET_DE = 0x00D8 @@ -85,8 +85,8 @@ # ___________________________________________________________________________ # Interrupt Registers -IE = 0xFFFF # Interrupt Enable -IF = 0xFF0F # Interrupt Flag +IE = 0xFFFF # Interrupt Enable +IF = 0xFF0F # Interrupt Flag # Interrupt Flags VBLANK = 0x01 # V-Blank Interrupt (INT 40h) @@ -115,19 +115,19 @@ WX = 0xFF4B # Window X Position (0-166) # OAM Register Addresses -OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) -OAM_SIZE = 0xA0 +OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) +OAM_SIZE = 0xA0 # Video RAM Addresses -VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) -VRAM_SIZE = 0x2000 +VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) +VRAM_SIZE = 0x2000 # VRAM Tile Data/Maps Addresses VRAM_DATA_A = 0x0000 # 4KB Tile Data (8000..8FFF) VRAM_DATA_B = 0x0800 # 4KB Tile Data (8800..97FF) -VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) -VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) +VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) +VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) #LCD Mode Durations @@ -141,7 +141,7 @@ MODE_1_END_TICKS = 1 # V-Blank Line 153 # Objects per Line -OBJECTS_PER_LINE = 10 +OBJECTS_PER_LINE = 10 # LCD Color Palette COLOR_MAP =[ @@ -181,14 +181,14 @@ # ___________________________________________________________________________ # Serial Clock Speed (8 x 1024 bits/sec) -SERIAL_CLOCK = GAMEBOY_CLOCK >> 16 +SERIAL_CLOCK = GAMEBOY_CLOCK >> 16 # Serial Idle Speed (128 Hz) SERIAL_IDLE_CLOCK = GAMEBOY_CLOCK >> 7 # Serial Register Addresses -SB = 0xFF01 # Serial Transfer Data -SC = 0xFF02 # Serial Transfer Control +SERIAL_TRANSFER_DATA = 0xFF01 +SERIAL_TRANSFER_CONTROL = 0xFF02 Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Sun Jun 8 14:55:12 2008 @@ -345,16 +345,16 @@ def emulate(self, ticks): self.cycles += ticks - self.handle_pending_interrupt() + self.handle_pending_interrupts() while self.cycles > 0: self.execute(self.fetch()) def emulate_step(self): - self.handle_pending_interrupt() + self.handle_pending_interrupts() self.execute(self.fetch()) - def handle_pending_interrupt(self): + def handle_pending_interrupts(self): if self.halted: if self.interrupt.is_pending(): self.halted = False @@ -914,7 +914,7 @@ # 1 cycle self.ime = True self.execute(self.fetch()) # 1 - self.handle_pending_interrupt() + self.handle_pending_interrupts() def halt(self): # HALT/STOP @@ -922,7 +922,7 @@ # emulate bug when interrupts are pending if not self.ime and self.interrupt.is_pending(): self.execute(self.memory.read(self.pc.get())) - self.handle_pending_interrupt() + self.handle_pending_interrupts() def stop(self): # 0 cycles Modified: pypy/dist/pypy/lang/gameboy/interrupt.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/interrupt.py (original) +++ pypy/dist/pypy/lang/gameboy/interrupt.py Sun Jun 8 14:55:12 2008 @@ -12,18 +12,25 @@ def reset(self): self._is_pending = self._reset + self.enabled = False def is_pending(self): return self._is_pending def set_pending(self, _is_pending=True): self._is_pending = _is_pending + + def is_enabled(self): + return self.enabled + + def set_enabled(self, enabled): + self.enabled = enabled +# -------------------------------------------------------------------- class Interrupt(iMemory): """ PyBoy GameBoy (TM) Emulator - Interrupt Controller """ @@ -34,9 +41,9 @@ self.reset() def create_interrupt_flags(self): - self.vblank = InterruptFlag(True, constants.VBLANK, 0x40) - self.lcd = InterruptFlag(False, constants.LCD, 0x48) - self.timer = InterruptFlag(False, constants.TIMER, 0x50) + self.vblank = InterruptFlag(True, constants.VBLANK, 0x40) + self.lcd = InterruptFlag(False, constants.LCD, 0x48) + self.timer = InterruptFlag(False, constants.TIMER, 0x50) self.serial = InterruptFlag(False, constants.SERIAL, 0x58) self.joypad = InterruptFlag(False, constants.JOYPAD, 0x60) @@ -50,55 +57,54 @@ self.mask_mapping[flag.mask] = flag def reset(self): - self.enable = False + self.set_enable_mask(0x0) for flag in self.interrupt_flags: flag.reset() - - def is_pending(self, mask=None): - if not self.enable: - return False - if mask is None: - return self.vblank.is_pending() - elif self.vblank.is_pending(): - return self.mask_mapping[mask].is_pending() - else: - return False - - def raise_interrupt(self, mask): - self.mask_mapping[mask].set_pending(True) - - def lower(self, mask): - self.mask_mapping[mask].set_pending(False) - + + def write(self, address, data): if address == constants.IE: - self.set_interrupt_enable(data) + self.set_enable_mask(data) elif address == constants.IF: self.set_fnterrupt_flag(data) def read(self, address): if address == constants.IE: - return self.get_interrupt_enable() + return self.get_enable_mask() elif address == constants.IF: return self.get_interrupt_flag() return 0xFF + + + def is_pending(self, mask=0xFF): + return (self.get_enable_mask() & self.get_interrupt_flag() & mask) != 0 + + def raise_interrupt(self, mask): + self.mask_mapping[mask].set_pending(True) - def get_interrupt_enable(self): - return int(self.enable) + def lower(self, mask): + self.mask_mapping[mask].set_pending(False) + + def get_enable_mask(self): + enabled = 0x00 + for interrupt_flag in self.interrupt_flags: + if interrupt_flag.is_enabled(): + enabled |= interrupt_flag.mask + return enabled | self.enable_rest_data; - def set_interrupt_enable(self, isEnabled=True): - self.enable = bool(isEnabled) + def set_enable_mask(self, enable_mask): + for flag in self.interrupt_flags: + flag.set_enabled((enable_mask & flag.mask) != 0) + self.enable_rest_data = enable_mask & 0xE0; + def get_interrupt_flag(self): flag = 0x00 for interrupt_flag in self.interrupt_flags: if interrupt_flag.is_pending(): flag |= interrupt_flag.mask - return 0xE0 | flag + return flag | 0xE0 def set_fnterrupt_flag(self, data): for flag in self.interrupt_flags: - if (data & flag.mask) != 0: - flag.set_pending(True) - else: - flag.set_pending(False) + flag.set_pending((data & flag.mask) != 0) Modified: pypy/dist/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/joypad.py Sun Jun 8 14:55:12 2008 @@ -31,6 +31,7 @@ if self.driver.is_raised(): self.update() self.cycles = constants.JOYPAD_CLOCK + #self.cycles = 150 def write(self, address, data): if address == constants.JOYP: Modified: pypy/dist/pypy/lang/gameboy/ram.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/ram.py (original) +++ pypy/dist/pypy/lang/gameboy/ram.py Sun Jun 8 14:55:12 2008 @@ -17,24 +17,20 @@ class RAM(iMemory): def __init__(self): - # Work RAM self.work_ram = [0]*8192 - # High RAM self.hi_ram = [0]*128 self.reset() def reset(self): - # Work RAM self.work_ram = [0]*8192 - # High RAM - self.hi_ram = [0]*128 + self.hi_ram = [0]*128 def write(self, address, data): # C000-DFFF Work RAM (8KB) # E000-FDFF Echo RAM if address >= 0xC000 and address <= 0xFDFF: self.work_ram[address & 0x1FFF] = data & 0xFF - # FF80-FFFE High RAM + # FF80-FFFE elif address >= 0xFF80 and address <= 0xFFFE: self.hi_ram[address & 0x7F] = data & 0xFF @@ -42,8 +38,8 @@ # C000-DFFF Work RAM # E000-FDFF Echo RAM if address >= 0xC000 and address <= 0xFDFF: - return self.work_ram[address & 0x1FFF] & 0xFF - # FF80-FFFE High RAM + return self.work_ram[address & 0x1FFF] + # FF80-FFFE elif address >= 0xFF80 and address <= 0xFFFE: - return self.hi_ram[address & 0x7F] & 0xFF + return self.hi_ram[address & 0x7F] raise Exception("Invalid Memory access, address out of range") \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/serial.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/serial.py (original) +++ pypy/dist/pypy/lang/gameboy/serial.py Sun Jun 8 14:55:12 2008 @@ -15,8 +15,8 @@ self.reset() def reset(self): - self.cycles = int(constants.SERIAL_CLOCK) - self.serial_data = 0x00 + self.cycles = int(constants.SERIAL_CLOCK) + self.serial_data = 0x00 self.serial_control = 0x00 def get_cycles(self): @@ -27,11 +27,17 @@ return self.cycles -= ticks if self.cycles <= 0: - self.serial_data = 0xFF + self.serial_data = 0xFF self.serial_control &= 0x7F - self.cycles = constants.SERIAL_IDLE_CLOCK + self.cycles = constants.SERIAL_IDLE_CLOCK self.interrupt.raise_interrupt(constants.SERIAL) + def write(self, address, data): + if address == constants.SERIAL_TRANSFER_DATA: + self.set_serial_data(data) + elif address == constants.SERIAL_TRANSFER_CONTROL: + self.set_serial_control(data) + def set_serial_data(self, data): self.serial_data = data @@ -39,25 +45,17 @@ self.serial_control = data # HACK: delay the serial interrupt self.cycles = constants.SERIAL_IDLE_CLOCK + constants.SERIAL_CLOCK - - def get_serial_data(self): - return self.serial_data - - def get_serial_control(self): - return self.serial_control - - def write(self, address, data): - address = int(address) - if address == constants.SB: - self.set_serial_data(data) - elif address == constants.SC: - self.set_serial_control(data) - + def read(self, address): - address = int(address) - if address == constants.SB: + if address == constants.SERIAL_TRANSFER_DATA: return self.get_serial_data() - elif address == constants.SC: + elif address == constants.SERIAL_TRANSFER_CONTROL: return self.get_serial_control() else: - return 0xFF \ No newline at end of file + return 0xFF + + def get_serial_data(self): + return self.serial_data + + def get_serial_control(self): + return self.serial_control \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu.py Sun Jun 8 14:55:12 2008 @@ -1068,8 +1068,9 @@ assert_default_registers(cpu, pc=value, sp=valueSp+2) # reti -def test_0xD9_returnFormInterrupt(): +def test_0xD9_return_form_interrupt(): cpu = get_cpu() + cpu.interrupt.reset() value = 0x1234 cpu.sp.set(0) prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1078,35 +1079,39 @@ cycle_test(cpu, 0xD9, 4+2) assert_default_registers(cpu, pc=value+1, sp=2) -def test_handleInterrupt(): +def test_handle_interrupt(): cpu = get_cpu() + cpu.interrupt.reset() cpu.halted = True cpu.cycles = 0xFF - cpu.handle_pending_interrupt() + cpu.handle_pending_interrupts() assert cpu.cycles == 0 cpu.reset() + cpu.interrupt.reset() cpu.halted = True - cpu.interrupt.set_interrupt_enable() + cpu.cycles = 4 + cpu.interrupt.set_enable_mask(0xFF) cpu.interrupt.vblank.set_pending() assert cpu.interrupt.is_pending() == True - cpu.cycles = 4 - cpu.handle_pending_interrupt() + assert cpu.halted == True + cpu.handle_pending_interrupts() assert cpu.cycles == 0 assert cpu.halted == False cpu.reset() + cpu.interrupt.reset() cpu.halted = False - cpu.ime = True + cpu.ime = True cpu.pc.set(0x1234) cpu.sp.set(0x02) sp = cpu.sp.get() - cpu.interrupt.set_interrupt_enable() + cpu.interrupt.set_enable_mask(0xFF) cpu.interrupt.vblank.set_pending() cpu.interrupt.lcd.set_pending() assert cpu.interrupt.is_pending() == True cpu.cycles = 0 - cpu.handle_pending_interrupt() + cpu.handle_pending_interrupts() assert cpu.cycles == 0 assert cpu.halted == False assert_default_registers(cpu, pc=cpu.interrupt.vblank.call_code, sp=sp-2) @@ -1182,40 +1187,53 @@ # di -def test_0xF3(): +def test_0xF3_disable_interrupt(): cpu = get_cpu() + cpu.interrupt.reset() cpu.ime == True cycle_test(cpu, 0xF3, 1) assert cpu.ime == False # ei -def test_0xFB(): - cpu = get_cpu() +def test_0xFB_enable_interrupt(): + cpu = get_cpu() + cpu.interrupt.reset() cpu.sp.set(0) - cpu.ime = False + cpu.ime = False cpu.halted = False prepare_for_fetch(cpu, 0x00) # nop 1 cycle + print cpu.interrupt.get_enable_mask() + assert cpu.interrupt.is_pending() == False cycle_test(cpu, 0xFB, 1+1) - assert cpu.ime == True + assert cpu.interrupt.is_pending() == False + assert cpu.ime == True cpu.reset() + cpu.interrupt.reset() cpu.sp.set(0) - cpu.ime = True + cpu.ime = True cpu.halted = False prepare_for_fetch(cpu, 0x00) # nop 1 cycle cpu.interrupt.vblank.set_pending() cpu.interrupt.serial.set_pending() - cpu.interrupt.set_interrupt_enable(True) + cpu.interrupt.set_enable_mask(0x1F) assert cpu.interrupt.is_pending() == True - assert cpu.halted == False - assert cpu.ime == True + assert cpu.halted == False + assert cpu.ime == True cycle_test(cpu, 0xFB, 1+1) - assert cpu.interrupt.is_pending() == False + assert cpu.interrupt.is_pending() == True assert cpu.interrupt.vblank.is_pending() == False - assert cpu.pc.get() == cpu.interrupt.vblank.call_code - assert cpu.ime == False + assert cpu.interrupt.serial.is_pending() == True + assert cpu.pc.get() == cpu.interrupt.vblank.call_code + assert cpu.ime == False + + cpu.ime = True + cycle_test(cpu, 0xFB, 1+1) + assert cpu.interrupt.vblank.is_pending() == False + assert cpu.interrupt.serial.is_pending() == False + assert cpu.interrupt.is_pending() == False -def conditionalCallTest(cpu, opCode, flagSetter): +def conditional_call_test(cpu, opCode, flagSetter): flagSetter(cpu, False) cpu.pc.set(0) f = cpu.f.get() @@ -1234,7 +1252,7 @@ # call_NZ_nnnn def test_0xC4(): cpu = get_cpu() - conditionalCallTest(cpu, 0xC4, setFlag0xC4) + conditional_call_test(cpu, 0xC4, setFlag0xC4) def setFlag0xC4(cpu, value): cpu.f.z_flag = not value @@ -1242,7 +1260,7 @@ # call_Z_nnnn def test_0xCC(): cpu = get_cpu() - conditionalCallTest(cpu, 0xCC, setFlag0xC4) + conditional_call_test(cpu, 0xCC, setFlag0xC4) def setFlag0xCC(cpu, value): cpu.f.c_flag = not value @@ -1250,7 +1268,7 @@ # call_NC_nnnn def test_0xD4(): cpu = get_cpu() - conditionalCallTest(cpu, 0xD4, setFlag0xC4) + conditional_call_test(cpu, 0xD4, setFlag0xC4) def setFlag0xD4(cpu, value): cpu.f.c_flag = value @@ -1258,13 +1276,13 @@ # call_C_nnnn def test_0xDC(): cpu = get_cpu() - conditionalCallTest(cpu, 0xDC, setFlag0xC4) + conditional_call_test(cpu, 0xDC, setFlag0xC4) def setFlag0xDC(cpu, value): cpu.f.z_flag = value # push_BC to push_AF -def test_0xC5_to_0xF5(): +def test_0xC5_to_0xF5_push(): cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.af] opCode = 0xC5 @@ -1279,7 +1297,7 @@ # call_nnnn -def test_0xCD(): +def test_0xCD_call(): cpu = get_cpu() fetchValue = 0x1234 cpu.sp.set(fetchValue) @@ -1301,7 +1319,7 @@ return cpu # add_A_nn -def test_0xC6(): +def test_0xC6_add_a_fetch(): a_nn_test(0xC6, 2, lambda a, b, cpu: a+b) # adc_A_nn Modified: pypy/dist/pypy/lang/gameboy/test/test_interrupt.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_interrupt.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_interrupt.py Sun Jun 8 14:55:12 2008 @@ -8,39 +8,57 @@ def test_reset(): - interrupt = get_interrupt() - assert interrupt.enable == 0 - assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + interrupt = get_interrupt() + assert interrupt.is_pending() == False + assert interrupt.get_enable_mask() == 0 + assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + interrupt.enable = 1 - interrupt.flag = ~constants.VBLANK + interrupt.flag = ~constants.VBLANK interrupt.reset() - assert interrupt.enable == 0 - assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + assert interrupt.get_enable_mask() == 0 + assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + + +def test_set_get_enable_mask(): + interrupt = get_interrupt() + assert interrupt.get_enable_mask() == 0x00 + interrupt.set_enable_mask(0x01) + assert interrupt.vblank.is_enabled() + assert interrupt.get_enable_mask() == 0x01 + + # enable all interrupts 0x01 - 0x10 + interrupt.set_enable_mask(0xFF) + assert interrupt.vblank.is_enabled() + assert interrupt.get_enable_mask() == 0xFF def test_is_pending(): interrupt = get_interrupt() - assert interrupt.is_pending() == False + interrupt.vblank.set_pending() + assert interrupt.is_pending() == False assert interrupt.is_pending(0x00) == False - interrupt.set_interrupt_enable(True) + + interrupt.set_enable_mask(0xFF) assert interrupt.is_pending() + interrupt.set_enable_mask(0x00) + assert interrupt.is_pending() == False def test_is_pending_common_masks(): interrupt = get_interrupt() for flag in interrupt.interrupt_flags: interrupt.reset() - interrupt.enable = True + interrupt.set_enable_mask(0xFF) assert interrupt.vblank.is_pending() flag.set_pending(True) assert interrupt.is_pending(flag.mask) - def test_raise_lower_interrupt(): interrupt = get_interrupt() masks= [constants.LCD, constants.TIMER, constants.JOYPAD, constants.SERIAL] - interrupt.set_interrupt_enable(True) + interrupt.set_enable_mask(0xFF) interrupt.vblank.set_pending(True) for mask in masks: interrupt.raise_interrupt(mask) @@ -51,13 +69,11 @@ def test_read_write(): interrupt = get_interrupt() - value = 1 - interrupt.write(constants.IE, value) - assert interrupt.enable == value - assert interrupt.read(constants.IE) == value + interrupt.write(constants.IE, 0x12) + assert interrupt.get_enable_mask() == 0x12 + assert interrupt.read(constants.IE) == 0x12 interrupt.reset() - value = constants.LCD - interrupt.write(constants.IF, value) - assert interrupt.get_interrupt_flag() == 0xE0 | value - assert interrupt.read(constants.IF) == 0xE0 | value + interrupt.write(constants.IF, constants.LCD) + assert interrupt.get_interrupt_flag() == 0xE0 | constants.LCD + assert interrupt.read(constants.IF) == 0xE0 | constants.LCD Modified: pypy/dist/pypy/lang/gameboy/test/test_serial.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_serial.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_serial.py Sun Jun 8 14:55:12 2008 @@ -20,10 +20,11 @@ def test_set_serial_control(): serial = get_serial() - value = 0x12 + value = 0x12 serial.set_serial_control(value) assert serial.get_serial_control() == value - assert serial.cycles == constants.SERIAL_IDLE_CLOCK + constants.SERIAL_CLOCK + assert serial.cycles == constants.SERIAL_IDLE_CLOCK + \ + constants.SERIAL_CLOCK def test_emulate(): @@ -36,13 +37,13 @@ serial.reset() serial.serial_control = 0x81 - serial.cycles = 10 + serial.cycles = 10 cycles = serial.cycles serial.emulate(2) assert serial.cycles > 0 - assert cycles-serial.cycles == 2 - assert serial.serial_data == 0 - assert serial.serial_control == 0x81 + assert cycles-serial.cycles == 2 + assert serial.serial_data == 0 + assert serial.serial_control == 0x81 assert serial.interrupt.serial.is_pending() == False serial.reset() @@ -51,21 +52,21 @@ serial.emulate(2) assert serial.serial_data == 0xFF assert serial.serial_control == 0x81 & 0x7F - assert serial.cycles == constants.SERIAL_IDLE_CLOCK + assert serial.cycles == constants.SERIAL_IDLE_CLOCK assert serial.interrupt.serial.is_pending() == True def test_read_write(): serial = get_serial() value = 0x12 - serial.write(constants.SB, value) - assert serial.read(constants.SB) == value - assert serial.serial_data == value + serial.write(constants.SERIAL_TRANSFER_DATA, value) + assert serial.read(constants.SERIAL_TRANSFER_DATA) == value + assert serial.serial_data == value value += 1 - serial.write(constants.SC, value) - assert serial.read(constants.SC) == value - assert serial.serial_control == value + serial.write(constants.SERIAL_TRANSFER_CONTROL, value) + assert serial.read(constants.SERIAL_TRANSFER_CONTROL) == value + assert serial.serial_control == value assert serial.read(0) == 0xFF \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/test/test_timer.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_timer.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_timer.py Sun Jun 8 14:55:12 2008 @@ -14,31 +14,31 @@ def test_reset(timer=None): if timer is None: timer = get_timer() - assert timer.div == 0 + assert timer.divider == 0 assert timer.divider_cycles == constants.DIV_CLOCK - assert timer.tima == 0 - assert timer.tma == 0 - assert timer.tac == 0 - assert timer.timer_cycles == constants.TIMER_CLOCK[0] - assert timer.timer_clock == constants.TIMER_CLOCK[0] + assert timer.timer_counter == 0 + assert timer.timer_modulo == 0 + assert timer.timer_control == 0 + assert timer.timer_cycles == constants.TIMER_CLOCK[0] + assert timer.timer_clock == constants.TIMER_CLOCK[0] def test_read_write(): - timer = get_timer() - timer.div = 10 - value = 0x11 + timer = get_timer() + timer.divider = 10 + value = 0x11 timer.write(constants.DIV, value) - assert timer.get_divider() == 0 + assert timer.get_divider() == 0 assert timer.read(constants.DIV) == 0 timer.reset() timer.write(constants.TIMA, value) - assert timer.get_timer_counter() == value + assert timer.get_timer_counter() == value assert timer.read(constants.TIMA) == value timer.reset() timer.write(constants.TMA, value) - assert timer.get_timer_modulo() == value + assert timer.get_timer_modulo() == value assert timer.read(constants.TMA) == value timer.reset() @@ -54,174 +54,174 @@ timer = get_timer() value = 0x12 timer.set_timer_control(value) - assert timer.tac == value - assert timer.timer_cycles == constants.TIMER_CLOCK[value & 0x03] - assert timer.timer_clock == constants.TIMER_CLOCK[value & 0x03] + assert timer.timer_control == value + assert timer.timer_cycles == constants.TIMER_CLOCK[value & 0x03] + assert timer.timer_clock == constants.TIMER_CLOCK[value & 0x03] timer.reset() - timer.tac = value+1 - timer.timer_clock = 0 - timer.timer_cycles = 0 + timer.timer_control = value+1 + timer.timer_clock = 0 + timer.timer_cycles = 0 timer.set_timer_control(value+1) - assert timer.tac == value+1 - assert timer.timer_clock == 0 - assert timer.timer_clock == 0 + assert timer.timer_control == value+1 + assert timer.timer_clock == 0 + assert timer.timer_clock == 0 def test_read_write_divider(): - timer = get_timer() - value = 0x12 - timer.div = value - assert timer.get_divider() == timer.div + timer = get_timer() + value = 0x12 + timer.divider = value + assert timer.get_divider() == timer.divider # divider resets on write timer.set_divider(value) assert timer.get_divider() == 0 def test_cycles(): - timer = get_timer() - value = 10 + timer = get_timer() + value = 10 timer.divider_cycles = value assert timer.get_cycles() == timer.divider_cycles - timer.tac = 0x04 - timer.timer_cycles = value-1 - timer.timer_cycles = value + timer.timer_control = 0x04 + timer.timer_cycles = value-1 + timer.timer_cycles = value assert timer.get_cycles() == timer.timer_cycles def test_emulate_divider(): - timer = get_timer() + timer = get_timer() timer.divider_cycles = 10 - timer.div = 1 + timer.divider = 1 timer.emulate_divider(2) - assert timer.div == 1 + assert timer.divider == 1 assert timer.divider_cycles == 8 def test_test_emulate_divider_below_zero(): - timer = get_timer() + timer = get_timer() timer.divider_cycles = 0 - timer.div = 1 + timer.divider = 1 timer.emulate_divider(2) assert timer.divider_cycles == constants.DIV_CLOCK - 2 - assert timer.div == 2 + assert timer.divider == 2 timer.divider_cycles = 0 - timer.div = 1 + timer.divider = 1 timer.emulate_divider(0) assert timer.divider_cycles == constants.DIV_CLOCK - assert timer.div == 2 + assert timer.divider == 2 timer.divider_cycles = 0 - timer.div = 0xFF + timer.divider = 0xFF timer.emulate_divider(2) assert timer.divider_cycles == constants.DIV_CLOCK - 2 - assert timer.div == 0 + assert timer.divider == 0 timer.divider_cycles = 0 - timer.div = 0 + timer.divider = 0 timer.emulate_divider(2*constants.DIV_CLOCK) assert timer.divider_cycles == constants.DIV_CLOCK - assert timer.div == 3 + assert timer.divider == 3 -def test_emulate_timer_tac_return(): +def test_emulate_timer_timer_control_return(): timer = get_timer() - timer.tac = 0 - timer.timer_cycles = -10 - timer.tima = 3 + timer.timer_control = 0 + timer.timer_cycles = -10 + timer.timer_counter = 3 timer.emulate_timer(10) - assert timer.timer_cycles == -10 - assert timer.tima == 3 + assert timer.timer_cycles == -10 + assert timer.timer_counter == 3 def test_emulate_timer_timer_cycles_return(): timer = get_timer() - timer.tac = 0x04 - timer.timer_cycles = 11 - cycles = timer.timer_cycles + timer.timer_control = 0x04 + timer.timer_cycles = 11 + cycles = timer.timer_cycles timer.emulate_timer(10) assert timer.timer_cycles == 1 -def test_emulate_timer_timer_cycles_tima(): +def test_emulate_timer_timer_cycles_timer_counter(): timer = get_timer() - timer.tac = 0x04 - timer.tima = 0 - timer.timer_cycles = 0 - timer.timer_clock = 5 - timer.emulate_timer(10) - assert timer.tima == 3 - assert timer.timer_cycles == 5 - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = 5 - timer.timer_cycles = 0 - timer.timer_clock = 5 - timer.emulate_timer(10) - assert timer.tima == 2+5 - assert timer.timer_cycles == 5 - -def test_emulate_timer_timer_cycles_tima_single_0_pass(): - timer = get_timer() - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = 0 - timer.timer_cycles = 0 - timer.timer_clock = 5 - timer.emulate_timer(10) - assert timer.tima == 2 - assert timer.timer_cycles == 5 - - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = 1 - timer.timer_cycles = 0 - timer.timer_clock = 5 - timer.emulate_timer(10) - assert timer.tima == 2+1 - assert timer.timer_cycles == 5 - - -def test_emulate_timer_timer_cycles_tima_mutli_0_pass(): - timer = get_timer() - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = 0 - timer.timer_cycles = 0 - timer.timer_clock = 1 + timer.timer_control = 0x04 + timer.timer_counter = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 3 + assert timer.timer_cycles == 5 + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 5 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2+5 + assert timer.timer_cycles == 5 + +def test_emulate_timer_timer_cycles_timer_counter_single_0_pass(): + timer = get_timer() + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2 + assert timer.timer_cycles == 5 + + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 1 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2+1 + assert timer.timer_cycles == 5 + + +def test_emulate_timer_timer_cycles_timer_counter_mutli_0_pass(): + timer = get_timer() + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 0 + timer.timer_cycles = 0 + timer.timer_clock = 1 # emulate 0xFF + 1+1 times => 2 zero passes timer.emulate_timer(0xFF+1) - assert timer.tima == 0 - assert timer.timer_cycles == 1 + assert timer.timer_counter == 0 + assert timer.timer_cycles == 1 - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = 1 - timer.timer_cycles = 0 - timer.timer_clock = 1 + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 1 + timer.timer_cycles = 0 + timer.timer_clock = 1 # emulate 0xFF + 1+1 times => 2 zero passes timer.emulate_timer(0xFF+1) - assert timer.tima == 2*1 - assert timer.timer_cycles == 1 + assert timer.timer_counter == 2*1 + assert timer.timer_cycles == 1 # emulate n zero passes for i in range(1,10): - timer.tac = 0x04 - timer.tima = 0xFF - timer.tma = i - timer.timer_cycles = 0 - timer.timer_clock = 1 + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = i + timer.timer_cycles = 0 + timer.timer_clock = 1 timer.emulate_timer((0xFF+1)*(i-1)) - assert timer.tima == i*i - assert timer.timer_cycles == 1 + assert timer.timer_counter == i*i + assert timer.timer_cycles == 1 def test_emulate_timer_interrupt(): - timer = get_timer() - ticks = 0 - timer.tac = 0x04 - timer.tima = -1 + timer = get_timer() + ticks = 0 + timer.timer_control = 0x04 + timer.timer_counter = -1 # raise an interupt as we pass 0 assert timer.interrupt.is_pending(constants.TIMER) == False - assert timer.interrupt.timer.is_pending() == False + assert timer.interrupt.timer.is_pending() == False timer.timer_cycles = -timer.timer_clock+1 timer.emulate_timer(ticks) - assert timer.timer_cycles == 1 - assert timer.tima == timer.tma + assert timer.timer_cycles == 1 + assert timer.timer_counter == timer.timer_modulo assert timer.interrupt.timer.is_pending() \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/timer.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/timer.py (original) +++ pypy/dist/pypy/lang/gameboy/timer.py Sun Jun 8 14:55:12 2008 @@ -12,6 +12,13 @@ import math +class TimerControl(object): + def __init__(self): + self.reset() + + def reset(self): + pass + class Timer(iMemory): def __init__(self, interrupt): @@ -20,16 +27,15 @@ self.reset() def reset(self): - self.div = 0 + self.divider = 0 self.divider_cycles = constants.DIV_CLOCK - self.tima = 0 - self.tma = 0 - self.tac = 0 + self.timer_counter = 0 + self.timer_modulo = 0 + self.timer_control = 0 self.timer_cycles = constants.TIMER_CLOCK[0] self.timer_clock = constants.TIMER_CLOCK[0] def write(self, address, data): - address = int(address) if address == constants.DIV: self.set_divider(data) elif address == constants.TIMA: @@ -40,7 +46,6 @@ self.set_timer_control(data) def read(self, address): - address = int(address) if address == constants.DIV: return self.get_divider() elif address == constants.TIMA: @@ -52,35 +57,39 @@ return 0xFF def get_divider(self): - return self.div + return self.divider def set_divider(self, data): """ DIV register resets on write """ - self.div = 0 + self.divider = 0 def get_timer_counter(self): - return self.tima + return self.timer_counter def set_timer_counter(self, data): - self.tima = data + self.timer_counter = data + def get_timer_modulo(self): - return self.tma + return self.timer_modulo def set_timer_modulo(self, data): - self.tma = data + self.timer_modulo = data + def get_timer_control(self): - return 0xF8 | self.tac + return 0xF8 | self.timer_control def set_timer_control(self, data): - if (self.tac & 0x03) != (data & 0x03): + if (self.timer_control & 0x03) != (data & 0x03): self.timer_clock = constants.TIMER_CLOCK[data & 0x03] self.timer_cycles = constants.TIMER_CLOCK[data & 0x03] - self.tac = data + self.timer_control = data + def get_cycles(self): - if (self.tac & 0x04) != 0 and self.timer_cycles < self.divider_cycles: + if (self.timer_control & 0x04) != 0 and \ + self.timer_cycles < self.divider_cycles: return self.timer_cycles return self.divider_cycles @@ -92,35 +101,36 @@ self.divider_cycles -= ticks if self.divider_cycles > 0: return - count = int(math.ceil(-self.divider_cycles / constants.DIV_CLOCK)+1) + count = int(math.ceil(-self.divider_cycles / + constants.DIV_CLOCK)+1) self.divider_cycles += count*constants.DIV_CLOCK - self.div = (self.div + count) % (0xFF+1); + self.divider = (self.divider + count) % (0xFF+1); def emulate_timer(self, ticks): - if (self.tac & 0x04) == 0: + if (self.timer_control & 0x04) == 0: return self.timer_cycles -= ticks while self.timer_cycles <= 0: - self.tima = (self.tima + 1) & 0xFF + self.timer_counter = (self.timer_counter + 1) & 0xFF self.timer_cycles += self.timer_clock - if self.tima == 0x00: - self.tima = self.tma + if self.timer_counter == 0x00: + self.timer_counter = self.timer_modulo self.interrupt.raise_interrupt(constants.TIMER) #def emulate_timer(self, ticks): - # if (self.tac & 0x04) == 0: + # if (self.timer_control & 0x04) == 0: # return # self.timer_cycles -= ticks # if self.timer_cycles > 0: return # count = int(math.ceil(-self.timer_cycles / self.timer_clock)) + 1 # self.timer_cycles += self.timer_clock*count # # check for zero pass - # if (self.tima + count) > 0xFF: + # if (self.timer_counter + count) > 0xFF: # self.interrupt.raise_interrupt(constants.TIMER) - # zero_passes = math.ceil(self.tima / count) - # self.tima = (self.tma + count - zero_passes ) % (0xFF +1) + # zero_passes = math.ceil(self.timer_counter / count) + # self.timer_counter = (self.timer_modulo + count - zero_passes ) % (0xFF +1) # else: - # self.tima = (self.tima + count) % (0xFF +1) + # self.timer_counter = (self.timer_counter + count) % (0xFF +1) # CLOCK DRIVER ----------------------------------------------------------------- class Clock(object): From arigo at codespeak.net Sun Jun 8 15:39:35 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 8 Jun 2008 15:39:35 +0200 (CEST) Subject: [pypy-svn] r55665 - pypy/dist/pypy/doc Message-ID: <20080608133935.E1928168503@codespeak.net> Author: arigo Date: Sun Jun 8 15:39:33 2008 New Revision: 55665 Modified: pypy/dist/pypy/doc/faq.txt Log: Mention that this is what LLVM would like to find someone to do. Modified: pypy/dist/pypy/doc/faq.txt ============================================================================== --- pypy/dist/pypy/doc/faq.txt (original) +++ pypy/dist/pypy/doc/faq.txt Sun Jun 8 15:39:33 2008 @@ -223,7 +223,12 @@ up where. In this way, you could compile the program into two copies of itself: a "fast" version and a "slow" version. The former would contain many guards that allow it to fall back to the latter if needed. That -would be a wholly different project than PyPy, though. +would be a wholly different project than PyPy, though. (As far as we +understand it, this is the approach that the LLVM__ group would like to +see LLVM used for, so if you feel like working very hard and attempting +something like this, check with them.) + +.. __: http://llvm.org/ What PyPy contains is, on the one hand, an non-soft static type inferencer for RPython, which is a sublanguage that we defined just so From antocuni at codespeak.net Sun Jun 8 15:52:37 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 15:52:37 +0200 (CEST) Subject: [pypy-svn] r55666 - pypy/branch/eval-loop-experiments Message-ID: <20080608135237.0EA7F168503@codespeak.net> Author: antocuni Date: Sun Jun 8 15:52:36 2008 New Revision: 55666 Added: pypy/branch/eval-loop-experiments/ - copied from r55665, pypy/dist/pypy/ Log: a branch to experiment with various hacks to speed up the main interpreter loop From antocuni at codespeak.net Sun Jun 8 15:56:36 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 15:56:36 +0200 (CEST) Subject: [pypy-svn] r55667 - in pypy/branch/eval-loop-experiments: config interpreter interpreter/test Message-ID: <20080608135636.19A3216806E@codespeak.net> Author: antocuni Date: Sun Jun 8 15:56:34 2008 New Revision: 55667 Modified: pypy/branch/eval-loop-experiments/config/pypyoption.py pypy/branch/eval-loop-experiments/interpreter/pycode.py pypy/branch/eval-loop-experiments/interpreter/pyopcode.py pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py Log: experimental option that precomputes opcode args and pack the bytecode to contains only opcodes, not opargs; the intent is to make the interpreter loop a bit smaller. The benchmarks are a bit controversial, it's not clear if you win or loose. Modified: pypy/branch/eval-loop-experiments/config/pypyoption.py ============================================================================== --- pypy/branch/eval-loop-experiments/config/pypyoption.py (original) +++ pypy/branch/eval-loop-experiments/config/pypyoption.py Sun Jun 8 15:56:34 2008 @@ -138,7 +138,11 @@ BoolOption("usepycfiles", "Write and read pyc files when importing", default=True), - + + BoolOption("usecodeargs", "store opcodes and opargs in separate lists", + default=False, + requires=[("objspace.usepycfiles", False)]), + BoolOption("honor__builtins__", "Honor the __builtins__ key of a module dictionary", default=False), Modified: pypy/branch/eval-loop-experiments/interpreter/pycode.py ============================================================================== --- pypy/branch/eval-loop-experiments/interpreter/pycode.py (original) +++ pypy/branch/eval-loop-experiments/interpreter/pycode.py Sun Jun 8 15:56:34 2008 @@ -11,6 +11,7 @@ from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.rlib.rarithmetic import intmask +from pypy.tool import stdlib_opcode # helper @@ -65,7 +66,7 @@ self.co_nlocals = nlocals self.co_stacksize = stacksize self.co_flags = flags - self.co_code = code + self.precompute_code(code) self.co_consts_w = consts self.co_names_w = [space.new_interned_str(aname) for aname in names] self.co_varnames = varnames @@ -114,7 +115,53 @@ def signature(self): return self._signature - + + def precompute_code(self, code): + from pypy.interpreter.pyopcode import decode_opcode + if not self.space.config.objspace.usecodeargs: + self.co_code = code + self.co_codeargs = None + return + + next_instr = 0 + codeargs = [] + codelist = [] + orig2new = {} # index in code --> index in codelist + new2orig = {} # index in codelist --> index in code + while next_instr < len(code): + opcode = ord(code[next_instr]) + orig2new[next_instr] = len(codelist) + new2orig[len(codelist)] = next_instr + next_instr += 1 + next_instr, opcode, oparg = decode_opcode(code, next_instr, opcode) + codelist.append(chr(opcode)) + codeargs.append(oparg) + + # sanity check + assert len(codelist) == len(codeargs) + for i, j in orig2new.iteritems(): + assert code[i] == codelist[j] + + # recompute target addresses + i = 0 + while i= HAVE_ARGUMENT: + lo = ord(co_code[next_instr]) + hi = ord(co_code[next_instr+1]) + next_instr += 2 + oparg = (hi << 8) | lo + hint(opcode, concrete=True) + hint(oparg, concrete=True) + else: + oparg = 0 + + while opcode == opcodedesc.EXTENDED_ARG.index: + opcode = ord(co_code[next_instr]) + if opcode < HAVE_ARGUMENT: + raise BytecodeCorruption + lo = ord(co_code[next_instr+1]) + hi = ord(co_code[next_instr+2]) + next_instr += 3 + oparg = (oparg << 16) | (hi << 8) | lo + hint(opcode, concrete=True) + hint(oparg, concrete=True) + + return next_instr, opcode, oparg +decode_opcode._always_inline_ = True + class __extend__(pyframe.PyFrame): """A PyFrame that knows about interpretation of standard Python opcodes @@ -73,20 +98,21 @@ next_instr = r_uint(next_instr) co_code = pycode.co_code + co_codeargs = pycode.co_codeargs try: while True: - next_instr = self.handle_bytecode(co_code, next_instr, ec) + next_instr = self.handle_bytecode(co_code, co_codeargs, next_instr, ec) rstack.resume_point("dispatch", self, co_code, ec, returns=next_instr) except ExitFrame: return self.popvalue() - def handle_bytecode(self, co_code, next_instr, ec): + def handle_bytecode(self, co_code, co_codeargs, next_instr, ec): from pypy.rlib import rstack # for resume points try: - next_instr = self.dispatch_bytecode(co_code, next_instr, ec) + next_instr = self.dispatch_bytecode(co_code, co_codeargs, next_instr, ec) rstack.resume_point("handle_bytecode", self, co_code, ec, returns=next_instr) except OperationError, operr: @@ -144,38 +170,25 @@ next_instr = block.handle(self, unroller) return next_instr - def dispatch_bytecode(self, co_code, next_instr, ec): + def dispatch_bytecode(self, co_code, co_codeargs, next_instr, ec): space = self.space while True: + self.last_instr = intmask(next_instr) if not we_are_jitted(): ec.bytecode_trace(self) next_instr = r_uint(self.last_instr) opcode = ord(co_code[next_instr]) - next_instr += 1 + if space.config.objspace.logbytecodes: space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1 - if opcode >= HAVE_ARGUMENT: - lo = ord(co_code[next_instr]) - hi = ord(co_code[next_instr+1]) - next_instr += 2 - oparg = (hi << 8) | lo + if space.config.objspace.usecodeargs: + oparg = co_codeargs[next_instr] + next_instr += 1 else: - oparg = 0 - hint(opcode, concrete=True) - hint(oparg, concrete=True) - - while opcode == opcodedesc.EXTENDED_ARG.index: - opcode = ord(co_code[next_instr]) - if opcode < HAVE_ARGUMENT: - raise BytecodeCorruption - lo = ord(co_code[next_instr+1]) - hi = ord(co_code[next_instr+2]) - next_instr += 3 - oparg = (oparg << 16) | (hi << 8) | lo - hint(opcode, concrete=True) - hint(oparg, concrete=True) + next_instr += 1 + next_instr, opcode, oparg = decode_opcode(co_code, next_instr, opcode) if opcode == opcodedesc.RETURN_VALUE.index: w_returnvalue = self.popvalue() Modified: pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py ============================================================================== --- pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py (original) +++ pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py Sun Jun 8 15:56:34 2008 @@ -43,6 +43,16 @@ ec = self.space.getexecutioncontext() ec.compiler = self.saved_compiler + def test_jump(self): + code =''' + def f(s): + if len(s) == 0: + return 42 + return 24 + ''' + assert self.codetest(code, 'f', ['']) == 42 + assert self.codetest(code, 'f', ['x']) == 24 + def test_exception_trivial(self): x = self.codetest('''\ def f(): From antocuni at codespeak.net Sun Jun 8 16:03:39 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 16:03:39 +0200 (CEST) Subject: [pypy-svn] r55668 - pypy/branch/eval-loop-experiments Message-ID: <20080608140339.10C2A1684E5@codespeak.net> Author: antocuni Date: Sun Jun 8 16:03:38 2008 New Revision: 55668 Removed: pypy/branch/eval-loop-experiments/ Log: remove this branch, as I branched at the wrong level From antocuni at codespeak.net Sun Jun 8 16:06:23 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 16:06:23 +0200 (CEST) Subject: [pypy-svn] r55669 - pypy/branch/eval-loop-experiments Message-ID: <20080608140623.5C20C1684E5@codespeak.net> Author: antocuni Date: Sun Jun 8 16:06:23 2008 New Revision: 55669 Added: pypy/branch/eval-loop-experiments/ - copied from r55668, pypy/dist/ Log: recreate the branch, hopefully at the right level now :-) From antocuni at codespeak.net Sun Jun 8 16:07:56 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 16:07:56 +0200 (CEST) Subject: [pypy-svn] r55670 - in pypy/branch/eval-loop-experiments/pypy: config interpreter interpreter/test Message-ID: <20080608140756.B42851684E5@codespeak.net> Author: antocuni Date: Sun Jun 8 16:07:56 2008 New Revision: 55670 Modified: pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py pypy/branch/eval-loop-experiments/pypy/interpreter/test/test_interpreter.py Log: experimental option that precomputes opcode args and pack the bytecode to contains only opcodes, not opargs; the intent is to make the interpreter loop a bit smaller. The benchmarks are a bit controversial, it's not clear if you win or loose. Modified: pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py (original) +++ pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py Sun Jun 8 16:07:56 2008 @@ -138,7 +138,11 @@ BoolOption("usepycfiles", "Write and read pyc files when importing", default=True), - + + BoolOption("usecodeargs", "store opcodes and opargs in separate lists", + default=False, + requires=[("objspace.usepycfiles", False)]), + BoolOption("honor__builtins__", "Honor the __builtins__ key of a module dictionary", default=False), Modified: pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py (original) +++ pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py Sun Jun 8 16:07:56 2008 @@ -11,6 +11,7 @@ from pypy.interpreter.gateway import NoneNotWrapped from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.rlib.rarithmetic import intmask +from pypy.tool import stdlib_opcode # helper @@ -65,7 +66,7 @@ self.co_nlocals = nlocals self.co_stacksize = stacksize self.co_flags = flags - self.co_code = code + self.precompute_code(code) self.co_consts_w = consts self.co_names_w = [space.new_interned_str(aname) for aname in names] self.co_varnames = varnames @@ -114,7 +115,53 @@ def signature(self): return self._signature - + + def precompute_code(self, code): + from pypy.interpreter.pyopcode import decode_opcode + if not self.space.config.objspace.usecodeargs: + self.co_code = code + self.co_codeargs = None + return + + next_instr = 0 + codeargs = [] + codelist = [] + orig2new = {} # index in code --> index in codelist + new2orig = {} # index in codelist --> index in code + while next_instr < len(code): + opcode = ord(code[next_instr]) + orig2new[next_instr] = len(codelist) + new2orig[len(codelist)] = next_instr + next_instr += 1 + next_instr, opcode, oparg = decode_opcode(code, next_instr, opcode) + codelist.append(chr(opcode)) + codeargs.append(oparg) + + # sanity check + assert len(codelist) == len(codeargs) + for i, j in orig2new.iteritems(): + assert code[i] == codelist[j] + + # recompute target addresses + i = 0 + while i= HAVE_ARGUMENT: + lo = ord(co_code[next_instr]) + hi = ord(co_code[next_instr+1]) + next_instr += 2 + oparg = (hi << 8) | lo + hint(opcode, concrete=True) + hint(oparg, concrete=True) + else: + oparg = 0 + + while opcode == opcodedesc.EXTENDED_ARG.index: + opcode = ord(co_code[next_instr]) + if opcode < HAVE_ARGUMENT: + raise BytecodeCorruption + lo = ord(co_code[next_instr+1]) + hi = ord(co_code[next_instr+2]) + next_instr += 3 + oparg = (oparg << 16) | (hi << 8) | lo + hint(opcode, concrete=True) + hint(oparg, concrete=True) + + return next_instr, opcode, oparg +decode_opcode._always_inline_ = True + class __extend__(pyframe.PyFrame): """A PyFrame that knows about interpretation of standard Python opcodes @@ -73,20 +98,23 @@ next_instr = r_uint(next_instr) co_code = pycode.co_code + co_codeargs = pycode.co_codeargs + + self.name = pycode.co_name try: while True: - next_instr = self.handle_bytecode(co_code, next_instr, ec) + next_instr = self.handle_bytecode(co_code, co_codeargs, next_instr, ec) rstack.resume_point("dispatch", self, co_code, ec, returns=next_instr) except ExitFrame: return self.popvalue() - def handle_bytecode(self, co_code, next_instr, ec): + def handle_bytecode(self, co_code, co_codeargs, next_instr, ec): from pypy.rlib import rstack # for resume points try: - next_instr = self.dispatch_bytecode(co_code, next_instr, ec) + next_instr = self.dispatch_bytecode(co_code, co_codeargs, next_instr, ec) rstack.resume_point("handle_bytecode", self, co_code, ec, returns=next_instr) except OperationError, operr: @@ -144,38 +172,25 @@ next_instr = block.handle(self, unroller) return next_instr - def dispatch_bytecode(self, co_code, next_instr, ec): + def dispatch_bytecode(self, co_code, co_codeargs, next_instr, ec): space = self.space while True: + self.last_instr = intmask(next_instr) if not we_are_jitted(): ec.bytecode_trace(self) next_instr = r_uint(self.last_instr) opcode = ord(co_code[next_instr]) - next_instr += 1 + if space.config.objspace.logbytecodes: space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1 - if opcode >= HAVE_ARGUMENT: - lo = ord(co_code[next_instr]) - hi = ord(co_code[next_instr+1]) - next_instr += 2 - oparg = (hi << 8) | lo + if space.config.objspace.usecodeargs: + oparg = co_codeargs[next_instr] + next_instr += 1 else: - oparg = 0 - hint(opcode, concrete=True) - hint(oparg, concrete=True) - - while opcode == opcodedesc.EXTENDED_ARG.index: - opcode = ord(co_code[next_instr]) - if opcode < HAVE_ARGUMENT: - raise BytecodeCorruption - lo = ord(co_code[next_instr+1]) - hi = ord(co_code[next_instr+2]) - next_instr += 3 - oparg = (oparg << 16) | (hi << 8) | lo - hint(opcode, concrete=True) - hint(oparg, concrete=True) + next_instr += 1 + next_instr, opcode, oparg = decode_opcode(co_code, next_instr, opcode) if opcode == opcodedesc.RETURN_VALUE.index: w_returnvalue = self.popvalue() Modified: pypy/branch/eval-loop-experiments/pypy/interpreter/test/test_interpreter.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/interpreter/test/test_interpreter.py (original) +++ pypy/branch/eval-loop-experiments/pypy/interpreter/test/test_interpreter.py Sun Jun 8 16:07:56 2008 @@ -43,6 +43,16 @@ ec = self.space.getexecutioncontext() ec.compiler = self.saved_compiler + def test_jump(self): + code =''' + def f(s): + if len(s) == 0: + return 42 + return 24 + ''' + assert self.codetest(code, 'f', ['']) == 42 + assert self.codetest(code, 'f', ['x']) == 24 + def test_exception_trivial(self): x = self.codetest('''\ def f(): From arigo at codespeak.net Sun Jun 8 16:09:22 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 8 Jun 2008 16:09:22 +0200 (CEST) Subject: [pypy-svn] r55671 - pypy/dist/pypy/doc Message-ID: <20080608140922.74AC31684E5@codespeak.net> Author: arigo Date: Sun Jun 8 16:09:22 2008 New Revision: 55671 Modified: pypy/dist/pypy/doc/index.txt Log: Very partial update of the status. Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Sun Jun 8 16:09:22 2008 @@ -75,7 +75,7 @@ =================================== PyPy can be used to run Python programs on Linux, OS/X, -Windows, on top of .NET, and (recently) on top of Java. +Windows, on top of .NET, and on top of Java. It is recommended to try out the current Subversion HEAD, which contains `major improvements`__ since the last release. @@ -83,10 +83,8 @@ PyPy is mainly developed on Linux and Mac OS X. Windows is supported, but platform-specific bugs tend to take longer before we notice and fix -them. About 64-bit machines: although support is mostly present, we -decided to stop tracking and fixing the remaining issues for a while, as -an attempt to keep some focus. So PyPy requires a 32-bit machine or OS -for now. +them. Linux 64-bit machines are supported (though it may also take some +time before we notice and fix bugs). PyPy's own tests, daily updated, `on Linux`_, `on Windows`_ and `on built pypy-c`_. From cami at codespeak.net Sun Jun 8 20:26:30 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sun, 8 Jun 2008 20:26:30 +0200 (CEST) Subject: [pypy-svn] r55673 - pypy/dist/pypy/lang/gameboy Message-ID: <20080608182630.D439F1684E4@codespeak.net> Author: cami Date: Sun Jun 8 20:26:27 2008 New Revision: 55673 Modified: pypy/dist/pypy/lang/gameboy/gameboy.py Log: added cpu interrupt call when write to interrupt or video Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Sun Jun 8 20:26:27 2008 @@ -24,12 +24,12 @@ self.create_gamboy_elements() def create_drivers(self): - self.clock = Clock() self.joypad_driver = JoypadDriver() self.video_driver = VideoDriver() self.sound_driver = SoundDriver() def create_gamboy_elements(self): + self.clock = Clock() self.ram = RAM() self.cartridge_manager = CartridgeManager(self.clock) self.interrupt = Interrupt() @@ -128,6 +128,8 @@ return raise Exception("invalid read address given") receiver.write(address, data) + if address == constants.STAT or address == 0xFFFF: + self.cpu.handle_interrupts() def read(self, address): receiver = self.get_receiver(address) @@ -156,7 +158,7 @@ elif 0xFE00 <= address <= 0xFEFF: self.print_receiver_msg(address, "video") return self.video - elif 0xFF00 <= address <= 0xFF00: + elif address == 0xFF00: self.print_receiver_msg(address, "joypad") return self.joypad elif 0xFF01 <= address <= 0xFF02: @@ -165,7 +167,7 @@ elif 0xFF04 <= address <= 0xFF07: self.print_receiver_msg(address, "timer") return self.timer - elif 0xFF0F <= address <= 0xFF0F: + elif address == 0xFF0F: self.print_receiver_msg(address, "interrupt") return self.interrupt elif 0xFF10 <= address <= 0xFF3F: @@ -177,7 +179,7 @@ elif 0xFF80 <= address <= 0xFFFE: self.print_receiver_msg(address, "ram") return self.ram - elif 0xFFFF <= address <= 0xFFFF: + elif address == 0xFFFF: self.print_receiver_msg(address, "interrupt") return self.interrupt From cami at codespeak.net Sun Jun 8 20:27:09 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sun, 8 Jun 2008 20:27:09 +0200 (CEST) Subject: [pypy-svn] r55674 - pypy/dist/pypy/lang/gameboy Message-ID: <20080608182709.61B01168455@codespeak.net> Author: cami Date: Sun Jun 8 20:27:09 2008 New Revision: 55674 Modified: pypy/dist/pypy/lang/gameboy/gameboy.py Log: cahnged call: handle_interrupts to handle_pending_interrupts Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Sun Jun 8 20:27:09 2008 @@ -129,7 +129,7 @@ raise Exception("invalid read address given") receiver.write(address, data) if address == constants.STAT or address == 0xFFFF: - self.cpu.handle_interrupts() + self.cpu.handle_pending_interrupts() def read(self, address): receiver = self.get_receiver(address) From cami at codespeak.net Sun Jun 8 21:30:55 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Sun, 8 Jun 2008 21:30:55 +0200 (CEST) Subject: [pypy-svn] r55675 - pypy/dist/pypy/lang/gameboy Message-ID: <20080608193055.2B1751684D6@codespeak.net> Author: cami Date: Sun Jun 8 21:30:54 2008 New Revision: 55675 Modified: pypy/dist/pypy/lang/gameboy/constants.py pypy/dist/pypy/lang/gameboy/gameboy.py pypy/dist/pypy/lang/gameboy/video.py Log: small refactorings in video. introduced interupt helper methods Modified: pypy/dist/pypy/lang/gameboy/constants.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/constants.py (original) +++ pypy/dist/pypy/lang/gameboy/constants.py Sun Jun 8 21:30:54 2008 @@ -9,11 +9,11 @@ GAMEBOY_SCREEN_WIDTH = 160 GAMEBOY_SCREEN_HEIGHT = 144 + #___________________________________________________________________________ # CATRIGE TYPES # ___________________________________________________________________________ - TYPE_ROM_ONLY = 0x00 TYPE_MBC1 = 0x01 @@ -81,7 +81,7 @@ # ___________________________________________________________________________ -#INTERRUP FLAGS +#INTERRUPT FLAGS # ___________________________________________________________________________ # Interrupt Registers Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Sun Jun 8 21:30:54 2008 @@ -196,11 +196,9 @@ self.video.write(0x8012 + (index << 3), pattern0) self.video.write(0x8014 + (index << 3), pattern1) self.video.write(0x8016 + (index << 3), pattern1) - for index in range(0, 8): self.video.write(0x8190 + (index << 1), \ constants.REGISTERED_BITMAP[index]) - for tile in range(0, 12): self.video.write(0x9904 + tile, tile + 1) self.video.write(0x9924 + tile, tile + 13) Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Sun Jun 8 21:30:54 2008 @@ -158,10 +158,10 @@ def write_oam(self, address, data): if address >= constants.OAM_ADDR and \ - address < constants.OAM_ADDR + constants.OAM_SIZE: - self.oam[address - constants.OAM_ADDR] = data & 0xFF + address < (constants.OAM_ADDR + constants.OAM_SIZE): + self.oam[address - constants.OAM_ADDR] = data & 0xFF elif address >= constants.VRAM_ADDR and \ - address < constants.VRAM_ADDR + constants.VRAM_SIZE: + address < (constants.VRAM_ADDR + constants.VRAM_SIZE): self.vram[address - constants.VRAM_ADDR] = data & 0xFF def read(self, address): @@ -195,10 +195,10 @@ def read_oam(self, address): if (address >= constants.OAM_ADDR and - address < constants.OAM_ADDR + constants.OAM_SIZE): + address < (constants.OAM_ADDR + constants.OAM_SIZE)): return self.oam[address - constants.OAM_ADDR] elif (address >= constants.VRAM_ADDR and - address < constants.VRAM_ADDR + constants.VRAM_SIZE): + address < (constants.VRAM_ADDR + constants.VRAM_SIZE)): return self.vram[address - constants.VRAM_ADDR] return 0xFF @@ -252,9 +252,13 @@ def set_status(self, data): self.stat = (self.stat & 0x87) | (data & 0x78) + self.set_status_bug() + + def set_status_bug(self) : # Gameboy Bug - if (self.control & 0x80) != 0 and (self.stat & 0x03) == 0x01 and \ - (self.stat & 0x44) != 0x44: + if (self.control & 0x80) != 0x00 and \ + (self.stat & 0x03) == 0x01 and \ + (self.stat & 0x44) != 0x44: self.interrupt.raise_interrupt(constants.LCD) def get_scroll_y(self): @@ -294,32 +298,32 @@ def set_dma(self, data): self.dma = data - for index in range(0, constants.OAM_SIZE): + for index in range(constants.OAM_SIZE): self.oam[index] = self.memory.read((self.dma << 8) + index) def get_background_palette(self): return self.background_palette def set_background_palette(self, data): - if self.background_palette != data: - self.background_palette = data - self.dirty = True + if self.background_palette == data: return + self.background_palette = data + self.dirty = True def get_object_palette_0(self): return self.object_palette_0 def set_object_palette_0(self, data): - if self.object_palette_0 != data: - self.object_palette_0 = data - self.dirty = True + if self.object_palette_0 == data: return + self.object_palette_0 = data + self.dirty = True def get_object_palette_1(self): return self.object_palette_1 def set_object_palette_1(self, data): - if self.object_palette_1 != data: - self.object_palette_1 = data - self.dirty = True + if self.object_palette_1 == data: return + self.object_palette_1 = data + self.dirty = True def get_window_y(self): return self.window_y @@ -348,10 +352,26 @@ else: self.stat = (self.stat & 0xFC) self.cycles += constants.MODE_0_TICKS - # H-Blank interrupt - if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) - + self.h_blank_interrupt_check() + + + def h_blank_interrupt_check(self): + if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44: + self.interrupt.raise_interrupt(constants.LCD) + + def oam_interrupt_check(self): + if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: + self.interrupt.raise_interrupt(constants.LCD) + + def v_blank_interrupt_check(self): + if (self.stat & 0x10) != 0: + self.interrupt.raise_interrupt(constants.LCD) + + def line_y_line_y_compare_interrupt_check(self): + if (self.stat & 0x40) != 0: + self.interrupt.raise_interrupt(constants.LCD) + + def emulate_hblank(self): self.line_y+=1 self.emulate_hblank_line_y_compare() @@ -362,20 +382,16 @@ def emulate_hblank_line_y_compare(self): if self.line_y == self.line_y_compare: - # LYC=LY interrupt self.stat |= 0x04 - if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) + self.line_y_line_y_compare_interrupt_check() else: self.stat &= 0xFB def emulate_hblank_part_1(self): - self.stat = (self.stat & 0xFC) | 0x02 + self.stat = (self.stat & 0xFC) | 0x02 self.cycles += constants.MODE_2_TICKS - # OAM interrupt - if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) - + self.oam_interrupt_check() + def emulate_hblank_part_2(self): if self.display: self.draw_frame() @@ -401,18 +417,14 @@ self.vblank = False self.stat = (self.stat & 0xFC) | 0x01 self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS - # V-Blank interrupt - if (self.stat & 0x10) != 0: - self.interrupt.raise_interrupt(constants.LCD) - # V-Blank interrupt + self.v_blank_interrupt_check() self.interrupt.raise_interrupt(constants.VBLANK) + def emulate_vblank_first_y_line(self): self.stat = (self.stat & 0xFC) | 0x02 self.cycles += constants.MODE_2_TICKS - #OAM interrupt - if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) + self.oam_interrupt_check(); def emulate_vblank_other(self): if self.line_y < 153: @@ -427,10 +439,8 @@ self.stat = (self.stat & 0xFC) | 0x01 self.cycles += constants.MODE_1_TICKS - constants.MODE_1_END_TICKS if self.line_y == self.line_y_compare: - #LYC=LY interrupt self.stat |= 0x04 - if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) + self.line_y_line_y_compare_interrupt_check(); else: self.stat &= 0xFB @@ -458,39 +468,44 @@ def draw_background(self): y = (self.scroll_y + self.line_y) & 0xFF - x = self.scroll_x & 0xFF - tileMap = constants.VRAM_MAP_A + x = self.scroll_x & 0xFF + tile_map = constants.VRAM_MAP_A if (self.control & 0x08) != 0: - tileMap = constants.VRAM_MAP_B - tileData = constants.VRAM_DATA_B + tile_map = constants.VRAM_MAP_B + + tile_data = constants.VRAM_DATA_B if (self.control & 0x10) != 0: - tileData = constants.VRAM_DATA_A - tileMap += ((y >> 3) << 5) + (x >> 3) - tileData += (y & 7) << 1 - self.draw_tiles(8 - (x & 7), tileMap, tileData) + tile_data = constants.VRAM_DATA_A + + tile_map += ((y >> 3) << 5) + (x >> 3) + tile_data += (y & 7) << 1 + self.draw_tiles(8 - (x & 7), tile_map, tile_data) def draw_window(self): - if self.line_y < self.window_y or self.window_x >= 167 or \ + if self.line_y < self.window_y or \ + self.window_x >= 167 or \ self.window_line_y >= 144: return - tileMap = constants.VRAM_MAP_A + tile_map = constants.VRAM_MAP_A if (self.control & 0x40) != 0: - tileMap = constants.VRAM_MAP_B - tileData = constants.VRAM_DATA_B + tile_map = constants.VRAM_MAP_B + + tile_data = constants.VRAM_DATA_B if (self.control & 0x10) != 0: - tileData = constants.VRAM_DATA_A - tileMap += (self.window_line_y >> 3) << 5 - tileData += (self.window_line_y & 7) << 1 - self.draw_tiles(self.window_x + 1, tileMap, tileData) + tile_data = constants.VRAM_DATA_A + + tile_map += (self.window_line_y >> 3) << 5 + tile_data += (self.window_line_y & 7) << 1 + self.draw_tiles(self.window_x + 1, tile_map, tile_data) self.window_line_y += 1 def draw_objects(self): count = self.scan_objects() lastx = 176 for index in range(176, count): - data = self.objects[index] - x = (data >> 24) & 0xFF - flags = (data >> 12) & 0xFF + data = self.objects[index] + x = (data >> 24) & 0xFF + flags = (data >> 12) & 0xFF address = data & 0xFFF if (x + 8 <= lastx): self.draw_object_tile(x, address, flags) @@ -506,9 +521,9 @@ x = self.oam[offset + 1] & 0xFF if (y <= 0 or y >= 144 + 16 or x <= 0 or x >= 168): continue - tile = self.oam[offset + 2] & 0xFF + tile = self.oam[offset + 2] & 0xFF flags = self.oam[offset + 3] & 0xFF - y = self.line_y - y + 16 + y = self.line_y - y + 16 if ((self.control & 0x04) != 0): # 8x16 tile size if (y < 0 or y > 15): @@ -534,25 +549,25 @@ def sort_scan_object(self, count): # sort objects from lower to higher priority - for index in range(0, count): + for index in range(count): rightmost = index for number in range(index+1, count): if (self.objects[number] >> 20) > \ (self.objects[rightmost] >> 20): rightmost = number if rightmost != index: - data = self.objects[index] - self.objects[index] = self.objects[rightmost] + data = self.objects[index] + self.objects[index] = self.objects[rightmost] self.objects[rightmost] = data - def draw_tiles(self, x, tileMap, tileData): + def draw_tiles(self, x, tile_map, tile_data): while x < 168: if (self.control & 0x10) != 0: - tile = self.vram[tileMap] + tile = self.vram[tile_map] else: - tile = (process_2_complement(self.vram[tileMap]) ^ 0x80) & 0xFF - self.draw_tile(x, tileData + (tile << 4)) - tileMap = (tileMap & 0x1FE0) + ((tileMap + 1) & 0x001F) + tile = (process_2_complement(self.vram[tile_map]) ^ 0x80) & 0xFF + self.draw_tile(x, tile_data + (tile << 4)) + tile_map = (tile_map & 0x1FE0) + ((tile_map + 1) & 0x001F) x += 8 def draw_tile(self, x, address): @@ -563,9 +578,23 @@ def get_pattern(self, address): return self.vram[address] +(self.vram[address + 1]) << 8 + + def draw_object_tile(self, x, address, flags): + self.draw_object(set_tile_line_call_wrapper(self), x, address, flags) + + def set_tile_line(self, pos, color, mask): + self.line[pos] |= color | mask + + def draw_overlapped_object_tile(self, x, address, flags): + self.draw_object(set_overlapped_object_line_call_wrapper(self), + x, address, flags) + + def set_overlapped_object_line(self, pos, color, mask): + self.line[pos] = (self.line[pos] & 0x0101) | color | mask + def draw_object(self, caller, x, address, flags): pattern = self.get_pattern(address) - mask = 0 + mask = 0 # priority if (flags & 0x80) != 0: mask |= 0x0008 @@ -573,19 +602,10 @@ if (flags & 0x10) != 0: mask |= 0x0004 if (flags & 0x20) != 0: - self.draw_object_normal(x, pattern, mask, caller) - else: self.draw_object_flipped(x, pattern, mask, caller) + else: + self.draw_object_normal(x, pattern, mask, caller) - def draw_object_normal(self, x, pattern, mask, caller): - for i in range(0, 7): - color = pattern >> (6-i) - if (color & 0x0202) != 0: - caller.call(x+1, color, mask) - color = pattern << 1 - if (color & 0x0202) != 0: - caller.call(x+7, color, mask) - def draw_object_flipped(self, x, pattern, mask, caller): color = pattern << 1 if (color & 0x0202) != 0: @@ -594,19 +614,15 @@ color = pattern >> i if (color & 0x0202) != 0: caller.call(x + i + 1, color, mask) - - def draw_object_tile(self, x, address, flags): - self.draw_object(set_tile_line_call_wrapper(self), x, address, flags) - - def set_tile_line(self, pos, color, mask): - self.line[pos] |= color | mask - - def draw_overlapped_object_tile(self, x, address, flags): - self.draw_object(set_overlapped_object_line_call_wrapper(self), - x, address, flags) - - def set_overlapped_object_line(self, pos, color, mask): - self.line[pos] = (self.line[pos] & 0x0101) | color | mask + + def draw_object_normal(self, x, pattern, mask, caller): + for i in range(0, 7): + color = pattern >> (6-i) + if (color & 0x0202) != 0: + caller.call(x+1, color, mask) + color = pattern << 1 + if (color & 0x0202) != 0: + caller.call(x+7, color, mask) def draw_pixels(self): self.update_palette() @@ -630,8 +646,8 @@ # bit 3 = OBJ priority for pattern in range(0, 64): #color - if (pattern & 0x22) == 0 or ((pattern & 0x08) != 0 and \ - (pattern & 0x11) != 0): + if (pattern & 0x22) == 0 or \ + ((pattern & 0x08) != 0 and (pattern & 0x11) != 0): # OBJ behind BG color 1-3 color = (self.background_palette >> ((((pattern >> 3) & 0x02) +\ (pattern & 0x01)) << 1)) & 0x03 From antocuni at codespeak.net Sun Jun 8 23:15:46 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 23:15:46 +0200 (CEST) Subject: [pypy-svn] r55676 - pypy/extradoc/sprintinfo/post-ep2008 Message-ID: <20080608211546.C43BC168453@codespeak.net> Author: antocuni Date: Sun Jun 8 23:15:44 2008 New Revision: 55676 Added: pypy/extradoc/sprintinfo/post-ep2008/ pypy/extradoc/sprintinfo/post-ep2008/announcement.txt (contents, props changed) Log: draft for the announcement of the post-europython sprint, mostly copied from the previous year's one Added: pypy/extradoc/sprintinfo/post-ep2008/announcement.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/post-ep2008/announcement.txt Sun Jun 8 23:15:44 2008 @@ -0,0 +1,74 @@ +======================================================== +Vilnius/Post EuroPython PyPy Sprint 10-12th of July +======================================================== + +The PyPy team is sprinting at EuroPython again and we invite +you to participate in our 3 day long sprint at the conference hotel +- Reval Hotel Lietuva. + +If you plan to attend the sprint we recommend you to listen to the PyPy +technical talks (`EuroPython schedule`_) during the +conference since it will give you a good overview of the status of development. + +On the morning of the first sprint day (10th) we will also have a +tutorial session for those new to PyPy development. As 3 days is relatively +short for a PyPy sprint we suggest to travel back home on the 13th if +possible (but it is ok to attend less than 3 days too). + +------------------------------ +Goals and topics of the sprint +------------------------------ + +There are many possible and interesting sprint topics to work on - here +we list some possible task areas: + +* XXX fill me +* some JIT improvement work +* port the stackless transform to ootypesystem +* other interesting stuff that you would like to work on ...;-) + +------------ +Registration +------------ + +If you'd like to come, please subscribe to the `pypy-sprint mailing list`_ +and drop a note about your interests and post any questions. More +organisational information will be sent to that list. + +Please register by adding yourself on the following list (via svn): + + http://codespeak.net/svn/pypy/extradoc/sprintinfo/post-ep2008/people.txt + +or on the pypy-sprint mailing list if you do not yet have check-in rights: + + http://codespeak.net/mailman/listinfo/pypy-sprint + +--------------------------------------- +Preparation (if you feel it is needed): +--------------------------------------- + +* read the `getting-started`_ pages on http://codespeak.net/pypy + +* for inspiration, overview and technical status you are welcome to + read `the technical reports available and other relevant documentation`_ + +* please direct any technical and/or development oriented questions to + pypy-dev at codespeak.net and any sprint organizing/logistical + questions to pypy-sprint at codespeak.net + +* if you need information about the conference, potential hotels, + directions etc we recommend to look at http://www.europython.org. + + +We are looking forward to meet you at the Vilnius Post EuroPython +PyPy sprint! + +The PyPy team + + +.. See also .. + +.. _getting-started: http://codespeak.net/pypy/dist/pypy/doc/getting-started.html +.. _`pypy-sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint +.. _`the technical reports available and other relevant documentation`: http://codespeak.net/pypy/dist/pypy/doc/index.html +.. _`EuroPython schedule`: http://europython.org/timetable From antocuni at codespeak.net Sun Jun 8 23:26:35 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 8 Jun 2008 23:26:35 +0200 (CEST) Subject: [pypy-svn] r55677 - pypy/branch/eval-loop-experiments/pypy/interpreter Message-ID: <20080608212635.C6CBD16805F@codespeak.net> Author: antocuni Date: Sun Jun 8 23:26:35 2008 New Revision: 55677 Modified: pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py Log: remove unneeded attribute Modified: pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py (original) +++ pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py Sun Jun 8 23:26:35 2008 @@ -100,8 +100,6 @@ co_code = pycode.co_code co_codeargs = pycode.co_codeargs - self.name = pycode.co_name - try: while True: next_instr = self.handle_bytecode(co_code, co_codeargs, next_instr, ec) From fijal at codespeak.net Mon Jun 9 06:03:59 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 06:03:59 +0200 (CEST) Subject: [pypy-svn] r55679 - in pypy/dist: lib-python/modified-2.4.1/test pypy/module/_lsprof/testing Message-ID: <20080609040359.923AE16843C@codespeak.net> Author: fijal Date: Mon Jun 9 06:03:56 2008 New Revision: 55679 Added: pypy/dist/pypy/module/_lsprof/testing/profilee.py - copied unchanged from r55617, pypy/dist/lib-python/modified-2.4.1/test/profilee.py Removed: pypy/dist/lib-python/modified-2.4.1/test/profilee.py Log: Move this file to a test directory, a first step to run this test on top of cpython as well From fijal at codespeak.net Mon Jun 9 06:05:37 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 06:05:37 +0200 (CEST) Subject: [pypy-svn] r55680 - in pypy/dist/pypy/module/_lsprof: test testing Message-ID: <20080609040537.D144316843C@codespeak.net> Author: fijal Date: Mon Jun 9 06:05:37 2008 New Revision: 55680 Added: pypy/dist/pypy/module/_lsprof/test/ - copied from r55678, pypy/dist/pypy/module/_lsprof/testing/ pypy/dist/pypy/module/_lsprof/test/__init__.py - copied unchanged from r55679, pypy/dist/pypy/module/_lsprof/testing/__init__.py pypy/dist/pypy/module/_lsprof/test/profilee.py - copied unchanged from r55679, pypy/dist/pypy/module/_lsprof/testing/profilee.py pypy/dist/pypy/module/_lsprof/test/test_cprofile.py - copied unchanged from r55679, pypy/dist/pypy/module/_lsprof/testing/test_cprofile.py Removed: pypy/dist/pypy/module/_lsprof/testing/ Log: Rename test directory, we don't need another name any more From fijal at codespeak.net Mon Jun 9 06:14:46 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 06:14:46 +0200 (CEST) Subject: [pypy-svn] r55681 - pypy/dist/pypy/module/_lsprof/test Message-ID: <20080609041446.AD99C168452@codespeak.net> Author: fijal Date: Mon Jun 9 06:14:46 2008 New Revision: 55681 Modified: pypy/dist/pypy/module/_lsprof/test/test_cprofile.py Log: Adapt this test to a bit newer version. It's kind of question "how it could ever work...", but at least I don't care right now. Modified: pypy/dist/pypy/module/_lsprof/test/test_cprofile.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/test/test_cprofile.py (original) +++ pypy/dist/pypy/module/_lsprof/test/test_cprofile.py Mon Jun 9 06:14:46 2008 @@ -9,125 +9,124 @@ def test_cprofile(self): skip("fails") - import sys - from cProfile import Profile - from test.profilee import testfunc, timer - - methodnames = ['print_stats', 'print_callers', 'print_callees'] - - def do_profiling(cls): - results = [] - prof = cls(timer, 0.001) - start_timer = timer() - prof.runctx("testfunc()", {'testfunc':testfunc}, locals()) - results.append(timer() - start_timer) - for methodname in methodnames: - import pstats - from StringIO import StringIO - s = StringIO() - stats = pstats.Stats(prof, stream=s) - stats.strip_dirs().sort_stats("stdname") - getattr(stats, methodname)() - results.append(s.getvalue()) - return results - - res = do_profiling(Profile) - assert res[0] == 1000 - for i, method in enumerate(methodnames): - if not res[i + 1] == self.expected_output[method]: - print method - print res[i + 1] - print self.expected_output[method] - assert 0 - #assert res[i + 1] == self.expected_output[method] + import sys, os + sys.path.insert(0, os.path.dirname(__file__)) + try: + from cProfile import Profile + from profilee import testfunc, timer + + methodnames = ['print_stats', 'print_callers', 'print_callees'] + + def do_profiling(cls): + results = [] + prof = cls(timer, 0.001) + start_timer = timer() + prof.runctx("testfunc()", {'testfunc':testfunc}, locals()) + results.append(timer() - start_timer) + for methodname in methodnames: + import pstats + from StringIO import StringIO + s = StringIO() + stats = pstats.Stats(prof, stream=s) + stats.strip_dirs().sort_stats("stdname") + getattr(stats, methodname)() + results.append(s.getvalue()) + return results + + res = do_profiling(Profile) + assert res[0] == 1000 + for i, method in enumerate(methodnames): + if not res[i + 1] == self.expected_output[method]: + print method + print res[i + 1] + print self.expected_output[method] + assert 0 + #assert res[i + 1] == self.expected_output[method] + finally: + sys.path.pop(0) expected_output = {} expected_output['print_stats'] = """\ - 127 function calls (107 primitive calls) in 999.749 CPU seconds + 126 function calls (106 primitive calls) in 1.000 CPU seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) - 4 -0.004 -0.001 -0.004 -0.001 :0(append) - 4 -0.004 -0.001 -0.004 -0.001 :0(exc_info) - 12 -0.024 -0.002 11.964 0.997 :0(hasattr) - 8 -0.008 -0.001 -0.008 -0.001 :0(range) - 1 0.000 0.000 0.000 0.000 :0(setprofile) - 1 -0.002 -0.002 999.751 999.751 :1() - 0 0.000 0.000 profile:0(profiler) - 1 -0.002 -0.002 999.749 999.749 profile:0(testfunc()) - 28 27.972 0.999 27.972 0.999 profilee.py:110(__getattr__) - 1 269.996 269.996 999.753 999.753 profilee.py:25(testfunc) - 23/3 149.937 6.519 169.917 56.639 profilee.py:35(factorial) - 20 19.980 0.999 19.980 0.999 profilee.py:48(mul) - 2 39.986 19.993 599.814 299.907 profilee.py:55(helper) - 4 115.984 28.996 119.964 29.991 profilee.py:73(helper1) - 2 -0.006 -0.003 139.942 69.971 profilee.py:84(helper2_indirect) - 8 311.976 38.997 399.896 49.987 profilee.py:88(helper2) - 8 63.968 7.996 79.944 9.993 profilee.py:98(subhelper) + 1 0.000 0.000 1.000 1.000 :1() + 28 0.028 0.001 0.028 0.001 profilee.py:110(__getattr__) + 1 0.270 0.270 1.000 1.000 profilee.py:25(testfunc) + 23/3 0.150 0.007 0.170 0.057 profilee.py:35(factorial) + 20 0.020 0.001 0.020 0.001 profilee.py:48(mul) + 2 0.040 0.020 0.600 0.300 profilee.py:55(helper) + 4 0.116 0.029 0.120 0.030 profilee.py:73(helper1) + 2 0.000 0.000 0.140 0.070 profilee.py:84(helper2_indirect) + 8 0.312 0.039 0.400 0.050 profilee.py:88(helper2) + 8 0.064 0.008 0.080 0.010 profilee.py:98(subhelper) + 12 0.000 0.000 0.012 0.001 {hasattr} + 4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} + 8 0.000 0.000 0.000 0.000 {range} + 4 0.000 0.000 0.000 0.000 {sys.exc_info} """ expected_output['print_callers'] = """\ Ordered by: standard name -Function was called by... -:0(append) <- profilee.py:73(helper1)(4) 119.964 -:0(exc_info) <- profilee.py:73(helper1)(4) 119.964 -:0(hasattr) <- profilee.py:73(helper1)(4) 119.964 - profilee.py:88(helper2)(8) 399.896 -:0(range) <- profilee.py:98(subhelper)(8) 79.944 -:0(setprofile) <- profile:0(testfunc())(1) 999.749 -:1() <- profile:0(testfunc())(1) 999.749 -profile:0(profiler) <- -profile:0(testfunc()) <- profile:0(profiler)(1) 0.000 -profilee.py:110(__getattr__) <- :0(hasattr)(12) 11.964 - profilee.py:98(subhelper)(16) 79.944 -profilee.py:25(testfunc) <- :1()(1) 999.751 -profilee.py:35(factorial) <- profilee.py:25(testfunc)(1) 999.753 - profilee.py:35(factorial)(20) 169.917 - profilee.py:84(helper2_indirect)(2) 139.942 -profilee.py:48(mul) <- profilee.py:35(factorial)(20) 169.917 -profilee.py:55(helper) <- profilee.py:25(testfunc)(2) 999.753 -profilee.py:73(helper1) <- profilee.py:55(helper)(4) 599.814 -profilee.py:84(helper2_indirect) <- profilee.py:55(helper)(2) 599.814 -profilee.py:88(helper2) <- profilee.py:55(helper)(6) 599.814 - profilee.py:84(helper2_indirect)(2) 139.942 -profilee.py:98(subhelper) <- profilee.py:88(helper2)(8) 399.896 +Function was called by... + ncalls tottime cumtime +:1() <- +profilee.py:110(__getattr__) <- 16 0.016 0.016 profilee.py:98(subhelper) + 12 0.012 0.012 {hasattr} +profilee.py:25(testfunc) <- 1 0.270 1.000 :1() +profilee.py:35(factorial) <- 1 0.014 0.130 profilee.py:25(testfunc) + 20/3 0.130 0.147 profilee.py:35(factorial) + 2 0.006 0.040 profilee.py:84(helper2_indirect) +profilee.py:48(mul) <- 20 0.020 0.020 profilee.py:35(factorial) +profilee.py:55(helper) <- 2 0.040 0.600 profilee.py:25(testfunc) +profilee.py:73(helper1) <- 4 0.116 0.120 profilee.py:55(helper) +profilee.py:84(helper2_indirect) <- 2 0.000 0.140 profilee.py:55(helper) +profilee.py:88(helper2) <- 6 0.234 0.300 profilee.py:55(helper) + 2 0.078 0.100 profilee.py:84(helper2_indirect) +profilee.py:98(subhelper) <- 8 0.064 0.080 profilee.py:88(helper2) +{hasattr} <- 4 0.000 0.004 profilee.py:73(helper1) + 8 0.000 0.008 profilee.py:88(helper2) +{method 'append' of 'list' objects} <- 4 0.000 0.000 profilee.py:73(helper1) +{method 'disable' of '_lsprof.Profiler' objects} <- +{range} <- 8 0.000 0.000 profilee.py:98(subhelper) +{sys.exc_info} <- 4 0.000 0.000 profilee.py:73(helper1) """ expected_output['print_callees'] = """\ Ordered by: standard name -Function called... -:0(append) -> -:0(exc_info) -> -:0(hasattr) -> profilee.py:110(__getattr__)(12) 27.972 -:0(range) -> -:0(setprofile) -> -:1() -> profilee.py:25(testfunc)(1) 999.753 -profile:0(profiler) -> profile:0(testfunc())(1) 999.749 -profile:0(testfunc()) -> :0(setprofile)(1) 0.000 - :1()(1) 999.751 -profilee.py:110(__getattr__) -> -profilee.py:25(testfunc) -> profilee.py:35(factorial)(1) 169.917 - profilee.py:55(helper)(2) 599.814 -profilee.py:35(factorial) -> profilee.py:35(factorial)(20) 169.917 - profilee.py:48(mul)(20) 19.980 -profilee.py:48(mul) -> -profilee.py:55(helper) -> profilee.py:73(helper1)(4) 119.964 - profilee.py:84(helper2_indirect)(2) 139.942 - profilee.py:88(helper2)(6) 399.896 -profilee.py:73(helper1) -> :0(append)(4) -0.004 - :0(exc_info)(4) -0.004 - :0(hasattr)(4) 11.964 -profilee.py:84(helper2_indirect) -> profilee.py:35(factorial)(2) 169.917 - profilee.py:88(helper2)(2) 399.896 -profilee.py:88(helper2) -> :0(hasattr)(8) 11.964 - profilee.py:98(subhelper)(8) 79.944 -profilee.py:98(subhelper) -> :0(range)(8) -0.008 - profilee.py:110(__getattr__)(16) 27.972 +Function called... + ncalls tottime cumtime +:1() -> 1 0.270 1.000 profilee.py:25(testfunc) +profilee.py:110(__getattr__) -> +profilee.py:25(testfunc) -> 1 0.014 0.130 profilee.py:35(factorial) + 2 0.040 0.600 profilee.py:55(helper) +profilee.py:35(factorial) -> 20/3 0.130 0.147 profilee.py:35(factorial) + 20 0.020 0.020 profilee.py:48(mul) +profilee.py:48(mul) -> +profilee.py:55(helper) -> 4 0.116 0.120 profilee.py:73(helper1) + 2 0.000 0.140 profilee.py:84(helper2_indirect) + 6 0.234 0.300 profilee.py:88(helper2) +profilee.py:73(helper1) -> 4 0.000 0.004 {hasattr} + 4 0.000 0.000 {method 'append' of 'list' objects} + 4 0.000 0.000 {sys.exc_info} +profilee.py:84(helper2_indirect) -> 2 0.006 0.040 profilee.py:35(factorial) + 2 0.078 0.100 profilee.py:88(helper2) +profilee.py:88(helper2) -> 8 0.064 0.080 profilee.py:98(subhelper) + 8 0.000 0.008 {hasattr} +profilee.py:98(subhelper) -> 16 0.016 0.016 profilee.py:110(__getattr__) + 8 0.000 0.000 {range} +{hasattr} -> 12 0.012 0.012 profilee.py:110(__getattr__) +{method 'append' of 'list' objects} -> +{method 'disable' of '_lsprof.Profiler' objects} -> +{range} -> +{sys.exc_info} -> """ From cami at codespeak.net Mon Jun 9 11:57:34 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Mon, 9 Jun 2008 11:57:34 +0200 (CEST) Subject: [pypy-svn] r55686 - pypy/dist/pypy/lang/gameboy Message-ID: <20080609095734.1ECDC168539@codespeak.net> Author: cami Date: Mon Jun 9 11:57:31 2008 New Revision: 55686 Modified: pypy/dist/pypy/lang/gameboy/video.py Log: video refactorings: more delegate methods Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Mon Jun 9 11:57:31 2008 @@ -49,14 +49,16 @@ self.reset() def reset(self): - self.mode = 0x02 - self.lyc_ly_coincidence = False - self.h_blank_interrupt = False - self.oam_interrupt = False - self.h_blank_interrupt = False - self.vblank_interrupt = False + self.mode = 0x02 + self.lcd_enable = False + self.window_tile_map_select = False + self.window_enable = False + self.background_and_window_tile_data_select = False + self.background_tile_map_select = False + self.big_sprite_size = False + self.sprite_display_enable = False + self.background_enable = False #Coincidence Flag (0:LYC<>LY, 1:LYC=LY) - self.coincidence_flag = False def read(self): value = 0 @@ -70,8 +72,16 @@ return value def write(self, value): + self.lyc_ly_coincidence = bool(value & (1 << 7)) + self.h_blank_interrupt = bool(value & (1 << 6)) + self.oam_interrupt = bool(value & (1 << 5)) + self.h_blank_interrupt = bool(value & (1 << 4)) + self.vblank_interrupt = bool(value & (1 << 3)) + self.coincidence_flag = bool(value & (1 << 2)) + self.mode = value & 0x03 + + def get_bg_tile_data_address(self): pass - # ----------------------------------------------------------------------------- @@ -286,10 +296,7 @@ if self.line_y == self.line_y_compare: # NOTE: raise interrupt once per line if (self.stat & 0x04) == 0: - # constants.LYC=LY interrupt - self.stat |= 0x04 - if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) + self.line_y_line_y_compare_interrupt_check() else: self.stat &= 0xFB @@ -338,22 +345,17 @@ self.window_x = data def emulate_oam(self): - self.stat = (self.stat & 0xFC) | 0x03 - self.cycles += constants.MODE_3_BEGIN_TICKS - self.transfer = True + self.set_mode_3_begin() def emulate_transfer(self): if self.transfer: if self.display: self.draw_line() - self.stat = (self.stat & 0xFC) | 0x03 - self.cycles += constants.MODE_3_END_TICKS - self.transfer = False - else: - self.stat = (self.stat & 0xFC) - self.cycles += constants.MODE_0_TICKS - self.h_blank_interrupt_check() - + self.set_mode_3_end() + else: + self.set_mode_0() + + # interrupt checks --------------------------------------------------- def h_blank_interrupt_check(self): if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44: @@ -368,29 +370,64 @@ self.interrupt.raise_interrupt(constants.LCD) def line_y_line_y_compare_interrupt_check(self): + self.stat |= 0x04 if (self.stat & 0x40) != 0: self.interrupt.raise_interrupt(constants.LCD) + # mode setting ----------------------------------------------------------- + + def set_mode_3_begin(self): + self.stat = (self.stat & 0xFC) | 0x03 + self.cycles += constants.MODE_3_BEGIN_TICKS + self.transfer = True + + def set_mode_3_end(self): + self.stat = (self.stat & 0xFC) | 0x03 + self.cycles += constants.MODE_3_END_TICKS + self.transfer = False + + def set_mode_0(self): + self.stat = (self.stat & 0xFC) + self.cycles += constants.MODE_0_TICKS + self.h_blank_interrupt_check() + def set_mode_2(self): + self.stat = (self.stat & 0xFC) | 0x02 + self.cycles += constants.MODE_2_TICKS + self.oam_interrupt_check() + + def set_mode_1_begin(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_BEGIN_TICKS + + def set_mode_1(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_TICKS + + def set_mode_1_between(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS + + def set_mode_1_end(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_END_TICKS + + # ---------------------------------------------------------------- + def emulate_hblank(self): self.line_y+=1 self.emulate_hblank_line_y_compare() if self.line_y < 144: - self.emulate_hblank_part_1() + self.set_mode_2() else: self.emulate_hblank_part_2() def emulate_hblank_line_y_compare(self): if self.line_y == self.line_y_compare: - self.stat |= 0x04 self.line_y_line_y_compare_interrupt_check() else: self.stat &= 0xFB - def emulate_hblank_part_1(self): - self.stat = (self.stat & 0xFC) | 0x02 - self.cycles += constants.MODE_2_TICKS - self.oam_interrupt_check() def emulate_hblank_part_2(self): if self.display: @@ -401,48 +438,40 @@ self.frames = 0 else: self.display = False - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_BEGIN_TICKS + self.set_mode_1_begin() self.vblank = True def emulate_vblank(self): if self.vblank: self.emulate_vblank_vblank() elif self.line_y == 0: - self.emulate_vblank_first_y_line() + self.set_mode_2() else: self.emulate_vblank_other() def emulate_vblank_vblank(self): self.vblank = False - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS + self.set_mode_1_between() self.v_blank_interrupt_check() self.interrupt.raise_interrupt(constants.VBLANK) - - def emulate_vblank_first_y_line(self): - self.stat = (self.stat & 0xFC) | 0x02 - self.cycles += constants.MODE_2_TICKS - self.oam_interrupt_check(); - def emulate_vblank_other(self): if self.line_y < 153: - self.line_y += 1 - self.stat = (self.stat & 0xFC) | 0x01 - if self.line_y == 153: - self.cycles += constants.MODE_1_END_TICKS - else: - self.cycles += constants.MODE_1_TICKS + self.emulate_vblank_mode_1() else: self.line_y = self.window_line_y = 0 - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_TICKS - constants.MODE_1_END_TICKS + self.set_mode_1_between() if self.line_y == self.line_y_compare: - self.stat |= 0x04 self.line_y_line_y_compare_interrupt_check(); else: self.stat &= 0xFB + + def emulate_vblank_mode_1(self): + self.line_y += 1 + if self.line_y == 153: + self.set_mode_1_end() + else: + self.set_mode_1() def draw_frame(self): self.driver.update_display() @@ -467,38 +496,38 @@ self.line[x] = 0x00 def draw_background(self): - y = (self.scroll_y + self.line_y) & 0xFF - x = self.scroll_x & 0xFF - tile_map = constants.VRAM_MAP_A - if (self.control & 0x08) != 0: - tile_map = constants.VRAM_MAP_B - - tile_data = constants.VRAM_DATA_B - if (self.control & 0x10) != 0: - tile_data = constants.VRAM_DATA_A - + y = (self.scroll_y + self.line_y) & 0xFF + x = self.scroll_x & 0xFF + tile_map = self.get_tile_map(0x08) tile_map += ((y >> 3) << 5) + (x >> 3) + tile_data = self.get_tile_data(0x10) tile_data += (y & 7) << 1 self.draw_tiles(8 - (x & 7), tile_map, tile_data) - + def draw_window(self): - if self.line_y < self.window_y or \ - self.window_x >= 167 or \ + if self.line_y < self.window_y or \ + self.window_x >= 167 or \ self.window_line_y >= 144: - return - tile_map = constants.VRAM_MAP_A - if (self.control & 0x40) != 0: - tile_map = constants.VRAM_MAP_B - - tile_data = constants.VRAM_DATA_B - if (self.control & 0x10) != 0: - tile_data = constants.VRAM_DATA_A - - tile_map += (self.window_line_y >> 3) << 5 - tile_data += (self.window_line_y & 7) << 1 + return + tile_map = self.get_tile_map(0x40) + tile_map += (self.window_line_y >> 3) << 5 + tile_data = self.get_tile_data(0x10) + tile_data += (self.window_line_y & 7) << 1 self.draw_tiles(self.window_x + 1, tile_map, tile_data) self.window_line_y += 1 + def get_tile_map(self, mask): + if (self.control & mask) != 0: + return constants.VRAM_MAP_B + else: + return constants.VRAM_MAP_A + + def get_tile_data(self, mask): + if (self.control & mask) != 0: + return constants.VRAM_DATA_A + else: + return constants.VRAM_DATA_B + def draw_objects(self): count = self.scan_objects() lastx = 176 @@ -517,12 +546,12 @@ count = 0 # search active objects for offset in range(0, 4*40, 4): - y = self.oam[offset + 0] & 0xFF - x = self.oam[offset + 1] & 0xFF + y = self.oam[offset + 0] + x = self.oam[offset + 1] if (y <= 0 or y >= 144 + 16 or x <= 0 or x >= 168): continue - tile = self.oam[offset + 2] & 0xFF - flags = self.oam[offset + 3] & 0xFF + tile = self.oam[offset + 2] + flags = self.oam[offset + 3] y = self.line_y - y + 16 if ((self.control & 0x04) != 0): # 8x16 tile size @@ -638,8 +667,7 @@ self.driver.clear_pixels() def update_palette(self): - if not self.dirty: - return + if not self.dirty: return # bit 4/0 = BG color, # bit 5/1 = OBJ color, # bit 2 = OBJ palette, From cami at codespeak.net Mon Jun 9 13:12:58 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Mon, 9 Jun 2008 13:12:58 +0200 (CEST) Subject: [pypy-svn] r55687 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080609111258.2D1FB169EBD@codespeak.net> Author: cami Date: Mon Jun 9 13:12:57 2008 New Revision: 55687 Modified: pypy/dist/pypy/lang/gameboy/cartridge.py pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/gameboy.py pypy/dist/pypy/lang/gameboy/interrupt.py pypy/dist/pypy/lang/gameboy/joypad.py pypy/dist/pypy/lang/gameboy/ram.py pypy/dist/pypy/lang/gameboy/serial.py pypy/dist/pypy/lang/gameboy/sound.py pypy/dist/pypy/lang/gameboy/test/test_cpu.py pypy/dist/pypy/lang/gameboy/timer.py pypy/dist/pypy/lang/gameboy/video.py Log: code reformatting Modified: pypy/dist/pypy/lang/gameboy/cartridge.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cartridge.py (original) +++ pypy/dist/pypy/lang/gameboy/cartridge.py Mon Jun 9 13:12:57 2008 @@ -357,7 +357,7 @@ class MBC1(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Memory Bank Controller 1 (2MB ROM, 32KB RAM) @@ -419,7 +419,7 @@ class MBC2(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Memory Bank Controller 2 (256KB ROM, 512x4bit RAM) @@ -480,7 +480,7 @@ class MBC3(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Memory Bank Controller 3 (2MB ROM, 32KB RAM, Real Time Clock) @@ -632,7 +632,7 @@ class MBC5(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Memory Bank Controller 5 (8MB ROM, 128KB RAM) * @@ -693,7 +693,7 @@ class HuC3(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Hudson Memory Bank Controller 3 (2MB ROM, 128KB RAM, RTC) Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Mon Jun 9 13:12:57 2008 @@ -6,7 +6,7 @@ # --------------------------------------------------------------------------- def process_2_complement(value): - # check if the left most bit is set + # check if the left most bit is set if (value >> 7) == 1: return -((~value) & 0xFF) - 1 else : @@ -466,8 +466,6 @@ def call(self, address, use_cycles=True): # 4 cycles self.push_double_register(self.pc, use_cycles) - #self.push(self.pc.get_hi(use_cycles), use_cycles) # 2 cycles - #self.push(self.pc.get_lo(use_cycles), use_cycles) # 2 cycles self.pc.set(address, use_cycles=use_cycles) # 1 cycle if use_cycles: self.cycles += 1 @@ -529,10 +527,8 @@ def subtract_a(self, getCaller, setCaller=None): # 1 cycle data = getCaller.get() - #self.compare_a(data) # 1 cycle self.compare_a_simple(data) self.a.sub(data, False) - #self.a.sub(getCaller.get(use_cycles=False), False) def fetch_subtract_a(self): data = self.fetch() @@ -555,7 +551,6 @@ def hc_flag_finish(self, data): if data > self.a.get(): self.f.c_flag = True - #self.f.c_flag_compare(data, self.a.get()) self.f.h_flag_compare(data, self.a.get()) def and_a(self, getCaller, setCaller=None): @@ -858,7 +853,6 @@ def relative_jump(self): # JR +nn, 3 cycles - #pc = pc & 0xFF00 + ((pc & 0x00FF) + add) & 0xFF self.pc.add(process_2_complement(self.fetch())) # 3 + 1 cycles self.cycles += 1 Modified: pypy/dist/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy.py Mon Jun 9 13:12:57 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator GameBoy Scheduler and Memory Mapper Modified: pypy/dist/pypy/lang/gameboy/interrupt.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/interrupt.py (original) +++ pypy/dist/pypy/lang/gameboy/interrupt.py Mon Jun 9 13:12:57 2008 @@ -30,7 +30,7 @@ class Interrupt(iMemory): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Interrupt Controller """ Modified: pypy/dist/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/joypad.py (original) +++ pypy/dist/pypy/lang/gameboy/joypad.py Mon Jun 9 13:12:57 2008 @@ -5,7 +5,7 @@ class Joypad(iMemory): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Joypad Input """ Modified: pypy/dist/pypy/lang/gameboy/ram.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/ram.py (original) +++ pypy/dist/pypy/lang/gameboy/ram.py Mon Jun 9 13:12:57 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Work and High RAM """ Modified: pypy/dist/pypy/lang/gameboy/serial.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/serial.py (original) +++ pypy/dist/pypy/lang/gameboy/serial.py Mon Jun 9 13:12:57 2008 @@ -5,7 +5,7 @@ class Serial(iMemory): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Serial Link Controller """ Modified: pypy/dist/pypy/lang/gameboy/sound.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/sound.py (original) +++ pypy/dist/pypy/lang/gameboy/sound.py Mon Jun 9 13:12:57 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Audio Processor Unit (Sharp LR35902 APU) """ Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu.py Mon Jun 9 13:12:57 2008 @@ -33,10 +33,10 @@ def test_reset(): cpu = get_cpu() - assert cpu.a.get() == 0x01 + assert cpu.a.get() == 0x01 #assert cpu.f.get() == 0xB0 - assert cpu.b.get() == 0x00 - assert cpu.c.get() == 0x13 + assert cpu.b.get() == 0x00 + assert cpu.c.get() == 0x13 assert cpu.de.get() == 0x00D8 assert cpu.hl.get() == 0x014D #assert cpu.sp.get() == 0xFFE @@ -44,66 +44,66 @@ def test_getters(): cpu = get_cpu() assert_default_registers(cpu) - assert cpu.af.cpu == cpu - assert cpu.a.cpu == cpu - assert cpu.f.cpu == cpu - - assert cpu.bc.cpu == cpu - assert cpu.b.cpu == cpu - assert cpu.c.cpu == cpu - - assert cpu.de.cpu == cpu - assert cpu.d.cpu == cpu - assert cpu.e.cpu == cpu + assert cpu.af.cpu == cpu + assert cpu.a.cpu == cpu + assert cpu.f.cpu == cpu + + assert cpu.bc.cpu == cpu + assert cpu.b.cpu == cpu + assert cpu.c.cpu == cpu + + assert cpu.de.cpu == cpu + assert cpu.d.cpu == cpu + assert cpu.e.cpu == cpu - assert cpu.hl.cpu == cpu + assert cpu.hl.cpu == cpu assert cpu.hli.cpu == cpu - assert cpu.h.cpu == cpu - assert cpu.l.cpu == cpu + assert cpu.h.cpu == cpu + assert cpu.l.cpu == cpu - assert cpu.sp.cpu == cpu - assert cpu.pc.cpu == cpu + assert cpu.sp.cpu == cpu + assert cpu.pc.cpu == cpu def test_fetch(): - cpu = get_cpu() - address = 0x3FFF - value = 0x12 + cpu = get_cpu() + address = 0x3FFF + value = 0x12 # in rom cpu.pc.set(address) cpu.rom[address] = value - startCycles = cpu.cycles - assert cpu.fetch() == value + startCycles = cpu.cycles + assert cpu.fetch() == value assert startCycles-cpu.cycles == 1 # in the memory - value = 0x13 - address = 0xC000 + value = 0x13 + address = 0xC000 cpu.pc.set(address) cpu.memory.write(address, value) assert cpu.fetch() == value def test_read_write(): - cpu = get_cpu() - address = 0xC000 - value = 0x12 + cpu = get_cpu() + address = 0xC000 + value = 0x12 startCycles = cpu.cycles cpu.write(address, value) assert startCycles-cpu.cycles == 2 startCycles = cpu.cycles - assert cpu.read(address) == value + assert cpu.read(address) == value assert startCycles-cpu.cycles == 1 - address +=1 - value += 1 + address +=1 + value += 1 cpu.write(address, value) - assert cpu.read(address) == value + assert cpu.read(address) == value def test_relative_conditional_jump(): - cpu = get_cpu() - pc = cpu.pc.get() - value = 0x12 + cpu = get_cpu() + pc = cpu.pc.get() + value = 0x12 cpu.rom[constants.RESET_PC] = value # test jr_nn startCycles = cpu.cycles @@ -112,26 +112,26 @@ assert_registers(cpu, pc=pc+value+1) # test pc.inc startCycles = cpu.cycles - pc = cpu.pc.get() + pc = cpu.pc.get() cpu.relative_conditional_jump(False) assert startCycles-cpu.cycles == 2 - assert cpu.pc.get() == pc+1 + assert cpu.pc.get() == pc+1 def test_flags(): cpu = get_cpu() cpu.f.set(constants.Z_FLAG) - assert cpu.is_z() == True + assert cpu.is_z() == True assert cpu.is_not_z() == False cpu.f.set(~constants.Z_FLAG) - assert cpu.is_z() == False + assert cpu.is_z() == False assert cpu.is_not_z() == True cpu.f.set(constants.C_FLAG) - assert cpu.is_c() == True + assert cpu.is_c() == True assert cpu.is_not_c() == False cpu.f.set(~constants.C_FLAG) - assert cpu.is_c() == False + assert cpu.is_c() == False assert cpu.is_not_c() == True def test_flags_memory_access(): @@ -173,10 +173,10 @@ def test_create_group_op_codes(): assert len(GROUPED_REGISTERS) == 8 - start=0x12 - step=0x03 - func = CPU.inc - table = [(start, step, func)] + start = 0x12 + step = 0x03 + func = CPU.inc + table = [(start, step, func)] grouped = create_group_op_codes(table) assert len(grouped) == len(table)*8 @@ -190,13 +190,13 @@ def test_create_register_op_codes(): - start = 0x09 - step = 0x10 - func = CPU.add_hl + start = 0x09 + step = 0x10 + func = CPU.add_hl registers = [CPU.get_bc]*128 - table = [(start, step, func, registers)] - list = create_register_op_codes(table) - opCode = start + table = [(start, step, func, registers)] + list = create_register_op_codes(table) + opCode = start assert len(list) == len(registers) for entry in list: assert len(entry) == 2 @@ -256,7 +256,7 @@ cpu.memory.write(pc, value & 0xFF) def test_prepare_for_fetch(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_fetch(cpu, value+1, value) assert cpu.fetch() == value @@ -270,7 +270,7 @@ cpu.memory.write(sp, value & 0xFF) def test_prepare_for_pop(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_pop(cpu, value+1, value) assert cpu.pop() == value @@ -286,14 +286,14 @@ # test helper methods ---------------------------------------------------------- def test_prepare_for_pop(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_pop(cpu, value, value+1) assert cpu.pop() == value+1 assert cpu.pop() == value def test_prepare_for_fetch(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_fetch(cpu, value, value+1) assert cpu.fetch() == value+1 @@ -310,28 +310,28 @@ #load_mem_SP def test_0x08(): - cpu = get_cpu() + cpu = get_cpu() assert_default_registers(cpu) startPC = cpu.pc.get() prepare_for_fetch(cpu, 0xCD, 0xEF) cpu.sp.set(0x1234) cycle_test(cpu, 0x08, 5) assert_default_registers(cpu, pc=startPC+2, sp=0x1234) - assert cpu.memory.read(0xCDEF) == cpu.sp.get_lo() + assert cpu.memory.read(0xCDEF) == cpu.sp.get_lo() assert cpu.memory.read(0xCDEF+1) == cpu.sp.get_hi() # stop def test_0x10(): cpu = get_cpu() - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0x10, 0) # fetches 1 cycle assert_default_registers(cpu, pc=pc+1) # jr_nn def test_0x18(): - cpu = get_cpu(); - pc = cpu.pc.get() + cpu = get_cpu(); + pc = cpu.pc.get() value = 0x12 cpu.rom[constants.RESET_PC] = value assert_default_registers(cpu) @@ -340,10 +340,10 @@ # jr_NZ_nn see test_jr_cc_nn def test_0x20_0x28_0x30(): - cpu = get_cpu() + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0x20 - value = 0x12 + value = 0x12 for i in range(0, 4): prepare_for_fetch(cpu, value) pc = cpu.pc.get() @@ -360,10 +360,10 @@ # ld_BC_nnnn to ld_SP_nnnn def test_0x01_0x11_0x21_0x31_load_register_nnnn(): - cpu = get_cpu() - registers= [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 - opCode = 0x01 + cpu = get_cpu() + registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] + value = 0x12 + opCode = 0x01 for index in range(0, len(registers)): prepare_for_fetch(cpu, value, value+1) cycle_test(cpu, opCode, 3) @@ -374,16 +374,16 @@ # add_HL_BC to add_HL_SP def test_0x09_0x19_0x29_0x39(): - cpu = get_cpu() - registers= [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x1234 - opCode = 0x09 + cpu = get_cpu() + registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] + value = 0x1234 + opCode = 0x09 for i in range(0, len(registers)): cpu.hl.set(value) registers[i].set(value) assert registers[i].get() == value cycle_test(cpu, opCode, 2) - assert cpu.hl.get() == value+value + assert cpu.hl.get() == value+value value += 3 opCode += 0x10 @@ -397,8 +397,8 @@ # ld_A_BCi def test_0x0A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xC020 cpu.bc.set(address) cpu.write(address, value) @@ -417,8 +417,8 @@ # load_a_DEi def test_0x1A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xC020 cpu.de.set(address) cpu.write(address, value) @@ -433,7 +433,7 @@ cpu.a.set(0x12); cycle_test(cpu, 0x22, 2); assert cpu.read(0xCDEF) == cpu.a.get() - assert cpu.hl.get() == 0xCDEF+1 + assert cpu.hl.get() == 0xCDEF+1 # ldd_HLi_A def test_0x32(): @@ -442,13 +442,13 @@ cpu.a.set(0x12); cycle_test(cpu, 0x32, 2); assert cpu.read(0xCDEF) == cpu.a.get() - assert cpu.hl.get() == 0xCDEF-1 + assert cpu.hl.get() == 0xCDEF-1 # ldi_A_HLi def test_0x2A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF cpu.hl.set(address) cpu.write(address, value) @@ -458,8 +458,8 @@ # ldd_A_HLi def test_0x3A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF cpu.hl.set(address) cpu.write(address, value) @@ -469,10 +469,10 @@ # inc_BC DE HL SP def test_0x03_to_0x33_inc_double_registers(): - cpu = get_cpu() - opCode = 0x03 + cpu = get_cpu() + opCode = 0x03 registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 + value = 0x12 for i in range(0,4): set_registers(registers, 0) registers[i].set(value) @@ -484,10 +484,10 @@ # dec_BC def test_0x0B_to_0c38_dec_double_registers(): - cpu = get_cpu() - opCode = 0x0B + cpu = get_cpu() + opCode = 0x0B registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 + value = 0x12 for i in range(0,4): set_registers(registers, 0) registers[i].set(value) @@ -517,10 +517,10 @@ # inc_B C D E H L A def test_0x04_to_0x3C_inc_registers(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x04 - value = 0x12 + opCode = 0x04 + value = 0x12 for register in registers: if register == cpu.hli: opCode += 0x08 @@ -535,7 +535,7 @@ # inc_HLi def test_0x34(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 cpu.hl.set(0xCDEF) cpu.write(cpu.hl.get(), value) @@ -545,9 +545,9 @@ def test_dec(): - cpu = get_cpu() + cpu = get_cpu() # cycle testing is done in the other tests - a = cpu.a + a = cpu.a a.set(1) cpu.f.c_flag = True cpu.dec(RegisterCallWrapper(a), RegisterCallWrapper(a)) @@ -571,10 +571,10 @@ # dec_B C D E H L A def test_0x05_to_0x3D_dec_registers(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x05 - value = 0x12 + opCode = 0x05 + value = 0x12 for register in registers: if register == cpu.hli: opCode += 0x08 @@ -589,7 +589,7 @@ # dec_HLi def test_0x35(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 cpu.hl.set(0xCDEF) cpu.write(cpu.hl.get(), value) @@ -599,10 +599,10 @@ # ld_B_nn C D E H L A ) def test_0x06_to_0x3A(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x06 - value = 0x12 + opCode = 0x06 + value = 0x12 for i in range(0, len(registers)): if registers[i] == cpu.hli: opCode += 0x08 @@ -611,7 +611,7 @@ set_registers(registers, 0) prepare_for_fetch(cpu, value) cycle_test(cpu, opCode, 2) - assert registers[i].get() == value + assert registers[i].get() == value assert cpu.pc.get() - oldPC == 1 cpu.reset() opCode += 0x08 @@ -619,19 +619,19 @@ # ld_HLi_nn def test_0x36(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF prepare_for_fetch(cpu, value) cpu.hl.set(address) - oldPC = cpu.pc.get() + oldPC = cpu.pc.get() cycle_test(cpu, 0x36, 3) assert cpu.read(cpu.hl.get()) == value assert_default_registers(cpu, pc=oldPC+1, hl=address) # rlca def test_0x07(): - cpu = get_cpu() + cpu = get_cpu() value = 0x80 cpu.a.set(value) cycle_test(cpu, 0x07, 1) @@ -645,7 +645,7 @@ # rrca def test_0x0F(): - cpu = get_cpu() + cpu = get_cpu() value = 0x01 cpu.a.set(value) cycle_test(cpu, 0x0F, 1) @@ -659,7 +659,7 @@ # rla def test_0x17(): - cpu = get_cpu() + cpu = get_cpu() value = 0x01 cpu.f.set(0x00) cpu.a.set(value) @@ -668,7 +668,7 @@ # rra def test_0x1F(): - cpu = get_cpu() + cpu = get_cpu() value = 0x40 cpu.f.set(0x00) cpu.a.set(value) @@ -696,9 +696,9 @@ # cpl def test_0x2F(): - cpu = get_cpu() - value = 0x12 - fValue = cpu.f.get() + cpu = get_cpu() + value = 0x12 + fValue = cpu.f.get() cpu.f.n_flag = False cpu.f.h_flag = False cpu.a.set(value) @@ -733,9 +733,9 @@ # halt def test_0x76(): - cpu = get_cpu() + cpu = get_cpu() cpu.cycles = 0xFF - cpu.ime = True + cpu.ime = True assert cpu.halted == False cycle_test(cpu, 0x76, cpu.cycles) assert cpu.halted == True @@ -744,9 +744,9 @@ # ld_B_B to ld_A_A def test_load_registers(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x40 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for store in registers: for load in registers: @@ -766,10 +766,10 @@ # add_A_B to add_A_A def test_0x80_to_0x87(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x80 valueA = 0x11 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -788,9 +788,9 @@ # adc_A_B to adx_A_A def test_0x88_to_0x8F(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x88 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -820,9 +820,9 @@ # sub_A_B to sub_A_A def test_0x90_to_0x98(): - cpu = get_cpu() - opCode = 0x90 - value = 0x12 + cpu = get_cpu() + opCode = 0x90 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -838,9 +838,9 @@ # sbc_A_B to sbc_A_A def test_0x98_0x9F(): - cpu = get_cpu() - opCode = 0x98 - value = 0x12 + cpu = get_cpu() + opCode = 0x98 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -870,10 +870,10 @@ # and_A_B to and_A_A def test_0xA0_to_0xA7(): - cpu = get_cpu() - opCode = 0xA0 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xA0 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -892,10 +892,10 @@ # xor_A_B to xor_A_A def test_0xA8_to_0xAF(): - cpu = get_cpu() - opCode = 0xA8 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xA8 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -915,10 +915,10 @@ # or_A_B to or_A_A def test_0xB0_to_0xB7(): - cpu = get_cpu() - opCode = 0xB0 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xB0 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -937,10 +937,10 @@ # cp_A_B to cp_A_A def test_0xB8_to_0xBF_compare_a(): - cpu = get_cpu() - opCode = 0xB8 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xB8 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -957,10 +957,10 @@ # ret_NZ to ret_C def test_0xC0(): - cpu = get_cpu() + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC0 - value = 0x1234 + value = 0x1234 for i in range(0, 4): cpu.reset() prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -978,9 +978,9 @@ # ldh_mem_A def test_0xE0(): - cpu = get_cpu() + cpu = get_cpu() valueA = 0x11 - value = 0x12 + value = 0x12 prepare_for_fetch(cpu, value) cpu.a.set(valueA) cycle_test(cpu, 0xE0, 3) @@ -989,8 +989,8 @@ # add_SP_nn def test_0xE8(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 spValue = 0xCDEF prepare_for_fetch(cpu, value) cpu.sp.set(spValue) @@ -999,9 +999,9 @@ # ldh_A_mem def test_0xF0(): - cpu = get_cpu() - valueA = 0x11 - value= 0x12 + cpu = get_cpu() + valueA = 0x11 + value = 0x12 address = 0x13 cpu.a.set(valueA) prepare_for_fetch(cpu, address) @@ -1011,11 +1011,11 @@ # ld_A_mem def test_0xFA(): - cpu = get_cpu() - value = 0x11 + cpu = get_cpu() + value = 0x11 valueA = 0x12 cpu.a.set(valueA) - pc = cpu.pc.get(); + pc = cpu.pc.get(); prepare_for_fetch(cpu, 0x12, 0x34) cpu.write(0x1234, value) cycle_test(cpu, 0xFA, 4) @@ -1023,7 +1023,7 @@ # ld_mem_A def test_0xEA(): - cpu = get_cpu() + cpu = get_cpu() valueA = 0x56 prepare_for_fetch(cpu, 0x12, 0x34) cpu.a.set(valueA) @@ -1033,22 +1033,22 @@ # ld_HL_SP_nn def test_0xF8(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueSp = 0x1234 prepare_for_fetch(cpu, value) cpu.sp.set(valueSp) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xF8, 3) - f = cpu.f.get(); + f = cpu.f.get(); assert_default_registers(cpu, hl=valueSp+value, f=f, sp=valueSp, pc=pc+1) # pop_BC to pop_AF def test_0xC1_to_0xF1(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.af] - opCode = 0xC1 - value = 0x1234 + opCode = 0xC1 + value = 0x1234 for register in registers: cpu.reset() prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1059,8 +1059,8 @@ # ret def test_0xC9(): - cpu = get_cpu() - value = 0x1234 + cpu = get_cpu() + value = 0x1234 valueSp = 0x5678 cpu.sp.set(valueSp) prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1069,18 +1069,18 @@ # reti def test_0xD9_return_form_interrupt(): - cpu = get_cpu() + cpu = get_cpu() cpu.interrupt.reset() value = 0x1234 cpu.sp.set(0) prepare_for_pop(cpu, value >> 8, value & 0xFF) prepare_for_fetch(cpu, 0x00) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xD9, 4+2) assert_default_registers(cpu, pc=value+1, sp=2) def test_handle_interrupt(): - cpu = get_cpu() + cpu = get_cpu() cpu.interrupt.reset() cpu.halted = True cpu.cycles = 0xFF @@ -1096,8 +1096,8 @@ assert cpu.interrupt.is_pending() == True assert cpu.halted == True cpu.handle_pending_interrupts() - assert cpu.cycles == 0 - assert cpu.halted == False + assert cpu.cycles == 0 + assert cpu.halted == False cpu.reset() cpu.interrupt.reset() @@ -1120,7 +1120,7 @@ # ld_PC_HL def test_0xE9(): - cpu = get_cpu() + cpu = get_cpu() value = 0x1234 cpu.hl.set(value) cycle_test(cpu, 0xE9, 1) @@ -1128,7 +1128,7 @@ # ld_SP_HL def test_0xF9(): - cpu = get_cpu() + cpu = get_cpu() value = 0x1234 cpu.hl.set(value) cycle_test(cpu, 0xF9, 2) @@ -1136,10 +1136,10 @@ # jp_NZ_nnnn to jp_C_nnnn def test_0xC2_to_0xDA(): - cpu = get_cpu() + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC2 - value = 0x1234 + value = 0x1234 for i in range(0, 4): cpu.reset() prepare_for_fetch(cpu, value >> 8, value & 0xFF) @@ -1159,8 +1159,8 @@ # ldh_Ci_A def test_0xE2(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueA = value+1 cpu.c.set(value) cpu.a.set(valueA) @@ -1169,7 +1169,7 @@ # ldh_A_Ci def test_0xF2(): - cpu = get_cpu() + cpu = get_cpu() valueC = 0x12 valueA = 0x11 cpu.c.set(valueC) @@ -1190,7 +1190,7 @@ def test_0xF3_disable_interrupt(): cpu = get_cpu() cpu.interrupt.reset() - cpu.ime == True + cpu.ime = True cycle_test(cpu, 0xF3, 1) assert cpu.ime == False @@ -1221,17 +1221,17 @@ assert cpu.halted == False assert cpu.ime == True cycle_test(cpu, 0xFB, 1+1) - assert cpu.interrupt.is_pending() == True + assert cpu.interrupt.is_pending() == True assert cpu.interrupt.vblank.is_pending() == False assert cpu.interrupt.serial.is_pending() == True - assert cpu.pc.get() == cpu.interrupt.vblank.call_code - assert cpu.ime == False + assert cpu.pc.get() == cpu.interrupt.vblank.call_code + assert cpu.ime == False cpu.ime = True cycle_test(cpu, 0xFB, 1+1) assert cpu.interrupt.vblank.is_pending() == False assert cpu.interrupt.serial.is_pending() == False - assert cpu.interrupt.is_pending() == False + assert cpu.interrupt.is_pending() == False def conditional_call_test(cpu, opCode, flagSetter): flagSetter(cpu, False) @@ -1283,10 +1283,10 @@ # push_BC to push_AF def test_0xC5_to_0xF5_push(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.af] - opCode = 0xC5 - value = 0x1234 + opCode = 0xC5 + value = 0x1234 for register in registers: register.set(value) cycle_test(cpu, opCode, 4) @@ -1298,7 +1298,7 @@ # call_nnnn def test_0xCD_call(): - cpu = get_cpu() + cpu = get_cpu() fetchValue = 0x1234 cpu.sp.set(fetchValue) prepare_for_fetch(cpu, fetchValue) @@ -1307,12 +1307,12 @@ def a_nn_test(opCode, cycles, opCaller): # flags tested already - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueAdd = 0x12 cpu.a.set(value) prepare_for_fetch(cpu, valueAdd,) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, opCode, cycles) assert_default_registers(cpu, a=opCaller(value,valueAdd, cpu), pc=pc+1, f=cpu.f.get()) @@ -1349,11 +1349,11 @@ # cp_A_nn def test_0xFE(): # flags tested already - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueA = 0x12 cpu.a.set(valueA) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xFE, 2) @@ -1362,15 +1362,15 @@ # rst(0x00) to rst(0x38) def test_0xC7_to_0xFF(): - cpu = get_cpu() - opCode = 0xC7 + cpu = get_cpu() + opCode = 0xC7 rstValue = 0x00 for i in range(0,8): cpu.reset() cpu.pc.set(0x1234) cycle_test(cpu, opCode, 4) assert cpu.pop() == 0x34 - assert cpu.pop() == 0x12 + assert cpu.pop() == 0x12 assert cpu.pc.get() == rstValue opCode += 0x08 rstValue += 0x08 @@ -1378,7 +1378,7 @@ # switching to other opcode set def test_0xCB(): cpu = get_cpu() - pc = cpu.pc.get() + pc = cpu.pc.get() prepare_for_fetch(cpu, 0x80) cycle_test(cpu, 0xCB, 2) assert_default_registers(cpu, pc=pc+1) @@ -1388,9 +1388,9 @@ # SECOND ORDER OPCODES --------------------------------------------------------- def second_order_test(opCode, createFunction): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0xF0 + value = 0xF0 for register in registers: cpu.reset() register.set(value) @@ -1436,9 +1436,9 @@ # bit_B to bit_A def test_testBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x40 + opCode = 0x40 for register in registers: registerOpCode = opCode for i in range(8): @@ -1461,17 +1461,16 @@ # set_B to set_C def test_setBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0x12 - opCode = 0xC0 + value = 0x12 + opCode = 0xC0 for register in registers: registerOpCode = opCode for i in range(8): cycles = 2 if register == cpu.hli: cycles = 4 - cpu.reset() register.set(0) fetch_execute_cycle_test_second_order(cpu, registerOpCode, cycles) @@ -1483,16 +1482,15 @@ # res_B to res_A def test_resetBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0x12 - opCode = 0x80 + value = 0x12 + opCode = 0x80 for register in registers: registerOpCode = opCode cycles = 2 if register == cpu.hli: cycles = 4 - for i in range(8): cpu.reset() register.set(0) @@ -1510,5 +1508,4 @@ - \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/timer.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/timer.py (original) +++ pypy/dist/pypy/lang/gameboy/timer.py Mon Jun 9 13:12:57 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Timer and Divider """ Modified: pypy/dist/pypy/lang/gameboy/video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/video.py (original) +++ pypy/dist/pypy/lang/gameboy/video.py Mon Jun 9 13:12:57 2008 @@ -1,5 +1,5 @@ """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator constants.LCD Video Display Processor """ @@ -293,12 +293,7 @@ self.line_y_compare = data if (self.control & 0x80) == 0: return - if self.line_y == self.line_y_compare: - # NOTE: raise interrupt once per line - if (self.stat & 0x04) == 0: - self.line_y_line_y_compare_interrupt_check() - else: - self.stat &= 0xFB + self.emulate_hblank_line_y_compare() def get_dma(self): return self.dma @@ -427,7 +422,6 @@ self.line_y_line_y_compare_interrupt_check() else: self.stat &= 0xFB - def emulate_hblank_part_2(self): if self.display: @@ -459,12 +453,10 @@ if self.line_y < 153: self.emulate_vblank_mode_1() else: - self.line_y = self.window_line_y = 0 + self.line_y = 0 + self.window_line_y = 0 self.set_mode_1_between() - if self.line_y == self.line_y_compare: - self.line_y_line_y_compare_interrupt_check(); - else: - self.stat &= 0xFB + self.emulate_hblank_line_y_compare() def emulate_vblank_mode_1(self): self.line_y += 1 @@ -498,24 +490,32 @@ def draw_background(self): y = (self.scroll_y + self.line_y) & 0xFF x = self.scroll_x & 0xFF + tile_map, tile_data = self.prepare_background_data(x, y) + self.draw_tiles(8 - (x & 7), tile_map, tile_data) + + def prepare_background_data(self, x, y): tile_map = self.get_tile_map(0x08) tile_map += ((y >> 3) << 5) + (x >> 3) tile_data = self.get_tile_data(0x10) tile_data += (y & 7) << 1 - self.draw_tiles(8 - (x & 7), tile_map, tile_data) + return tile_map, tile_data def draw_window(self): if self.line_y < self.window_y or \ self.window_x >= 167 or \ self.window_line_y >= 144: return + tile_map, tile_data = self.prepare_window_data() + self.draw_tiles(self.window_x + 1, tile_map, tile_data) + self.window_line_y += 1 + + def prepare_window_data(self): tile_map = self.get_tile_map(0x40) tile_map += (self.window_line_y >> 3) << 5 tile_data = self.get_tile_data(0x10) tile_data += (self.window_line_y & 7) << 1 - self.draw_tiles(self.window_x + 1, tile_map, tile_data) - self.window_line_y += 1 - + return tile_map, tile_data; + def get_tile_map(self, mask): if (self.control & mask) != 0: return constants.VRAM_MAP_B From fijal at codespeak.net Mon Jun 9 18:58:00 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 18:58:00 +0200 (CEST) Subject: [pypy-svn] r55695 - pypy/dist/pypy/interpreter Message-ID: <20080609165800.3D773398005@codespeak.net> Author: fijal Date: Mon Jun 9 18:57:57 2008 New Revision: 55695 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: Small decluttering - don't get result which we never use Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Mon Jun 9 18:57:57 2008 @@ -6,9 +6,9 @@ return Stack() def app_profile_call(space, w_callable, frame, event, w_arg): - w_result = space.call_function(w_callable, - space.wrap(frame), - space.wrap(event), w_arg) + space.call_function(w_callable, + space.wrap(frame), + space.wrap(event), w_arg) class ExecutionContext: """An ExecutionContext holds the state of an execution thread From fijal at codespeak.net Mon Jun 9 18:59:04 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 18:59:04 +0200 (CEST) Subject: [pypy-svn] r55696 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080609165904.685BF398005@codespeak.net> Author: fijal Date: Mon Jun 9 18:59:03 2008 New Revision: 55696 Modified: pypy/dist/pypy/interpreter/pycode.py pypy/dist/pypy/interpreter/test/test_code.py pypy/dist/pypy/interpreter/typedef.py Log: Pycode.__repr__ Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Mon Jun 9 18:59:03 2008 @@ -393,3 +393,8 @@ #hidden_applevel=False, magic = 62061 | 0x0a0d0000 ] return space.newtuple([new_inst, space.newtuple(tup)]) + + def repr(self, space): + return space.wrap("" % ( + self.co_name, self.co_filename, self.co_firstlineno)) + repr.unwrap_spec = ['self', ObjSpace] Modified: pypy/dist/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_code.py (original) +++ pypy/dist/pypy/interpreter/test/test_code.py Mon Jun 9 18:59:03 2008 @@ -1,6 +1,16 @@ +from pypy.conftest import gettestobjspace +from pypy.interpreter import gateway +import py class AppTestCodeIntrospection: + def setup_class(cls): + space = gettestobjspace() + cls.space = space + if py.test.config.option.runappdirect: + cls.w_file = space.wrap(__file__[:-1]) + else: + cls.w_file = space.wrap("None<%s" % gateway.__file__[:-1]) def test_attributes(self): def f(): pass @@ -135,3 +145,14 @@ assert args == ['obj'] assert varargs is None assert varkw is None + + def test_repr(self): + def f(): + xxx + res = repr(f.func_code) + expected = [" Author: fijal Date: Mon Jun 9 19:01:00 2008 New Revision: 55697 Modified: pypy/dist/pypy/interpreter/test/test_code.py Log: Don't be too lazy - len can have or cannot have func_code depending on cpython version. Play on the safe side. Modified: pypy/dist/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_code.py (original) +++ pypy/dist/pypy/interpreter/test/test_code.py Mon Jun 9 19:01:00 2008 @@ -138,10 +138,10 @@ assert hash(d1['f'].func_code) == hash(d2['f'].func_code) def test_inspect(self): - if not hasattr(len, 'func_code'): - skip("CPython: no func_code attribute on built-in functions") + def f(obj): + pass import inspect - args, varargs, varkw = inspect.getargs(len.func_code) + args, varargs, varkw = inspect.getargs(f.func_code) assert args == ['obj'] assert varargs is None assert varkw is None From fijal at codespeak.net Mon Jun 9 19:09:34 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 19:09:34 +0200 (CEST) Subject: [pypy-svn] r55698 - pypy/dist/pypy/interpreter/test Message-ID: <20080609170934.F02B22A00DE@codespeak.net> Author: fijal Date: Mon Jun 9 19:09:34 2008 New Revision: 55698 Modified: pypy/dist/pypy/interpreter/test/test_code.py Log: Revert 55697, it was breaking test. Modified: pypy/dist/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_code.py (original) +++ pypy/dist/pypy/interpreter/test/test_code.py Mon Jun 9 19:09:34 2008 @@ -138,10 +138,10 @@ assert hash(d1['f'].func_code) == hash(d2['f'].func_code) def test_inspect(self): - def f(obj): - pass + if not hasattr(len, 'func_code'): + skip("Cannot run this test if builtins have no func_code") import inspect - args, varargs, varkw = inspect.getargs(f.func_code) + args, varargs, varkw = inspect.getargs(len.func_code) assert args == ['obj'] assert varargs is None assert varkw is None From fijal at codespeak.net Mon Jun 9 19:31:48 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 19:31:48 +0200 (CEST) Subject: [pypy-svn] r55699 - in pypy/dist/pypy/module/_lsprof: . test Message-ID: <20080609173148.2D23C2A0153@codespeak.net> Author: fijal Date: Mon Jun 9 19:31:47 2008 New Revision: 55699 Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py pypy/dist/pypy/module/_lsprof/test/test_cprofile.py Log: "Whack until it works". Make _lsprof module really working and adapt test good enough to resemble what it does. Modified: pypy/dist/pypy/module/_lsprof/interp_lsprof.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/interp_lsprof.py (original) +++ pypy/dist/pypy/module/_lsprof/interp_lsprof.py Mon Jun 9 19:31:47 2008 @@ -19,6 +19,17 @@ def get_calls(space, self): return self.w_calls + def repr(self, space): + frame_repr = space.str_w(space.repr(self.frame)) + if not self.w_calls: + calls_repr = "None" + else: + calls_repr = space.str_w(space.repr(self.w_calls)) + return space.wrap('("%s", %d, %d, %f, %f, %s)' % ( + frame_repr, self.callcount, self.reccallcount, + self.tt, self.it, calls_repr)) + repr.unwrap_spec = ['self', ObjSpace] + W_StatsEntry.typedef = TypeDef( 'StatsEntry', code = interp_attrproperty('frame', W_StatsEntry), @@ -27,6 +38,7 @@ inlinetime = interp_attrproperty('it', W_StatsEntry), totaltime = interp_attrproperty('tt', W_StatsEntry), calls = GetSetProperty(W_StatsEntry.get_calls), + __repr__ = interp2app(W_StatsEntry.repr), ) class W_StatsSubEntry(Wrappable): @@ -37,6 +49,12 @@ self.it = it self.tt = tt + def repr(self, space): + frame_repr = space.str_w(space.repr(self.frame)) + return space.wrap('("%s", %d, %d, %f, %f)' % ( + frame_repr, self.callcount, self.reccallcount, self.tt, self.it)) + repr.unwrap_spec = ['self', ObjSpace] + W_StatsSubEntry.typedef = TypeDef( 'SubStatsEntry', code = interp_attrproperty('frame', W_StatsSubEntry), @@ -44,6 +62,7 @@ reccallcount = interp_attrproperty('reccallcount', W_StatsSubEntry), inlinetime = interp_attrproperty('it', W_StatsSubEntry), totaltime = interp_attrproperty('tt', W_StatsSubEntry), + __repr__ = interp2app(W_StatsSubEntry.repr), ) def stats(space, data, factor): @@ -75,8 +94,8 @@ return space.wrap(w_se) class ProfilerSubEntry(object): - def __init__(self, caller): - # self.key = caller # XXX why? + def __init__(self, frame): + self.frame = frame self.tt = 0 self.it = 0 self.callcount = 0 @@ -84,7 +103,7 @@ self.recursionLevel = 0 def stats(self, space, parent, factor): - w_sse = W_StatsSubEntry(space, parent.frame, + w_sse = W_StatsSubEntry(space, self.frame, self.callcount, self.recursivecallcount, factor * self.tt, factor * self.it) return space.wrap(w_sse) @@ -96,8 +115,12 @@ self.previous = profobj.current_context entry.recursionLevel += 1 if profobj.subcalls and self.previous: - subentry = ProfilerSubEntry(entry) - entry.calls[entry] = subentry + caller = self.previous.entry + try: + subentry = caller.calls[entry] + except KeyError: + subentry = ProfilerSubEntry(entry.frame) + caller.calls[entry] = subentry subentry.recursionLevel += 1 self.t0 = profobj.timer() Modified: pypy/dist/pypy/module/_lsprof/test/test_cprofile.py ============================================================================== --- pypy/dist/pypy/module/_lsprof/test/test_cprofile.py (original) +++ pypy/dist/pypy/module/_lsprof/test/test_cprofile.py Mon Jun 9 19:31:47 2008 @@ -1,4 +1,5 @@ +import py from pypy.conftest import gettestobjspace class AppTestCProfile(object): @@ -6,11 +7,13 @@ space = gettestobjspace(usemodules=('_lsprof',)) cls.w_expected_output = space.wrap(expected_output) cls.space = space + cls.w_file = space.wrap(__file__) def test_cprofile(self): - skip("fails") import sys, os - sys.path.insert(0, os.path.dirname(__file__)) + # XXX this is evil trickery to walk around the fact that we don't + # have __file__ at app-level here + sys.path.insert(0, os.path.dirname(self.file)) try: from cProfile import Profile from profilee import testfunc, timer @@ -31,15 +34,24 @@ stats.strip_dirs().sort_stats("stdname") getattr(stats, methodname)() results.append(s.getvalue()) - return results + return results, prof - res = do_profiling(Profile) + res, prof = do_profiling(Profile) assert res[0] == 1000 for i, method in enumerate(methodnames): if not res[i + 1] == self.expected_output[method]: print method print res[i + 1] print self.expected_output[method] + one = res[i + 1].split("\n") + two = self.expected_output[method].split("\n") + for k in range(len(res[i + 1])): + if one[k] != two[k]: + print k + print one[k] + print two[k] + import pdb + pdb.set_trace() assert 0 #assert res[i + 1] == self.expected_output[method] finally: @@ -47,6 +59,79 @@ expected_output = {} expected_output['print_stats'] = """\ + 98 function calls (78 primitive calls) in 1.000 CPU seconds + + Ordered by: standard name + + ncalls tottime percall cumtime percall filename:lineno(function) + 1 0.000 0.000 1.000 1.000 :0() + 1 0.000 0.000 0.000 0.000 ?:1() + 28 0.028 0.001 0.028 0.001 profilee.py:110(__getattr__) + 1 0.270 0.270 1.000 1.000 profilee.py:25(testfunc) + 23/3 0.150 0.007 0.170 0.057 profilee.py:35(factorial) + 20 0.020 0.001 0.020 0.001 profilee.py:48(mul) + 2 0.040 0.020 0.600 0.300 profilee.py:55(helper) + 4 0.116 0.029 0.120 0.030 profilee.py:73(helper1) + 2 0.000 0.000 0.140 0.070 profilee.py:84(helper2_indirect) + 8 0.312 0.039 0.400 0.050 profilee.py:88(helper2) + 8 0.064 0.008 0.080 0.010 profilee.py:98(subhelper) + + +""" +expected_output['print_callers'] = """\ + Ordered by: standard name + +Function was called by... + ncalls tottime cumtime +:0() <- +?:1() <- +profilee.py:110(__getattr__) <- 4 0.004 0.004 profilee.py:73(helper1) + 8 0.008 0.008 profilee.py:88(helper2) + 16 0.016 0.016 profilee.py:98(subhelper) +profilee.py:25(testfunc) <- 1 0.270 1.000 :0() +profilee.py:35(factorial) <- 1 0.014 0.130 profilee.py:25(testfunc) + 20/3 0.130 0.147 profilee.py:35(factorial) + 2 0.006 0.040 profilee.py:84(helper2_indirect) +profilee.py:48(mul) <- 20 0.020 0.020 profilee.py:35(factorial) +profilee.py:55(helper) <- 2 0.040 0.600 profilee.py:25(testfunc) +profilee.py:73(helper1) <- 4 0.116 0.120 profilee.py:55(helper) +profilee.py:84(helper2_indirect) <- 2 0.000 0.140 profilee.py:55(helper) +profilee.py:88(helper2) <- 6 0.234 0.300 profilee.py:55(helper) + 2 0.078 0.100 profilee.py:84(helper2_indirect) +profilee.py:98(subhelper) <- 8 0.064 0.080 profilee.py:88(helper2) + + +""" +expected_output['print_callees'] = """\ + Ordered by: standard name + +Function called... + ncalls tottime cumtime +:0() -> 1 0.270 1.000 profilee.py:25(testfunc) +?:1() -> +profilee.py:110(__getattr__) -> +profilee.py:25(testfunc) -> 1 0.014 0.130 profilee.py:35(factorial) + 2 0.040 0.600 profilee.py:55(helper) +profilee.py:35(factorial) -> 20/3 0.130 0.147 profilee.py:35(factorial) + 20 0.020 0.020 profilee.py:48(mul) +profilee.py:48(mul) -> +profilee.py:55(helper) -> 4 0.116 0.120 profilee.py:73(helper1) + 2 0.000 0.140 profilee.py:84(helper2_indirect) + 6 0.234 0.300 profilee.py:88(helper2) +profilee.py:73(helper1) -> 4 0.004 0.004 profilee.py:110(__getattr__) +profilee.py:84(helper2_indirect) -> 2 0.006 0.040 profilee.py:35(factorial) + 2 0.078 0.100 profilee.py:88(helper2) +profilee.py:88(helper2) -> 8 0.064 0.080 profilee.py:98(subhelper) + 8 0.008 0.008 profilee.py:110(__getattr__) +profilee.py:98(subhelper) -> 16 0.016 0.016 profilee.py:110(__getattr__) + + +""" + +# this is how stuff would look like if we trace built-in calls + +real_expected_output = {} +real_expected_output['print_stats'] = """\ 126 function calls (106 primitive calls) in 1.000 CPU seconds Ordered by: standard name @@ -70,7 +155,7 @@ """ -expected_output['print_callers'] = """\ +real_expected_output['print_callers'] = """\ Ordered by: standard name Function was called by... @@ -98,7 +183,7 @@ """ -expected_output['print_callees'] = """\ +real_expected_output['print_callees'] = """\ Ordered by: standard name Function called... From fijal at codespeak.net Mon Jun 9 19:34:42 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 19:34:42 +0200 (CEST) Subject: [pypy-svn] r55700 - pypy/dist/pypy/doc/config Message-ID: <20080609173442.5181C2A0183@codespeak.net> Author: fijal Date: Mon Jun 9 19:34:41 2008 New Revision: 55700 Removed: pypy/dist/pypy/doc/config/translation.backendopt.coalloc.txt Log: This option is gone From fijal at codespeak.net Mon Jun 9 19:59:28 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 19:59:28 +0200 (CEST) Subject: [pypy-svn] r55705 - pypy/dist/pypy/config Message-ID: <20080609175928.AF225169EBB@codespeak.net> Author: fijal Date: Mon Jun 9 19:59:26 2008 New Revision: 55705 Modified: pypy/dist/pypy/config/pypyoption.py Log: Add _lsprof to allworkingmodules Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Mon Jun 9 19:59:26 2008 @@ -21,10 +21,11 @@ "recparser", "symbol", "_random", "__pypy__"])) +# --allworkingmodules working_modules = default_modules.copy() working_modules.update(dict.fromkeys( ["_socket", "unicodedata", "mmap", "fcntl", - "rctime" , "select", "zipimport", + "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "dyngram", "_rawffi", "termios", "zlib", "struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO"] )) From cami at codespeak.net Mon Jun 9 20:08:49 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Mon, 9 Jun 2008 20:08:49 +0200 (CEST) Subject: [pypy-svn] r55706 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080609180849.BC76D169EC5@codespeak.net> Author: cami Date: Mon Jun 9 20:08:49 2008 New Revision: 55706 Modified: pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/gameboy_implementation.py pypy/dist/pypy/lang/gameboy/test/test_cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Log: added debug logger added explicit load test to control the opcodes Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Mon Jun 9 20:08:49 2008 @@ -2,6 +2,7 @@ from pypy.lang.gameboy import constants from pypy.lang.gameboy.ram import * from pypy.lang.gameboy.interrupt import * +from pypy.lang.gameboy.debug import * # --------------------------------------------------------------------------- @@ -356,14 +357,17 @@ def handle_pending_interrupts(self): if self.halted: - if self.interrupt.is_pending(): - self.halted = False - self.cycles -= 4 - elif (self.cycles > 0): - self.cycles = 0 + self.update_interrupt_cycles() if self.ime and self.interrupt.is_pending(): self.lower_pending_interrupt() + def update_interrupt_cycles(self): + if self.interrupt.is_pending(): + self.halted = False + self.cycles -= 4 + elif (self.cycles > 0): + self.cycles = 0 + def lower_pending_interrupt(self): for flag in self.interrupt.interrupt_flags: if flag.is_pending(): @@ -377,11 +381,13 @@ #print " fetch exe:", hex(opCode), " " #, FETCH_EXECUTE_OP_CODES[opCode].__name__ self.last_fetch_execute_op_code = opCode + if DEBUG: log(opCode, is_fetch_execute=True) FETCH_EXECUTE_OP_CODES[opCode](self) def execute(self, opCode): self.instruction_counter += 1 + if DEBUG: log(opCode) #print self.instruction_counter, "-"*60 #print "exe: ", hex(opCode), " " #, OP_CODES[opCode].__name__ @@ -1069,7 +1075,7 @@ # OPCODE TABLES --------------------------------------------------------------- # Table with one to one mapping of simple OP Codes -FIRST_or_aDER_OP_CODES = [ +FIRST_ORDER_OP_CODES = [ (0x00, CPU.nop), (0x08, CPU.load_mem_sp), (0x10, CPU.stop), @@ -1109,14 +1115,14 @@ (0xF8, CPU.store_fetch_added_sp_in_hl), (0xCB, CPU.fetch_execute), (0xCD, CPU.unconditional_call), - (0xC6, lambda s: CPU.add_a(s, CPUFetchCaller(s))), + (0xC6, lambda s: CPU.add_a(s, CPUFetchCaller(s))), (0xCE, lambda s: CPU.add_a_with_carry(s, CPUFetchCaller(s))), (0xD6, CPU.fetch_subtract_a), (0xDE, lambda s: CPU.subtract_with_carry_a(s, CPUFetchCaller(s))), (0xE6, lambda s: CPU.and_a(s, CPUFetchCaller(s))), (0xEE, lambda s: CPU.xor_a(s, CPUFetchCaller(s))), (0xF6, lambda s: CPU.or_a(s, CPUFetchCaller(s))), - (0xFE, lambda s: CPU.compare_a(s, CPUFetchCaller(s))), + (0xFE, lambda s: CPU.compare_a(s, CPUFetchCaller(s))), (0xC7, lambda s: CPU.restart(s, 0x00)), (0xCF, lambda s: CPU.restart(s, 0x08)), (0xD7, lambda s: CPU.restart(s, 0x10)), @@ -1144,9 +1150,9 @@ ] -REGISTER_SET_A = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_sp] -REGISTER_SET_B = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_af] -FLAG_REGISTER_SET = [CPU.is_not_z, CPU.is_z, CPU.is_not_c, CPU.is_c] +REGISTER_SET_A = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_sp] +REGISTER_SET_B = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_af] +FLAG_REGISTER_SET = [CPU.is_not_z, CPU.is_z, CPU.is_not_c, CPU.is_c] # Table for Register OP Codes: (startAddress, delta, method, regsiters) REGISTER_OP_CODES = [ @@ -1162,7 +1168,7 @@ (0xC5, 0x10, CPU.push_double_register, REGISTER_SET_B) ] # Table for Second Order OPCodes: (startAddress, delta, method, [args]) -SECOND_or_aDER_REGISTER_GROUP_OP_CODES = [ +SECOND_ORDER_REGISTER_GROUP_OP_CODES = [ (0x00, 0x01, CPU.rotate_left_circular), (0x08, 0x01, CPU.rotate_right_circular), (0x10, 0x01, CPU.rotate_left), @@ -1178,11 +1184,12 @@ # RAW OPCODE TABLE INITIALIZATION ---------------------------------------------- -FIRST_or_aDER_OP_CODES += create_register_op_codes(REGISTER_OP_CODES) -FIRST_or_aDER_OP_CODES += create_group_op_codes(REGISTER_GROUP_OP_CODES) -FIRST_or_aDER_OP_CODES += create_load_group_op_codes() -SECOND_or_aDER_OP_CODES = create_group_op_codes(SECOND_or_aDER_REGISTER_GROUP_OP_CODES) +FIRST_ORDER_OP_CODES += create_register_op_codes(REGISTER_OP_CODES) +FIRST_ORDER_OP_CODES += create_group_op_codes(REGISTER_GROUP_OP_CODES) +FIRST_ORDER_OP_CODES += create_load_group_op_codes() +SECOND_ORDER_OP_CODES = create_group_op_codes(SECOND_ORDER_REGISTER_GROUP_OP_CODES) + +OP_CODES = initialize_op_code_table(FIRST_ORDER_OP_CODES) +FETCH_EXECUTE_OP_CODES = initialize_op_code_table(SECOND_ORDER_OP_CODES) -OP_CODES = initialize_op_code_table(FIRST_or_aDER_OP_CODES) -FETCH_EXECUTE_OP_CODES = initialize_op_code_table(SECOND_or_aDER_OP_CODES) Modified: pypy/dist/pypy/lang/gameboy/gameboy_implementation.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/gameboy_implementation.py (original) +++ pypy/dist/pypy/lang/gameboy/gameboy_implementation.py Mon Jun 9 20:08:49 2008 @@ -6,6 +6,7 @@ from pypy.lang.gameboy.sound import SoundDriver from pypy.lang.gameboy.timer import Clock from pypy.lang.gameboy import constants +from pypy.lang.gameboy import debug from pypy.rlib.rsdl import RSDL, RSDL_helper from pypy.rpython.lltypesystem import lltype, rffi @@ -40,6 +41,7 @@ finally: lltype.free(self.event, flavor='raw') RSDL.Quit() + debug.print_results() return 0 def handle_events(self): @@ -91,7 +93,8 @@ #if y%2 == 0 or True: # px = self.get_pixel_color(x, y) # str += ["#", "%", "+", " ", " "][px] - RSDL_helper.set_pixel(self.screen, x, y, self.pixel_map(x, y)) + #RSDL_helper.set_pixel(self.screen, x, y, self.pixel_map(x, y)) + pass #print str; def pixel_map(self, x, y): Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu.py Mon Jun 9 20:08:49 2008 @@ -477,7 +477,7 @@ set_registers(registers, 0) registers[i].set(value) cycle_test(cpu, opCode, 2); - assert registers[i].get() == value +1 + assert registers[i].get() == value + 1 cpu.reset() opCode += 0x10 value += 3 @@ -492,7 +492,7 @@ set_registers(registers, 0) registers[i].set(value) cycle_test(cpu, opCode, 2); - assert registers[i].get() == value-1 + assert registers[i].get() == value - 1 cpu.reset() cpu.reset() opCode += 0x10 @@ -612,10 +612,11 @@ prepare_for_fetch(cpu, value) cycle_test(cpu, opCode, 2) assert registers[i].get() == value + # one fetch assert cpu.pc.get() - oldPC == 1 cpu.reset() opCode += 0x08 - value += 3 + value += 3 # ld_HLi_nn def test_0x36(): @@ -782,8 +783,8 @@ if register == cpu.a: assert cpu.a.get() == 2*value else: - assert cpu.a.get() == valueA+value - value += 3 + assert cpu.a.get() == valueA + value + value += 3 opCode += 0x01 # adc_A_B to adx_A_A @@ -869,7 +870,7 @@ opCode += 0x01 # and_A_B to and_A_A -def test_0xA0_to_0xA7(): +def test_0xA0_to_0xA7_and_a(): cpu = get_cpu() opCode = 0xA0 value = 0x12 @@ -956,7 +957,7 @@ opCode += 0x01 # ret_NZ to ret_C -def test_0xC0(): +def test_0xC0_to_0xD8_return_on_condition(): cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC0 @@ -1010,7 +1011,7 @@ assert cpu.a.get() == value # ld_A_mem -def test_0xFA(): +def test_0xFA_store_fetched_memory_in_a(): cpu = get_cpu() value = 0x11 valueA = 0x12 @@ -1119,18 +1120,20 @@ assert cpu.pop() == 0x12 # ld_PC_HL -def test_0xE9(): +def test_0xE9_store_hl_in_pc(): cpu = get_cpu() value = 0x1234 cpu.hl.set(value) + cpu.pc.set(0) cycle_test(cpu, 0xE9, 1) assert_default_registers(cpu, pc=value, hl=value) # ld_SP_HL -def test_0xF9(): +def test_0xF9_store_hl_in_sp(): cpu = get_cpu() value = 0x1234 cpu.hl.set(value) + cpu.sp.set(0) cycle_test(cpu, 0xF9, 2) assert_default_registers(cpu, sp=value, hl=value) @@ -1361,7 +1364,7 @@ assert cpu.f.z_flag == True # rst(0x00) to rst(0x38) -def test_0xC7_to_0xFF(): +def test_0xC7_to_0xFF_reset(): cpu = get_cpu() opCode = 0xC7 rstValue = 0x00 @@ -1369,10 +1372,10 @@ cpu.reset() cpu.pc.set(0x1234) cycle_test(cpu, opCode, 4) - assert cpu.pop() == 0x34 + assert cpu.pop() == 0x34 assert cpu.pop() == 0x12 assert cpu.pc.get() == rstValue - opCode += 0x08 + opCode += 0x08 rstValue += 0x08 # switching to other opcode set @@ -1472,6 +1475,9 @@ if register == cpu.hli: cycles = 4 cpu.reset() + if registerOpCode ==0xFF: + print "6544444444444444" + register.set(0) fetch_execute_cycle_test_second_order(cpu, registerOpCode, cycles) assert (register.get() & (1<> i == 1 @@ -1506,6 +1512,127 @@ opCode += 1 +# LOAD TEST ----------------------------------------------------------------- +# just for double checking ;) +def load_test(cpu, test_set): + value = 0 + for test in test_set: + opCode = test[0] + reg_write = test[1] + reg_read = test[2] + value = 1 + (value + 1) & 0xFE + reg_write.set(0) + reg_read.set(value) + cpu.execute(opCode) + assert reg_write.get() == reg_read.get(), hex(opCode)+" load failed!" + + +def test_load_b(): + cpu = get_cpu() + read_register = cpu.b + load_test(cpu, + [(0x40, read_register, cpu.b), + (0x41, read_register, cpu.c), + (0x42, read_register, cpu.d), + (0x43, read_register, cpu.e), + (0x44, read_register, cpu.h), + (0x45, read_register, cpu.l), + #(0x46, read_register, cpu.hli), + (0x47, read_register, cpu.a)]) + +def test_load_c(): + cpu = get_cpu() + read_register = cpu.c + load_test(cpu, + [(0x48, read_register, cpu.b), + (0x49, read_register, cpu.c), + (0x4A, read_register, cpu.d), + (0x4B, read_register, cpu.e), + (0x4C, read_register, cpu.h), + (0x4D, read_register, cpu.l), + #(0x4E, read_register, cpu.hli), + (0x4F, read_register, cpu.a)]) + + +def test_load_d(): + cpu = get_cpu() + read_register = cpu.d + load_test(cpu, + [(0x50, read_register, cpu.b), + (0x51, read_register, cpu.c), + (0x52, read_register, cpu.d), + (0x53, read_register, cpu.e), + (0x54, read_register, cpu.h), + (0x55, read_register, cpu.l), + # (0x56, read_register, cpu.hli), + (0x57, read_register, cpu.a)]) + +def test_load_e(): + cpu = get_cpu() + read_register = cpu.e + load_test(cpu, + [(0x58, read_register, cpu.b), + (0x59, read_register, cpu.c), + (0x5A, read_register, cpu.d), + (0x5B, read_register, cpu.e), + (0x5C, read_register, cpu.h), + (0x5D, read_register, cpu.l), + #(0x5E, read_register, cpu.hli), + (0x5F, read_register, cpu.a)]) + +def test_load_h(): + cpu = get_cpu() + read_register = cpu.h + load_test(cpu, + [(0x60, read_register, cpu.b), + (0x61, read_register, cpu.c), + (0x62, read_register, cpu.d), + (0x63, read_register, cpu.e), + (0x64, read_register, cpu.h), + (0x65, read_register, cpu.l), + #(0x66, read_register, cpu.hli), + (0x67, read_register, cpu.a)]) + +def test_load_l(): + cpu = get_cpu() + read_register = cpu.l + load_test(cpu, + [(0x68, read_register, cpu.b), + (0x69, read_register, cpu.c), + (0x6A, read_register, cpu.d), + (0x6B, read_register, cpu.e), + (0x6C, read_register, cpu.h), + (0x6D, read_register, cpu.l), + #(0x6E, read_register, cpu.hli), + (0x6F, read_register, cpu.a)]) + +def test_load_hli(): + cpu = get_cpu() + read_register = cpu.hli + load_test(cpu, + [(0x70, read_register, cpu.b), + (0x71, read_register, cpu.c), + (0x72, read_register, cpu.d), + (0x73, read_register, cpu.e), + (0x74, read_register, cpu.h), + (0x75, read_register, cpu.l), + (0x77, read_register, cpu.a)]) + +def test_load_a(): + cpu = get_cpu() + read_register = cpu.a + load_test(cpu, + [(0x78, read_register, cpu.b), + (0x79, read_register, cpu.c), + (0x7A, read_register, cpu.d), + (0x7B, read_register, cpu.e), + (0x7C, read_register, cpu.h), + (0x7D, read_register, cpu.l), + #(0x7E, read_register, cpu.hli), + (0x7F, read_register, cpu.a)]) + + + \ No newline at end of file Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Mon Jun 9 20:08:49 2008 @@ -123,7 +123,7 @@ # Tests ----------------------------------------------------------------------- -def test_add_a_with_carry(): +def test_pa_with_carry(): cpu = get_cpu() cpu.f.set(0xFF) cpu.a.set(0x00) @@ -238,6 +238,12 @@ method_value_call(cpu, CPU.and_a, 0x12) assert cpu.a.get() == 0x12 assert_flags(cpu, z=False, n=False, h=True, c=False) + + cpu.f.set(0x00) + cpu.a.set(0xFF) + method_value_call(cpu, CPU.and_a, 0x12) + assert cpu.a.get() == 0x12 + assert_flags(cpu, z=False, n=False, h=True, c=False) def test_or_a(): cpu = get_cpu() From fijal at codespeak.net Mon Jun 9 20:51:23 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 20:51:23 +0200 (CEST) Subject: [pypy-svn] r55708 - pypy/branch/parser-complexity Message-ID: <20080609185123.4A4D4169FA7@codespeak.net> Author: fijal Date: Mon Jun 9 20:51:22 2008 New Revision: 55708 Removed: pypy/branch/parser-complexity/ Log: Anything that happened on this branch was merged From fijal at codespeak.net Mon Jun 9 20:52:44 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 20:52:44 +0200 (CEST) Subject: [pypy-svn] r55709 - pypy/branch/faster-ctypes Message-ID: <20080609185244.16C1E169FAA@codespeak.net> Author: fijal Date: Mon Jun 9 20:52:43 2008 New Revision: 55709 Added: pypy/branch/faster-ctypes/ - copied from r55708, pypy/dist/ Log: A branch to experiment with more-rpython based ctypes From fijal at codespeak.net Mon Jun 9 22:58:19 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 9 Jun 2008 22:58:19 +0200 (CEST) Subject: [pypy-svn] r55721 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080609205819.23E632A0183@codespeak.net> Author: fijal Date: Mon Jun 9 22:58:18 2008 New Revision: 55721 Modified: pypy/dist/pypy/interpreter/function.py pypy/dist/pypy/interpreter/test/test_function.py Log: Allow func.func_defaults = None Modified: pypy/dist/pypy/interpreter/function.py ============================================================================== --- pypy/dist/pypy/interpreter/function.py (original) +++ pypy/dist/pypy/interpreter/function.py Mon Jun 9 22:58:18 2008 @@ -230,8 +230,11 @@ return space.newtuple(values_w) def fset_func_defaults(space, self, w_defaults): + if space.is_w(w_defaults, space.w_None): + self.defs_w = [] + return if not space.is_true( space.isinstance( w_defaults, space.w_tuple ) ): - raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object") ) + raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object or None") ) self.defs_w = space.unpackiterable( w_defaults ) def fdel_func_defaults(space, self): Modified: pypy/dist/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_function.py (original) +++ pypy/dist/pypy/interpreter/test/test_function.py Mon Jun 9 22:58:18 2008 @@ -11,6 +11,8 @@ def f(): pass assert hasattr(f, 'func_code') assert f.func_defaults == None + f.func_defaults = None + assert f.func_defaults == None assert f.func_dict == {} assert type(f.func_globals) == dict #self.assertEquals(f.func_closure, None) XXX From fijal at codespeak.net Tue Jun 10 06:49:33 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 10 Jun 2008 06:49:33 +0200 (CEST) Subject: [pypy-svn] r55726 - pypy/dist/pypy/interpreter/astcompiler Message-ID: <20080610044933.9C2EB169E37@codespeak.net> Author: fijal Date: Tue Jun 10 06:49:31 2008 New Revision: 55726 Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Log: Behave *exactly* like cpython. This broke some stuff and people rely on it. For record: http://morepypy.blogspot.com/2008/06/list-comprehension-implementation.html Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Tue Jun 10 06:49:31 2008 @@ -596,7 +596,7 @@ def visitListComp(self, node): self.set_lineno(node) # setup list - tmpname = "$list%d" % self.__list_count + tmpname = "_[%d]" % self.__list_count self.__list_count = self.__list_count + 1 self.emitop_int('BUILD_LIST', 0) self.emit('DUP_TOP') From fijal at codespeak.net Tue Jun 10 07:22:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 10 Jun 2008 07:22:31 +0200 (CEST) Subject: [pypy-svn] r55728 - pypy/dist/pypy/objspace/std/test Message-ID: <20080610052231.431AF169F9E@codespeak.net> Author: fijal Date: Tue Jun 10 07:22:30 2008 New Revision: 55728 Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py Log: Some obscure test. People rely on this. Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_userobject.py Tue Jun 10 07:22:30 2008 @@ -207,6 +207,11 @@ s = repr(Foo()) assert s.startswith(' Author: afa Date: Tue Jun 10 09:27:57 2008 New Revision: 55729 Modified: pypy/branch/build-external/ (props changed) Log: Initialized merge tracking via "svnmerge" with revisions "1-55321" from https://codespeak.net/svn/pypy/dist From cfbolz at codespeak.net Tue Jun 10 11:08:56 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 10 Jun 2008 11:08:56 +0200 (CEST) Subject: [pypy-svn] r55730 - in pypy/dist/pypy/interpreter: astcompiler test Message-ID: <20080610090856.551522A0183@codespeak.net> Author: cfbolz Date: Tue Jun 10 11:08:54 2008 New Revision: 55730 Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/test/test_interpreter.py Log: be _completely_ compatible with CPython and start numbering with 1. Write a test for the behaviour Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Tue Jun 10 11:08:54 2008 @@ -596,8 +596,8 @@ def visitListComp(self, node): self.set_lineno(node) # setup list - tmpname = "_[%d]" % self.__list_count self.__list_count = self.__list_count + 1 + tmpname = "_[%d]" % self.__list_count self.emitop_int('BUILD_LIST', 0) self.emit('DUP_TOP') self._implicitNameOp('STORE', tmpname) Modified: pypy/dist/pypy/interpreter/test/test_interpreter.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_interpreter.py (original) +++ pypy/dist/pypy/interpreter/test/test_interpreter.py Tue Jun 10 11:08:54 2008 @@ -231,6 +231,13 @@ assert self.codetest(code, 'g', [12, {}]) == () assert self.codetest(code, 'g', [12, {3:1}]) == (3,) + def test_list_comprehension(self): + code = ''' + def f(): + return [dir() for i in [1]][0] + ''' + assert self.codetest(code, 'f', [])[0] == '_[1]' + class TestPyPyInterpreter(TestInterpreter): """Runs the previous test with the pypy parser""" From arigo at codespeak.net Tue Jun 10 12:11:00 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 10 Jun 2008 12:11:00 +0200 (CEST) Subject: [pypy-svn] r55731 - pypy/dist/pypy/doc Message-ID: <20080610101100.221B4169F0C@codespeak.net> Author: arigo Date: Tue Jun 10 12:10:59 2008 New Revision: 55731 Modified: pypy/dist/pypy/doc/translation.txt Log: Update. Modified: pypy/dist/pypy/doc/translation.txt ============================================================================== --- pypy/dist/pypy/doc/translation.txt (original) +++ pypy/dist/pypy/doc/translation.txt Tue Jun 10 12:10:59 2008 @@ -644,19 +644,16 @@ must be made. In keeping with PyPy's approach to flexibility, there is freedom to change how to do it. There are three approaches implemented today: - - reference counting + - reference counting (deprecated, too slow) - using the `Boehm-Demers-Weiser conservative garbage collector`_ - - using a mark and sweep collector implemented in RPython + - using one of our custom `exact GCs implemented in RPython`_ .. _`Boehm-Demers-Weiser conservative garbage collector`: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ +.. _`exact GCs implemented in RPython`: garbage_collection.html Almost all application-level Python code allocates objects at a very fast -rate; this means that the memory management implementation is critical too the -performance of the PyPy interpreter. That said, work so far has many focussed -on flexibility and robustness, not performance. - -For a quite detailed description of how memory management and garbage collection -are performed in PyPy, see the `Technical report`_ about this topic (section 4.2). +rate; this means that the memory management implementation is critical to the +performance of the PyPy interpreter. You can choose which garbage collection strategy to use with :config:`translation.gc`. From afa at codespeak.net Tue Jun 10 12:48:53 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 10 Jun 2008 12:48:53 +0200 (CEST) Subject: [pypy-svn] r55732 - in pypy/branch/build-external/pypy: config doc doc/config doc/discussion interpreter interpreter/astcompiler interpreter/test lang/gameboy lang/gameboy/test lang/smalltalk lang/smalltalk/test lang/smalltalk/tool lib lib/app_test lib/test2 module/__builtin__ module/__builtin__/test module/__pypy__ module/_file module/_lsprof module/_lsprof/test module/_rawffi/test module/gc module/signal module/sys module/thread module/thread/test module/zipimport module/zipimport/test objspace objspace/flow objspace/std objspace/std/test rlib rlib/rstruct rlib/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory rpython/memory/gctransform rpython/module rpython/ootypesystem rpython/test rpython/tool rpython/tool/test tool tool/test translator/backendopt translator/backendopt/test translator/c translator/c/src translator/c/test translator/goal translator/goal/test2 translator/tool translator/tool/test Message-ID: <20080610104853.B1F23169F02@codespeak.net> Author: afa Date: Tue Jun 10 12:48:46 2008 New Revision: 55732 Added: pypy/branch/build-external/pypy/doc/config/objspace.usemodules._lsprof.txt - copied unchanged from r55728, pypy/dist/pypy/doc/config/objspace.usemodules._lsprof.txt pypy/branch/build-external/pypy/lang/gameboy/gameboy_implementation.py - copied unchanged from r55728, pypy/dist/pypy/lang/gameboy/gameboy_implementation.py pypy/branch/build-external/pypy/lang/gameboy/test/test_cpu_2.py - copied unchanged from r55728, pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py pypy/branch/build-external/pypy/lang/gameboy/test/test_gameboy_implementaton.py - copied unchanged from r55728, pypy/dist/pypy/lang/gameboy/test/test_gameboy_implementaton.py pypy/branch/build-external/pypy/lang/smalltalk/objspace.py - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/objspace.py pypy/branch/build-external/pypy/lang/smalltalk/running-something-mini.image - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/running-something-mini.image pypy/branch/build-external/pypy/lang/smalltalk/test/test_objectspace.py - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/test/test_objectspace.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_wrapper.py - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/test/test_wrapper.py pypy/branch/build-external/pypy/lang/smalltalk/todo.txt - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/todo.txt pypy/branch/build-external/pypy/lang/smalltalk/tool/infostats.py - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/tool/infostats.py pypy/branch/build-external/pypy/lang/smalltalk/tool/profile.sh - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/tool/profile.sh pypy/branch/build-external/pypy/lang/smalltalk/wrapper.py - copied unchanged from r55728, pypy/dist/pypy/lang/smalltalk/wrapper.py pypy/branch/build-external/pypy/lib/py - copied unchanged from r55728, pypy/dist/pypy/lib/py pypy/branch/build-external/pypy/module/_lsprof/ (props changed) - copied from r55728, pypy/dist/pypy/module/_lsprof/ pypy/branch/build-external/pypy/module/_lsprof/__init__.py - copied unchanged from r55728, pypy/dist/pypy/module/_lsprof/__init__.py pypy/branch/build-external/pypy/module/_lsprof/interp_lsprof.py - copied unchanged from r55728, pypy/dist/pypy/module/_lsprof/interp_lsprof.py pypy/branch/build-external/pypy/module/_lsprof/test/ (props changed) - copied from r55728, pypy/dist/pypy/module/_lsprof/test/ pypy/branch/build-external/pypy/module/_lsprof/test/__init__.py - copied unchanged from r55728, pypy/dist/pypy/module/_lsprof/test/__init__.py pypy/branch/build-external/pypy/module/_lsprof/test/profilee.py - copied unchanged from r55728, pypy/dist/pypy/module/_lsprof/test/profilee.py pypy/branch/build-external/pypy/module/_lsprof/test/test_cprofile.py - copied unchanged from r55728, pypy/dist/pypy/module/_lsprof/test/test_cprofile.py pypy/branch/build-external/pypy/module/thread/test/test_gil.py - copied unchanged from r55728, pypy/dist/pypy/module/thread/test/test_gil.py pypy/branch/build-external/pypy/translator/goal/runpystone.py - copied unchanged from r55728, pypy/dist/pypy/translator/goal/runpystone.py Removed: pypy/branch/build-external/pypy/doc/config/translation.backendopt.coalloc.txt pypy/branch/build-external/pypy/doc/discussion/standalone-howto.txt pypy/branch/build-external/pypy/lang/gameboy/gameboyImplementation.py pypy/branch/build-external/pypy/lang/smalltalk/classtable.py pypy/branch/build-external/pypy/lang/smalltalk/objtable.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_classtable.py pypy/branch/build-external/pypy/lang/smalltalk/utility.py pypy/branch/build-external/pypy/translator/goal/targetgcbench2.py Modified: pypy/branch/build-external/pypy/config/config.py pypy/branch/build-external/pypy/config/pypyoption.py pypy/branch/build-external/pypy/config/translationoption.py pypy/branch/build-external/pypy/doc/_ref.txt pypy/branch/build-external/pypy/doc/cpython_differences.txt pypy/branch/build-external/pypy/doc/download.txt pypy/branch/build-external/pypy/doc/faq.txt pypy/branch/build-external/pypy/doc/getting-started.txt pypy/branch/build-external/pypy/doc/index.txt pypy/branch/build-external/pypy/doc/redirections pypy/branch/build-external/pypy/interpreter/astcompiler/misc.py pypy/branch/build-external/pypy/interpreter/astcompiler/pycodegen.py pypy/branch/build-external/pypy/interpreter/executioncontext.py pypy/branch/build-external/pypy/interpreter/function.py pypy/branch/build-external/pypy/interpreter/gateway.py pypy/branch/build-external/pypy/interpreter/miscutils.py pypy/branch/build-external/pypy/interpreter/pycode.py pypy/branch/build-external/pypy/interpreter/test/test_code.py pypy/branch/build-external/pypy/interpreter/test/test_executioncontext.py pypy/branch/build-external/pypy/interpreter/test/test_function.py pypy/branch/build-external/pypy/interpreter/test/test_gateway.py pypy/branch/build-external/pypy/interpreter/typedef.py pypy/branch/build-external/pypy/lang/gameboy/cartridge.py pypy/branch/build-external/pypy/lang/gameboy/constants.py pypy/branch/build-external/pypy/lang/gameboy/cpu.py pypy/branch/build-external/pypy/lang/gameboy/gameboy.py pypy/branch/build-external/pypy/lang/gameboy/gameboyTest.py pypy/branch/build-external/pypy/lang/gameboy/interrupt.py pypy/branch/build-external/pypy/lang/gameboy/joypad.py pypy/branch/build-external/pypy/lang/gameboy/ram.py pypy/branch/build-external/pypy/lang/gameboy/serial.py pypy/branch/build-external/pypy/lang/gameboy/sound.py pypy/branch/build-external/pypy/lang/gameboy/test/test_cartridge.py pypy/branch/build-external/pypy/lang/gameboy/test/test_cpu.py pypy/branch/build-external/pypy/lang/gameboy/test/test_interrupt.py pypy/branch/build-external/pypy/lang/gameboy/test/test_joypad.py pypy/branch/build-external/pypy/lang/gameboy/test/test_memory_bank_controller.py pypy/branch/build-external/pypy/lang/gameboy/test/test_ram.py pypy/branch/build-external/pypy/lang/gameboy/test/test_serial.py pypy/branch/build-external/pypy/lang/gameboy/test/test_timer.py pypy/branch/build-external/pypy/lang/gameboy/test/test_video.py pypy/branch/build-external/pypy/lang/gameboy/timer.py pypy/branch/build-external/pypy/lang/gameboy/video.py pypy/branch/build-external/pypy/lang/smalltalk/constants.py pypy/branch/build-external/pypy/lang/smalltalk/error.py pypy/branch/build-external/pypy/lang/smalltalk/interpreter.py pypy/branch/build-external/pypy/lang/smalltalk/model.py pypy/branch/build-external/pypy/lang/smalltalk/primitives.py pypy/branch/build-external/pypy/lang/smalltalk/shadow.py pypy/branch/build-external/pypy/lang/smalltalk/squeakimage.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_interpreter.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_miniimage.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_model.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_primitives.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_shadow.py pypy/branch/build-external/pypy/lang/smalltalk/test/test_squeakimage.py pypy/branch/build-external/pypy/lang/smalltalk/tool/analyseimage.py pypy/branch/build-external/pypy/lang/smalltalk/tool/autopath.py pypy/branch/build-external/pypy/lib/app_test/test_pyexpat.py pypy/branch/build-external/pypy/lib/pyexpat.py pypy/branch/build-external/pypy/lib/test2/test_itertools.py pypy/branch/build-external/pypy/module/__builtin__/app_misc.py pypy/branch/build-external/pypy/module/__builtin__/importing.py pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py pypy/branch/build-external/pypy/module/__pypy__/interp_magic.py pypy/branch/build-external/pypy/module/_file/interp_file.py pypy/branch/build-external/pypy/module/_rawffi/test/test__rawffi.py pypy/branch/build-external/pypy/module/gc/__init__.py pypy/branch/build-external/pypy/module/signal/interp_signal.py pypy/branch/build-external/pypy/module/sys/state.py pypy/branch/build-external/pypy/module/thread/gil.py pypy/branch/build-external/pypy/module/thread/ll_thread.py pypy/branch/build-external/pypy/module/thread/os_thread.py pypy/branch/build-external/pypy/module/thread/test/support.py pypy/branch/build-external/pypy/module/thread/test/test_ll_thread.py pypy/branch/build-external/pypy/module/thread/threadlocals.py pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py pypy/branch/build-external/pypy/module/zipimport/test/test_zipimport.py pypy/branch/build-external/pypy/objspace/descroperation.py pypy/branch/build-external/pypy/objspace/flow/flowcontext.py pypy/branch/build-external/pypy/objspace/std/objspace.py pypy/branch/build-external/pypy/objspace/std/test/test_unicodeobject.py pypy/branch/build-external/pypy/objspace/std/test/test_userobject.py pypy/branch/build-external/pypy/objspace/std/typeobject.py pypy/branch/build-external/pypy/objspace/std/unicodeobject.py pypy/branch/build-external/pypy/objspace/std/unicodetype.py pypy/branch/build-external/pypy/rlib/_rsocket_rffi.py pypy/branch/build-external/pypy/rlib/libffi.py pypy/branch/build-external/pypy/rlib/rmmap.py pypy/branch/build-external/pypy/rlib/rposix.py pypy/branch/build-external/pypy/rlib/rstruct/nativefmttable.py pypy/branch/build-external/pypy/rlib/streamio.py pypy/branch/build-external/pypy/rlib/test/test_libffi.py pypy/branch/build-external/pypy/rpython/llinterp.py pypy/branch/build-external/pypy/rpython/lltypesystem/llheap.py pypy/branch/build-external/pypy/rpython/lltypesystem/lloperation.py pypy/branch/build-external/pypy/rpython/lltypesystem/rffi.py pypy/branch/build-external/pypy/rpython/lltypesystem/rpbc.py pypy/branch/build-external/pypy/rpython/lltypesystem/rstr.py pypy/branch/build-external/pypy/rpython/lltypesystem/test/test_rffi.py pypy/branch/build-external/pypy/rpython/memory/gctransform/framework.py pypy/branch/build-external/pypy/rpython/memory/support.py pypy/branch/build-external/pypy/rpython/module/ll_os.py pypy/branch/build-external/pypy/rpython/module/ll_os_stat.py pypy/branch/build-external/pypy/rpython/ootypesystem/ootype.py pypy/branch/build-external/pypy/rpython/test/test_rpbc.py pypy/branch/build-external/pypy/rpython/test/test_rstr.py pypy/branch/build-external/pypy/rpython/tool/rffi_platform.py pypy/branch/build-external/pypy/rpython/tool/test/test_rffi_platform.py pypy/branch/build-external/pypy/tool/gcc_cache.py pypy/branch/build-external/pypy/tool/test/test_tab.py pypy/branch/build-external/pypy/tool/tls.py pypy/branch/build-external/pypy/translator/backendopt/malloc.py pypy/branch/build-external/pypy/translator/backendopt/test/test_malloc.py pypy/branch/build-external/pypy/translator/c/gc.py pypy/branch/build-external/pypy/translator/c/genc.py pypy/branch/build-external/pypy/translator/c/src/thread.h pypy/branch/build-external/pypy/translator/c/src/thread_nt.h pypy/branch/build-external/pypy/translator/c/src/thread_pthread.h pypy/branch/build-external/pypy/translator/c/test/test_boehm.py pypy/branch/build-external/pypy/translator/goal/app_main.py pypy/branch/build-external/pypy/translator/goal/bench-cronjob.py pypy/branch/build-external/pypy/translator/goal/gcbench.py pypy/branch/build-external/pypy/translator/goal/targetgcbench.py pypy/branch/build-external/pypy/translator/goal/targetimageloadingsmalltalk.py (contents, props changed) pypy/branch/build-external/pypy/translator/goal/targettinybenchsmalltalk.py pypy/branch/build-external/pypy/translator/goal/test2/test_app_main.py pypy/branch/build-external/pypy/translator/tool/cbuild.py pypy/branch/build-external/pypy/translator/tool/test/test_cbuild.py Log: merge revisions 55322:55728 Modified: pypy/branch/build-external/pypy/config/config.py ============================================================================== --- pypy/branch/build-external/pypy/config/config.py (original) +++ pypy/branch/build-external/pypy/config/config.py Tue Jun 10 12:48:46 2008 @@ -520,6 +520,12 @@ value = self.convert_from_cmdline(value) self.config.setoption(self.option._name, value, who='cmdline') except ConfigError, e: + # This OptionValueError is going to exit the translate.py process. + # Now is the last chance to print the warnings, which might give + # more information... hack. + import sys + for warning in self.config.get_warnings(): + print >> sys.stderr, warning raise optparse.OptionValueError(e.args[0]) def help_default(self): Modified: pypy/branch/build-external/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/build-external/pypy/config/pypyoption.py (original) +++ pypy/branch/build-external/pypy/config/pypyoption.py Tue Jun 10 12:48:46 2008 @@ -21,10 +21,11 @@ "recparser", "symbol", "_random", "__pypy__"])) +# --allworkingmodules working_modules = default_modules.copy() working_modules.update(dict.fromkeys( ["_socket", "unicodedata", "mmap", "fcntl", - "rctime" , "select", "zipimport", + "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "dyngram", "_rawffi", "termios", "zlib", "struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO"] )) Modified: pypy/branch/build-external/pypy/config/translationoption.py ============================================================================== --- pypy/branch/build-external/pypy/config/translationoption.py (original) +++ pypy/branch/build-external/pypy/config/translationoption.py Tue Jun 10 12:48:46 2008 @@ -71,9 +71,11 @@ requires={ "shadowstack": [("translation.gctransformer", "framework")], "llvmgc": [("translation.gctransformer", "framework"), - ("translation.backend", "llvm")], + ("translation.backend", "llvm"), + ("translation.thread", False)], "asmgcc": [("translation.gctransformer", "framework"), - ("translation.backend", "c")], + ("translation.backend", "c"), + ("translation.thread", False)], }, suggests={ "shadowstack": [("translation.gc", "generation")], @@ -81,8 +83,7 @@ "asmgcc": [("translation.gc", "generation")], }), BoolOption("thread", "enable use of threading primitives", - default=False, cmdline="--thread", - requires=[("translation.gc", "boehm")]), + default=False, cmdline="--thread"), BoolOption("verbose", "Print extra information", default=False), BoolOption("debug", "Record extra annotation information", cmdline="-d --debug", default=False), Modified: pypy/branch/build-external/pypy/doc/_ref.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/_ref.txt (original) +++ pypy/branch/build-external/pypy/doc/_ref.txt Tue Jun 10 12:48:46 2008 @@ -10,6 +10,7 @@ .. _`pypy/annotation/model.py`: ../../pypy/annotation/model.py .. _`bin/`: ../../pypy/bin .. _`config/`: ../../pypy/config +.. _`pypy/config/pypyoption.py`: ../../pypy/config/pypyoption.py .. _`doc/`: ../../pypy/doc .. _`doc/config/`: ../../pypy/doc/config .. _`doc/discussion/`: ../../pypy/doc/discussion Modified: pypy/branch/build-external/pypy/doc/cpython_differences.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/cpython_differences.txt (original) +++ pypy/branch/build-external/pypy/doc/cpython_differences.txt Tue Jun 10 12:48:46 2008 @@ -13,19 +13,67 @@ Differences related to garbage collection strategies ---------------------------------------------------- -XXX: write me please - - -Subclasses of builtin ``dict`` objects --------------------------------------- - -When you pass an instance of a subclass of ``dict`` to the -``dict.update`` method, CPython simply ignores potentially overridden -methods, such as ``keys()`` or ``__getitem__()``; on the other hand, -PyPy correctly calls the overridden versions of the methods. - -For example, the following code prints ``42`` on PyPy but ``foo`` -on CPython:: +Most of the garbage collectors used or implemented by PyPy are not based on +reference counting, so the objects are not freed instantly when they are no +longer reachable. The most obvious effect of this is that files are not +promptly closed when they go out of scope. For files that are opened for +writing, data can be left sitting in their output buffers for a while, making +the on-disk file appear empty or truncated. + +Fixing this is essentially not possible without forcing a +reference-counting approach to garbage collection. The effect that you +get in CPython has clearly been described as a side-effect of the +implementation and not a language design decision: programs relying on +this are basically bogus. It would anyway be insane to try to enforce +CPython's behavior in a language spec, given that it has no chance to be +adopted by Jython or IronPython (or any other port of Python to Java or +.NET, like PyPy itself). + +There are a few extra implications for the difference in the GC. Most +notably, if an object has a __del__, the __del__ is never called more +than once in PyPy; but CPython will call the same __del__ several times +if the object is resurrected and dies again. The __del__ methods are +called in "the right" order if they are on objects pointing to each +other, as in CPython, but unlike CPython, if there is a dead cycle of +objects referencing each other, their __del__ methods are called anyway; +CPython would instead put them into the list ``garbage`` of the ``gc`` +module. More information is available on the blog `[1]`__ `[2]`__. + +.. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-1.html +.. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-2.html + +The built-in function ``id()`` returns numbers that are not addresses +for most of PyPy's garbage collectors. +This is most visible in the default repr: a typical PyPy object can +pretend to be located ``at 0x00000009``. This is just its ``id()``, not +its real address (because the physical address can change). + +Note that if you have a long chain of objects, each with a reference to +the next one, and each with a __del__, PyPy's GC will perform badly. On +the bright side, in most other cases, benchmarks have shown that PyPy's +GCs perform much better than CPython's. + + +Subclasses of built-in types +---------------------------- + +Officially, CPython has no rule at all for when exactly +overriden method of subclasses of built-in types get +implicitly called or not. As an approximation, these methods +are never called by other built-in methods of the same object. +For example, an overridden ``__getitem__()`` in a subclass of +``dict`` will not be called by e.g. the built-in ``get()`` +method. + +The above is true both in CPython and in PyPy. Differences +can occur about whether a built-in function or method will +call an overridden method of *another* object than ``self``. +In PyPy, they are generally always called, whereas not in +CPython. For example, in PyPy, ``dict1.update(dict2)`` +considers that ``dict2`` is just a general mapping object, and +will thus call overridden ``keys()`` and ``__getitem__()`` +methods on it. So the following code prints ``42`` on PyPy +but ``foo`` on CPython:: >>>> class D(dict): .... def __getitem__(self, key): @@ -38,10 +86,18 @@ >>>> print d1['a'] 42 -Comparison differencies + +Ignored exceptions ----------------------- -When custom \_\_eq\_\_ function on object (or any other rich comparison -method) raises an exception, we don't swallow the exception and instead -report it to user. +In many corner cases, CPython can silently swallow exceptions. +The precise list of when this occurs is rather long, even +though most cases are very uncommon. The most well-known +places are custom rich comparison methods (like \_\_eq\_\_); +dictionary lookup; calls to some built-in functions like +isinstance(). + +Unless this behavior is clearly present by design and +documented as such (as e.g. for hasattr()), in most cases PyPy +lets the exception propagate instead. Modified: pypy/branch/build-external/pypy/doc/download.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/download.txt (original) +++ pypy/branch/build-external/pypy/doc/download.txt Tue Jun 10 12:48:46 2008 @@ -2,6 +2,13 @@ Download one of the following release files: ============================================= +:warning: + + the 1.0 release is out of date. We strongly recommend that you + use the latest stable version. See `getting started`_. + +.. _`getting started`: getting-started.html#get-via-subversion + PyPy 1.0 Sources: ----------------- Modified: pypy/branch/build-external/pypy/doc/faq.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/faq.txt (original) +++ pypy/branch/build-external/pypy/doc/faq.txt Tue Jun 10 12:48:46 2008 @@ -54,9 +54,7 @@ At the moment you need CPython 2.4 (with ctypes 0.9.9.6 or newer) or CPython 2.5 for the translation process. -Currently (due to time restrictions) we are not trying hard to support -PyPy in a 64 bit environment. While things seem to mostly work, a few -modules won't work on 64 bit machines, such as ``bz2``. +PyPy also basically works in a 64-bit Linux environment. ------------------------------------------------ Which Python version (2.x?) does PyPy implement? @@ -64,10 +62,8 @@ PyPy currently aims to be fully compatible with Python 2.4. That means that it contains the standard library of Python 2.4 and that it supports 2.4 -features (such as decorators) but not the 2.5 features (with statement, the ternary -operator). The 2.5 features will probably be eventually supported, the most -important reason why nobody is working on them is that we did not promise this -to the EU and have currently enough other tasks. +features (such as decorators). The 2.5 features (e.g. the ``with`` statement, +the ternary operator) are in progress. .. _threading: @@ -75,26 +71,24 @@ Do threads work? What are the modules that work? ------------------------------------------------- -Operating system-level threads work in a limited way. If you enable the ``thread`` -module then PyPy will get support for GIL based threading. One limitation is -that not that many IO operations actually release the GIL, which reduces the -usefulness of threads. On the other hand, PyPy fully supports `stackless-like +Operating system-level threads basically work. If you enable the ``thread`` +module then PyPy will get support for GIL based threading. +Note that PyPy also fully supports `stackless-like microthreads`_ (although both cannot be mixed yet). As for other modules: The general rule of thumb is that pure-Python modules -work, C extension modules don't. Some of the C extension modules of the standard +work, C extension modules don't. However, many of the C extension modules +of the standard library have been re-implemented in pure Python or as a mixed module (for some -there were also older pure-Python versions available). A (probably incomplete) -list: +there were also older pure-Python versions available). The list of supported +modules can be found as follows: - * pure Python implementations: binascii, cmath, collections, cPickle, - cStringIO, datetime, functional, imp, itertools, md5, operator, - sha, struct - - * mixed module implementations: exceptions, sys, __builtin__, posix - _codecs, gc, _weakref, array, marshal, errno, math, _sre, parser, symbol, - _random, socket, unicodedata, mmap, fcntl, time, select, bz2, crypt, - signal, readline (incomplete) + * pure Python implementations: all the modules found in the `pypy/lib/`_ + directory + + * mixed module implementations: all the modules listed in + ``essential_modules``, ``default_modules`` and ``working_modules`` + in `pypy/config/pypyoption.py`_. .. _`stackless-like microthreads`: stackless.html @@ -110,8 +104,7 @@ rely heavily on CPython's C API which contains a lot of implementation details like reference counting, exact C-level object implementation and layout etc. -Although if your module uses ctypes rather than C-level code, there is -a hope -- you can try to write a mixed module (see next question). +A module based on ctypes is a different matter -- we support these nowadays. The long-term answer might be different. In principle, it should be possible for PyPy to support the CPython C API (or at least a large subset of its @@ -122,11 +115,10 @@ How do I write extension modules for PyPy? ------------------------------------------ -PyPy extension modules are written in the form of `mixed modules`_, so -called because they can contain a mixture of compiled and interpreted -Python code. At the moment they all need to be translated together with the rest of PyPy. +See `Writing extension modules for PyPy`__. + +.. __: extending.html -.. _`mixed modules`: coding-guide.html#mixed-module-mechanism .. _`slower than CPython`: .. _`how fast is pypy`: @@ -141,17 +133,16 @@ CPython, the version of PyPy that still runs on top of CPython is slower by a factor of 2000. The first translated version was roughly 300 times slower than CPython, a number which we decreased release after release -to the current point, where PyPy is only between 1.7 and 4 times slower -than CPython. Note that the speed heavily depends on the options -enabled at compile time. +to the current point, where PyPy is somewhere between 1 and 2, i.e. it +is as fast as CPython in some cases, and up to twice as slow in other +cases. Note that the speed heavily depends on the options enabled at +compile time. The integration of the work on the Just-In-Time compiler has just -started; it can be `manually enabled`_ and gives good results on -functions doing integer arithmetic (60 times faster than CPython, -i.e. within 20% of recoding the function in C and compiling with ``gcc`` -without optimizations). +started; it is not yet ready enough to give useful speed-ups. See +status__. -.. _`manually enabled`: jit/status.html +.. __: jit/status.html .. _`prolog and javascript`: @@ -232,7 +223,12 @@ up where. In this way, you could compile the program into two copies of itself: a "fast" version and a "slow" version. The former would contain many guards that allow it to fall back to the latter if needed. That -would be a wholly different project than PyPy, though. +would be a wholly different project than PyPy, though. (As far as we +understand it, this is the approach that the LLVM__ group would like to +see LLVM used for, so if you feel like working very hard and attempting +something like this, check with them.) + +.. __: http://llvm.org/ What PyPy contains is, on the one hand, an non-soft static type inferencer for RPython, which is a sublanguage that we defined just so @@ -290,6 +286,29 @@ an "entry point" function. The translation toolchain follows all calls recursively and discovers what belongs to the program and what not. +------------------------------------------------------------------------- +Can I use PyPy and RPython to compile smaller parts of my Python program? +------------------------------------------------------------------------- + +No. That would be possible, and we played with early attempts in that +direction, but there are many delicate issues: for example, how the +compiled and the non-compiled parts exchange data. Supporting this in a +nice way would be a lot of work. + +PyPy is certainly a good starting point for someone that would like to +work in that direction. Early attempts were dropped because they +conflicted with refactorings that we needed in order to progress on the +rest of PyPy; the currently active developers of PyPy have different +priorities. If someone wants to start working in that direction I +imagine that he might get a (very little) bit of support from us, +though. + +Alternatively, it's possible to write a mixed-module, i.e. an extension +module for PyPy in RPython, which you can then import from your Python +program when it runs on top of PyPy. This is similar to writing a C +extension module for CPython in term of investment of effort (without +all the INCREF/DECREF mess, though). + ------------------------------------------------------ What's the ``"NOT_RPYTHON"`` I see in some docstrings? ------------------------------------------------------ Modified: pypy/branch/build-external/pypy/doc/getting-started.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/getting-started.txt (original) +++ pypy/branch/build-external/pypy/doc/getting-started.txt Tue Jun 10 12:48:46 2008 @@ -26,29 +26,35 @@ ============== .. _gettingpypy: +.. _`latest stable version via subversion`: +.. _`get via Subversion`: -Downloading & running the PyPy 1.0 release --------------------------------------------- +Svn-check out & run the latest PyPy as a two-liner +-------------------------------------------------- -*Note: the 1.0 release is out of date. We strongly recommend that you -use the latest stable version* (which you can `get via Subversion`_). +If you want to play with the stable development PyPy version +you can check it out from the repository using subversion. +(Here are `old links`_ to the PyPy release 1.0 -- but don't +use it, it is too far out of date.) + +.. _`old links`: download.html + +Download and install subversion_ if you don't already have it. We have +some `help on installing subversion`_ for PyPy. Then you can issue on +the command line (DOS box or terminal):: -Download one of the following release files: + svn co http://codespeak.net/svn/pypy/dist pypy-dist -*pypy-1.0* - - * `pypy-1.0.0.tar.bz2`_ (sources, unix line endings) or - * `pypy-1.0.0.tar.gz`_ (sources, unix line endings) or - * `pypy-1.0.0.zip`_ (sources, windows line-endings) or - * `pypy-1.0.0-win32.zip`_ (precompiled executables for windows) - * or get the `latest stable version via subversion`_. - -After unpacking the source downloads you can change to the -``pypy-1.0.0`` directory and execute the following command line:: +This will create a directory named ``pypy-dist``, and will get you the PyPy +source in ``pypy-dist/pypy`` and documentation files in +``pypy-dist/pypy/doc``. - python pypy/bin/py.py +After checkout you can get a PyPy interpreter via:: + + python pypy-dist/pypy/bin/py.py -This will give you a PyPy prompt, i.e. a very compliant Python +have fun :-) +This gives you a PyPy prompt, i.e. a very compliant Python interpreter implemented in Python. PyPy passes around `98% of CPythons core language regression tests`_. Because this invocation of PyPy still runs on top of CPython, it runs around 2000 times slower @@ -58,48 +64,13 @@ is required to import our version of ctypes). This is probably not something you want to play with for too long, -though, as it is really slow. -Since the 0.7.0 release it is possible to use PyPy to `translate +though, as it is really slow. Instead, you should use PyPy to `translate itself to lower level languages`_ after which it runs standalone, is not dependant on CPython anymore and becomes faster (within the same speed magnitude as CPython itself). -If you are using the precompiled Windows executables, please look -at the included ``README.txt`` on how to start already translated -interpreters. Note that the examples in the html documentation generally -assume that you have a py.py; with precompiled binaries, you need to -pick one with the matching features compiled in. - .. _`98% of CPythons core language regression tests`: http://www2.openend.se/~pedronis/pypy-c-test/allworkingmodules/summary.html -.. _`pypy-1.0.0.tar.bz2`: http://codespeak.net/download/pypy/pypy-1.0.0.tar.bz2 -.. _`pypy-1.0.0.zip`: http://codespeak.net/download/pypy/pypy-1.0.0.zip -.. _`pypy-1.0.0.tar.gz`: http://codespeak.net/download/pypy/pypy-1.0.0.tar.gz -.. _`pypy-1.0.0-win32.zip`: http://codespeak.net/download/pypy/pypy-1.0.0-win32.zip -.. _`latest stable version via subversion`: -.. _`get via Subversion`: - -Svn-check out & run the latest PyPy as a two-liner --------------------------------------------------- - -If you want to play with the stable development PyPy version -you can check it out from the repository using subversion. Download -and install subversion_ if you don't already have it. Then you can -issue on the command line (DOS box or terminal):: - - svn co http://codespeak.net/svn/pypy/dist pypy-dist - -This will create a directory named ``pypy-dist``, and will get you the PyPy -source in ``pypy-dist/pypy`` and documentation files in -``pypy-dist/pypy/doc``. - -After checkout you can get a PyPy interpreter via:: - - python pypy-dist/pypy/bin/py.py - -have fun :-) - -We have some `help on installing subversion`_ for PyPy. Have a look at `interesting starting points`_ for some guidance on how to continue. @@ -572,34 +543,37 @@ .. _`windows document`: windows.html -You can -translate the PyPy's whole of Python interpreter to low level C code. This is -the largest and -ultimate example of source that our translation toolchain can process. -If you don't need threads, the most standard variant nowadays is:: +You can translate the whole of PyPy's Python interpreter to low level C +code. This is the largest and ultimate example of RPython program that +our translation toolchain can process. The most standard variant +nowadays is:: cd pypy/translator/goal - python translate.py --gc=hybrid targetpypystandalone.py --allworkingmodules --faassen + python translate.py --gc=hybrid --thread targetpypystandalone.py --allworkingmodules --faassen + +Dependencies: this will compile all supported built-in modules, some of +which have external dependencies. On a Debian Linux, for example, you +need to install the following packages: a full C compiler like gcc; +``python-dev, python-ctypes``; ``libffi-dev, libz-dev, libbz2-dev, +libncurses-dev``. This whole process will take some time and quite a lot of memory (around 1GB). It creates an executable ``pypy-c`` in the current directory. The ``--gc=hybrid`` option means that the ``pypy-c`` will use our own exact generational garbage collector implementation, whose performance -is rather good nowadays. The ``--faassen`` option enables all the +is rather good nowadays. The ``--thread`` option enables the thread +module, which is still slightly experimental. +The ``--faassen`` option enables all the worthwhile performance optimizations, but slows down the translation -itself. On Linux 32-bit Intel machines you can also add -``--gcrootfinder=asmgcc`` after ``--gc=hybrid`` for extra speed (and -extra translation time). - -At the moment, threads only work with the `Boehm-Demers-Weiser garbage -collector`_. So to enable them, you need instead:: - - cd pypy/translator/goal - python translate.py --thread targetpypystandalone.py --allworkingmodules --faassen +itself. On Linux 32-bit Intel machines, if you don't need threads, you +can get some extra speed (and extra translation time) by removing +``--thread`` and replacing it with ``--gcrootfinder=asmgcc``. +An alternative is to use the `Boehm-Demers-Weiser garbage +collector`_ instead of our own. For this, use ``--gc=boehm``. Be sure to install Boehm before starting the translation (e.g. by running ``apt-get install libgc-dev`` on Debian or Ubuntu). Translating with Boehm -is a bit faster and less memory-hungry than translating with our own GCs. +is somewhat faster and less memory-hungry than translating with our own GCs. In any case, as described above, you can find the produced executable under the name ``pypy-c``. Type ``pypy-c --help`` to see the options it supports -- @@ -618,7 +592,7 @@ * ``--gc=boehm|ref|marknsweep|semispace|generation|hybrid``: choose between using the `Boehm-Demers-Weiser garbage collector`_, our reference - counting implementation or three of own collector implementations + counting implementation or four of own collector implementations (Boehm's collector is the default). Find a more detailed description of the various options in our `configuration Modified: pypy/branch/build-external/pypy/doc/index.txt ============================================================================== --- pypy/branch/build-external/pypy/doc/index.txt (original) +++ pypy/branch/build-external/pypy/doc/index.txt Tue Jun 10 12:48:46 2008 @@ -75,7 +75,7 @@ =================================== PyPy can be used to run Python programs on Linux, OS/X, -Windows, on top of .NET, and (recently) on top of Java. +Windows, on top of .NET, and on top of Java. It is recommended to try out the current Subversion HEAD, which contains `major improvements`__ since the last release. @@ -83,10 +83,8 @@ PyPy is mainly developed on Linux and Mac OS X. Windows is supported, but platform-specific bugs tend to take longer before we notice and fix -them. About 64-bit machines: although support is mostly present, we -decided to stop tracking and fixing the remaining issues for a while, as -an attempt to keep some focus. So PyPy requires a 32-bit machine or OS -for now. +them. Linux 64-bit machines are supported (though it may also take some +time before we notice and fix bugs). PyPy's own tests, daily updated, `on Linux`_, `on Windows`_ and `on built pypy-c`_. Modified: pypy/branch/build-external/pypy/doc/redirections ============================================================================== --- pypy/branch/build-external/pypy/doc/redirections (original) +++ pypy/branch/build-external/pypy/doc/redirections Tue Jun 10 12:48:46 2008 @@ -4,5 +4,6 @@ 'news.html': 'home.html', 'contact.html': 'home.html', 'jit.html': 'jit/index.html', + 'standalone-howto.html': 'faq.html#pypy-translation-tool-chain', } Modified: pypy/branch/build-external/pypy/interpreter/astcompiler/misc.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/astcompiler/misc.py (original) +++ pypy/branch/build-external/pypy/interpreter/astcompiler/misc.py Tue Jun 10 12:48:46 2008 @@ -45,11 +45,31 @@ return "_%s%s" % (klass, name) +class Queue(object): + def __init__(self, item): + self.head = [item] + self.tail = [] + + def pop(self): + if self.head: + return self.head.pop() + else: + for i in range(len(self.tail)-1, -1, -1): + self.head.append(self.tail[i]) + self.tail = [] + return self.head.pop() + + def extend(self, items): + self.tail.extend(items) + + def nonempty(self): + return self.tail or self.head + def set_filename(filename, tree): """Set the filename attribute to filename on every node in tree""" - worklist = [tree] - while worklist: - node = worklist.pop(0) + worklist = Queue(tree) + while worklist.nonempty(): + node = worklist.pop() assert isinstance(node, ast.Node) node.filename = filename worklist.extend(node.getChildNodes()) Modified: pypy/branch/build-external/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/branch/build-external/pypy/interpreter/astcompiler/pycodegen.py Tue Jun 10 12:48:46 2008 @@ -596,7 +596,7 @@ def visitListComp(self, node): self.set_lineno(node) # setup list - tmpname = "$list%d" % self.__list_count + tmpname = "_[%d]" % self.__list_count self.__list_count = self.__list_count + 1 self.emitop_int('BUILD_LIST', 0) self.emit('DUP_TOP') Modified: pypy/branch/build-external/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/build-external/pypy/interpreter/executioncontext.py Tue Jun 10 12:48:46 2008 @@ -5,6 +5,11 @@ def new_framestack(): return Stack() +def app_profile_call(space, w_callable, frame, event, w_arg): + space.call_function(w_callable, + space.wrap(frame), + space.wrap(event), w_arg) + class ExecutionContext: """An ExecutionContext holds the state of an execution thread in the Python interpreter.""" @@ -13,11 +18,12 @@ self.space = space self.framestack = new_framestack() self.w_tracefunc = None - self.w_profilefunc = None self.is_tracing = 0 self.ticker = 0 self.pending_actions = [] self.compiler = space.createcompiler() + self.profilefunc = None + self.w_profilefuncarg = None def enter(self, frame): if self.framestack.depth() > self.space.sys.recursionlimit: @@ -32,7 +38,7 @@ self.framestack.push(frame) def leave(self, frame): - if self.w_profilefunc: + if self.profilefunc: self._trace(frame, 'leaveframe', None) if not frame.hide(): @@ -45,19 +51,22 @@ def __init__(self): self.framestack = new_framestack() self.w_tracefunc = None - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None self.is_tracing = 0 def enter(self, ec): ec.framestack = self.framestack ec.w_tracefunc = self.w_tracefunc - ec.w_profilefunc = self.w_profilefunc + ec.profilefunc = self.profilefunc + ec.w_profilefuncarg = self.w_profilefuncarg ec.is_tracing = self.is_tracing def leave(self, ec): self.framestack = ec.framestack self.w_tracefunc = ec.w_tracefunc - self.w_profilefunc = ec.w_profilefunc + self.profilefunc = ec.profilefunc + self.w_profilefuncarg = ec.w_profilefuncarg self.is_tracing = ec.is_tracing # the following interface is for pickling and unpickling @@ -182,9 +191,17 @@ def setprofile(self, w_func): """Set the global trace function.""" if self.space.is_w(w_func, self.space.w_None): - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None else: - self.w_profilefunc = w_func + self.w_profilefuncarg = w_func + self.profilefunc = app_profile_call + + def setllprofile(self, func, w_arg): + self.profilefunc = func + if func is not None and w_arg is None: + raise ValueError("Cannot call setllprofile with real None") + self.w_profilefuncarg = w_arg def call_tracing(self, w_func, w_args): is_tracing = self.is_tracing @@ -229,7 +246,7 @@ frame.locals2fast() # Profile cases - if self.w_profilefunc is not None: + if self.profilefunc is not None: if event not in ['leaveframe', 'call']: return @@ -242,11 +259,11 @@ self.is_tracing += 1 try: try: - w_result = space.call_function(self.w_profilefunc, - space.wrap(frame), - space.wrap(event), w_arg) + self.profilefunc(space, self.w_profilefuncarg, + frame, event, w_arg) except: - self.w_profilefunc = None + self.profilefunc = None + self.w_profilefuncarg = None raise finally: Modified: pypy/branch/build-external/pypy/interpreter/function.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/function.py (original) +++ pypy/branch/build-external/pypy/interpreter/function.py Tue Jun 10 12:48:46 2008 @@ -230,8 +230,11 @@ return space.newtuple(values_w) def fset_func_defaults(space, self, w_defaults): + if space.is_w(w_defaults, space.w_None): + self.defs_w = [] + return if not space.is_true( space.isinstance( w_defaults, space.w_tuple ) ): - raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object") ) + raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object or None") ) self.defs_w = space.unpackiterable( w_defaults ) def fdel_func_defaults(space, self): Modified: pypy/branch/build-external/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/gateway.py (original) +++ pypy/branch/build-external/pypy/interpreter/gateway.py Tue Jun 10 12:48:46 2008 @@ -213,7 +213,7 @@ def visit__object(self, typ): name = int_unwrapping_space_method(typ) - self.run_args.append("space.%s_w(%s)" % + self.run_args.append("space.%s(%s)" % (name, self.scopenext())) def visit_index(self, typ): @@ -328,7 +328,7 @@ def visit__object(self, typ): name = int_unwrapping_space_method(typ) - self.unwrap.append("space.%s_w(%s)" % (name, + self.unwrap.append("space.%s(%s)" % (name, self.nextarg())) def visit_index(self, typ): @@ -368,13 +368,15 @@ make_fastfunc = staticmethod(make_fastfunc) def int_unwrapping_space_method(typ): - assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong) + assert typ in (int, str, float, unicode, r_longlong, r_uint, r_ulonglong, bool) if typ is r_int is r_longlong: - return 'r_longlong' + return 'r_longlong_w' elif typ is r_uint: - return 'uint' + return 'uint_w' + elif typ is bool: + return 'is_true' else: - return typ.__name__ + return typ.__name__ + '_w' class BuiltinCode(eval.Code): "The code object implementing a built-in (interpreter-level) hook." Modified: pypy/branch/build-external/pypy/interpreter/miscutils.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/miscutils.py (original) +++ pypy/branch/build-external/pypy/interpreter/miscutils.py Tue Jun 10 12:48:46 2008 @@ -168,9 +168,6 @@ def getmainthreadvalue(self): return self._value - def getGIL(self): - return None # XXX temporary hack! - class Action(object): """Abstract base class for actions that must be performed regularly, Modified: pypy/branch/build-external/pypy/interpreter/pycode.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/pycode.py (original) +++ pypy/branch/build-external/pypy/interpreter/pycode.py Tue Jun 10 12:48:46 2008 @@ -393,3 +393,8 @@ #hidden_applevel=False, magic = 62061 | 0x0a0d0000 ] return space.newtuple([new_inst, space.newtuple(tup)]) + + def repr(self, space): + return space.wrap("" % ( + self.co_name, self.co_filename, self.co_firstlineno)) + repr.unwrap_spec = ['self', ObjSpace] Modified: pypy/branch/build-external/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/branch/build-external/pypy/interpreter/test/test_code.py (original) +++ pypy/branch/build-external/pypy/interpreter/test/test_code.py Tue Jun 10 12:48:46 2008 @@ -1,6 +1,16 @@ +from pypy.conftest import gettestobjspace +from pypy.interpreter import gateway +import py class AppTestCodeIntrospection: + def setup_class(cls): + space = gettestobjspace() + cls.space = space + if py.test.config.option.runappdirect: + cls.w_file = space.wrap(__file__[:-1]) + else: + cls.w_file = space.wrap("None<%s" % gateway.__file__[:-1]) def test_attributes(self): def f(): pass @@ -129,9 +139,20 @@ def test_inspect(self): if not hasattr(len, 'func_code'): - skip("CPython: no func_code attribute on built-in functions") + skip("Cannot run this test if builtins have no func_code") import inspect args, varargs, varkw = inspect.getargs(len.func_code) assert args == ['obj'] assert varargs is None assert varkw is None + + def test_repr(self): + def f(): + xxx + res = repr(f.func_code) + expected = ["=0x00 and rom_size<=0x07: return 32768 << rom_size return -1 def get_ram_size(self): - return constants.CARTRIDGE_RAM_SIZE_MAPPING[self.rom[constants.CARTRIDGE_RAM_SIZE_ADDRESS]] + return constants.CARTRIDGE_RAM_SIZE_MAPPING[ + self.rom[constants.CARTRIDGE_RAM_SIZE_ADDRESS]] def get_destination_code(self): - return self.rom[constants.DESTINATION_CODE_ADDRESS] & 0xFF + return self.rom[constants.DESTINATION_CODE_ADDRESS] def get_licensee_code(): - return self.rom[constants.LICENSEE_ADDRESS] & 0xFF + return self.rom[constants.LICENSEE_ADDRESS] def get_rom_version(self): - return self.rom[constants.CARTRIDGE_ROM_VERSION_ADDRESS] & 0xFF + return self.rom[constants.CARTRIDGE_ROM_VERSION_ADDRESS] def get_header_checksum(self): - return self.rom[constants.HEADER_CHECKSUM_ADDRESS] & 0xFF + return self.rom[constants.HEADER_CHECKSUM_ADDRESS] def get_checksum(self): - return ((self.rom[constants.CHECKSUM_A_ADDRESS] & 0xFF) << 8) \ - + (self.rom[constants.CHECKSUM_B_ADDRESS] & 0xFF) - + return ((self.rom[constants.CHECKSUM_A_ADDRESS]) << 8) \ + + (self.rom[constants.CHECKSUM_B_ADDRESS]) + def has_battery(self): return has_cartridge_battery(self.get_memory_bank_type()) @@ -138,7 +159,7 @@ checksum = 0 for address in range(len(self.rom)): if address is not 0x014E and address is not 0x014F: - checksum = (checksum + (self.rom[address] & 0xFF)) & 0xFFFF + checksum = (checksum + (self.rom[address])) & 0xFF return (checksum == self.get_checksum()) def verify_header(self): @@ -146,12 +167,18 @@ return False checksum = 0xE7 for address in range(0x0134, 0x014C): - checksum = (checksum - (self.rom[address] & 0xFF)) & 0xFF + checksum = (checksum - (self.rom[address])) & 0xFF return (checksum == self.get_header_checksum()) def create_bank_controller(self, type, rom, ram, clock_driver): return MEMORY_BANK_MAPPING[type](rom, ram, clock_driver) + + def __repr__(self): + return "Type=%s, Destination: %s ramSize: %sKB romSize: %sKB" % \ + (self.get_memory_bank_type(), self.get_destination_code(), + self.get_ram_size(), self.get_rom_size()/1024) + # ------------------------------------------------------------------------------ @@ -166,32 +193,32 @@ self.load(file) def reset(self): - self.cartridge_name = "" - self.cartridge_file_path = "" - self.cartridge_stream = None + self.cartridge_name = "" + self.cartridge_file_path = "" + self.cartridge_stream = None self.cartridge_file_contents = None - self.battery_name = "" - self.battery_file_path = "" - self.battery_stream = None - self.battery_file_contents = None + self.battery_name = "" + self.battery_file_path = "" + self.battery_stream = None + self.battery_file_contents = None def load(self, cartridge_path): - if cartridge_path is None: - raise Exception("cartridge_path cannot be None!") - cartridge_path = str(cartridge_path) - self.cartridge_file_path = cartridge_path - self.cartridge_stream = open_file_as_stream(cartridge_path) - self.cartridge_file_contents = map_to_byte( \ + cartridge_path = str(cartridge_path) + self.cartridge_file_path = cartridge_path + self.cartridge_stream = open_file_as_stream(cartridge_path) + self.cartridge_file_contents = map_to_byte( self.cartridge_stream.readall()) self.load_battery(cartridge_path) def load_battery(self, cartridge_file_path): self.battery_file_path = self.create_battery_file_path(cartridge_file_path) if self.has_battery(): - self.battery_stream = open_file_as_stream(self.battery_file_path) - self.battery_file_contents = map_to_byte( \ - self.battery_stream.readall()) + self.read_battery() + + def read_battery(self): + self.battery_stream = open_file_as_stream(self.battery_file_path) + self.battery_file_contents = map_to_byte(self.battery_stream.readall()) def create_battery_file_path(self, cartridge_file_path): if cartridge_file_path.endswith(constants.CARTRIDGE_FILE_EXTENSION): @@ -213,7 +240,7 @@ return self.cartridge_file_contents def read_battery(self): - return self.battery_file_contents + return self.battery_file_contents def write_battery(self, ram): output_stream = open_file_as_stream(self.battery_file_path, "w") @@ -242,18 +269,20 @@ def __init__(self, rom, ram, clock_driver, min_rom_bank_size=0, max_rom_bank_size=0, - min_ram_bank_size=0, max_ram_bank_size=0): + min_ram_bank_size=0, max_ram_bank_size=0, + rom_bank_size=constants.ROM_BANK_SIZE): self.clock = clock_driver self.min_rom_bank_size = min_rom_bank_size self.max_rom_bank_size = max_rom_bank_size self.min_ram_bank_size = min_ram_bank_size self.max_ram_bank_size = max_ram_bank_size + self.rom_bank_size = rom_bank_size + self.rom_bank = self.rom_bank_size self.reset() self.set_rom(rom) self.set_ram(ram) def reset(self): - self.rom_bank = constants.ROM_BANK_SIZE self.ram_bank = 0 self.ram_enable = False self.rom = [] @@ -262,39 +291,45 @@ self.ram_size = 0 def set_rom(self, buffer): - banks = int(len(buffer) / constants.ROM_BANK_SIZE) + banks = int(len(buffer) / self.rom_bank_size) if banks < self.min_rom_bank_size or banks > self.max_rom_bank_size: - raise Exception("Invalid ROM size %s, should be in [%s %s]" % \ - (hex(banks), hex(self.min_rom_bank_size), \ + raise InvalidSizeException("Invalid ROM size %s, should be in [%s %s]" % + (hex(banks), hex(self.min_rom_bank_size), hex(self.max_rom_bank_size))) - self.rom = buffer - self.rom_size = constants.ROM_BANK_SIZE * banks - 1 + self.rom = buffer + self.rom_size = self.rom_bank_size * banks - 1 def set_ram(self, buffer): banks = int(len(buffer) / constants.RAM_BANK_SIZE) if banks < self.min_ram_bank_size or banks > self.max_ram_bank_size: - raise Exception("Invalid RAM size %s, should be in [%s %s]" % \ - (hex(banks), hex(self.min_ram_bank_size), \ + raise InvalidSizeException("Invalid RAM size %s, should be in [%s %s]" % + (hex(banks), hex(self.min_ram_bank_size), hex(self.max_ram_bank_size))) - self.ram = buffer + self.ram = buffer self.ram_size = constants.RAM_BANK_SIZE * banks - 1 - def read(self, address): - if address <= 0x3FFF: # 0000-3FFF - return self.rom[address] & 0xFF - elif address <= 0x7FFF:# 4000-7FFF - return self.rom[self.rom_bank + (address & 0x3FFF)] & 0xFF - elif address >= 0xA000 and address <= 0xBFFF: # A000-BFFF + def read(self, address): + # 0000-3FFF + if address <= 0x3FFF: + return self.rom[address] + # 4000-7FFF + elif address <= 0x7FFF: + return self.rom[self.rom_bank + (address & 0x3FFF)] + # A000-BFFF + elif address >= 0xA000 and address <= 0xBFFF: if self.ram_enable: - return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF + return self.ram[self.ram_bank + (address & 0x1FFF)] else: + #return 0xFF raise Exception("RAM is not Enabled") - raise Exception("MBC: Invalid address, out of range: %s" % hex(address)) + #return 0xFF + raise InvalidMemoryAccessException("MBC: Invalid address, out of range: %s" + % hex(address)) def write(self, address, data): - raise Exception("MBC: Invalid write access") + raise InvalidMemoryAccessException("MBC: Invalid write access") def write_ram_enable(self, address, data): if self.ram_size > 0: @@ -314,7 +349,7 @@ max_ram_bank_size=0xFFFFFF) def write(self, address, data): - self.ram[address] = data + self.ram[self.ram_bank + (address & 0x1FFF)] = data #------------------------------------------------------------------------------- @@ -322,9 +357,9 @@ class MBC1(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator - Memory Bank Controller 1 (2MB constants.ROM, 32KB constants.RAM) + Memory Bank Controller 1 (2MB ROM, 32KB RAM) 0000-3FFF ROM Bank 0 (16KB) 4000-7FFF ROM Bank 1-127 (16KB) @@ -342,30 +377,39 @@ self.memory_model = 0 def write(self, address, data): - if address <= 0x1FFF: # 0000-1FFF + # 0000-1FFF + if address <= 0x1FFF: self.write_ram_enable(address, data) - elif address <= 0x3FFF: # 2000-3FFF + # 2000-3FFF + elif address <= 0x3FFF: self.write_rom_bank_1(address, data) - elif address <= 0x5FFF: # 4000-5FFF + # 4000-5FFF + elif address <= 0x5FFF: self.write_rom_bank_2(address, data) - elif address <= 0x7FFF: # 6000-7FFF + # 6000-7FFF + elif address <= 0x7FFF: self.memory_model = data & 0x01 - elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: # A000-BFFF + # A000-BFFF + elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: self.ram[self.ram_bank + (address & 0x1FFF)] = data else: - raise Exception("Invalid memory Access address: %s" % hex(address)) + return + #raise InvalidMemoryAccessException("MBC 1Invalid memory Access address: %s" + # % hex(address)) def write_rom_bank_1(self, address, data): if (data & 0x1F) == 0: data = 1 if self.memory_model == 0: - self.rom_bank = ((self.rom_bank & 0x180000) + ((data & 0x1F) << 14)) & self.rom_size + self.rom_bank = ((self.rom_bank & 0x180000) + + ((data & 0x1F) << 14)) & self.rom_size else: self.rom_bank = ((data & 0x1F) << 14) & self.rom_size def write_rom_bank_2(self, address, data): if self.memory_model == 0: - self.rom_bank = ((self.rom_bank & 0x07FFFF) + ((data & 0x03) << 19)) & self.rom_size + self.rom_bank = ((self.rom_bank & 0x07FFFF) + + ((data & 0x03) << 19)) & self.rom_size else: self.ram_bank = ((data & 0x03) << 13) & self.ram_size @@ -375,44 +419,45 @@ class MBC2(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator - Memory Bank Controller 2 (256KB constants.ROM, 512x4bit constants.RAM) + Memory Bank Controller 2 (256KB ROM, 512x4bit RAM) 0000-3FFF ROM Bank 0 (16KB) 4000-7FFF ROM Bank 1-15 (16KB) A000-A1FF RAM Bank (512x4bit) """ - RAM_BANK_SIZE = 512 - def __init__(self, rom, ram, clock_driver): MBC.__init__(self, rom, ram, clock_driver, - min_ram_bank_size=1, - max_ram_bank_size=1, - min_rom_bank_size=2, - max_rom_bank_size=16) + min_ram_bank_size=1, max_ram_bank_size=1, + min_rom_bank_size=2, max_rom_bank_size=16, + rom_bank_size=512) - def read(self, address): if address > 0xA1FF: - raise Exception("MBC2 out of Bounds: %s" % hex(address)) + raise InvalidMemoryAccessException("MBC2 out of Bounds: %s" + % hex(address)) elif address >= 0xA000: return self.ram[address & 0x01FF] - elif address >= 0xA000 and address <= 0xA1FF: # A000-BFFF + # A000-BFFF + elif address >= 0xA000 and address <= 0xA1FF: if self.ram_enable: - return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF + return self.ram[self.ram_bank + (address & 0x1FFF)] else: raise Exception("RAM is not Enabled") else: return MBC.read(self, address) def write(self, address, data): - if address <= 0x1FFF: # 0000-1FFF + # 0000-1FFF + if address <= 0x1FFF: self.write_ram_enable(address, data) - elif address <= 0x3FFF: # 2000-3FFF + # 2000-3FFF + elif address <= 0x3FFF: self.write_rom_bank(address, data) - elif address >= 0xA000 and address <= 0xA1FF: # A000-A1FF + # A000-A1FF + elif address >= 0xA000 and address <= 0xA1FF: self.write_ram(address, data) def write_rom_bank(self, address, data): @@ -435,14 +480,15 @@ class MBC3(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator - Memory Bank Controller 3 (2MB constants.ROM, 32KB constants.RAM, Real Time Clock) + Memory Bank Controller 3 (2MB ROM, 32KB RAM, Real Time Clock) 0000-3FFF ROM Bank 0 (16KB) 4000-7FFF ROM Bank 1-127 (16KB) A000-BFFF RAM Bank 0-3 (8KB) """ + def __init__(self, rom, ram, clock_driver): MBC.__init__(self, rom, ram, clock_driver, min_ram_bank_size=0, @@ -450,7 +496,6 @@ min_rom_bank_size=2, max_rom_bank_size=128) - def reset(self): MBC.reset(self) self.clock_latched_daysclock_latched_control = None @@ -468,11 +513,11 @@ self.clock_latched_days = 0 self.clock_latched_control = 0 - def read(self, address): - if address >= 0xA000 and address <= 0xBFFF: # A000-BFFF + # A000-BFFF + if address >= 0xA000 and address <= 0xBFFF: if self.ram_bank >= 0: - return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF + return self.ram[self.ram_bank + (address & 0x1FFF)] else: return self.read_clock_data(address) else: @@ -489,18 +534,24 @@ return self.clock_latched_days if self.clock_register == 0x0C: return self.clock_latched_control - raise Exception("MBC*.read_clock_data invalid address %i") + raise InvalidMemoryAccessException("MBC3.read_clock_data invalid address %i") def write(self, address, data): - if address <= 0x1FFF: # 0000-1FFF + print hex(address), hex(data) + # 0000-1FFF + if address <= 0x1FFF: self.write_ram_enable(address, data) - elif address <= 0x3FFF: # 2000-3FFF + # 2000-3FFF + elif address <= 0x3FFF: self.write_rom_bank(address, data) - elif address <= 0x5FFF: # 4000-5FFF + # 4000-5FFF + elif address <= 0x5FFF: self.write_ram_bank(address, data) - elif address <= 0x7FFF: # 6000-7FFF + # 6000-7FFF + elif address <= 0x7FFF: self.write_clock_latch(address, data) - elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: # A000-BFFF + # A000-BFFF + elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: if self.ram_bank >= 0: self.ram[self.ram_bank + (address & 0x1FFF)] = data else: @@ -543,35 +594,37 @@ self.clock_latched_minutes = self.clock_minutes self.clock_latched_hours = self.clock_hours self.clock_latched_days = self.clock_days & 0xFF - self.clock_latched_control = (self.clock_control & 0xFE) | ((self.clock_days >> 8) & 0x01) + self.clock_latched_control = (self.clock_control & 0xFE) | \ + ((self.clock_days >> 8) & 0x01) def update_clock(self): now = self.clock.get_time() - if (self.clock_control & 0x40) == 0: - elapsed = now - self.clock_time - while elapsed >= 246060: - elapsed -= 246060 - self.clock_days+=1 - while elapsed >= 6060: - elapsed -= 6060 - self.clock_hours+=1 - while elapsed >= 60: - elapsed -= 60 - self.clock_minutes+=1 - self.clock_seconds += elapsed - while self.clock_seconds >= 60: - self.clock_seconds -= 60 - self.clock_minutes+=1 - while self.clock_minutes >= 60: - self.clock_minutes -= 60 - self.clock_hours+=1 - while self.clock_hours >= 24: - self.clock_hours -= 24 - self.clock_days+=1 - while self.clock_days >= 512: - self.clock_days -= 512 - self.clock_control |= 0x80 + elapsed = now - self.clock_time self.clock_time = now + if (self.clock_control & 0x40) != 0: + return + elapsed += self.clock_days * 24*60*60 + elapsed += self.clock_hours * 60*60 + elapsed += self.clock_minutes * 60 + elapsed += self.clock_seconds + + days = int(math.floor(elapsed / (24.0*60*60.0))) + self.clock_days += days + elapsed -= days * 24*60*60 + + hours = int(math.floor(elapsed / (60*60))) + self.clock_hours += hours + elapsed -= hours * 60*60 + + minutes = int(math.floor(elapsed / 60)) + self.clock_minutes += minutes + elapsed -= minutes * 60 + + self.clock_seconds += elapsed + + if self.clock_days >= 512: + self.clock_days %= 512 + self.clock_control |= 0x80 #------------------------------------------------------------------------------- @@ -579,9 +632,9 @@ class MBC5(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator - Memory Bank Controller 5 (8MB constants.ROM, 128KB constants.RAM) + Memory Bank Controller 5 (8MB ROM, 128KB RAM) * 0000-3FFF ROM Bank 0 (16KB) 4000-7FFF ROM Bank 1-511 (16KB) @@ -600,17 +653,22 @@ def write(self, address, data): address = int(address) - if address <= 0x1FFF: # 0000-1FFF + # 0000-1FFF + if address <= 0x1FFF: self.write_ram_enable(address, data) - elif address <= 0x2FFF: # 2000-2FFF - self.rom_bank = ((self.rom_bank & (0x01 << 22)) + \ - ((data & 0xFF) << 14)) & self.rom_size - elif address <= 0x3FFF: # 3000-3FFF - self.rom_bank = ((self.rom_bank & (0xFF << 14)) + \ + # 2000-2FFF + elif address <= 0x2FFF: + self.rom_bank = ((self.rom_bank & (0x01 << 22)) + + ((data) << 14)) & self.rom_size + # 3000-3FFF + elif address <= 0x3FFF: + self.rom_bank = ((self.rom_bank & (0xFF << 14)) + ((data & 0x01) << 22)) & self.rom_size - elif address <= 0x4FFF: # 4000-4FFF + # 4000-4FFF + elif address <= 0x4FFF: self.write_ram_bank(address, data) - elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: # A000-BFFF + # A000-BFFF + elif address >= 0xA000 and address <= 0xBFFF and self.ram_enable: self.ram[self.ram_bank + (address & 0x1FFF)] = data def write_ram_bank(self, address, data): @@ -635,9 +693,9 @@ class HuC3(MBC): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator - Hudson Memory Bank Controller 3 (2MB constants.ROM, 128KB constants.RAM, constants.RTC) + Hudson Memory Bank Controller 3 (2MB ROM, 128KB RAM, RTC) 0000-3FFF ROM Bank 0 (16KB) 4000-7FFF ROM Bank 1-127 (16KB) @@ -650,7 +708,6 @@ min_rom_bank_size=2, max_rom_bank_size=128) - def reset(self): MBC.reset(self) self.ram_flag = 0 @@ -659,30 +716,35 @@ self.clock_shift = 0 self.clock_time = self.clock.get_time() - def read(self, address): - address = int(address) - if address >= 0xA000 and address <= 0xBFFF:# A000-BFFF - if self.ram_flag == 0x0C: - return self.ram_value - elif self.ram_flag == 0x0D: - return 0x01 - elif self.ram_flag == 0x0A or self.ram_flag == 0x00: - if self.ram_size > 0: - return self.ram[self.ram_bank + (address & 0x1FFF)] & 0xFF - raise Exception("Huc3 read error") + # A000-BFFF + if address >= 0xA000 and address <= 0xBFFF: + return self.read_ram_or_flag(address) else: return MBC.read(self, address) + + def read_ram_or_flag(self, address): + if self.ram_flag == 0x0C: + return self.ram_value + elif self.ram_flag == 0x0D: + return 0x01 + elif self.ram_flag == 0x0A or self.ram_flag == 0x00 and \ + self.ram_size > 0: + return self.ram[self.ram_bank + (address & 0x1FFF)] + raise InvalidMemoryAccessException("Huc3 read error") def write(self, address, data): - address = int(address) - if address <= 0x1FFF: # 0000-1FFF + # 0000-1FFF + if address <= 0x1FFF: self.ram_flag = data - elif address <= 0x3FFF:# 2000-3FFF + # 2000-3FFF + elif address <= 0x3FFF: self.write_rom_bank(address, data) - elif address <= 0x5FFF: # 4000-5FFF + # 4000-5FFF + elif address <= 0x5FFF: self.ram_bank = ((data & 0x0F) << 13) & self.ram_size - elif address >= 0xA000 and address <= 0xBFFF: # A000-BFFF + # A000-BFFF + elif address >= 0xA000 and address <= 0xBFFF: self.write_ram_flag(address, data) def write_rom_bank(self, address, data): @@ -699,26 +761,25 @@ self.ram[self.ram_bank + (address & 0x1FFF)] = data def write_with_ram_flag_0x0B(self, address, data): - if (data & 0xF0) == 0x10: + compare = data & 0xF0 + if self.clock_shift > 24 and data != 0x60: + return + if compare == 0x10: self.write_ram_value_clock_shift(address, data) - elif (data & 0xF0) == 0x30: + elif compare == 0x30: self.write_clock_register_clock_shift(address, data) - elif (data & 0xF0) == 0x40: + elif compare == 0x40: self.write_clock_shift(address, data) - elif (data & 0xF0) == 0x50: + elif compare == 0x50: pass - elif (data & 0xF0) == 0x60: + elif compare == 0x60: self.ram_value = 0x01 def write_ram_value_clock_shift(self, address, data): - if self.clock_shift > 24: - return self.ram_value = (self.clock_register >> self.clock_shift) & 0x0F self.clock_shift += 4 def write_clock_register_clock_shift(self, address, data): - if self.clock_shift > 24: - return self.clock_register &= ~(0x0F << self.clock_shift) self.clock_register |= ((data & 0x0F) << self.clock_shift) self.clock_shift += 4 @@ -737,21 +798,19 @@ now = self.clock.get_time() elapsed = now - self.clock_time # years (4 bits) - while elapsed >= 365246060: - self.clock_register += 1 << 24 - elapsed -= 365246060 + years = int(math.floor(elapsed / (365*24*60*60))) + elapsed -= years*365*24*60*60 # days (12 bits) - while elapsed >= 246060: - self.clock_register += 1 << 12 - elapsed -= 246060 + days = int(math.floor(elapsed / (24*60*60))) + elapsed -= days*24*60*60 # minutes (12 bits) - while elapsed >= 60: - self.clock_register += 1 - elapsed -= 60 - if (self.clock_register & 0x0000FFF) >= 2460: - self.clock_register += (1 << 12) - 2460 - if (self.clock_register & 0x0FFF000) >= (365 << 12): - self.clock_register += (1 << 24) - (365 << 12) + minutes = int(math.floor(elapsed / 60)) + elapsed -= minutes*60 + + self.clock_register |= years << 24 + self.clock_register |= days << 12 + self.clock_register |= minutes + self.clock_time = now - elapsed Modified: pypy/branch/build-external/pypy/lang/gameboy/constants.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/constants.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/constants.py Tue Jun 10 12:48:46 2008 @@ -9,53 +9,53 @@ GAMEBOY_SCREEN_WIDTH = 160 GAMEBOY_SCREEN_HEIGHT = 144 + #___________________________________________________________________________ # CATRIGE TYPES # ___________________________________________________________________________ +TYPE_ROM_ONLY = 0x00 -TYPE_ROM_ONLY = 0x00 - -TYPE_MBC1 = 0x01 -TYPE_MBC1_RAM = 0x02 -TYPE_MBC1_RAM_BATTERY = 0x03 - -TYPE_MBC2 = 0x05 -TYPE_MBC2_BATTERY = 0x06 - -TYPE_MBC3_RTC_BATTERY = 0x0F -TYPE_MBC3_RTC_RAM_BATTERY = 0x10 -TYPE_MBC3 = 0x11 -TYPE_MBC3_RAM = 0x12 -TYPE_MBC3_RAM_BATTERY = 0x13 - -TYPE_MBC5 = 0x19 -TYPE_MBC5_RAM = 0x1A -TYPE_MBC5_RAM_BATTERY = 0x1B +TYPE_MBC1 = 0x01 +TYPE_MBC1_RAM = 0x02 +TYPE_MBC1_RAM_BATTERY = 0x03 + +TYPE_MBC2 = 0x05 +TYPE_MBC2_BATTERY = 0x06 + +TYPE_MBC3_RTC_BATTERY = 0x0F +TYPE_MBC3_RTC_RAM_BATTERY = 0x10 +TYPE_MBC3 = 0x11 +TYPE_MBC3_RAM = 0x12 +TYPE_MBC3_RAM_BATTERY = 0x13 + +TYPE_MBC5 = 0x19 +TYPE_MBC5_RAM = 0x1A +TYPE_MBC5_RAM_BATTERY = 0x1B TYPE_MBC5_RUMBLE = 0x1C -TYPE_MBC5_RUMBLE_RAM = 0x1D +TYPE_MBC5_RUMBLE_RAM = 0x1D TYPE_MBC5_RUMBLE_RAM_BATTERY = 0x1E -TYPE_HUC3_RTC_RAM = 0xFE -TYPE_HUC1_RAM_BATTERY = 0xFF +TYPE_HUC3_RTC_RAM = 0xFE +TYPE_HUC1_RAM_BATTERY = 0xFF -CARTRIDGE_TYPE_ADDRESS = 0x0147 -CARTRIDGE_ROM_SIZE_ADDRESS = 0x0148 -CARTRIDGE_RAM_SIZE_ADDRESS = 0x0149 -CARTRIDGE_RAM_SIZE_MAPPING = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768} -DESTINATION_CODE_ADDRESS = 0x014A -LICENSEE_ADDRESS = 0x014B -ROM_VERSION_ADDRESS = 0x014C -HEADER_CHECKSUM_ADDRESS = 0x014D -CHECKSUM_A_ADDRESS = 0x014E -CHECKSUM_B_ADDRESS = 0x014F +CARTRIDGE_TYPE_ADDRESS = 0x0147 +CARTRIDGE_ROM_SIZE_ADDRESS = 0x0148 +CARTRIDGE_RAM_SIZE_ADDRESS = 0x0149 +CARTRIDGE_RAM_SIZE_MAPPING = {0x00:0, 0x01:8192, 0x02:8192, 0x03:32768} +DESTINATION_CODE_ADDRESS = 0x014A +LICENSEE_ADDRESS = 0x014B +ROM_VERSION_ADDRESS = 0x014C +HEADER_CHECKSUM_ADDRESS = 0x014D +CHECKSUM_A_ADDRESS = 0x014E +CHECKSUM_B_ADDRESS = 0x014F # ROM Bank Size (16KB) -ROM_BANK_SIZE = 0x4000 +ROM_BANK_SIZE = 0x4000 # constants.RAM Bank Size (8KB) -RAM_BANK_SIZE = 0x2000 +RAM_BANK_SIZE = 0x2000 CARTRIDGE_FILE_EXTENSION = ".gb" CARTRIDGE_COLOR_FILE_EXTENSION = ".gbc" @@ -65,13 +65,13 @@ # CPU FLAGS # ___________________________________________________________________________ -Z_FLAG = 0x80 -N_FLAG = 0x40 -H_FLAG = 0x20 -C_FLAG = 0x10 +Z_FLAG = 0x80 +N_FLAG = 0x40 +H_FLAG = 0x20 +C_FLAG = 0x10 RESET_A = 0x01 -#RESET_F = 0xB0 +#RESET_F = 0xB0 RESET_F = 0x80 RESET_BC = 0x0013 RESET_DE = 0x00D8 @@ -81,12 +81,12 @@ # ___________________________________________________________________________ -#INTERRUP FLAGS +#INTERRUPT FLAGS # ___________________________________________________________________________ # Interrupt Registers -IE = 0xFFFF # Interrupt Enable -IF = 0xFF0F # Interrupt Flag +IE = 0xFFFF # Interrupt Enable +IF = 0xFF0F # Interrupt Flag # Interrupt Flags VBLANK = 0x01 # V-Blank Interrupt (INT 40h) @@ -101,47 +101,47 @@ # ___________________________________________________________________________ # LCD Register Addresses -LCDC = 0xFF40 # LCD Control */ -STAT = 0xFF41 # LCD Status */ -SCY = 0xFF42 # BG Scroll Y (0-255) */ -SCX = 0xFF43 # BG Scroll X (0-255) */ -LY = 0xFF44 # LCDC Y-Coordinate (0-153) */ -LYC = 0xFF45 # LY Compare */ -DMA = 0xFF46 # OAM DMA Transfer */ -BGP = 0xFF47 # BG Palette Data */ -OBP0 = 0xFF48 # Object Palette 0 Data */ -OBP1 = 0xFF49 # Object Palette 1 Data */ -WY = 0xFF4A # Window Y Position (0-143) */ -WX = 0xFF4B # Window X Position (0-166) */ +LCDC = 0xFF40 # LCD Control +STAT = 0xFF41 # LCD Status +SCY = 0xFF42 # BG Scroll Y (0-255) +SCX = 0xFF43 # BG Scroll X (0-255) +LY = 0xFF44 # LCDC Y-Coordinate (0-153) +LYC = 0xFF45 # LY Compare +DMA = 0xFF46 # OAM DMA Transfer +BGP = 0xFF47 # BG Palette Data +OBP0 = 0xFF48 # Object Palette 0 Data +OBP1 = 0xFF49 # Object Palette 1 Data +WY = 0xFF4A # Window Y Position (0-143) +WX = 0xFF4B # Window X Position (0-166) # OAM Register Addresses -OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) */ -OAM_SIZE = 0xA0 +OAM_ADDR = 0xFE00 # OAM Object Attribute Map (FE00..FE9F) +OAM_SIZE = 0xA0 # Video RAM Addresses -VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) */ -VRAM_SIZE = 0x2000 +VRAM_ADDR = 0x8000 # 8KB Video RAM (8000..9FFF) +VRAM_SIZE = 0x2000 # VRAM Tile Data/Maps Addresses -VRAM_DATA_A = 0x0000 # 4KB Tile Data (8000..8FFF) */ -VRAM_DATA_B = 0x0800 # 4KB Tile Data (8800..97FF) */ +VRAM_DATA_A = 0x0000 # 4KB Tile Data (8000..8FFF) +VRAM_DATA_B = 0x0800 # 4KB Tile Data (8800..97FF) -VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) */ -VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) */ +VRAM_MAP_A = 0x1800 # 1KB BG Tile Map 0 (9800..9BFF) +VRAM_MAP_B = 0x1C00 # 1KB BG Tile Map 1 (9C00..9FFF) #LCD Mode Durations -MODE_0_TICKS = 50 # H-Blank */ -MODE_1_TICKS = 114 # V-Blank */ +MODE_0_TICKS = 50 # H-Blank +MODE_1_TICKS = 114 # V-Blank MODE_2_TICKS = 20 # OAM#/ -MODE_3_BEGIN_TICKS = 12 # Display */ -MODE_3_END_TICKS = 32 # Display */ +MODE_3_BEGIN_TICKS = 12 # Display +MODE_3_END_TICKS = 32 # Display -MODE_1_BEGIN_TICKS = 8 # V-Blank Line 144 */ -MODE_1_END_TICKS = 1 # V-Blank Line 153 */ +MODE_1_BEGIN_TICKS = 8 # V-Blank Line 144 +MODE_1_END_TICKS = 1 # V-Blank Line 153 # Objects per Line -OBJECTS_PER_LINE = 10 +OBJECTS_PER_LINE = 10 # LCD Color Palette COLOR_MAP =[ @@ -157,11 +157,11 @@ # ___________________________________________________________________________ # Joypad Registers P+ -JOYP = 0xFF00 +JOYP = 0xFF00 # Joypad Poll Speed (64 Hz) -JOYPAD_CLOCK = GAMEBOY_CLOCK >> 6 +JOYPAD_CLOCK = GAMEBOY_CLOCK >> 6 BUTTON_DOWN = 0x08 @@ -181,14 +181,14 @@ # ___________________________________________________________________________ # Serial Clock Speed (8 x 1024 bits/sec) -SERIAL_CLOCK = GAMEBOY_CLOCK >> 16 +SERIAL_CLOCK = GAMEBOY_CLOCK >> 16 # Serial Idle Speed (128 Hz) SERIAL_IDLE_CLOCK = GAMEBOY_CLOCK >> 7 # Serial Register Addresses -SB = 0xFF01 # Serial Transfer Data -SC = 0xFF02 # Serial Transfer Control +SERIAL_TRANSFER_DATA = 0xFF01 +SERIAL_TRANSFER_CONTROL = 0xFF02 @@ -201,31 +201,31 @@ SOUND_CLOCK = 256 # Sound Register Addresses -NR10 = 0xFF10 # AUD1SWEEP */ -NR11 = 0xFF11 # AUD1LEN */ -NR12 = 0xFF12 # AUD1ENV */ -NR13 = 0xFF13 # AUD1LOW */ -NR14 = 0xFF14 # AUD1HIGH */ - -NR21 = 0xFF16 # AUD2LEN */ -NR22 = 0xFF17 # AUD2ENV */ -NR23 = 0xFF18 # AUD2LOW */ -NR24 = 0xFF19 # AUD2HIGH */ - -NR30 = 0xFF1A # AUD3ENA */ -NR31 = 0xFF1B # AUD3LEN */ -NR32 = 0xFF1C # AUD3LEVEL */ -NR33 = 0xFF1D # AUD3LOW */ -NR34 = 0xFF1E # AUD3HIGH */ - -NR41 = 0xFF20 # AUD4LEN */ -NR42 = 0xFF21 # AUD4ENV */ -NR43 = 0xFF22 # AUD4POLY */ -NR44 = 0xFF23 # AUD4GO */ - -NR50 = 0xFF24 # AUDVOL */ -NR51 = 0xFF25 # AUDTERM */ -NR52 = 0xFF26 # AUDENA */ +NR10 = 0xFF10 # AUD1SWEEP +NR11 = 0xFF11 # AUD1LEN +NR12 = 0xFF12 # AUD1ENV +NR13 = 0xFF13 # AUD1LOW +NR14 = 0xFF14 # AUD1HIGH + +NR21 = 0xFF16 # AUD2LEN +NR22 = 0xFF17 # AUD2ENV +NR23 = 0xFF18 # AUD2LOW +NR24 = 0xFF19 # AUD2HIGH + +NR30 = 0xFF1A # AUD3ENA +NR31 = 0xFF1B # AUD3LEN +NR32 = 0xFF1C # AUD3LEVEL +NR33 = 0xFF1D # AUD3LOW +NR34 = 0xFF1E # AUD3HIGH + +NR41 = 0xFF20 # AUD4LEN +NR42 = 0xFF21 # AUD4ENV +NR43 = 0xFF22 # AUD4POLY +NR44 = 0xFF23 # AUD4GO + +NR50 = 0xFF24 # AUDVOL +NR51 = 0xFF25 # AUDTERM +NR52 = 0xFF26 # AUDENA AUD3WAVERAM = 0xFF30 Modified: pypy/branch/build-external/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/cpu.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/cpu.py Tue Jun 10 12:48:46 2008 @@ -2,13 +2,23 @@ from pypy.lang.gameboy import constants from pypy.lang.gameboy.ram import * from pypy.lang.gameboy.interrupt import * +from pypy.lang.gameboy.debug import * +# --------------------------------------------------------------------------- -class iRegister(object): +def process_2_complement(value): + # check if the left most bit is set + if (value >> 7) == 1: + return -((~value) & 0xFF) - 1 + else : + return value +# --------------------------------------------------------------------------- + +class AbstractRegister(object): def get(self, use_cycles=True): return 0xFF -class Register(iRegister): +class Register(AbstractRegister): def __init__(self, cpu, value=0): assert isinstance(cpu, CPU) @@ -29,21 +39,14 @@ return self.value def add(self, value, use_cycles=True): - value = self.process_2_complement(value) self.set(self.get(use_cycles)+value, use_cycles) def sub(self, value, use_cycles=True): self.set(self.get(use_cycles)-value, use_cycles) - def process_2_complement(self, value): - # check if the left most bit is set - if (value >> 7) == 1: - return -(~value) & 0xFF-1 - else : - return value #------------------------------------------------------------------------------ -class DoubleRegister(iRegister): +class DoubleRegister(AbstractRegister): def __init__(self, cpu, hi, lo, reset_value=0): assert isinstance(cpu, CPU) @@ -94,19 +97,10 @@ self.cpu.cycles -= 1 def add(self, value, use_cycles=True): - value = self.process_2_complement(value) self.set(self.get(use_cycles) + value, use_cycles=use_cycles) if use_cycles: self.cpu.cycles -= 2 - def process_2_complement(self, value): - if value > 0xFF: - return value - # check if the left most bit is set - elif (value >> 7) == 1: - return -((~value) & 0xFF)-1 - else : - return value # ------------------------------------------------------------------------------ @@ -133,7 +127,7 @@ def __init__(self, cpu, reset_value): assert isinstance(cpu, CPU) - self.cpu = cpu + self.cpu = cpu self.reset_value = reset_value self.reset() @@ -157,7 +151,7 @@ self.lower = 0x00 def get(self, use_cycles=True): - value = 0 + value = 0 value += (int(self.c_flag) << 4) value += (int(self.h_flag) << 5) value += (int(self.n_flag) << 6) @@ -169,7 +163,7 @@ self.h_flag = bool(value & (1 << 5)) self.n_flag = bool(value & (1 << 6)) self.z_flag = bool(value & (1 << 7)) - self.lower = value & 0x0F + self.lower = value & 0x0F if use_cycles: self.cpu.cycles -= 1 @@ -202,9 +196,9 @@ class CPU(object): """ - PyBoy GameBoy (TM) Emulator + PyGIRL GameBoy (TM) Emulator - Central Unit ProcessOR (Sharp LR35902 CPU) + Central Unit Processor_a (Sharp LR35902 CPU) """ def __init__(self, interrupt, memory): assert isinstance(interrupt, Interrupt) @@ -218,36 +212,36 @@ self.reset() def ini_registers(self): - self.b = Register(self) - self.c = Register(self) - self.bc = DoubleRegister(self, self.b, self.c, constants.RESET_BC) - - self.d = Register(self) - self.e = Register(self) - self.de = DoubleRegister(self, self.d, self.e, constants.RESET_DE) - - self.h = Register(self) - self.l = Register(self) - self.hl = DoubleRegister(self, self.h, self.l, constants.RESET_HL) + self.b = Register(self) + self.c = Register(self) + self.bc = DoubleRegister(self, self.b, self.c, constants.RESET_BC) + + self.d = Register(self) + self.e = Register(self) + self.de = DoubleRegister(self, self.d, self.e, constants.RESET_DE) + + self.h = Register(self) + self.l = Register(self) + self.hl = DoubleRegister(self, self.h, self.l, constants.RESET_HL) self.hli = ImmediatePseudoRegister(self, self.hl) self.pc = DoubleRegister(self, Register(self), Register(self), reset_value=constants.RESET_PC) self.sp = DoubleRegister(self, Register(self), Register(self), reset_value=constants.RESET_SP) - self.a = Register(self, constants.RESET_A) - self.f = FlagRegister(self, constants.RESET_F) - self.af = DoubleRegister(self, self.a, self.f) + self.a = Register(self, constants.RESET_A) + self.f = FlagRegister(self, constants.RESET_F) + self.af = DoubleRegister(self, self.a, self.f) def reset(self): self.reset_registers() self.f.reset() self.f.z_flag = True - self.ime = False - self.halted = False - self.cycles = 0 - self.instruction_counter = 0 - self.last_op_code = -1 + self.ime = False + self.halted = False + self.cycles = 0 + self.instruction_counter = 0 + self.last_op_code = -1 self.last_fetch_execute_op_code = -1 def reset_registers(self): @@ -352,26 +346,28 @@ def emulate(self, ticks): self.cycles += ticks - self.handle_pending_interrupt() + self.handle_pending_interrupts() while self.cycles > 0: self.execute(self.fetch()) def emulate_step(self): - self.handle_pending_interrupt() + self.handle_pending_interrupts() self.execute(self.fetch()) - def handle_pending_interrupt(self): - # Interrupts + def handle_pending_interrupts(self): if self.halted: - if self.interrupt.is_pending(): - self.halted = False - self.cycles -= 4 - elif (self.cycles > 0): - self.cycles = 0 + self.update_interrupt_cycles() if self.ime and self.interrupt.is_pending(): self.lower_pending_interrupt() + def update_interrupt_cycles(self): + if self.interrupt.is_pending(): + self.halted = False + self.cycles -= 4 + elif (self.cycles > 0): + self.cycles = 0 + def lower_pending_interrupt(self): for flag in self.interrupt.interrupt_flags: if flag.is_pending(): @@ -381,16 +377,17 @@ return def fetch_execute(self): - # Execution opCode = self.fetch() #print " fetch exe:", hex(opCode), " " #, FETCH_EXECUTE_OP_CODES[opCode].__name__ self.last_fetch_execute_op_code = opCode + if DEBUG: log(opCode, is_fetch_execute=True) FETCH_EXECUTE_OP_CODES[opCode](self) def execute(self, opCode): self.instruction_counter += 1 + if DEBUG: log(opCode) #print self.instruction_counter, "-"*60 #print "exe: ", hex(opCode), " " #, OP_CODES[opCode].__name__ @@ -474,8 +471,7 @@ def call(self, address, use_cycles=True): # 4 cycles - self.push(self.pc.get_hi(use_cycles), use_cycles) # 2 cycles - self.push(self.pc.get_lo(use_cycles), use_cycles) # 2 cycles + self.push_double_register(self.pc, use_cycles) self.pc.set(address, use_cycles=use_cycles) # 1 cycle if use_cycles: self.cycles += 1 @@ -489,63 +485,57 @@ def store_hl_in_pc(self): # LD PC,HL, 1 cycle - self.ld(DoubleRegisterCallWrapper(self.hl), \ + self.ld(DoubleRegisterCallWrapper(self.hl), DoubleRegisterCallWrapper(self.pc)) def fetch_load(self, getCaller, setCaller): self.ld(CPUFetchCaller(self), setCaller) def add_a(self, getCaller, setCaller=None): + data = getCaller.get() # ALU, 1 cycle - added = (self.a.get() + getCaller.get()) & 0xFF - self.f.reset() - self.f.z_flag_compare(added) - self.f.h_flag_compare(added, self.a.get(), inverted=True) - self.f.c_flag = (added < self.a.get()) - self.a.set(added) # 1 cycle + added = (self.a.get() + data) & 0xFF + self.add_sub_flag_finish(added, data) def add_hl(self, register): # 2 cycles - a=1 - added = (self.hl.get() + register.get()) & 0xFFFF # 1 cycle + data = register.get() + added = (self.hl.get() + data) # 1 cycle self.f.partial_reset(keep_z=True) - self.f.h_flag_compare((added >> 8), self.hl.get()) - self.f.c_flag_compare(added, self.hl.get()) - self.hl.set(added) + if ((added ^ self.hl.get() ^ data) & 0x1000) != 0: + self.f.h_flag = True + self.f.c_flag = (added >= 0x10000 or added < 0) + self.hl.set(added & 0xFFFF) self.cycles -= 1 - def add_with_carry(self, getCaller, setCaller=None): + def add_a_with_carry(self, getCaller, setCaller=None): # 1 cycle data = getCaller.get() - s = self.a.get() + data - if self.f.c_flag: - s +=1 - self.carry_flag_finish(s,data) + s = self.a.get() + data + int(self.f.c_flag) + self.add_sub_flag_finish(s,data) - def subtract_with_carry(self, getCaller, setCaller=None): + def subtract_with_carry_a(self, getCaller, setCaller=None): # 1 cycle data = getCaller.get() - s = self.a.get() - data - if self.f.c_flag: - s -= 1 - self.carry_flag_finish(s, data) + s = self.a.get() - data - int(self.f.c_flag) + self.add_sub_flag_finish(s, data) self.f.n_flag = True - def carry_flag_finish(self, s, data): + def add_sub_flag_finish(self, s, data): self.f.reset() - # set the hflag if the 0x10 bit was affected + # set the h flag if the 0x10 bit was affected if ((s ^ self.a.get() ^ data) & 0x10) != 0: self.f.h_flag = True - if s >= 0x100: - self.f.c_flag= True + self.f.c_flag = (s >= 0x100 or s < 0) self.f.z_flag_compare(s) - self.a.set(s) # 1 cycle + self.a.set(s & 0xFF) # 1 cycle def subtract_a(self, getCaller, setCaller=None): # 1 cycle - self.compare_a(getCaller) # 1 cycle - self.a.sub(getCaller.get(use_cycles=False), False) - + data = getCaller.get() + self.compare_a_simple(data) + self.a.sub(data, False) + def fetch_subtract_a(self): data = self.fetch() # 1 cycle @@ -554,10 +544,10 @@ def compare_a(self, getCaller, setCaller=None): # 1 cycle - self.compare_a_simple(self.a.get() - getCaller.get()) + self.compare_a_simple(getCaller.get()) def compare_a_simple(self, s): - s = s & 0xFF + s = (self.a.get() - s) & 0xFF self.f.reset() self.f.n_flag = True self.f.z_flag_compare(s) @@ -567,30 +557,33 @@ def hc_flag_finish(self, data): if data > self.a.get(): self.f.c_flag = True - #self.f.c_flag_compare(data, self.a.get()) self.f.h_flag_compare(data, self.a.get()) - def AND(self, getCaller, setCaller=None): + def and_a(self, getCaller, setCaller=None): # 1 cycle self.a.set(self.a.get() & getCaller.get()) # 1 cycle - self.f.z_flag_compare(self.a.get(), reset=True) + self.f.reset() + self.f.z_flag_compare(self.a.get()) + self.f.h_flag = True - def XOR(self, getCaller, setCaller=None): + def xor_a(self, getCaller, setCaller=None): # 1 cycle self.a.set( self.a.get() ^ getCaller.get()) # 1 cycle self.f.z_flag_compare(self.a.get(), reset=True) - def OR(self, getCaller, setCaller=None): + def or_a(self, getCaller, setCaller=None): # 1 cycle self.a.set(self.a.get() | getCaller.get()) # 1 cycle self.f.z_flag_compare(self.a.get(), reset=True) - def inc_double_register(self, doubleRegister): - self.inc(doubleRegister.get, doubleRegister.set) - - def dec_double_register(self, doubleRegister): - self.dec(doubleRegister.get, doubleRegister.set) - + def inc_double_register(self, register): + # INC rr + register.inc() + + def dec_double_register(self, register): + # DEC rr + register.dec() + def inc(self, getCaller, setCaller): # 1 cycle data = (getCaller.get() + 1) & 0xFF @@ -611,72 +604,74 @@ def rotate_left_circular(self, getCaller, setCaller): # RLC 1 cycle data = getCaller.get() - s = (data << 1) + (data >> 7) - self.flags_and_setter_finish(s, setCaller, 0x80) + s = ((data << 1) & 0xFF) + ((data & 0x80) >> 7) + self.flags_and_setter_finish(s, data, setCaller, 0x80) #self.cycles -= 1 def rotate_left_circular_a(self): # RLCA rotate_left_circular_a 1 cycle - self.rotate_left_circular(RegisterCallWrapper(self.a), \ + self.rotate_left_circular(RegisterCallWrapper(self.a), RegisterCallWrapper(self.a)) def rotate_left(self, getCaller, setCaller): # 1 cycle - s = (getCaller.get() << 1) & 0xFF - if self.f.c_flag: - s += 0x01 - self.flags_and_setter_finish(s, setCaller, 0x80) # 1 cycle + data = getCaller.get() + s = ((data & 0x7F) << 1) + int(self.f.c_flag) + self.flags_and_setter_finish(s, data, setCaller, 0x80) # 1 cycle def rotate_left_a(self): # RLA 1 cycle - self.rotate_left(RegisterCallWrapper(self.a), \ + self.rotate_left(RegisterCallWrapper(self.a), RegisterCallWrapper(self.a)) def rotate_right_circular(self, getCaller, setCaller): data = getCaller.get() # RRC 1 cycle s = (data >> 1) + ((data & 0x01) << 7) - self.flags_and_setter_finish(s, setCaller) # 1 cycle + self.flags_and_setter_finish(s, data, setCaller) # 1 cycle def rotate_right_circular_a(self): # RRCA 1 cycle - self.rotate_right_circular(RegisterCallWrapper(self.a), \ + self.rotate_right_circular(RegisterCallWrapper(self.a), RegisterCallWrapper(self.a)) def rotate_right(self, getCaller, setCaller): # 1 cycle - s = (getCaller.get() >> 1) + data = getCaller.get() + s = (data >> 1) if self.f.c_flag: - s += 0x08 - self.flags_and_setter_finish(s, setCaller) # 1 cycle + s += 0x80 + self.flags_and_setter_finish(s, data, setCaller) # 1 cycle def rotate_right_a(self): # RRA 1 cycle - self.rotate_right(RegisterCallWrapper(self.a), \ + self.rotate_right(RegisterCallWrapper(self.a), RegisterCallWrapper(self.a)) - + def shift_left_arithmetic(self, getCaller, setCaller): # 2 cycles - s = (getCaller.get() << 1) & 0xFF - self.flags_and_setter_finish(s, setCaller, 0x80) # 1 cycle + data = getCaller.get() + s = (data << 1) & 0xFF + self.flags_and_setter_finish(s, data, setCaller, 0x80) # 1 cycle def shift_right_arithmetic(self, getCaller, setCaller): data = getCaller.get() # 1 cycle s = (data >> 1) + (data & 0x80) - self.flags_and_setter_finish(s, setCaller) # 1 cycle + self.flags_and_setter_finish(s, data, setCaller) # 1 cycle def shift_word_right_logical(self, getCaller, setCaller): # 2 cycles - s = (getCaller.get() >> 1) - self.flags_and_setter_finish(s, setCaller) # 2 cycles - - def flags_and_setter_finish(self, s, setCaller, compare_and=0x01): + data = getCaller.get() + s = (data >> 1) + self.flags_and_setter_finish(s, data, setCaller) # 2 cycles + + def flags_and_setter_finish(self, s, data, setCaller, compare_and=0x01): # 2 cycles s &= 0xFF self.f.reset() self.f.z_flag_compare(s) - self.f.c_flag_compare(s, compare_and) + self.f.c_flag_compare(data, compare_and) setCaller.set(s) # 1 cycle def swap(self, getCaller, setCaller): @@ -686,6 +681,7 @@ self.f.z_flag_compare(s, reset=True) setCaller.set(s) + def test_bit(self, getCaller, setCaller, n): # 2 cycles self.f.partial_reset(keep_c=True) @@ -786,7 +782,7 @@ self.f.n_flag = True self.f.h_flag = True - def decimal_adjust_accumulator(self): + def decimal_adjust_a(self): # DAA 1 cycle delta = 0 if self.is_h(): @@ -808,14 +804,6 @@ self.f.c_flag = True self.f.z_flag_compare(self.a.get()) - def inc_double_register(self, register): - # INC rr - register.inc() - - def dec_double_register(self, register): - # DEC rr - register.dec() - def increment_sp_by_fetch(self): # ADD SP,nn 4 cycles self.sp.set(self.get_fetchadded_sp()) # 1+1 cycle @@ -828,7 +816,7 @@ def get_fetchadded_sp(self): # 1 cycle - offset = self.process_2_complement(self.fetch()) # 1 cycle + offset = process_2_complement(self.fetch()) # 1 cycle s = (self.sp.get() + offset) & 0xFFFF self.f.reset() if (offset >= 0): @@ -843,12 +831,6 @@ self.f.h_flag = True return s - def process_2_complement(self, value): - # check if the left most bit is set - if (value >> 7) == 1: - return -((~value) & 0xFF)-1 - else : - return value def complement_carry_flag(self): # CCF/SCF @@ -863,7 +845,7 @@ # NOP 1 cycle self.cycles -= 1 - def unconditional_jump(self): + def jump(self): # JP nnnn, 4 cycles self.pc.set(self.fetch_double_address()) # 1+2 cycles self.cycles -= 1 @@ -871,20 +853,19 @@ def conditional_jump(self, cc): # JP cc,nnnn 3,4 cycles if cc: - self.unconditional_jump() # 4 cycles + self.jump() # 4 cycles else: self.pc.add(2) # 3 cycles - def relative_unconditional_jump(self): + def relative_jump(self): # JR +nn, 3 cycles - #pc = pc & 0xFF00 + ((pc & 0x00FF) + add) & 0xFF - self.pc.add(self.process_2_complement(self.fetch())) # 3 + 1 cycles + self.pc.add(process_2_complement(self.fetch())) # 3 + 1 cycles self.cycles += 1 def relative_conditional_jump(self, cc): # JR cc,+nn, 2,3 cycles if cc: - self.relative_unconditional_jump() # 3 cycles + self.relative_jump() # 3 cycles else: self.pc.inc() # 2 cycles @@ -926,14 +907,14 @@ def disable_interrups(self): # DI/EI 1 cycle - self.ime = False + self.ime = False self.cycles -= 1 def enable_interrupts(self): # 1 cycle self.ime = True self.execute(self.fetch()) # 1 - self.handle_pending_interrupt() + self.handle_pending_interrupts() def halt(self): # HALT/STOP @@ -941,7 +922,7 @@ # emulate bug when interrupts are pending if not self.ime and self.interrupt.is_pending(): self.execute(self.memory.read(self.pc.get())) - self.handle_pending_interrupt() + self.handle_pending_interrupts() def stop(self): # 0 cycles @@ -953,11 +934,11 @@ class CallWrapper(object): def get(self, use_cycles=True): - raise Exception("called CalLWrapper.get") + raise Exception("called CallWrapper.get") return 0 def set(self, value, use_cycles=True): - raise Exception("called CalLWrapper.set") + raise Exception("called CallWrapper.set") pass class NumberCallWrapper(CallWrapper): @@ -969,7 +950,7 @@ return self.number def set(self, value, use_cycles=True): - raise Exception("called CalLWrapper.set") + raise Exception("called CallWrapper.set") pass class RegisterCallWrapper(CallWrapper): @@ -1009,18 +990,10 @@ def get(self, use_cycles=True): return self.cpu.fetch(use_cycles) -# ------------------------------------------------------------------------------ # OPCODE LOOKUP TABLE GENERATION ----------------------------------------------- - -GROUPED_REGISTERS = [CPU.get_b, - CPU.get_c, - CPU.get_d, - CPU.get_e, - CPU.get_h, - CPU.get_l, - CPU.get_hli, - CPU.get_a] +GROUPED_REGISTERS = [CPU.get_b, CPU.get_c, CPU.get_d, CPU.get_e, + CPU.get_h, CPU.get_l, CPU.get_hli, CPU.get_a] def create_group_op_codes(table): opCodes =[] @@ -1049,13 +1022,11 @@ def group_lambda(function, register_getter, value=None): if value is None: - def f(s): function(s, RegisterCallWrapper(register_getter(s)), \ + return lambda s: function(s, RegisterCallWrapper(register_getter(s)), RegisterCallWrapper(register_getter(s))) else: - def f(s): function(s, RegisterCallWrapper(register_getter(s)), \ + return lambda s: function(s, RegisterCallWrapper(register_getter(s)), RegisterCallWrapper(register_getter(s)), value) - f.__name__ += function.__name__ - return f def create_load_group_op_codes(): opCodes = [] @@ -1068,10 +1039,8 @@ return opCodes def load_group_lambda(store_register, load_register): - def f(s): CPU.ld(s, RegisterCallWrapper(load_register(s)), \ + return lambda s: CPU.ld(s, RegisterCallWrapper(load_register(s)), RegisterCallWrapper(store_register(s))) - f.__name__ += "ld" - return f def create_register_op_codes(table): opCodes = [] @@ -1105,12 +1074,12 @@ return result # OPCODE TABLES --------------------------------------------------------------- - +# Table with one to one mapping of simple OP Codes FIRST_ORDER_OP_CODES = [ (0x00, CPU.nop), (0x08, CPU.load_mem_sp), (0x10, CPU.stop), - (0x18, CPU.relative_unconditional_jump), + (0x18, CPU.relative_jump), (0x02, CPU.write_a_at_bc_address), (0x12, CPU.write_a_at_de_address), (0x22, CPU.load_and_increment_hli_a), @@ -1123,7 +1092,7 @@ (0x0F, CPU.rotate_right_circular_a), (0x17, CPU.rotate_left_a), (0x1F, CPU.rotate_right_a), - (0x27, CPU.decimal_adjust_accumulator), + (0x27, CPU.decimal_adjust_a), (0x2F, CPU.complement_a), (0x37, CPU.set_carry_flag), (0x3F, CPU.complement_carry_flag), @@ -1134,7 +1103,7 @@ (0xEA, CPU.store_a_at_fetched_address), (0xF2, CPU.store_expanded_c_in_a), (0xFA, CPU.store_fetched_memory_in_a), - (0xC3, CPU.unconditional_jump), + (0xC3, CPU.jump), (0xC9, CPU.ret), (0xD9, CPU.return_form_interrupt), (0xDD, CPU.debug), @@ -1146,14 +1115,14 @@ (0xF8, CPU.store_fetch_added_sp_in_hl), (0xCB, CPU.fetch_execute), (0xCD, CPU.unconditional_call), - (0xC6, lambda s: CPU.add_a(s, CPUFetchCaller(s))), - (0xCE, lambda s: CPU.add_with_carry(s, CPUFetchCaller(s))), + (0xC6, lambda s: CPU.add_a(s, CPUFetchCaller(s))), + (0xCE, lambda s: CPU.add_a_with_carry(s, CPUFetchCaller(s))), (0xD6, CPU.fetch_subtract_a), - (0xDE, lambda s: CPU.subtract_with_carry(s, CPUFetchCaller(s))), - (0xE6, lambda s: CPU.AND(s, CPUFetchCaller(s))), - (0xEE, lambda s: CPU.XOR(s, CPUFetchCaller(s))), - (0xF6, lambda s: CPU.OR(s, CPUFetchCaller(s))), - (0xFE, lambda s: CPU.compare_a(s, CPUFetchCaller(s))), + (0xDE, lambda s: CPU.subtract_with_carry_a(s, CPUFetchCaller(s))), + (0xE6, lambda s: CPU.and_a(s, CPUFetchCaller(s))), + (0xEE, lambda s: CPU.xor_a(s, CPUFetchCaller(s))), + (0xF6, lambda s: CPU.or_a(s, CPUFetchCaller(s))), + (0xFE, lambda s: CPU.compare_a(s, CPUFetchCaller(s))), (0xC7, lambda s: CPU.restart(s, 0x00)), (0xCF, lambda s: CPU.restart(s, 0x08)), (0xD7, lambda s: CPU.restart(s, 0x10)), @@ -1164,37 +1133,28 @@ (0xFF, lambda s: CPU.restart(s, 0x38)) ] +# Table for RegisterGroup OP Codes: (startAddress, delta, method) REGISTER_GROUP_OP_CODES = [ (0x04, 0x08, CPU.inc), (0x05, 0x08, CPU.dec), (0x06, 0x08, CPU.load_fetch_register), (0x80, 0x01, CPU.add_a), - (0x88, 0x01, CPU.add_with_carry), + (0x88, 0x01, CPU.add_a_with_carry), (0x90, 0x01, CPU.subtract_a), - (0x98, 0x01, CPU.subtract_with_carry), - (0xA0, 0x01, CPU.AND), - (0xA8, 0x01, CPU.XOR), - (0xB0, 0x01, CPU.OR), + (0x98, 0x01, CPU.subtract_with_carry_a), + (0xA0, 0x01, CPU.and_a), + (0xA8, 0x01, CPU.xor_a), + (0xB0, 0x01, CPU.or_a), (0xB8, 0x01, CPU.compare_a), (0x06, 0x08, CPU.fetch_load) ] -REGISTER_SET_A = [CPU.get_bc, - CPU.get_de, - CPU.get_hl, - CPU.get_sp] - -REGISTER_SET_B = [CPU.get_bc, - CPU.get_de, - CPU.get_hl, - CPU.get_af] - -FLAG_REGISTER_SET = [CPU.is_not_z, - CPU.is_z, - CPU.is_not_c, - CPU.is_c] +REGISTER_SET_A = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_sp] +REGISTER_SET_B = [CPU.get_bc, CPU.get_de, CPU.get_hl, CPU.get_af] +FLAG_REGISTER_SET = [CPU.is_not_z, CPU.is_z, CPU.is_not_c, CPU.is_c] +# Table for Register OP Codes: (startAddress, delta, method, regsiters) REGISTER_OP_CODES = [ (0x01, 0x10, CPU.fetch_double_register, REGISTER_SET_A), (0x09, 0x10, CPU.add_hl, REGISTER_SET_A), @@ -1207,7 +1167,7 @@ (0xC1, 0x10, CPU.pop_double_register, REGISTER_SET_B), (0xC5, 0x10, CPU.push_double_register, REGISTER_SET_B) ] - +# Table for Second Order OPCodes: (startAddress, delta, method, [args]) SECOND_ORDER_REGISTER_GROUP_OP_CODES = [ (0x00, 0x01, CPU.rotate_left_circular), (0x08, 0x01, CPU.rotate_right_circular), @@ -1224,11 +1184,12 @@ # RAW OPCODE TABLE INITIALIZATION ---------------------------------------------- -FIRST_ORDER_OP_CODES += create_register_op_codes(REGISTER_OP_CODES) -FIRST_ORDER_OP_CODES += create_group_op_codes(REGISTER_GROUP_OP_CODES) -FIRST_ORDER_OP_CODES += create_load_group_op_codes() -SECOND_ORDER_OP_CODES = create_group_op_codes(SECOND_ORDER_REGISTER_GROUP_OP_CODES) +FIRST_ORDER_OP_CODES += create_register_op_codes(REGISTER_OP_CODES) +FIRST_ORDER_OP_CODES += create_group_op_codes(REGISTER_GROUP_OP_CODES) +FIRST_ORDER_OP_CODES += create_load_group_op_codes() +SECOND_ORDER_OP_CODES = create_group_op_codes(SECOND_ORDER_REGISTER_GROUP_OP_CODES) -OP_CODES = initialize_op_code_table(FIRST_ORDER_OP_CODES) +OP_CODES = initialize_op_code_table(FIRST_ORDER_OP_CODES) FETCH_EXECUTE_OP_CODES = initialize_op_code_table(SECOND_ORDER_OP_CODES) + Modified: pypy/branch/build-external/pypy/lang/gameboy/gameboy.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/gameboy.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/gameboy.py Tue Jun 10 12:48:46 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator GameBoy Scheduler and Memory Mapper @@ -16,7 +16,7 @@ from pypy.lang.gameboy.video import * from pypy.lang.gameboy.cartridge import * - + class GameBoy(object): def __init__(self): @@ -24,22 +24,22 @@ self.create_gamboy_elements() def create_drivers(self): - self.clock = Clock() self.joypad_driver = JoypadDriver() self.video_driver = VideoDriver() self.sound_driver = SoundDriver() def create_gamboy_elements(self): - self.ram = RAM() + self.clock = Clock() + self.ram = RAM() self.cartridge_manager = CartridgeManager(self.clock) self.interrupt = Interrupt() - self.cpu = CPU(self.interrupt, self) - self.serial = Serial(self.interrupt) - self.timer = Timer(self.interrupt) - self.joypad = Joypad(self.joypad_driver, self.interrupt) - self.video = Video(self.video_driver, self.interrupt, self) - #self.sound = Sound(self.sound_driver) - self.sound = BogusSound() + self.cpu = CPU(self.interrupt, self) + self.serial = Serial(self.interrupt) + self.timer = Timer(self.interrupt) + self.joypad = Joypad(self.joypad_driver, self.interrupt) + self.video = Video(self.video_driver, self.interrupt, self) + #self.sound = Sound(self.sound_driver) + self.sound = BogusSound() def get_cartridge_manager(self): return self.cartridge_manager @@ -47,6 +47,7 @@ def load_cartridge(self, cartridge, verify=True): self.cartridge_manager.load(cartridge, verify) self.cpu.set_rom(self.cartridge_manager.get_rom()) + self.memory_bank_controller = self.cartridge_manager.get_memory_bank() def load_cartridge_file(self, path, verify=True): self.load_cartridge(CartridgeFile(path), verify) @@ -58,7 +59,7 @@ self.video.set_frame_skip(frameSkip) def save(self, cartridgeName): - self.cartridge.save(cartridgeName) + self.cartridge_manager.save(cartridgeName) def start(self): self.sound.start() @@ -68,7 +69,7 @@ def reset(self): self.ram.reset() - self.cartridge.reset() + self.memory_bank_controller.reset() self.interrupt.reset() self.cpu.reset() self.serial.reset() @@ -77,12 +78,14 @@ self.video.reset() self.sound.reset() self.cpu.set_rom(self.cartridge_manager.get_rom()) - self.draw_logo() + #self.draw_logo() def get_cycles(self): - return min(min(min(min( self.video.get_cycles(), self.serial.get_cycles()), - self.timer.get_cycles()), self.sound.get_cycles()), - self.joypad.get_cycles()) + return min(min(min(min( self.video.get_cycles(), + self.serial.get_cycles()), + self.timer.get_cycles()), + self.sound.get_cycles()), + self.joypad.get_cycles()) def emulate(self, ticks): while ticks > 0: @@ -122,13 +125,17 @@ def write(self, address, data): receiver = self.get_receiver(address) if receiver is None: + return raise Exception("invalid read address given") receiver.write(address, data) + if address == constants.STAT or address == 0xFFFF: + self.cpu.handle_pending_interrupts() def read(self, address): receiver = self.get_receiver(address) if receiver is None: - raise Exception("invalid read address given") + return 0xFF + #raise Exception("invalid read address given") return receiver.read(address) def print_receiver_msg(self, address, name): @@ -151,7 +158,7 @@ elif 0xFE00 <= address <= 0xFEFF: self.print_receiver_msg(address, "video") return self.video - elif 0xFF00 <= address <= 0xFF00: + elif address == 0xFF00: self.print_receiver_msg(address, "joypad") return self.joypad elif 0xFF01 <= address <= 0xFF02: @@ -160,7 +167,7 @@ elif 0xFF04 <= address <= 0xFF07: self.print_receiver_msg(address, "timer") return self.timer - elif 0xFF0F <= address <= 0xFF0F: + elif address == 0xFF0F: self.print_receiver_msg(address, "interrupt") return self.interrupt elif 0xFF10 <= address <= 0xFF3F: @@ -172,32 +179,28 @@ elif 0xFF80 <= address <= 0xFFFE: self.print_receiver_msg(address, "ram") return self.ram - elif 0xFFFF <= address <= 0xFFFF: + elif address == 0xFFFF: self.print_receiver_msg(address, "interrupt") return self.interrupt def draw_logo(self): for index in range(0, 48): - bits = self.cartridge.read(0x0104 + index) - pattern0 = ((bits >> 0) & 0x80) + ((bits >> 1) & 0x60)\ - + ((bits >> 2) & 0x18) + ((bits >> 3) & 0x06)\ - + ((bits >> 4) & 0x01) - - pattern1 = ((bits << 4) & 0x80) + ((bits << 3) & 0x60)\ - + ((bits << 2) & 0x18) + ((bits << 1) & 0x06)\ - + ((bits << 0) & 0x01) - + bits = self.memory_bank_controller.read(0x0104 + index) + pattern0 = ((bits >> 0) & 0x80) + ((bits >> 1) & 0x60) + \ + ((bits >> 2) & 0x18) + ((bits >> 3) & 0x06) + \ + ((bits >> 4) & 0x01) + pattern1 = ((bits << 4) & 0x80) + ((bits << 3) & 0x60) + \ + ((bits << 2) & 0x18) + ((bits << 1) & 0x06) + \ + ((bits << 0) & 0x01) self.video.write(0x8010 + (index << 3), pattern0) self.video.write(0x8012 + (index << 3), pattern0) - self.video.write(0x8014 + (index << 3), pattern1) self.video.write(0x8016 + (index << 3), pattern1) - for index in range(0, 8): - self.video.write(0x8190 + (index << 1), constants.REGISTERED_BITMAP[index]) - + self.video.write(0x8190 + (index << 1), \ + constants.REGISTERED_BITMAP[index]) for tile in range(0, 12): self.video.write(0x9904 + tile, tile + 1) self.video.write(0x9924 + tile, tile + 13) - self.video.write(0x9905 + 12, 25) + Modified: pypy/branch/build-external/pypy/lang/gameboy/gameboyTest.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/gameboyTest.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/gameboyTest.py Tue Jun 10 12:48:46 2008 @@ -1,4 +1,4 @@ -from pypy.lang.gameboy.gameboyImplementation import * +from pypy.lang.gameboy.gameboy_implementation import * import sys from AppKit import NSApplication Modified: pypy/branch/build-external/pypy/lang/gameboy/interrupt.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/interrupt.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/interrupt.py Tue Jun 10 12:48:46 2008 @@ -5,25 +5,32 @@ class InterruptFlag(object): def __init__(self, _reset, mask, call_code): - self._reset = _reset - self.mask = mask + self._reset = _reset + self.mask = mask self.call_code = call_code self.reset() def reset(self): self._is_pending = self._reset + self.enabled = False def is_pending(self): return self._is_pending def set_pending(self, _is_pending=True): self._is_pending = _is_pending + + def is_enabled(self): + return self.enabled + + def set_enabled(self, enabled): + self.enabled = enabled +# -------------------------------------------------------------------- class Interrupt(iMemory): """ - PyBoy GameBoy (TM) Emulator - + PyGirl GameBoy (TM) Emulator Interrupt Controller """ @@ -34,18 +41,15 @@ self.reset() def create_interrupt_flags(self): - self.v_blank = InterruptFlag(True, constants.VBLANK, 0x40) - self.lcd = InterruptFlag(False, constants.LCD, 0x48) - self.timer = InterruptFlag(False, constants.TIMER, 0x50) + self.vblank = InterruptFlag(True, constants.VBLANK, 0x40) + self.lcd = InterruptFlag(False, constants.LCD, 0x48) + self.timer = InterruptFlag(False, constants.TIMER, 0x50) self.serial = InterruptFlag(False, constants.SERIAL, 0x58) self.joypad = InterruptFlag(False, constants.JOYPAD, 0x60) def create_flag_list(self): - self.interrupt_flags = [ - self.v_blank, self.lcd, - self.timer, self.serial, - self.joypad - ] + self.interrupt_flags = [ self.vblank, self.lcd, self.timer, self.serial, + self.joypad] def create_flag_mask_mapping(self): self.mask_mapping = {} @@ -53,57 +57,54 @@ self.mask_mapping[flag.mask] = flag def reset(self): - self.enable = False + self.set_enable_mask(0x0) for flag in self.interrupt_flags: flag.reset() - - def is_pending(self, mask=None): - if not self.enable: - return False - if mask is None: - return self.v_blank.is_pending() - elif self.v_blank.is_pending(): - return self.mask_mapping[mask].is_pending() - else: - return False - - def raise_interrupt(self, mask): - self.mask_mapping[mask].set_pending(True) - - def lower(self, mask): - self.mask_mapping[mask].set_pending(False) - + + def write(self, address, data): - address = int(address) if address == constants.IE: - self.set_interrupt_enable(data) + self.set_enable_mask(data) elif address == constants.IF: self.set_fnterrupt_flag(data) def read(self, address): - address = int(address) if address == constants.IE: - return self.get_interrupt_enable() + return self.get_enable_mask() elif address == constants.IF: return self.get_interrupt_flag() return 0xFF + + + def is_pending(self, mask=0xFF): + return (self.get_enable_mask() & self.get_interrupt_flag() & mask) != 0 + + def raise_interrupt(self, mask): + self.mask_mapping[mask].set_pending(True) - def get_interrupt_enable(self): - return int(self.enable) + def lower(self, mask): + self.mask_mapping[mask].set_pending(False) + + def get_enable_mask(self): + enabled = 0x00 + for interrupt_flag in self.interrupt_flags: + if interrupt_flag.is_enabled(): + enabled |= interrupt_flag.mask + return enabled | self.enable_rest_data; - def set_interrupt_enable(self, isEnabled=True): - self.enable = bool(isEnabled) + def set_enable_mask(self, enable_mask): + for flag in self.interrupt_flags: + flag.set_enabled((enable_mask & flag.mask) != 0) + self.enable_rest_data = enable_mask & 0xE0; + def get_interrupt_flag(self): flag = 0x00 for interrupt_flag in self.interrupt_flags: if interrupt_flag.is_pending(): flag |= interrupt_flag.mask - return 0xE0 | flag + return flag | 0xE0 def set_fnterrupt_flag(self, data): for flag in self.interrupt_flags: - if (data & flag.mask) != 0: - flag.set_pending(True) - else: - flag.set_pending(False) + flag.set_pending((data & flag.mask) != 0) Modified: pypy/branch/build-external/pypy/lang/gameboy/joypad.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/joypad.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/joypad.py Tue Jun 10 12:48:46 2008 @@ -5,55 +5,53 @@ class Joypad(iMemory): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Joypad Input """ def __init__(self, joypad_driver, interrupt): assert isinstance(joypad_driver, JoypadDriver) - assert isinstance(interrupt, Interrupt ) - self.driver = joypad_driver + assert isinstance(interrupt, Interrupt) + self.driver = joypad_driver self.interrupt = interrupt self.reset() def reset(self): - self.joyp = 0xF - self.button_code = 0xF - self.cycles = constants.JOYPAD_CLOCK + self.read_control = 0xF + self.button_code = 0xF + self.cycles = constants.JOYPAD_CLOCK def get_cycles(self): return self.cycles def emulate(self, ticks): - ticks = int(ticks) self.cycles -= ticks if self.cycles <= 0: if self.driver.is_raised(): self.update() self.cycles = constants.JOYPAD_CLOCK + #self.cycles = 150 def write(self, address, data): - address = int(address) if address == constants.JOYP: - self.joyp = (self.joyp & 0xC) + (data & 0x3) + self.read_control = (self.read_control & 0xC) + ((data & 0x30)>>4) self.update() def read(self, address): - address = int(address) if address == constants.JOYP: - return (self.joyp << 4) + self.button_code + return (self.read_control << 4) + self.button_code return 0xFF def update(self): - oldButtons = self.button_code - if self.joyp == 0x1: + old_buttons = self.button_code + if self.read_control & 0x3 == 1: self.button_code = self.driver.get_button_code() - elif self.joyp == 0x2: + elif self.read_control & 0x3 == 2: self.button_code = self.driver.get_direction_code() - else: + elif self.read_control & 0x3 == 3: self.button_code = 0xF - if oldButtons != self.button_code: + if old_buttons != self.button_code: self.interrupt.raise_interrupt(constants.JOYPAD) @@ -88,8 +86,8 @@ self.right.opposite_button = self.left def create_button_groups(self): - self.directions = [self.up, self.right, self.down, self.left] - self.buttons = [self.start, self.select, self.a, self.b] + self.directions = [self.up, self.right, self.down, self.left] + self.buttons = [self.start, self.select, self.a, self.b] def get_buttons(self): return self.buttons @@ -110,7 +108,7 @@ return code def is_raised(self): - raised = self.raised + raised = self.raised self.raised = False return raised @@ -173,9 +171,9 @@ class Button(object): def __init__(self, code_value, opposite_button=None): - self.code_value = int(code_value) + self.code_value = int(code_value) self.opposite_button = opposite_button - self.pressed = False + self.pressed = False def get_code(self): if self.pressed: Modified: pypy/branch/build-external/pypy/lang/gameboy/ram.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/ram.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/ram.py Tue Jun 10 12:48:46 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Work and High RAM """ @@ -17,36 +17,29 @@ class RAM(iMemory): def __init__(self): - # Work RAM - self.w_ram = [0]*8192 - # High RAM - self.h_ram = [0]*128 + self.work_ram = [0]*8192 + self.hi_ram = [0]*128 self.reset() def reset(self): - # Work RAM - self.w_ram = [0]*8192 - # High RAM - self.h_ram = [0]*128 + self.work_ram = [0]*8192 + self.hi_ram = [0]*128 def write(self, address, data): - address = int(address) - data = int(data) + # C000-DFFF Work RAM (8KB) + # E000-FDFF Echo RAM if address >= 0xC000 and address <= 0xFDFF: - # C000-DFFF Work RAM (8KB) - # E000-FDFF Echo RAM - self.w_ram[address & 0x1FFF] = data + self.work_ram[address & 0x1FFF] = data & 0xFF + # FF80-FFFE elif address >= 0xFF80 and address <= 0xFFFE: - # FF80-FFFE High RAM - self.h_ram[address & 0x7F] = data + self.hi_ram[address & 0x7F] = data & 0xFF def read(self, address): - address = int(address) + # C000-DFFF Work RAM + # E000-FDFF Echo RAM if address >= 0xC000 and address <= 0xFDFF: - # C000-DFFF Work RAM - # E000-FDFF Echo RAM - return self.w_ram[address & 0x1FFF] & 0xFF + return self.work_ram[address & 0x1FFF] + # FF80-FFFE elif address >= 0xFF80 and address <= 0xFFFE: - # FF80-FFFE High RAM - return self.h_ram[address & 0x7F] & 0xFF + return self.hi_ram[address & 0x7F] raise Exception("Invalid Memory access, address out of range") \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/serial.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/serial.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/serial.py Tue Jun 10 12:48:46 2008 @@ -5,7 +5,7 @@ class Serial(iMemory): """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator Serial Link Controller """ @@ -15,50 +15,47 @@ self.reset() def reset(self): - self.cycles = int(constants.SERIAL_CLOCK) - self.sb = 0x00 - self.sc = 0x00 + self.cycles = int(constants.SERIAL_CLOCK) + self.serial_data = 0x00 + self.serial_control = 0x00 def get_cycles(self): return self.cycles def emulate(self, ticks): - ticks = int(ticks) - if (self.sc & 0x81) != 0x81: + if (self.serial_control & 0x81) != 0x81: return self.cycles -= ticks if self.cycles <= 0: - self.sb = 0xFF - self.sc &= 0x7F - self.cycles = constants.SERIAL_IDLE_CLOCK + self.serial_data = 0xFF + self.serial_control &= 0x7F + self.cycles = constants.SERIAL_IDLE_CLOCK self.interrupt.raise_interrupt(constants.SERIAL) - def set_serial_data(self, data): - self.sb = data - - def set_serial_control(self, data): - self.sc = data - # HACK: delay the serial interrupt (Shin Nihon Pro Wrestling) - self.cycles = constants.SERIAL_IDLE_CLOCK + constants.SERIAL_CLOCK - - def get_serial_data(self): - return self.sb - - def get_serial_control(self): - return self.sc - def write(self, address, data): - address = int(address) - if address == constants.SB: + if address == constants.SERIAL_TRANSFER_DATA: self.set_serial_data(data) - elif address == constants.SC: + elif address == constants.SERIAL_TRANSFER_CONTROL: self.set_serial_control(data) + def set_serial_data(self, data): + self.serial_data = data + + def set_serial_control(self, data): + self.serial_control = data + # HACK: delay the serial interrupt + self.cycles = constants.SERIAL_IDLE_CLOCK + constants.SERIAL_CLOCK + def read(self, address): - address = int(address) - if address == constants.SB: + if address == constants.SERIAL_TRANSFER_DATA: return self.get_serial_data() - elif address == constants.SC: + elif address == constants.SERIAL_TRANSFER_CONTROL: return self.get_serial_control() else: - return 0xFF \ No newline at end of file + return 0xFF + + def get_serial_data(self): + return self.serial_data + + def get_serial_control(self): + return self.serial_control \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/sound.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/sound.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/sound.py Tue Jun 10 12:48:46 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Audio Processor Unit (Sharp LR35902 APU) """ Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_cartridge.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_cartridge.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_cartridge.py Tue Jun 10 12:48:46 2008 @@ -18,7 +18,7 @@ def get_cartridge_managers(): pass -def get_cartridge(): +def get_cartridge_file(): ctrg = CartridgeFile() return ctrg @@ -41,63 +41,63 @@ # STORE MANAGER TEST ----------------------------------------------------------- -def test_cartridge_init(): - cartridge = get_cartridge() +def test_cartridge_file_init(): + cartridge_file = get_cartridge_file() - assert cartridge.cartridge_name is "" - assert cartridge.cartridge_stream is None - assert cartridge.cartridge_file_contents is None + assert cartridge_file.cartridge_name is "" + assert cartridge_file.cartridge_stream is None + assert cartridge_file.cartridge_file_contents is None - assert cartridge.battery_name is "" - assert cartridge.battery_stream is None - assert cartridge.battery_file_contents is None + assert cartridge_file.battery_name is "" + assert cartridge_file.battery_stream is None + assert cartridge_file.battery_file_contents is None -def rest_cartridge_load(): - cartridge = get_cartridge() +def test_cartridge_file_load(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH+"/rom1/"+romName - cartridge.load(romFilePath) - #assert cartridge.cartridge_name == romName - assert cartridge.cartridge_file_path == romFilePath + cartridge_file.load(romFilePath) + #assert cartridge_file.cartridge_name == romName + assert cartridge_file.cartridge_file_path == romFilePath - assert cartridge.battery_name == romFile+constants.BATTERY_FILE_EXTENSION - assert cartridge.battery_file_path == romFilePath+constants.BATTERY_FILE_EXTENSION - assert cartridge.has_battery() == False + #assert cartridge_file.battery_name == romFilePath+constants.BATTERY_FILE_EXTENSION + assert cartridge_file.battery_file_path == romFilePath+constants.BATTERY_FILE_EXTENSION + assert cartridge_file.has_battery() == False -def test_cartridge_hasBattery(): - cartridge = get_cartridge() +def test_cartridge_file_hasBattery(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH+"/rom1/"+romName - cartridge.load(romFilePath) - assert cartridge.has_battery() == False + cartridge_file.load(romFilePath) + assert cartridge_file.has_battery() == False -def test_cartridge_read(): - cartridge = get_cartridge() - assert cartridge.read() is None +def test_cartridge_file_read(): + cartridge_file = get_cartridge_file() + assert cartridge_file.read() is None -def test_cartridge_remove_write_read_Battery(): - cartridge = get_cartridge() +def test_cartridge_file_remove_write_read_Battery(): + cartridge_file = get_cartridge_file() romName = "rom1.raw" romFilePath = ROM_PATH + "/rom1/"+romName - cartridge.load(romFilePath) - cartridge.remove_battery() - assert cartridge.has_battery() == False - - cartridge.write_battery(MAPPED_CONTENT) - assert cartridge.has_battery() == True - assert cartridge.read_battery() == MAPPED_CONTENT + cartridge_file.load(romFilePath) + cartridge_file.remove_battery() + assert cartridge_file.has_battery() == False + + cartridge_file.write_battery(MAPPED_CONTENT) + assert cartridge_file.has_battery() == True + assert cartridge_file.read_battery() == MAPPED_CONTENT - cartridge.remove_battery() - assert cartridge.has_battery() == False + cartridge_file.remove_battery() + assert cartridge_file.has_battery() == False Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_cpu.py Tue Jun 10 12:48:46 2008 @@ -33,10 +33,10 @@ def test_reset(): cpu = get_cpu() - assert cpu.a.get() == 0x01 + assert cpu.a.get() == 0x01 #assert cpu.f.get() == 0xB0 - assert cpu.b.get() == 0x00 - assert cpu.c.get() == 0x13 + assert cpu.b.get() == 0x00 + assert cpu.c.get() == 0x13 assert cpu.de.get() == 0x00D8 assert cpu.hl.get() == 0x014D #assert cpu.sp.get() == 0xFFE @@ -44,66 +44,66 @@ def test_getters(): cpu = get_cpu() assert_default_registers(cpu) - assert cpu.af.cpu == cpu - assert cpu.a.cpu == cpu - assert cpu.f.cpu == cpu - - assert cpu.bc.cpu == cpu - assert cpu.b.cpu == cpu - assert cpu.c.cpu == cpu - - assert cpu.de.cpu == cpu - assert cpu.d.cpu == cpu - assert cpu.e.cpu == cpu + assert cpu.af.cpu == cpu + assert cpu.a.cpu == cpu + assert cpu.f.cpu == cpu + + assert cpu.bc.cpu == cpu + assert cpu.b.cpu == cpu + assert cpu.c.cpu == cpu + + assert cpu.de.cpu == cpu + assert cpu.d.cpu == cpu + assert cpu.e.cpu == cpu - assert cpu.hl.cpu == cpu + assert cpu.hl.cpu == cpu assert cpu.hli.cpu == cpu - assert cpu.h.cpu == cpu - assert cpu.l.cpu == cpu + assert cpu.h.cpu == cpu + assert cpu.l.cpu == cpu - assert cpu.sp.cpu == cpu - assert cpu.pc.cpu == cpu + assert cpu.sp.cpu == cpu + assert cpu.pc.cpu == cpu def test_fetch(): - cpu = get_cpu() - address = 0x3FFF - value = 0x12 + cpu = get_cpu() + address = 0x3FFF + value = 0x12 # in rom cpu.pc.set(address) cpu.rom[address] = value - startCycles = cpu.cycles - assert cpu.fetch() == value + startCycles = cpu.cycles + assert cpu.fetch() == value assert startCycles-cpu.cycles == 1 # in the memory - value = 0x13 - address = 0xC000 + value = 0x13 + address = 0xC000 cpu.pc.set(address) cpu.memory.write(address, value) assert cpu.fetch() == value def test_read_write(): - cpu = get_cpu() - address = 0xC000 - value = 0x12 + cpu = get_cpu() + address = 0xC000 + value = 0x12 startCycles = cpu.cycles cpu.write(address, value) assert startCycles-cpu.cycles == 2 startCycles = cpu.cycles - assert cpu.read(address) == value + assert cpu.read(address) == value assert startCycles-cpu.cycles == 1 - address +=1 - value += 1 + address +=1 + value += 1 cpu.write(address, value) - assert cpu.read(address) == value + assert cpu.read(address) == value def test_relative_conditional_jump(): - cpu = get_cpu() - pc = cpu.pc.get() - value = 0x12 + cpu = get_cpu() + pc = cpu.pc.get() + value = 0x12 cpu.rom[constants.RESET_PC] = value # test jr_nn startCycles = cpu.cycles @@ -112,26 +112,26 @@ assert_registers(cpu, pc=pc+value+1) # test pc.inc startCycles = cpu.cycles - pc = cpu.pc.get() + pc = cpu.pc.get() cpu.relative_conditional_jump(False) assert startCycles-cpu.cycles == 2 - assert cpu.pc.get() == pc+1 + assert cpu.pc.get() == pc+1 def test_flags(): cpu = get_cpu() cpu.f.set(constants.Z_FLAG) - assert cpu.is_z() == True + assert cpu.is_z() == True assert cpu.is_not_z() == False cpu.f.set(~constants.Z_FLAG) - assert cpu.is_z() == False + assert cpu.is_z() == False assert cpu.is_not_z() == True cpu.f.set(constants.C_FLAG) - assert cpu.is_c() == True + assert cpu.is_c() == True assert cpu.is_not_c() == False cpu.f.set(~constants.C_FLAG) - assert cpu.is_c() == False + assert cpu.is_c() == False assert cpu.is_not_c() == True def test_flags_memory_access(): @@ -173,10 +173,10 @@ def test_create_group_op_codes(): assert len(GROUPED_REGISTERS) == 8 - start=0x12 - step=0x03 - func = CPU.inc - table = [(start, step, func)] + start = 0x12 + step = 0x03 + func = CPU.inc + table = [(start, step, func)] grouped = create_group_op_codes(table) assert len(grouped) == len(table)*8 @@ -190,13 +190,13 @@ def test_create_register_op_codes(): - start = 0x09 - step = 0x10 - func = CPU.add_hl + start = 0x09 + step = 0x10 + func = CPU.add_hl registers = [CPU.get_bc]*128 - table = [(start, step, func, registers)] - list = create_register_op_codes(table) - opCode = start + table = [(start, step, func, registers)] + list = create_register_op_codes(table) + opCode = start assert len(list) == len(registers) for entry in list: assert len(entry) == 2 @@ -256,7 +256,7 @@ cpu.memory.write(pc, value & 0xFF) def test_prepare_for_fetch(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_fetch(cpu, value+1, value) assert cpu.fetch() == value @@ -270,7 +270,7 @@ cpu.memory.write(sp, value & 0xFF) def test_prepare_for_pop(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_pop(cpu, value+1, value) assert cpu.pop() == value @@ -286,14 +286,14 @@ # test helper methods ---------------------------------------------------------- def test_prepare_for_pop(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_pop(cpu, value, value+1) assert cpu.pop() == value+1 assert cpu.pop() == value def test_prepare_for_fetch(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 prepare_for_fetch(cpu, value, value+1) assert cpu.fetch() == value+1 @@ -310,28 +310,28 @@ #load_mem_SP def test_0x08(): - cpu = get_cpu() + cpu = get_cpu() assert_default_registers(cpu) startPC = cpu.pc.get() prepare_for_fetch(cpu, 0xCD, 0xEF) cpu.sp.set(0x1234) cycle_test(cpu, 0x08, 5) assert_default_registers(cpu, pc=startPC+2, sp=0x1234) - assert cpu.memory.read(0xCDEF) == cpu.sp.get_lo() + assert cpu.memory.read(0xCDEF) == cpu.sp.get_lo() assert cpu.memory.read(0xCDEF+1) == cpu.sp.get_hi() # stop def test_0x10(): cpu = get_cpu() - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0x10, 0) # fetches 1 cycle assert_default_registers(cpu, pc=pc+1) # jr_nn def test_0x18(): - cpu = get_cpu(); - pc = cpu.pc.get() + cpu = get_cpu(); + pc = cpu.pc.get() value = 0x12 cpu.rom[constants.RESET_PC] = value assert_default_registers(cpu) @@ -340,10 +340,10 @@ # jr_NZ_nn see test_jr_cc_nn def test_0x20_0x28_0x30(): - cpu = get_cpu() + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0x20 - value = 0x12 + value = 0x12 for i in range(0, 4): prepare_for_fetch(cpu, value) pc = cpu.pc.get() @@ -360,10 +360,10 @@ # ld_BC_nnnn to ld_SP_nnnn def test_0x01_0x11_0x21_0x31_load_register_nnnn(): - cpu = get_cpu() - registers= [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 - opCode = 0x01 + cpu = get_cpu() + registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] + value = 0x12 + opCode = 0x01 for index in range(0, len(registers)): prepare_for_fetch(cpu, value, value+1) cycle_test(cpu, opCode, 3) @@ -374,16 +374,16 @@ # add_HL_BC to add_HL_SP def test_0x09_0x19_0x29_0x39(): - cpu = get_cpu() - registers= [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x1234 - opCode = 0x09 + cpu = get_cpu() + registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] + value = 0x1234 + opCode = 0x09 for i in range(0, len(registers)): cpu.hl.set(value) registers[i].set(value) assert registers[i].get() == value cycle_test(cpu, opCode, 2) - assert cpu.hl.get() == value+value + assert cpu.hl.get() == value+value value += 3 opCode += 0x10 @@ -397,8 +397,8 @@ # ld_A_BCi def test_0x0A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xC020 cpu.bc.set(address) cpu.write(address, value) @@ -417,8 +417,8 @@ # load_a_DEi def test_0x1A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xC020 cpu.de.set(address) cpu.write(address, value) @@ -433,7 +433,7 @@ cpu.a.set(0x12); cycle_test(cpu, 0x22, 2); assert cpu.read(0xCDEF) == cpu.a.get() - assert cpu.hl.get() == 0xCDEF+1 + assert cpu.hl.get() == 0xCDEF+1 # ldd_HLi_A def test_0x32(): @@ -442,13 +442,13 @@ cpu.a.set(0x12); cycle_test(cpu, 0x32, 2); assert cpu.read(0xCDEF) == cpu.a.get() - assert cpu.hl.get() == 0xCDEF-1 + assert cpu.hl.get() == 0xCDEF-1 # ldi_A_HLi def test_0x2A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF cpu.hl.set(address) cpu.write(address, value) @@ -458,8 +458,8 @@ # ldd_A_HLi def test_0x3A(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF cpu.hl.set(address) cpu.write(address, value) @@ -469,30 +469,30 @@ # inc_BC DE HL SP def test_0x03_to_0x33_inc_double_registers(): - cpu = get_cpu() - opCode = 0x03 + cpu = get_cpu() + opCode = 0x03 registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 + value = 0x12 for i in range(0,4): set_registers(registers, 0) registers[i].set(value) cycle_test(cpu, opCode, 2); - assert registers[i].get() == value +1 + assert registers[i].get() == value + 1 cpu.reset() opCode += 0x10 value += 3 # dec_BC def test_0x0B_to_0c38_dec_double_registers(): - cpu = get_cpu() - opCode = 0x0B + cpu = get_cpu() + opCode = 0x0B registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] - value = 0x12 + value = 0x12 for i in range(0,4): set_registers(registers, 0) registers[i].set(value) cycle_test(cpu, opCode, 2); - assert registers[i].get() == value-1 + assert registers[i].get() == value - 1 cpu.reset() cpu.reset() opCode += 0x10 @@ -517,10 +517,10 @@ # inc_B C D E H L A def test_0x04_to_0x3C_inc_registers(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x04 - value = 0x12 + opCode = 0x04 + value = 0x12 for register in registers: if register == cpu.hli: opCode += 0x08 @@ -535,7 +535,7 @@ # inc_HLi def test_0x34(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 cpu.hl.set(0xCDEF) cpu.write(cpu.hl.get(), value) @@ -545,9 +545,9 @@ def test_dec(): - cpu = get_cpu() + cpu = get_cpu() # cycle testing is done in the other tests - a = cpu.a + a = cpu.a a.set(1) cpu.f.c_flag = True cpu.dec(RegisterCallWrapper(a), RegisterCallWrapper(a)) @@ -571,10 +571,10 @@ # dec_B C D E H L A def test_0x05_to_0x3D_dec_registers(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x05 - value = 0x12 + opCode = 0x05 + value = 0x12 for register in registers: if register == cpu.hli: opCode += 0x08 @@ -589,7 +589,7 @@ # dec_HLi def test_0x35(): - cpu = get_cpu() + cpu = get_cpu() value = 0x12 cpu.hl.set(0xCDEF) cpu.write(cpu.hl.get(), value) @@ -599,10 +599,10 @@ # ld_B_nn C D E H L A ) def test_0x06_to_0x3A(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x06 - value = 0x12 + opCode = 0x06 + value = 0x12 for i in range(0, len(registers)): if registers[i] == cpu.hli: opCode += 0x08 @@ -611,107 +611,84 @@ set_registers(registers, 0) prepare_for_fetch(cpu, value) cycle_test(cpu, opCode, 2) - assert registers[i].get() == value + assert registers[i].get() == value + # one fetch assert cpu.pc.get() - oldPC == 1 cpu.reset() opCode += 0x08 - value += 3 + value += 3 # ld_HLi_nn def test_0x36(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 address = 0xCDEF prepare_for_fetch(cpu, value) cpu.hl.set(address) - oldPC = cpu.pc.get() + oldPC = cpu.pc.get() cycle_test(cpu, 0x36, 3) assert cpu.read(cpu.hl.get()) == value assert_default_registers(cpu, pc=oldPC+1, hl=address) # rlca def test_0x07(): - cpu = get_cpu() + cpu = get_cpu() value = 0x80 cpu.a.set(value) cycle_test(cpu, 0x07, 1) assert_default_registers(cpu, a=((value << 1) | (value >> 7)) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) cpu.reset() value = 0x40 cpu.a.set(value) cycle_test(cpu, 0x07, 1) assert_default_registers(cpu, a=((value << 1) | (value >> 7)) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=True) # rrca def test_0x0F(): - cpu = get_cpu() + cpu = get_cpu() value = 0x01 cpu.a.set(value) cycle_test(cpu, 0x0F, 1) assert_default_registers(cpu, a=((value >> 1) | (value << 7)) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) cpu.reset() value = 0x02 cpu.a.set(value) cycle_test(cpu, 0x0F, 1) assert_default_registers(cpu, a=((value >> 1) | (value << 7)) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=True) # rla def test_0x17(): - cpu = get_cpu() + cpu = get_cpu() value = 0x01 + cpu.f.set(0x00) cpu.a.set(value) - cpu.f.c_flag = False cycle_test(cpu, 0x17, 1) assert_default_registers(cpu, a=(value << 1) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) - - cpu.reset() - value = 0x01 - cpu.a.set(value) - cpu.f.c_flag = True - cycle_test(cpu, 0x17, 1) - assert_default_registers(cpu, a=((value << 1)+1) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) - - cpu.reset() - value = 0x40 - cpu.a.set(value) - cpu.f.c_flag = False - cycle_test(cpu, 0x17, 1) - assert_default_registers(cpu, a=(value << 1) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=True) # rra def test_0x1F(): - cpu = get_cpu() + cpu = get_cpu() value = 0x40 + cpu.f.set(0x00) cpu.a.set(value) - cpu.f.c_flag = False cycle_test(cpu, 0x1F, 1) assert_default_registers(cpu, a=(value >> 1) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) cpu.reset() + cpu.f.set(0x00) value = 0x40 cpu.a.set(value) - cpu.f.c_flag = True cycle_test(cpu, 0x1F, 1) - assert_default_registers(cpu, a=(0x08+(value >> 1)) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=False) + assert_default_registers(cpu, a=(value >> 1) & 0xFF, f=None); cpu.reset() + cpu.f.set(0x00) value = 0x02 cpu.a.set(value) - cpu.f.c_flag = False cycle_test(cpu, 0x1F, 1) assert_default_registers(cpu, a=(value >> 1) & 0xFF, f=None); - assert_default_flags(cpu, z_flag=False, c_flag=True) # daa def test_0x27(): @@ -720,15 +697,14 @@ # cpl def test_0x2F(): - cpu = get_cpu() - value = 0x12 - fValue = cpu.f.get() + cpu = get_cpu() + value = 0x12 + fValue = cpu.f.get() cpu.f.n_flag = False cpu.f.h_flag = False cpu.a.set(value) cycle_test(cpu, 0x2F, 1) assert_default_registers(cpu, a=value^0xFF, f=None) - assert_default_flags(cpu, n_flag=True, h_flag=True) # scf def test_0x37(): @@ -758,9 +734,9 @@ # halt def test_0x76(): - cpu = get_cpu() + cpu = get_cpu() cpu.cycles = 0xFF - cpu.ime = True + cpu.ime = True assert cpu.halted == False cycle_test(cpu, 0x76, cpu.cycles) assert cpu.halted == True @@ -769,9 +745,9 @@ # ld_B_B to ld_A_A def test_load_registers(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x40 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for store in registers: for load in registers: @@ -788,28 +764,13 @@ assert store.get() == value opCode += 0x01 - -def test_add_flags(): - cpu = get_cpu() - - cpu.a.set(0) - cpu.b.set(0) - cpu.add_a(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=True, h_flag=False) - - cpu.reset() - cpu.a.set(0x0F) - cpu.b.set(0x01) - cpu.add_a(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False, h_flag=True) - # add_A_B to add_A_A def test_0x80_to_0x87(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x80 valueA = 0x11 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -822,51 +783,15 @@ if register == cpu.a: assert cpu.a.get() == 2*value else: - assert cpu.a.get() == valueA+value - value += 3 + assert cpu.a.get() == valueA + value + value += 3 opCode += 0x01 - -def test_adc_flags(): - cpu = get_cpu() - b = cpu.b - a = cpu.a - - cpu.reset() - a.set(0) - b.set(0) - cpu.add_with_carry(RegisterCallWrapper(cpu.b), None) - assert_default_registers(cpu, a=0, f=None) - assert_default_flags(cpu, z_flag=True, c_flag=False, h_flag=False) - - cpu.reset() - a.set(0) - b.set(0) - cpu.f.c_flag = True - cpu.add_with_carry(RegisterCallWrapper(cpu.b), None) - assert_default_registers(cpu, a=1, f=None) - assert_default_flags(cpu, z_flag=False, c_flag=False, h_flag=False) - - cpu.reset() - a.set(0xF0) - b.set(0xFF) - cpu.add_with_carry(RegisterCallWrapper(cpu.b), None) - # overflow for a - assert_default_registers(cpu, a=0xEF, bc=None, f=None) - assert_default_flags(cpu, z_flag=False, c_flag=True, h_flag=False) - - cpu.reset() - a.set(0x0F) - b.set(0x01) - cpu.add_with_carry(RegisterCallWrapper(cpu.b), None) - assert_default_registers(cpu, a=0x10, f=None, bc=None) - assert_default_flags(cpu, z_flag=False, c_flag=False, h_flag=True) - # adc_A_B to adx_A_A def test_0x88_to_0x8F(): - cpu = get_cpu() + cpu = get_cpu() opCode = 0x88 - value = 0x12 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -896,9 +821,9 @@ # sub_A_B to sub_A_A def test_0x90_to_0x98(): - cpu = get_cpu() - opCode = 0x90 - value = 0x12 + cpu = get_cpu() + opCode = 0x90 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -911,42 +836,12 @@ assert cpu.a.get() == 0 value += 3 opCode += 0x01 - -def test_sbc_flags(): - cpu = get_cpu() - b = cpu.b - a = cpu.a - value = 0xFF - - cpu.reset() - a.set(value) - b.set(value) - cpu.subtract_with_carry(RegisterCallWrapper(cpu.b), None) - assert_default_registers(cpu, a=0, bc=None, f=None) - assert_default_flags(cpu, z_flag=True, c_flag=False, h_flag=False, n_flag=True) - - cpu.reset() - a.set(value) - b.set(value-1) - cpu.f.c_flag = True - cpu.subtract_with_carry(RegisterCallWrapper(cpu.b), None) - assert_default_registers(cpu, a=0, bc=None, f=None) - assert_default_flags(cpu, z_flag=True, c_flag=False, h_flag=False, n_flag=True) - - cpu.reset() - a.set(0x20) - b.set(0x01) - cpu.subtract_with_carry(RegisterCallWrapper(cpu.b), None) - # overflow for a - assert_default_registers(cpu, a=0x1F, bc=None, f=None) - assert_default_flags(cpu, z_flag=False, c_flag=False, h_flag=True, n_flag=True) - # sbc_A_B to sbc_A_A def test_0x98_0x9F(): - cpu = get_cpu() - opCode = 0x98 - value = 0x12 + cpu = get_cpu() + opCode = 0x98 + value = 0x12 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -973,27 +868,13 @@ value += 3 opCode += 0x01 - -def test_and_flags(): - cpu = get_cpu() - value = 0x12 - cpu.a.set(value) - cpu.b.set(value) - cpu.AND(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False) - - cpu.reset() - cpu.a.set(value) - cpu.b.set(0) - cpu.AND(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=True) # and_A_B to and_A_A -def test_0xA0_to_0xA7(): - cpu = get_cpu() - opCode = 0xA0 - value = 0x12 - valueA = 0x11 +def test_0xA0_to_0xA7_and_a(): + cpu = get_cpu() + opCode = 0xA0 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -1007,34 +888,15 @@ assert cpu.a.get() == (value & value) else: assert cpu.a.get() == (valueA & value) - if cpu.a.get() == 0: - assert cpu.f.get() == constants.Z_FLAG - else: - assert cpu.f.get() == 0 value += 1 opCode += 0x01 - - -def test_xor_flags(): - cpu = get_cpu() - value = 0x12 - cpu.a.set(value) - cpu.b.set(value) - cpu.XOR(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=True) - - cpu.reset() - cpu.a.set(value) - cpu.b.set(value+1) - cpu.XOR(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False) # xor_A_B to xor_A_A def test_0xA8_to_0xAF(): - cpu = get_cpu() - opCode = 0xA8 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xA8 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -1048,33 +910,16 @@ assert cpu.a.get() == (value ^ value) else: assert cpu.a.get() == (valueA ^ value) - if cpu.a.get() == 0: - assert cpu.f.z_flag == True - else: - assert cpu.f.get() == 0 value += 1 opCode += 0x01 -def test_or_flags(): - cpu = get_cpu() - value = 0x12 - cpu.a.set(value) - cpu.b.set(value) - cpu.OR(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False) - - cpu.reset() - cpu.a.set(0) - cpu.b.set(0) - cpu.OR(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=True) # or_A_B to or_A_A def test_0xB0_to_0xB7(): - cpu = get_cpu() - opCode = 0xB0 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xB0 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -1088,40 +933,15 @@ assert cpu.a.get() == (value | value) else: assert cpu.a.get() == (valueA | value) - if cpu.a.get() == 0: - assert cpu.f.get() == constants.Z_FLAG - else: - assert cpu.f.get() == 0 value += 1 opCode += 0x01 -def test_cp_flags(): - cpu = get_cpu() - value = 0x12 - cpu.a.set(value) - cpu.b.set(value) - cpu.compare_a(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=True, n_flag=True) - - cpu.reset() - cpu.a.set(value) - cpu.b.set(0) - cpu.compare_a(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False, n_flag=True) - - cpu.reset() - cpu.a.set(0xF0) - cpu.b.set(0x01) - cpu.compare_a(RegisterCallWrapper(cpu.b), None) - assert_default_flags(cpu, z_flag=False, h_flag=True, n_flag=True) - - # cp_A_B to cp_A_A def test_0xB8_to_0xBF_compare_a(): - cpu = get_cpu() - opCode = 0xB8 - value = 0x12 - valueA = 0x11 + cpu = get_cpu() + opCode = 0xB8 + value = 0x12 + valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() @@ -1133,22 +953,15 @@ cycle_test(cpu, opCode, numCycles) if register == cpu.a: valueA = value - assert cpu.f.n_flag == True - if valueA == value: - assert cpu.f.z_flag == True - if value < 0: - assert cpu.f.c_flag == True - if ((valueA-value) & 0x0F) > (valueA & 0x0F): - assert cpu.f.h_flag == True value += 1 opCode += 0x01 # ret_NZ to ret_C -def test_0xC0(): - cpu = get_cpu() +def test_0xC0_to_0xD8_return_on_condition(): + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC0 - value = 0x1234 + value = 0x1234 for i in range(0, 4): cpu.reset() prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1166,9 +979,9 @@ # ldh_mem_A def test_0xE0(): - cpu = get_cpu() + cpu = get_cpu() valueA = 0x11 - value = 0x12 + value = 0x12 prepare_for_fetch(cpu, value) cpu.a.set(valueA) cycle_test(cpu, 0xE0, 3) @@ -1177,8 +990,8 @@ # add_SP_nn def test_0xE8(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 spValue = 0xCDEF prepare_for_fetch(cpu, value) cpu.sp.set(spValue) @@ -1187,9 +1000,9 @@ # ldh_A_mem def test_0xF0(): - cpu = get_cpu() - valueA = 0x11 - value= 0x12 + cpu = get_cpu() + valueA = 0x11 + value = 0x12 address = 0x13 cpu.a.set(valueA) prepare_for_fetch(cpu, address) @@ -1198,12 +1011,12 @@ assert cpu.a.get() == value # ld_A_mem -def test_0xFA(): - cpu = get_cpu() - value = 0x11 +def test_0xFA_store_fetched_memory_in_a(): + cpu = get_cpu() + value = 0x11 valueA = 0x12 cpu.a.set(valueA) - pc = cpu.pc.get(); + pc = cpu.pc.get(); prepare_for_fetch(cpu, 0x12, 0x34) cpu.write(0x1234, value) cycle_test(cpu, 0xFA, 4) @@ -1211,7 +1024,7 @@ # ld_mem_A def test_0xEA(): - cpu = get_cpu() + cpu = get_cpu() valueA = 0x56 prepare_for_fetch(cpu, 0x12, 0x34) cpu.a.set(valueA) @@ -1221,22 +1034,22 @@ # ld_HL_SP_nn def test_0xF8(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueSp = 0x1234 prepare_for_fetch(cpu, value) cpu.sp.set(valueSp) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xF8, 3) - f = cpu.f.get(); + f = cpu.f.get(); assert_default_registers(cpu, hl=valueSp+value, f=f, sp=valueSp, pc=pc+1) # pop_BC to pop_AF def test_0xC1_to_0xF1(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.af] - opCode = 0xC1 - value = 0x1234 + opCode = 0xC1 + value = 0x1234 for register in registers: cpu.reset() prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1247,8 +1060,8 @@ # ret def test_0xC9(): - cpu = get_cpu() - value = 0x1234 + cpu = get_cpu() + value = 0x1234 valueSp = 0x5678 cpu.sp.set(valueSp) prepare_for_pop(cpu, value >> 8, value & 0xFF) @@ -1256,73 +1069,80 @@ assert_default_registers(cpu, pc=value, sp=valueSp+2) # reti -def test_0xD9_returnFormInterrupt(): - cpu = get_cpu() +def test_0xD9_return_form_interrupt(): + cpu = get_cpu() + cpu.interrupt.reset() value = 0x1234 cpu.sp.set(0) prepare_for_pop(cpu, value >> 8, value & 0xFF) prepare_for_fetch(cpu, 0x00) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xD9, 4+2) assert_default_registers(cpu, pc=value+1, sp=2) -def test_handleInterrupt(): - cpu = get_cpu() +def test_handle_interrupt(): + cpu = get_cpu() + cpu.interrupt.reset() cpu.halted = True cpu.cycles = 0xFF - cpu.handle_pending_interrupt() + cpu.handle_pending_interrupts() assert cpu.cycles == 0 cpu.reset() + cpu.interrupt.reset() cpu.halted = True - cpu.interrupt.set_interrupt_enable() - cpu.interrupt.v_blank.set_pending() - assert cpu.interrupt.is_pending() == True cpu.cycles = 4 - cpu.handle_pending_interrupt() - assert cpu.cycles == 0 - assert cpu.halted == False + cpu.interrupt.set_enable_mask(0xFF) + cpu.interrupt.vblank.set_pending() + assert cpu.interrupt.is_pending() == True + assert cpu.halted == True + cpu.handle_pending_interrupts() + assert cpu.cycles == 0 + assert cpu.halted == False cpu.reset() + cpu.interrupt.reset() cpu.halted = False - cpu.ime = True + cpu.ime = True cpu.pc.set(0x1234) cpu.sp.set(0x02) sp = cpu.sp.get() - cpu.interrupt.set_interrupt_enable() - cpu.interrupt.v_blank.set_pending() + cpu.interrupt.set_enable_mask(0xFF) + cpu.interrupt.vblank.set_pending() cpu.interrupt.lcd.set_pending() assert cpu.interrupt.is_pending() == True cpu.cycles = 0 - cpu.handle_pending_interrupt() + cpu.handle_pending_interrupts() assert cpu.cycles == 0 assert cpu.halted == False - assert_default_registers(cpu, pc=cpu.interrupt.v_blank.call_code, sp=sp-2) + assert_default_registers(cpu, pc=cpu.interrupt.vblank.call_code, sp=sp-2) assert cpu.pop() == 0x34 assert cpu.pop() == 0x12 # ld_PC_HL -def test_0xE9(): - cpu = get_cpu() +def test_0xE9_store_hl_in_pc(): + cpu = get_cpu() value = 0x1234 cpu.hl.set(value) + cpu.pc.set(0) cycle_test(cpu, 0xE9, 1) assert_default_registers(cpu, pc=value, hl=value) # ld_SP_HL -def test_0xF9(): - cpu = get_cpu() +def test_0xF9_store_hl_in_sp(): + cpu = get_cpu() value = 0x1234 cpu.hl.set(value) + cpu.sp.set(0) cycle_test(cpu, 0xF9, 2) assert_default_registers(cpu, sp=value, hl=value) # jp_NZ_nnnn to jp_C_nnnn def test_0xC2_to_0xDA(): - cpu = get_cpu() + cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC2 - value = 0x1234 + value = 0x1234 for i in range(0, 4): cpu.reset() prepare_for_fetch(cpu, value >> 8, value & 0xFF) @@ -1342,8 +1162,8 @@ # ldh_Ci_A def test_0xE2(): - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueA = value+1 cpu.c.set(value) cpu.a.set(valueA) @@ -1352,7 +1172,7 @@ # ldh_A_Ci def test_0xF2(): - cpu = get_cpu() + cpu = get_cpu() valueC = 0x12 valueA = 0x11 cpu.c.set(valueC) @@ -1370,40 +1190,53 @@ # di -def test_0xF3(): +def test_0xF3_disable_interrupt(): cpu = get_cpu() - cpu.ime == True + cpu.interrupt.reset() + cpu.ime = True cycle_test(cpu, 0xF3, 1) assert cpu.ime == False # ei -def test_0xFB(): - cpu = get_cpu() +def test_0xFB_enable_interrupt(): + cpu = get_cpu() + cpu.interrupt.reset() cpu.sp.set(0) - cpu.ime = False + cpu.ime = False cpu.halted = False prepare_for_fetch(cpu, 0x00) # nop 1 cycle + print cpu.interrupt.get_enable_mask() + assert cpu.interrupt.is_pending() == False cycle_test(cpu, 0xFB, 1+1) - assert cpu.ime == True + assert cpu.interrupt.is_pending() == False + assert cpu.ime == True cpu.reset() + cpu.interrupt.reset() cpu.sp.set(0) - cpu.ime = True + cpu.ime = True cpu.halted = False prepare_for_fetch(cpu, 0x00) # nop 1 cycle - cpu.interrupt.v_blank.set_pending() + cpu.interrupt.vblank.set_pending() cpu.interrupt.serial.set_pending() - cpu.interrupt.set_interrupt_enable(True) + cpu.interrupt.set_enable_mask(0x1F) assert cpu.interrupt.is_pending() == True - assert cpu.halted == False - assert cpu.ime == True + assert cpu.halted == False + assert cpu.ime == True cycle_test(cpu, 0xFB, 1+1) - assert cpu.interrupt.is_pending() == False - assert cpu.interrupt.v_blank.is_pending() == False - assert cpu.pc.get() == cpu.interrupt.v_blank.call_code - assert cpu.ime == False + assert cpu.interrupt.is_pending() == True + assert cpu.interrupt.vblank.is_pending() == False + assert cpu.interrupt.serial.is_pending() == True + assert cpu.pc.get() == cpu.interrupt.vblank.call_code + assert cpu.ime == False + + cpu.ime = True + cycle_test(cpu, 0xFB, 1+1) + assert cpu.interrupt.vblank.is_pending() == False + assert cpu.interrupt.serial.is_pending() == False + assert cpu.interrupt.is_pending() == False -def conditionalCallTest(cpu, opCode, flagSetter): +def conditional_call_test(cpu, opCode, flagSetter): flagSetter(cpu, False) cpu.pc.set(0) f = cpu.f.get() @@ -1422,7 +1255,7 @@ # call_NZ_nnnn def test_0xC4(): cpu = get_cpu() - conditionalCallTest(cpu, 0xC4, setFlag0xC4) + conditional_call_test(cpu, 0xC4, setFlag0xC4) def setFlag0xC4(cpu, value): cpu.f.z_flag = not value @@ -1430,7 +1263,7 @@ # call_Z_nnnn def test_0xCC(): cpu = get_cpu() - conditionalCallTest(cpu, 0xCC, setFlag0xC4) + conditional_call_test(cpu, 0xCC, setFlag0xC4) def setFlag0xCC(cpu, value): cpu.f.c_flag = not value @@ -1438,7 +1271,7 @@ # call_NC_nnnn def test_0xD4(): cpu = get_cpu() - conditionalCallTest(cpu, 0xD4, setFlag0xC4) + conditional_call_test(cpu, 0xD4, setFlag0xC4) def setFlag0xD4(cpu, value): cpu.f.c_flag = value @@ -1446,17 +1279,17 @@ # call_C_nnnn def test_0xDC(): cpu = get_cpu() - conditionalCallTest(cpu, 0xDC, setFlag0xC4) + conditional_call_test(cpu, 0xDC, setFlag0xC4) def setFlag0xDC(cpu, value): cpu.f.z_flag = value # push_BC to push_AF -def test_0xC5_to_0xF5(): - cpu = get_cpu() +def test_0xC5_to_0xF5_push(): + cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.af] - opCode = 0xC5 - value = 0x1234 + opCode = 0xC5 + value = 0x1234 for register in registers: register.set(value) cycle_test(cpu, opCode, 4) @@ -1467,8 +1300,8 @@ # call_nnnn -def test_0xCD(): - cpu = get_cpu() +def test_0xCD_call(): + cpu = get_cpu() fetchValue = 0x1234 cpu.sp.set(fetchValue) prepare_for_fetch(cpu, fetchValue) @@ -1477,19 +1310,19 @@ def a_nn_test(opCode, cycles, opCaller): # flags tested already - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueAdd = 0x12 cpu.a.set(value) prepare_for_fetch(cpu, valueAdd,) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, opCode, cycles) assert_default_registers(cpu, a=opCaller(value,valueAdd, cpu), pc=pc+1, f=cpu.f.get()) return cpu # add_A_nn -def test_0xC6(): +def test_0xC6_add_a_fetch(): a_nn_test(0xC6, 2, lambda a, b, cpu: a+b) # adc_A_nn @@ -1519,11 +1352,11 @@ # cp_A_nn def test_0xFE(): # flags tested already - cpu = get_cpu() - value = 0x12 + cpu = get_cpu() + value = 0x12 valueA = 0x12 cpu.a.set(valueA) - pc = cpu.pc.get() + pc = cpu.pc.get() cycle_test(cpu, 0xFE, 2) @@ -1531,51 +1364,36 @@ assert cpu.f.z_flag == True # rst(0x00) to rst(0x38) -def test_0xC7_to_0xFF(): - cpu = get_cpu() - opCode = 0xC7 +def test_0xC7_to_0xFF_reset(): + cpu = get_cpu() + opCode = 0xC7 rstValue = 0x00 for i in range(0,8): cpu.reset() cpu.pc.set(0x1234) cycle_test(cpu, opCode, 4) - assert cpu.pop() == 0x34 - assert cpu.pop() == 0x12 + assert cpu.pop() == 0x34 + assert cpu.pop() == 0x12 assert cpu.pc.get() == rstValue - opCode += 0x08 + opCode += 0x08 rstValue += 0x08 # switching to other opcode set def test_0xCB(): cpu = get_cpu() - pc = cpu.pc.get() + pc = cpu.pc.get() prepare_for_fetch(cpu, 0x80) cycle_test(cpu, 0xCB, 2) assert_default_registers(cpu, pc=pc+1) -def test_rotateLeft_flags(): - cpu = get_cpu() - a = cpu.a - a.set(0x01) - assert_default_flags(cpu) - cpu.rotate_left_a() - assert_default_flags(cpu, z_flag=False, c_flag=False) - assert_default_registers(cpu, a=0x02, f=None) - - cpu.reset() - a.set(0x40) - cpu.rotate_left_a() - assert_default_flags(cpu, z_flag=False, c_flag=True) - assert_default_registers(cpu, a=0x80, f=None) - # SECOND ORDER OPCODES --------------------------------------------------------- def second_order_test(opCode, createFunction): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0xF0 + value = 0xF0 for register in registers: cpu.reset() register.set(value) @@ -1621,9 +1439,9 @@ # bit_B to bit_A def test_testBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - opCode = 0x40 + opCode = 0x40 for register in registers: registerOpCode = opCode for i in range(8): @@ -1646,18 +1464,20 @@ # set_B to set_C def test_setBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0x12 - opCode = 0xC0 + value = 0x12 + opCode = 0xC0 for register in registers: registerOpCode = opCode for i in range(8): cycles = 2 if register == cpu.hli: cycles = 4 - cpu.reset() + if registerOpCode ==0xFF: + print "6544444444444444" + register.set(0) fetch_execute_cycle_test_second_order(cpu, registerOpCode, cycles) assert (register.get() & (1<> i == 1 @@ -1668,16 +1488,15 @@ # res_B to res_A def test_resetBit_opCodes(): - cpu = get_cpu() + cpu = get_cpu() registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] - value = 0x12 - opCode = 0x80 + value = 0x12 + opCode = 0x80 for register in registers: registerOpCode = opCode cycles = 2 if register == cpu.hli: cycles = 4 - for i in range(8): cpu.reset() register.set(0) @@ -1693,7 +1512,127 @@ opCode += 1 +# LOAD TEST ----------------------------------------------------------------- +# just for double checking ;) - +def load_test(cpu, test_set): + value = 0 + for test in test_set: + opCode = test[0] + reg_write = test[1] + reg_read = test[2] + value = 1 + (value + 1) & 0xFE + reg_write.set(0) + reg_read.set(value) + cpu.execute(opCode) + assert reg_write.get() == reg_read.get(), hex(opCode)+" load failed!" + + +def test_load_b(): + cpu = get_cpu() + read_register = cpu.b + load_test(cpu, + [(0x40, read_register, cpu.b), + (0x41, read_register, cpu.c), + (0x42, read_register, cpu.d), + (0x43, read_register, cpu.e), + (0x44, read_register, cpu.h), + (0x45, read_register, cpu.l), + #(0x46, read_register, cpu.hli), + (0x47, read_register, cpu.a)]) + +def test_load_c(): + cpu = get_cpu() + read_register = cpu.c + load_test(cpu, + [(0x48, read_register, cpu.b), + (0x49, read_register, cpu.c), + (0x4A, read_register, cpu.d), + (0x4B, read_register, cpu.e), + (0x4C, read_register, cpu.h), + (0x4D, read_register, cpu.l), + #(0x4E, read_register, cpu.hli), + (0x4F, read_register, cpu.a)]) + + +def test_load_d(): + cpu = get_cpu() + read_register = cpu.d + load_test(cpu, + [(0x50, read_register, cpu.b), + (0x51, read_register, cpu.c), + (0x52, read_register, cpu.d), + (0x53, read_register, cpu.e), + (0x54, read_register, cpu.h), + (0x55, read_register, cpu.l), + # (0x56, read_register, cpu.hli), + (0x57, read_register, cpu.a)]) + +def test_load_e(): + cpu = get_cpu() + read_register = cpu.e + load_test(cpu, + [(0x58, read_register, cpu.b), + (0x59, read_register, cpu.c), + (0x5A, read_register, cpu.d), + (0x5B, read_register, cpu.e), + (0x5C, read_register, cpu.h), + (0x5D, read_register, cpu.l), + #(0x5E, read_register, cpu.hli), + (0x5F, read_register, cpu.a)]) + +def test_load_h(): + cpu = get_cpu() + read_register = cpu.h + load_test(cpu, + [(0x60, read_register, cpu.b), + (0x61, read_register, cpu.c), + (0x62, read_register, cpu.d), + (0x63, read_register, cpu.e), + (0x64, read_register, cpu.h), + (0x65, read_register, cpu.l), + #(0x66, read_register, cpu.hli), + (0x67, read_register, cpu.a)]) + +def test_load_l(): + cpu = get_cpu() + read_register = cpu.l + load_test(cpu, + [(0x68, read_register, cpu.b), + (0x69, read_register, cpu.c), + (0x6A, read_register, cpu.d), + (0x6B, read_register, cpu.e), + (0x6C, read_register, cpu.h), + (0x6D, read_register, cpu.l), + #(0x6E, read_register, cpu.hli), + (0x6F, read_register, cpu.a)]) + +def test_load_hli(): + cpu = get_cpu() + read_register = cpu.hli + load_test(cpu, + [(0x70, read_register, cpu.b), + (0x71, read_register, cpu.c), + (0x72, read_register, cpu.d), + (0x73, read_register, cpu.e), + (0x74, read_register, cpu.h), + (0x75, read_register, cpu.l), + (0x77, read_register, cpu.a)]) + +def test_load_a(): + cpu = get_cpu() + read_register = cpu.a + load_test(cpu, + [(0x78, read_register, cpu.b), + (0x79, read_register, cpu.c), + (0x7A, read_register, cpu.d), + (0x7B, read_register, cpu.e), + (0x7C, read_register, cpu.h), + (0x7D, read_register, cpu.l), + #(0x7E, read_register, cpu.hli), + (0x7F, read_register, cpu.a)]) + + + \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_interrupt.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_interrupt.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_interrupt.py Tue Jun 10 12:48:46 2008 @@ -8,40 +8,58 @@ def test_reset(): - interrupt = get_interrupt() - assert interrupt.enable == 0 - assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + interrupt = get_interrupt() + assert interrupt.is_pending() == False + assert interrupt.get_enable_mask() == 0 + assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + interrupt.enable = 1 - interrupt.flag = ~constants.VBLANK + interrupt.flag = ~constants.VBLANK interrupt.reset() - assert interrupt.enable == 0 - assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + assert interrupt.get_enable_mask() == 0 + assert interrupt.get_interrupt_flag() == 0xE0 | constants.VBLANK + + +def test_set_get_enable_mask(): + interrupt = get_interrupt() + assert interrupt.get_enable_mask() == 0x00 + interrupt.set_enable_mask(0x01) + assert interrupt.vblank.is_enabled() + assert interrupt.get_enable_mask() == 0x01 + + # enable all interrupts 0x01 - 0x10 + interrupt.set_enable_mask(0xFF) + assert interrupt.vblank.is_enabled() + assert interrupt.get_enable_mask() == 0xFF def test_is_pending(): interrupt = get_interrupt() - assert interrupt.is_pending() == False + interrupt.vblank.set_pending() + assert interrupt.is_pending() == False assert interrupt.is_pending(0x00) == False - interrupt.set_interrupt_enable(True) + + interrupt.set_enable_mask(0xFF) assert interrupt.is_pending() + interrupt.set_enable_mask(0x00) + assert interrupt.is_pending() == False def test_is_pending_common_masks(): interrupt = get_interrupt() for flag in interrupt.interrupt_flags: interrupt.reset() - interrupt.enable = True - assert interrupt.v_blank.is_pending() + interrupt.set_enable_mask(0xFF) + assert interrupt.vblank.is_pending() flag.set_pending(True) assert interrupt.is_pending(flag.mask) - def test_raise_lower_interrupt(): interrupt = get_interrupt() masks= [constants.LCD, constants.TIMER, constants.JOYPAD, constants.SERIAL] - interrupt.set_interrupt_enable(True) - interrupt.v_blank.set_pending(True) + interrupt.set_enable_mask(0xFF) + interrupt.vblank.set_pending(True) for mask in masks: interrupt.raise_interrupt(mask) assert interrupt.mask_mapping[mask].is_pending() == True @@ -51,13 +69,11 @@ def test_read_write(): interrupt = get_interrupt() - value = 1 - interrupt.write(constants.IE, value) - assert interrupt.enable == value - assert interrupt.read(constants.IE) == value + interrupt.write(constants.IE, 0x12) + assert interrupt.get_enable_mask() == 0x12 + assert interrupt.read(constants.IE) == 0x12 interrupt.reset() - value = constants.LCD - interrupt.write(constants.IF, value) - assert interrupt.get_interrupt_flag() == 0xE0 | value - assert interrupt.read(constants.IF) == 0xE0 | value + interrupt.write(constants.IF, constants.LCD) + assert interrupt.get_interrupt_flag() == 0xE0 | constants.LCD + assert interrupt.read(constants.IF) == 0xE0 | constants.LCD Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_joypad.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_joypad.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_joypad.py Tue Jun 10 12:48:46 2008 @@ -44,11 +44,11 @@ # TEST BUTTON ------------------------------------------------------------------ def test_ini(): - value = 0xf + value = 0xf button = Button(value) assert button.opposite_button is None - assert button.code_value == value - assert button.is_pressed() == False + assert button.code_value == value + assert button.is_pressed() == False button2 = Button(value, button) assert button2.opposite_button == button @@ -67,74 +67,108 @@ button2.press() assert button2.is_pressed() == True button.press() - assert button.is_pressed() == True + assert button.is_pressed() == True assert button2.is_pressed() == False button.release() - assert button.is_pressed() == False + assert button.is_pressed() == False assert button2.is_pressed() == False # TEST JOYPAD DRIVER ----------------------------------------------------------- -def test_ini(): +def test_joypad_driver_ini(): driver = get_driver() - assert driver.raised == False - assert driver.get_button_code() == 0 + assert driver.raised == False + assert driver.get_button_code() == 0 assert driver.get_direction_code() == 0 -def test_isRaised(): - driver = get_driver() +def test_joypad_driver_isRaised(): + driver = get_driver() driver.raised = True - assert driver.raised == True + assert driver.raised == True assert driver.is_raised() == True - assert driver.raised == False + assert driver.raised == False -def test_button_code_values(): +def test_joypad_driver_button_code_values(): driver = get_driver() - assert driver.up.code_value == constants.BUTTON_UP - assert driver.right.code_value == constants.BUTTON_RIGHT - assert driver.down.code_value == constants.BUTTON_DOWN - assert driver.left.code_value == constants.BUTTON_LEFT + assert driver.up.code_value == constants.BUTTON_UP + assert driver.right.code_value == constants.BUTTON_RIGHT + assert driver.down.code_value == constants.BUTTON_DOWN + assert driver.left.code_value == constants.BUTTON_LEFT assert driver.select.code_value == constants.BUTTON_SELECT - assert driver.start.code_value == constants.BUTTON_START - assert driver.a.code_value == constants.BUTTON_A - assert driver.b.code_value == constants.BUTTON_B + assert driver.start.code_value == constants.BUTTON_START + assert driver.a.code_value == constants.BUTTON_A + assert driver.b.code_value == constants.BUTTON_B + +def test_joypad_driver_button_toggled_values(): + driver = get_driver() + driver.button_a() + assert driver.get_button_code() == 0x01 + + driver.reset() + driver.button_b() + assert driver.get_button_code() == 0x02 + + driver.reset() + driver.button_select() + assert driver.get_button_code() == 0x04 + + driver.reset() + driver.button_start() + assert driver.get_button_code() == 0x08 + +def test_joypad_driver_direction_toggled_values(): + driver = get_driver() + driver.button_up() + assert driver.get_direction_code() == 0x04 + + driver.reset() + driver.button_right() + assert driver.get_direction_code() == 0x01 + + driver.reset() + driver.button_down() + assert driver.get_direction_code() == 0x08 + + driver.reset() + driver.button_left() + assert driver.get_direction_code() == 0x02 def test_toggle_opposite_directions(): driver = get_driver() - directions = [(driver.button_up, driver.up, driver.down), - (driver.button_down, driver.down, driver.up), - (driver.button_left, driver.left, driver.right), - (driver.button_right, driver.right, driver.left)] + directions = [(driver.button_up, driver.up, driver.down), + (driver.button_down, driver.down, driver.up), + (driver.button_left, driver.left, driver.right), + (driver.button_right, driver.right, driver.left)] for dir in directions: - toggleFunction = dir[0] - button = dir[1] + toggleFunction = dir[0] + button = dir[1] opposite_button = dir[2] driver.reset() opposite_button.press() - assert driver.raised == False - assert button.is_pressed() == False + assert driver.raised == False + assert button.is_pressed() == False assert opposite_button.is_pressed() == True - assert driver.get_direction_code() == opposite_button.code_value - assert driver.get_button_code() == 0 + assert driver.get_direction_code() == opposite_button.code_value + assert driver.get_button_code() == 0 toggleFunction() - assert driver.raised == True - assert button.is_pressed() == True + assert driver.raised == True + assert button.is_pressed() == True assert opposite_button.is_pressed() == False - assert driver.get_direction_code() == button.code_value - assert driver.get_button_code() == 0 + assert driver.get_direction_code() == button.code_value + assert driver.get_button_code() == 0 toggleFunction(False) - assert button.is_pressed() == False + assert button.is_pressed() == False assert opposite_button.is_pressed() == False - assert driver.get_direction_code() == 0 - assert driver.get_button_code() == 0 + assert driver.get_direction_code() == 0 + assert driver.get_button_code() == 0 def test_toggle_buttons(): - driver = get_driver() + driver = get_driver() buttons = [(driver.button_select, driver.select), (driver.button_start, driver.start), (driver.button_a, driver.a), @@ -144,24 +178,24 @@ button = button[1] driver.reset() - assert button.is_pressed() == False - assert driver.get_button_code() == 0 + assert button.is_pressed() == False + assert driver.get_button_code() == 0 assert driver.get_direction_code() == 0 toggleFunction() - assert driver.raised == True - assert button.is_pressed() == True - assert driver.get_button_code() == button.code_value + assert driver.raised == True + assert button.is_pressed() == True + assert driver.get_button_code() == button.code_value assert driver.get_direction_code() == 0 toggleFunction(False) - assert button.is_pressed() == False - assert driver.get_button_code() == 0 + assert button.is_pressed() == False + assert driver.get_button_code() == 0 assert driver.get_direction_code() == 0 def test_toggle_multiple_buttons(): - driver = get_driver() + driver = get_driver() buttons = [(driver.button_select, driver.select), (driver.button_start, driver.start), (driver.button_a, driver.a), @@ -200,66 +234,93 @@ def test_reset(joypad=None): if joypad is None: joypad = get_joypad() - assert joypad.joyp == 0xF + assert joypad.read_control == 0xF assert joypad.cycles == constants.JOYPAD_CLOCK + assert joypad.read(constants.JOYP) == 0xFF def test_emulate(): - joypad = get_joypad() - ticks = 2 - cycles = joypad.cycles - joypad.emulate(ticks) - assert cycles - joypad.cycles == ticks + joypad = get_joypad() + joypad.cycles = 10 + joypad.emulate(5) + assert joypad.cycles == 5 def test_emulate_zero_ticks(): - joypad = get_joypad() + joypad = get_joypad() joypad.cycles = 2 - ticks = 2 - joypad.emulate(ticks) + joypad.emulate(2) assert joypad.cycles == constants.JOYPAD_CLOCK def test_emulate_zero_ticks_update(): joypad = get_joypad() - value = 0x1 - joypad.joyp = value - joypad.driver.button_code = 0x4 - joypad.driver.raised = True - joypad.cycles = 2 - ticks = 2 - joypad.emulate(ticks) - assert joypad.cycles == constants.JOYPAD_CLOCK - assert joypad.joyp == value - assert joypad.button_code == 0 + joypad.read_control = 0x2 + joypad.driver.button_up() + assert joypad.driver.get_direction_code() == constants.BUTTON_UP + joypad.driver.raised = False + joypad.cycles = 2 + + assert joypad.button_code == 0xF + joypad.emulate(2) + assert joypad.cycles == constants.JOYPAD_CLOCK + assert joypad.read_control == 2 + assert joypad.button_code == 0xF + assert joypad.interrupt.joypad.is_pending() == False + + joypad.driver.raised = True + joypad.cycles = 2 + assert joypad.button_code == 0xF + joypad.emulate(2) + assert joypad.cycles == constants.JOYPAD_CLOCK + assert joypad.read_control == 2 + assert joypad.button_code == constants.BUTTON_UP + assert joypad.interrupt.joypad.is_pending() == True def test_read_write(): joypad = get_joypad() - value = 0x2 - joypad.write(constants.JOYP, value) - joyp = 0xC + (value & 0x3) - assert joypad.joyp == joyp - joyp = (joyp << 4) + 0xF - assert joypad.read(constants.JOYP) == joyp + assert joypad.read(constants.JOYP) == 0xFF + joypad.write(constants.JOYP, 0x02) + assert joypad.read(constants.JOYP) == 0xCF assert joypad.read(constants.JOYP+1) == 0xFF - # no change on writing the wrong address - joypad.write(constants.JOYP+1, value+1) - assert joypad.read(constants.JOYP) == joyp + joypad.write(constants.JOYP, 0x00) + assert joypad.read(constants.JOYP) & 0xF0 == 0xC0 + + joypad.write(constants.JOYP, 0x10) + assert joypad.read(constants.JOYP) & 0xF0 == 0xD0 + + joypad.write(constants.JOYP, 0x20) + assert joypad.read(constants.JOYP) & 0xF0 == 0xE0 + + joypad.write(constants.JOYP, 0x30) + assert joypad.read(constants.JOYP) & 0xF0 == 0xF0 + + joypad.write(constants.JOYP, 0xFF) + assert joypad.read(constants.JOYP) & 0xF0 == 0xF0 def test_update(): joypad = get_joypad() + # toogle the buttons joypad.driver.button_select() assert joypad.driver.get_button_code() == constants.BUTTON_SELECT joypad.driver.button_up() assert joypad.driver.get_direction_code() == constants.BUTTON_UP assert joypad.button_code == 0xF - joypad.joyp = 0x1 + + joypad.write(constants.JOYP, 0x10) + joypad.update() + assert joypad.button_code == constants.BUTTON_SELECT + assert joypad.interrupt.joypad.is_pending() + + joypad.interrupt.joypad.set_pending(False) + joypad.write(constants.JOYP, 0x10) joypad.update() - assert joypad.button_code == (constants.BUTTON_SELECT | constants.BUTTON_UP) + assert joypad.button_code == constants.BUTTON_SELECT + assert joypad.interrupt.joypad.is_pending() == False - joypad.joyp = 0x2 + joypad.write(constants.JOYP, 0x20) joypad.update() - assert joypad.button_code == (constants.BUTTON_SELECT | constants.BUTTON_UP) + assert joypad.button_code == constants.BUTTON_UP - joypad.joyp = 0x3 + joypad.write(constants.JOYP, 0x30) joypad.update() assert joypad.button_code == 0xF Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_memory_bank_controller.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_memory_bank_controller.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_memory_bank_controller.py Tue Jun 10 12:48:46 2008 @@ -5,17 +5,26 @@ import py import pdb +class TestClock(object): + def __init__(self): + self.time = 0 + + def get_time(self): + return self.time + + def get_clock_driver(): return Clock() + RAM_SIZE = 3 ROM_SIZE = 2 def get_ram(size=RAM_SIZE): - return [0] * size * constants.RAM_BANK_SIZE + return [0] * int(size * constants.RAM_BANK_SIZE) def get_rom(size=ROM_SIZE): - return [0xFF] * size * constants.ROM_BANK_SIZE + return [0xFF] * int(size * constants.ROM_BANK_SIZE) def fail_ini_test(caller, ram_size, rom_size): try: @@ -150,16 +159,13 @@ return DefaultMBC([0]*0xFFFF, [0]*0xFFFF, get_clock_driver()) def test_default_mbc_read_write(): - py.test.skip("buggy implementation of DefaultMBC") mbc = get_default_mbc() - for i in range(0xFFFF): + mbc.ram_bank = 0 + mbc.ram_enable = True + for i in range(0xA000, 0xBFFF): mbc.write(i, i) assert mbc.read(i) == i -def test_default_mbc_write(): - py.test.skip("not yet implemented") - mbc = get_default_mbc() - # ----------------------------------------------------------------------------- def get_mbc1(rom_size=128, ram_size=4): @@ -241,7 +247,7 @@ # ----------------------------------------------------------------------------- def get_mbc2(rom_size=16, ram_size=1): - return MBC2(get_rom(rom_size), get_ram(ram_size), get_clock_driver()) + return MBC2(get_rom(rom_size/32.0), get_ram(ram_size), get_clock_driver()) def test_mbc2_create(): mbc = get_mbc2() @@ -249,8 +255,7 @@ fail_ini_test(mbc, 2, 2) fail_ini_test(mbc, 1, 1) fail_ini_test(mbc, 17, 1) - # only to the upper border of mbc - basic_read_write_test(mbc, 0, 0x7FFF) + # FIXME read write test missing def test_mbc2_write_ram_enable(): @@ -290,13 +295,15 @@ value %= 0x0F # ----------------------------------------------------------------------------- - + def get_mbc3(rom_size=128, ram_size=4): - return MBC3(get_rom(rom_size), get_ram(ram_size), get_clock_driver()) + return MBC3(get_rom(rom_size), get_ram(ram_size), get_clock_driver()) + +get_mbc3() def test_mbc3_create(): mbc = get_mbc3() - fail_ini_test(mbc, 128, -1) + fail_ini_test(mbc, 128, 0) fail_ini_test(mbc, 128, 5) fail_ini_test(mbc, 1, 4) fail_ini_test(mbc, 129, 4) @@ -352,7 +359,6 @@ mbc.ram_enable = True for address in range(0xA000, 0xBFFF+1): mbc.write(address, value) - #pdb.runcall(mbc.write, address, value) assert mbc.ram[mbc.ram_bank + (address & 0x1FFF)] == value assert mbc.read(address) == value; value += 1 @@ -388,14 +394,70 @@ value += 1 value %= 0xFF - + def test_mbc3_update_clock(): - py.test.skip("not yet implemented") mbc = get_mbc3() + mbc.clock = TestClock() + mbc.clock.time = 1 + 2*60 + 3*60*60 + 4*24*60*60 + mbc.clock_days = 0 + mbc.clock_hours = 0 + mbc.clock_minutes = 0 + mbc.clock_seconds = 0 + mbc.clock_time = 0 + mbc.clock_control = 0xFF + mbc.update_clock() + assert mbc.clock_days == 0 + assert mbc.clock_hours == 0 + assert mbc.clock_minutes == 0 + assert mbc.clock_seconds == 0 + assert mbc.clock_time == mbc.clock.time + + mbc.clock_time = 0 + mbc.clock_control = 0x00 + mbc.update_clock() + assert mbc.clock_days == 4 + assert mbc.clock_hours == 3 + assert mbc.clock_minutes == 2 + assert mbc.clock_seconds == 1 + assert mbc.clock_time == mbc.clock.time + +def test_mbc3_update_clock_day_overflow(): + mbc = get_mbc3() + mbc.clock = TestClock() + mbc.clock.time = 2*512*24*60*60 + mbc.clock_days = 0 + mbc.clock_hours = 0 + mbc.clock_minutes = 0 + mbc.clock_seconds = 0 + mbc.clock_time = 0 + mbc.clock_control = 0x01 + mbc.update_clock() + assert mbc.clock_days == 0 + assert mbc.clock_hours == 0 + assert mbc.clock_minutes == 0 + assert mbc.clock_seconds == 0 + assert mbc.clock_control == 0x81 def test_mbc3_latch_clock(): - py.test.skip("not yet implemented") mbc = get_mbc3() + mbc.clock = TestClock() + mbc.clock.time = 1 + 2*60 + 3*60*60 + (0xFF+2)*24*60*60 + mbc.clock_days = 0 + mbc.clock_hours = 0 + mbc.clock_minutes = 0 + mbc.clock_seconds = 0 + mbc.clock_time = 0 + mbc.clock_control = 0x00 + mbc.latch_clock() + assert mbc.clock_days == 0xFF+2 + assert mbc.clock_latched_days == (0xFF+2) & 0xFF + assert mbc.clock_hours == 3 + assert mbc.clock_latched_hours == 3 + assert mbc.clock_minutes == 2 + assert mbc.clock_latched_minutes == 2 + assert mbc.clock_seconds == 1 + assert mbc.clock_latched_seconds == 1 + assert mbc.clock_latched_control == (mbc.clock_days>>8) & 0x01 # ----------------------------------------------------------------------------- @@ -531,7 +593,7 @@ value = +1 value %= 0xFF -def test_huc3_write_ram_value(): +def test_huc3_write_ram_value_clock_shift(): mbc = get_huc3() mbc.ram_flag = 0x0B for address in range(0xA000, 0xBFFF+1): @@ -544,7 +606,7 @@ assert mbc.clock_shift == clock_shift mbc.clock_shift = 0 -def test_huc3_write_reset_ram_value(): +def test_huc3_write_ram_value_clock_shift(): mbc = get_huc3() value = 1 mbc.ram_flag = 0x0B @@ -555,7 +617,7 @@ value = +1 value %= 0xFF -def test_huc3_write_clock_register(): +def test_huc3_write_clock_register_clock_shift(): mbc = get_huc3() value = 1 mbc.ram_flag = 0x0B @@ -564,17 +626,17 @@ clock_register = mbc.clock_register mbc.write(address, 0x30+value) if clock_shift <= 24: + assert mbc.clock_shift == clock_shift+4 assert mbc.clock_register == (clock_register & \ ~(0x0F << clock_shift)) | \ - (value << clock_shift) - assert mbc.clock_shift == clock_shift+4 + ((value & 0x0F) << clock_shift) else: assert mbc.clock_shift == clock_shift mbc.clock_shift = 0 value = +1 value %= 0xF -def test_huc3_write_update_clock(): +def test_huc3_write_clock_shift(): mbc = get_huc3() value = 1 mbc.ram_flag = 0x0B @@ -589,10 +651,17 @@ value = +1 value %= 0xF + def test_huc3_update_clock(): - py.test.skip("not yet implemented") mbc = get_huc3() - pass - + mbc.clock = TestClock() + mbc.clock.time = 1*60 + 2*24*60*60 + 3*365*24*60*60 + mbc.clock_register = 0x00 + mbc.clock_time = 0 + mbc.update_clock() + assert mbc.clock_register & 0x00000FFF == 1 + assert mbc.clock_register & 0x00FFF000 == 2 << 12 + assert mbc.clock_register & 0xFF000000 == 3 << 24 + assert mbc.clock_time == mbc.clock.time # ----------------------------------------------------------------------------- Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_ram.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_ram.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_ram.py Tue Jun 10 12:48:46 2008 @@ -6,55 +6,78 @@ return RAM() +def test_ram_reset(): + ram = get_ram(); + assert len(ram.work_ram) == 8192 + assert len(ram.hi_ram) == 128 + ram.hi_ram = range(50) + ram.work_ram = range(50) + ram.reset() + + assert len(ram.work_ram) == 8192 + assert len(ram.hi_ram) == 128 + assert ram.work_ram == [0] * 8192 + assert ram.hi_ram == [0] * 128 + + + def test_ram_read_write(): ram = get_ram() - address = 0x00 value = 0x12 - ram.write(address, value) + ram.write(0x00, value) try: - ram.read(address) + ram.read(0x00) py.test.fail() except Exception: pass - assert value not in ram.w_ram - assert value not in ram.h_ram + assert value not in ram.work_ram + assert value not in ram.hi_ram - address = 0xC000 - ram.write(address, value) - assert ram.read(address) == value - assert value in ram.w_ram - assert value not in ram.h_ram + ram.write(0xC000, value) + assert ram.read(0xC000) == value + assert value in ram.work_ram + assert value not in ram.hi_ram - address = 0xFDFF value += 1 - ram.write(address, value) - assert ram.read(address) == value - assert value in ram.w_ram - assert value not in ram.h_ram + ram.write(0xFDFF, value) + assert ram.read(0xFDFF) == value + assert value in ram.work_ram + assert value not in ram.hi_ram - address = 0xFF80 value += 1 - ram.write(address, value) - assert ram.read(address) == value - assert value in ram.h_ram - assert value not in ram.w_ram + ram.write(0xFF80, value) + assert ram.read(0xFF80) == value + assert value in ram.hi_ram + assert value not in ram.work_ram - address = 0xFFFE value += 1 - ram.write(address, value) - assert ram.read(address) == value - assert value in ram.h_ram - assert value not in ram.w_ram + ram.write(0xFFFE, value) + assert ram.read(0xFFFE) == value + assert value in ram.hi_ram + assert value not in ram.work_ram - address += 1 value += 1 - ram.write(address, value) + ram.write(0xFFFF, value) try: - ram.read(address) + ram.read(0xFFFF) py.test.fail() except Exception: pass - assert value not in ram.h_ram - assert value not in ram.w_ram \ No newline at end of file + assert value not in ram.hi_ram + assert value not in ram.work_ram + +def test_read_write_work_ram(): + ram = get_ram(); + ram.hi_ram = None + for i in range(0xC000, 0xFDFF): + ram.write(i, i) + assert ram.read(i) == i & 0xFF + +def test_read_write_hi_ram(): + ram = get_ram(); + ram.work_ram = None + for i in range(0xFF80, 0xFFFE): + ram.write(i, i) + assert ram.read(i) == i & 0xFF \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_serial.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_serial.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_serial.py Tue Jun 10 12:48:46 2008 @@ -9,63 +9,64 @@ def test_reset(): serial = get_serial() - serial.cycles = 12 - serial.sb = 12 - serial.sc = 12 + serial.cycles = 12 + serial.serial_data = 12 + serial.serial_control = 12 serial.reset() - assert serial.cycles == constants.SERIAL_CLOCK - assert serial.sb == 0 - assert serial.sc == 0 + assert serial.cycles == constants.SERIAL_CLOCK + assert serial.serial_data == 0 + assert serial.serial_control == 0 def test_set_serial_control(): serial = get_serial() - value = 0x12 + value = 0x12 serial.set_serial_control(value) assert serial.get_serial_control() == value - assert serial.cycles == constants.SERIAL_IDLE_CLOCK + constants.SERIAL_CLOCK + assert serial.cycles == constants.SERIAL_IDLE_CLOCK + \ + constants.SERIAL_CLOCK def test_emulate(): serial = get_serial() - serial.sc = 0x00 + serial.serial_control = 0x00 serial.emulate(20) - assert serial.cycles == constants.SERIAL_CLOCK - assert serial.sb == 0 - assert serial.sc == 0 + assert serial.cycles == constants.SERIAL_CLOCK + assert serial.serial_data == 0 + assert serial.serial_control == 0 serial.reset() - serial.sc = 0x81 - serial.cycles = 10 + serial.serial_control = 0x81 + serial.cycles = 10 cycles = serial.cycles serial.emulate(2) assert serial.cycles > 0 - assert cycles-serial.cycles == 2 - assert serial.sb == 0 - assert serial.sc == 0x81 + assert cycles-serial.cycles == 2 + assert serial.serial_data == 0 + assert serial.serial_control == 0x81 assert serial.interrupt.serial.is_pending() == False serial.reset() - serial.sc = 0x81 + serial.serial_control = 0x81 serial.cycles = 0 serial.emulate(2) - assert serial.sb == 0xFF - assert serial.sc == 0x81 & 0x7F - assert serial.cycles == constants.SERIAL_IDLE_CLOCK + assert serial.serial_data == 0xFF + assert serial.serial_control == 0x81 & 0x7F + assert serial.cycles == constants.SERIAL_IDLE_CLOCK assert serial.interrupt.serial.is_pending() == True def test_read_write(): serial = get_serial() value = 0x12 - serial.write(constants.SB, value) - assert serial.read(constants.SB) == value - assert serial.sb == value + serial.write(constants.SERIAL_TRANSFER_DATA, value) + assert serial.read(constants.SERIAL_TRANSFER_DATA) == value + assert serial.serial_data == value value += 1 - serial.write(constants.SC, value) - assert serial.read(constants.SC) == value - assert serial.sc == value + serial.write(constants.SERIAL_TRANSFER_CONTROL, value) + assert serial.read(constants.SERIAL_TRANSFER_CONTROL) == value + assert serial.serial_control == value assert serial.read(0) == 0xFF \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_timer.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_timer.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_timer.py Tue Jun 10 12:48:46 2008 @@ -14,31 +14,31 @@ def test_reset(timer=None): if timer is None: timer = get_timer() - assert timer.div == 0 + assert timer.divider == 0 assert timer.divider_cycles == constants.DIV_CLOCK - assert timer.tima == 0 - assert timer.tma == 0 - assert timer.tac == 0 - assert timer.timer_cycles == constants.TIMER_CLOCK[0] - assert timer.timer_clock == constants.TIMER_CLOCK[0] + assert timer.timer_counter == 0 + assert timer.timer_modulo == 0 + assert timer.timer_control == 0 + assert timer.timer_cycles == constants.TIMER_CLOCK[0] + assert timer.timer_clock == constants.TIMER_CLOCK[0] def test_read_write(): - timer = get_timer() - timer.div = 10 - value = 0x11 + timer = get_timer() + timer.divider = 10 + value = 0x11 timer.write(constants.DIV, value) - assert timer.get_divider() == 0 + assert timer.get_divider() == 0 assert timer.read(constants.DIV) == 0 timer.reset() timer.write(constants.TIMA, value) - assert timer.get_timer_counter() == value + assert timer.get_timer_counter() == value assert timer.read(constants.TIMA) == value timer.reset() timer.write(constants.TMA, value) - assert timer.get_timer_modulo() == value + assert timer.get_timer_modulo() == value assert timer.read(constants.TMA) == value timer.reset() @@ -54,83 +54,174 @@ timer = get_timer() value = 0x12 timer.set_timer_control(value) - assert timer.tac == value - assert timer.timer_cycles == constants.TIMER_CLOCK[value & 0x03] - assert timer.timer_clock == constants.TIMER_CLOCK[value & 0x03] + assert timer.timer_control == value + assert timer.timer_cycles == constants.TIMER_CLOCK[value & 0x03] + assert timer.timer_clock == constants.TIMER_CLOCK[value & 0x03] timer.reset() - timer.tac = value+1 - timer.timer_clock = 0 - timer.timer_cycles = 0 + timer.timer_control = value+1 + timer.timer_clock = 0 + timer.timer_cycles = 0 timer.set_timer_control(value+1) - assert timer.tac == value+1 - assert timer.timer_clock == 0 - assert timer.timer_clock == 0 + assert timer.timer_control == value+1 + assert timer.timer_clock == 0 + assert timer.timer_clock == 0 def test_read_write_divider(): - timer = get_timer() - value = 0x12 - timer.div = value - assert timer.get_divider() == timer.div + timer = get_timer() + value = 0x12 + timer.divider = value + assert timer.get_divider() == timer.divider # divider resets on write timer.set_divider(value) assert timer.get_divider() == 0 def test_cycles(): - timer = get_timer() - value = 10 + timer = get_timer() + value = 10 timer.divider_cycles = value assert timer.get_cycles() == timer.divider_cycles - timer.tac = 0x04 - timer.timer_cycles = value-1 - timer.timer_cycles = value + timer.timer_control = 0x04 + timer.timer_cycles = value-1 + timer.timer_cycles = value assert timer.get_cycles() == timer.timer_cycles -def test_emulate_divider_normal(): - timer = get_timer() - value = 2 - timer.timer_cycles = 0 - timer.emulate_timer(value) +def test_emulate_divider(): + timer = get_timer() + timer.divider_cycles = 10 + timer.divider = 1 + timer.emulate_divider(2) + assert timer.divider == 1 + assert timer.divider_cycles == 8 + +def test_test_emulate_divider_below_zero(): + timer = get_timer() + timer.divider_cycles = 0 + timer.divider = 1 + timer.emulate_divider(2) + assert timer.divider_cycles == constants.DIV_CLOCK - 2 + assert timer.divider == 2 + + timer.divider_cycles = 0 + timer.divider = 1 + timer.emulate_divider(0) + assert timer.divider_cycles == constants.DIV_CLOCK + assert timer.divider == 2 -def test_test_emulate_divider_zero(): - timer = get_timer() - value = 2 - timer.timer_cycles = value - timer.emulate_timer(value) - assert timer.timer_cycles == value + timer.divider_cycles = 0 + timer.divider = 0xFF + timer.emulate_divider(2) + assert timer.divider_cycles == constants.DIV_CLOCK - 2 + assert timer.divider == 0 + + timer.divider_cycles = 0 + timer.divider = 0 + timer.emulate_divider(2*constants.DIV_CLOCK) + assert timer.divider_cycles == constants.DIV_CLOCK + assert timer.divider == 3 -def test_emulate_timer_tac_return(): +def test_emulate_timer_timer_control_return(): timer = get_timer() - timer.tac = 0 - timer.timer_cycles = -10 - cycles = timer.timer_cycles + timer.timer_control = 0 + timer.timer_cycles = -10 + timer.timer_counter = 3 timer.emulate_timer(10) - assert timer.timer_cycles == cycles + assert timer.timer_cycles == -10 + assert timer.timer_counter == 3 def test_emulate_timer_timer_cycles_return(): timer = get_timer() - timer.tac = 0x04 - value = 10 - timer.timer_cycles = value+1 - cycles = timer.timer_cycles - timer.emulate_timer(value) + timer.timer_control = 0x04 + timer.timer_cycles = 11 + cycles = timer.timer_cycles + timer.emulate_timer(10) assert timer.timer_cycles == 1 +def test_emulate_timer_timer_cycles_timer_counter(): timer = get_timer() - timer.tac = 0x04 + timer.timer_control = 0x04 + timer.timer_counter = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 3 + assert timer.timer_cycles == 5 + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 5 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2+5 + assert timer.timer_cycles == 5 +def test_emulate_timer_timer_cycles_timer_counter_single_0_pass(): + timer = get_timer() + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 0 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2 + assert timer.timer_cycles == 5 -def test_emulate_timer_interrupt(): + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 1 + timer.timer_cycles = 0 + timer.timer_clock = 5 + timer.emulate_timer(10) + assert timer.timer_counter == 2+1 + assert timer.timer_cycles == 5 + + +def test_emulate_timer_timer_cycles_timer_counter_mutli_0_pass(): timer = get_timer() - ticks = 0 - timer.tac = 0x04 - timer.tima = -1 + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 0 + timer.timer_cycles = 0 + timer.timer_clock = 1 + # emulate 0xFF + 1+1 times => 2 zero passes + timer.emulate_timer(0xFF+1) + assert timer.timer_counter == 0 + assert timer.timer_cycles == 1 + + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = 1 + timer.timer_cycles = 0 + timer.timer_clock = 1 + # emulate 0xFF + 1+1 times => 2 zero passes + timer.emulate_timer(0xFF+1) + assert timer.timer_counter == 2*1 + assert timer.timer_cycles == 1 + + # emulate n zero passes + for i in range(1,10): + timer.timer_control = 0x04 + timer.timer_counter = 0xFF + timer.timer_modulo = i + timer.timer_cycles = 0 + timer.timer_clock = 1 + timer.emulate_timer((0xFF+1)*(i-1)) + assert timer.timer_counter == i*i + assert timer.timer_cycles == 1 + + + +def test_emulate_timer_interrupt(): + timer = get_timer() + ticks = 0 + timer.timer_control = 0x04 + timer.timer_counter = -1 # raise an interupt as we pass 0 assert timer.interrupt.is_pending(constants.TIMER) == False - assert timer.interrupt.timer.is_pending() == False + assert timer.interrupt.timer.is_pending() == False timer.timer_cycles = -timer.timer_clock+1 timer.emulate_timer(ticks) - assert timer.timer_cycles == 1 - assert timer.tima == timer.tma + assert timer.timer_cycles == 1 + assert timer.timer_counter == timer.timer_modulo assert timer.interrupt.timer.is_pending() \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/test/test_video.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/test/test_video.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/test/test_video.py Tue Jun 10 12:48:46 2008 @@ -0,0 +1,359 @@ +from pypy.lang.gameboy.video import * +from pypy.lang.gameboy.interrupt import Interrupt +import pypy.lang.gameboy.constants +import py + +class Memory(object): + def __init__(self): + self.memory = [0xFF]*0xFFFFF + + def write(self, address, data): + self.memory[address] = data + + def read(self, address): + return self.memory[address] + +# ---------------------------------------------------------------------------- + +def get_video(): + return Video(get_video_driver(), Interrupt(), Memory()) + +def get_video_driver(): + return VideoDriver() + +# ---------------------------------------------------------------------------- + + +def test_reset(): + video = get_video() + assert video.cycles == constants.MODE_2_TICKS + assert video.control == 0x91 + assert video.stat == 2 + assert video.line_y == 0 + assert video.line_y_compare == 0 + assert video.dma == 0xFF + assert video.scroll_x == 0 + assert video.scroll_y == 0 + assert video.window_x == 0 + assert video.window_y == 0 + assert video.window_line_y == 0 + assert video.background_palette == 0xFC + assert video.object_palette_0 == 0xFF + assert video.object_palette_1 == 0xFF + assert video.transfer == True + assert video.display == True + assert video.vblank == True + assert video.dirty == True + assert len(video.vram) == constants.VRAM_SIZE + assert len(video.oam) == constants.OAM_SIZE + assert len(video.line) == 176 + assert len(video.objects) == constants.OBJECTS_PER_LINE + assert len(video.palette) == 1024 + assert video.frames == 0 + assert video.frame_skip == 0 + +def test_read_write_properties(): + video = get_video() + checks = [(0xFF40, "control"), + (0xFF42, "scroll_y"), + (0xFF43, "scroll_x"), + #(0xFF44, "line_y"), read only + (0xFF45, "line_y_compare"), + (0xFF46, "dma"), + (0xFF47, "background_palette"), + (0xFF48, "object_palette_0"), + (0xFF49, "object_palette_1"), + (0xFF4A, "window_y"), + (0xFF4B, "window_x")] + counted_value = 0 + for check in checks: + address = check[0] + property = check[1] + value = counted_value + if len(check) > 2: + value = check[2] + video.write(address, value) + assert video.__getattribute__(property) == value + assert video.read(address) == value + counted_value = (counted_value + 1 ) % 0xFF + +def test_set_status(): + video = get_video() + value = 0x95 + valueb = 0xD2 + video.stat = valueb + video.write(0xFF41, value) + assert video.stat == (valueb & 0x87) | (value & 0x78) + + video.control = 0x80 + video.stat = 0x01 + video.write(0xFF41, 0x01) + assert video.interrupt.lcd.is_pending() + + +def test_set_line_y_compare(): + video = get_video() + value = 0xF6 + video.write(0xFF45, value) + assert video.line_y_compare == value + + video.control = 0x80 + video.line_y = value -1 + video.stat = 0xFF + video.write(0xFF45, value) + assert video.stat == 0xFB + assert video.interrupt.lcd.is_pending() == False + + video.control = 0x80 + video.line_y = value + video.stat = 0x40 + video.write(0xFF45, value) + assert video.stat == 0x44 + assert video.interrupt.lcd.is_pending() == True + + +def test_control(): + video = get_video() + + video.control = 0x80 + video.window_line_y = 1 + video.write(0xFF40, 0x80) + assert video.control == 0x80 + assert video.window_line_y == 1 + +def test_control_window_draw_skip(): + video = get_video() + video.control = 0x80 + video.window_y = 0 + video.line_y = 1 + video.window_line_y = 0 + video.write(0xFF40, 0x80+0x20) + assert video.control == 0x80+0x20 + assert video.window_line_y == 144 + +def test_control_reset1(): + video = get_video() + video.control = 0 + video.stat = 0x30 + video.line_y = 1 + video.display = True + video.write(0xFF40, 0x80) + assert video.control == 0x80 + assert video.stat == 0x30 + 0x02 + assert video.cycles == constants.MODE_2_TICKS + assert video.line_y == 0 + assert video.display == False + +def test_control_reset2(): + video = get_video() + video.control = 0x80 + video.stat = 0x30 + video.line_y = 1 + video.display = True + video.write(0xFF40, 0x30) + assert video.control == 0x30 + assert video.stat == 0x30 + assert video.cycles == constants.MODE_1_TICKS + assert video.line_y == 0 + assert video.display == True + +def test_video_dirty_properties(): + video = get_video() + video.background_palette = 0 + video.dirty = False + video.write(0xFF47, 0) + assert video.dirty == False + assert video.dirty == 0 + video.write(0xFF47, 1) + assert video.dirty == True + assert video.background_palette == 1 + video.dirty = False + video.write(0xFF47, 1) + assert video.dirty == False + + + video.object_palette_0 = 0 + video.write(0xFF48, 0) + assert video.dirty == False + assert video.object_palette_0 == 0 + video.write(0xFF48, 1) + assert video.dirty == True + assert video.object_palette_0 == 1 + video.dirty = False + video.write(0xFF48, 1) + assert video.dirty == False + + + video.object_palette_1 = 0 + video.write(0xFF49, 0) + assert video.dirty == False + assert video.object_palette_1 == 0 + video.write(0xFF49, 1) + assert video.dirty == True + assert video.object_palette_1 == 1 + video.dirty = False + video.write(0xFF49, 1) + assert video.dirty == False + + +def test_emulate_OAM(): + video = get_video() + video.transfer = False + video.stat = 0xFE + video.cycles = 0 + video.emulate_oam() + assert video.stat == 0xFF + assert video.cycles == constants.MODE_3_BEGIN_TICKS + assert video.transfer == True + +def test_emulate_transfer(): + video = get_video() + + video.transfer = False + video.cycles = 0 + video.stat = 0xF0 + video.emulate_transfer() + assert video.stat == 0xF0 + assert video.cycles == constants.MODE_0_TICKS + assert not video.interrupt.lcd.is_pending() + + video.transfer = False + video.cycles = 0 + video.stat = 0xF8 + assert not video.interrupt.lcd.is_pending() + video.emulate_transfer() + assert video.stat == 0xF8 + assert video.cycles == constants.MODE_0_TICKS + assert video.interrupt.lcd.is_pending() + + video.transfer = True + video.cycles = 0 + video.stat = 0xFC + video.emulate_transfer() + assert video.cycles == constants.MODE_3_END_TICKS + assert video.transfer == False + assert video.stat == 0xFF + + +def test_emulate_h_blank_part_1_1(): + video = get_video() + video.line_y = 0 + video.line_y_compare = 1 + video.stat = 0x20 + video.cycles = 0 + video.frames = 0 + assert not video.interrupt.lcd.is_pending() + video.emulate_hblank() + assert video.cycles == constants.MODE_2_TICKS + assert video.interrupt.lcd.is_pending() + assert video.stat == 0x20 + 0x04 + 0x2 + assert video.line_y == 1 + assert video.frames == 0 + + +def test_emulate_h_blank_part_2_1(): + video = get_video() + video.line_y = 1 + video.line_y_compare = 0 + video.stat = 0x0F + video.cycles = 0 + video.frames = 0 + video.emulate_hblank() + assert video.line_y == 2 + assert video.cycles == constants.MODE_2_TICKS + assert not video.interrupt.lcd.is_pending() + assert video.stat == 0x0B&0xFC + 0x2 + assert video.frames == 0 + +def test_emulate_h_blank_part_2_2(): + video = get_video() + video.line_y = 144 + video.line_y_compare = 0 + video.stat = 0xFB + video.cycles = 0 + video.frames = 0 + video.frame_skip = 20 + video.vblank = False + video.display = False + video.emulate_hblank() + assert video.line_y == 145 + assert video.cycles == constants.MODE_1_BEGIN_TICKS + assert not video.interrupt.lcd.is_pending() + assert video.stat == 0xFB & 0xFC + 0x01 + assert video.frames == 1 + assert video.display == False + assert video.vblank == True + + +def test_emulate_h_blank_part_2_2_frame_skip(): + video = get_video() + video.line_y = 144 + video.line_y_compare = 0 + video.stat = 0xFB + video.cycles = 0 + video.frames = 10 + video.frame_skip = 10 + video.vblank = False + video.display = False + video.emulate_hblank() + assert video.line_y == 145 + assert video.cycles == constants.MODE_1_BEGIN_TICKS + assert not video.interrupt.lcd.is_pending() + assert video.stat == 0xFB & 0xFC + 0x01 + assert video.frames == 0 + assert video.vblank == True + + +def test_emulate_v_vblank_1(): + video = get_video() + video.interrupt.set_fnterrupt_flag(0) + video.stat = 0xFE + video.vblank = True + video.cycles = 0 + video.emulate_vblank() + assert video.vblank == False + assert video.stat == 0xFD + assert video.cycles == constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS + assert video.interrupt.vblank.is_pending() + assert video.interrupt.lcd.is_pending() + + video.interrupt.set_fnterrupt_flag(0) + video.stat = 0x00 + video.vblank = True + assert not video.interrupt.vblank.is_pending() + assert not video.interrupt.lcd.is_pending() + video.emulate_vblank() + assert video.stat == 0x01 + assert video.interrupt.vblank.is_pending() + assert not video.interrupt.lcd.is_pending() + + + +def test_emulate_v_vblank_2(): + video = get_video() + video.interrupt.set_fnterrupt_flag(0) + video.stat = 0x2D + video.vblank = False + video.cycles = 0 + video.line_y = 0 + video.emulate_vblank() + assert video.vblank == False + assert video.stat == 0x2E + assert video.cycles == constants.MODE_2_TICKS + assert not video.interrupt.vblank.is_pending() + assert video.interrupt.lcd.is_pending() + + video.interrupt.set_fnterrupt_flag(0) + video.cycles = 0 + video.stat = 0xFD + video.emulate_vblank() + assert video.vblank == False + assert video.stat == 0xFE + assert video.cycles == constants.MODE_2_TICKS + assert not video.interrupt.lcd.is_pending() + + +def test_emulate_v_vblank_3(): + py.test.skip("not yet implemented") + + \ No newline at end of file Modified: pypy/branch/build-external/pypy/lang/gameboy/timer.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/timer.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/timer.py Tue Jun 10 12:48:46 2008 @@ -1,5 +1,5 @@ """ -PyBoy GameBoy (TM) Emulator +PyGirl GameBoy (TM) Emulator Timer and Divider """ @@ -9,8 +9,16 @@ from math import ceil from pypy.lang.gameboy.ram import iMemory import time +import math +class TimerControl(object): + def __init__(self): + self.reset() + + def reset(self): + pass + class Timer(iMemory): def __init__(self, interrupt): @@ -19,16 +27,15 @@ self.reset() def reset(self): - self.div = 0 + self.divider = 0 self.divider_cycles = constants.DIV_CLOCK - self.tima = 0 - self.tma = 0 - self.tac = 0 + self.timer_counter = 0 + self.timer_modulo = 0 + self.timer_control = 0 self.timer_cycles = constants.TIMER_CLOCK[0] self.timer_clock = constants.TIMER_CLOCK[0] def write(self, address, data): - address = int(address) if address == constants.DIV: self.set_divider(data) elif address == constants.TIMA: @@ -39,7 +46,6 @@ self.set_timer_control(data) def read(self, address): - address = int(address) if address == constants.DIV: return self.get_divider() elif address == constants.TIMA: @@ -51,34 +57,39 @@ return 0xFF def get_divider(self): - return self.div + return self.divider - def set_divider(self, data): #DIV register resets on write - self.div = 0 + def set_divider(self, data): + """ DIV register resets on write """ + self.divider = 0 def get_timer_counter(self): - return self.tima + return self.timer_counter def set_timer_counter(self, data): - self.tima = data + self.timer_counter = data + def get_timer_modulo(self): - return self.tma + return self.timer_modulo def set_timer_modulo(self, data): - self.tma = data + self.timer_modulo = data + def get_timer_control(self): - return 0xF8 | self.tac + return 0xF8 | self.timer_control def set_timer_control(self, data): - if (self.tac & 0x03) != (data & 0x03): + if (self.timer_control & 0x03) != (data & 0x03): self.timer_clock = constants.TIMER_CLOCK[data & 0x03] self.timer_cycles = constants.TIMER_CLOCK[data & 0x03] - self.tac = data + self.timer_control = data + def get_cycles(self): - if (self.tac & 0x04) != 0 and self.timer_cycles < self.divider_cycles: + if (self.timer_control & 0x04) != 0 and \ + self.timer_cycles < self.divider_cycles: return self.timer_cycles return self.divider_cycles @@ -90,21 +101,36 @@ self.divider_cycles -= ticks if self.divider_cycles > 0: return - while self.divider_cycles <= 0: - self.div = (self.div + 1) & 0xFF; - self.divider_cycles += constants.DIV_CLOCK; + count = int(math.ceil(-self.divider_cycles / + constants.DIV_CLOCK)+1) + self.divider_cycles += count*constants.DIV_CLOCK + self.divider = (self.divider + count) % (0xFF+1); def emulate_timer(self, ticks): - if (self.tac & 0x04) == 0: + if (self.timer_control & 0x04) == 0: return self.timer_cycles -= ticks while self.timer_cycles <= 0: - self.tima = (self.tima + 1) & 0xFF + self.timer_counter = (self.timer_counter + 1) & 0xFF self.timer_cycles += self.timer_clock - if self.tima == 0x00: - self.tima = self.tma + if self.timer_counter == 0x00: + self.timer_counter = self.timer_modulo self.interrupt.raise_interrupt(constants.TIMER) - + + #def emulate_timer(self, ticks): + # if (self.timer_control & 0x04) == 0: + # return + # self.timer_cycles -= ticks + # if self.timer_cycles > 0: return + # count = int(math.ceil(-self.timer_cycles / self.timer_clock)) + 1 + # self.timer_cycles += self.timer_clock*count + # # check for zero pass + # if (self.timer_counter + count) > 0xFF: + # self.interrupt.raise_interrupt(constants.TIMER) + # zero_passes = math.ceil(self.timer_counter / count) + # self.timer_counter = (self.timer_modulo + count - zero_passes ) % (0xFF +1) + # else: + # self.timer_counter = (self.timer_counter + count) % (0xFF +1) # CLOCK DRIVER ----------------------------------------------------------------- class Clock(object): Modified: pypy/branch/build-external/pypy/lang/gameboy/video.py ============================================================================== --- pypy/branch/build-external/pypy/lang/gameboy/video.py (original) +++ pypy/branch/build-external/pypy/lang/gameboy/video.py Tue Jun 10 12:48:46 2008 @@ -1,10 +1,11 @@ """ - PyBoy GameBoy (TM) Emulator + PyGirl GameBoy (TM) Emulator constants.LCD Video Display Processor """ from pypy.lang.gameboy import constants from pypy.lang.gameboy.ram import iMemory +from pypy.lang.gameboy.cpu import process_2_complement @@ -33,19 +34,31 @@ # ----------------------------------------------------------------------------- def VideoStatus(object): + # used for enabled or disabled window or background + # Bit 7 - LCD Display Enable (0=Off, 1=On) + # Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) + # Bit 5 - Window Display Enable (0=Off, 1=On) + # Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF) + # Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) + # Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16) + # Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On) + # Bit 0 - BG Display (for CGB see below) (0=Off, 1=On) + def __init__(self, video): self.video = video self.reset() def reset(self): - self.mode = False - self.lyc_ly_coincidence = False - self.h_blank_interrupt = False - self.oam_interrupt = False - self.h_blank_interrupt = False - self.v_blank_interrupt = False + self.mode = 0x02 + self.lcd_enable = False + self.window_tile_map_select = False + self.window_enable = False + self.background_and_window_tile_data_select = False + self.background_tile_map_select = False + self.big_sprite_size = False + self.sprite_display_enable = False + self.background_enable = False #Coincidence Flag (0:LYC<>LY, 1:LYC=LY) - self.coincidence_flag = False def read(self): value = 0 @@ -53,25 +66,26 @@ value += int(self.h_blank_interrupt) << 6 value += int(self.oam_interrupt) << 5 value += int(self.h_blank_interrupt) << 4 - value += int(self.v_blank_interrupt) << 3 + value += int(self.vblank_interrupt) << 3 value += int(self.coincidence_flag) << 2 value += self.mode & 0x03 return value def write(self, value): + self.lyc_ly_coincidence = bool(value & (1 << 7)) + self.h_blank_interrupt = bool(value & (1 << 6)) + self.oam_interrupt = bool(value & (1 << 5)) + self.h_blank_interrupt = bool(value & (1 << 4)) + self.vblank_interrupt = bool(value & (1 << 3)) + self.coincidence_flag = bool(value & (1 << 2)) + self.mode = value & 0x03 + + def get_bg_tile_data_address(self): pass - # ----------------------------------------------------------------------------- class Video(iMemory): - #frames = 0 - #frame_skip = 0 - - # Line Buffer, constants.OAM Cache and Color Palette - #line = []#= new int[8 + 160 + 8] - #objects = []#= new int[OBJECTS_PER_LINE] - #palette = []#= new int[1024] def __init__(self, video_driver, interrupt, memory): assert isinstance(video_driver, VideoDriver) @@ -88,15 +102,6 @@ def reset(self): self.cycles = constants.MODE_2_TICKS - # used for enabled or disablind window or background - # Bit 7 - LCD Display Enable (0=Off, 1=On) - # Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) - # Bit 5 - Window Display Enable (0=Off, 1=On) - # Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF) - # Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF) - # Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16) - # Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On) - # Bit 0 - BG Display (for CGB see below) (0=Off, 1=On) self.control = 0x91 self.stat = 2 self.line_y = 0 @@ -109,7 +114,7 @@ # window position self.window_x = 0 self.window_y = 0 - self.wline_y = 0 + self.window_line_y = 0 self.background_palette = 0xFC self.object_palette_0 = 0xFF self.object_palette_1 = 0xFF @@ -145,7 +150,7 @@ # Read Online_y pass elif address == constants.LYC: - self.set_ly_compare(data) + self.set_line_y_compare(data) elif address == constants.DMA: self.set_dma(data) elif address == constants.BGP: @@ -163,10 +168,10 @@ def write_oam(self, address, data): if address >= constants.OAM_ADDR and \ - address < constants.OAM_ADDR + constants.OAM_SIZE: - self.oam[address - constants.OAM_ADDR] = data & 0xFF + address < (constants.OAM_ADDR + constants.OAM_SIZE): + self.oam[address - constants.OAM_ADDR] = data & 0xFF elif address >= constants.VRAM_ADDR and \ - address < constants.VRAM_ADDR + constants.VRAM_SIZE: + address < (constants.VRAM_ADDR + constants.VRAM_SIZE): self.vram[address - constants.VRAM_ADDR] = data & 0xFF def read(self, address): @@ -199,11 +204,11 @@ return self.read_oam(address) def read_oam(self, address): - if (address >= constants.OAM_ADDR and \ - address < constants.OAM_ADDR + constants.OAM_SIZE): + if (address >= constants.OAM_ADDR and + address < (constants.OAM_ADDR + constants.OAM_SIZE)): return self.oam[address - constants.OAM_ADDR] - elif (address >= constants.VRAM_ADDR and \ - address < constants.VRAM_ADDR + constants.VRAM_SIZE): + elif (address >= constants.VRAM_ADDR and + address < (constants.VRAM_ADDR + constants.VRAM_SIZE)): return self.vram[address - constants.VRAM_ADDR] return 0xFF @@ -236,21 +241,20 @@ self.reset_control(data) # don't draw window if it was not enabled and not being drawn before if (self.control & 0x20) == 0 and (data & 0x20) != 0 and \ - self.wline_y == 0 and self.line_y > self.window_y: - self.wline_y = 144 + self.window_line_y == 0 and self.line_y > self.window_y: + self.window_line_y = 144 self.control = data def reset_control(self, data): # NOTE: do not reset constants.LY=LYC flag (bit 2) of the STAT register (Mr. Do!) + self.line_y = 0 + self.stat = (self.stat & 0xFC) if (data & 0x80) != 0: - self.stat = (self.stat & 0xFC) | 0x02 + self.stat |= 0x02 self.cycles = constants.MODE_2_TICKS - self.line_y = 0 self.display = False else: - self.stat = (self.stat & 0xFC) | 0x00 self.cycles = constants.MODE_1_TICKS - self.line_y = 0 self.clear_frame() def get_status(self): @@ -258,9 +262,13 @@ def set_status(self, data): self.stat = (self.stat & 0x87) | (data & 0x78) + self.set_status_bug() + + def set_status_bug(self) : # Gameboy Bug - if (self.control & 0x80) != 0 and (self.stat & 0x03) == 0x01 and \ - (self.stat & 0x44) != 0x44: + if (self.control & 0x80) != 0x00 and \ + (self.stat & 0x03) == 0x01 and \ + (self.stat & 0x44) != 0x44: self.interrupt.raise_interrupt(constants.LCD) def get_scroll_y(self): @@ -281,51 +289,43 @@ def get_line_y_compare(self): return self.line_y_compare - def set_ly_compare(self, data): + def set_line_y_compare(self, data): self.line_y_compare = data if (self.control & 0x80) == 0: return - if self.line_y == self.line_y_compare: - # NOTE: raise interrupt once per line - if (self.stat & 0x04) == 0: - # constants.LYC=LY interrupt - self.stat |= 0x04 -# if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) - else: - self.stat &= 0xFB + self.emulate_hblank_line_y_compare() def get_dma(self): return self.dma def set_dma(self, data): self.dma = data - for index in range(0, constants.OAM_SIZE): + for index in range(constants.OAM_SIZE): self.oam[index] = self.memory.read((self.dma << 8) + index) def get_background_palette(self): return self.background_palette def set_background_palette(self, data): - if self.background_palette != data: - self.background_palette = data - self.dirty = True + if self.background_palette == data: return + self.background_palette = data + self.dirty = True def get_object_palette_0(self): return self.object_palette_0 def set_object_palette_0(self, data): - if self.object_palette_0 != data: - self.object_palette_0 = data - self.dirty = True + if self.object_palette_0 == data: return + self.object_palette_0 = data + self.dirty = True def get_object_palette_1(self): return self.object_palette_1 def set_object_palette_1(self, data): - if self.object_palette_1 != data: - self.object_palette_1 = data - self.dirty = True + if self.object_palette_1 == data: return + self.object_palette_1 = data + self.dirty = True def get_window_y(self): return self.window_y @@ -340,48 +340,89 @@ self.window_x = data def emulate_oam(self): - self.stat = (self.stat & 0xFC) | 0x03 - self.cycles += constants.MODE_3_BEGIN_TICKS - self.transfer = True + self.set_mode_3_begin() def emulate_transfer(self): if self.transfer: if self.display: self.draw_line() - self.stat = (self.stat & 0xFC) | 0x03 - self.cycles += constants.MODE_3_END_TICKS - self.transfer = False - else: - self.stat = (self.stat & 0xFC) - self.cycles += constants.MODE_0_TICKS - # H-Blank interrupt - if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) - + self.set_mode_3_end() + else: + self.set_mode_0() + + # interrupt checks --------------------------------------------------- + + def h_blank_interrupt_check(self): + if (self.stat & 0x08) != 0 and (self.stat & 0x44) != 0x44: + self.interrupt.raise_interrupt(constants.LCD) + + def oam_interrupt_check(self): + if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: + self.interrupt.raise_interrupt(constants.LCD) + + def v_blank_interrupt_check(self): + if (self.stat & 0x10) != 0: + self.interrupt.raise_interrupt(constants.LCD) + + def line_y_line_y_compare_interrupt_check(self): + self.stat |= 0x04 + if (self.stat & 0x40) != 0: + self.interrupt.raise_interrupt(constants.LCD) + + # mode setting ----------------------------------------------------------- + + def set_mode_3_begin(self): + self.stat = (self.stat & 0xFC) | 0x03 + self.cycles += constants.MODE_3_BEGIN_TICKS + self.transfer = True + + def set_mode_3_end(self): + self.stat = (self.stat & 0xFC) | 0x03 + self.cycles += constants.MODE_3_END_TICKS + self.transfer = False + + def set_mode_0(self): + self.stat = (self.stat & 0xFC) + self.cycles += constants.MODE_0_TICKS + self.h_blank_interrupt_check() + + def set_mode_2(self): + self.stat = (self.stat & 0xFC) | 0x02 + self.cycles += constants.MODE_2_TICKS + self.oam_interrupt_check() + + def set_mode_1_begin(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_BEGIN_TICKS + + def set_mode_1(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_TICKS + + def set_mode_1_between(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS + + def set_mode_1_end(self): + self.stat = (self.stat & 0xFC) | 0x01 + self.cycles += constants.MODE_1_END_TICKS + + # ---------------------------------------------------------------- + def emulate_hblank(self): self.line_y+=1 self.emulate_hblank_line_y_compare() if self.line_y < 144: - self.emulate_hblank_part_1() + self.set_mode_2() else: self.emulate_hblank_part_2() def emulate_hblank_line_y_compare(self): if self.line_y == self.line_y_compare: - # constants.LYC=LY interrupt - self.stat |= 0x04 - if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) + self.line_y_line_y_compare_interrupt_check() else: self.stat &= 0xFB - - def emulate_hblank_part_1(self): - self.stat = (self.stat & 0xFC) | 0x02 - self.cycles += constants.MODE_2_TICKS - # constants.OAM interrupt - if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) - + def emulate_hblank_part_2(self): if self.display: self.draw_frame() @@ -391,55 +432,38 @@ self.frames = 0 else: self.display = False - - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_BEGIN_TICKS - self.vblank = True + self.set_mode_1_begin() + self.vblank = True def emulate_vblank(self): if self.vblank: self.emulate_vblank_vblank() elif self.line_y == 0: - self.emulate_vblank_first_y_line() + self.set_mode_2() else: self.emulate_vblank_other() def emulate_vblank_vblank(self): - self.vblank = False - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_TICKS - constants.MODE_1_BEGIN_TICKS - # V-Blank interrupt - if (self.stat & 0x10) != 0: - self.interrupt.raise_interrupt(constants.LCD) - # V-Blank interrupt + self.vblank = False + self.set_mode_1_between() + self.v_blank_interrupt_check() self.interrupt.raise_interrupt(constants.VBLANK) - def emulate_vblank_first_y_line(self): - self.stat = (self.stat & 0xFC) | 0x02 - self.cycles += constants.MODE_2_TICKS - # constants.OAM interrupt - if (self.stat & 0x20) != 0 and (self.stat & 0x44) != 0x44: - self.interrupt.raise_interrupt(constants.LCD) - def emulate_vblank_other(self): if self.line_y < 153: - self.line_y+=1 - self.stat = (self.stat & 0xFC) | 0x01 - if self.line_y == 153: - self.cycles += constants.MODE_1_END_TICKS - else: - self.cycles += constants.MODE_1_TICKS + self.emulate_vblank_mode_1() else: - self.line_y = self.wline_y = 0 - self.stat = (self.stat & 0xFC) | 0x01 - self.cycles += constants.MODE_1_TICKS - constants.MODE_1_END_TICKS - if self.line_y == self.line_y_compare: - # constants.LYC=LY interrupt - self.stat |= 0x04 - if (self.stat & 0x40) != 0: - self.interrupt.raise_interrupt(constants.LCD) + self.line_y = 0 + self.window_line_y = 0 + self.set_mode_1_between() + self.emulate_hblank_line_y_compare() + + def emulate_vblank_mode_1(self): + self.line_y += 1 + if self.line_y == 153: + self.set_mode_1_end() else: - self.stat &= 0xFB + self.set_mode_1() def draw_frame(self): self.driver.update_display() @@ -464,40 +488,53 @@ self.line[x] = 0x00 def draw_background(self): - y = (self.scroll_y + self.line_y) & 0xFF - x = self.scroll_x & 0xFF - tileMap = constants.VRAM_MAP_A - if (self.control & 0x08) != 0: - tileMap = constants.VRAM_MAP_B - tileData = constants.VRAM_DATA_B - if (self.control & 0x10) != 0: - tileData = constants.VRAM_DATA_A - tileMap += ((y >> 3) << 5) + (x >> 3) - tileData += (y & 7) << 1 - self.draw_tiles(8 - (x & 7), tileMap, tileData) - + y = (self.scroll_y + self.line_y) & 0xFF + x = self.scroll_x & 0xFF + tile_map, tile_data = self.prepare_background_data(x, y) + self.draw_tiles(8 - (x & 7), tile_map, tile_data) + + def prepare_background_data(self, x, y): + tile_map = self.get_tile_map(0x08) + tile_map += ((y >> 3) << 5) + (x >> 3) + tile_data = self.get_tile_data(0x10) + tile_data += (y & 7) << 1 + return tile_map, tile_data + def draw_window(self): - if self.line_y < self.window_y or self.window_x >= 167 or \ - self.wline_y >= 144: - return - tileMap = constants.VRAM_MAP_A - if (self.control & 0x40) != 0: - tileMap = constants.VRAM_MAP_B - tileData = constants.VRAM_DATA_B - if (self.control & 0x10) != 0: - tileData = constants.VRAM_DATA_A - tileMap += (self.wline_y >> 3) << 5 - tileData += (self.wline_y & 7) << 1 - self.draw_tiles(self.window_x + 1, tileMap, tileData) - self.wline_y+=1 - + if self.line_y < self.window_y or \ + self.window_x >= 167 or \ + self.window_line_y >= 144: + return + tile_map, tile_data = self.prepare_window_data() + self.draw_tiles(self.window_x + 1, tile_map, tile_data) + self.window_line_y += 1 + + def prepare_window_data(self): + tile_map = self.get_tile_map(0x40) + tile_map += (self.window_line_y >> 3) << 5 + tile_data = self.get_tile_data(0x10) + tile_data += (self.window_line_y & 7) << 1 + return tile_map, tile_data; + + def get_tile_map(self, mask): + if (self.control & mask) != 0: + return constants.VRAM_MAP_B + else: + return constants.VRAM_MAP_A + + def get_tile_data(self, mask): + if (self.control & mask) != 0: + return constants.VRAM_DATA_A + else: + return constants.VRAM_DATA_B + def draw_objects(self): count = self.scan_objects() lastx = 176 for index in range(176, count): - data = self.objects[index] - x = (data >> 24) & 0xFF - flags = (data >> 12) & 0xFF + data = self.objects[index] + x = (data >> 24) & 0xFF + flags = (data >> 12) & 0xFF address = data & 0xFFF if (x + 8 <= lastx): self.draw_object_tile(x, address, flags) @@ -509,15 +546,13 @@ count = 0 # search active objects for offset in range(0, 4*40, 4): - y = self.oam[offset + 0] & 0xFF - x = self.oam[offset + 1] & 0xFF + y = self.oam[offset + 0] + x = self.oam[offset + 1] if (y <= 0 or y >= 144 + 16 or x <= 0 or x >= 168): continue - tile = self.oam[offset + 2] & 0xFF - flags = self.oam[offset + 3] & 0xFF - - y = self.line_y - y + 16 - + tile = self.oam[offset + 2] + flags = self.oam[offset + 3] + y = self.line_y - y + 16 if ((self.control & 0x04) != 0): # 8x16 tile size if (y < 0 or y > 15): @@ -543,35 +578,52 @@ def sort_scan_object(self, count): # sort objects from lower to higher priority - for index in range(0, count): + for index in range(count): rightmost = index for number in range(index+1, count): if (self.objects[number] >> 20) > \ (self.objects[rightmost] >> 20): rightmost = number if rightmost != index: - data = self.objects[index] - self.objects[index] = self.objects[rightmost] + data = self.objects[index] + self.objects[index] = self.objects[rightmost] self.objects[rightmost] = data - def draw_tiles(self, x, tileMap, tileData): + def draw_tiles(self, x, tile_map, tile_data): while x < 168: if (self.control & 0x10) != 0: - tile = self.vram[tileMap] & 0xFF + tile = self.vram[tile_map] else: - tile = (self.vram[tileMap] ^ 0x80) & 0xFF - self.draw_tile(x, tileData + (tile << 4)) - tileMap = (tileMap & 0x1FE0) + ((tileMap + 1) & 0x001F) + tile = (process_2_complement(self.vram[tile_map]) ^ 0x80) & 0xFF + self.draw_tile(x, tile_data + (tile << 4)) + tile_map = (tile_map & 0x1FE0) + ((tile_map + 1) & 0x001F) x += 8 - + + def draw_tile(self, x, address): + pattern = self.get_pattern(address) + for i in range(0, 8): + self.line[x + i] = (pattern >> (7-i)) & 0x0101 + def get_pattern(self, address): - pattern = self.vram[address] & 0xFF - pattern += (self.vram[address + 1] & 0xFF) << 8 - return pattern + return self.vram[address] +(self.vram[address + 1]) << 8 + + def draw_object_tile(self, x, address, flags): + self.draw_object(set_tile_line_call_wrapper(self), x, address, flags) + + def set_tile_line(self, pos, color, mask): + self.line[pos] |= color | mask + + def draw_overlapped_object_tile(self, x, address, flags): + self.draw_object(set_overlapped_object_line_call_wrapper(self), + x, address, flags) + + def set_overlapped_object_line(self, pos, color, mask): + self.line[pos] = (self.line[pos] & 0x0101) | color | mask + def draw_object(self, caller, x, address, flags): pattern = self.get_pattern(address) - mask = 0 + mask = 0 # priority if (flags & 0x80) != 0: mask |= 0x0008 @@ -579,19 +631,10 @@ if (flags & 0x10) != 0: mask |= 0x0004 if (flags & 0x20) != 0: - self.draw_object_normal(x, pattern, mask, caller) - else: self.draw_object_flipped(x, pattern, mask, caller) + else: + self.draw_object_normal(x, pattern, mask, caller) - def draw_object_normal(self, x, pattern, mask, caller): - for i in range(0, 7): - color = pattern >> (6-i) - if (color & 0x0202) != 0: - caller.call(x+1, color, mask) - color = pattern << 1 - if (color & 0x0202) != 0: - caller.call(x+7, color, mask) - def draw_object_flipped(self, x, pattern, mask, caller): color = pattern << 1 if (color & 0x0202) != 0: @@ -600,24 +643,15 @@ color = pattern >> i if (color & 0x0202) != 0: caller.call(x + i + 1, color, mask) - - def draw_tile(self, x, address): - pattern = self.get_pattern(address) - for i in range(0, 8): - self.line[x + i] = (pattern >> (7-i)) & 0x0101 - - def draw_object_tile(self, x, address, flags): - self.draw_object(set_tile_line_call_wrapper(self), x, address, flags) - - def set_tile_line(self, pos, color, mask): - self.line[pos] |= color | mask - - def draw_overlapped_object_tile(self, x, address, flags): - self.draw_object(set_overlapped_object_line_call_wrapper(self), \ - x, address, flags) - - def set_overlapped_object_line(self, pos, color, mask): - self.line[pos] = (self.line[pos] & 0x0101) | color | mask + + def draw_object_normal(self, x, pattern, mask, caller): + for i in range(0, 7): + color = pattern >> (6-i) + if (color & 0x0202) != 0: + caller.call(x+1, color, mask) + color = pattern << 1 + if (color & 0x0202) != 0: + caller.call(x+7, color, mask) def draw_pixels(self): self.update_palette() @@ -625,7 +659,7 @@ offset = self.line_y * self.driver.get_width() for x in range(8, 168, 4): for i in range(0,4): - pattern = self.line[x + i] + pattern = self.line[x + i] pixels[offset + i] = self.palette[pattern] offset += 4 @@ -633,28 +667,28 @@ self.driver.clear_pixels() def update_palette(self): - if not self.dirty: - return - # bit 4/0 = constants.BG color, - # bit 5/1 = constants.OBJ color, - # bit 2 = constants.OBJ palette, - # bit 3 = constants.OBJ priority + if not self.dirty: return + # bit 4/0 = BG color, + # bit 5/1 = OBJ color, + # bit 2 = OBJ palette, + # bit 3 = OBJ priority for pattern in range(0, 64): #color - if (pattern & 0x22) == 0 or ((pattern & 0x08) != 0 and \ - (pattern & 0x11) != 0): - # constants.OBJ behind constants.BG color 1-3 + if (pattern & 0x22) == 0 or \ + ((pattern & 0x08) != 0 and (pattern & 0x11) != 0): + # OBJ behind BG color 1-3 color = (self.background_palette >> ((((pattern >> 3) & 0x02) +\ (pattern & 0x01)) << 1)) & 0x03 - # constants.OBJ above constants.BG + # OBJ above BG elif ((pattern & 0x04) == 0): color = (self.object_palette_0 >> ((((pattern >> 4) & 0x02) + \ ((pattern >> 1) & 0x01)) << 1)) & 0x03 else: color = (self.object_palette_1 >> ((((pattern >> 4) & 0x02) +\ ((pattern >> 1) & 0x01)) << 1)) & 0x03 - index= ((pattern & 0x30) << 4) + (pattern & 0x0F) - self.palette[index] = constants.COLOR_MAP[color] + index = ((pattern & 0x30) << 4) + (pattern & 0x0F) + #self.palette[index] = constants.COLOR_MAP[color] + self.palette[index] = color self.dirty = False # ------------------------------------------------------------------------------ @@ -680,4 +714,4 @@ def update_display(self): self.clear_pixels() - \ No newline at end of file + Modified: pypy/branch/build-external/pypy/lang/smalltalk/constants.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/constants.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/constants.py Tue Jun 10 12:48:46 2008 @@ -13,32 +13,32 @@ CLASS_SUPERCLASS_INDEX = 0 CLASS_METHODDICT_INDEX = 1 CLASS_FORMAT_INDEX = 2 -CLASS_NAME_INDEX = 6 # in the mini.image, at least +CLASS_NAME_INDEX = 6 # in the mini.image, at least +# MethodDict METHODDICT_TALLY_INDEX = 0 METHODDICT_VALUES_INDEX = 1 METHODDICT_NAMES_INDEX = 2 +# Message MESSAGE_SELECTOR_INDEX = 0 MESSAGE_ARGUMENTS_INDEX = 1 MESSAGE_LOOKUP_CLASS_INDEX = 2 -ASSOCIATION_KEY_INDEX = 0 -ASSOCIATION_VALUE_INDEX = 1 - +# ContextPart CTXPART_SENDER_INDEX = 0 CTXPART_PC_INDEX = 1 CTXPART_STACKP_INDEX = 2 METHOD_HEADER_INDEX = 0 -# Extends CTXPART_* +# BlockContext < ContextPart BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX = 3 BLKCTX_INITIAL_IP_INDEX = 4 BLKCTX_HOME_INDEX = 5 -BLKCTX_TEMP_FRAME_START = 6 +BLKCTX_STACK_START = 6 -# Extends CTXPART_* +# MethodContext < ContextPart MTHDCTX_METHOD = 3 MTHDCTX_RECEIVER_MAP = 4 MTHDCTX_RECEIVER = 5 @@ -101,21 +101,34 @@ # XXX more missing? classes_in_special_object_table = { - "SmallInteger": SO_SMALLINTEGER_CLASS, - "Array": SO_ARRAY_CLASS, - "String": SO_STRING_CLASS, - "Float": SO_FLOAT_CLASS, - "BlockContext": SO_BLOCKCONTEXT_CLASS, - "MethodContext": SO_METHODCONTEXT_CLASS, - "Character": SO_CHARACTER_CLASS, - "ByteArray": SO_BYTEARRAY_CLASS, - "CompiledMethod": SO_COMPILEDMETHOD_CLASS, +# "Bitmap" : SO_BITMAP_CLASS, + "SmallInteger" : SO_SMALLINTEGER_CLASS, + "String" : SO_STRING_CLASS, + "Array" : SO_ARRAY_CLASS, + "Float" : SO_FLOAT_CLASS, + "MethodContext" : SO_METHODCONTEXT_CLASS, + "BlockContext" : SO_BLOCKCONTEXT_CLASS, + "Point" : SO_POINT_CLASS, + "LargePositiveInteger" : SO_LARGEPOSITIVEINTEGER_CLASS, +# "Display" : SO_DISPLAY_CLASS, +# "Message" : SO_MESSAGE_CLASS, + "CompiledMethod" : SO_COMPILEDMETHOD_CLASS, + "Semaphore" : SO_SEMAPHORE_CLASS, + "Character" : SO_CHARACTER_CLASS, + "ByteArray" : SO_BYTEARRAY_CLASS, + "Process" : SO_PROCESS_CLASS, +# "PseudoContext" : SO_PSEUDOCONTEXT_CLASS, +# "TranslatedMethod" : SO_TRANSLATEDMETHOD_CLASS, + # "LargeNegativeInteger" : SO_LARGENEGATIVEINTEGER_CLASS, # Not available in mini.image } objects_in_special_object_table = { "nil": SO_NIL, "true": SO_TRUE, "false": SO_FALSE, + "charactertable": SO_CHARACTER_TABLE_ARRAY, + "schedulerassociationpointer" : SO_SCHEDULERASSOCIATIONPOINTER, + "smalltalkdict" : SO_SMALLTALK, } TAGGED_MAXINT = 2 ** (LONG_BIT - 2) - 1 Modified: pypy/branch/build-external/pypy/lang/smalltalk/error.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/error.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/error.py Tue Jun 10 12:48:46 2008 @@ -15,3 +15,10 @@ class WrappingError(PrimitiveFailedError): pass +class WrapperException(SmalltalkException): + def __init__(self, msg): + self.msg = msg + +class FatalError(SmalltalkException): + def __init__(self, msg): + self.msg = msg Modified: pypy/branch/build-external/pypy/lang/smalltalk/interpreter.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/interpreter.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/interpreter.py Tue Jun 10 12:48:46 2008 @@ -1,9 +1,10 @@ import py +from pypy.lang.smalltalk.shadow import ContextPartShadow, MethodContextShadow, BlockContextShadow from pypy.lang.smalltalk import model, constants, primitives -from pypy.lang.smalltalk import objtable -from pypy.lang.smalltalk.model import W_ContextPart +from pypy.lang.smalltalk.shadow import ContextPartShadow from pypy.lang.smalltalk.conftest import option from pypy.rlib import objectmodel, unroll +from pypy.lang.smalltalk import wrapper class MissingBytecode(Exception): @@ -15,20 +16,24 @@ class IllegalStoreError(Exception): """Illegal Store.""" -class Interpreter: - - TRUE = objtable.w_true - FALSE = objtable.w_false - NIL = objtable.w_nil - MINUS_ONE = objtable.w_minus_one - ZERO = objtable.w_zero - ONE = objtable.w_one - TWO = objtable.w_two +class Interpreter(object): _w_last_active_context = None - def __init__(self): - self.w_active_context = None + def __init__(self, space): + self._w_active_context = None + self.space = space + self.cnt = 0 + + def w_active_context(self): + return self._w_active_context + + def store_w_active_context(self, w_context): + assert isinstance(w_context, model.W_PointersObject) + self._w_active_context = w_context + + def s_active_context(self): + return self.w_active_context().as_context_get_shadow(self.space) def interpret(self): try: @@ -41,30 +46,35 @@ return (not objectmodel.we_are_translated()) and option.bc_trace def step(self): - next = self.w_active_context.getNextBytecode() + next = self.s_active_context().getNextBytecode() # we_are_translated returns false on top of CPython and true when # translating the interpreter if not objectmodel.we_are_translated(): bytecodeimpl = BYTECODE_TABLE[next] - if self._w_last_active_context != self.w_active_context: - cnt = 0 - p = self.w_active_context - # AK make method - while p is not None: - cnt += 1 - p = p.w_sender - self._last_indent = " " * cnt - self._w_last_active_context = self.w_active_context + if self.should_trace(): - + if self._w_last_active_context != self.w_active_context(): + cnt = 0 + p = self.w_active_context() + # AK make method + while p is not self.space.w_nil: + cnt += 1 + # Do not update the context + # for this action. + p = p.as_context_get_shadow(self.space).w_sender() + self._last_indent = " " * cnt + self._w_last_active_context = self.w_active_context() + print "%sStack=%s" % ( self._last_indent, - repr(self.w_active_context.stack),) + repr(self.s_active_context().stack()),) print "%sBytecode at %d (%d:%s):" % ( self._last_indent, - self.w_active_context.pc, + self.s_active_context().pc(), next, bytecodeimpl.__name__,) - bytecodeimpl(self.w_active_context, self) + + bytecodeimpl(self.s_active_context(), self) + else: # this is a performance optimization: when translating the # interpreter, the bytecode dispatching is not implemented as a @@ -72,7 +82,7 @@ # below produces the switch (by being unrolled). for code, bytecodeimpl in unrolling_bytecode_table: if code == next: - bytecodeimpl(self.w_active_context, self) + bytecodeimpl(self.s_active_context(), self) break @@ -83,14 +93,14 @@ # ___________________________________________________________________________ # Bytecode Implementations: # -# "self" is always a W_ContextPart instance. +# "self" is always a ContextPartShadow instance. -# __extend__ adds new methods to the W_ContextPart class -class __extend__(W_ContextPart): +# __extend__ adds new methods to the ContextPartShadow class +class __extend__(ContextPartShadow): # push bytecodes def pushReceiverVariableBytecode(self, interp): index = self.currentBytecode & 15 - self.push(self.receiver().fetch(index)) + self.push(self.w_receiver().fetch(self.space, index)) def pushTemporaryVariableBytecode(self, interp): index = self.currentBytecode & 15 @@ -105,14 +115,13 @@ # which is an object with two named vars, and fetches the second # named var (the value). index = self.currentBytecode & 31 - association = self.w_method().getliteral(index) - assert isinstance(association, model.W_PointersObject) - assert association.size() == 2 - self.push(association.fetch(constants.ASSOCIATION_VALUE_INDEX)) + w_association = self.w_method().getliteral(index) + association = wrapper.AssociationWrapper(self.space, w_association) + self.push(association.value()) def storeAndPopReceiverVariableBytecode(self, interp): index = self.currentBytecode & 7 - self.receiver().store(index, self.pop()) + self.w_receiver().store(self.space, index, self.pop()) def storeAndPopTemporaryVariableBytecode(self, interp): index = self.currentBytecode & 7 @@ -120,31 +129,31 @@ # push bytecodes def pushReceiverBytecode(self, interp): - self.push(self.receiver()) + self.push(self.w_receiver()) def pushConstantTrueBytecode(self, interp): - self.push(interp.TRUE) + self.push(interp.space.w_true) def pushConstantFalseBytecode(self, interp): - self.push(interp.FALSE) + self.push(interp.space.w_false) def pushConstantNilBytecode(self, interp): - self.push(interp.NIL) + self.push(interp.space.w_nil) def pushConstantMinusOneBytecode(self, interp): - self.push(interp.MINUS_ONE) + self.push(interp.space.w_minus_one) def pushConstantZeroBytecode(self, interp): - self.push(interp.ZERO) + self.push(interp.space.w_zero) def pushConstantOneBytecode(self, interp): - self.push(interp.ONE) + self.push(interp.space.w_one) def pushConstantTwoBytecode(self, interp): - self.push(interp.TWO) + self.push(interp.space.w_two) def pushActiveContextBytecode(self, interp): - self.push(self) + self.push(self.w_self()) def duplicateTopBytecode(self, interp): self.push(self.top()) @@ -158,19 +167,21 @@ def _sendSelfSelector(self, selector, argcount, interp): receiver = self.peek(argcount) self._sendSelector(selector, argcount, interp, - receiver, receiver.shadow_of_my_class()) + receiver, receiver.shadow_of_my_class(self.space)) def _sendSuperSelector(self, selector, argcount, interp): - s_compiledin = self.w_method().compiledin().as_class_get_shadow() - self._sendSelector(selector, argcount, interp, self.receiver(), - s_compiledin.s_superclass) + w_compiledin = self.w_method().compiledin() + assert isinstance(w_compiledin, model.W_PointersObject) + s_compiledin = w_compiledin.as_class_get_shadow(self.space) + self._sendSelector(selector, argcount, interp, self.w_receiver(), + s_compiledin.s_superclass()) def _sendSelector(self, selector, argcount, interp, receiver, receiverclassshadow): if interp.should_trace(): print "%sSending selector %r to %r with: %r" % ( interp._last_indent, selector, receiver, - [self.stack[i-argcount] for i in range(argcount)]) + [self.peek(argcount-1-i) for i in range(argcount)]) pass assert argcount >= 0 method = receiverclassshadow.lookup(selector) @@ -199,36 +210,36 @@ if interp.should_trace(): print "PRIMITIVE FAILED: %d %s" % (method.primitive, selector,) pass # ignore this error and fall back to the Smalltalk version - start = len(self.stack) - argcount - assert start >= 0 # XXX check in the Blue Book what to do in this case - arguments = self.stack[start:] - interp.w_active_context = method.create_frame(receiver, arguments, self) - self.pop_n(argcount + 1) + arguments = self.pop_and_return_n(argcount) + frame = method.create_frame(self.space, receiver, arguments, + self.w_self()) + interp.store_w_active_context(frame) + self.pop() def _return(self, object, interp, w_return_to): # for tests, when returning from the top-level context - if w_return_to is None: + if w_return_to is self.space.w_nil: raise ReturnFromTopLevel(object) - w_return_to.push(object) - interp.w_active_context = w_return_to + w_return_to.as_context_get_shadow(self.space).push(object) + interp.store_w_active_context(w_return_to) def returnReceiver(self, interp): - self._return(self.receiver(), interp, self.w_home.w_sender) + self._return(self.w_receiver(), interp, self.s_home().w_sender()) def returnTrue(self, interp): - self._return(interp.TRUE, interp, self.w_home.w_sender) + self._return(interp.space.w_true, interp, self.s_home().w_sender()) def returnFalse(self, interp): - self._return(interp.FALSE, interp, self.w_home.w_sender) + self._return(interp.space.w_false, interp, self.s_home().w_sender()) def returnNil(self, interp): - self._return(interp.NIL, interp, self.w_home.w_sender) + self._return(interp.space.w_nil, interp, self.s_home().w_sender()) def returnTopFromMethod(self, interp): - self._return(self.top(), interp, self.w_home.w_sender) + self._return(self.top(), interp, self.s_home().w_sender()) def returnTopFromBlock(self, interp): - self._return(self.top(), interp, self.w_sender) + self._return(self.top(), interp, self.w_sender()) def unknownBytecode(self, interp): raise MissingBytecode("unknownBytecode") @@ -241,30 +252,30 @@ def extendedPushBytecode(self, interp): variableType, variableIndex = self.extendedVariableTypeAndIndex() if variableType == 0: - self.push(self.receiver().fetch(variableIndex)) + self.push(self.w_receiver().fetch(self.space, variableIndex)) elif variableType == 1: self.push(self.gettemp(variableIndex)) elif variableType == 2: self.push(self.w_method().getliteral(variableIndex)) elif variableType == 3: - association = self.w_method().getliteral(variableIndex) - assert isinstance(association, model.W_PointersObject) - self.push(association.fetch(constants.ASSOCIATION_VALUE_INDEX)) + w_association = self.w_method().getliteral(variableIndex) + association = wrapper.AssociationWrapper(self.space, w_association) + self.push(association.value()) else: assert 0 def extendedStoreBytecode(self, interp): variableType, variableIndex = self.extendedVariableTypeAndIndex() if variableType == 0: - self.receiver().store(variableIndex, self.top()) + self.w_receiver().store(self.space, variableIndex, self.top()) elif variableType == 1: self.settemp(variableIndex, self.top()) elif variableType == 2: raise IllegalStoreError elif variableType == 3: - association = self.w_method().getliteral(variableIndex) - assert isinstance(association, model.W_PointersObject) - association.store(constants.ASSOCIATION_VALUE_INDEX, self.top()) + w_association = self.w_method().getliteral(variableIndex) + association = wrapper.AssociationWrapper(self.space, w_association) + association.store_value(self.top()) def extendedStoreAndPopBytecode(self, interp): self.extendedStoreBytecode(interp) @@ -293,23 +304,23 @@ second & 31, interp) elif opType == 2: # pushReceiver - self.push(self.receiver().fetch(third)) + self.push(self.w_receiver().fetch(self.space, third)) elif opType == 3: # pushLiteralConstant self.push(self.w_method().getliteral(third)) elif opType == 4: # pushLiteralVariable - association = self.w_method().getliteral(third) - assert isinstance(association, model.W_PointersObject) - self.push(association.fetch(constants.ASSOCIATION_VALUE_INDEX)) + w_association = self.w_method().getliteral(third) + association = wrapper.AssociationWrapper(self.space, w_association) + self.push(association.value()) elif opType == 5: - self.receiver().store(third, self.top()) + self.w_receiver().store(self.space, third, self.top()) elif opType == 6: - self.receiver().store(third, self.pop()) + self.w_receiver().store(self.space, third, self.pop()) elif opType == 7: - association = self.w_method().getliteral(third) - assert isinstance(association, model.W_PointersObject) - association.store(constants.ASSOCIATION_VALUE_INDEX, self.top()) + w_association = self.w_method().getliteral(third) + association = wrapper.AssociationWrapper(self.space, w_association) + association.store_value(self.top()) def singleExtendedSuperBytecode(self, interp): selector, argcount = self.getExtendedSelectorArgcount() @@ -328,7 +339,7 @@ raise MissingBytecode("experimentalBytecode") def jump(self,offset): - self.pc = self.pc + offset + self.store_pc(self.pc() + offset) def jumpConditional(self,bool,position): if self.top() == bool: @@ -342,7 +353,7 @@ self.jump(self.shortJumpPosition()) def shortConditionalJump(self, interp): - self.jumpConditional(interp.FALSE,self.shortJumpPosition()) + self.jumpConditional(interp.space.w_false, self.shortJumpPosition()) def longUnconditionalJump(self, interp): self.jump((((self.currentBytecode & 7) - 4) << 8) + self.getbytecode()) @@ -351,10 +362,10 @@ return ((self.currentBytecode & 3) << 8) + self.getbytecode() def longJumpIfTrue(self, interp): - self.jumpConditional(interp.TRUE,self.longJumpPosition()) + self.jumpConditional(interp.space.w_true, self.longJumpPosition()) def longJumpIfFalse(self, interp): - self.jumpConditional(interp.FALSE,self.longJumpPosition()) + self.jumpConditional(interp.space.w_false, self.longJumpPosition()) # RPython trick: specialize the following function on its second argument # this makes sure that the primitive call is a direct one @@ -430,7 +441,7 @@ self.callPrimitive(primitives.MOD, "\\\\", 1, interp) def bytecodePrimMakePoint(self, interp): - raise MissingBytecode("bytecodePrimMakePoint") + self.callPrimitive(primitives.MAKE_POINT, "@", 1, interp) def bytecodePrimBitShift(self, interp): self.callPrimitive(primitives.BIT_SHIFT, "bitShift:", 1, interp) @@ -512,77 +523,77 @@ BYTECODE_RANGES = [ - ( 0, 15, W_ContextPart.pushReceiverVariableBytecode), - ( 16, 31, W_ContextPart.pushTemporaryVariableBytecode), - ( 32, 63, W_ContextPart.pushLiteralConstantBytecode), - ( 64, 95, W_ContextPart.pushLiteralVariableBytecode), - ( 96, 103, W_ContextPart.storeAndPopReceiverVariableBytecode), - (104, 111, W_ContextPart.storeAndPopTemporaryVariableBytecode), - (112, W_ContextPart.pushReceiverBytecode), - (113, W_ContextPart.pushConstantTrueBytecode), - (114, W_ContextPart.pushConstantFalseBytecode), - (115, W_ContextPart.pushConstantNilBytecode), - (116, W_ContextPart.pushConstantMinusOneBytecode), - (117, W_ContextPart.pushConstantZeroBytecode), - (118, W_ContextPart.pushConstantOneBytecode), - (119, W_ContextPart.pushConstantTwoBytecode), - (120, W_ContextPart.returnReceiver), - (121, W_ContextPart.returnTrue), - (122, W_ContextPart.returnFalse), - (123, W_ContextPart.returnNil), - (124, W_ContextPart.returnTopFromMethod), - (125, W_ContextPart.returnTopFromBlock), - (126, W_ContextPart.unknownBytecode), - (127, W_ContextPart.unknownBytecode), - (128, W_ContextPart.extendedPushBytecode), - (129, W_ContextPart.extendedStoreBytecode), - (130, W_ContextPart.extendedStoreAndPopBytecode), - (131, W_ContextPart.singleExtendedSendBytecode), - (132, W_ContextPart.doubleExtendedDoAnythingBytecode), - (133, W_ContextPart.singleExtendedSuperBytecode), - (134, W_ContextPart.secondExtendedSendBytecode), - (135, W_ContextPart.popStackBytecode), - (136, W_ContextPart.duplicateTopBytecode), - (137, W_ContextPart.pushActiveContextBytecode), - (138, 143, W_ContextPart.experimentalBytecode), - (144, 151, W_ContextPart.shortUnconditionalJump), - (152, 159, W_ContextPart.shortConditionalJump), - (160, 167, W_ContextPart.longUnconditionalJump), - (168, 171, W_ContextPart.longJumpIfTrue), - (172, 175, W_ContextPart.longJumpIfFalse), - (176, W_ContextPart.bytecodePrimAdd), - (177, W_ContextPart.bytecodePrimSubtract), - (178, W_ContextPart.bytecodePrimLessThan), - (179, W_ContextPart.bytecodePrimGreaterThan), - (180, W_ContextPart.bytecodePrimLessOrEqual), - (181, W_ContextPart.bytecodePrimGreaterOrEqual), - (182, W_ContextPart.bytecodePrimEqual), - (183, W_ContextPart.bytecodePrimNotEqual), - (184, W_ContextPart.bytecodePrimMultiply), - (185, W_ContextPart.bytecodePrimDivide), - (186, W_ContextPart.bytecodePrimMod), - (187, W_ContextPart.bytecodePrimMakePoint), - (188, W_ContextPart.bytecodePrimBitShift), - (189, W_ContextPart.bytecodePrimDiv), - (190, W_ContextPart.bytecodePrimBitAnd), - (191, W_ContextPart.bytecodePrimBitOr), - (192, W_ContextPart.bytecodePrimAt), - (193, W_ContextPart.bytecodePrimAtPut), - (194, W_ContextPart.bytecodePrimSize), - (195, W_ContextPart.bytecodePrimNext), - (196, W_ContextPart.bytecodePrimNextPut), - (197, W_ContextPart.bytecodePrimAtEnd), - (198, W_ContextPart.bytecodePrimEquivalent), - (199, W_ContextPart.bytecodePrimClass), - (200, W_ContextPart.bytecodePrimBlockCopy), - (201, W_ContextPart.bytecodePrimValue), - (202, W_ContextPart.bytecodePrimValueWithArg), - (203, W_ContextPart.bytecodePrimDo), - (204, W_ContextPart.bytecodePrimNew), - (205, W_ContextPart.bytecodePrimNewWithArg), - (206, W_ContextPart.bytecodePrimPointX), - (207, W_ContextPart.bytecodePrimPointY), - (208, 255, W_ContextPart.sendLiteralSelectorBytecode), + ( 0, 15, ContextPartShadow.pushReceiverVariableBytecode), + ( 16, 31, ContextPartShadow.pushTemporaryVariableBytecode), + ( 32, 63, ContextPartShadow.pushLiteralConstantBytecode), + ( 64, 95, ContextPartShadow.pushLiteralVariableBytecode), + ( 96, 103, ContextPartShadow.storeAndPopReceiverVariableBytecode), + (104, 111, ContextPartShadow.storeAndPopTemporaryVariableBytecode), + (112, ContextPartShadow.pushReceiverBytecode), + (113, ContextPartShadow.pushConstantTrueBytecode), + (114, ContextPartShadow.pushConstantFalseBytecode), + (115, ContextPartShadow.pushConstantNilBytecode), + (116, ContextPartShadow.pushConstantMinusOneBytecode), + (117, ContextPartShadow.pushConstantZeroBytecode), + (118, ContextPartShadow.pushConstantOneBytecode), + (119, ContextPartShadow.pushConstantTwoBytecode), + (120, ContextPartShadow.returnReceiver), + (121, ContextPartShadow.returnTrue), + (122, ContextPartShadow.returnFalse), + (123, ContextPartShadow.returnNil), + (124, ContextPartShadow.returnTopFromMethod), + (125, ContextPartShadow.returnTopFromBlock), + (126, ContextPartShadow.unknownBytecode), + (127, ContextPartShadow.unknownBytecode), + (128, ContextPartShadow.extendedPushBytecode), + (129, ContextPartShadow.extendedStoreBytecode), + (130, ContextPartShadow.extendedStoreAndPopBytecode), + (131, ContextPartShadow.singleExtendedSendBytecode), + (132, ContextPartShadow.doubleExtendedDoAnythingBytecode), + (133, ContextPartShadow.singleExtendedSuperBytecode), + (134, ContextPartShadow.secondExtendedSendBytecode), + (135, ContextPartShadow.popStackBytecode), + (136, ContextPartShadow.duplicateTopBytecode), + (137, ContextPartShadow.pushActiveContextBytecode), + (138, 143, ContextPartShadow.experimentalBytecode), + (144, 151, ContextPartShadow.shortUnconditionalJump), + (152, 159, ContextPartShadow.shortConditionalJump), + (160, 167, ContextPartShadow.longUnconditionalJump), + (168, 171, ContextPartShadow.longJumpIfTrue), + (172, 175, ContextPartShadow.longJumpIfFalse), + (176, ContextPartShadow.bytecodePrimAdd), + (177, ContextPartShadow.bytecodePrimSubtract), + (178, ContextPartShadow.bytecodePrimLessThan), + (179, ContextPartShadow.bytecodePrimGreaterThan), + (180, ContextPartShadow.bytecodePrimLessOrEqual), + (181, ContextPartShadow.bytecodePrimGreaterOrEqual), + (182, ContextPartShadow.bytecodePrimEqual), + (183, ContextPartShadow.bytecodePrimNotEqual), + (184, ContextPartShadow.bytecodePrimMultiply), + (185, ContextPartShadow.bytecodePrimDivide), + (186, ContextPartShadow.bytecodePrimMod), + (187, ContextPartShadow.bytecodePrimMakePoint), + (188, ContextPartShadow.bytecodePrimBitShift), + (189, ContextPartShadow.bytecodePrimDiv), + (190, ContextPartShadow.bytecodePrimBitAnd), + (191, ContextPartShadow.bytecodePrimBitOr), + (192, ContextPartShadow.bytecodePrimAt), + (193, ContextPartShadow.bytecodePrimAtPut), + (194, ContextPartShadow.bytecodePrimSize), + (195, ContextPartShadow.bytecodePrimNext), + (196, ContextPartShadow.bytecodePrimNextPut), + (197, ContextPartShadow.bytecodePrimAtEnd), + (198, ContextPartShadow.bytecodePrimEquivalent), + (199, ContextPartShadow.bytecodePrimClass), + (200, ContextPartShadow.bytecodePrimBlockCopy), + (201, ContextPartShadow.bytecodePrimValue), + (202, ContextPartShadow.bytecodePrimValueWithArg), + (203, ContextPartShadow.bytecodePrimDo), + (204, ContextPartShadow.bytecodePrimNew), + (205, ContextPartShadow.bytecodePrimNewWithArg), + (206, ContextPartShadow.bytecodePrimPointX), + (207, ContextPartShadow.bytecodePrimPointY), + (208, 255, ContextPartShadow.sendLiteralSelectorBytecode), ] Modified: pypy/branch/build-external/pypy/lang/smalltalk/model.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/model.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/model.py Tue Jun 10 12:48:46 2008 @@ -1,84 +1,148 @@ +""" +Squeak model. + + W_Object + W_SmallInteger + W_Float + W_AbstractObjectWithIdentityHash + W_AbstractObjectWithClassReference + W_PointersObject + W_BytesObject + W_WordsObject + W_CompiledMethod + +W_BlockContext and W_MethodContext classes have been replaced by functions +that create W_PointersObjects of correct size with attached shadows. +""" import sys -from pypy.rlib import rrandom +from pypy.rlib import rrandom, objectmodel from pypy.rlib.rarithmetic import intmask -from pypy.lang.smalltalk import constants +from pypy.lang.smalltalk import constants, error from pypy.tool.pairtype import extendabletype from pypy.rlib.objectmodel import instantiate from pypy.lang.smalltalk.tool.bitmanipulation import splitter class W_Object(object): + """Root of Squeak model, abstract.""" __slots__ = () # no RPython-level instance variables allowed in W_Object def size(self): + """Return bytesize that conforms to Blue Book. + + The reported size may differ from the actual size in Spy's object + space, as memory representation varies depending on PyPy translation.""" return 0 - def varsize(self): - return self.size() + def varsize(self, space): + """Return bytesize of variable-sized part. - def primsize(self): + Variable sized objects are those created with #new:.""" + return self.size(space) + + def primsize(self, space): + # TODO remove this method return self.size() - def getclass(self): - raise NotImplementedError + def getclass(self, space): + """Return Squeak class.""" + raise NotImplementedError() def gethash(self): - raise NotImplementedError - - def at0(self, index0): - raise NotImplementedError + """Return 31-bit hash value.""" + raise NotImplementedError() - def atput0(self, index0, w_value): - raise NotImplementedError + def at0(self, space, index0): + """Access variable-sized part, as by Object>>at:. - def fetch(self, n0): - raise NotImplementedError + Return value depends on layout of instance. Byte objects return bytes, + word objects return words, pointer objects return pointers. Compiled method are + treated special, if index0 within the literalsize returns pointer to literal, + otherwise returns byte (ie byte code indexing starts at literalsize).""" + raise NotImplementedError() + + def atput0(self, space, index0, w_value): + """Access variable-sized part, as by Object>>at:put:. + + Semantics depend on layout of instance. Byte objects set bytes, + word objects set words, pointer objects set pointers. Compiled method are + treated special, if index0 within the literalsize sets pointer to literal, + otherwise patches bytecode (ie byte code indexing starts at literalsize).""" + raise NotImplementedError() + + def fetch(self, space, n0): + """Access fixed-size part, maybe also variable-sized part (we have to + consult the Blue Book).""" + # TODO check the Blue Book + raise NotImplementedError() - def store(self, n0, w_value): - raise NotImplementedError + def store(self, space, n0, w_value): + """Access fixed-size part, maybe also variable-sized part (we have to + consult the Blue Book).""" + raise NotImplementedError() def invariant(self): return True - def shadow_of_my_class(self): - return self.getclass().as_class_get_shadow() - - def shallow_equals(self,other): - return self == other - - def equals(self, other): - return self.shallow_equals(other) + def shadow_of_my_class(self, space): + """Return internal representation of Squeak class.""" + return self.getclass(space).as_class_get_shadow(space) + + def is_same_object(self, other): + """Compare object identity""" + return self is other + + def become(self, other): + """Become swaps two objects. + False means swapping failed""" + return False class W_SmallInteger(W_Object): + """Boxed integer value""" + # TODO can we tell pypy that its never larger then 31-bit? __slots__ = ('value',) # the only allowed slot here def __init__(self, value): self.value = value - def getclass(self): - from pypy.lang.smalltalk.classtable import w_SmallInteger - return w_SmallInteger + def getclass(self, space): + """Return SmallInteger from special objects array.""" + return space.w_SmallInteger def gethash(self): return self.value def invariant(self): - return isinstance(self.value, int) + return isinstance(self.value, int) and self.value < 0x8000 def __repr__(self): return "W_SmallInteger(%d)" % self.value - def shallow_equals(self, other): + def is_same_object(self, other): + # TODO what is correct terminology to say that identity is by value? + if not isinstance(other, W_SmallInteger): + return False + return self.value == other.value + + def __eq__(self, other): if not isinstance(other, W_SmallInteger): return False return self.value == other.value + def __ne__(self, other): + return not self == other + + def __hash__(self): + return self.value + + class W_Float(W_Object): + """Boxed float value.""" def __init__(self, value): self.value = value - def getclass(self): - from pypy.lang.smalltalk.classtable import w_Float - return w_Float + def getclass(self, space): + """Return Float from special objects array.""" + return space.w_Float def gethash(self): return 41 # XXX check this @@ -89,18 +153,35 @@ def __repr__(self): return "W_Float(%f)" % self.value - def shallow_equals(self, other): + def is_same_object(self, other): if not isinstance(other, W_Float): return False + # TODO is that correct in Squeak? return self.value == other.value + def __eq__(self, other): + if not isinstance(other, W_Float): + return False + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + class W_AbstractObjectWithIdentityHash(W_Object): + """Object with explicit hash (ie all except small + ints and floats).""" #XXX maybe this is too extreme, but it's very random hash_generator = rrandom.Random() UNASSIGNED_HASH = sys.maxint hash = UNASSIGNED_HASH # default value + def setchar(self, n0, character): + raise NotImplementedError() + def gethash(self): if self.hash == self.UNASSIGNED_HASH: self.hash = hash = intmask(self.hash_generator.genrand32()) // 2 @@ -110,15 +191,23 @@ def invariant(self): return isinstance(self.hash, int) + def become(self, w_other): + if not isinstance(w_other, W_AbstractObjectWithIdentityHash): + return False + self.hash, w_other.hash = w_other.hash, self.hash + return True + class W_AbstractObjectWithClassReference(W_AbstractObjectWithIdentityHash): - """ The base class of objects that store 'w_class' explicitly. """ + """Objects with arbitrary class (ie not CompiledMethod, SmallInteger or + Float).""" def __init__(self, w_class): if w_class is not None: # it's None only for testing assert isinstance(w_class, W_PointersObject) self.w_class = w_class - def getclass(self): + def getclass(self, space): + assert self.w_class is not None return self.w_class def __repr__(self): @@ -126,93 +215,148 @@ def __str__(self): if isinstance(self, W_PointersObject) and self._shadow is not None: - return "%s class" % (self.as_class_get_shadow().name or '?',) + return self._shadow.getname() else: - return "a %s" % (self.shadow_of_my_class().name or '?',) + name = None + if self.w_class._shadow is not None: + name = self.w_class._shadow.name + return "a %s" % (name or '?',) def invariant(self): return (W_AbstractObjectWithIdentityHash.invariant(self) and isinstance(self.w_class, W_PointersObject)) + def become(self, w_other): + if not isinstance(w_other, W_AbstractObjectWithClassReference): + return False + self.w_class, w_other.w_class = w_other.w_class, self.w_class + return W_AbstractObjectWithIdentityHash.become(self, w_other) + class W_PointersObject(W_AbstractObjectWithClassReference): - """ The normal object """ + """Common object.""" _shadow = None # Default value def __init__(self, w_class, size): + """Create new object with size = fixed + variable size.""" W_AbstractObjectWithClassReference.__init__(self, w_class) self._vars = [w_nil] * size - def at0(self, index0): - return self.fetch(index0) + def at0(self, space, index0): + # To test, at0 = in varsize part + return self.fetch(space, index0+self.instsize(space)) + + def atput0(self, space, index0, w_value): + # To test, at0 = in varsize part + self.store(space, index0 + self.instsize(space), w_value) - def atput0(self, index0, w_value): - self.store(index0, w_value) + def fetch(self, space, n0): + if self._shadow is not None: + return self._shadow.fetch(n0) + return self._fetch(n0) - def fetch(self, n0): + def _fetch(self, n0): return self._vars[n0] - def store(self, n0, w_value): + def store(self, space, n0, w_value): if self._shadow is not None: - self._shadow.invalidate() - self._vars[n0] = w_value + return self._shadow.store(n0, w_value) + return self._store(n0, w_value) - def fetchvarpointer(self, idx): - return self._vars[idx+self.instsize()] + def _store(self, n0, w_value): + self._vars[n0] = w_value - def storevarpointer(self, idx, value): - self._vars[idx+self.instsize()] = value - def varsize(self): - return self.size() - self.shadow_of_my_class().instsize() + def varsize(self, space): + return self.size() - self.instsize(space) - def instsize(self): - return self.getclass().as_class_get_shadow().instsize() + def instsize(self, space): + return self.shadow_of_my_class(space).instsize() - def primsize(self): - return self.varsize() + def primsize(self, space): + return self.varsize(space) def size(self): + if self._shadow is not None: + return self._shadow.size() + return self._size() + + def _size(self): return len(self._vars) def invariant(self): return (W_AbstractObjectWithClassReference.invariant(self) and isinstance(self._vars, list)) - def as_class_get_shadow(self): - from pypy.lang.smalltalk.shadow import ClassShadow + def store_shadow(self, shadow): + self._shadow = shadow + + @objectmodel.specialize.arg(2) + def attach_shadow_of_class(self, space, TheClass): + shadow = TheClass(space, self) + self._shadow = shadow + shadow.attach_shadow() + return shadow + + @objectmodel.specialize.arg(2) + def as_special_get_shadow(self, space, TheClass): shadow = self._shadow if shadow is None: - self._shadow = shadow = ClassShadow(self) - assert isinstance(shadow, ClassShadow) # for now, the only kind - shadow.check_for_updates() + shadow = self.attach_shadow_of_class(space, TheClass) + elif not isinstance(shadow, TheClass): + shadow.detach_shadow() + shadow = self.attach_shadow_of_class(space, TheClass) + shadow.sync_shadow() return shadow - def equals(self, other): - if not isinstance(other, W_PointersObject): - return False - if not other.getclass() == self.getclass(): - return False - if not other.size() == self.size(): + def get_shadow(self, space): + from pypy.lang.smalltalk.shadow import AbstractShadow + return self.as_special_get_shadow(space, AbstractShadow) + + def as_class_get_shadow(self, space): + from pypy.lang.smalltalk.shadow import ClassShadow + return self.as_special_get_shadow(space, ClassShadow) + + def as_blockcontext_get_shadow(self, space): + from pypy.lang.smalltalk.shadow import BlockContextShadow + return self.as_special_get_shadow(space, BlockContextShadow) + + def as_methodcontext_get_shadow(self, space): + from pypy.lang.smalltalk.shadow import MethodContextShadow + return self.as_special_get_shadow(space, MethodContextShadow) + + def as_context_get_shadow(self, space): + from pypy.lang.smalltalk.shadow import ContextPartShadow + # XXX TODO should figure out itself if its method or block context + if self._shadow is None: + if ContextPartShadow.is_block_context(self, space): + return self.as_blockcontext_get_shadow(space) + return self.as_methodcontext_get_shadow(space) + return self.as_special_get_shadow(space, ContextPartShadow) + + def as_methoddict_get_shadow(self, space): + from pypy.lang.smalltalk.shadow import MethodDictionaryShadow + return self.as_special_get_shadow(space, MethodDictionaryShadow) + + def become(self, w_other): + if not isinstance(w_other, W_PointersObject): return False - for i in range(self.size()): - if not other.fetch(i).shallow_equals(self.fetch(i)): - return False - return True + self._vars, w_other._vars = w_other._vars, self._vars + self._shadow, w_other._shadow = w_other._shadow, self._shadow + return W_AbstractObjectWithClassReference.become(self, w_other) + class W_BytesObject(W_AbstractObjectWithClassReference): def __init__(self, w_class, size): W_AbstractObjectWithClassReference.__init__(self, w_class) self.bytes = ['\x00'] * size - def at0(self, index0): - from pypy.lang.smalltalk import utility - return utility.wrap_int(ord(self.getchar(index0))) + def at0(self, space, index0): + return space.wrap_int(ord(self.getchar(index0))) - def atput0(self, index0, w_value): - from pypy.lang.smalltalk import utility - self.setchar(index0, chr(utility.unwrap_int(w_value))) + def atput0(self, space, index0, w_value): + self.setchar(index0, chr(space.unwrap_int(w_value))) def getchar(self, n0): return self.bytes[n0] @@ -241,8 +385,8 @@ return False return True - def shallow_equals(self, other): - if not isinstance(other,W_BytesObject): + def is_same_object(self, other): + if not isinstance(other, W_BytesObject): return False return self.bytes == other.bytes @@ -251,13 +395,29 @@ W_AbstractObjectWithClassReference.__init__(self, w_class) self.words = [0] * size - def at0(self, index0): - from pypy.lang.smalltalk import utility - return utility.wrap_int(self.getword(index0)) - - def atput0(self, index0, w_value): - from pypy.lang.smalltalk import utility - self.setword(index0, utility.unwrap_int(w_value)) + def at0(self, space, index0): + val = self.getword(index0) + if val & (3 << 30) == 0: + return space.wrap_int(val) + else: + w_result = W_BytesObject(space.classtable['w_LargePositiveInteger'], 4) + for i in range(4): + w_result.setchar(i, chr((val >> i*8) & 255)) + return w_result + + def atput0(self, space, index0, w_value): + if isinstance(w_value, W_BytesObject): + # XXX Probably we want to allow all subclasses + if not (w_value.getclass(self).is_same_object( + space.classtable['w_LargePositiveInteger']) and + w_value.size() == 4): + raise UnwrappingError("Failed to convert bytes to word") + word = 0 + for i in range(4): + word += ord(w_value.getchar(i)) << 8*i + else: + word = space.unwrap_int(w_value) + self.setword(index0, word) def getword(self, n): return self.words[n] @@ -272,11 +432,8 @@ return (W_AbstractObjectWithClassReference.invariant(self) and isinstance(self.words, list)) - def shallow_equals(self, other): - if not isinstance(other,W_WordsObject): - return False - return self.words == other.words - +# XXX Shouldn't compiledmethod have class reference for subclassed compiled +# methods? class W_CompiledMethod(W_AbstractObjectWithIdentityHash): """My instances are methods suitable for interpretation by the virtual machine. This is the only class in the system whose instances intermix both indexable pointer fields and indexable integer fields. @@ -285,38 +442,38 @@ header (4 bytes) literals (4 bytes each) bytecodes (variable) - trailer (variable) - - The header is a 30-bit integer with the following format: - - (index 0) 9 bits: main part of primitive number (#primitive) - (index 9) 8 bits: number of literals (#numLiterals) - (index 17) 1 bit: whether a large frame size is needed (#frameSize) - (index 18) 6 bits: number of temporary variables (#numTemps) - (index 24) 4 bits: number of arguments to the method (#numArgs) - (index 28) 1 bit: high-bit of primitive number (#primitive) - (index 29) 1 bit: flag bit, ignored by the VM (#flag) - - The trailer has two variant formats. In the first variant, the last byte is at least 252 and the last four bytes represent a source pointer into one of the sources files (see #sourcePointer). In the second variant, the last byte is less than 252, and the last several bytes are a compressed version of the names of the method's temporary variables. The number of bytes used for this purpose is the value of the last byte in the method. """ +### Extension from Squeak 3.9 doc, which we do not implement: +### trailer (variable) +### The trailer has two variant formats. In the first variant, the last +### byte is at least 252 and the last four bytes represent a source pointer +### into one of the sources files (see #sourcePointer). In the second +### variant, the last byte is less than 252, and the last several bytes +### are a compressed version of the names of the method's temporary +### variables. The number of bytes used for this purpose is the value of +### the last byte in the method. + def __init__(self, bytecount=0, header=0): self.setheader(header) self.bytes = "\x00"*bytecount def compiledin(self): if self.w_compiledin is None: - # (Blue book, p 607) All CompiledMethods that contain extended-super bytecodes have the clain which they are found as their last literal variable. + from pypy.lang.smalltalk import wrapper + # (Blue book, p 607) All CompiledMethods that contain + # extended-super bytecodes have the clain which they are found as + # their last literal variable. # Last of the literals is an association with compiledin # as a class - association = self.literals[-1] - assert isinstance(association, W_PointersObject) - self.w_compiledin = association.fetch(constants.ASSOCIATION_VALUE_INDEX) + w_association = self.literals[-1] + # XXX XXX XXX where to get a space from here + association = wrapper.AssociationWrapper(None, w_association) + self.w_compiledin = association.value() return self.w_compiledin - def getclass(self): - from pypy.lang.smalltalk.classtable import w_CompiledMethod - return w_CompiledMethod + def getclass(self, space): + return space.w_CompiledMethod def getliteral(self, index): # We changed this part @@ -327,15 +484,21 @@ assert isinstance(w_literal, W_BytesObject) return w_literal.as_string() # XXX performance issue here - def create_frame(self, receiver, arguments, sender = None): + def create_frame(self, space, receiver, arguments, sender = None): + from pypy.lang.smalltalk import shadow assert len(arguments) == self.argsize - return W_MethodContext(self, receiver, arguments, sender) + w_new = shadow.MethodContextShadow.make_context( + space, self, receiver, arguments, sender) + return w_new def __str__(self): from pypy.lang.smalltalk.interpreter import BYTECODE_TABLE - return ("\n\nBytecode:\n---------------------\n" + - "\n".join([BYTECODE_TABLE[ord(i)].__name__ + " " + str(ord(i)) for i in self.bytes]) + - "\n---------------------\n") + j = 1 + retval = "\n\nBytecode:\n---------------------\n" + for i in self.bytes: + retval += str(j) + ": " + BYTECODE_TABLE[ord(i)].__name__ + " " + str(ord(i)) + "\n" + j += 1 + return retval + "\n---------------------\n" def invariant(self): return (W_Object.invariant(self) and @@ -351,11 +514,14 @@ self.primitive is not None) def size(self): - return self.getliteralsize() + len(self.bytes) + self.headersize() + return self.headersize() + self.getliteralsize() + len(self.bytes) def getliteralsize(self): return self.literalsize * constants.BYTES_PER_WORD + def bytecodeoffset(self): + return self.getliteralsize() + self.headersize() + def headersize(self): return constants.BYTES_PER_WORD @@ -363,13 +529,16 @@ return self.header def setheader(self, header): - #(index 0) 9 bits: main part of primitive number (#primitive) - #(index 9) 8 bits: number of literals (#numLiterals) - #(index 17) 1 bit: whether a large frame size is needed (#frameSize) - #(index 18) 6 bits: number of temporary variables (#numTemps) - #(index 24) 4 bits: number of arguments to the method (#numArgs) - #(index 28) 1 bit: high-bit of primitive number (#primitive) - #(index 29) 1 bit: flag bit, ignored by the VM (#flag) + """Decode 30-bit method header and apply new format. + + (index 0) 9 bits: main part of primitive number (#primitive) + (index 9) 8 bits: number of literals (#numLiterals) + (index 17) 1 bit: whether a large frame size is needed (#frameSize) + (index 18) 6 bits: number of temporary variables (#numTemps) + (index 24) 4 bits: number of arguments to the method (#numArgs) + (index 28) 1 bit: high-bit of primitive number (#primitive) + (index 29) 1 bit: flag bit, ignored by the VM (#flag) + """ primitive, literalsize, islarge, tempsize, numargs, highbit = ( splitter[9,8,1,6,4,1](header)) primitive = primitive + (highbit << 10) ##XXX todo, check this @@ -378,224 +547,57 @@ self.header = header self.argsize = numargs self.tempsize = tempsize + assert self.tempsize >= self.argsize self.primitive = primitive self.w_compiledin = None + self.islarge = islarge - def literalat0(self, index0): + def literalat0(self, space, index0): if index0 == 0: - from pypy.lang.smalltalk import utility - return utility.wrap_int(self.getheader()) + return space.wrap_int(self.getheader()) else: return self.literals[index0-1] - def literalatput0(self, index0, w_value): + def literalatput0(self, space, index0, w_value): if index0 == 0: - from pypy.lang.smalltalk import utility - header = utility.unwrap_int(w_value) + header = space.unwrap_int(w_value) self.setheader(header) else: self.literals[index0-1] = w_value - def at0(self, index0): - from pypy.lang.smalltalk import utility - if index0 < self.getliteralsize(): - self.literalat0(index0) + def store(self, space, index0, w_v): + self.atput0(space, index0, w_v) + + def at0(self, space, index0): + if index0 <= self.getliteralsize(): + return self.literalat0(space, index0 / constants.BYTES_PER_WORD) else: - index0 = index0 - self.getliteralsize() - return utility.wrap_int(ord(self.bytes[index0])) + # From blue book: + # The literal count indicates the size of the + # CompiledMethod's literal frame. + # This, in turn, indicates where the + # CompiledMethod's bytecodes start. + index0 = index0 - self.getliteralsize() - self.headersize() + assert index0 < len(self.bytes) + return space.wrap_int(ord(self.bytes[index0])) - def atput0(self, index0, w_value): - from pypy.lang.smalltalk import utility - if index0 < self.getliteralsize(): - self.literalatput0(index0, w_value) + def atput0(self, space, index0, w_value): + if index0 <= self.getliteralsize(): + self.literalatput0(space, index0 / constants.BYTES_PER_WORD, w_value) else: # XXX use to-be-written unwrap_char - index0 = index0 - self.getliteralsize() - self.setchar(index0, chr(utility.unwrap_int(w_value))) + index0 = index0 - self.getliteralsize() - self.headersize() + assert index0 < len(self.bytes) + self.setchar(index0, chr(space.unwrap_int(w_value))) def setchar(self, index0, character): assert index0 >= 0 self.bytes = (self.bytes[:index0] + character + self.bytes[index0 + 1:]) -class W_ContextPart(W_AbstractObjectWithIdentityHash): - - __metaclass__ = extendabletype - - def __init__(self, w_home, w_sender): - self.stack = [] - self.pc = 0 - assert isinstance(w_home, W_MethodContext) - self.w_home = w_home - assert w_sender is None or isinstance(w_sender, W_ContextPart) - self.w_sender = w_sender - - def receiver(self): - " Return self of the method, or the method that contains the block " - return self.w_home.w_receiver - - # ______________________________________________________________________ - # Imitate the primitive accessors - - def fetch(self, index): - from pypy.lang.smalltalk import utility, objtable - if index == constants.CTXPART_SENDER_INDEX: - if self.w_sender: - return self.w_sender - else: - return objtable.w_nil - elif index == constants.CTXPART_PC_INDEX: - return utility.wrap_int(self.pc) - elif index == constants.CTXPART_STACKP_INDEX: - return utility.wrap_int(len(self.stack)) - - # Invalid! - raise IndexError - - def store(self, index, value): - raise NotImplementedError - - # ______________________________________________________________________ - # Method that contains the bytecode for this method/block context - - def w_method(self): - return self.w_home._w_method - - def getbytecode(self): - bytecode = self.w_method().bytes[self.pc] - currentBytecode = ord(bytecode) - self.pc = self.pc + 1 - return currentBytecode - - def getNextBytecode(self): - self.currentBytecode = self.getbytecode() - return self.currentBytecode - - # ______________________________________________________________________ - # Temporary Variables - # - # Are always fetched relative to the home method context. - - def gettemp(self, index): - return self.w_home.temps[index] - - def settemp(self, index, w_value): - self.w_home.temps[index] = w_value - - # ______________________________________________________________________ - # Stack Manipulation - - def pop(self): - return self.stack.pop() - - def push(self, w_v): - assert w_v - self.stack.append(w_v) - - def push_all(self, lst): - " Equivalent to 'for x in lst: self.push(x)' where x is a lst " - assert None not in lst - self.stack += lst - - def top(self): - return self.peek(0) - - def peek(self, idx): - return self.stack[-(idx+1)] - - def pop_n(self, n): - assert n >= 0 - start = len(self.stack) - n - assert start >= 0 # XXX what if this fails? - del self.stack[start:] - - def pop_and_return_n(self, n): - assert n >= 0 - start = len(self.stack) - n - assert start >= 0 # XXX what if this fails? - res = self.stack[start:] - del self.stack[start:] - return res - -class W_BlockContext(W_ContextPart): - - def __init__(self, w_home, w_sender, argcnt, initialip): - W_ContextPart.__init__(self, w_home, w_sender) - self.argcnt = argcnt - self.initialip = initialip - - def expected_argument_count(self): - return self.argcnt - - def getclass(self): - from pypy.lang.smalltalk.classtable import w_BlockContext - return w_BlockContext - - def fetch(self, index): - from pypy.lang.smalltalk import utility - if index == constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX: - return utility.wrap_int(self.argcnt) - elif index == constants.BLKCTX_INITIAL_IP_INDEX: - return utility.wrap_int(self.initialip) - elif index == constants.BLKCTX_HOME_INDEX: - return self.w_home - elif index >= constants.BLKCTX_TEMP_FRAME_START: - stack_index = len(self.stack) - index - 1 - return self.stack[stack_index] - else: - return W_ContextPart.fetch(self, index) - - def store(self, index, value): - # THIS IS ALL UNTESTED CODE and we're a bit unhappy about it - # because it crashd the translation N+4 times :-( - from pypy.lang.smalltalk import utility - if index == constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX: - self.argcnt = utility.unwrap_int(value) - elif index == constants.BLKCTX_INITIAL_IP_INDEX: - self.pc = utility.unwrap_int(value) - elif index == constants.BLKCTX_HOME_INDEX: - assert isinstance(value, W_MethodContext) - self.w_home = value - elif index >= constants.BLKCTX_TEMP_FRAME_START: - stack_index = len(self.stack) - index - 1 - self.stack[stack_index] = value - else: - W_ContextPart.store(self, index, value) - -class W_MethodContext(W_ContextPart): - def __init__(self, w_method, w_receiver, - arguments, w_sender=None): - W_ContextPart.__init__(self, self, w_sender) - self._w_method = w_method - self.w_receiver = w_receiver - self.temps = arguments + [w_nil] * w_method.tempsize - - def getclass(self): - from pypy.lang.smalltalk.classtable import w_MethodContext - return w_MethodContext - - def fetch(self, index): - if index == constants.MTHDCTX_METHOD: - return self.w_method() - elif index == constants.MTHDCTX_RECEIVER_MAP: # what is this thing? - return w_nil - elif index == constants.MTHDCTX_RECEIVER: - return self.w_receiver - elif index >= constants.MTHDCTX_TEMP_FRAME_START: - # First set of indices are temporary variables: - offset = index - constants.MTHDCTX_TEMP_FRAME_START - if offset < len(self.temps): - return self.temps[offset] - - # After that comes the stack: - offset -= len(self.temps) - stack_index = len(self.stack) - offset - 1 - return self.stack[stack_index] - else: - return W_ContextPart.fetch(self, index) - # Use black magic to create w_nil without running the constructor, # thus allowing it to be used even in the constructor of its own -# class. Note that we patch its class in objtable. +# class. Note that we patch its class in the space +# YYY there should be no global w_nil w_nil = instantiate(W_PointersObject) w_nil._vars = [] Modified: pypy/branch/build-external/pypy/lang/smalltalk/primitives.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/primitives.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/primitives.py Tue Jun 10 12:48:46 2008 @@ -1,21 +1,20 @@ import inspect import math import operator -from pypy.lang.smalltalk import model, shadow, utility -from pypy.lang.smalltalk import classtable -from pypy.lang.smalltalk import objtable +from pypy.lang.smalltalk import model, shadow from pypy.lang.smalltalk import constants from pypy.lang.smalltalk.error import PrimitiveFailedError, \ PrimitiveNotYetWrittenError from pypy.rlib import rarithmetic, unroll +from pypy.lang.smalltalk import wrapper def assert_bounds(n0, minimum, maximum): if not minimum <= n0 < maximum: raise PrimitiveFailedError() -def assert_valid_index(n0, w_obj): - if not 0 <= n0 < w_obj.size(): +def assert_valid_index(space, n0, w_obj): + if not 0 <= n0 < w_obj.primsize(space): raise PrimitiveFailedError() # return the index, since from here on the annotator knows that # n0 cannot be negative @@ -68,7 +67,7 @@ w_result = func(interp, argument_count_m1) if not no_result: assert w_result is not None - interp.w_active_context.push(w_result) + interp.s_active_context().push(w_result) return w_result else: len_unwrap_spec = len(unwrap_spec) @@ -77,23 +76,25 @@ unrolling_unwrap_spec = unrolling_iterable(enumerate(unwrap_spec)) def wrapped(interp, argument_count_m1): argument_count = argument_count_m1 + 1 # to account for the rcvr - frame = interp.w_active_context + frame = interp.w_active_context() + s_frame = frame.as_context_get_shadow(interp.space) assert argument_count == len_unwrap_spec - if len(frame.stack) < len_unwrap_spec: + if len(s_frame.stack()) < len_unwrap_spec: raise PrimitiveFailedError() args = () for i, spec in unrolling_unwrap_spec: - index = -len_unwrap_spec + i - w_arg = frame.stack[index] + index = len_unwrap_spec - 1 - i + w_arg = s_frame.peek(index) if spec is int: - args += (utility.unwrap_int(w_arg), ) + args += (interp.space.unwrap_int(w_arg), ) elif spec is index1_0: - args += (utility.unwrap_int(w_arg)-1, ) + args += (interp.space.unwrap_int(w_arg)-1, ) elif spec is float: - args += (utility.unwrap_float(w_arg), ) + args += (interp.space.unwrap_float(w_arg), ) elif spec is object: args += (w_arg, ) elif spec is str: + assert isinstance(w_arg, model.W_BytesObject) args += (w_arg.as_string(), ) elif spec is char: args += (unwrap_char(w_arg), ) @@ -101,10 +102,13 @@ raise NotImplementedError( "unknown unwrap_spec %s" % (spec, )) w_result = func(interp, *args) - frame.pop_n(len_unwrap_spec) # only if no exception occurs! + # After calling primitive, reload context-shadow in case it + # needs to be updated + new_s_frame = interp.s_active_context() + frame.as_context_get_shadow(interp.space).pop_n(len_unwrap_spec) # only if no exception occurs! if not no_result: assert w_result is not None - interp.w_active_context.push(w_result) + new_s_frame.push(w_result) wrapped.func_name = "wrap_prim_" + name prim_table[code] = wrapped prim_table_implemented_only.append((code, wrapped)) @@ -140,7 +144,7 @@ res = rarithmetic.ovfcheck(op(receiver, argument)) except OverflowError: raise PrimitiveFailedError() - return utility.wrap_int(res) + return interp.space.wrap_int(res) make_func(op) bitwise_binary_ops = { @@ -153,7 +157,7 @@ @expose_primitive(code, unwrap_spec=[int, int]) def func(interp, receiver, argument): res = op(receiver, argument) - return utility.wrap_int(res) + return interp.space.wrap_int(res) make_func(op) # #/ -- return the result of a division, only succeed if the division is exact @@ -163,28 +167,28 @@ raise PrimitiveFailedError() if receiver % argument != 0: raise PrimitiveFailedError() - return utility.wrap_int(receiver // argument) + return interp.space.wrap_int(receiver // argument) # #\\ -- return the remainder of a division @expose_primitive(MOD, unwrap_spec=[int, int]) def func(interp, receiver, argument): if argument == 0: raise PrimitiveFailedError() - return utility.wrap_int(receiver % argument) + return interp.space.wrap_int(receiver % argument) # #// -- return the result of a division, rounded towards negative zero @expose_primitive(DIV, unwrap_spec=[int, int]) def func(interp, receiver, argument): if argument == 0: raise PrimitiveFailedError() - return utility.wrap_int(receiver // argument) + return interp.space.wrap_int(receiver // argument) # #// -- return the result of a division, rounded towards negative infinity @expose_primitive(QUO, unwrap_spec=[int, int]) def func(interp, receiver, argument): if argument == 0: raise PrimitiveFailedError() - return utility.wrap_int(receiver // argument) + return interp.space.wrap_int(receiver // argument) # #bitShift: -- return the shifted value @expose_primitive(BIT_SHIFT, unwrap_spec=[int, int]) @@ -195,11 +199,11 @@ shifted = receiver << argument if (shifted >> argument) != receiver: raise PrimitiveFailedError() - return utility.wrap_int(shifted) + return interp.space.wrap_int(shifted) # right shift, ok to lose bits else: - return utility.wrap_int(receiver >> -argument) + return interp.space.wrap_int(receiver >> -argument) # ___________________________________________________________________________ @@ -230,35 +234,35 @@ def make_func(op): @expose_primitive(code, unwrap_spec=[float, float]) def func(interp, v1, v2): - w_res = utility.wrap_float(op(v1, v2)) + w_res = interp.space.wrap_float(op(v1, v2)) return w_res make_func(op) @expose_primitive(FLOAT_TRUNCATED, unwrap_spec=[float]) def func(interp, f): - w_res = utility.wrap_int(int(f)) + w_res = interp.space.wrap_int(int(f)) return w_res @expose_primitive(FLOAT_TIMES_TWO_POWER, unwrap_spec=[float, int]) def func(interp, rcvr, arg): - w_res = utility.wrap_float(math.ldexp(rcvr, arg)) + w_res = interp.space.wrap_float(math.ldexp(rcvr, arg)) return w_res @expose_primitive(FLOAT_SQUARE_ROOT, unwrap_spec=[float]) def func(interp, f): if f < 0.0: raise PrimitiveFailedError - w_res = utility.wrap_float(math.sqrt(f)) + w_res = interp.space.wrap_float(math.sqrt(f)) return w_res @expose_primitive(FLOAT_SIN, unwrap_spec=[float]) def func(interp, f): - w_res = utility.wrap_float(math.sin(f)) + w_res = interp.space.wrap_float(math.sin(f)) return w_res @expose_primitive(FLOAT_ARCTAN, unwrap_spec=[float]) def func(interp, f): - w_res = utility.wrap_float(math.atan(f)) + w_res = interp.space.wrap_float(math.atan(f)) return w_res @expose_primitive(FLOAT_LOG_N, unwrap_spec=[float]) @@ -269,13 +273,28 @@ res = rarithmetic.NAN else: res = math.log(f) - return utility.wrap_float(res) + return interp.space.wrap_float(res) @expose_primitive(FLOAT_EXP, unwrap_spec=[float]) def func(interp, f): - w_res = utility.wrap_float(math.exp(f)) + w_res = interp.space.wrap_float(math.exp(f)) return w_res +MAKE_POINT = 18 + + at expose_primitive(MAKE_POINT, unwrap_spec=[int, int]) +def func(interp, x, y): + w_res = interp.space.classtable['w_Point'].as_class_get_shadow(interp.space).new(2) + point = wrapper.PointWrapper(interp.space, w_res) + point.store_x(interp.space, x) + point.store_y(interp.space, y) + return w_res + + +# ___________________________________________________________________________ +# Failure + +FAIL = 19 # ___________________________________________________________________________ # Subscript and Stream Primitives @@ -288,34 +307,37 @@ @expose_primitive(AT, unwrap_spec=[object, index1_0]) def func(interp, w_obj, n0): - n0 = assert_valid_index(n0, w_obj) - return w_obj.at0(n0) + n0 = assert_valid_index(interp.space, n0, w_obj) + return w_obj.at0(interp.space, n0) @expose_primitive(AT_PUT, unwrap_spec=[object, index1_0, object]) def func(interp, w_obj, n0, w_val): - n0 = assert_valid_index(n0, w_obj) - w_obj.atput0(n0, w_val) + n0 = assert_valid_index(interp.space, n0, w_obj) + w_obj.atput0(interp.space, n0, w_val) return w_val @expose_primitive(SIZE, unwrap_spec=[object]) def func(interp, w_obj): - if not w_obj.shadow_of_my_class().isvariable(): + if not w_obj.shadow_of_my_class(interp.space).isvariable(): raise PrimitiveFailedError() - return utility.wrap_int(w_obj.primsize()) + return interp.space.wrap_int(w_obj.primsize(interp.space)) @expose_primitive(STRING_AT, unwrap_spec=[object, index1_0]) def func(interp, w_obj, n0): - n0 = assert_valid_index(n0, w_obj) + n0 = assert_valid_index(interp.space, n0, w_obj) # XXX I am not sure this is correct, but it un-breaks translation: # make sure that getbyte is only performed on W_BytesObjects if not isinstance(w_obj, model.W_BytesObject): raise PrimitiveFailedError - return utility.wrap_char(w_obj.getchar(n0)) + return interp.space.wrap_char(w_obj.getchar(n0)) @expose_primitive(STRING_AT_PUT, unwrap_spec=[object, index1_0, object]) def func(interp, w_obj, n0, w_val): - val = utility.unwrap_char(w_val) - n0 = assert_valid_index(n0, w_obj) + val = interp.space.unwrap_char(w_val) + n0 = assert_valid_index(interp.space, n0, w_obj) + if not (isinstance(w_obj, model.W_CompiledMethod) or + isinstance(w_obj, model.W_BytesObject)): + raise PrimitiveFailedError() w_obj.setchar(n0, val) return w_val @@ -346,26 +368,28 @@ def func(interp, w_rcvr, n0): if not isinstance(w_rcvr, model.W_CompiledMethod): raise PrimitiveFailedError() - return w_rcvr.literalat0(n0) + return w_rcvr.literalat0(interp.space, n0) @expose_primitive(OBJECT_AT_PUT, unwrap_spec=[object, index1_0, object]) def func(interp, w_rcvr, n0, w_value): if not isinstance(w_rcvr, model.W_CompiledMethod): raise PrimitiveFailedError() #assert_bounds(n0, 0, len(w_rcvr.literals)) - w_rcvr.literalatput0(n0, w_value) + w_rcvr.literalatput0(interp.space, n0, w_value) return w_value @expose_primitive(NEW, unwrap_spec=[object]) def func(interp, w_cls): - s_class = w_cls.as_class_get_shadow() + assert isinstance(w_cls, model.W_PointersObject) + s_class = w_cls.as_class_get_shadow(interp.space) if s_class.isvariable(): raise PrimitiveFailedError() return s_class.new() @expose_primitive(NEW_WITH_ARG, unwrap_spec=[object, int]) def func(interp, w_cls, size): - s_class = w_cls.as_class_get_shadow() + assert isinstance(w_cls, model.W_PointersObject) + s_class = w_cls.as_class_get_shadow(interp.space) if not s_class.isvariable(): raise PrimitiveFailedError() return s_class.new(size) @@ -377,27 +401,28 @@ @expose_primitive(INST_VAR_AT, unwrap_spec=[object, index1_0]) def func(interp, w_rcvr, n0): "Fetches a fixed field from the object, and fails otherwise" - s_class = w_rcvr.shadow_of_my_class() + s_class = w_rcvr.shadow_of_my_class(interp.space) assert_bounds(n0, 0, s_class.instsize()) # only pointers have non-0 size - assert isinstance(w_rcvr, model.W_PointersObject) - return w_rcvr.fetch(n0) + # XXX Now MethodContext is still own format, leave + #assert isinstance(w_rcvr, model.W_PointersObject) + return w_rcvr.fetch(interp.space, n0) @expose_primitive(INST_VAR_AT_PUT, unwrap_spec=[object, index1_0, object]) def func(interp, w_rcvr, n0, w_value): "Stores a value into a fixed field from the object, and fails otherwise" - s_class = w_rcvr.shadow_of_my_class() + s_class = w_rcvr.shadow_of_my_class(interp.space) assert_bounds(n0, 0, s_class.instsize()) - # only pointers have non-0 size - assert isinstance(w_rcvr, model.W_PointersObject) - w_rcvr.store(n0, w_value) + # XXX Now MethodContext is still own format, leave + #assert isinstance(w_rcvr, model.W_PointersObject) + w_rcvr.store(interp.space, n0, w_value) return w_value @expose_primitive(AS_OOP, unwrap_spec=[object]) def func(interp, w_rcvr): if isinstance(w_rcvr, model.W_SmallInteger): raise PrimitiveFailedError() - return utility.wrap_int(w_rcvr.gethash()) + return interp.space.wrap_int(w_rcvr.gethash()) @expose_primitive(STORE_STACKP, unwrap_spec=[object, object]) def func(interp, w_obj1, w_obj2): @@ -436,11 +461,11 @@ @expose_primitive(EQUIVALENT, unwrap_spec=[object, object]) def func(interp, w_arg, w_rcvr): - return utility.wrap_bool(w_arg.equals(w_rcvr)) + return interp.space.wrap_bool(w_arg.is_same_object(w_rcvr)) @expose_primitive(CLASS, unwrap_spec=[object]) def func(interp, w_obj): - return w_obj.getclass() + return w_obj.getclass(interp.space) @expose_primitive(BYTES_LEFT, unwrap_spec=[object]) def func(interp, w_rcvr): @@ -456,15 +481,15 @@ @expose_primitive(CHANGE_CLASS, unwrap_spec=[object, object], no_result=True) def func(interp, w_arg, w_rcvr): - w_arg_class = w_arg.getclass() - w_rcvr_class = w_rcvr.getclass() + w_arg_class = w_arg.getclass(interp.space) + w_rcvr_class = w_rcvr.getclass(interp.space) # We should fail if: # 1. Rcvr or arg are SmallIntegers # XXX this is wrong too - if (w_arg_class == classtable.w_SmallInteger or - w_rcvr_class == classtable.w_SmallInteger): + if (w_arg_class.is_same_object(interp.space.w_SmallInteger) or + w_rcvr_class.is_same_object(interp.space.w_SmallInteger)): raise PrimitiveFailedError() # 2. Rcvr is an instance of a compact class and argument isn't @@ -484,18 +509,37 @@ # ___________________________________________________________________________ # Squeak Miscellaneous Primitives (128-149) +BECOME = 128 FULL_GC = 130 INC_GC = 131 -def fake_bytes_left(): - return utility.wrap_int(2**20) # XXX we don't know how to do this :-( + at expose_primitive(BECOME, unwrap_spec=[object, object]) +def func(interp, w_rcvr, w_new): + if w_rcvr.size() != w_new.size(): + raise PrimitiveFailedError + w_lefts = [] + w_rights = [] + for i in range(w_rcvr.size()): + w_left = w_rcvr.at0(interp.space, i) + w_right = w_new.at0(interp.space, i) + if w_left.become(w_right): + w_lefts.append(w_left) + w_rights.append(w_right) + else: + for i in range(len(w_lefts)): + w_lefts[i].become(w_rights[i]) + raise PrimitiveFailedError() + return w_rcvr + +def fake_bytes_left(interp): + return interp.space.wrap_int(2**20) # XXX we don't know how to do this :-( @expose_primitive(INC_GC, unwrap_spec=[object]) @expose_primitive(FULL_GC, unwrap_spec=[object]) def func(interp, w_arg): # Squeak pops the arg and ignores it ... go figure from pypy.rlib import rgc rgc.collect() - return fake_bytes_left() + return fake_bytes_left(interp) #____________________________________________________________________________ # Time Primitives @@ -506,13 +550,13 @@ def func(interp, w_arg): import time import math - return utility.wrap_int(int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2))) + return interp.space.wrap_int(int(math.fmod(time.time()*1000, constants.TAGGED_MAXINT/2))) @expose_primitive(SECONDS_CLOCK, unwrap_spec=[object]) def func(interp, w_arg): import time - return utility.wrap_int(0x23910d6c) # HACK: too big for a small int! - #return utility.wrap_int(int(time.time())) + return interp.space.wrap_int(0x23910d6c) # HACK: too big for a small int! + #return interp.space.wrap_int(int(time.time())) # ___________________________________________________________________________ # Boolean Primitives @@ -544,7 +588,7 @@ @expose_primitive(code, unwrap_spec=[int, int]) def func(interp, v1, v2): res = op(v1, v2) - w_res = utility.wrap_bool(res) + w_res = interp.space.wrap_bool(res) return w_res make_func(op) @@ -553,7 +597,7 @@ @expose_primitive(code+_FLOAT_OFFSET, unwrap_spec=[float, float]) def func(interp, v1, v2): res = op(v1, v2) - w_res = utility.wrap_bool(res) + w_res = interp.space.wrap_bool(res) return w_res make_func(op) @@ -574,20 +618,21 @@ # no-op really return w_self -for (code, const) in [ - (PUSH_TRUE, objtable.w_true), - (PUSH_FALSE, objtable.w_false), - (PUSH_NIL, objtable.w_nil), - (PUSH_MINUS_ONE, objtable.w_minus_one), - (PUSH_ZERO, objtable.w_zero), - (PUSH_ONE, objtable.w_one), - (PUSH_TWO, objtable.w_two), +def make_push_const_func(code, name): + @expose_primitive(code, unwrap_spec=[object]) + def func(interp, w_ignored): + return getattr(interp.space, name) + +for (code, name) in [ + (PUSH_TRUE, "w_true"), + (PUSH_FALSE, "w_false"), + (PUSH_NIL, "w_nil"), + (PUSH_MINUS_ONE, "w_minus_one"), + (PUSH_ZERO, "w_zero"), + (PUSH_ONE, "w_one"), + (PUSH_TWO, "w_two"), ]: - def make_func(const): - @expose_primitive(code, unwrap_spec=[object]) - def func(interp, w_ignored): - return const - make_func(const) + make_push_const_func(code, name) # ___________________________________________________________________________ # Control Primitives @@ -605,28 +650,28 @@ @expose_primitive(PRIMITIVE_BLOCK_COPY, unwrap_spec=[object, int]) def func(interp, w_context, argcnt): - frame = interp.w_active_context + frame = interp.s_active_context() # From B.B.: If receiver is a MethodContext, then it becomes # the new BlockContext's home context. Otherwise, the home # context of the receiver is used for the new BlockContext. # Note that in our impl, MethodContext.w_home == self - if not isinstance(w_context, model.W_ContextPart): - raise PrimitiveFailedError() - w_method_context = w_context.w_home + assert isinstance(w_context, model.W_PointersObject) + w_method_context = w_context.as_context_get_shadow(interp.space).w_home() # The block bytecodes are stored inline: so we skip past the # byteodes to invoke this primitive to find them (hence +2) - initialip = frame.pc + 2 - w_new_context = model.W_BlockContext( - w_method_context, None, argcnt, initialip) + initialip = frame.pc() + 2 + w_new_context = shadow.BlockContextShadow.make_context( + interp.space, + w_method_context, interp.space.w_nil, argcnt, initialip) return w_new_context -def finalize_block_ctx(interp, w_block_ctx, frame): +def finalize_block_ctx(interp, s_block_ctx, frame): # Set some fields - w_block_ctx.pc = w_block_ctx.initialip - w_block_ctx.w_sender = frame - interp.w_active_context = w_block_ctx + s_block_ctx.store_pc(s_block_ctx.initialip()) + s_block_ctx.store_w_sender(frame) + interp.store_w_active_context(s_block_ctx.w_self()) @expose_primitive(PRIMITIVE_VALUE, no_result=True) def func(interp, argument_count): @@ -636,46 +681,59 @@ # Rcvr | Arg 0 | Arg1 | Arg 2 # - frame = interp.w_active_context + frame = interp.s_active_context() # Validate that we have a block on the stack and that it received # the proper number of arguments: w_block_ctx = frame.peek(argument_count) - if not isinstance(w_block_ctx, model.W_BlockContext): + + # XXX need to check this since VALUE is called on all sorts of objects. + if not w_block_ctx.getclass(interp.space).is_same_object( + interp.space.w_BlockContext): raise PrimitiveFailedError() - exp_arg_cnt = w_block_ctx.expected_argument_count() + + assert isinstance(w_block_ctx, model.W_PointersObject) + + s_block_ctx = w_block_ctx.as_blockcontext_get_shadow(interp.space) + + exp_arg_cnt = s_block_ctx.expected_argument_count() if argument_count != exp_arg_cnt: # exp_arg_cnt doesn't count self raise PrimitiveFailedError() # Initialize the block stack with the arguments that were # pushed. Also pop the receiver. block_args = frame.pop_and_return_n(exp_arg_cnt) - w_block_ctx.push_all(block_args) + + # Reset stack of blockcontext to [] + s_block_ctx.reset_stack() + s_block_ctx.push_all(block_args) frame.pop() - finalize_block_ctx(interp, w_block_ctx, frame) + finalize_block_ctx(interp, s_block_ctx, frame.w_self()) @expose_primitive(PRIMITIVE_VALUE_WITH_ARGS, unwrap_spec=[object, object], no_result=True) def func(interp, w_block_ctx, w_args): - if not isinstance(w_block_ctx, model.W_BlockContext): - raise PrimitiveFailedError() - exp_arg_cnt = w_block_ctx.expected_argument_count() + + assert isinstance(w_block_ctx, model.W_PointersObject) + s_block_ctx = w_block_ctx.as_blockcontext_get_shadow(interp.space) + exp_arg_cnt = s_block_ctx.expected_argument_count() # Check that our arguments have pointers format and the right size: - if w_args.getclass() != classtable.w_Array: + if not w_args.getclass(interp.space).is_same_object( + interp.space.w_Array): raise PrimitiveFailedError() if w_args.size() != exp_arg_cnt: raise PrimitiveFailedError() + assert isinstance(w_args, model.W_PointersObject) # Push all the items from the array for i in range(exp_arg_cnt): - w_block_ctx.push(w_args.fetchvarpointer(i)) + s_block_ctx.push(w_args.at0(interp.space, i)) # XXX Check original logic. Image does not test this anyway # because falls back to value + internal implementation - - finalize_block_ctx(interp, w_block_ctx, interp.w_active_context) + finalize_block_ctx(interp, s_block_ctx, interp.w_active_context()) @expose_primitive(PRIMITIVE_PERFORM) def func(interp, argcount): @@ -685,34 +743,56 @@ unwrap_spec=[object, str, object], no_result=True) def func(interp, w_rcvr, sel, w_args): - w_method = w_rcvr.shadow_of_my_class().lookup(sel) + w_method = w_rcvr.shadow_of_my_class(interp.space).lookup(sel) assert w_method - w_frame = w_method.create_frame(w_rcvr, - [w_args.fetch(i) for i in range(w_args.size())]) + w_frame = w_method.create_frame(interp.space, w_rcvr, + [w_args.fetch(interp.space, i) for i in range(w_args.size())]) - w_frame.w_sender = interp.w_active_context - interp.w_active_context = w_frame + w_frame.as_context_get_shadow(interp.space).store_w_sender(interp.w_active_context()) + interp.store_w_active_context(w_frame) @expose_primitive(PRIMITIVE_SIGNAL, unwrap_spec=[object]) def func(interp, w_rcvr): - raise PrimitiveNotYetWrittenError() + # XXX we might want to disable this check + if not w_rcvr.getclass(interp.space).is_same_object( + interp.space.classtable['w_Semaphore']): + raise PrimitiveFailedError() + wrapper.SemaphoreWrapper(interp.space, w_rcvr).signal(interp) + return w_rcvr @expose_primitive(PRIMITIVE_WAIT, unwrap_spec=[object]) def func(interp, w_rcvr): - raise PrimitiveNotYetWrittenError() + # XXX we might want to disable this check + if not w_rcvr.getclass(interp.space).is_same_object( + interp.space.classtable['w_Semaphore']): + raise PrimitiveFailedError() + wrapper.SemaphoreWrapper(interp.space, w_rcvr).wait(interp) + return w_rcvr @expose_primitive(PRIMITIVE_RESUME, unwrap_spec=[object]) def func(interp, w_rcvr,): - raise PrimitiveNotYetWrittenError() - + # XXX we might want to disable this check + if not w_rcvr.getclass(interp.space).is_same_object( + interp.space.classtable['w_Process']): + raise PrimitiveFailedError() + wrapper.ProcessWrapper(interp.space, w_rcvr).resume(interp) + return w_rcvr + @expose_primitive(PRIMITIVE_SUSPEND, unwrap_spec=[object]) def func(interp, w_rcvr): - raise PrimitiveNotYetWrittenError() - + # XXX we might want to disable this check + if not w_rcvr.getclass(interp.space).is_same_object( + interp.space.classtable['w_Process']): + raise PrimitiveFailedError() + wrapper.ProcessWrapper(interp.space, w_rcvr).suspend(interp) + return w_rcvr + @expose_primitive(PRIMITIVE_FLUSH_CACHE, unwrap_spec=[object]) def func(interp, w_rcvr): - raise PrimitiveNotYetWrittenError() + # XXX we currently don't care about bad flushes :) XXX + # raise PrimitiveNotYetWrittenError() + return w_rcvr # ___________________________________________________________________________ # PrimitiveLoadInstVar @@ -728,7 +808,7 @@ def make_prim(i): @expose_primitive(i, unwrap_spec=[object]) def func(interp, w_object): - return w_object.fetch(i - 264) + return w_object.fetch(interp.space, i - 264) globals()["INST_VAR_AT_%d" % (i-264)] = i make_prim(i) Modified: pypy/branch/build-external/pypy/lang/smalltalk/shadow.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/shadow.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/shadow.py Tue Jun 10 12:48:46 2008 @@ -1,13 +1,61 @@ import weakref -from pypy.lang.smalltalk import model, constants, utility, error +from pypy.lang.smalltalk import model, constants, error +from pypy.tool.pairtype import extendabletype class AbstractShadow(object): """A shadow is an optional extra bit of information that can be attached at run-time to any Smalltalk object. """ - def invalidate(self): - """XXX This should get called whenever the base Smalltalk + def __init__(self, space, w_self): + self.space = space + self._w_self = w_self + def fetch(self, n0): + return self.w_self()._fetch(n0) + def store(self, n0, w_value): + return self.w_self()._store(n0, w_value) + def size(self): + return self.w_self()._size() + def w_self(self): + return self._w_self + def getname(self): + return repr(self) + def attach_shadow(self): pass + def detach_shadow(self): pass + def sync_shadow(self): pass + +class AbstractCachingShadow(AbstractShadow): + def __init__(self, space, w_self): + AbstractShadow.__init__(self, space, w_self) + self.invalid = True + self.invalidate_shadow() + + def detach_shadow(self): + self.invalidate_shadow() + + def invalidate_shadow(self): + """This should get called whenever the base Smalltalk object changes.""" + if not self.invalid: + self.invalid = True + + def attach_shadow(self): + self.update_shadow() + + def sync_shadow(self): + if self.invalid: + self.update_shadow() + + def update_shadow(self): + self.w_self().store_shadow(self) + self.invalid = False + self.sync_cache() + + def sync_cache(self): + raise NotImplementedError() + + def store(self, n0, w_value): + self.invalidate_shadow() + AbstractShadow.store(self, n0, w_value) # ____________________________________________________________ @@ -24,32 +72,29 @@ class ClassShadowError(error.SmalltalkException): pass -class ClassShadow(AbstractShadow): +class ClassShadow(AbstractCachingShadow): """A shadow for Smalltalk objects that are classes (i.e. used as the class of another Smalltalk object). """ - def __init__(self, w_self): - self.w_self = w_self - self.invalidate() + name = None + def __init__(self, space, w_self): + self.name = "" + AbstractCachingShadow.__init__(self, space, w_self) + def invalidate_shadow(self): + AbstractCachingShadow.invalidate_shadow(self) + self.w_methoddict = None + self.w_superclass = None - def invalidate(self): - self.methoddict = {} - self.s_superclass = None # the ClassShadow of the super class - self.name = None - self.invalid = True - - def check_for_updates(self): - if self.invalid: - self.update_shadow() + def getname(self): + return "%s class" % (self.name or '?',) - def update_shadow(self): + def sync_cache(self): "Update the ClassShadow with data from the w_self class." - from pypy.lang.smalltalk import objtable - w_self = self.w_self + w_self = self.w_self() # read and painfully decode the format - classformat = utility.unwrap_int( - w_self.fetch(constants.CLASS_FORMAT_INDEX)) + classformat = self.space.unwrap_int( + w_self._fetch(constants.CLASS_FORMAT_INDEX)) # The classformat in Squeak, as an integer value, is: # <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec> # <6 bits=instSize\\64><1 bit=0> @@ -82,57 +127,66 @@ self.instance_kind = COMPILED_METHOD else: raise ClassShadowError("unknown format %d" % (format,)) + + self.guess_class_name() + + # read the methoddict + w_methoddict = w_self._fetch(constants.CLASS_METHODDICT_INDEX) + assert isinstance(w_methoddict, model.W_PointersObject) + self.w_methoddict = w_methoddict + + w_superclass = w_self._fetch(constants.CLASS_SUPERCLASS_INDEX) + if w_superclass.is_same_object(self.space.w_nil): + self.w_superclass = None + else: + assert isinstance(w_superclass, model.W_PointersObject) + self.w_superclass = w_superclass + + def guess_class_name(self): + w_self = self.w_self() + w_name = None + # read the name if w_self.size() > constants.CLASS_NAME_INDEX: - w_name = w_self.fetch(constants.CLASS_NAME_INDEX) - if isinstance(w_name, model.W_BytesObject): - self.name = w_name.as_string() - # read the methoddict - w_methoddict = w_self.fetch(constants.CLASS_METHODDICT_INDEX) - w_values = w_methoddict.fetch(constants.METHODDICT_VALUES_INDEX) - size = w_methoddict.size() - constants.METHODDICT_NAMES_INDEX - for i in range(size): - w_selector = w_methoddict.fetch(constants.METHODDICT_NAMES_INDEX+i) - if w_selector is not objtable.w_nil: - if not isinstance(w_selector, model.W_BytesObject): - raise ClassShadowError("bogus selector in method dict") - selector = w_selector.as_string() - w_compiledmethod = w_values.fetch(i) - if not isinstance(w_compiledmethod, model.W_CompiledMethod): - raise ClassShadowError("the methoddict must contain " - "CompiledMethods only for now") - self.methoddict[selector] = w_compiledmethod - # for the rest, we need to reset invalid to False already so - # that cycles in the superclass and/or metaclass chains don't - # cause infinite recursion - self.invalid = False - # read s_superclass - w_superclass = w_self.fetch(constants.CLASS_SUPERCLASS_INDEX) - if w_superclass is objtable.w_nil: - self.s_superclass = None + w_name = w_self._fetch(constants.CLASS_NAME_INDEX) else: - self.s_superclass = w_superclass.as_class_get_shadow() + # Some heuristic to find the classname + # Only used for debugging + # XXX This is highly experimental XXX + # if the name-pos of class is not bytesobject, + # we are probably holding a metaclass instead of a class. + # metaclasses hold a pointer to the real class in the last + # slot. This is pos 6 in mini.image and higher in squeak3.9 + w_realclass = w_self._fetch(w_self.size() - 1) + assert isinstance(w_realclass, model.W_PointersObject) + if w_realclass.size() > constants.CLASS_NAME_INDEX: + # TODO ADD TEST WHICH GOES OVER THIS PART + w_name = w_realclass._fetch(constants.CLASS_NAME_INDEX) + + if isinstance(w_name, model.W_BytesObject): + self.name = w_name.as_string() def new(self, extrasize=0): - from pypy.lang.smalltalk import classtable - w_cls = self.w_self - - if w_cls == classtable.w_BlockContext: - return model.W_BlockContext(None, None, 0, 0) - elif w_cls == classtable.w_MethodContext: - # From slang: Contexts must only be created with newForMethod: - raise error.PrimitiveFailedError - + w_cls = self.w_self() if self.instance_kind == POINTERS: - return model.W_PointersObject(w_cls, self.instance_size+extrasize) + w_new = model.W_PointersObject(w_cls, self.instance_size+extrasize) elif self.instance_kind == WORDS: - return model.W_WordsObject(w_cls, extrasize) + w_new = model.W_WordsObject(w_cls, extrasize) elif self.instance_kind == BYTES: - return model.W_BytesObject(w_cls, extrasize) + w_new = model.W_BytesObject(w_cls, extrasize) elif self.instance_kind == COMPILED_METHOD: - return model.W_CompiledMethod(extrasize) + w_new = model.W_CompiledMethod(extrasize) else: raise NotImplementedError(self.instance_kind) + return w_new + + def s_methoddict(self): + return self.w_methoddict.as_methoddict_get_shadow(self.space) + + def s_superclass(self): + if self.w_superclass is None: + return None + return self.w_superclass.as_class_get_shadow(self.space) # _______________________________________________________________ # Methods for querying the format word, taken from the blue book: @@ -167,7 +221,7 @@ while classshadow is not None: if classshadow is s_superclass: return True - classshadow = classshadow.s_superclass + classshadow = classshadow.s_superclass() else: return False @@ -179,18 +233,463 @@ def lookup(self, selector): look_in_shadow = self - while True: + while look_in_shadow is not None: try: - return look_in_shadow.methoddict[selector] - except KeyError: - pass - look_in_shadow = look_in_shadow.s_superclass - if look_in_shadow is None: - # attach information on the exception, for debugging. - raise MethodNotFound(self, selector) + w_method = look_in_shadow.s_methoddict().methoddict[selector] + return w_method + except KeyError, e: + look_in_shadow = look_in_shadow.s_superclass() + raise MethodNotFound(self, selector) + + def initialize_methoddict(self): + "NOT_RPYTHON" # this is only for testing. + if self.w_methoddict is None: + self.w_methoddict = model.W_PointersObject(None, 2) + self.w_methoddict._store(1, model.W_PointersObject(None, 0)) + self.s_methoddict().invalid = False def installmethod(self, selector, method): "NOT_RPYTHON" # this is only for testing. - assert isinstance(method, model.W_CompiledMethod) - self.methoddict[selector] = method - method.w_compiledin = self.w_self + self.initialize_methoddict() + self.s_methoddict().methoddict[selector] = method + if isinstance(method, model.W_CompiledMethod): + method.w_compiledin = self.w_self() + +class MethodDictionaryShadow(AbstractCachingShadow): + + def invalidate_shadow(self): + AbstractCachingShadow.invalidate_shadow(self) + self.methoddict = None + + def sync_cache(self): + w_values = self.w_self()._fetch(constants.METHODDICT_VALUES_INDEX) + assert isinstance(w_values, model.W_PointersObject) + s_values = w_values.get_shadow(self.space) + # XXX Should add! + # s_values.notifyinvalid(self) + size = self.w_self().size() - constants.METHODDICT_NAMES_INDEX + self.methoddict = {} + for i in range(size): + w_selector = self.w_self()._fetch(constants.METHODDICT_NAMES_INDEX+i) + if not w_selector.is_same_object(self.space.w_nil): + if not isinstance(w_selector, model.W_BytesObject): + raise ClassShadowError("bogus selector in method dict") + selector = w_selector.as_string() + w_compiledmethod = w_values._fetch(i) + if not isinstance(w_compiledmethod, model.W_CompiledMethod): + raise ClassShadowError("the methoddict must contain " + "CompiledMethods only for now") + self.methoddict[selector] = w_compiledmethod + + +class AbstractRedirectingShadow(AbstractShadow): + def __init__(self, space, w_self): + AbstractShadow.__init__(self, space, w_self) + self._w_self_size = self.w_self().size() + def fetch(self, n0): + raise NotImplementedError() + def store(self, n0, w_value): + raise NotImplementedError() + def size(self): + return self._w_self_size + + def attach_shadow(self): + AbstractShadow.attach_shadow(self) + for i in range(self._w_self_size): + self.copy_from_w_self(i) + self.w_self()._vars = None + + def detach_shadow(self): + self.w_self()._vars = [self.space.w_nil] * self._w_self_size + for i in range(self._w_self_size): + self.copy_to_w_self(i) + + def copy_from_w_self(self, n0): + self.store(n0, self.w_self()._fetch(n0)) + def copy_to_w_self(self, n0): + self.w_self()._store(n0, self.fetch(n0)) + +class ContextPartShadow(AbstractRedirectingShadow): + + __metaclass__ = extendabletype + + def __init__(self, space, w_self): + self._w_sender = space.w_nil + self._stack = [] + self.currentBytecode = -1 + AbstractRedirectingShadow.__init__(self, space, w_self) + + @staticmethod + def is_block_context(w_pointers, space): + method_or_argc = w_pointers.fetch(space, constants.MTHDCTX_METHOD) + return method_or_argc.getclass(space).is_same_object( + space.w_SmallInteger) + + def fetch(self, n0): + if n0 == constants.CTXPART_SENDER_INDEX: + return self.w_sender() + if n0 == constants.CTXPART_PC_INDEX: + return self.wrap_pc() + if n0 == constants.CTXPART_STACKP_INDEX: + return self.wrap_stackpointer() + if self.stackstart() <= n0 < self.external_stackpointer(): + return self._stack[n0-self.stackstart()] + if self.external_stackpointer() <= n0 < self.stackend(): + return self.space.w_nil + else: + # XXX later should store tail out of known context part as well + raise error.WrapperException("Index in context out of bounds") + + def store(self, n0, w_value): + if n0 == constants.CTXPART_SENDER_INDEX: + return self.store_w_sender(w_value) + if n0 == constants.CTXPART_PC_INDEX: + return self.store_unwrap_pc(w_value) + if n0 == constants.CTXPART_STACKP_INDEX: + return self.unwrap_store_stackpointer(w_value) + if self.stackstart() <= n0 < self.external_stackpointer(): + self._stack[n0 - self.stackstart()] = w_value + return + if self.external_stackpointer() <= n0 < self.stackend(): + return + else: + # XXX later should store tail out of known context part as well + raise error.WrapperException("Index in context out of bounds") + + def unwrap_store_stackpointer(self, w_sp1): + # the stackpointer in the W_PointersObject starts counting at the + # tempframe start + # Stackpointer from smalltalk world == stacksize in python world + self.store_stackpointer(self.space.unwrap_int(w_sp1) - + self.tempsize()) + + def store_stackpointer(self, size): + if size < len(self._stack): + # TODO Warn back to user + assert size >= 0 + self._stack = self._stack[:size] + else: + add = [self.space.w_nil] * (size - len(self._stack)) + self._stack.extend(add) + + def wrap_stackpointer(self): + return self.space.wrap_int(len(self._stack) + + self.tempsize()) + + def external_stackpointer(self): + return len(self._stack) + self.stackstart() + + def w_home(self): + raise NotImplementedError() + + def s_home(self): + return self.w_home().as_methodcontext_get_shadow(self.space) + + def stackstart(self): + raise NotImplementedError() + + def stackpointer_offset(self): + raise NotImplementedError() + + def w_receiver(self): + " Return self of the method, or the method that contains the block " + return self.s_home().w_receiver() + + def store_w_sender(self, w_sender): + assert isinstance(w_sender, model.W_PointersObject) + self._w_sender = w_sender + + def w_sender(self): + return self._w_sender + + def s_sender(self): + w_sender = self.w_sender() + if w_sender.is_same_object(self.space.w_nil): + return None + else: + return w_sender.as_context_get_shadow(self.space) + + def store_unwrap_pc(self, w_pc): + if w_pc.is_same_object(self.space.w_nil): + return + pc = self.space.unwrap_int(w_pc) + pc -= self.w_method().bytecodeoffset() + pc -= 1 + self.store_pc(pc) + + def wrap_pc(self): + pc = self.pc() + pc += 1 + pc += self.w_method().bytecodeoffset() + return self.space.wrap_int(pc) + + def pc(self): + return self._pc + + def store_pc(self, newpc): + self._pc = newpc + + def stackpointer_offset(self): + raise NotImplementedError() + + # ______________________________________________________________________ + # Method that contains the bytecode for this method/block context + + def w_method(self): + return self.s_home().w_method() + + def getbytecode(self): + assert self._pc >= 0 + bytecode = self.w_method().bytes[self._pc] + currentBytecode = ord(bytecode) + self._pc += 1 + return currentBytecode + + def getNextBytecode(self): + self.currentBytecode = self.getbytecode() + return self.currentBytecode + + # ______________________________________________________________________ + # Temporary Variables + # + # Are always fetched relative to the home method context. + + def gettemp(self, index): + return self.s_home().gettemp(index) + + def settemp(self, index, w_value): + self.s_home().settemp(index, w_value) + + # ______________________________________________________________________ + # Stack Manipulation + def pop(self): + return self._stack.pop() + + def push(self, w_v): + self._stack.append(w_v) + + def push_all(self, lst): + self._stack.extend(lst) + + def top(self): + return self.peek(0) + + def peek(self, idx): + return self._stack[-(idx + 1)] + + def pop_n(self, n): + assert n >= 0 + start = len(self._stack) - n + assert start >= 0 # XXX what if this fails? + del self._stack[start:] + + def stack(self): + return self._stack + + def pop_and_return_n(self, n): + assert n >= 0 + start = len(self._stack) - n + assert start >= 0 # XXX what if this fails? + res = self._stack[start:] + del self._stack[start:] + return res + + def stackend(self): + # XXX this is incorrect when there is subclassing + return self._w_self_size + + def tempsize(self): + raise NotImplementedError() + +class BlockContextShadow(ContextPartShadow): + + @staticmethod + def make_context(space, w_home, w_sender, argcnt, initialip): + # create and attach a shadow manually, to not have to carefully put things + # into the right places in the W_PointersObject + # XXX could hack some more to never have to create the _vars of w_result + contextsize = w_home.as_methodcontext_get_shadow(space).myblocksize() + w_result = model.W_PointersObject(space.w_BlockContext, contextsize) + s_result = BlockContextShadow(space, w_result) + w_result.store_shadow(s_result) + s_result.store_expected_argument_count(argcnt) + s_result.store_initialip(initialip) + s_result.store_w_home(w_home) + s_result.store_pc(initialip) + return w_result + + def fetch(self, n0): + if n0 == constants.BLKCTX_HOME_INDEX: + return self.w_home() + if n0 == constants.BLKCTX_INITIAL_IP_INDEX: + return self.wrap_initialip() + if n0 == constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX: + return self.wrap_eargc() + else: + return ContextPartShadow.fetch(self, n0) + + def store(self, n0, w_value): + if n0 == constants.BLKCTX_HOME_INDEX: + return self.store_w_home(w_value) + if n0 == constants.BLKCTX_INITIAL_IP_INDEX: + return self.unwrap_store_initialip(w_value) + if n0 == constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX: + return self.unwrap_store_eargc(w_value) + else: + return ContextPartShadow.store(self, n0, w_value) + + def attach_shadow(self): + # Make sure the home context is updated first + self.copy_from_w_self(constants.BLKCTX_HOME_INDEX) + ContextPartShadow.attach_shadow(self) + + def unwrap_store_initialip(self, w_value): + initialip = self.space.unwrap_int(w_value) + initialip -= 1 + self.w_method().getliteralsize() + self.store_initialip(initialip) + + def wrap_initialip(self): + initialip = self.initialip() + initialip += 1 + self.w_method().getliteralsize() + return self.space.wrap_int(initialip) + + def unwrap_store_eargc(self, w_value): + self.store_expected_argument_count(self.space.unwrap_int(w_value)) + + def wrap_eargc(self): + return self.space.wrap_int(self.expected_argument_count()) + + def expected_argument_count(self): + return self._eargc + + def store_expected_argument_count(self, argc): + self._eargc = argc + + def initialip(self): + return self._initialip + + def store_initialip(self, initialip): + self._initialip = initialip + + def store_w_home(self, w_home): + assert isinstance(w_home, model.W_PointersObject) + self._w_home = w_home + + def w_home(self): + return self._w_home + + def reset_stack(self): + self._stack = [] + + def stackstart(self): + return constants.BLKCTX_STACK_START + + def stackpointer_offset(self): + return constants.BLKCTX_STACK_START + + def tempsize(self): + # A blockcontext doesn't have any temps + return 0 + +class MethodContextShadow(ContextPartShadow): + def __init__(self, space, w_self): + self.w_receiver_map = space.w_nil + self._w_receiver = None + ContextPartShadow.__init__(self, space, w_self) + + @staticmethod + def make_context(space, w_method, w_receiver, + arguments, w_sender=None): + # From blue book: normal mc have place for 12 temps+maxstack + # mc for methods with islarge flag turned on 32 + size = 12 + w_method.islarge * 20 + w_method.argsize + w_result = space.w_MethodContext.as_class_get_shadow(space).new(size) + assert isinstance(w_result, model.W_PointersObject) + # create and attach a shadow manually, to not have to carefully put things + # into the right places in the W_PointersObject + # XXX could hack some more to never have to create the _vars of w_result + s_result = MethodContextShadow(space, w_result) + w_result.store_shadow(s_result) + s_result.store_w_method(w_method) + if w_sender: + s_result.store_w_sender(w_sender) + s_result.store_w_receiver(w_receiver) + s_result.store_pc(0) + s_result._temps = [space.w_nil] * w_method.tempsize + for i in range(len(arguments)): + s_result.settemp(i, arguments[i]) + return w_result + + def fetch(self, n0): + if n0 == constants.MTHDCTX_METHOD: + return self.w_method() + if n0 == constants.MTHDCTX_RECEIVER_MAP: + return self.w_receiver_map + if n0 == constants.MTHDCTX_RECEIVER: + return self.w_receiver() + if (0 <= n0-constants.MTHDCTX_TEMP_FRAME_START < + self.tempsize()): + return self.gettemp(n0-constants.MTHDCTX_TEMP_FRAME_START) + else: + return ContextPartShadow.fetch(self, n0) + + def store(self, n0, w_value): + if n0 == constants.MTHDCTX_METHOD: + return self.store_w_method(w_value) + if n0 == constants.MTHDCTX_RECEIVER_MAP: + self.w_receiver_map = w_value + return + if n0 == constants.MTHDCTX_RECEIVER: + self.store_w_receiver(w_value) + return + if (0 <= n0-constants.MTHDCTX_TEMP_FRAME_START < + self.tempsize()): + return self.settemp(n0-constants.MTHDCTX_TEMP_FRAME_START, + w_value) + else: + return ContextPartShadow.store(self, n0, w_value) + + def attach_shadow(self): + # Make sure the method is updated first + self.copy_from_w_self(constants.MTHDCTX_METHOD) + # And that there is space for the temps + self._temps = [self.space.w_nil] * self.tempsize() + ContextPartShadow.attach_shadow(self) + + def tempsize(self): + return self.w_method().tempsize + + def w_method(self): + return self._w_method + + def store_w_method(self, w_method): + assert isinstance(w_method, model.W_CompiledMethod) + self._w_method = w_method + + def w_receiver(self): + return self._w_receiver + + def store_w_receiver(self, w_receiver): + self._w_receiver = w_receiver + + def gettemp(self, index0): + return self._temps[index0] + + def settemp(self, index0, w_value): + self._temps[index0] = w_value + + def w_home(self): + return self.w_self() + + def s_home(self): + return self + + def stackpointer_offset(self): + return constants.MTHDCTX_TEMP_FRAME_START + + def stackstart(self): + return (constants.MTHDCTX_TEMP_FRAME_START + + self.tempsize()) + + def myblocksize(self): + return self.size() - self.tempsize() Modified: pypy/branch/build-external/pypy/lang/smalltalk/squeakimage.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/squeakimage.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/squeakimage.py Tue Jun 10 12:48:46 2008 @@ -1,7 +1,7 @@ import py import os +from pypy.lang.smalltalk import constants from pypy.lang.smalltalk import model -from pypy.lang.smalltalk import objtable, utility from pypy.rlib import objectmodel from pypy.lang.smalltalk.tool.bitmanipulation import splitter @@ -69,7 +69,8 @@ # ____________________________________________________________ class ImageReader(object): - def __init__(self, stream): + def __init__(self, space, stream): + self.space = space self.stream = stream self.chunks = {} self.chunklist = [] @@ -124,16 +125,13 @@ chunk.g_object.init_w_object() def assign_prebuilt_constants(self): - from pypy.lang.smalltalk import classtable, constants, objtable # assign w_objects for objects that are already in classtable for name, so_index in constants.classes_in_special_object_table.items(): - # w_object = getattr(classtable, "w_" + name) - w_object = classtable.classtable["w_" + name] + w_object = self.space.classtable["w_" + name] self.special_object(so_index).w_object = w_object # assign w_objects for objects that are already in objtable for name, so_index in constants.objects_in_special_object_table.items(): - # w_object = getattr(objtable, "w_" + name) - w_object = objtable.objtable["w_" + name] + w_object = self.space.objtable["w_" + name] self.special_object(so_index).w_object = w_object def special_object(self, index): @@ -173,14 +171,14 @@ kind, size, format, classid, idhash = ( splitter[2,6,4,5,12](self.stream.next())) assert kind == 3 - return ImageChunk(size, format, classid, idhash), self.stream.count - 4 + return ImageChunk(self.space, size, format, classid, idhash), self.stream.count - 4 def read_2wordobjectheader(self): assert self.stream.peek() & 3 == 1 #kind classid = self.stream.next() - 01 # remove headertype to get pointer kind, size, format, _, idhash = splitter[2,6,4,5,12](self.stream.next()) assert kind == 1 - return ImageChunk(size, format, classid, idhash), self.stream.count - 4 + return ImageChunk(self.space, size, format, classid, idhash), self.stream.count - 4 def read_3wordobjectheader(self): kind, size = splitter[2,30](self.stream.next()) @@ -189,18 +187,21 @@ classid = self.stream.next() - 00 # remove headertype to get pointer kind, _, format, _, idhash = splitter[2,6,4,5,12](self.stream.next()) assert kind == 0 - return ImageChunk(size, format, classid, idhash), self.stream.count - 4 + return ImageChunk(self.space, size, format, classid, idhash), self.stream.count - 4 # ____________________________________________________________ class SqueakImage(object): - def from_reader(self, reader): + def from_reader(self, space, reader): + from pypy.lang.smalltalk import constants self.special_objects = [g_object.w_object for g_object in reader.chunks[reader.specialobjectspointer] .g_object.pointers] - self.objects = [chunk.g_object.w_object for chunk in reader.chunklist] + + for name, idx in constants.objects_in_special_object_table.items(): + space.objtable["w_" + name] = self.special_objects[idx] def special(self, index): return self.special_objects[index] @@ -215,7 +216,8 @@ GenericObject from the image chunks, and uses them as starting point for the actual create of pypy.lang.smalltalk.model classes. """ - def __init__(self): + def __init__(self, space): + self.space = space self.owner = None def isinitialized(self): @@ -225,7 +227,7 @@ self.owner = reader self.value = value self.size = -1 - self.w_object = utility.wrap_int(value) + self.w_object = self.space.wrap_int(value) def initialize(self, chunk, reader): self.owner = reader @@ -252,7 +254,7 @@ def decode_pointer(self, pointer): if (pointer & 1) == 1: - small_int = GenericObject() + small_int = GenericObject(self.space) small_int.initialize_int(pointer >> 1, self.owner) return small_int else: @@ -320,19 +322,25 @@ def fillin_pointersobject(self, w_pointersobject): assert self.pointers is not None + if w_pointersobject._shadow is not None: + w_pointersobject._shadow.detach_shadow() w_pointersobject._vars = [g_object.w_object for g_object in self.pointers] - w_pointersobject.w_class = self.g_class.w_object + w_class = self.g_class.w_object + assert isinstance(w_class, model.W_PointersObject) + w_pointersobject.w_class = w_class w_pointersobject.hash = self.chunk.hash12 - if w_pointersobject._shadow is not None: - w_pointersobject._shadow.invalidate() def fillin_wordsobject(self, w_wordsobject): w_wordsobject.words = self.chunk.data - w_wordsobject.w_class = self.g_class.w_object + w_class = self.g_class.w_object + assert isinstance(w_class, model.W_PointersObject) + w_wordsobject.w_class = w_class w_wordsobject.hash = self.chunk.hash12 # XXX check this def fillin_bytesobject(self, w_bytesobject): - w_bytesobject.w_class = self.g_class.w_object + w_class = self.g_class.w_object + assert isinstance(w_class, model.W_PointersObject) + w_bytesobject.w_class = w_class w_bytesobject.bytes = self.get_bytes() w_bytesobject.hash = self.chunk.hash12 # XXX check this def get_bytes(self): @@ -359,20 +367,19 @@ header = self.chunk.data[0] w_compiledmethod.setheader(header>>1) # We untag before giving header for i in range(1,w_compiledmethod.literalsize+1): - w_compiledmethod.literalatput0(i, self.decode_pointer(self.chunk.data[i]).w_object) + w_compiledmethod.literalatput0( + self.space, i, self.decode_pointer(self.chunk.data[i]).w_object) bbytes = self.get_bytes()[(w_compiledmethod.literalsize + 1)*4:] - # XXX assert mirrorcache.get_or_build(self.g_class.w_object) is - # ct.m_CompiledMethod w_compiledmethod.bytes = ''.join(bbytes) class ImageChunk(object): - def __init__(self, size, format, classid, hash12): + def __init__(self, space, size, format, classid, hash12): self.size = size self.format = format self.classid = classid self.hash12 = hash12 self.data = None - self.g_object = GenericObject() + self.g_object = GenericObject(space) def __eq__(self, other): "(for testing)" Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_interpreter.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_interpreter.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_interpreter.py Tue Jun 10 12:48:46 2008 @@ -1,10 +1,10 @@ import py from pypy.lang.smalltalk import model, interpreter, primitives, shadow -from pypy.lang.smalltalk import objtable, classtable, utility -from pypy.lang.smalltalk.utility import wrap_int, wrap_char, wrap_string, \ - unwrap_int +from pypy.lang.smalltalk import objspace -mockclass = classtable.bootstrap_class +mockclass = objspace.bootstrap_class + +space = objspace.ObjSpace() # expose the bytecode's values as global constants. # Bytecodes that have a whole range are exposed as global functions: @@ -29,73 +29,78 @@ # Install faked compiled methods that just invoke the primitive: for (w_class, primnum, argsize, methname) in methods: - s_class = w_class.as_class_get_shadow() + s_class = w_class.as_class_get_shadow(space) prim_meth = model.W_CompiledMethod(0) prim_meth.primitive = primnum prim_meth.w_compiledin = w_class prim_meth.argsize = argsize s_class.installmethod(methname, prim_meth) + assert space.w_nil._shadow is None try: func() finally: # Uninstall those methods: + assert space.w_nil._shadow is None for (w_class, _, _, methname) in methods: - s_class = w_class.as_class_get_shadow() - del s_class.methoddict[methname] + s_class = w_class.as_class_get_shadow(space) + del s_class.s_methoddict().methoddict[methname] def fakesymbol(s, _cache={}): try: return _cache[s] except KeyError: - result = _cache[s] = wrap_string(s) + result = _cache[s] = space.wrap_string(s) return result -def fakeliterals(*literals): +def fakeliterals(space, *literals): def fakeliteral(lit): if isinstance(lit, str): return fakesymbol(lit) elif isinstance(lit, int): - return wrap_int(lit) + return space.wrap_int(lit) elif isinstance(lit, list): lstlen = len(lit) - res = classtable.w_Array.as_class_get_shadow().new(lstlen) + res = space.w_Array.as_class_get_shadow(space).new(lstlen) for i in range(lstlen): - res.storevarpointer(i, fakeliteral(lit[i])) + res.atput0(space, i, fakeliteral(lit[i])) return res return lit return [fakeliteral(lit) for lit in literals] -def new_interpreter(bytes, receiver=objtable.w_nil): +def new_interpreter(bytes, receiver=space.w_nil): assert isinstance(bytes, str) w_method = model.W_CompiledMethod(len(bytes)) + w_method.islarge = 1 w_method.bytes = bytes w_method.argsize=2 - w_method.tempsize=1 - w_frame = w_method.create_frame(receiver, ["foo", "bar"]) - interp = interpreter.Interpreter() - interp.w_active_context = w_frame + w_method.tempsize=8 + w_frame = w_method.create_frame(space, receiver, ["foo", "bar"]) + interp = interpreter.Interpreter(space) + interp.store_w_active_context(w_frame) return interp def test_create_frame(): w_method = model.W_CompiledMethod(len("hello")) w_method.bytes="hello" + w_method.islarge = 1 w_method.argsize=2 - w_method.tempsize=1 - w_frame = w_method.create_frame("receiver", ["foo", "bar"]) - assert w_frame.w_receiver == "receiver" - assert w_frame.gettemp(0) == "foo" - assert w_frame.gettemp(1) == "bar" - assert w_frame.gettemp(2) is objtable.w_nil - w_frame.settemp(2, "spam") - assert w_frame.gettemp(2) == "spam" - assert w_frame.getNextBytecode() == ord("h") - assert w_frame.getNextBytecode() == ord("e") - assert w_frame.getNextBytecode() == ord("l") + w_method.tempsize=8 + w_frame = w_method.create_frame(space, "receiver", ["foo", "bar"]) + s_frame = w_frame.as_context_get_shadow(space) + assert s_frame.w_receiver() == "receiver" + assert s_frame.gettemp(0) == "foo" + assert s_frame.gettemp(1) == "bar" + assert s_frame.gettemp(2) is space.w_nil + s_frame.settemp(2, "spam") + assert s_frame.gettemp(2) == "spam" + assert s_frame.getNextBytecode() == ord("h") + assert s_frame.getNextBytecode() == ord("e") + assert s_frame.getNextBytecode() == ord("l") def test_push_pop(): interp = new_interpreter("") - frame = interp.w_active_context + frame = interp.s_active_context() frame.push(12) frame.push(34) frame.push(56) @@ -116,264 +121,267 @@ def test_pushReceiverBytecode(): interp = new_interpreter(pushReceiverBytecode) interp.step() - assert interp.w_active_context.top() == interp.w_active_context.w_receiver + assert interp.s_active_context().top().is_same_object( + interp.w_active_context().as_methodcontext_get_shadow(space).w_receiver()) def test_pushReceiverVariableBytecode(bytecode = (pushReceiverVariableBytecode(0) + pushReceiverVariableBytecode(1) + pushReceiverVariableBytecode(2))): - w_demo = mockclass(3).as_class_get_shadow().new() - w_demo.store(0, "egg") - w_demo.store(1, "bar") - w_demo.store(2, "baz") + w_demo = mockclass(space, 3).as_class_get_shadow(space).new() + w_demo.store(space, 0, "egg") + w_demo.store(space, 1, "bar") + w_demo.store(space, 2, "baz") interp = new_interpreter(bytecode, receiver = w_demo) interp.step() interp.step() interp.step() - assert interp.w_active_context.stack == ["egg", "bar", "baz"] + assert interp.s_active_context().stack() == ["egg", "bar", "baz"] def test_pushTemporaryVariableBytecode(bytecode=(pushTemporaryVariableBytecode(0) + pushTemporaryVariableBytecode(1) + pushTemporaryVariableBytecode(2))): interp = new_interpreter(bytecode) - interp.w_active_context.settemp(2, "temp") + interp.w_active_context().as_methodcontext_get_shadow(space).settemp(2, "temp") interp.step() interp.step() interp.step() - assert interp.w_active_context.stack == ["foo", "bar", "temp"] + assert interp.s_active_context().stack() == ["foo", "bar", "temp"] def test_pushLiteralConstantBytecode(bytecode=pushLiteralConstantBytecode(0) + pushLiteralConstantBytecode(1) + pushLiteralConstantBytecode(2)): interp = new_interpreter(bytecode) - interp.w_active_context.w_method().literals = fakeliterals("a", "b", "c") + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, "a", "b", "c") interp.step() interp.step() interp.step() - assert interp.w_active_context.stack == [fakesymbol("a"), + assert interp.s_active_context().stack() == [fakesymbol("a"), fakesymbol("b"), fakesymbol("c")] def test_pushLiteralVariableBytecode(bytecode=pushLiteralVariableBytecode(0)): - w_association = mockclass(2).as_class_get_shadow().new() - w_association.store(0, "mykey") - w_association.store(1, "myvalue") + w_association = mockclass(space, 2).as_class_get_shadow(space).new() + w_association.store(space, 0, "mykey") + w_association.store(space, 1, "myvalue") interp = new_interpreter(bytecode) - interp.w_active_context.w_method().literals = fakeliterals(w_association) + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, w_association) interp.step() - assert interp.w_active_context.stack == ["myvalue"] + assert interp.s_active_context().stack() == ["myvalue"] def test_storeAndPopReceiverVariableBytecode(bytecode=storeAndPopReceiverVariableBytecode, popped=True): - shadow = mockclass(8).as_class_get_shadow() + shadow = mockclass(space, 8).as_class_get_shadow(space) for index in range(8): w_object = shadow.new() interp = new_interpreter(pushConstantTrueBytecode + bytecode(index)) - interp.w_active_context.w_receiver = w_object + interp.w_active_context().as_methodcontext_get_shadow(space).store_w_receiver(w_object) interp.step() interp.step() if popped: - assert interp.w_active_context.stack == [] + assert interp.s_active_context().stack() == [] else: - assert interp.w_active_context.stack == [interp.TRUE] + assert interp.s_active_context().stack() == [space.w_true] for test_index in range(8): if test_index == index: - assert w_object.fetch(test_index) == interp.TRUE + assert w_object.fetch(space, test_index).is_same_object(space.w_true) else: - assert w_object.fetch(test_index) is objtable.w_nil + assert w_object.fetch(space, test_index) is space.w_nil def test_storeAndPopTemporaryVariableBytecode(bytecode=storeAndPopTemporaryVariableBytecode): for index in range(8): interp = new_interpreter(pushConstantTrueBytecode + bytecode(index)) - interp.w_active_context.temps = [None] * 8 + #interp.w_active_context().as_methodcontext_get_shadow(space).temps = [None] * 8 interp.step() interp.step() - assert interp.w_active_context.stack == [] + assert interp.s_active_context().stack() == [] + interp.w_active_context().as_methodcontext_get_shadow(space) for test_index in range(8): + print interp.w_active_context()._vars if test_index == index: - assert interp.w_active_context.temps[test_index] == interp.TRUE + assert interp.s_active_context().gettemp(test_index) == space.w_true else: - assert interp.w_active_context.temps[test_index] == None + assert interp.s_active_context().gettemp(test_index) != space.w_true def test_pushConstantTrueBytecode(): interp = new_interpreter(pushConstantTrueBytecode) interp.step() - assert interp.w_active_context.pop() == interp.TRUE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_true) + assert interp.s_active_context().stack() == [] def test_pushConstantFalseBytecode(): interp = new_interpreter(pushConstantFalseBytecode) interp.step() - assert interp.w_active_context.pop() == interp.FALSE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_false) + assert interp.s_active_context().stack() == [] def test_pushConstantNilBytecode(): interp = new_interpreter(pushConstantNilBytecode) interp.step() - assert interp.w_active_context.pop() == interp.NIL - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_nil) + assert interp.s_active_context().stack() == [] def test_pushConstantMinusOneBytecode(): interp = new_interpreter(pushConstantMinusOneBytecode) interp.step() - assert interp.w_active_context.pop() == interp.MINUS_ONE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_minus_one) + assert interp.s_active_context().stack() == [] def test_pushConstantZeroBytecode(): interp = new_interpreter(pushConstantZeroBytecode) interp.step() - assert interp.w_active_context.pop() == interp.ZERO - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_zero) + assert interp.s_active_context().stack() == [] def test_pushConstantOneBytecode(): interp = new_interpreter(pushConstantOneBytecode) interp.step() - assert interp.w_active_context.pop() == interp.ONE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_one) + assert interp.s_active_context().stack() == [] def test_pushConstantTwoBytecode(): interp = new_interpreter(pushConstantTwoBytecode) interp.step() - assert interp.w_active_context.pop() == interp.TWO - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().is_same_object(space.w_two) + assert interp.s_active_context().stack() == [] def test_pushActiveContextBytecode(): interp = new_interpreter(pushActiveContextBytecode) interp.step() - assert interp.w_active_context.pop() == interp.w_active_context - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop() == interp.w_active_context() + assert interp.s_active_context().stack() == [] def test_duplicateTopBytecode(): interp = new_interpreter(pushConstantZeroBytecode + duplicateTopBytecode) interp.step() interp.step() - assert interp.w_active_context.stack == [interp.ZERO, interp.ZERO] + assert interp.s_active_context().stack() == [space.w_zero, space.w_zero] def test_bytecodePrimBitAnd(): interp = new_interpreter(pushConstantOneBytecode + pushConstantTwoBytecode + bytecodePrimBitAnd) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == 0 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == 0 + assert interp.s_active_context().stack() == [] def test_bytecodePrimBitOr(): interp = new_interpreter(pushConstantOneBytecode + pushConstantTwoBytecode + bytecodePrimBitOr) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == 3 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == 3 + assert interp.s_active_context().stack() == [] def test_bytecodePrimBitShift(): interp = new_interpreter(pushConstantOneBytecode + pushConstantTwoBytecode + bytecodePrimBitShift) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == 4 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == 4 + assert interp.s_active_context().stack() == [] def test_bytecodePrimClass(): interp = new_interpreter(pushConstantOneBytecode + bytecodePrimClass) interp.step() interp.step() - assert interp.w_active_context.pop() == classtable.w_SmallInteger - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop() == space.w_SmallInteger + assert interp.s_active_context().stack() == [] def test_bytecodePrimSubtract(): interp = new_interpreter(pushConstantOneBytecode + pushConstantTwoBytecode + bytecodePrimSubtract) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == -1 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == -1 + assert interp.s_active_context().stack() == [] def test_bytecodePrimMultiply(): interp = new_interpreter(pushConstantMinusOneBytecode + pushConstantTwoBytecode + bytecodePrimMultiply) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == -2 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == -2 + assert interp.s_active_context().stack() == [] def test_bytecodePrimDivide(): interp = new_interpreter(pushConstantTwoBytecode + pushConstantMinusOneBytecode + bytecodePrimDivide) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == -2 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == -2 + assert interp.s_active_context().stack() == [] def test_bytecodePrimDiv(): interp = new_interpreter(pushConstantTwoBytecode + pushConstantMinusOneBytecode + bytecodePrimDiv) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == -2 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == -2 + assert interp.s_active_context().stack() == [] def test_bytecodePrimMod(): interp = new_interpreter(pushConstantTwoBytecode + pushConstantMinusOneBytecode + bytecodePrimMod) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop().value == 0 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == 0 + assert interp.s_active_context().stack() == [] def test_bytecodePrimEquivalent(): interp = new_interpreter(pushConstantTwoBytecode + pushConstantMinusOneBytecode + bytecodePrimEquivalent) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop() == interpreter.Interpreter.FALSE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop() == space.w_false + assert interp.s_active_context().stack() == [] interp = new_interpreter(pushConstantOneBytecode + pushConstantOneBytecode + bytecodePrimEquivalent) interp.step() interp.step() interp.step() - assert interp.w_active_context.pop() == interpreter.Interpreter.TRUE - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop() == space.w_true + assert interp.s_active_context().stack() == [] def test_bytecodePrimNew(): - w_fakeclassclass = mockclass(10, name='fakeclassclass') - w_fakeclass = mockclass(1, name='fakeclass', varsized=False, + w_fakeclassclass = mockclass(space, 10, name='fakeclassclass') + w_fakeclass = mockclass(space, 1, name='fakeclass', varsized=False, w_metaclass=w_fakeclassclass) interp = new_interpreter(bytecodePrimNew) - interp.w_active_context.push(w_fakeclass) + interp.s_active_context().push(w_fakeclass) run_with_faked_methods( [[w_fakeclassclass, primitives.NEW, 0, "new"]], interp.step) - w_fakeinst = interp.w_active_context.pop() - assert interp.w_active_context.stack == [] - assert w_fakeinst.getclass() == w_fakeclass + w_fakeinst = interp.s_active_context().pop() + assert interp.s_active_context().stack() == [] + assert w_fakeinst.getclass(space).is_same_object(w_fakeclass) assert w_fakeinst.size() == 1 def test_bytecodePrimNewWithArg(): - w_fakeclassclass = mockclass(10, name='fakeclassclass') - w_fakeclass = mockclass(1, name='fakeclass', varsized=True, + w_fakeclassclass = mockclass(space, 10, name='fakeclassclass') + w_fakeclass = mockclass(space, 1, name='fakeclass', varsized=True, w_metaclass=w_fakeclassclass) interp = new_interpreter(bytecodePrimNewWithArg) - interp.w_active_context.push(w_fakeclass) - interp.w_active_context.push(interpreter.Interpreter.TWO) + interp.s_active_context().push(w_fakeclass) + interp.s_active_context().push(space.w_two) run_with_faked_methods( [[w_fakeclassclass, primitives.NEW_WITH_ARG, 1, "new:"]], interp.step) - w_fakeinst = interp.w_active_context.pop() - assert interp.w_active_context.stack == [] - assert w_fakeinst.getclass() == w_fakeclass + w_fakeinst = interp.s_active_context().pop() + assert interp.s_active_context().stack() == [] + assert w_fakeinst.getclass(space).is_same_object(w_fakeclass) assert w_fakeinst.size() == 3 def test_bytecodePrimSize(): - w_fakeclass = mockclass(2, name='fakeclass', varsized=True) - w_fakeinst = w_fakeclass.as_class_get_shadow().new(5) + w_fakeclass = mockclass(space, 2, name='fakeclass', varsized=True) + w_fakeinst = w_fakeclass.as_class_get_shadow(space).new(5) interp = new_interpreter(bytecodePrimSize) - interp.w_active_context.push(w_fakeinst) + interp.s_active_context().push(w_fakeinst) run_with_faked_methods( [[w_fakeclass, primitives.SIZE, 0, "size"]], interp.step) - assert interp.w_active_context.pop().value == 5 - assert interp.w_active_context.stack == [] + assert interp.s_active_context().pop().value == 5 + assert interp.s_active_context().stack() == [] # w_class - the class from which the method is going to be called # (and on which it is going to be installed) @@ -381,124 +389,138 @@ # bytecodes - the bytecode to be executed def sendBytecodesTest(w_class, w_object, bytecodes): for bytecode, result in [ (returnReceiver, w_object), - (returnTrue, interpreter.Interpreter.TRUE), - (returnFalse, interpreter.Interpreter.FALSE), - (returnNil, interpreter.Interpreter.NIL), - (returnTopFromMethod, interpreter.Interpreter.ONE) ]: - shadow = w_class.as_class_get_shadow() + (returnTrue, space.w_true), + (returnFalse, space.w_false), + (returnNil, space.w_nil), + (returnTopFromMethod, space.w_one) ]: + shadow = w_class.as_class_get_shadow(space) w_method = model.W_CompiledMethod(2) w_method.bytes = pushConstantOneBytecode + bytecode shadow.installmethod("foo", w_method) interp = new_interpreter(bytecodes) - interp.w_active_context.w_method().literals = fakeliterals("foo") - interp.w_active_context.push(w_object) - callerContext = interp.w_active_context - interp.step() - assert interp.w_active_context.w_sender == callerContext - assert interp.w_active_context.stack == [] - assert interp.w_active_context.w_receiver == w_object - assert interp.w_active_context.w_method() == shadow.methoddict["foo"] - assert callerContext.stack == [] + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, "foo") + interp.s_active_context().push(w_object) + callerContext = interp.w_active_context() + interp.step() + assert interp.s_active_context().w_sender() == callerContext + assert interp.s_active_context().stack() == [] + assert interp.w_active_context().as_methodcontext_get_shadow(space).w_receiver().is_same_object(w_object) + assert interp.w_active_context().as_methodcontext_get_shadow(space).w_method().is_same_object(shadow.s_methoddict().methoddict["foo"]) + assert callerContext.as_context_get_shadow(space).stack() == [] interp.step() interp.step() - assert interp.w_active_context == callerContext - assert interp.w_active_context.stack == [result] + assert interp.w_active_context() == callerContext + assert interp.s_active_context().stack() == [result] def test_sendLiteralSelectorBytecode(): - w_class = mockclass(0) - w_object = w_class.as_class_get_shadow().new() + w_class = mockclass(space, 0) + w_object = w_class.as_class_get_shadow(space).new() sendBytecodesTest(w_class, w_object, sendLiteralSelectorBytecode(0)) def test_fibWithArgument(): bytecode = ''.join(map(chr, [ 16, 119, 178, 154, 118, 164, 11, 112, 16, 118, 177, 224, 112, 16, 119, 177, 224, 176, 124 ])) - shadow = mockclass(0).as_class_get_shadow() + shadow = mockclass(space, 0).as_class_get_shadow(space) method = model.W_CompiledMethod(len(bytecode)) method.literalsize = 1 method.bytes = bytecode method.argsize = 1 - method.literals = fakeliterals("fib:") + method.tempsize = 1 + method.literals = fakeliterals(space, "fib:") shadow.installmethod("fib:", method) w_object = shadow.new() interp = new_interpreter(sendLiteralSelectorBytecode(16) + returnTopFromMethod) - interp.w_active_context.w_method().literals = fakeliterals("fib:") - interp.w_active_context.push(w_object) - interp.w_active_context.push(wrap_int(8)) + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, "fib:") + interp.s_active_context().push(w_object) + interp.s_active_context().push(space.wrap_int(8)) result = interp.interpret() - assert unwrap_int(result) == 34 + assert space.unwrap_int(result) == 34 def test_send_to_primitive(): def test(): interp = new_interpreter(sendLiteralSelectorBytecode(1 + 16)) - interp.w_active_context.w_method().literals = fakeliterals("foo", "sub") - interp.w_active_context.push(wrap_int(50)) - interp.w_active_context.push(wrap_int(8)) - callerContext = interp.w_active_context - interp.step() - assert interp.w_active_context is callerContext - assert len(interp.w_active_context.stack) == 1 - w_result = interp.w_active_context.pop() - assert unwrap_int(w_result) == 42 + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, "foo", "sub") + interp.s_active_context().push(space.wrap_int(50)) + interp.s_active_context().push(space.wrap_int(8)) + callerContext = interp.w_active_context() + interp.step() + assert interp.w_active_context() is callerContext + assert len(interp.s_active_context().stack()) == 1 + w_result = interp.s_active_context().pop() + assert space.unwrap_int(w_result) == 42 run_with_faked_methods( - [[classtable.w_SmallInteger, primitives.SUBTRACT, + [[space.w_SmallInteger, primitives.SUBTRACT, 1, "sub"]], test) +def test_makePoint(): + interp = new_interpreter(pushConstantZeroBytecode + + pushConstantOneBytecode + + bytecodePrimMakePoint) + interp.step() + interp.step() + interp.step() + w_point = interp.s_active_context().top() + from pypy.lang.smalltalk.wrapper import PointWrapper + point = PointWrapper(interp.space, w_point) + assert point.x(interp.space) == 0 + assert point.y(interp.space) == 1 + def test_longJumpIfTrue(): interp = new_interpreter(longJumpIfTrue(0) + chr(15) + longJumpIfTrue(0) + chr(15)) - interp.w_active_context.push(interp.FALSE) - pc = interp.w_active_context.pc + 2 + interp.s_active_context().push(space.w_false) + pc = interp.s_active_context().pc() + 2 interp.step() - assert interp.w_active_context.pc == pc - interp.w_active_context.push(interp.TRUE) - pc = interp.w_active_context.pc + 2 + assert interp.s_active_context().pc() == pc + interp.s_active_context().push(space.w_true) + pc = interp.s_active_context().pc() + 2 interp.step() - assert interp.w_active_context.pc == pc + 15 + assert interp.s_active_context().pc() == pc + 15 def test_longJumpIfFalse(): interp = new_interpreter(pushConstantTrueBytecode + longJumpIfFalse(0) + chr(15) + pushConstantFalseBytecode + longJumpIfFalse(0) + chr(15)) interp.step() - pc = interp.w_active_context.pc + 2 + pc = interp.s_active_context().pc() + 2 interp.step() - assert interp.w_active_context.pc == pc + assert interp.s_active_context().pc() == pc interp.step() - pc = interp.w_active_context.pc + 2 + pc = interp.s_active_context().pc() + 2 interp.step() - assert interp.w_active_context.pc == pc + 15 + assert interp.s_active_context().pc() == pc + 15 def test_longUnconditionalJump(): interp = new_interpreter(longUnconditionalJump(4) + chr(15)) - pc = interp.w_active_context.pc + 2 + pc = interp.s_active_context().pc() + 2 interp.step() - assert interp.w_active_context.pc == pc + 15 + assert interp.s_active_context().pc() == pc + 15 def test_shortUnconditionalJump(): interp = new_interpreter(chr(145)) - pc = interp.w_active_context.pc + 1 + pc = interp.s_active_context().pc() + 1 interp.step() - assert interp.w_active_context.pc == pc + 2 + assert interp.s_active_context().pc() == pc + 2 def test_shortConditionalJump(): interp = new_interpreter(pushConstantTrueBytecode + shortConditionalJump(3) + pushConstantFalseBytecode + shortConditionalJump(3)) interp.step() - pc = interp.w_active_context.pc + 1 + pc = interp.s_active_context().pc() + 1 interp.step() - assert interp.w_active_context.pc == pc + assert interp.s_active_context().pc() == pc interp.step() - pc = interp.w_active_context.pc + 1 + pc = interp.s_active_context().pc() + 1 interp.step() - assert interp.w_active_context.pc == pc + 4 + assert interp.s_active_context().pc() == pc + 4 def test_popStackBytecode(): interp = new_interpreter(pushConstantTrueBytecode + popStackBytecode) interp.step() - assert interp.w_active_context.stack == [interp.TRUE] + assert interp.s_active_context().stack() == [space.w_true] interp.step() - assert interp.w_active_context.stack == [] + assert interp.s_active_context().stack() == [] def test_extendedPushBytecode(): test_pushReceiverVariableBytecode(extendedPushBytecode + chr((0<<6) + 0) + @@ -516,14 +538,14 @@ test_pushLiteralVariableBytecode(extendedPushBytecode + chr((3<<6) + 0)) def storeAssociation(bytecode): - w_association = mockclass(2).as_class_get_shadow().new() - w_association.store(0, "mykey") - w_association.store(1, "myvalue") + w_association = mockclass(space, 2).as_class_get_shadow(space).new() + w_association.store(space, 0, "mykey") + w_association.store(space, 1, "myvalue") interp = new_interpreter(pushConstantOneBytecode + bytecode) - interp.w_active_context.w_method().literals = fakeliterals(w_association) + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, w_association) interp.step() interp.step() - assert w_association.fetch(1) == interp.ONE + assert w_association.fetch(space, 1).is_same_object(space.w_one) def test_extendedStoreAndPopBytecode(): test_storeAndPopReceiverVariableBytecode(lambda index: extendedStoreAndPopBytecode + chr((0<<6) + index)) @@ -538,20 +560,21 @@ def test_callPrimitiveAndPush_fallback(): interp = new_interpreter(bytecodePrimAdd) - shadow = mockclass(0).as_class_get_shadow() + shadow = mockclass(space, 0).as_class_get_shadow(space) w_method = model.W_CompiledMethod(0) w_method.argsize = 1 + w_method.tempsize = 1 w_method.literalsize = 1 shadow.installmethod("+", w_method) w_object = shadow.new() - interp.w_active_context.push(w_object) - interp.w_active_context.push(interp.ONE) + interp.s_active_context().push(w_object) + interp.s_active_context().push(space.w_one) interp.step() - assert interp.w_active_context.w_method() == shadow.methoddict["+"] - assert interp.w_active_context.w_receiver is w_object - assert interp.w_active_context.gettemp(0) == interp.ONE - assert interp.w_active_context.stack == [] + assert interp.w_active_context().as_methodcontext_get_shadow(space).w_method() == shadow.s_methoddict().methoddict["+"] + assert interp.s_active_context().w_receiver() is w_object + assert interp.w_active_context().as_methodcontext_get_shadow(space).gettemp(0).is_same_object(space.w_one) + assert interp.s_active_context().stack() == [] def test_bytecodePrimBool(): interp = new_interpreter(bytecodePrimLessThan + @@ -561,60 +584,60 @@ bytecodePrimEqual + bytecodePrimNotEqual) for i in range(6): - interp.w_active_context.push(interp.ONE) - interp.w_active_context.push(interp.TWO) + interp.s_active_context().push(space.w_one) + interp.s_active_context().push(space.w_two) interp.step() - assert interp.w_active_context.stack == [interp.TRUE, interp.FALSE, - interp.TRUE, interp.FALSE, - interp.FALSE, interp.TRUE] + assert interp.s_active_context().stack() == [space.w_true, space.w_false, + space.w_true, space.w_false, + space.w_false, space.w_true] def test_singleExtendedSendBytecode(): - w_class = mockclass(0) - w_object = w_class.as_class_get_shadow().new() + w_class = mockclass(space, 0) + w_object = w_class.as_class_get_shadow(space).new() sendBytecodesTest(w_class, w_object, singleExtendedSendBytecode + chr((0<<5)+0)) def test_singleExtendedSuperBytecode(bytecode=singleExtendedSuperBytecode + chr((0<<5) + 0)): - w_supersuper = mockclass(0) - w_super = mockclass(0, w_superclass=w_supersuper) - w_class = mockclass(0, w_superclass=w_super) - w_object = w_class.as_class_get_shadow().new() + w_supersuper = mockclass(space, 0) + w_super = mockclass(space, 0, w_superclass=w_supersuper) + w_class = mockclass(space, 0, w_superclass=w_super) + w_object = w_class.as_class_get_shadow(space).new() # first call method installed in w_class bytecodes = singleExtendedSendBytecode + chr(0) # which does a call to its super meth1 = model.W_CompiledMethod(2) meth1.bytes = pushReceiverBytecode + bytecode - w_class.as_class_get_shadow().installmethod("foo", meth1) + w_class.as_class_get_shadow(space).installmethod("foo", meth1) # and that one again to its super meth2 = model.W_CompiledMethod(2) meth2.bytes = pushReceiverBytecode + bytecode - w_super.as_class_get_shadow().installmethod("foo", meth2) + w_super.as_class_get_shadow(space).installmethod("foo", meth2) meth3 = model.W_CompiledMethod(0) - w_supersuper.as_class_get_shadow().installmethod("foo", meth3) - meth1.literals = fakeliterals("foo") - meth2.literals = fakeliterals("foo") + w_supersuper.as_class_get_shadow(space).installmethod("foo", meth3) + meth1.literals = fakeliterals(space, "foo") + meth2.literals = fakeliterals(space, "foo") interp = new_interpreter(bytecodes) - interp.w_active_context.w_method().literals = fakeliterals("foo") - interp.w_active_context.push(w_object) + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = fakeliterals(space, "foo") + interp.s_active_context().push(w_object) interp.step() for w_specificclass in [w_super, w_supersuper]: - callerContext = interp.w_active_context + callerContext = interp.w_active_context() interp.step() interp.step() - assert interp.w_active_context.w_sender == callerContext - assert interp.w_active_context.stack == [] - assert interp.w_active_context.w_receiver == w_object - meth = w_specificclass.as_class_get_shadow().methoddict["foo"] - assert interp.w_active_context.w_method() == meth - assert callerContext.stack == [] + assert interp.s_active_context().w_sender() == callerContext + assert interp.s_active_context().stack() == [] + assert interp.w_active_context().as_methodcontext_get_shadow(space).w_receiver() == w_object + meth = w_specificclass.as_class_get_shadow(space).s_methoddict().methoddict["foo"] + assert interp.w_active_context().as_methodcontext_get_shadow(space).w_method() == meth + assert callerContext.as_context_get_shadow(space).stack() == [] def test_secondExtendedSendBytecode(): - w_class = mockclass(0) - w_object = w_class.as_class_get_shadow().new() + w_class = mockclass(space, 0) + w_object = w_class.as_class_get_shadow(space).new() sendBytecodesTest(w_class, w_object, secondExtendedSendBytecode + chr(0)) def test_doubleExtendedDoAnythinBytecode(): - w_class = mockclass(0) - w_object = w_class.as_class_get_shadow().new() + w_class = mockclass(space, 0) + w_object = w_class.as_class_get_shadow(space).new() sendBytecodesTest(w_class, w_object, doubleExtendedDoAnythingBytecode + chr((0<<5) + 0) + chr(0)) @@ -636,10 +659,10 @@ storeAssociation(doubleExtendedDoAnythingBytecode + chr(7<<5) + chr(0)) -def interpret_bc(bcodes, literals, receiver=objtable.w_nil): +def interpret_bc(bcodes, literals, receiver=space.w_nil): bcode = "".join([chr(x) for x in bcodes]) interp = new_interpreter(bcode, receiver=receiver) - interp.w_active_context.w_method().literals = literals + interp.w_active_context().as_methodcontext_get_shadow(space).w_method().literals = literals return interp.interpret() # tests: bytecodePrimValue & bytecodePrimValueWithArg @@ -651,7 +674,7 @@ # ^ [ 3 + 4 ] value assert interpret_bc( [ 137, 117, 200, 164, 4, 32, 33, 176, 125, 201, 124], - fakeliterals(wrap_int(3), wrap_int(4))).value == 7 + fakeliterals(space, space.wrap_int(3), space.wrap_int(4))).value == 7 def test_bc_x_plus_x_plus_1(): @@ -663,7 +686,7 @@ assert interpret_bc( [ 137, 118, 200, 164, 7, 104, 16, 16, 176, 118, 176, 125, 32, 202, 124 ], - fakeliterals(wrap_int(3))).value == 7 + fakeliterals(space, space.wrap_int(3))).value == 7 def test_bc_x_plus_y(): # value2 @@ -676,9 +699,9 @@ assert interpret_bc( [ 137, 119, 200, 164, 6, 105, 104, 16, 17, 176, 125, 33, 34, 240, 124 ], - fakeliterals("value:value:", wrap_int(3), wrap_int(4))).value == 7 + fakeliterals(space, "value:value:", space.wrap_int(3), space.wrap_int(4))).value == 7 run_with_faked_methods( - [[classtable.w_BlockContext, primitives.PRIMITIVE_VALUE, + [[space.w_BlockContext, primitives.PRIMITIVE_VALUE, 2, "value:value:"]], test) @@ -690,7 +713,7 @@ # ^ [ self ] value assert interpret_bc( [ 137, 117, 200, 164, 2, 112, 125, 201, 124 ], - fakeliterals(wrap_int(3))) is objtable.w_nil + fakeliterals(space, space.wrap_int(3))) is space.w_nil def test_bc_value_return(): # valueReturn @@ -700,7 +723,7 @@ # [ ^ 1 ] value. ^ 2 assert interpret_bc( [ 137, 117, 200, 164, 2, 118, 124, 201, 135, 119, 124 ], - fakeliterals()).value == 1 + fakeliterals(space, )).value == 1 def test_bc_value_with_args(): # valueWithArgs @@ -713,10 +736,10 @@ [ 137, 119, 200, 164, 6, 105, 104, 16, 17, 177, 125, 33, 224, 124 ], - fakeliterals("valueWithArguments:", + fakeliterals(space, "valueWithArguments:", [3, 2])).value == 1 run_with_faked_methods( - [[classtable.w_BlockContext, primitives.PRIMITIVE_VALUE_WITH_ARGS, + [[space.w_BlockContext, primitives.PRIMITIVE_VALUE_WITH_ARGS, 1, "valueWithArguments:"]], test) @@ -725,9 +748,9 @@ def test(): assert interpret_bc( [ 32, 118, 192, 124], - fakeliterals("a")) == wrap_char("a") + fakeliterals(space, "a")) == space.wrap_char("a") run_with_faked_methods( - [[classtable.w_String, primitives.STRING_AT, 1, "at:"]], + [[space.w_String, primitives.STRING_AT, 1, "at:"]], test) def test_bc_primBytecodeAtPut_string(): @@ -735,22 +758,21 @@ def test(): assert interpret_bc( [ 32, 118, 33, 193, 124 ], - fakeliterals("a", wrap_char("b"))) == wrap_char("b") + fakeliterals(space, "a", space.wrap_char("b"))) == space.wrap_char("b") run_with_faked_methods( - [[classtable.w_String, primitives.STRING_AT_PUT, 2, "at:put:"]], + [[space.w_String, primitives.STRING_AT_PUT, 2, "at:put:"]], test) def test_bc_primBytecodeAt_with_instvars(): # ^ self at: 1 - py.test.skip("Broken, fix me") - w_fakeclass = mockclass(1, name='fakeclass', varsized=True) - w_fakeinst = w_fakeclass.as_class_get_shadow().new(1) - w_fakeinst.store(0, wrap_char("a")) # static slot 0: instance variable - w_fakeinst.store(1, wrap_char("b")) # varying slot 1 + w_fakeclass = mockclass(space, 1, name='fakeclass', varsized=True) + w_fakeinst = w_fakeclass.as_class_get_shadow(space).new(1) + w_fakeinst.store(space, 0, space.wrap_char("a")) # static slot 0: instance variable + w_fakeinst.store(space, 1, space.wrap_char("b")) # varying slot 1 def test(): - assert utility.unwrap_char(interpret_bc( + assert space.unwrap_char(interpret_bc( [112, 118, 192, 124], - fakeliterals(), + fakeliterals(space, ), receiver=w_fakeinst)) == "b" run_with_faked_methods( [[w_fakeclass, primitives.AT, 1, "at:"]], @@ -758,18 +780,17 @@ def test_bc_primBytecodeAtPut_with_instvars(): # ^ self at: 1 put: #b - py.test.skip("Broken, fix me") - w_fakeclass = mockclass(1, name='fakeclass', varsized=True) - w_fakeinst = w_fakeclass.as_class_get_shadow().new(1) - w_fakeinst.store(0, wrap_char("a")) # static slot 0: instance variable - w_fakeinst.store(1, wrap_char("a")) # varying slot 1 + w_fakeclass = mockclass(space, 1, name='fakeclass', varsized=True) + w_fakeinst = w_fakeclass.as_class_get_shadow(space).new(1) + w_fakeinst.store(space, 0, space.wrap_char("a")) # static slot 0: instance variable + w_fakeinst.store(space, 1, space.wrap_char("a")) # varying slot 1 def test(): - assert utility.unwrap_char(interpret_bc( + assert space.unwrap_char(interpret_bc( [0x70, 0x76, 0x20, 0xc1, 0x7c], - fakeliterals(wrap_char("b")), + fakeliterals(space, space.wrap_char("b")), receiver=w_fakeinst)) == "b" - assert utility.unwrap_char(w_fakeinst.fetch(0)) == "a" - assert utility.unwrap_char(w_fakeinst.fetch(1)) == "b" + assert space.unwrap_char(w_fakeinst.fetch(space, 0)) == "a" + assert space.unwrap_char(w_fakeinst.fetch(space, 1)) == "b" run_with_faked_methods( [[w_fakeclass, primitives.AT_PUT, 2, "at:put:"]], test) @@ -779,15 +800,13 @@ # ^ self objectAt: 2. yields the first literal (22) # ^ self objectAt: 2 put: 3. changes the first literal to 3 # ^ self objectAt: 2. yields the new first literal (3) - py.test.skip("Broken, fix me") - prim_meth = model.W_CompiledMethod(0) - prim_meth.literals = fakeliterals(22) - mhs = fakesymbol("methodheader") - oal = fakeliterals("objectAt:") - oalp = fakeliterals("objectAt:put:", 3) + prim_meth = model.W_CompiledMethod(header=1024) + prim_meth.literals = fakeliterals(space, 22) + oal = fakeliterals(space, "objectAt:") + oalp = fakeliterals(space, "objectAt:put:", 3) def test(): assert interpret_bc( - [112, 118, 224, 124], oal, receiver=prim_meth) == mhs + [112, 118, 224, 124], oal, receiver=prim_meth).value == 1024 assert interpret_bc( [112, 119, 224, 124], oal, receiver=prim_meth).value == 22 assert interpret_bc( @@ -795,6 +814,15 @@ assert interpret_bc( [112, 119, 224, 124], oal, receiver=prim_meth).value == 3 run_with_faked_methods( - [[classtable.w_CompiledMethod, primitives.OBJECT_AT, 1, "objectAt:"], - [classtable.w_CompiledMethod, primitives.OBJECT_AT_PUT, 2, "objectAt:put:"]], + [[space.w_CompiledMethod, primitives.OBJECT_AT, 1, "objectAt:"], + [space.w_CompiledMethod, primitives.OBJECT_AT_PUT, 2, "objectAt:put:"]], test) + +def test_runwithtrace(): + # We run random tests with the bc_trace option turned on explicitely + from pypy.lang.smalltalk.conftest import option + bc_trace = option.bc_trace + option.bc_trace = True + test_storeAndPopReceiverVariableBytecode() + test_bc_objectAtAndAtPut() + option.bc_trace = bc_trace Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_miniimage.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_miniimage.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_miniimage.py Tue Jun 10 12:48:46 2008 @@ -6,24 +6,21 @@ from pypy.lang.smalltalk import model from pypy.lang.smalltalk import constants from pypy.lang.smalltalk import interpreter -from pypy.lang.smalltalk import objtable -from pypy.lang.smalltalk import classtable from pypy.lang.smalltalk import shadow -from pypy.lang.smalltalk import utility +from pypy.lang.smalltalk import objspace # lazy initialization of test data, ie ImageReader and Float class -def setup_module(module): - global mini_image - global reader - global image - mini_image = py.magic.autopath().dirpath().dirpath().join('mini.image') - reader = open_miniimage() +def setup_module(module, filename='mini.image'): + space = objspace.ObjSpace() + module.mini_image = py.magic.autopath().dirpath().dirpath().join(filename) + module.reader = open_miniimage(space) reader.initialize() - image = squeakimage.SqueakImage() - image.from_reader(get_reader()) + module.image = squeakimage.SqueakImage() + module.image.from_reader(space, get_reader()) + module.space = space -def open_miniimage(): - return squeakimage.ImageReader(squeakimage.Stream(mini_image.open())) +def open_miniimage(space): + return squeakimage.ImageReader(space, squeakimage.Stream(mini_image.open())) def get_reader(): return reader @@ -41,26 +38,19 @@ assert mini_image.check(dir=False) def test_read_header(): - reader = open_miniimage() + reader = open_miniimage(space) reader.read_header() assert reader.endofmemory == 0x93174 assert reader.oldbaseaddress == 0x6649000 assert reader.specialobjectspointer == 0x6668380 def test_read_all_header(): - reader = open_miniimage() + reader = open_miniimage(space) reader.read_header() next = reader.stream.peek() assert next != 0 #expects object header, which must not be 0x00000000 - -def test_number_of_objects(): - image = get_image() - objects = image.objects - assert len(objects) > 0 - assert 15000 < len(objects) < 16000 - def test_all_pointers_are_valid(): reader = get_reader() for each in reader.chunks.itervalues(): @@ -74,42 +64,44 @@ reader = get_reader() assert len(reader.compactclasses) == 31 -def test_invariant(): - image = get_image() - for each in image.objects: - each.invariant() - def test_float_class_size(): w_float_class = get_float_class() assert w_float_class.size() == 9 def test_float_class_name(): w_float_class = get_float_class() - w_float_class_name = w_float_class.fetch(6) + w_float_class_name = w_float_class.fetch(space, 6) assert isinstance(w_float_class_name, model.W_BytesObject) assert w_float_class_name.bytes == list("Float") def test_str_w_object(): w_float_class = get_float_class() + w_float_class.as_class_get_shadow(space) assert str(w_float_class) == "Float class" - assert str(w_float_class.getclass()) == "a Metaclass" #yes, with article - assert str(w_float_class.getclass().getclass()) == "Metaclass class" + w_float_class.shadow_of_my_class(space) + #assert str(w_float_class.getclass(space)) == "a Metaclass" #yes, with article + w_float_class.getclass(space).shadow_of_my_class(space) + #assert str(w_float_class.getclass(space).getclass(space)) == "Metaclass class" def test_nil_true_false(): image = get_image() w = image.special(constants.SO_NIL) + w.shadow_of_my_class(space) assert str(w) == "a UndefinedObject" #yes, with article w = image.special(constants.SO_FALSE) + w.shadow_of_my_class(space) assert str(w) == "a False" #yes, with article w = image.special(constants.SO_TRUE) + w.shadow_of_my_class(space) assert str(w) == "a True" #yes, with article def test_scheduler(): image = get_image() w = image.special(constants.SO_SCHEDULERASSOCIATIONPOINTER) - w0 = w.fetch(0) + w0 = w.fetch(space, 0) assert str(w0) == "Processor" - w0 = w.fetch(1) + w0 = w.fetch(space, 1) + w0.shadow_of_my_class(space) assert str(w0) == "a ProcessorScheduler" def test_special_classes0(): @@ -146,20 +138,20 @@ def test_name_of_shadow_of_specials(): image = get_image() w_doesnot = image.special(constants.SO_DOES_NOT_UNDERSTAND) - assert repr(w_doesnot.shadow_of_my_class()) == "" - assert repr(objtable.w_nil.shadow_of_my_class()) == "" - assert repr(objtable.w_minus_one.shadow_of_my_class()) == "" - assert repr(objtable.w_zero.shadow_of_my_class()) == "" - assert repr(objtable.w_one.shadow_of_my_class()) == "" - assert repr(objtable.w_two.shadow_of_my_class()) == "" - assert repr(objtable.w_true.shadow_of_my_class()) == "" - assert repr(objtable.w_false.shadow_of_my_class()) == "" + assert repr(w_doesnot.shadow_of_my_class(space)) == "" + assert repr(space.w_nil.shadow_of_my_class(space)) == "" + assert repr(space.w_minus_one.shadow_of_my_class(space)) == "" + assert repr(space.w_zero.shadow_of_my_class(space)) == "" + assert repr(space.w_one.shadow_of_my_class(space)) == "" + assert repr(space.w_two.shadow_of_my_class(space)) == "" + assert repr(space.w_true.shadow_of_my_class(space)) == "" + assert repr(space.w_false.shadow_of_my_class(space)) == "" def test_special_classes0(): image = get_image() w = image.special(constants.SO_DOES_NOT_UNDERSTAND) assert str(w) == "doesNotUnderstand:" - assert str(w.getclass()) == "Symbol class" # for some strange reason not a symbol + assert str(w.getclass(space)) == "Symbol class" # for some strange reason not a symbol """SO_DOES_NOT_UNDERSTAND = 20 @@ -190,25 +182,22 @@ def test_lookup_abs_in_integer(int=10): image = get_image() - interp = interpreter.Interpreter() + interp = interpreter.Interpreter(space) w_object = model.W_SmallInteger(int) # Should get this from w_object w_smallint_class = image.special(constants.SO_SMALLINTEGER_CLASS) - s_class = w_object.shadow_of_my_class() + s_class = w_object.shadow_of_my_class(space) w_method = s_class.lookup("abs") assert w_method - w_frame = w_method.create_frame(w_object, []) - interp.w_active_context = w_frame - - print w_method + w_frame = w_method.create_frame(space, w_object, []) + interp.store_w_active_context(w_frame) while True: try: interp.step() - print interp.w_active_context.stack except interpreter.ReturnFromTopLevel, e: assert e.object.value == abs(int) return @@ -218,52 +207,115 @@ def test_map_mirrors_to_classtable(): w_compiledmethod_class = image.special(constants.SO_COMPILEDMETHOD_CLASS) - assert w_compiledmethod_class is classtable.w_CompiledMethod + assert w_compiledmethod_class.is_same_object(space.w_CompiledMethod) w_nil = image.special(constants.SO_NIL) - assert w_nil is objtable.w_nil + assert w_nil.is_same_object(space.w_nil) w_true = image.special(constants.SO_TRUE) - assert w_true is objtable.w_true + assert w_true.is_same_object(space.w_true) w_false = image.special(constants.SO_FALSE) - assert w_false is objtable.w_false + assert w_false.is_same_object(space.w_false) +def test_runimage(): + py.test.skip("This method actually runs an image. Fails since no graphical primitives yet") + from pypy.lang.smalltalk import wrapper + ap = wrapper.ProcessWraper(wrapper.scheduler().active_process()) + s_ctx = ap.suspended_context().as_methodcontext_get_shadow() + ap.store_suspended_context(space.w_nil) + + interp = interpreter.Interpreter() + interp.store_w_active_context(s_ctx.w_self()) + interp.interpret() + def test_compile_method(): - py.test.skip("Not working yet.") sourcecode = """fib ^self < 2 ifTrue: [ 1 ] ifFalse: [ (self - 1) fib + (self - 2) fib ]""" - perform(w(10).getclass(), "compile:classified:notifying:", w(sourcecode), w('pypy'), w(None)) - assert perform(w(10), "fib") == w(89) + perform(w(10).getclass(space), "compile:classified:notifying:", w(sourcecode), w('pypy'), w(None)) + assert perform(w(10), "fib").is_same_object(w(89)) + def w(any): + # XXX could put this on the space? if any is None: - return objtable.w_nil + return space.w_nil if isinstance(any, str): # assume never have strings of length 1 if len(any) == 1: - return utility.wrap_chr(any) + return space.wrap_chr(any) else: - return utility.wrap_string(any) - if isinstance(any, int): - return utility.wrap_int(any) + return space.wrap_string(any) if isinstance(any, bool): - return utility.wrap_bool(any) + return space.wrap_bool(any) + if isinstance(any, int): + return space.wrap_int(any) if isinstance(any, float): - return utility.wrap_float(any) + return space.wrap_float(any) else: raise Exception - + +def test_become(): + sourcecode = """ + testBecome + | p1 p2 a | + p1 := 1 at 2. + p2 := #(3 4 5). + a := p1 -> p2. + (1 at 2 = a key) ifFalse: [^false]. + (#(3 4 5) = a value) ifFalse: [^false]. + (p1 -> p2 = a) ifFalse: [^false]. + (p1 == a key) ifFalse: [^false]. + (p2 == a value) ifFalse: [^false]. + p1 become: p2. + (1 at 2 = a value) ifFalse: [^false]. + (#(3 4 5) = a key) ifFalse: [^false]. + (p1 -> p2 = a) ifFalse: [^false]. + (p1 == a key) ifFalse: [^false]. + (p2 == a value) ifFalse: [^false]. + + ^true""" + perform(w(10).getclass(space), "compile:classified:notifying:", w(sourcecode), w('pypy'), w(None)) + w_true = w(True) + w_result = perform(w(10), "testBecome") + w_result.is_same_object(w_true) + def perform(w_receiver, selector, *arguments_w): - interp = interpreter.Interpreter() - s_class = w_receiver.shadow_of_my_class() + interp = interpreter.Interpreter(space) + s_class = w_receiver.shadow_of_my_class(space) w_method = s_class.lookup(selector) assert w_method - w_frame = w_method.create_frame(w_receiver, list(arguments_w)) - interp.w_active_context = w_frame + w_frame = w_method.create_frame(space, w_receiver, list(arguments_w)) + interp.store_w_active_context(w_frame) while True: try: interp.step() - #print interp.w_active_context.stack + #print interp.s_active_context.stack except interpreter.ReturnFromTopLevel, e: - return e.object.value - + return e.object + +def test_step_forged_image(): + from pypy.lang.smalltalk import wrapper + ap = wrapper.ProcessWrapper(space, wrapper.scheduler(space).active_process()) + s_ctx = ap.suspended_context().as_context_get_shadow(space) + assert isinstance(s_ctx, shadow.MethodContextShadow) + assert s_ctx.top().is_same_object(space.w_true) + +def test_step_run_something(): + from pypy.lang.smalltalk.test import test_miniimage + setup_module(test_miniimage, filename='running-something-mini.image') + from pypy.lang.smalltalk import wrapper + ap = wrapper.ProcessWrapper(space, wrapper.scheduler(space).active_process()) + s_ctx = ap.suspended_context().as_context_get_shadow(space) + ap.store_suspended_context(space.w_nil) + + interp = interpreter.Interpreter(space) + interp.store_w_active_context(s_ctx.w_self()) + assert isinstance(s_ctx, shadow.MethodContextShadow) + assert interp.s_active_context().top().is_same_object(space.w_true) + interp.step() + interp.step() + assert interp.s_active_context().top().value == 1 + interp.step() + assert interp.s_active_context().top().value == 2 + interp.step() + assert interp.s_active_context().top().value == 3 Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_model.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_model.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_model.py Tue Jun 10 12:48:46 2008 @@ -1,33 +1,43 @@ import py -from pypy.lang.smalltalk import model, shadow, objtable +from pypy.lang.smalltalk import model, shadow from pypy.lang.smalltalk.shadow import MethodNotFound -from pypy.lang.smalltalk import classtable +from pypy.lang.smalltalk import objspace + +mockclass = objspace.bootstrap_class + +space = objspace.ObjSpace() + +def joinbits(values, lengths): + result = 0 + for each, length in reversed(zip(values, lengths)): + result = result << length + result += each + return result -mockclass = classtable.bootstrap_class def test_new(): - w_mycls = mockclass(0) - w_myinstance = w_mycls.as_class_get_shadow().new() + w_mycls = mockclass(space, 0) + w_myinstance = w_mycls.as_class_get_shadow(space).new() assert isinstance(w_myinstance, model.W_PointersObject) - assert w_myinstance.getclass() is w_mycls - assert w_myinstance.shadow_of_my_class() is w_mycls.as_class_get_shadow() + assert w_myinstance.getclass(space).is_same_object(w_mycls) + assert w_myinstance.shadow_of_my_class(space) is w_mycls.as_class_get_shadow(space) def test_new_namedvars(): - w_mycls = mockclass(3) - w_myinstance = w_mycls.as_class_get_shadow().new() + w_mycls = mockclass(space, 3) + w_myinstance = w_mycls.as_class_get_shadow(space).new() assert isinstance(w_myinstance, model.W_PointersObject) - assert w_myinstance.getclass() is w_mycls - assert w_myinstance.fetch(0) is objtable.w_nil - py.test.raises(IndexError, lambda: w_myinstance.fetch(3)) - w_myinstance.store(1, w_myinstance) - assert w_myinstance.fetch(1) is w_myinstance + assert w_myinstance.getclass(space).is_same_object(w_mycls) + assert w_myinstance.fetch(space, 0) is space.w_nil + py.test.raises(IndexError, lambda: w_myinstance.fetch(space, 3)) + w_myinstance.store(space, 1, w_myinstance) + assert w_myinstance.fetch(space, 1) is w_myinstance def test_bytes_object(): - w_class = mockclass(0, format=shadow.BYTES) - w_bytes = w_class.as_class_get_shadow().new(20) - assert w_bytes.getclass() is w_class + w_class = mockclass(space, 0, format=shadow.BYTES) + w_bytes = w_class.as_class_get_shadow(space).new(20) + assert w_bytes.getclass(space).is_same_object(w_class) assert w_bytes.size() == 20 - assert w_class.as_class_get_shadow().instsize() == 0 + assert w_class.as_class_get_shadow(space).instsize() == 0 assert w_bytes.getchar(3) == "\x00" w_bytes.setchar(3, "\xAA") assert w_bytes.getchar(3) == "\xAA" @@ -35,11 +45,11 @@ py.test.raises(IndexError, lambda: w_bytes.getchar(20)) def test_word_object(): - w_class = mockclass(0, format=shadow.WORDS) - w_bytes = w_class.as_class_get_shadow().new(20) - assert w_bytes.getclass() is w_class + w_class = mockclass(space, 0, format=shadow.WORDS) + w_bytes = w_class.as_class_get_shadow(space).new(20) + assert w_bytes.getclass(space).is_same_object(w_class) assert w_bytes.size() == 20 - assert w_class.as_class_get_shadow().instsize() == 0 + assert w_class.as_class_get_shadow(space).instsize() == 0 assert w_bytes.getword(3) == 0 w_bytes.setword(3, 42) assert w_bytes.getword(3) == 42 @@ -47,14 +57,16 @@ py.test.raises(IndexError, lambda: w_bytes.getword(20)) def test_method_lookup(): - w_class = mockclass(0) - shadow = w_class.as_class_get_shadow() - shadow.methoddict["foo"] = 1 - shadow.methoddict["bar"] = 2 - w_subclass = mockclass(0, w_superclass=w_class) - subshadow = w_subclass.as_class_get_shadow() - assert subshadow.s_superclass is shadow - subshadow.methoddict["foo"] = 3 + w_class = mockclass(space, 0) + shadow = w_class.as_class_get_shadow(space) + shadow.installmethod("foo", 1) + shadow.installmethod("bar", 2) + w_subclass = mockclass(space, 0, w_superclass=w_class) + subshadow = w_subclass.as_class_get_shadow(space) + assert subshadow.s_superclass() is shadow + subshadow.installmethod("foo", 3) + shadow.initialize_methoddict() + subshadow.initialize_methoddict() assert shadow.lookup("foo") == 1 assert shadow.lookup("bar") == 2 py.test.raises(MethodNotFound, shadow.lookup, "zork") @@ -63,11 +75,12 @@ py.test.raises(MethodNotFound, subshadow.lookup, "zork") def test_w_compiledin(): - w_super = mockclass(0) - w_class = mockclass(0, w_superclass=w_super) - supershadow = w_super.as_class_get_shadow() + w_super = mockclass(space, 0) + w_class = mockclass(space, 0, w_superclass=w_super) + supershadow = w_super.as_class_get_shadow(space) supershadow.installmethod("foo", model.W_CompiledMethod(0)) - classshadow = w_class.as_class_get_shadow() + classshadow = w_class.as_class_get_shadow(space) + classshadow.initialize_methoddict() assert classshadow.lookup("foo").w_compiledin is w_super def test_compiledmethod_setchar(): @@ -78,10 +91,133 @@ def test_hashes(): w_five = model.W_SmallInteger(5) assert w_five.gethash() == 5 - w_class = mockclass(0) - w_inst = w_class.as_class_get_shadow().new() + w_class = mockclass(space, 0) + w_inst = w_class.as_class_get_shadow(space).new() assert w_inst.hash == w_inst.UNASSIGNED_HASH h1 = w_inst.gethash() h2 = w_inst.gethash() assert h1 == h2 assert h1 == w_inst.hash + +def test_compiledmethod_at0(): + w_method = model.W_CompiledMethod() + w_method.bytes = "abc" + w_method.header = 100 + w_method.literals = [ 'lit1', 'lit2' ] + w_method.literalsize = 2 + assert space.unwrap_int(w_method.at0(space, 0)) == 100 + assert w_method.at0(space, 4) == 'lit1' + assert w_method.at0(space, 8) == 'lit2' + assert space.unwrap_int(w_method.at0(space, 12)) == ord('a') + assert space.unwrap_int(w_method.at0(space, 13)) == ord('b') + assert space.unwrap_int(w_method.at0(space, 14)) == ord('c') + +def test_compiledmethod_atput0(): + w_method = model.W_CompiledMethod(3) + newheader = joinbits([0,2,0,0,0,0],[9,8,1,6,4,1]) + assert w_method.getliteralsize() == 0 + w_method.atput0(space, 0, space.wrap_int(newheader)) + assert w_method.getliteralsize() == 8 # 2 from new header * BYTES_PER_WORD (= 4) + w_method.atput0(space, 4, 'lit1') + w_method.atput0(space, 8, 'lit2') + w_method.atput0(space, 12, space.wrap_int(ord('a'))) + w_method.atput0(space, 13, space.wrap_int(ord('b'))) + w_method.atput0(space, 14, space.wrap_int(ord('c'))) + assert space.unwrap_int(w_method.at0(space, 0)) == newheader + assert w_method.at0(space, 4) == 'lit1' + assert w_method.at0(space, 8) == 'lit2' + assert space.unwrap_int(w_method.at0(space, 12)) == ord('a') + assert space.unwrap_int(w_method.at0(space, 13)) == ord('b') + assert space.unwrap_int(w_method.at0(space, 14)) == ord('c') + +def test_is_same_object(w_o1=model.W_PointersObject(None,0), w_o2=None): + if w_o2 is None: + w_o2 = w_o1 + assert w_o1.is_same_object(w_o2) + assert w_o2.is_same_object(w_o1) + +def test_not_is_same_object(w_o1=model.W_PointersObject(None,0),w_o2=model.W_PointersObject(None,0)): + assert not w_o1.is_same_object(w_o2) + assert not w_o2.is_same_object(w_o1) + w_o2 = model.W_SmallInteger(2) + assert not w_o1.is_same_object(w_o2) + assert not w_o2.is_same_object(w_o1) + w_o2 = model.W_Float(5.5) + assert not w_o1.is_same_object(w_o2) + assert not w_o2.is_same_object(w_o1) + +def test_intfloat_is_same_object(): + test_is_same_object(model.W_SmallInteger(1), model.W_SmallInteger(1)) + test_is_same_object(model.W_SmallInteger(100), model.W_SmallInteger(100)) + test_is_same_object(model.W_Float(1.100), model.W_Float(1.100)) + +def test_intfloat_notis_same_object(): + test_not_is_same_object(model.W_SmallInteger(1), model.W_Float(1)) + test_not_is_same_object(model.W_Float(100), model.W_SmallInteger(100)) + test_not_is_same_object(model.W_Float(1.100), model.W_Float(1.200)) + test_not_is_same_object(model.W_SmallInteger(101), model.W_SmallInteger(100)) + +def test_charis_same_object(): + test_is_same_object(space.wrap_char('a'), space.wrap_char('a')) + test_is_same_object(space.wrap_char('d'), space.wrap_char('d')) + +def test_not_charis_same_object(): + test_not_is_same_object(space.wrap_char('a'), space.wrap_char('d')) + test_not_is_same_object(space.wrap_char('d'), space.wrap_int(3)) + test_not_is_same_object(space.wrap_char('d'), space.wrap_float(3.0)) + +def test_become_pointers(): + w_clsa = mockclass(space, 3) + w_a = w_clsa.as_class_get_shadow(space).new() + + w_clsb = mockclass(space, 4) + w_b = w_clsb.as_class_get_shadow(space).new() + + hasha = w_a.gethash() + hashb = w_b.gethash() + + w_a.store(space, 0, w_b) + w_b.store(space, 1, w_a) + + res = w_a.become(w_b) + assert res + assert w_a.gethash() == hashb + assert w_b.gethash() == hasha + + assert w_a.getclass(space).is_same_object(w_clsb) + assert w_b.getclass(space).is_same_object(w_clsa) + + assert w_b.fetch(space, 0) is w_b + assert w_a.fetch(space, 1) is w_a + +def test_become_with_shadow(): + w_clsa = mockclass(space, 3) + s_clsa = w_clsa.as_class_get_shadow(space) + w_clsb = mockclass(space, 4) + s_clsb = w_clsb.as_class_get_shadow(space) + res = w_clsa.become(w_clsb) + assert res + assert w_clsa.as_class_get_shadow(space) is s_clsb + assert w_clsb.as_class_get_shadow(space) is s_clsa + +def test_word_atput(): + i = model.W_SmallInteger(100) + b = model.W_WordsObject(None, 1) + b.atput0(space, 0, i) + assert 100 == b.getword(0) + i = space.classtable['w_LargePositiveInteger'].as_class_get_shadow(space).new(4) + i.atput0(space, 3, space.wrap_int(192)) + b.atput0(space, 0, i) + assert b.getword(0) == 3221225472 + +def test_word_at(): + b = model.W_WordsObject(None, 1) + b.setword(0, 100) + r = b.at0(space, 0) + assert isinstance(r, model.W_SmallInteger) + assert space.unwrap_int(r) == 100 + + b.setword(0, 3221225472) + r = b.at0(space, 0) + assert isinstance(r, model.W_BytesObject) + assert r.size() == 4 Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_primitives.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_primitives.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_primitives.py Tue Jun 10 12:48:46 2008 @@ -1,48 +1,56 @@ import py import math from pypy.lang.smalltalk.primitives import prim_table, PrimitiveFailedError -from pypy.lang.smalltalk import model, shadow -from pypy.lang.smalltalk import interpreter, utility -from pypy.lang.smalltalk import classtable, objtable, constants +from pypy.lang.smalltalk import model, shadow, interpreter +from pypy.lang.smalltalk import constants from pypy.rlib.rarithmetic import INFINITY, NAN, isinf, isnan from pypy.lang.smalltalk import primitives +from pypy.lang.smalltalk import objspace -mockclass = classtable.bootstrap_class +mockclass = objspace.bootstrap_class -class MockFrame(model.W_MethodContext): +space = objspace.ObjSpace() + +class MockFrame(model.W_PointersObject): def __init__(self, stack): - self.stack = stack + self._vars = [None] * 6 + stack + s_self = self.as_blockcontext_get_shadow() + s_self._stack = stack + s_self.store_expected_argument_count(0) + def as_blockcontext_get_shadow(self): + self._shadow = shadow.BlockContextShadow(space, self) + return self._shadow def wrap(x): - if isinstance(x, int): return utility.wrap_int(x) - if isinstance(x, float): return utility.wrap_float(x) + if isinstance(x, int): return space.wrap_int(x) + if isinstance(x, float): return space.wrap_float(x) if isinstance(x, model.W_Object): return x - if isinstance(x, str) and len(x) == 1: return utility.wrap_char(x) - if isinstance(x, str): return utility.wrap_string(x) + if isinstance(x, str) and len(x) == 1: return space.wrap_char(x) + if isinstance(x, str): return space.wrap_string(x) raise NotImplementedError def mock(stack): mapped_stack = [wrap(x) for x in stack] frame = MockFrame(mapped_stack) - interp = interpreter.Interpreter() - interp.w_active_context = frame + interp = interpreter.Interpreter(space) + interp.store_w_active_context(frame) return (interp, len(stack)) def prim(code, stack): interp, argument_count = mock(stack) prim_table[code](interp, argument_count-1) - res = interp.w_active_context.pop() - assert not len(interp.w_active_context.stack) # check args are consumed + res = interp.s_active_context().pop() + assert not len(interp.s_active_context().stack()) # check args are consumed return res def prim_fails(code, stack): interp, argument_count = mock(stack) - orig_stack = list(interp.w_active_context.stack) + orig_stack = list(interp.s_active_context().stack()) try: prim_table[code](interp, argument_count-1) py.test.fail("Expected PrimitiveFailedError") except PrimitiveFailedError: - assert interp.w_active_context.stack == orig_stack + assert interp.s_active_context().stack() == orig_stack # smallinteger tests def test_small_int_add(): @@ -175,16 +183,16 @@ assert prim(primitives.FLOAT_TRUNCATED, [4.6]).value == 4 def test_at(): - w_obj = mockclass(0, varsized=True).as_class_get_shadow().new(1) - w_obj.store(0, "foo") + w_obj = mockclass(space, 0, varsized=True).as_class_get_shadow(space).new(1) + w_obj.store(space, 0, "foo") assert prim(primitives.AT, [w_obj, 1]) == "foo" def test_invalid_at(): - w_obj = mockclass(0).as_class_get_shadow().new() + w_obj = mockclass(space, 0).as_class_get_shadow(space).new() prim_fails(primitives.AT, [w_obj, 1]) def test_at_put(): - w_obj = mockclass(0, varsized=1).as_class_get_shadow().new(1) + w_obj = mockclass(space, 0, varsized=1).as_class_get_shadow(space).new(1) assert prim(primitives.AT_PUT, [w_obj, 1, 22]).value == 22 assert prim(primitives.AT, [w_obj, 1]).value == 22 @@ -197,13 +205,13 @@ assert prim(primitives.AT, [w_str, 3]).value == ord('c') def test_invalid_at_put(): - w_obj = mockclass(0).as_class_get_shadow().new() + w_obj = mockclass(space, 0).as_class_get_shadow(space).new() prim_fails(primitives.AT_PUT, [w_obj, 1, 22]) def test_size(): - w_obj = mockclass(0, varsized=True).as_class_get_shadow().new(0) + w_obj = mockclass(space, 0, varsized=True).as_class_get_shadow(space).new(0) assert prim(primitives.SIZE, [w_obj]).value == 0 - w_obj = mockclass(3, varsized=True).as_class_get_shadow().new(5) + w_obj = mockclass(space, 3, varsized=True).as_class_get_shadow(space).new(5) assert prim(primitives.SIZE, [w_obj]).value == 5 def test_size_of_compiled_method(): @@ -227,7 +235,7 @@ prim_fails(primitives.OBJECT_AT, ["q", constants.CHARACTER_VALUE_INDEX+2]) def test_invalid_object_at_put(): - w_obj = mockclass(1).as_class_get_shadow().new() + w_obj = mockclass(space, 1).as_class_get_shadow(space).new() prim_fails(primitives.OBJECT_AT_PUT, [w_obj, 2, 42]) def test_string_at_put(): @@ -238,20 +246,20 @@ assert prim(primitives.STRING_AT, [test_str, i]) == wrap(exp[i-1]) def test_new(): - w_Object = classtable.classtable['w_Object'] + w_Object = space.classtable['w_Object'] w_res = prim(primitives.NEW, [w_Object]) - assert w_res.getclass() is w_Object + assert w_res.getclass(space).is_same_object(w_Object) def test_invalid_new(): - prim_fails(primitives.NEW, [classtable.w_String]) + prim_fails(primitives.NEW, [space.w_String]) def test_new_with_arg(): - w_res = prim(primitives.NEW_WITH_ARG, [classtable.w_String, 20]) - assert w_res.getclass() == classtable.w_String + w_res = prim(primitives.NEW_WITH_ARG, [space.w_String, 20]) + assert w_res.getclass(space).is_same_object(space.w_String) assert w_res.size() == 20 def test_invalid_new_with_arg(): - w_Object = classtable.classtable['w_Object'] + w_Object = space.classtable['w_Object'] prim_fails(primitives.NEW_WITH_ARG, [w_Object, 20]) def test_inst_var_at(): @@ -266,10 +274,10 @@ def test_inst_var_at_put(): # n.b.: 1-based indexing! - w_q = classtable.w_Character.as_class_get_shadow().new() + w_q = space.w_Character.as_class_get_shadow(space).new() vidx = constants.CHARACTER_VALUE_INDEX+1 ordq = ord("q") - assert prim(primitives.INST_VAR_AT, [w_q, vidx]) == objtable.w_nil + assert prim(primitives.INST_VAR_AT, [w_q, vidx]) == space.w_nil assert prim(primitives.INST_VAR_AT_PUT, [w_q, vidx, ordq]).value == ordq assert prim(primitives.INST_VAR_AT, [w_q, vidx]).value == ordq @@ -279,12 +287,12 @@ ["q", constants.CHARACTER_VALUE_INDEX+2, "t"]) def test_class(): - assert prim(primitives.CLASS, ["string"]) == classtable.w_String - assert prim(primitives.CLASS, [1]) == classtable.w_SmallInteger + assert prim(primitives.CLASS, ["string"]).is_same_object(space.w_String) + assert prim(primitives.CLASS, [1]).is_same_object(space.w_SmallInteger) def test_as_oop(): py.test.skip("not yet clear what AS_OOP returns: hash or header?") - w_obj = mockclass(0).as_class_get_shadow().new() + w_obj = mockclass(space, 0).as_class_get_shadow(space).new() w_obj.w_hash = wrap(22) assert prim(primitives.AS_OOP, [w_obj]).value == 22 @@ -293,33 +301,33 @@ def test_const_primitives(): for (code, const) in [ - (primitives.PUSH_TRUE, objtable.w_true), - (primitives.PUSH_FALSE, objtable.w_false), - (primitives.PUSH_NIL, objtable.w_nil), - (primitives.PUSH_MINUS_ONE, objtable.w_minus_one), - (primitives.PUSH_ZERO, objtable.w_zero), - (primitives.PUSH_ONE, objtable.w_one), - (primitives.PUSH_TWO, objtable.w_two), + (primitives.PUSH_TRUE, space.w_true), + (primitives.PUSH_FALSE, space.w_false), + (primitives.PUSH_NIL, space.w_nil), + (primitives.PUSH_MINUS_ONE, space.w_minus_one), + (primitives.PUSH_ZERO, space.w_zero), + (primitives.PUSH_ONE, space.w_one), + (primitives.PUSH_TWO, space.w_two), ]: - assert prim(code, [objtable.w_nil]) is const - assert prim(primitives.PUSH_SELF, [objtable.w_nil]) is objtable.w_nil + assert prim(code, [space.w_nil]).is_same_object(const) + assert prim(primitives.PUSH_SELF, [space.w_nil]).is_same_object(space.w_nil) assert prim(primitives.PUSH_SELF, ["a"]) is wrap("a") def test_boolean(): - assert prim(primitives.LESSTHAN, [1,2]) == objtable.w_true - assert prim(primitives.GREATERTHAN, [3,4]) == objtable.w_false - assert prim(primitives.LESSOREQUAL, [1,2]) == objtable.w_true - assert prim(primitives.GREATEROREQUAL, [3,4]) == objtable.w_false - assert prim(primitives.EQUAL, [2,2]) == objtable.w_true - assert prim(primitives.NOTEQUAL, [2,2]) == objtable.w_false + assert prim(primitives.LESSTHAN, [1,2]).is_same_object(space.w_true) + assert prim(primitives.GREATERTHAN, [3,4]).is_same_object(space.w_false) + assert prim(primitives.LESSOREQUAL, [1,2]).is_same_object(space.w_true) + assert prim(primitives.GREATEROREQUAL, [3,4]).is_same_object(space.w_false) + assert prim(primitives.EQUAL, [2,2]).is_same_object(space.w_true) + assert prim(primitives.NOTEQUAL, [2,2]).is_same_object(space.w_false) def test_float_boolean(): - assert prim(primitives.FLOAT_LESSTHAN, [1.0,2.0]) == objtable.w_true - assert prim(primitives.FLOAT_GREATERTHAN, [3.0,4.0]) == objtable.w_false - assert prim(primitives.FLOAT_LESSOREQUAL, [1.3,2.6]) == objtable.w_true - assert prim(primitives.FLOAT_GREATEROREQUAL, [3.5,4.9]) == objtable.w_false - assert prim(primitives.FLOAT_EQUAL, [2.2,2.2]) == objtable.w_true - assert prim(primitives.FLOAT_NOTEQUAL, [2.2,2.2]) == objtable.w_false + assert prim(primitives.FLOAT_LESSTHAN, [1.0,2.0]).is_same_object(space.w_true) + assert prim(primitives.FLOAT_GREATERTHAN, [3.0,4.0]).is_same_object(space.w_false) + assert prim(primitives.FLOAT_LESSOREQUAL, [1.3,2.6]).is_same_object(space.w_true) + assert prim(primitives.FLOAT_GREATEROREQUAL, [3.5,4.9]).is_same_object(space.w_false) + assert prim(primitives.FLOAT_EQUAL, [2.2,2.2]).is_same_object(space.w_true) + assert prim(primitives.FLOAT_NOTEQUAL, [2.2,2.2]).is_same_object(space.w_false) def test_block_copy_and_value(): # see test_interpreter for tests of these opcodes @@ -390,29 +398,6 @@ now = int(time.time()) assert (prim(primitives.SECONDS_CLOCK, [42]).value - now) <= 2 -def test_become(): - py.test.skip("implement me!") - """ - testBecome - | p1 p2 a | - p1 := 1 at 2. - p2 := #(3 4 5). - a := p1 -> p2. - self assert: 1 at 2 = a key. - self assert: #(3 4 5) = a value. - self assert: p1 -> p2 = a. - self assert: p1 == a key. - self assert: p2 == a value. - p1 become: p2. - self assert: 1 at 2 = a value. - self assert: #(3 4 5) = a key. - self assert: p1 -> p2 = a. - self assert: p1 == a key. - self assert: p2 == a value. - - self should: [1 become: 2] raise: Error. - """ - def test_load_inst_var(): " try to test the LoadInstVar primitives a little " w_v = prim(primitives.INST_VAR_AT_0, ["q"]) @@ -421,11 +406,11 @@ def test_new_method(): bytecode = ''.join(map(chr, [ 16, 119, 178, 154, 118, 164, 11, 112, 16, 118, 177, 224, 112, 16, 119, 177, 224, 176, 124 ])) - shadow = mockclass(0).as_class_get_shadow() - w_method = prim(primitives.NEW_METHOD, [classtable.w_CompiledMethod, len(bytecode), 1025]) - assert w_method.literalat0(0).value == 1025 + shadow = mockclass(space, 0).as_class_get_shadow(space) + w_method = prim(primitives.NEW_METHOD, [space.w_CompiledMethod, len(bytecode), 1025]) + assert w_method.literalat0(space, 0).value == 1025 assert w_method.literalsize == 2 - assert w_method.literalat0(1) is objtable.w_nil + assert w_method.literalat0(space, 1).is_same_object(space.w_nil) assert w_method.bytes == "\x00" * len(bytecode) Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_shadow.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_shadow.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_shadow.py Tue Jun 10 12:48:46 2008 @@ -1,30 +1,31 @@ import random -from pypy.lang.smalltalk import model, shadow, classtable, constants, objtable -from pypy.lang.smalltalk import utility +from pypy.lang.smalltalk import model, shadow, constants +from pypy.lang.smalltalk import objspace -w_Object = classtable.classtable['w_Object'] -w_Metaclass = classtable.classtable['w_Metaclass'] -w_MethodDict = classtable.classtable['w_MethodDict'] -w_Array = classtable.classtable['w_Array'] +space = objspace.ObjSpace() + +w_Object = space.classtable['w_Object'] +w_Metaclass = space.classtable['w_Metaclass'] +w_MethodDict = space.classtable['w_MethodDict'] +w_Array = space.classtable['w_Array'] def build_methoddict(methods): size = int(len(methods) * 1.5) - w_methoddict = w_MethodDict.as_class_get_shadow().new(size) - w_array = w_Array.as_class_get_shadow().new(size) + w_methoddict = w_MethodDict.as_class_get_shadow(space).new(size) + w_array = w_Array.as_class_get_shadow(space).new(size) for i in range(size): - w_array.store(i, objtable.w_nil) - w_methoddict.store(constants.METHODDICT_NAMES_INDEX+i, objtable.w_nil) - w_tally = utility.wrap_int(len(methods)) - w_methoddict.store(constants.METHODDICT_TALLY_INDEX, w_tally) - w_methoddict.store(constants.METHODDICT_VALUES_INDEX, w_array) + w_array.store(space, i, space.w_nil) + w_methoddict.store(space, constants.METHODDICT_NAMES_INDEX+i, space.w_nil) + w_tally = space.wrap_int(len(methods)) + w_methoddict.store(space, constants.METHODDICT_TALLY_INDEX, w_tally) + w_methoddict.store(space, constants.METHODDICT_VALUES_INDEX, w_array) positions = range(size) random.shuffle(positions) for selector, w_compiledmethod in methods.items(): pos = positions.pop() - w_selector = utility.wrap_string(selector) - w_methoddict.store(constants.METHODDICT_NAMES_INDEX+pos, w_selector) - w_array.store(pos, w_compiledmethod) - #print w_methoddict._vars + w_selector = space.wrap_string(selector) + w_methoddict.store(space, constants.METHODDICT_NAMES_INDEX+pos, w_selector) + w_array.store(space, pos, w_compiledmethod) return w_methoddict def build_smalltalk_class(name, format, w_superclass=w_Object, @@ -36,21 +37,21 @@ w_methoddict = build_methoddict(methods) size = constants.CLASS_NAME_INDEX + 1 w_class = model.W_PointersObject(w_classofclass, size) - w_class.store(constants.CLASS_SUPERCLASS_INDEX, w_superclass) - w_class.store(constants.CLASS_METHODDICT_INDEX, w_methoddict) - w_class.store(constants.CLASS_FORMAT_INDEX, utility.wrap_int(format)) + w_class.store(space, constants.CLASS_SUPERCLASS_INDEX, w_superclass) + w_class.store(space, constants.CLASS_METHODDICT_INDEX, w_methoddict) + w_class.store(space, constants.CLASS_FORMAT_INDEX, space.wrap_int(format)) if name is not None: - w_class.store(constants.CLASS_NAME_INDEX, utility.wrap_string(name)) + w_class.store(space, constants.CLASS_NAME_INDEX, space.wrap_string(name)) return w_class def basicshape(name, format, kind, varsized, instsize): w_class = build_smalltalk_class(name, format) - classshadow = w_class.as_class_get_shadow() + classshadow = w_class.as_class_get_shadow(space) assert classshadow.instance_kind == kind assert classshadow.isvariable() == varsized assert classshadow.instsize() == instsize assert classshadow.name == name - assert classshadow.s_superclass is w_Object.as_class_get_shadow() + assert classshadow.s_superclass() is w_Object.as_class_get_shadow(space) def test_basic_shape(): yield basicshape, "Empty", 0x02, shadow.POINTERS, False, 0 @@ -67,5 +68,116 @@ methods = {'foo': model.W_CompiledMethod(0), 'bar': model.W_CompiledMethod(0)} w_class = build_smalltalk_class("Demo", 0x90, methods=methods) - classshadow = w_class.as_class_get_shadow() - assert classshadow.methoddict == methods + classshadow = w_class.as_class_get_shadow(space) + assert classshadow.s_methoddict().methoddict == methods + +def method(tempsize=3,argsize=2, bytes="abcde"): + w_m = model.W_CompiledMethod() + w_m.bytes = bytes + w_m.tempsize = tempsize + w_m.argsize = argsize + w_m.literalsize = 2 + return w_m + +def methodcontext(w_sender=space.w_nil, pc=1, stackpointer=0, stacksize=5, + method=method()): + w_object = model.W_PointersObject(space.w_MethodContext, constants.MTHDCTX_TEMP_FRAME_START+method.tempsize+stacksize) + w_object.store(space, constants.CTXPART_SENDER_INDEX, w_sender) + w_object.store(space, constants.CTXPART_PC_INDEX, space.wrap_int(pc)) + w_object.store(space, constants.CTXPART_STACKP_INDEX, space.wrap_int(method.tempsize+stackpointer)) + w_object.store(space, constants.MTHDCTX_METHOD, method) + # XXX + w_object.store(space, constants.MTHDCTX_RECEIVER_MAP, '???') + w_object.store(space, constants.MTHDCTX_RECEIVER, 'receiver') + + w_object.store(space, constants.MTHDCTX_TEMP_FRAME_START, 'el') + return w_object + +def blockcontext(w_sender=space.w_nil, pc=1, stackpointer=1, stacksize=5, + home=methodcontext()): + w_object = model.W_PointersObject(space.w_MethodContext, constants.MTHDCTX_TEMP_FRAME_START+stacksize) + w_object.store(space, constants.CTXPART_SENDER_INDEX, w_sender) + w_object.store(space, constants.CTXPART_PC_INDEX, space.wrap_int(pc)) + w_object.store(space, constants.CTXPART_STACKP_INDEX, space.wrap_int(stackpointer)) + w_object.store(space, constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX, space.wrap_int(54)) + w_object.store(space, constants.BLKCTX_INITIAL_IP_INDEX, space.wrap_int(17)) + w_object.store(space, constants.BLKCTX_HOME_INDEX, home) + w_object.store(space, constants.BLKCTX_STACK_START, 'el') + return w_object + +def test_context(): + w_m = method() + w_object = methodcontext(stackpointer=3, method=w_m) + w_object2 = methodcontext(w_sender=w_object) + s_object = w_object.as_methodcontext_get_shadow(space) + assert len(s_object.stack()) == 3 + s_object2 = w_object2.as_methodcontext_get_shadow(space) + assert w_object2.fetch(space, constants.CTXPART_SENDER_INDEX) == w_object + assert s_object.w_self() == w_object + assert s_object2.w_self() == w_object2 + assert s_object.s_sender() == None + assert s_object2.s_sender() == s_object + assert s_object.w_receiver() == 'receiver' + s_object2.settemp(0, 'a') + s_object2.settemp(1, 'b') + assert s_object2.gettemp(1) == 'b' + assert s_object2.gettemp(0) == 'a' + assert s_object.w_method() == w_m + idx = s_object.stackstart() + w_object.store(space, idx, 'f') + w_object.store(space, idx + 1, 'g') + w_object.store(space, idx + 2, 'h') + assert s_object.stack() == ['f', 'g', 'h' ] + assert s_object.top() == 'h' + s_object.push('i') + assert s_object.top() == 'i' + assert s_object.peek(1) == 'h' + assert s_object.pop() == 'i' + assert s_object.pop_and_return_n(2) == ['g', 'h'] + assert s_object.pop() == 'f' + assert s_object.external_stackpointer() == s_object.stackstart() + +def test_methodcontext(): + w_m = method() + # Point over 2 literals of size 4 + w_object = methodcontext(pc=13,method=w_m) + s_object = w_object.as_methodcontext_get_shadow(space) + assert s_object.getbytecode() == 97 + assert s_object.getbytecode() == 98 + assert s_object.getbytecode() == 99 + assert s_object.getbytecode() == 100 + assert s_object.getbytecode() == 101 + assert s_object.s_home() == s_object + +def test_attach_detach_mc(): + w_m = method() + w_object = methodcontext(pc=13, method=w_m) + old_vars = w_object._vars + s_object = w_object.as_methodcontext_get_shadow(space) + assert w_object._vars is None + s_object.detach_shadow() + assert w_object._vars == old_vars + assert w_object._vars is not old_vars + +def test_attach_detach_bc(): + w_object = blockcontext(pc=13) + old_vars = w_object._vars + s_object = w_object.as_blockcontext_get_shadow(space) + assert w_object._vars is None + s_object.detach_shadow() + assert w_object._vars == old_vars + assert w_object._vars is not old_vars + +def test_replace_to_bc(): + w_object = blockcontext(pc=13) + old_vars = w_object._vars + s_object = w_object.as_blockcontext_get_shadow(space) + s_object.detach_shadow() + s_classshadow = shadow.ClassShadow(space, w_object) + w_object._shadow = s_classshadow + s_classshadow.invalid = False + s_newobject = w_object.as_blockcontext_get_shadow(space) + assert s_classshadow.invalid + assert ([s_newobject.fetch(i) for i in range(s_newobject.size())] == + [s_object.fetch(i) for i in range(s_newobject.size())]) + assert w_object._shadow is s_newobject Modified: pypy/branch/build-external/pypy/lang/smalltalk/test/test_squeakimage.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/test/test_squeakimage.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/test/test_squeakimage.py Tue Jun 10 12:48:46 2008 @@ -1,6 +1,9 @@ import py from pypy.lang.smalltalk import squeakimage from pypy.lang.smalltalk.squeakimage import chrs2int +from pypy.lang.smalltalk import objspace + +space = objspace.ObjSpace() # ----- helpers ---------------------------------------------- @@ -19,7 +22,7 @@ import StringIO f = StringIO.StringIO(string) stream = squeakimage.Stream(f) - return squeakimage.ImageReader(stream) + return squeakimage.ImageReader(space, stream) # ----- tests ------------------------------------------------ @@ -91,31 +94,31 @@ def test_1wordobjectheader(): s = ints2str(joinbits([3, 1, 2, 3, 4], [2,6,4,5,12])) r = imagereader_mock(s) - assert (squeakimage.ImageChunk(1, 2, 3, 4), 0) == r.read_1wordobjectheader() + assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0) == r.read_1wordobjectheader() def test_1wordobjectheader2(): s = ints2str(joinbits([3, 1, 2, 3, 4], [2,6,4,5,12])) r = imagereader_mock(s * 3) - assert (squeakimage.ImageChunk(1, 2, 3, 4), 0) == r.read_1wordobjectheader() - assert (squeakimage.ImageChunk(1, 2, 3, 4), 4) == r.read_1wordobjectheader() - assert (squeakimage.ImageChunk(1, 2, 3, 4), 8) == r.read_1wordobjectheader() + assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0) == r.read_1wordobjectheader() + assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 4) == r.read_1wordobjectheader() + assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 8) == r.read_1wordobjectheader() def test_2wordobjectheader(): s = ints2str(4200 + 1, joinbits([1, 1, 2, 3, 4], [2,6,4,5,12])) r = imagereader_mock(s) - assert (squeakimage.ImageChunk(1, 2, 4200, 4), 4) == r.read_2wordobjectheader() + assert (squeakimage.ImageChunk(space, 1, 2, 4200, 4), 4) == r.read_2wordobjectheader() def test_3wordobjectheader(): s = ints2str(1701 << 2, 4200 + 0, joinbits([0, 1, 2, 3, 4], [2,6,4,5,12])) r = imagereader_mock(s) - assert (squeakimage.ImageChunk(1701, 2, 4200, 4), 8) == r.read_3wordobjectheader() + assert (squeakimage.ImageChunk(space, 1701, 2, 4200, 4), 8) == r.read_3wordobjectheader() def test_read3wordheaderobject(): size = 42 s = ints2str(size << 2, 4200 + 0, joinbits([0, 1, 2, 3, 4], [2,6,4,5,12])) r = imagereader_mock(s + '\x00\x00\x19\x66' * (size - 1)) chunk, pos = r.read_object() - chunk0 = squeakimage.ImageChunk(size, 2, 4200, 4) + chunk0 = squeakimage.ImageChunk(space, size, 2, 4200, 4) chunk0.data = [6502] * (size - 1) assert pos == 8 assert chunk0 == chunk Modified: pypy/branch/build-external/pypy/lang/smalltalk/tool/analyseimage.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/tool/analyseimage.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/tool/analyseimage.py Tue Jun 10 12:48:46 2008 @@ -3,22 +3,20 @@ from pypy.lang.smalltalk import squeakimage from pypy.lang.smalltalk import constants from pypy.lang.smalltalk import model -from pypy.lang.smalltalk import objtable -from pypy.lang.smalltalk import classtable from pypy.lang.smalltalk import interpreter import sys mini_image = py.magic.autopath().dirpath().dirpath().join('mini.image') -def get_miniimage(): - return squeakimage.ImageReader(squeakimage.Stream(mini_image.open())) +def get_miniimage(space): + return squeakimage.ImageReader(space, squeakimage.Stream(mini_image.open())) -def create_squeakimage(): - example = get_miniimage() +def create_squeakimage(space): + example = get_miniimage(space) example.initialize() image = squeakimage.SqueakImage() - image.from_reader(example) + image.from_reader(space, example) return image def printStringsInImage(): @@ -42,39 +40,15 @@ assert w_method w_frame = w_method.create_frame(w_object, []) - interp.w_active_context = w_frame - - print w_method - print "Going to execute %d toplevel bytecodes" % (len(w_method.bytes),) - counter = 0 + interp.store_w_active_context(w_frame) from pypy.lang.smalltalk.interpreter import BYTECODE_TABLE while True: try: - counter += 1 - if interp.w_active_context == w_frame: - print "Executing toplevel bytecode nr: %d of %d" % (interp.w_active_context.pc+1, len(w_method.bytes)) - cb = ord(interp.w_active_context.w_method().bytes[interp.w_active_context.pc]) - print "= bytecode: %s %d" % (BYTECODE_TABLE[cb].__name__,cb) interp.step() - #if hasattr(interp.w_active_context,"currentBytecode"): - # print "Executing bytecode: %s" % (BYTECODE_TABLE[interp.w_active_context.currentBytecode].__name__,) - #else: - # print "Jump to new stackframe" - # print interp.w_active_context.stack - if counter == 100000: - counter = 0 - sys.stderr.write("#") except interpreter.ReturnFromTopLevel, e: print e.object return - except: - if hasattr(interp.w_active_context,"currentBytecode"): - cb = interp.w_active_context.currentBytecode - print "Failing bytecode: %s %d" % (BYTECODE_TABLE[cb].__name__,cb) - raise - - def test_do(): #testSelector() Modified: pypy/branch/build-external/pypy/lang/smalltalk/tool/autopath.py ============================================================================== --- pypy/branch/build-external/pypy/lang/smalltalk/tool/autopath.py (original) +++ pypy/branch/build-external/pypy/lang/smalltalk/tool/autopath.py Tue Jun 10 12:48:46 2008 @@ -33,22 +33,13 @@ except NameError: head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) - error = None while head: partdir = head head, tail = os.path.split(head) if tail == part: - # check if "../py/__init__.py" exists - checkfile = os.path.join(partdir, os.pardir, 'py', '__init__.py') - if not os.path.exists(checkfile): - error = "Cannot find %r" % (os.path.normpath(checkfile),) break else: - error = "Cannot find the parent directory %r of the path %r" % ( - partdir, this_dir) - if error: - raise EnvironmentError("Invalid source tree - bogus checkout! " + - error) + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) pypy_root = os.path.join(head, '') try: Modified: pypy/branch/build-external/pypy/lib/app_test/test_pyexpat.py ============================================================================== --- pypy/branch/build-external/pypy/lib/app_test/test_pyexpat.py (original) +++ pypy/branch/build-external/pypy/lib/app_test/test_pyexpat.py Tue Jun 10 12:48:46 2008 @@ -2,10 +2,11 @@ # handler, are obscure and unhelpful. import StringIO, sys -import unittest +import unittest, py import pyexpat -from xml.parsers import expat +#from xml.parsers import expat +expat = pyexpat from test.test_support import sortdict, run_unittest @@ -254,6 +255,7 @@ class TestInterning: def test(self): + py.test.skip("Not working") # Test the interning machinery. p = expat.ParserCreate() L = [] @@ -310,8 +312,7 @@ # Make sure buffering is turned on assert self.parser.buffer_text self.parser.Parse("123", 1) - assert self.stuff == ['123'], ( - "buffered text not properly collapsed") + assert self.stuff == ['123'] def test1(self): # XXX This test exposes more detail of Expat's text chunking than we @@ -442,7 +443,11 @@ """ def setup_class(cls): import py - py.test.skip("Doesn't work on cpy 2.5") + try: + import __pypy__ + except ImportError: + pass + #py.test.skip("Doesn't work on cpy 2.5") def test_1025_bytes(self): assert self.small_buffer_test(1025) == 2 Modified: pypy/branch/build-external/pypy/lib/pyexpat.py ============================================================================== --- pypy/branch/build-external/pypy/lib/pyexpat.py (original) +++ pypy/branch/build-external/pypy/lib/pyexpat.py Tue Jun 10 12:48:46 2008 @@ -2,7 +2,8 @@ import ctypes import ctypes.util from ctypes_configure import configure -from ctypes import c_char_p, c_int, c_void_p, POINTER, c_char +from ctypes import c_char_p, c_int, c_void_p, POINTER, c_char, c_wchar_p +import sys lib = ctypes.CDLL(ctypes.util.find_library('expat')) @@ -21,21 +22,31 @@ 'XML_PARAM_ENTITY_PARSING_ALWAYS']: locals()[name] = configure.ConstantInteger(name) + XML_Encoding = configure.Struct('XML_Encoding',[ + ('data', c_void_p), + ('convert', c_void_p), + ('release', c_void_p), + ('map', c_int * 256)]) + # this is insanely stupid + XML_FALSE = configure.ConstantInteger('XML_FALSE') + XML_TRUE = configure.ConstantInteger('XML_TRUE') + info = configure.configure(CConfigure) for k, v in info.items(): globals()[k] = v XML_Parser = ctypes.c_void_p # an opaque pointer assert XML_Char is ctypes.c_char # this assumption is everywhere in # cpython's expat, let's explode -XML_ParserCreate = lib.XML_ParserCreate -XML_ParserCreate.args = [ctypes.c_char_p] -XML_ParserCreate.result = XML_Parser -XML_ParserCreateNS = lib.XML_ParserCreateNS -XML_ParserCreateNS.args = [c_char_p, c_char] -XML_ParserCreateNS.result = XML_Parser -XML_Parse = lib.XML_Parse -XML_Parse.args = [XML_Parser, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] -XML_Parse.result = ctypes.c_int + +def declare_external(name, args, res): + func = getattr(lib, name) + func.args = args + func.result = res + globals()[name] = func + +declare_external('XML_ParserCreate', [c_char_p], XML_Parser) +declare_external('XML_ParserCreateNS', [c_char_p, c_char], XML_Parser) +declare_external('XML_Parse', [XML_Parser, c_char_p, c_int, c_int], c_int) currents = ['CurrentLineNumber', 'CurrentColumnNumber', 'CurrentByteIndex'] for name in currents: @@ -43,15 +54,22 @@ func.args = [XML_Parser] func.result = c_int -XML_SetReturnNSTriplet = lib.XML_SetReturnNSTriplet -XML_SetReturnNSTriplet.args = [XML_Parser, c_int] -XML_SetReturnNSTriplet.result = None -XML_GetSpecifiedAttributeCount = lib.XML_GetSpecifiedAttributeCount -XML_GetSpecifiedAttributeCount.args = [XML_Parser] -XML_GetSpecifiedAttributeCount.result = c_int -XML_SetParamEntityParsing = lib.XML_SetParamEntityParsing -XML_SetParamEntityParsing.args = [XML_Parser, c_int] -XML_SetParamEntityParsing.result = None +declare_external('XML_SetReturnNSTriplet', [XML_Parser, c_int], None) +declare_external('XML_GetSpecifiedAttributeCount', [XML_Parser], c_int) +declare_external('XML_SetParamEntityParsing', [XML_Parser, c_int], None) +declare_external('XML_GetErrorCode', [XML_Parser], c_int) +declare_external('XML_StopParser', [XML_Parser, c_int], None) +lib.XML_ErrorString.args = [c_int] +lib.XML_ErrorString.result = c_int + +declare_external('XML_SetUnknownEncodingHandler', [XML_Parser, c_void_p, + c_void_p], None) + +def XML_ErrorString(code): + res = lib.XML_ErrorString(code) + p = c_char_p() + p.value = res + return p.value handler_names = [ 'StartElement', @@ -92,7 +110,8 @@ setters[name] = cfunc class ExpatError(Exception): - pass + def __str__(self): + return self.s error = ExpatError @@ -111,6 +130,7 @@ self.itself = XML_ParserCreateNS(encoding, ord(namespace_separator)) if not self.itself: raise RuntimeError("Creating parser failed") + self._set_unknown_encoding_handler() self.storage = {} self.buffer = None self.buffer_size = 8192 @@ -128,10 +148,42 @@ if self.character_data_handler: self.character_data_handler(buf) - def Parse(self, data, is_final): + def _set_unknown_encoding_handler(self): + def UnknownEncoding(encodingData, name, info_p): + info = info_p.contents + s = ''.join([chr(i) for i in range(256)]) + u = s.decode(self.encoding, 'replace') + for i in range(len(u)): + if u[i] == u'\xfffd': + info.map[i] = -1 + else: + info.map[i] = ord(u[i]) + info.data = None + info.convert = None + info.release = None + return 1 + + CB = ctypes.CFUNCTYPE(c_int, c_void_p, c_char_p, POINTER(XML_Encoding)) + cb = CB(UnknownEncoding) + self._unknown_encoding_handler = (cb, UnknownEncoding) + XML_SetUnknownEncodingHandler(self.itself, cb, None) + + def _set_error(self, code): + e = ExpatError() + e.code = code + lineno = lib.XML_GetCurrentLineNumber(self.itself) + colno = lib.XML_GetCurrentColumnNumber(self.itself) + e.offset = colno + e.lineno = lineno + err = XML_ErrorString(code)[:200] + e.s = "%s: line: %d, column: %d" % (err, lineno, colno) + self._error = e + + def Parse(self, data, is_final=0): res = XML_Parse(self.itself, data, len(data), is_final) if res == 0: - xxx + self._set_error(XML_GetErrorCode(self.itself)) + raise self.__exc_info[0], self.__exc_info[1], self.__exc_info[2] self._flush_character_buffer() return res @@ -147,6 +199,15 @@ cb = getattr(self, 'get_cb_for_%s' % name)(real_cb) setter(self.itself, cb) + def _wrap_cb(self, cb): + def f(*args): + try: + return cb(*args) + except: + self.__exc_info = sys.exc_info() + XML_StopParser(self.itself, XML_FALSE) + return f + def get_cb_for_StartElementHandler(self, real_cb): def StartElement(unused, name, attrs): # unpack name and attrs @@ -165,6 +226,7 @@ for i in range(0, max, 2): res[conv(attrs[i])] = conv(attrs[i + 1]) real_cb(conv(name), res) + StartElement = self._wrap_cb(StartElement) CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, POINTER(c_char_p)) return CB(StartElement) @@ -177,6 +239,7 @@ if res is None: return 0 return res + ExternalEntity = self._wrap_cb(ExternalEntity) CB = ctypes.CFUNCTYPE(c_int, c_void_p, *([c_char_p] * 4)) return CB(ExternalEntity) @@ -189,11 +252,12 @@ self._flush_character_buffer() if self.character_data_handler is None: return - if lgt > self.buffer_size: + if lgt >= self.buffer_size: self._call_character_handler(s[:lgt]) self.buffer = [] else: self.buffer.append(s[:lgt]) + CharacterData = self._wrap_cb(CharacterData) CB = ctypes.CFUNCTYPE(None, c_void_p, POINTER(c_char), c_int) return CB(CharacterData) @@ -206,6 +270,7 @@ pub_id, not_name] args = [self.conv(arg) for arg in args] real_cb(*args) + EntityDecl = self._wrap_cb(EntityDecl) CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p, c_int, c_char_p, c_char_p, c_char_p, c_char_p) return CB(EntityDecl) @@ -213,7 +278,8 @@ def get_cb_for_ElementDeclHandler(self, real_cb): # XXX this is broken, needs tests def ElementDecl(unused, *args): - pass + print "WARNING! ElementDeclHandler Not supported" + ElementDecl = self._wrap_cb(ElementDecl) CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, c_void_p) return CB(ElementDecl) @@ -224,6 +290,7 @@ arg = self.conv(s[:len]) real_cb(arg) func.func_name = name + func = self._wrap_cb(func) CB = ctypes.CFUNCTYPE(*sign) return CB(func) get_callback_for_.func_name = 'get_cb_for_' + name @@ -242,6 +309,7 @@ args = [self.conv(arg) for arg in args] real_cb(*args) func.func_name = name + func = self._wrap_cb(func) CB = ctypes.CFUNCTYPE(*sign) return CB(func) get_callback_for_.func_name = 'get_cb_for_' + name @@ -293,6 +361,12 @@ else: self._flush_character_buffer() self.buffer = None + elif name == 'buffer_size': + if not isinstance(value, int): + raise TypeError("Expected int") + if value <= 0: + raise ValueError("Expected positive int") + self.__dict__[name] = value elif name == 'namespace_prefixes': XML_SetReturnNSTriplet(self.itself, int(bool(value))) elif name in setters: Modified: pypy/branch/build-external/pypy/lib/test2/test_itertools.py ============================================================================== --- pypy/branch/build-external/pypy/lib/test2/test_itertools.py (original) +++ pypy/branch/build-external/pypy/lib/test2/test_itertools.py Tue Jun 10 12:48:46 2008 @@ -5,7 +5,7 @@ cls.space = gettestobjspace() cls.w_itertools = cls.space.appexec([], "(): import itertools; return itertools") - def test_chain(): - it = itertools.chain([], [1, 2, 3]) + def test_chain(self): + it = self.itertools.chain([], [1, 2, 3]) lst = list(it) assert lst == [1, 2, 3] Modified: pypy/branch/build-external/pypy/module/__builtin__/app_misc.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/app_misc.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/app_misc.py Tue Jun 10 12:48:46 2008 @@ -24,6 +24,7 @@ importer = importer_cache.get(p) else: importer_cache[p] = None + importer = None for hook in path_hooks: try: importer = hook(p) Modified: pypy/branch/build-external/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/importing.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/importing.py Tue Jun 10 12:48:46 2008 @@ -585,11 +585,11 @@ path_hooks = sys.path_hooks importer_cache = sys.path_importer_cache for p in path: - importer = None if importer_cache.get(p,None): importer = importer_cache.get(p) else: importer_cache[p] = None + importer = None for hook in path_hooks: try: importer = hook(p) Modified: pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/branch/build-external/pypy/module/__builtin__/test/test_import.py Tue Jun 10 12:48:46 2008 @@ -537,27 +537,31 @@ finally: sys.meta_path.pop() - def test_importer_cache(self): - class FooImporter(object): - def __init__(self, name): - if not name.startswith("foo_"): - raise ImportError + def test_path_hooks_leaking(self): + class Importer(object): def find_module(self, fullname, path=None): - return None + if fullname == "a": + return self + def load_module(self, name): + return sys + + def importer_for_path(path): + if path == "xxx": + return Importer() + raise ImportError() import sys - sys.path_hooks.append(FooImporter) - sys.path.insert(0, "foo_something") try: - import datetime + sys.path_hooks.append(importer_for_path) + sys.path.insert(0, "yyy") + sys.path.insert(0, "xxx") + import a + try: + import b + except ImportError: + pass + assert sys.path_importer_cache['yyy'] is None finally: - sys.path_hooks.pop() sys.path.pop(0) - - cache = sys.path_importer_cache - assert isinstance(cache['foo_something'], FooImporter) - for path, importer in sys.path_importer_cache.items(): - if path == 'foo_something': - assert isinstance(importer, FooImporter) - else: - assert importer is None + sys.path.pop(0) + sys.path_hooks.pop() Modified: pypy/branch/build-external/pypy/module/__pypy__/interp_magic.py ============================================================================== --- pypy/branch/build-external/pypy/module/__pypy__/interp_magic.py (original) +++ pypy/branch/build-external/pypy/module/__pypy__/interp_magic.py Tue Jun 10 12:48:46 2008 @@ -24,15 +24,13 @@ """Return a tuple (method_cache_hits, method_cache_misses) for calls to methods with the name.""" assert space.config.objspace.std.withmethodcachecounter - ec = space.getexecutioncontext() - return space.newtuple([space.newint(ec.method_cache_hits.get(name, 0)), - space.newint(ec.method_cache_misses.get(name, 0)),]) + return space.newtuple([space.newint(space.method_cache_hits.get(name, 0)), + space.newint(space.method_cache_misses.get(name, 0)),]) method_cache_counter.unwrap_spec = [ObjSpace, str] def reset_method_cache_counter(space): """Reset the method cache counter to zero for all method names.""" assert space.config.objspace.std.withmethodcachecounter - ec = space.getexecutioncontext() - ec.method_cache_misses = {} - ec.method_cache_hits = {} + space.method_cache_misses = {} + space.method_cache_hits = {} Modified: pypy/branch/build-external/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/build-external/pypy/module/_file/interp_file.py (original) +++ pypy/branch/build-external/pypy/module/_file/interp_file.py Tue Jun 10 12:48:46 2008 @@ -63,6 +63,16 @@ space.wrap('I/O operation on closed file')) return stream + def _when_reading_first_flush(self, otherfile): + """Flush otherfile before reading from self.""" + self.stream = streamio.CallbackReadFilter(self.stream, + otherfile._try_to_flush) + + def _try_to_flush(self): + stream = self.stream + if stream is not None: + stream.flush() + # ____________________________________________________________ # # The 'direct_' methods assume that the caller already acquired the Modified: pypy/branch/build-external/pypy/module/_rawffi/test/test__rawffi.py ============================================================================== --- pypy/branch/build-external/pypy/module/_rawffi/test/test__rawffi.py (original) +++ pypy/branch/build-external/pypy/module/_rawffi/test/test__rawffi.py Tue Jun 10 12:48:46 2008 @@ -461,17 +461,16 @@ ll_to_sort[i] = 4-i qsort = libc.ptr('qsort', ['P', 'i', 'i', 'P'], None) resarray = _rawffi.Array('i')(1) - bogus_args = False + bogus_args = [] def compare(a, b): a1 = _rawffi.Array('i').fromaddress(_rawffi.Array('i').fromaddress(a, 1)[0], 1) a2 = _rawffi.Array('i').fromaddress(_rawffi.Array('i').fromaddress(b, 1)[0], 1) + print "comparing", a1[0], "with", a2[0] if a1[0] not in [1,2,3,4] or a2[0] not in [1,2,3,4]: - print "comparing", a1[0], "with", a2[0] - bogus_args = True + bogus_args.append((a1[0], a2[0])) if a1[0] > a2[0]: - res = -1 - res = 1 - return res + return 1 + return -1 a1 = ll_to_sort.byptr() a2 = _rawffi.Array('i')(1) a2[0] = len(ll_to_sort) Modified: pypy/branch/build-external/pypy/module/gc/__init__.py ============================================================================== --- pypy/branch/build-external/pypy/module/gc/__init__.py (original) +++ pypy/branch/build-external/pypy/module/gc/__init__.py Tue Jun 10 12:48:46 2008 @@ -11,4 +11,5 @@ 'enable_finalizers': 'interp_gc.enable_finalizers', 'disable_finalizers': 'interp_gc.disable_finalizers', 'estimate_heap_size': 'interp_gc.estimate_heap_size', + 'garbage' : 'space.newlist([])', } Modified: pypy/branch/build-external/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/branch/build-external/pypy/module/signal/interp_signal.py (original) +++ pypy/branch/build-external/pypy/module/signal/interp_signal.py Tue Jun 10 12:48:46 2008 @@ -31,7 +31,9 @@ pypysig_ignore = external('pypysig_ignore', [rffi.INT], lltype.Void) pypysig_default = external('pypysig_default', [rffi.INT], lltype.Void) pypysig_setflag = external('pypysig_setflag', [rffi.INT], lltype.Void) -pypysig_poll = external('pypysig_poll', [], rffi.INT) +pypysig_poll = external('pypysig_poll', [], rffi.INT, threadsafe=False) +# don't bother releasing the GIL around a call to pypysig_poll: it's +# pointless and a performance issue class CheckSignalAction(Action): """A repeatitive action at the space level, checking if the Modified: pypy/branch/build-external/pypy/module/sys/state.py ============================================================================== --- pypy/branch/build-external/pypy/module/sys/state.py (original) +++ pypy/branch/build-external/pypy/module/sys/state.py Tue Jun 10 12:48:46 2008 @@ -94,6 +94,8 @@ stderr.name = '' self.w_stderr = space.wrap(stderr) + stdin._when_reading_first_flush(stdout) + def getio(space): return space.fromcache(IOState) Modified: pypy/branch/build-external/pypy/module/thread/gil.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/gil.py (original) +++ pypy/branch/build-external/pypy/module/thread/gil.py Tue Jun 10 12:48:46 2008 @@ -5,7 +5,7 @@ # This module adds a global lock to an object space. # If multiple threads try to execute simultaneously in this space, # all but one will be blocked. The other threads get a chance to run -# from time to time, using the executioncontext's XXX +# from time to time, using the hook yield_thread(). from pypy.module.thread import ll_thread as thread from pypy.module.thread.error import wrap_thread_error @@ -16,15 +16,16 @@ class GILThreadLocals(OSThreadLocals): """A version of OSThreadLocals that enforces a GIL.""" - GIL = None + ll_GIL = thread.null_ll_lock def setup_threads(self, space): """Enable threads in the object space, if they haven't already been.""" - if self.GIL is None: + if not self.ll_GIL: try: - self.GIL = thread.allocate_lock_NOAUTO() + self.ll_GIL = thread.allocate_ll_lock() except thread.error: raise wrap_thread_error(space, "can't allocate GIL") + thread.acquire_NOAUTO(self.ll_GIL, True) self.enter_thread(space) # setup the main thread # add the GIL-releasing callback as an action on the space space.pending_actions.append(GILReleaseAction(self)) @@ -40,31 +41,17 @@ # test_lock_again after the global state was cleared by # test_compile_lock. As a workaround, we repatch these global # fields systematically. - spacestate.GIL = self.GIL + spacestate.ll_GIL = self.ll_GIL invoke_around_extcall(before_external_call, after_external_call) return result - def enter_thread(self, space): - "Notification that the current thread is just starting: grab the GIL." - self.GIL.acquire(True) - OSThreadLocals.enter_thread(self, space) - - def leave_thread(self, space): - "Notification that the current thread is stopping: release the GIL." - OSThreadLocals.leave_thread(self, space) - self.GIL.release() - def yield_thread(self): """Notification that the current thread is between two bytecodes: release the GIL for a little while.""" - GIL = self.GIL - # Other threads can run between the release() and the acquire(). - # This is a single external function so that we are sure that nothing - # occurs between the release and the acquire, e.g. no GC operation. - GIL.fused_release_acquire() - - def getGIL(self): - return self.GIL # XXX temporary hack! + # Other threads can run between the release() and the acquire() + # implicit in the following external function call (which has + # otherwise no effect). + thread.yield_thread() class GILReleaseAction(Action): @@ -81,7 +68,9 @@ class SpaceState: - pass + def _freeze_(self): + self.ll_GIL = thread.null_ll_lock + return False spacestate = SpaceState() # Fragile code below. We have to preserve the C-level errno manually... @@ -90,10 +79,13 @@ # this function must not raise, in such a way that the exception # transformer knows that it cannot raise! e = get_errno() - spacestate.GIL.release() + thread.release_NOAUTO(spacestate.ll_GIL) set_errno(e) +before_external_call._gctransformer_hint_cannot_collect_ = True def after_external_call(): e = get_errno() - spacestate.GIL.acquire(True) + thread.acquire_NOAUTO(spacestate.ll_GIL, True) + thread.gc_thread_run() set_errno(e) +after_external_call._gctransformer_hint_cannot_collect_ = True Modified: pypy/branch/build-external/pypy/module/thread/ll_thread.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/ll_thread.py (original) +++ pypy/branch/build-external/pypy/module/thread/ll_thread.py Tue Jun 10 12:48:46 2008 @@ -6,16 +6,19 @@ from pypy.rpython.annlowlevel import cast_instance_to_base_ptr from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rpython.lltypesystem import llmemory -import thread, py, os +import py, os from pypy.rpython.extregistry import ExtRegistryEntry from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem.lltype import typeOf from pypy.rlib.debug import ll_assert +from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.lltypesystem.lloperation import llop from pypy.tool import autopath from distutils import sysconfig python_inc = sysconfig.get_python_inc() -error = thread.error +class error(Exception): + pass eci = ExternalCompilationInfo( includes = ['src/thread.h'], @@ -24,102 +27,75 @@ python_inc], export_symbols = ['RPyThreadGetIdent', 'RPyThreadLockInit', 'RPyThreadAcquireLock', 'RPyThreadReleaseLock', - 'RPyThreadFusedReleaseAcquireLock',] + 'RPyThreadYield'] ) def llexternal(name, args, result, **kwds): + kwds.setdefault('sandboxsafe', True) return rffi.llexternal(name, args, result, compilation_info=eci, **kwds) -CALLBACK = lltype.Ptr(lltype.FuncType([rffi.VOIDP], rffi.VOIDP)) -c_thread_start = llexternal('RPyThreadStart', [CALLBACK, rffi.VOIDP], rffi.INT) -c_thread_get_ident = llexternal('RPyThreadGetIdent', [], rffi.INT) +def _emulated_start_new_thread(func): + "NOT_RPYTHON" + import thread + try: + ident = thread.start_new_thread(func, ()) + except thread.error: + ident = -1 + return rffi.cast(rffi.INT, ident) + +CALLBACK = lltype.Ptr(lltype.FuncType([], lltype.Void)) +c_thread_start = llexternal('RPyThreadStart', [CALLBACK], rffi.INT, + _callable=_emulated_start_new_thread, + threadsafe=True) # release the GIL, but most + # importantly, reacquire it + # around the callback +c_thread_get_ident = llexternal('RPyThreadGetIdent', [], rffi.INT, + _nowrapper=True) # always call directly TLOCKP = rffi.COpaquePtr('struct RPyOpaque_ThreadLock', compilation_info=eci) c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], lltype.Void) c_thread_acquirelock = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], - rffi.INT) -c_thread_releaselock = llexternal('RPyThreadReleaseLock', [TLOCKP], lltype.Void) + rffi.INT, + threadsafe=True) # release the GIL +c_thread_releaselock = llexternal('RPyThreadReleaseLock', [TLOCKP], lltype.Void, + threadsafe=True) # release the GIL # another set of functions, this time in versions that don't cause the # GIL to be released. To use to handle the GIL lock itself. c_thread_acquirelock_NOAUTO = llexternal('RPyThreadAcquireLock', [TLOCKP, rffi.INT], rffi.INT, - threadsafe=False) + _nowrapper=True) c_thread_releaselock_NOAUTO = llexternal('RPyThreadReleaseLock', [TLOCKP], lltype.Void, - threadsafe=False) -c_thread_fused_releaseacquirelock_NOAUTO = llexternal( - 'RPyThreadFusedReleaseAcquireLock', [TLOCKP], lltype.Void, - threadsafe=False) + _nowrapper=True) -def allocate_lock(): - ll_lock = lltype.malloc(TLOCKP.TO, flavor='raw') - res = c_thread_lock_init(ll_lock) - if res == -1: - lltype.free(ll_lock, flavor='raw') - raise error("out of resources") - return Lock(ll_lock) +# this function does nothing apart from releasing the GIL temporarily. +yield_thread = llexternal('RPyThreadYield', [], lltype.Void, threadsafe=True) -def allocate_lock_NOAUTO(): - ll_lock = lltype.malloc(TLOCKP.TO, flavor='raw') - res = c_thread_lock_init(ll_lock) - if res == -1: - lltype.free(ll_lock, flavor='raw') - raise error("out of resources") - return Lock_NOAUTO(ll_lock) - -def _start_new_thread(x, y): - return thread.start_new_thread(x, (y,)) +def allocate_lock(): + return Lock(allocate_ll_lock()) -def ll_start_new_thread(l_func, arg): - l_arg = cast_instance_to_base_ptr(arg) - l_arg = rffi.cast(rffi.VOIDP, l_arg) - ident = c_thread_start(l_func, l_arg) +def ll_start_new_thread(func): + ident = c_thread_start(func) if ident == -1: raise error("can't start new thread") return ident -class LLStartNewThread(ExtRegistryEntry): - _about_ = _start_new_thread - - def compute_result_annotation(self, s_func, s_arg): - bookkeeper = self.bookkeeper - s_result = bookkeeper.emulate_pbc_call(bookkeeper.position_key, - s_func, [s_arg]) - assert annmodel.s_None.contains(s_result) - return annmodel.SomeInteger() - - def specialize_call(self, hop): - rtyper = hop.rtyper - bk = rtyper.annotator.bookkeeper - r_result = rtyper.getrepr(hop.s_result) - hop.exception_is_here() - args_r = [rtyper.getrepr(s_arg) for s_arg in hop.args_s] - _callable = hop.args_s[0].const - funcptr = lltype.functionptr(CALLBACK.TO, _callable.func_name, - _callable=_callable) - func_s = bk.immutablevalue(funcptr) - s_args = [func_s, hop.args_s[1]] - obj = rtyper.getannmixlevel().delayedfunction( - ll_start_new_thread, s_args, annmodel.SomeInteger()) - bootstrap = rtyper.getannmixlevel().delayedfunction( - _callable, [hop.args_s[1]], annmodel.s_None) - vlist = [hop.inputconst(typeOf(obj), obj), - hop.inputconst(typeOf(bootstrap), bootstrap), - #hop.inputarg(args_r[0], 0), - hop.inputarg(args_r[1], 1)] - return hop.genop('direct_call', vlist, r_result) - # wrappers... def get_ident(): - return c_thread_get_ident() + return rffi.cast(lltype.Signed, c_thread_get_ident()) def start_new_thread(x, y): - return _start_new_thread(x, y[0]) + """In RPython, no argument can be passed. You have to use global + variables to pass information to the new thread. That's not very + nice, but at least it avoids some levels of GC issues. + """ + assert len(y) == 0 + return rffi.cast(lltype.Signed, ll_start_new_thread(x)) class Lock(object): """ Container for low-level implementation @@ -129,7 +105,9 @@ self._lock = ll_lock def acquire(self, flag): - return bool(c_thread_acquirelock(self._lock, int(flag))) + res = c_thread_acquirelock(self._lock, int(flag)) + res = rffi.cast(lltype.Signed, res) + return bool(res) def release(self): # Sanity check: the lock must be locked @@ -142,23 +120,58 @@ def __del__(self): lltype.free(self._lock, flavor='raw') -class Lock_NOAUTO(object): - """A special lock that doesn't cause the GIL to be released when - we try to acquire it. Used for the GIL itself.""" +# ____________________________________________________________ +# +# GIL support wrappers - def __init__(self, ll_lock): - self._lock = ll_lock - - def acquire(self, flag): - return bool(c_thread_acquirelock_NOAUTO(self._lock, int(flag))) +null_ll_lock = lltype.nullptr(TLOCKP.TO) - def release(self): - ll_assert(not self.acquire(False), "Lock_NOAUTO was not held!") - c_thread_releaselock_NOAUTO(self._lock) +def allocate_ll_lock(): + ll_lock = lltype.malloc(TLOCKP.TO, flavor='raw') + res = c_thread_lock_init(ll_lock) + if res == -1: + lltype.free(ll_lock, flavor='raw') + raise error("out of resources") + return ll_lock - def fused_release_acquire(self): - ll_assert(not self.acquire(False), "Lock_NOAUTO was not held!") - c_thread_fused_releaseacquirelock_NOAUTO(self._lock) +def acquire_NOAUTO(ll_lock, flag): + flag = rffi.cast(rffi.INT, int(flag)) + res = c_thread_acquirelock_NOAUTO(ll_lock, flag) + res = rffi.cast(lltype.Signed, res) + return bool(res) + +def release_NOAUTO(ll_lock): + if not we_are_translated(): + ll_assert(not acquire_NOAUTO(ll_lock, False), "NOAUTO lock not held!") + c_thread_releaselock_NOAUTO(ll_lock) + +# ____________________________________________________________ +# +# Thread integration. +# These are three completely ad-hoc operations at the moment. + +def gc_thread_prepare(): + """To call just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if we_are_translated(): + llop.gc_thread_prepare(lltype.Void) - def __del__(self): - lltype.free(self._lock, flavor='raw') +def gc_thread_run(): + """To call whenever the current thread (re-)acquired the GIL. + """ + if we_are_translated(): + llop.gc_thread_run(lltype.Void) +gc_thread_run._always_inline_ = True + +def gc_thread_die(): + """To call just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + if we_are_translated(): + llop.gc_thread_die(lltype.Void) +gc_thread_die._always_inline_ = True Modified: pypy/branch/build-external/pypy/module/thread/os_thread.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/os_thread.py (original) +++ pypy/branch/build-external/pypy/module/thread/os_thread.py Tue Jun 10 12:48:46 2008 @@ -9,38 +9,107 @@ from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments from pypy.rlib.objectmodel import free_non_gc_object -# This code has subtle memory management issues in order to start -# a new thread. It should work correctly with Boehm, but the framework -# GC will not see the references stored in the raw-malloced Bootstrapper -# instances => crash. It crashes with refcounting too -# (see the skipped test_raw_instance_flavor in -# rpython/memory/gctransformer/test/test_refcounting). +# Here are the steps performed to start a new thread: +# +# * The bootstrapper.lock is first acquired to prevent two parallel +# starting threads from messing with each other's start-up data. +# +# * The start-up data (the app-level callable and arguments) is +# stored in the global bootstrapper object. +# +# * The GC is notified that a new thread is about to start; in the +# framework GC, this allocates a fresh new shadow stack (but doesn't +# use it yet). See gc_thread_prepare(). +# +# * The new thread is launched at RPython level using an rffi call +# to the C function RPyThreadStart() defined in +# translator/c/src/thread*.h. This RPython thread will invoke the +# static method bootstrapper.bootstrap() as a call-back. +# +# * As if it was a regular callback, rffi adds a wrapper around +# bootstrap(). This wrapper acquires and releases the GIL. In this +# way the new thread is immediately GIL-protected. +# +# * As soon as the GIL is acquired in the new thread, the gc_thread_run() +# operation is called (this is all done by gil.after_external_call(), +# called from the rffi-generated wrapper). The gc_thread_run() +# operation will automatically notice that the current thread id was +# not seen before, and start using the freshly prepared shadow stack. +# +# * Only then does bootstrap() really run. The first thing it does +# is grab the start-up information (app-level callable and args) +# out of the global bootstrapper object and release bootstrapper.lock. +# Then it calls the app-level callable, to actually run the thread. +# +# * After each potential thread switch, as soon as the GIL is re-acquired, +# gc_thread_run() is called again; it ensures that the currently +# installed shadow stack is the correct one for the currently running +# thread. +# +# * Just before a thread finishes, gc_thread_die() is called to free +# its shadow stack. + class Bootstrapper(object): - _alloc_flavor_ = 'raw' - - def bootstrap(self): - space = self.space + "A global container used to pass information to newly starting threads." + + # Passing a closure argument to ll_thread.start_new_thread() would be + # theoretically nicer, but comes with messy memory management issues. + # This is much more straightforward. + + # The following lock is held whenever the fields + # 'bootstrapper.w_callable' and 'bootstrapper.args' are in use. + lock = None + + def setup(space): + if bootstrapper.lock is None: + try: + bootstrapper.lock = thread.allocate_lock() + except thread.error: + raise wrap_thread_error(space, "can't allocate bootstrap lock") + setup = staticmethod(setup) + + def bootstrap(): + # Note that when this runs, we already hold the GIL. This is ensured + # by rffi's callback mecanism: we are a callback for the + # c_thread_start() external function. + space = bootstrapper.space + w_callable = bootstrapper.w_callable + args = bootstrapper.args + bootstrapper.release() + # run! space.threadlocals.enter_thread(space) try: - self.run() + bootstrapper.run(space, w_callable, args) finally: - # release ownership of these objects before we release the GIL. - # (for the refcounting gc it is necessary to reset the fields to - # None before we use free_non_gc_object(), because the latter - # doesn't know that it needs to decref the fields) - self.args = None - self.w_callable = None - # we can free the empty 'self' structure now - free_non_gc_object(self) # clean up space.threadlocals to remove the ExecutionContext - # entry corresponding to the current thread and release the GIL - space.threadlocals.leave_thread(space) + # entry corresponding to the current thread + try: + space.threadlocals.leave_thread(space) + finally: + thread.gc_thread_die() + bootstrap = staticmethod(bootstrap) + + def acquire(space, w_callable, args): + # If the previous thread didn't start yet, wait until it does. + # Note that bootstrapper.lock must be a regular lock, not a NOAUTO + # lock, because the GIL must be released while we wait. + bootstrapper.lock.acquire(True) + bootstrapper.space = space + bootstrapper.w_callable = w_callable + bootstrapper.args = args + acquire = staticmethod(acquire) + + def release(): + # clean up 'bootstrapper' to make it ready for the next + # start_new_thread() and release the lock to tell that there + # isn't any bootstrapping thread left. + bootstrapper.w_callable = None + bootstrapper.args = None + bootstrapper.lock.release() + release = staticmethod(release) - def run(self): - space = self.space - w_callable = self.w_callable - args = self.args + def run(space, w_callable, args): try: space.call_args(w_callable, args) except OperationError, e: @@ -49,10 +118,14 @@ where = 'thread %d started by ' % ident e.write_unraisable(space, where, w_callable) e.clear(space) + run = staticmethod(run) + +bootstrapper = Bootstrapper() def setup_threads(space): space.threadlocals.setup_threads(space) + bootstrapper.setup(space) def start_new_thread(space, w_callable, w_args, w_kwargs=NoneNotWrapped): @@ -74,12 +147,14 @@ space.wrap("first arg must be callable")) args = Arguments.frompacked(space, w_args, w_kwargs) - boot = Bootstrapper() - boot.space = space - boot.w_callable = w_callable - boot.args = args + bootstrapper.acquire(space, w_callable, args) try: - ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,)) + try: + thread.gc_thread_prepare() + ident = thread.start_new_thread(bootstrapper.bootstrap, ()) + except Exception, e: + bootstrapper.release() # normally called by the new thread + raise except thread.error: raise wrap_thread_error(space, "can't start new thread") return space.wrap(ident) Modified: pypy/branch/build-external/pypy/module/thread/test/support.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/test/support.py (original) +++ pypy/branch/build-external/pypy/module/thread/test/support.py Tue Jun 10 12:48:46 2008 @@ -2,6 +2,7 @@ import time, gc from pypy.conftest import gettestobjspace, option from pypy.interpreter.gateway import ObjSpace, W_Root, interp2app_temp +from pypy.module.thread import gil NORMAL_TIMEOUT = 300.0 # 5 minutes @@ -10,10 +11,9 @@ adaptivedelay = 0.04 limit = time.time() + delay * NORMAL_TIMEOUT while time.time() <= limit: - GIL = space.threadlocals.GIL - GIL.release() + gil.before_external_call() time.sleep(adaptivedelay) - GIL.acquire(True) + gil.after_external_call() gc.collect() if space.is_true(space.call_function(w_condition)): return Modified: pypy/branch/build-external/pypy/module/thread/test/test_ll_thread.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/test/test_ll_thread.py (original) +++ pypy/branch/build-external/pypy/module/thread/test/test_ll_thread.py Tue Jun 10 12:48:46 2008 @@ -1,11 +1,15 @@ - +import gc from pypy.module.thread.ll_thread import * from pypy.translator.c.test.test_boehm import AbstractGCTestClass -from pypy.rpython.lltypesystem import lltype -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.objectmodel import free_non_gc_object +from pypy.rpython.lltypesystem import lltype, rffi import py +def setup_module(mod): + # Hack to avoid a deadlock if the module is run after other test files :-( + # In this module, we assume that ll_thread.start_new_thread() is not + # providing us with a GIL equivalent. + rffi.aroundstate._freeze_() + def test_lock(): l = allocate_lock() ok1 = l.acquire(True) @@ -24,19 +28,9 @@ else: py.test.fail("Did not raise") -def test_fused(): - l = allocate_lock_NOAUTO() - l.acquire(True) - l.fused_release_acquire() - could_acquire_again = l.acquire(False) - assert not could_acquire_again - l.release() - could_acquire_again = l.acquire(False) - assert could_acquire_again - -class TestUsingBoehm(AbstractGCTestClass): - gcpolicy = 'boehm' +class AbstractThreadTests(AbstractGCTestClass): + use_threads = True def test_start_new_thread(self): import time @@ -51,21 +45,16 @@ def __del__(self): state.freed_counter += 1 - class Y: - _alloc_flavor_ = 'raw' - - def bootstrap(self): - state.my_thread_ident = get_ident() - assert state.my_thread_ident == get_ident() - state.seen_value = self.z.value - self.z = None - free_non_gc_object(self) - state.done = 1 + def bootstrap(): + state.my_thread_ident = get_ident() + assert state.my_thread_ident == get_ident() + state.seen_value = state.z.value + state.z = None + state.done = 1 def g(i): - y = Y() - y.z = Z(i) - start_new_thread(Y.bootstrap, (y,)) + state.z = Z(i) + start_new_thread(bootstrap, ()) g._dont_inline_ = True def f(): @@ -76,6 +65,7 @@ state.done = 0 state.seen_value = 0 g(i) + gc.collect() willing_to_wait_more = 1000 while not state.done: willing_to_wait_more -= 1 @@ -86,7 +76,7 @@ assert state.seen_value == i # try to force Boehm to do some freeing for i in range(3): - llop.gc__collect(lltype.Void) + gc.collect() return state.freed_counter fn = self.getcompiled(f, []) @@ -110,34 +100,43 @@ self.j = j def run(self): j = self.j - state.gil.acquire(True) - assert j == self.j if self.i > 1: g(self.i-1, self.j * 2) + assert j == self.j g(self.i-2, self.j * 2 + 1) else: - state.answers.append(self.i) - assert j == self.j - state.gil.release() + if len(state.answers) % 7 == 5: + gc.collect() + state.answers.append(self.j) assert j == self.j run._dont_inline_ = True - class Y(object): - _alloc_flavor_ = 'raw' - def bootstrap(self): - self.z.run() - self.z = None - free_non_gc_object(self) - state.done = 1 + def bootstrap(): + acquire_NOAUTO(state.gil, True) + gc_thread_run() + z = state.z + state.z = None + z.run() + gc_thread_die() + release_NOAUTO(state.gil) def g(i, j): - y = Y() - y.z = Z(i, j) - start_new_thread(Y.bootstrap, (y,)) - g._dont_inline_ = True + state.z = Z(i, j) + gc_thread_prepare() + start_new_thread(bootstrap, ()) + # now wait until the new thread really started and consumed 'z' + willing_to_wait_more = 1000 + while state.z is not None: + assert willing_to_wait_more > 0 + willing_to_wait_more -= 1 + release_NOAUTO(state.gil) + time.sleep(0.005) + acquire_NOAUTO(state.gil, True) + gc_thread_run() def f(): - state.gil = allocate_lock_NOAUTO() + state.gil = allocate_ll_lock() + acquire_NOAUTO(state.gil, True) state.answers = [] state.finished = 0 g(7, 1) @@ -149,10 +148,12 @@ " expected %d" % (len(state.answers), expected)) willing_to_wait_more -= 1 - state.gil.acquire(True) done = len(state.answers) == expected - state.gil.release() + release_NOAUTO(state.gil) time.sleep(0.01) + acquire_NOAUTO(state.gil, True) + gc_thread_run() + release_NOAUTO(state.gil) time.sleep(0.1) return len(state.answers) @@ -161,8 +162,12 @@ answers = fn() assert answers == expected -class TestUsingFramework(TestUsingBoehm): - gcpolicy = 'generation' +class TestRunDirectly(AbstractThreadTests): + def getcompiled(self, f, argtypes): + return f - def test_gc_locking(self): - py.test.skip("in-progress") +class TestUsingBoehm(AbstractThreadTests): + gcpolicy = 'boehm' + +class TestUsingFramework(AbstractThreadTests): + gcpolicy = 'generation' Modified: pypy/branch/build-external/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/branch/build-external/pypy/module/thread/threadlocals.py (original) +++ pypy/branch/build-external/pypy/module/thread/threadlocals.py Tue Jun 10 12:48:46 2008 @@ -9,10 +9,19 @@ def __init__(self): self._valuedict = {} # {thread_ident: ExecutionContext()} self._mainthreadident = 0 + self._mostrecentkey = 0 # fast minicaching for the common case + self._mostrecentvalue = None # fast minicaching for the common case def getvalue(self): ident = thread.get_ident() - return self._valuedict.get(ident, None) + if ident == self._mostrecentkey: + return self._mostrecentvalue + else: + value = self._valuedict.get(ident, None) + # slow path: update the minicache + self._mostrecentkey = ident + self._mostrecentvalue = value + return value def setvalue(self, value): ident = thread.get_ident() @@ -25,6 +34,9 @@ del self._valuedict[ident] except KeyError: pass + # update the minicache to prevent it from containing an outdated value + self._mostrecentkey = ident + self._mostrecentvalue = value def getmainthreadvalue(self): ident = self._mainthreadident @@ -52,7 +64,3 @@ def atthreadexit(self, space, exit_func, w_obj): ec = space.getexecutioncontext() ec.thread_exit_funcs.append((exit_func, w_obj)) - - def getGIL(self): - return None - Modified: pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py ============================================================================== --- pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py (original) +++ pypy/branch/build-external/pypy/module/zipimport/interp_zipimport.py Tue Jun 10 12:48:46 2008 @@ -106,6 +106,7 @@ 'zip_dict', __getitem__ = interp2app(W_ZipCache.getitem), __contains__ = interp2app(W_ZipCache.contains), + __iter__ = interp2app(W_ZipCache.iterkeys), items = interp2app(W_ZipCache.items), iteritems = interp2app(W_ZipCache.iteritems), keys = interp2app(W_ZipCache.keys), @@ -143,10 +144,10 @@ w = space.wrap w_mod = w(Module(space, w(modname))) real_name = self.name + os.path.sep + filename + space.setattr(w_mod, w('__loader__'), space.wrap(self)) importing._prepare_module(space, w_mod, real_name, pkgpath) result = importing.load_source_module(space, w(modname), w_mod, filename, buf, write_pyc=False) - space.setattr(w_mod, w('__loader__'), space.wrap(self)) return result def _parse_mtime(self, space, filename): @@ -191,11 +192,11 @@ buf = buf[8:] # XXX ugly copy, should use sequential read instead w_mod = w(Module(space, w(modname))) real_name = self.name + os.path.sep + filename + space.setattr(w_mod, w('__loader__'), space.wrap(self)) importing._prepare_module(space, w_mod, real_name, pkgpath) result = importing.load_compiled_module(space, w(modname), w_mod, filename, magic, timestamp, buf) - space.setattr(w_mod, w('__loader__'), space.wrap(self)) return result def have_modulefile(self, space, filename): Modified: pypy/branch/build-external/pypy/module/zipimport/test/test_zipimport.py ============================================================================== --- pypy/branch/build-external/pypy/module/zipimport/test/test_zipimport.py (original) +++ pypy/branch/build-external/pypy/module/zipimport/test/test_zipimport.py Tue Jun 10 12:48:46 2008 @@ -234,6 +234,16 @@ assert archive == self.zipfile assert importer.prefix == prefix + def test_zip_directory_cache(self): + """ Check full dictionary interface + """ + import os + import zipimport + self.writefile( + self, os.sep.join(("directory", "package", "__init__.py")), "") + importer = zipimport.zipimporter(self.zipfile + "/directory") + l = [i for i in zipimport._zip_directory_cache] + assert len(l) class AppTestZipimportDeflated(AppTestZipimport): compression = ZIP_DEFLATED Modified: pypy/branch/build-external/pypy/objspace/descroperation.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/descroperation.py (original) +++ pypy/branch/build-external/pypy/objspace/descroperation.py Tue Jun 10 12:48:46 2008 @@ -460,10 +460,20 @@ # __xxx__ and __rxxx__ methods where found by identity. # Note that space.is_w() is potentially not happy if one of them # is None (e.g. with the thunk space)... - if (w_left_src is not w_right_src # XXX - and space.is_true(space.issubtype(w_typ2, w_typ1))): - w_obj1, w_obj2 = w_obj2, w_obj1 - w_left_impl, w_right_impl = w_right_impl, w_left_impl + if w_left_src is not w_right_src: # XXX + # -- cpython bug compatibility: see objspace/std/test/ + # -- test_unicodeobject.test_str_unicode_concat_overrides. + # -- The following handles "unicode + string subclass" by + # -- pretending that the unicode is a superclass of the + # -- string, thus giving priority to the string subclass' + # -- __radd__() method. The case "string + unicode subclass" + # -- is handled directly by add__String_Unicode(). + if symbol == '+' and space.is_w(w_typ1, space.w_unicode): + w_typ1 = space.w_basestring + # -- end of bug compatibility + if space.is_true(space.issubtype(w_typ2, w_typ1)): + w_obj1, w_obj2 = w_obj2, w_obj1 + w_left_impl, w_right_impl = w_right_impl, w_left_impl w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2) if w_res is not None: Modified: pypy/branch/build-external/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/flow/flowcontext.py (original) +++ pypy/branch/build-external/pypy/objspace/flow/flowcontext.py Tue Jun 10 12:48:46 2008 @@ -1,3 +1,4 @@ +import collections from pypy.interpreter.executioncontext import ExecutionContext from pypy.interpreter.error import OperationError from pypy.interpreter import pyframe @@ -209,7 +210,7 @@ #for joinpoint in code.getjoinpoints(): # self.joinpoints[joinpoint] = [] # list of blocks initialblock = SpamBlock(FrameState(frame).copy()) - self.pendingblocks = [initialblock] + self.pendingblocks = collections.deque([initialblock]) self.graph = FunctionGraph(name or code.co_name, initialblock) make_link = Link # overridable for transition tracking @@ -251,7 +252,7 @@ def build_flow(self): while self.pendingblocks: - block = self.pendingblocks.pop(0) + block = self.pendingblocks.popleft() frame = self.create_frame() try: self.recorder = block.patchframe(frame) Modified: pypy/branch/build-external/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/std/objspace.py (original) +++ pypy/branch/build-external/pypy/objspace/std/objspace.py Tue Jun 10 12:48:46 2008 @@ -280,6 +280,16 @@ from pypy.objspace.std import builtinshortcut builtinshortcut.install_is_true(self, self.MM.nonzero, self.MM.len) + # set up the method cache + if self.config.objspace.std.withmethodcache: + SIZE = 1 << self.config.objspace.std.methodcachesizeexp + self.method_cache_versions = [None] * SIZE + self.method_cache_names = [None] * SIZE + self.method_cache_lookup_where = [(None, None)] * SIZE + if self.config.objspace.std.withmethodcachecounter: + self.method_cache_hits = {} + self.method_cache_misses = {} + # hack to avoid imports in the time-critical functions below for cls in self.model.typeorder: globals()[cls.__name__] = cls @@ -419,14 +429,6 @@ # execution context themselves (e.g. nearly all space methods) ec = ObjSpace.createexecutioncontext(self) ec._py_repr = None - if self.config.objspace.std.withmethodcache: - SIZE = 1 << self.config.objspace.std.methodcachesizeexp - ec.method_cache_versions = [None] * SIZE - ec.method_cache_names = [None] * SIZE - ec.method_cache_lookup_where = [(None, None)] * SIZE - if self.config.objspace.std.withmethodcachecounter: - ec.method_cache_hits = {} - ec.method_cache_misses = {} return ec def createframe(self, code, w_globals, closure=None): Modified: pypy/branch/build-external/pypy/objspace/std/test/test_unicodeobject.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/std/test/test_unicodeobject.py (original) +++ pypy/branch/build-external/pypy/objspace/std/test/test_unicodeobject.py Tue Jun 10 12:48:46 2008 @@ -262,6 +262,11 @@ assert unicode(None) == u'None' assert unicode(123) == u'123' assert unicode([2, 3]) == u'[2, 3]' + class U(unicode): + pass + assert unicode(U()).__class__ is unicode + assert U(u'test') == u'test' + assert U(u'test').__class__ is U def test_call_unicode(self): skip("does not work") @@ -554,3 +559,63 @@ '\x00X\x00Y', 'X\x00\x00\x00Y\x00\x00\x00', '\x00\x00\x00X\x00\x00\x00Y'] + + def test_call_special_methods(self): + # xxx not completely clear if these are implementation details or not + assert 'abc'.__add__(u'def') == u'abcdef' + assert u'abc'.__add__(u'def') == u'abcdef' + assert u'abc'.__add__('def') == u'abcdef' + # xxx CPython has no str.__radd__ and no unicode.__radd__ + + def test_str_unicode_concat_overrides(self): + "Test from Jython about being bug-compatible with CPython." + + def check(value, expected): + assert type(value) == type(expected) + assert value == expected + + def _test_concat(t1, t2): + tprecedent = str + if issubclass(t1, unicode) or issubclass(t2, unicode): + tprecedent = unicode + + class SubclassB(t2): + def __add__(self, other): + return SubclassB(t2(self) + t2(other)) + check(SubclassB('py') + SubclassB('thon'), SubclassB('python')) + check(t1('python') + SubclassB('3'), tprecedent('python3')) + check(SubclassB('py') + t1('py'), SubclassB('pypy')) + + class SubclassC(t2): + def __radd__(self, other): + return SubclassC(t2(other) + t2(self)) + check(SubclassC('stack') + SubclassC('less'), t2('stackless')) + check(t1('iron') + SubclassC('python'), SubclassC('ironpython')) + check(SubclassC('tiny') + t1('py'), tprecedent('tinypy')) + + class SubclassD(t2): + def __add__(self, other): + return SubclassD(t2(self) + t2(other)) + + def __radd__(self, other): + return SubclassD(t2(other) + t2(self)) + check(SubclassD('di') + SubclassD('ct'), SubclassD('dict')) + check(t1('list') + SubclassD(' comp'), SubclassD('list comp')) + check(SubclassD('dun') + t1('der'), SubclassD('dunder')) + + _test_concat(str, str) + _test_concat(unicode, unicode) + # the following two cases are really there to emulate a CPython bug. + _test_concat(str, unicode) # uses hack in add__String_Unicode() + _test_concat(unicode, str) # uses hack in descroperation.binop_impl() + + def test_returns_subclass(self): + class X(unicode): + pass + + class Y(object): + def __unicode__(self): + return X("stuff") + + assert unicode(Y()).__class__ is X + Modified: pypy/branch/build-external/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/branch/build-external/pypy/objspace/std/test/test_userobject.py Tue Jun 10 12:48:46 2008 @@ -207,6 +207,11 @@ s = repr(Foo()) assert s.startswith('> SHIFT - cached_version_tag = ec.method_cache_versions[method_hash] + cached_version_tag = space.method_cache_versions[method_hash] if cached_version_tag is version_tag: - cached_name = ec.method_cache_names[method_hash] + cached_name = space.method_cache_names[method_hash] if cached_name is name: - tup = ec.method_cache_lookup_where[method_hash] + tup = space.method_cache_lookup_where[method_hash] if space.config.objspace.std.withmethodcachecounter: - ec.method_cache_hits[name] = \ - ec.method_cache_hits.get(name, 0) + 1 + space.method_cache_hits[name] = \ + space.method_cache_hits.get(name, 0) + 1 # print "hit", w_self, name return tup tup = w_self._lookup_where(name) - ec.method_cache_versions[method_hash] = version_tag - ec.method_cache_names[method_hash] = name - ec.method_cache_lookup_where[method_hash] = tup + space.method_cache_versions[method_hash] = version_tag + space.method_cache_names[method_hash] = name + space.method_cache_lookup_where[method_hash] = tup if space.config.objspace.std.withmethodcachecounter: - ec.method_cache_misses[name] = \ - ec.method_cache_misses.get(name, 0) + 1 + space.method_cache_misses[name] = \ + space.method_cache_misses.get(name, 0) + 1 # print "miss", w_self, name return tup Modified: pypy/branch/build-external/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/build-external/pypy/objspace/std/unicodeobject.py Tue Jun 10 12:48:46 2008 @@ -100,14 +100,28 @@ return W_UnicodeObject(w_left._value + w_right._value) def add__String_Unicode(space, w_left, w_right): + # this function is needed to make 'abc'.__add__(u'def') return + # u'abcdef' instead of NotImplemented. This is what occurs on + # top of CPython. from pypy.objspace.std.unicodetype import unicode_from_string + # XXX fragile implementation detail: for "string + unicode subclass", + # if the unicode subclass overrides __radd__(), then it will be + # called (see test_str_unicode_concat_overrides). This occurs as a + # result of the following call to space.add() in which the first + # argument is a unicode and the second argument a subclass of unicode + # (and thus the usual logic about calling __radd__() first applies). return space.add(unicode_from_string(space, w_left) , w_right) add__Rope_Unicode = add__String_Unicode def add__Unicode_String(space, w_left, w_right): + # this function is needed to make 'abc'.__radd__(u'def') return + # u'defabc', although it's completely unclear if that's necessary + # given that CPython doesn't even have a method str.__radd__(). from pypy.objspace.std.unicodetype import unicode_from_string return space.add(w_left, unicode_from_string(space, w_right)) + # Note about "unicode + string subclass": look for + # "cpython bug compatibility" in descroperation.py add__Unicode_Rope = add__Unicode_String Modified: pypy/branch/build-external/pypy/objspace/std/unicodetype.py ============================================================================== --- pypy/branch/build-external/pypy/objspace/std/unicodetype.py (original) +++ pypy/branch/build-external/pypy/objspace/std/unicodetype.py Tue Jun 10 12:48:46 2008 @@ -251,25 +251,25 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.ropeunicodeobject import W_RopeUnicodeObject w_obj = w_string - w_obj_type = space.type(w_obj) encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) - if space.is_w(w_obj_type, space.w_unicode): + if space.is_true(space.isinstance(w_obj, space.w_unicode)): if encoding is not None or errors is not None: raise OperationError(space.w_TypeError, space.wrap('decoding Unicode is not supported')) - if space.is_w(w_unicodetype, space.w_unicode): - return w_obj w_value = w_obj - elif encoding is None and errors is None: - if space.is_true(space.isinstance(w_obj, space.w_str)): - w_value = unicode_from_string(space, w_obj) - elif space.is_true(space.isinstance(w_obj, space.w_unicode)): - w_value = w_obj - else: - w_value = unicode_from_object(space, w_obj) else: - w_value = unicode_from_encoded_object(space, w_obj, encoding, errors) + if encoding is None and errors is None: + if space.is_true(space.isinstance(w_obj, space.w_str)): + w_value = unicode_from_string(space, w_obj) + else: + w_value = unicode_from_object(space, w_obj) + else: + w_value = unicode_from_encoded_object(space, w_obj, + encoding, errors) + if space.is_w(w_unicodetype, space.w_unicode): + return w_value + if space.config.objspace.std.withropeunicode: assert isinstance(w_value, W_RopeUnicodeObject) w_newobj = space.allocate_instance(W_RopeUnicodeObject, w_unicodetype) Modified: pypy/branch/build-external/pypy/rlib/_rsocket_rffi.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/_rsocket_rffi.py (original) +++ pypy/branch/build-external/pypy/rlib/_rsocket_rffi.py Tue Jun 10 12:48:46 2008 @@ -53,7 +53,7 @@ constants = {} eci = ExternalCompilationInfo( - pre_include_lines = (HEADER + COND_HEADER).split("\n"), + post_include_bits = [HEADER, COND_HEADER], includes = includes, libraries = libraries, ) Modified: pypy/branch/build-external/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/libffi.py (original) +++ pypy/branch/build-external/pypy/rlib/libffi.py Tue Jun 10 12:48:46 2008 @@ -37,7 +37,7 @@ else: libffidir = py.path.local(pypydir).join('translator', 'c', 'src', 'libffi_msvc') eci = ExternalCompilationInfo( - pre_include_lines = ['#define _WIN32_WINNT 0x501'], + pre_include_bits = ['#define _WIN32_WINNT 0x501'], includes = ['ffi.h', 'windows.h'], libraries = ['kernel32'], include_dirs = [libffidir], Modified: pypy/branch/build-external/pypy/rlib/rmmap.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/rmmap.py (original) +++ pypy/branch/build-external/pypy/rlib/rmmap.py Tue Jun 10 12:48:46 2008 @@ -31,9 +31,9 @@ class CConfig: _compilation_info_ = ExternalCompilationInfo( includes=includes, - pre_include_lines=['#ifndef _GNU_SOURCE', - '#define _GNU_SOURCE', - '#endif'] + pre_include_bits=['#ifndef _GNU_SOURCE\n' + + '#define _GNU_SOURCE\n' + + '#endif'] ) size_t = rffi_platform.SimpleType("size_t", rffi.LONG) off_t = rffi_platform.SimpleType("off_t", rffi.LONG) @@ -52,9 +52,9 @@ }""" _compilation_info_ = ExternalCompilationInfo( includes=includes, - pre_include_lines=['#ifndef _GNU_SOURCE', - '#define _GNU_SOURCE', - '#endif'], + pre_include_bits=['#ifndef _GNU_SOURCE\n' + + '#define _GNU_SOURCE\n' + + '#endif'], separate_module_sources=[code], ) PAGESIZE = rffi_platform.ConstantInteger("get_page_size()") Modified: pypy/branch/build-external/pypy/rlib/rposix.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/rposix.py (original) +++ pypy/branch/build-external/pypy/rlib/rposix.py Tue Jun 10 12:48:46 2008 @@ -1,6 +1,6 @@ import os from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT -from pypy.rpython.lltypesystem import lltype, ll2ctypes +from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rlib.rarithmetic import intmask @@ -22,12 +22,19 @@ includes=['errno.h'] ) -_get_errno, set_errno = CExternVariable(INT, 'errno', errno_eci, - CConstantErrno, sandboxsafe=True) +_get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci, + CConstantErrno, sandboxsafe=True, + _nowrapper=True) +# the default wrapper for set_errno is not suitable for use in critical places +# like around GIL handling logic, so we provide our own wrappers. def get_errno(): return intmask(_get_errno()) +def set_errno(errno): + _set_errno(rffi.cast(INT, errno)) + + def closerange(fd_low, fd_high): # this behaves like os.closerange() from Python 2.6. for fd in xrange(fd_low, fd_high): Modified: pypy/branch/build-external/pypy/rlib/rstruct/nativefmttable.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/rstruct/nativefmttable.py (original) +++ pypy/branch/build-external/pypy/rlib/rstruct/nativefmttable.py Tue Jun 10 12:48:46 2008 @@ -79,18 +79,18 @@ 'd': 'double', } - pre_include_lines = [] + pre_include_bits = [] for fmtchar, ctype in INSPECT.items(): - pre_include_lines += (""" + pre_include_bits.append(""" struct about_%s { char pad; %s field; }; - """ % (fmtchar, ctype)).split("\n") + """ % (fmtchar, ctype)) class CConfig: _compilation_info_ = ExternalCompilationInfo( - pre_include_lines = pre_include_lines + pre_include_bits = pre_include_bits ) for fmtchar, ctype in INSPECT.items(): Modified: pypy/branch/build-external/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/streamio.py (original) +++ pypy/branch/build-external/pypy/rlib/streamio.py Tue Jun 10 12:48:46 2008 @@ -944,6 +944,32 @@ flush_buffers=False) +class CallbackReadFilter(Stream): + """Pseudo read filter that invokes a callback before blocking on a read. + """ + + def __init__(self, base, callback): + self.base = base + self.callback = callback + + def flush_buffers(self): + self.callback() + + tell = PassThrough("tell", flush_buffers=False) + seek = PassThrough("seek", flush_buffers=False) + read = PassThrough("read", flush_buffers=True) + readall = PassThrough("readall", flush_buffers=True) + readline = PassThrough("readline", flush_buffers=True) + peek = PassThrough("peek", flush_buffers=False) + flush = PassThrough("flush", flush_buffers=False) + flushable = PassThrough("flushable", flush_buffers=False) + close = PassThrough("close", flush_buffers=False) + write = PassThrough("write", flush_buffers=False) + truncate = PassThrough("truncate", flush_buffers=False) + getnewlines= PassThrough("getnewlines",flush_buffers=False) + try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", + flush_buffers=False) + # _________________________________________________ # The following functions are _not_ RPython! Modified: pypy/branch/build-external/pypy/rlib/test/test_libffi.py ============================================================================== --- pypy/branch/build-external/pypy/rlib/test/test_libffi.py (original) +++ pypy/branch/build-external/pypy/rlib/test/test_libffi.py Tue Jun 10 12:48:46 2008 @@ -362,6 +362,10 @@ assert not ALLOCATED class TestWin32Handles: + def setup_class(cls): + if sys.platform != 'win32': + py.test.skip("Win-only test") + def test_get_libc_handle(self): handle = get_libc_handle() print get_libc_name() Modified: pypy/branch/build-external/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/llinterp.py (original) +++ pypy/branch/build-external/pypy/rpython/llinterp.py Tue Jun 10 12:48:46 2008 @@ -774,6 +774,15 @@ addr = llmemory.cast_ptr_to_adr(ptr) return self.heap.can_move(addr) + def op_gc_thread_prepare(self): + self.heap.thread_prepare() + + def op_gc_thread_run(self): + self.heap.thread_run() + + def op_gc_thread_die(self): + self.heap.thread_die() + def op_gc_free(self, addr): # what can you do? pass Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/llheap.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/llheap.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/llheap.py Tue Jun 10 12:48:46 2008 @@ -34,3 +34,12 @@ for i in range(final_size): ll_str.chars[i] = buf.chars[i] return ll_str + +def thread_prepare(): + pass + +def thread_run(): + pass + +def thread_die(): + pass Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/lloperation.py Tue Jun 10 12:48:46 2008 @@ -406,6 +406,9 @@ 'gc_id': LLOp(canraise=(MemoryError,), sideeffects=False), 'gc_set_max_heap_size': LLOp(), 'gc_can_move' : LLOp(sideeffects=False), + 'gc_thread_prepare' : LLOp(canraise=(MemoryError,)), + 'gc_thread_run' : LLOp(), + 'gc_thread_die' : LLOp(), # experimental operations in support of thread cloning, only # implemented by the Mark&Sweep GC 'gc_x_swap_pool': LLOp(canraise=(MemoryError,), canunwindgc=True), Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/rffi.py Tue Jun 10 12:48:46 2008 @@ -146,6 +146,10 @@ if before: before() # NB. it is essential that no exception checking occurs after # the call to before(), because we don't have the GIL any more! + # It is also essential that no GC pointer is alive between now + # and the end of the function, so that the external function + # calls below don't need to be guarded by GC shadow stack logic + # that would crash if not protected by the GIL! res = funcptr(*real_args) if invoke_around_handlers: if after: after() @@ -159,7 +163,12 @@ return cast(lltype.Unsigned, res) return res wrapper._annspecialcase_ = 'specialize:ll' - wrapper._always_inline_ = True + if invoke_around_handlers: + # don't inline, as a hack to guarantee that no GC pointer is alive + # in the final part of the wrapper + wrapper._dont_inline_ = True + else: + wrapper._always_inline_ = True # for debugging, stick ll func ptr to that wrapper._ptr = funcptr @@ -173,16 +182,16 @@ errorcode = callable._errorcode_ else: errorcode = TP.TO.RESULT._example() - if aroundstate is not None: - before = aroundstate.before - after = aroundstate.after - else: - before = None - after = None callable_name = getattr(callable, '__name__', '?') args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple + if aroundstate is not None: + before = aroundstate.before + after = aroundstate.after + else: + before = None + after = None if after: after() # from now on we hold the GIL @@ -192,6 +201,9 @@ os.write(2, "Warning: uncaught exception in callback: %%s %%s\n" %% (callable_name, str(e))) + if not we_are_translated(): + import traceback + traceback.print_exc() result = errorcode if before: before() @@ -203,6 +215,7 @@ miniglobals = locals().copy() miniglobals['Exception'] = Exception miniglobals['os'] = os + miniglobals['we_are_translated'] = we_are_translated exec source.compile() in miniglobals return miniglobals['wrapper'] _make_wrapper_for._annspecialcase_ = 'specialize:memo' @@ -379,7 +392,7 @@ return lltype.Ptr(COpaque(*args, **kwds)) def CExternVariable(TYPE, name, eci, _CConstantClass=CConstant, - sandboxsafe=False, readonly=False): + sandboxsafe=False, readonly=False, _nowrapper=False): """Return a pair of functions - a getter and a setter - to access the given global C variable. """ @@ -418,14 +431,15 @@ sources = ('\n'.join(lines),) new_eci = eci.merge(ExternalCompilationInfo( separate_module_sources = sources, - post_include_lines = [getter_prototype, setter_prototype], + post_include_bits = [getter_prototype, setter_prototype], export_symbols = symbols, )) getter = llexternal(getter_name, [], TYPE, compilation_info=new_eci, - sandboxsafe=sandboxsafe) + sandboxsafe=sandboxsafe, _nowrapper=_nowrapper) setter = llexternal(setter_name, [TYPE], lltype.Void, - compilation_info=new_eci, sandboxsafe=sandboxsafe) + compilation_info=new_eci, sandboxsafe=sandboxsafe, + _nowrapper=_nowrapper) return getter, setter # char, represented as a Python character Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/rpbc.py Tue Jun 10 12:48:46 2008 @@ -16,6 +16,8 @@ SingleFrozenPBCRepr, none_frozen_pbc_repr, get_concrete_calltable from pypy.rpython.lltypesystem import rclass, llmemory from pypy.tool.sourcetools import has_varargs +from pypy.rlib.unroll import unrolling_iterable +from pypy.rlib.debug import ll_assert from pypy.rpython import callparse @@ -132,6 +134,7 @@ self.lowleveltype = Char self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc) self._conversion_tables = {} + self._compression_function = None self._dispatch_cache = {} def _setup_repr(self): @@ -269,11 +272,31 @@ return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int], resulttype=r_ptr.lowleveltype) +def compression_function(r_set): + if r_set._compression_function is None: + table = [] + for i, p in enumerate(r_set.c_pointer_table.value): + table.append((chr(i), p)) + last_c, last_p = table[-1] + unroll_table = unrolling_iterable(table[:-1]) + def ll_compress(fnptr): + for c, p in unroll_table: + if fnptr == p: + return c + else: + ll_assert(fnptr == last_p, "unexpected function pointer") + return last_c + r_set._compression_function = ll_compress + return r_set._compression_function + class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)): def convert_from_to((r_ptr, r_set), v, llops): - assert r_ptr.lowleveltype is Void - desc, = r_ptr.s_pbc.descriptions - return inputconst(Char, r_set.convert_desc(desc)) + if r_ptr.lowleveltype is Void: + desc, = r_ptr.s_pbc.descriptions + return inputconst(Char, r_set.convert_desc(desc)) + else: + ll_compress = compression_function(r_set) + return llops.gendirectcall(ll_compress, v) def conversion_table(r_from, r_to): if r_to in r_from._conversion_tables: Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/rstr.py Tue Jun 10 12:48:46 2008 @@ -514,6 +514,8 @@ if end > len(s1.chars): end = len(s1.chars) if len2 == 0: + if (end-start) < 0: + return -1 return end # Construct the array of possible restarting positions T = malloc( SIGNED_ARRAY, len2 ) Modified: pypy/branch/build-external/pypy/rpython/lltypesystem/test/test_rffi.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/lltypesystem/test/test_rffi.py (original) +++ pypy/branch/build-external/pypy/rpython/lltypesystem/test/test_rffi.py Tue Jun 10 12:48:46 2008 @@ -531,7 +531,8 @@ assert interpret(f, []) == 3 def test_implicit_cast(self): - z = llexternal('z', [USHORT, ULONG, USHORT, DOUBLE], USHORT) + z = llexternal('z', [USHORT, ULONG, USHORT, DOUBLE], USHORT, + sandboxsafe=True) # to allow the wrapper to be inlined def f(x, y, xx, yy): return z(x, y, xx, yy) Modified: pypy/branch/build-external/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/build-external/pypy/rpython/memory/gctransform/framework.py Tue Jun 10 12:48:46 2008 @@ -22,6 +22,16 @@ class CollectAnalyzer(graphanalyze.GraphAnalyzer): + + def analyze_direct_call(self, graph, seen=None): + try: + if graph.func._gctransformer_hint_cannot_collect_: + return False + except AttributeError: + pass + return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph, + seen) + def operation_is_true(self, op): if op.opname in ('malloc', 'malloc_varsize'): flags = op.args[1].value @@ -343,6 +353,20 @@ annmodel.s_None, minimal_transform = False) + # thread support + if translator.config.translation.thread: + if not hasattr(root_walker, "need_thread_support"): + raise Exception("%s does not support threads" % ( + root_walker.__class__.__name__,)) + root_walker.need_thread_support() + self.thread_prepare_ptr = getfn(root_walker.thread_prepare, + [], annmodel.s_None) + self.thread_run_ptr = getfn(root_walker.thread_run, + [], annmodel.s_None, + inline=True) + self.thread_die_ptr = getfn(root_walker.thread_die, + [], annmodel.s_None) + annhelper.finish() # at this point, annotate all mix-level helpers annhelper.backend_optimize() @@ -645,6 +669,18 @@ self.c_const_gc, v_size]) + def gct_gc_thread_prepare(self, hop): + assert self.translator.config.translation.thread + hop.genop("direct_call", [self.thread_prepare_ptr]) + + def gct_gc_thread_run(self, hop): + assert self.translator.config.translation.thread + hop.genop("direct_call", [self.thread_run_ptr]) + + def gct_gc_thread_die(self, hop): + assert self.translator.config.translation.thread + hop.genop("direct_call", [self.thread_die_ptr]) + def gct_malloc_nonmovable_varsize(self, hop): TYPE = hop.spaceop.result.concretetype if self.gcdata.gc.can_malloc_nonmovable(): @@ -836,6 +872,8 @@ class ShadowStackRootWalker(BaseRootWalker): need_root_stack = True + thread_setup = None + collect_stacks_from_other_threads = None def __init__(self, gctransformer): BaseRootWalker.__init__(self, gctransformer) @@ -855,12 +893,27 @@ return top self.decr_stack = decr_stack + def push_stack(self, addr): + top = self.incr_stack(1) + top.address[0] = addr + + def pop_stack(self): + top = self.decr_stack(1) + return top.address[0] + + def allocate_stack(self): + result = llmemory.raw_malloc(self.rootstacksize) + if result: + llmemory.raw_memclear(result, self.rootstacksize) + return result + def setup_root_walker(self): - stackbase = llmemory.raw_malloc(self.rootstacksize) + stackbase = self.allocate_stack() ll_assert(bool(stackbase), "could not allocate root stack") - llmemory.raw_memclear(stackbase, self.rootstacksize) self.gcdata.root_stack_top = stackbase self.gcdata.root_stack_base = stackbase + if self.thread_setup is not None: + self.thread_setup() def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata @@ -871,3 +924,121 @@ if addr.address[0] != llmemory.NULL: collect_stack_root(gc, addr) addr += sizeofaddr + if self.collect_stacks_from_other_threads is not None: + self.collect_stacks_from_other_threads(collect_stack_root) + + def need_thread_support(self): + from pypy.module.thread import ll_thread # xxx fish + from pypy.rpython.memory.support import AddressDict + from pypy.rpython.memory.support import copy_without_null_values + gcdata = self.gcdata + # the interfacing between the threads and the GC is done via + # three completely ad-hoc operations at the moment: + # gc_thread_prepare, gc_thread_run, gc_thread_die. + # See docstrings below. + + def get_aid(): + """Return the thread identifier, cast to an (opaque) address.""" + return llmemory.cast_int_to_adr(ll_thread.get_ident()) + + def thread_setup(): + """Called once when the program starts.""" + aid = get_aid() + gcdata.main_thread = aid + gcdata.active_thread = aid + gcdata.thread_stacks = AddressDict() # {aid: root_stack_top} + gcdata._fresh_rootstack = llmemory.NULL + gcdata.dead_threads_count = 0 + + def thread_prepare(): + """Called just before thread.start_new_thread(). This + allocates a new shadow stack to be used by the future + thread. If memory runs out, this raises a MemoryError + (which can be handled by the caller instead of just getting + ignored if it was raised in the newly starting thread). + """ + if not gcdata._fresh_rootstack: + gcdata._fresh_rootstack = self.allocate_stack() + if not gcdata._fresh_rootstack: + raise MemoryError + + def thread_run(): + """Called whenever the current thread (re-)acquired the GIL. + This should ensure that the shadow stack installed in + gcdata.root_stack_top/root_stack_base is the one corresponding + to the current thread. + """ + aid = get_aid() + if gcdata.active_thread != aid: + switch_shadow_stacks(aid) + + def thread_die(): + """Called just before the final GIL release done by a dying + thread. After a thread_die(), no more gc operation should + occur in this thread. + """ + aid = get_aid() + gcdata.thread_stacks.setitem(aid, llmemory.NULL) + old = gcdata.root_stack_base + if gcdata._fresh_rootstack == llmemory.NULL: + gcdata._fresh_rootstack = old + else: + llmemory.raw_free(old) + install_new_stack(gcdata.main_thread) + # from time to time, rehash the dictionary to remove + # old NULL entries + gcdata.dead_threads_count += 1 + if (gcdata.dead_threads_count & 511) == 0: + gcdata.thread_stacks = copy_without_null_values( + gcdata.thread_stacks) + + def switch_shadow_stacks(new_aid): + save_away_current_stack() + install_new_stack(new_aid) + switch_shadow_stacks._dont_inline_ = True + + def save_away_current_stack(): + old_aid = gcdata.active_thread + # save root_stack_base on the top of the stack + self.push_stack(gcdata.root_stack_base) + # store root_stack_top into the dictionary + gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top) + + def install_new_stack(new_aid): + # look for the new stack top + top = gcdata.thread_stacks.get(new_aid, llmemory.NULL) + if top == llmemory.NULL: + # first time we see this thread. It is an error if no + # fresh new stack is waiting. + base = gcdata._fresh_rootstack + gcdata._fresh_rootstack = llmemory.NULL + ll_assert(base != llmemory.NULL, "missing gc_thread_prepare") + gcdata.root_stack_top = base + gcdata.root_stack_base = base + else: + # restore the root_stack_base from the top of the stack + gcdata.root_stack_top = top + gcdata.root_stack_base = self.pop_stack() + # done + gcdata.active_thread = new_aid + + def collect_stack(aid, stacktop, callback): + if stacktop != llmemory.NULL and aid != get_aid(): + # collect all valid stacks from the dict (the entry + # corresponding to the current thread is not valid) + gc = self.gc + end = stacktop - sizeofaddr + addr = end.address[0] + while addr != end: + if addr.address[0] != llmemory.NULL: + callback(gc, addr) + addr += sizeofaddr + + def collect_more_stacks(callback): + gcdata.thread_stacks.foreach(collect_stack, callback) + + self.thread_setup = thread_setup + self.thread_prepare = thread_prepare + self.thread_run = thread_run + self.thread_die = thread_die + self.collect_stacks_from_other_threads = collect_more_stacks Modified: pypy/branch/build-external/pypy/rpython/memory/support.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/memory/support.py (original) +++ pypy/branch/build-external/pypy/rpython/memory/support.py Tue Jun 10 12:48:46 2008 @@ -305,3 +305,19 @@ arg.setitem(newkey, value) return callback _get_updater._annspecialcase_ = 'specialize:memo' + + +def copy_without_null_values(dict): + """Make a copy of 'dict' without the key/value pairs where value==NULL.""" + newdict = AddressDict + if not we_are_translated(): + # when not translated, return a dict of the same kind as 'dict' + if not isinstance(dict, BasicAddressDict): + from pypy.rpython.memory.lldict import newdict + result = newdict() + dict.foreach(_null_value_checker, result) + return result + +def _null_value_checker(key, value, arg): + if value: + arg.setitem(key, value) Modified: pypy/branch/build-external/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/module/ll_os.py (original) +++ pypy/branch/build-external/pypy/rpython/module/ll_os.py Tue Jun 10 12:48:46 2008 @@ -97,14 +97,13 @@ defs = [] for name in self.w_star: data = {'ret_type': 'int', 'name': name} - decls.append(decl_snippet % data) - defs.append(def_snippet % data) - h_source = decls + defs + decls.append((decl_snippet % data).strip()) + defs.append((def_snippet % data).strip()) self.compilation_info = self.compilation_info.merge( ExternalCompilationInfo( - post_include_lines = decls, - separate_module_sources = ["\n".join(h_source)] + post_include_bits = decls, + separate_module_sources = ["\n".join(defs)] )) # a simple, yet usefull factory @@ -1122,7 +1121,18 @@ @registering_if(os, 'fork') def register_os_fork(self): - os_fork = self.llexternal('fork', [], rffi.PID_T) + # XXX horrible workaround for a bug of profiling in gcc on + # OS X with functions containing a direct call to fork() + eci = ExternalCompilationInfo( + post_include_bits = ['pid_t _noprof_fork(void);'], + separate_module_sources = [''' + /*--no-profiling-for-this-file!--*/ + pid_t _noprof_fork(void) { + return fork(); + } + ''']) + os_fork = self.llexternal('_noprof_fork', [], rffi.PID_T, + compilation_info = eci) def fork_llimpl(): childpid = rffi.cast(lltype.Signed, os_fork()) Modified: pypy/branch/build-external/pypy/rpython/module/ll_os_stat.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/module/ll_os_stat.py (original) +++ pypy/branch/build-external/pypy/rpython/module/ll_os_stat.py Tue Jun 10 12:48:46 2008 @@ -146,7 +146,7 @@ INCLUDES = ['sys/types.h', 'sys/stat.h', 'unistd.h'] compilation_info = ExternalCompilationInfo( - pre_include_lines = ['#define _FILE_OFFSET_BITS 64'], + pre_include_bits = ['#define _FILE_OFFSET_BITS 64'], includes = INCLUDES ) Modified: pypy/branch/build-external/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/build-external/pypy/rpython/ootypesystem/ootype.py Tue Jun 10 12:48:46 2008 @@ -1238,10 +1238,14 @@ def ll_find(self, s, start, end): # NOT_RPYTHON + if start > len(self._str): # workaround to cope with corner case + return -1 # bugs in CPython 2.4 unicode.find('') return self._str.find(s._str, start, end) def ll_rfind(self, s, start, end): # NOT_RPYTHON + if start > len(self._str): # workaround to cope with corner case + return -1 # bugs in CPython 2.4 unicode.rfind('') return self._str.rfind(s._str, start, end) def ll_count(self, s, start, end): Modified: pypy/branch/build-external/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/test/test_rpbc.py (original) +++ pypy/branch/build-external/pypy/rpython/test/test_rpbc.py Tue Jun 10 12:48:46 2008 @@ -1927,10 +1927,6 @@ kwds['config'] = self.config return TestLLtype.interpret(self, fn, args, **kwds) - def test_shrink_pbc_set(self): - # fails with config.translation.withsmallfuncsets == 3 - py.test.skip("XXX not implemented") - def test_smallfuncsets_basic(): from pypy.translator.translator import TranslationContext, graphof from pypy.config.pypyoption import get_pypy_config Modified: pypy/branch/build-external/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/test/test_rstr.py (original) +++ pypy/branch/build-external/pypy/rpython/test/test_rstr.py Tue Jun 10 12:48:46 2008 @@ -281,9 +281,9 @@ x+= s.find(const(''), i, i)*100 x+= s.find(const(''), i, i+1)*1000 return x - for i in range(5): + for i, expected in enumerate([0, 1110, 2220, 3330, -1110, -1110]): res = self.interpret(f, [i]) - assert res == f(i) + assert res == expected def test_rfind(self): const = self.const @@ -306,14 +306,14 @@ def f(i): assert i >= 0 s = const("abc") - x = s.find(const('')) - x+= s.find(const(''), i)*10 - x+= s.find(const(''), i, i)*100 - x+= s.find(const(''), i, i+1)*1000 + x = s.rfind(const('')) + x+= s.rfind(const(''), i)*10 + x+= s.rfind(const(''), i, i)*100 + x+= s.rfind(const(''), i, i+1)*1000 return x - for i in range(5): + for i, expected in enumerate([1033, 2133, 3233, 3333, 3-1110, 3-1110]): res = self.interpret(f, [i]) - assert res == f(i) + assert res == expected def test_find_char(self): const = self.const Modified: pypy/branch/build-external/pypy/rpython/tool/rffi_platform.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/tool/rffi_platform.py (original) +++ pypy/branch/build-external/pypy/rpython/tool/rffi_platform.py Tue Jun 10 12:48:46 2008 @@ -16,7 +16,7 @@ def eci_from_header(c_header_source): return ExternalCompilationInfo( - pre_include_lines=c_header_source.split("\n") + pre_include_bits=[c_header_source] ) def getstruct(name, c_header_source, interesting_fields): Modified: pypy/branch/build-external/pypy/rpython/tool/test/test_rffi_platform.py ============================================================================== --- pypy/branch/build-external/pypy/rpython/tool/test/test_rffi_platform.py (original) +++ pypy/branch/build-external/pypy/rpython/tool/test/test_rffi_platform.py Tue Jun 10 12:48:46 2008 @@ -111,9 +111,9 @@ class CConfig: _compilation_info_ = ExternalCompilationInfo( - pre_include_lines = ["/* a C comment */", - "#include ", - "#include "], + pre_include_bits = ["/* a C comment */", + "#include ", + "#include "], include_dirs = [str(udir)] ) @@ -130,13 +130,15 @@ def test_ifdef(): class CConfig: _compilation_info_ = ExternalCompilationInfo( - post_include_lines = ['/* a C comment */', - '#define XYZZY 42', - 'typedef int foo;', - 'struct s {', - 'int i;', - 'double f;' - '};']) + post_include_bits = ['/* a C comment */', + '#define XYZZY 42', + 'typedef int foo;', + ''' + struct s { + int i; + double f; + }; + ''']) s = rffi_platform.Struct('struct s', [('i', rffi.INT)], ifdef='XYZZY') @@ -155,7 +157,7 @@ def test_nested_structs(): class CConfig: _compilation_info_ = ExternalCompilationInfo( - post_include_lines=""" + post_include_bits=[""" struct x { int foo; unsigned long bar; @@ -164,7 +166,7 @@ char c; struct x x; }; - """.split("\n")) + """]) x = rffi_platform.Struct("struct x", [("bar", rffi.SHORT)]) y = rffi_platform.Struct("struct y", [("x", x)]) @@ -178,7 +180,7 @@ def test_nested_structs_in_the_opposite_order(): class CConfig: _compilation_info_ = ExternalCompilationInfo( - post_include_lines=""" + post_include_bits=[""" struct y { int foo; unsigned long bar; @@ -187,7 +189,7 @@ char c; struct y y; }; - """.split("\n")) + """]) y = rffi_platform.Struct("struct y", [("bar", rffi.SHORT)]) x = rffi_platform.Struct("struct x", [("y", y)]) Modified: pypy/branch/build-external/pypy/tool/gcc_cache.py ============================================================================== --- pypy/branch/build-external/pypy/tool/gcc_cache.py (original) +++ pypy/branch/build-external/pypy/tool/gcc_cache.py Tue Jun 10 12:48:46 2008 @@ -5,8 +5,6 @@ from pypy.translator.tool.cbuild import CompilationError import md5 import py -import distutils -import distutils.errors cache_dir_root = py.path.local(pypydir).join('_cache').ensure(dir=1) Modified: pypy/branch/build-external/pypy/tool/test/test_tab.py ============================================================================== --- pypy/branch/build-external/pypy/tool/test/test_tab.py (original) +++ pypy/branch/build-external/pypy/tool/test/test_tab.py Tue Jun 10 12:48:46 2008 @@ -23,7 +23,7 @@ data = f.read() f.close() assert '\t' not in data, "%r contains tabs!" % (reldir,) - elif os.path.isdir(path): + elif os.path.isdir(path) and not os.path.islink(path): for entry in os.listdir(path): if not entry.startswith('.'): walk('%s/%s' % (reldir, entry)) Modified: pypy/branch/build-external/pypy/tool/tls.py ============================================================================== --- pypy/branch/build-external/pypy/tool/tls.py (original) +++ pypy/branch/build-external/pypy/tool/tls.py Tue Jun 10 12:48:46 2008 @@ -1,26 +1,8 @@ -##"""Thread-local storage.""" -## -##try: -## from thread import _local as tlsobject -##except ImportError: # Python < 2.4 -## -## # XXX needs a real object whose attributes are visible only in -## # the thread that reads/writes them. -## -## import autopath, os -## filename = os.path.join(os.path.dirname(autopath.pypydir), -## 'lib-python', '2.4.1', '_threading_local.py') -## glob = {'__name__': '_threading_local'} -## execfile(filename, glob) -## tlsobject = glob['local'] -## del glob, filename +"""Thread-local storage.""" - - - -class tlsobject(object): - """Storage that is NOT THREAD-LOCAL AT ALL because we don't really need it - at the moment, and it has a performance impact -- a minor one on top of 2.4, - and an extreme one on top of 2.3 :-((((( - """ +try: + from thread import _local as tlsobject +except ImportError: + class tlsobject(object): + pass Modified: pypy/branch/build-external/pypy/translator/backendopt/malloc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/backendopt/malloc.py (original) +++ pypy/branch/build-external/pypy/translator/backendopt/malloc.py Tue Jun 10 12:48:46 2008 @@ -63,11 +63,10 @@ def inline_type(self, TYPE): raise NotImplementedError - def flowin(self, block, count, var, newvarsmap): + def flowin(self, block, count, vars, newvarsmap): # in this 'block', follow where the 'var' goes to and replace # it by a flattened-out family of variables. This family is given # by newvarsmap, whose keys are the 'flatnames'. - vars = {var: True} self.last_removed_access = None def list_newvars(): @@ -82,7 +81,6 @@ self.flowin_op(op, vars, newvarsmap) elif op.result in vars: assert op.opname == self.MALLOC_OP - assert vars == {var: True} progress = True # drop the "malloc" operation newvarsmap = self.flatconstants.copy() # zero initial values @@ -106,10 +104,13 @@ assert block.exitswitch not in vars for link in block.exits: + appended = False newargs = [] for arg in link.args: if arg in vars: - newargs += list_newvars() + if not appended: + newargs += list_newvars() + appended = True else: newargs.append(arg) link.args[:] = newargs @@ -271,20 +272,24 @@ for block, vars in variables_by_block.items(): # look for variables arriving from outside the block - for var in vars: - if var in block.inputargs: - i = block.inputargs.index(var) - newinputargs = block.inputargs[:i] - newvarsmap = {} - for key in self.flatnames: - newvar = Variable() - newvar.concretetype = self.newvarstype[key] - newvarsmap[key] = newvar - newinputargs.append(newvar) - newinputargs += block.inputargs[i+1:] - block.inputargs[:] = newinputargs - assert var not in block.inputargs - self.flowin(block, count, var, newvarsmap) + newvarsmap = None + newinputargs = [] + inputvars = {} + for var in block.inputargs: + if var in vars: + inputvars[var] = None + if newvarsmap is None: + newvarsmap = {} + for key in self.flatnames: + newvar = Variable() + newvar.concretetype = self.newvarstype[key] + newvarsmap[key] = newvar + newinputargs.append(newvar) + else: + newinputargs.append(var) + block.inputargs[:] = newinputargs + if inputvars: + self.flowin(block, count, inputvars, newvarsmap) # look for variables created inside the block by a malloc vars_created_here = [] @@ -292,7 +297,7 @@ if self.check_malloc(op) and op.result in vars: vars_created_here.append(op.result) for var in vars_created_here: - self.flowin(block, count, var, newvarsmap=None) + self.flowin(block, count, {var: True}, newvarsmap=None) return count[0] @@ -486,7 +491,6 @@ newvarsmap[key] = op.args[2] self.last_removed_access = len(self.newops) elif op.opname in ("same_as", "cast_pointer"): - assert op.result not in vars vars[op.result] = True # Consider the two pointers (input and result) as # equivalent. We can, and indeed must, use the same @@ -605,7 +609,6 @@ newvarsmap[key] = op.args[2] last_removed_access = len(self.newops) elif op.opname in ("same_as", "oodowncast", "ooupcast"): - assert op.result not in vars vars[op.result] = True # Consider the two pointers (input and result) as # equivalent. We can, and indeed must, use the same Modified: pypy/branch/build-external/pypy/translator/backendopt/test/test_malloc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/backendopt/test/test_malloc.py (original) +++ pypy/branch/build-external/pypy/translator/backendopt/test/test_malloc.py Tue Jun 10 12:48:46 2008 @@ -334,6 +334,17 @@ [link] = entrymap[graph.returnblock] assert link.prevblock.operations[-1].opname == 'keepalive' + def test_nested_struct(self): + S = lltype.GcStruct("S", ('x', lltype.Signed)) + T = lltype.GcStruct("T", ('s', S)) + def f(x): + t = lltype.malloc(T) + s = t.s + if x: + s.x = x + return t.s.x + s.x + graph = self.check(f, [int], [42], 2 * 42) + def test_interior_ptr(self): py.test.skip("fails") S = lltype.Struct("S", ('x', lltype.Signed)) Modified: pypy/branch/build-external/pypy/translator/c/gc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/c/gc.py (original) +++ pypy/branch/build-external/pypy/translator/c/gc.py Tue Jun 10 12:48:46 2008 @@ -73,6 +73,15 @@ def OP_GC_SET_MAX_HEAP_SIZE(self, funcgen, op): return '' + def OP_GC_THREAD_PREPARE(self, funcgen, op): + return '' + + def OP_GC_THREAD_RUN(self, funcgen, op): + return '' + + def OP_GC_THREAD_DIE(self, funcgen, op): + return '' + class RefcountingInfo: static_deallocator = None Modified: pypy/branch/build-external/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/build-external/pypy/translator/c/genc.py (original) +++ pypy/branch/build-external/pypy/translator/c/genc.py Tue Jun 10 12:48:46 2008 @@ -290,22 +290,32 @@ standalone = True executable_name = None - def getentrypointptr(self): - # XXX check that the entrypoint has the correct - # signature: list-of-strings -> int - bk = self.translator.annotator.bookkeeper - return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph()) - - def getccompiler(self): - cc = self.config.translation.cc + def getprofbased(self): profbased = None if self.config.translation.instrumentctl is not None: profbased = self.config.translation.instrumentctl else: + # xxx handling config.translation.profopt is a bit messy, because + # it could be an empty string (not to be confused with None) and + # because noprofopt can be used as an override. profopt = self.config.translation.profopt if profopt is not None and not self.config.translation.noprofopt: profbased = (ProfOpt, profopt) + return profbased + + def has_profopt(self): + profbased = self.getprofbased() + return (profbased and isinstance(profbased, tuple) + and profbased[0] is ProfOpt) + def getentrypointptr(self): + # XXX check that the entrypoint has the correct + # signature: list-of-strings -> int + bk = self.translator.annotator.bookkeeper + return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph()) + + def getccompiler(self): + cc = self.config.translation.cc # Copy extrafiles to target directory, if needed extrafiles = [] for fn in self.extrafiles: @@ -325,7 +335,7 @@ return CCompiler( [self.c_source_filename] + extrafiles, - self.eci, compiler_exe = cc, profbased = profbased) + self.eci, compiler_exe = cc, profbased = self.getprofbased()) def compile(self): assert self.c_source_filename @@ -398,9 +408,20 @@ cc = self.config.translation.cc else: cc = 'gcc' - if self.config.translation.profopt: + make_no_prof = '' + if self.has_profopt(): profopt = self.config.translation.profopt default_target = 'profopt' + # XXX horrible workaround for a bug of profiling in gcc on + # OS X with functions containing a direct call to fork() + non_profilable = [] + assert len(compiler.cfilenames) == len(ofiles) + for fn, oname in zip(compiler.cfilenames, ofiles): + fn = py.path.local(fn) + if '/*--no-profiling-for-this-file!--*/' in fn.read(): + non_profilable.append(oname) + if non_profilable: + make_no_prof = '$(MAKE) %s' % (' '.join(non_profilable),) else: profopt = '' default_target = '$(TARGET)' @@ -444,6 +465,7 @@ else: print >> f, 'TFLAGS = ' + '' print >> f, 'PROFOPT = ' + profopt + print >> f, 'MAKENOPROF = ' + make_no_prof print >> f, 'CC = ' + cc print >> f print >> f, MAKEFILE.strip() @@ -864,11 +886,13 @@ $(TARGET): $(OBJECTS) \t$(CC) $(LDFLAGS) $(TFLAGS) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) +# -frandom-seed is only to try to be as reproducable as possible + %.o: %.c -\t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS) +\t$(CC) $(CFLAGS) -frandom-seed=$< -o $@ -c $< $(INCLUDEDIRS) %.s: %.c -\t$(CC) $(CFLAGS) -o $@ -S $< $(INCLUDEDIRS) +\t$(CC) $(CFLAGS) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS) %.gcmap: %.s \t$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $@ || (rm -f $@ && exit 1) @@ -877,7 +901,7 @@ \t$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@ || (rm -f $@ && exit 1) clean: -\trm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) *.gc?? +\trm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) *.gc?? ../module_cache/*.gc?? clean_noprof: \trm -f $(OBJECTS) $(TARGET) $(GCMAPFILES) @@ -910,6 +934,7 @@ ABS_TARGET = $(shell python -c "import sys,os; print os.path.abspath(sys.argv[1])" $(TARGET)) profopt: +\t$(MAKENOPROF) # these files must be compiled without profiling \t$(MAKE) CFLAGS="-fprofile-generate $(CFLAGS)" LDFLAGS="-fprofile-generate $(LDFLAGS)" $(TARGET) \tcd $(PYPYDIR)/translator/goal && $(ABS_TARGET) $(PROFOPT) \t$(MAKE) clean_noprof Modified: pypy/branch/build-external/pypy/translator/c/src/thread.h ============================================================================== --- pypy/branch/build-external/pypy/translator/c/src/thread.h (original) +++ pypy/branch/build-external/pypy/translator/c/src/thread.h Tue Jun 10 12:48:46 2008 @@ -44,17 +44,13 @@ #endif -/* common helper: this is a single external function so that we are - sure that nothing occurs between the release and the acquire, - e.g. no GC operation. */ - -void RPyThreadFusedReleaseAcquireLock(struct RPyOpaque_ThreadLock *lock); +/* common helper: this does nothing, but is called with the GIL released. + This gives other threads a chance to grab the GIL and run. */ +void RPyThreadYield(void); #ifndef PYPY_NOT_MAIN_FILE -void RPyThreadFusedReleaseAcquireLock(struct RPyOpaque_ThreadLock *lock) +void RPyThreadYield(void) { - RPyThreadReleaseLock(lock); - RPyThreadAcquireLock(lock, 1); } #endif Modified: pypy/branch/build-external/pypy/translator/c/src/thread_nt.h ============================================================================== --- pypy/branch/build-external/pypy/translator/c/src/thread_nt.h (original) +++ pypy/branch/build-external/pypy/translator/c/src/thread_nt.h Tue Jun 10 12:48:46 2008 @@ -22,8 +22,7 @@ #define RPyOpaque_INITEXPR_ThreadLock { 0, 0, NULL } typedef struct { - void (*func)(void*); - void *arg; + void (*func)(void); long id; HANDLE done; } callobj; @@ -35,7 +34,7 @@ } NRMUTEX, *PNRMUTEX ; /* prototypes */ -long RPyThreadStart(void (*func)(void *), void *arg); +long RPyThreadStart(void (*func)(void)); BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex); VOID DeleteNonRecursiveMutex(PNRMUTEX mutex); DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait); @@ -63,23 +62,21 @@ { callobj *obj = (callobj*)call; /* copy callobj since other thread might free it before we're done */ - void (*func)(void*) = obj->func; - void *arg = obj->arg; + void (*func)(void) = obj->func; obj->id = RPyThreadGetIdent(); ReleaseSemaphore(obj->done, 1, NULL); - func(arg); + func(); return 0; } -long RPyThreadStart(void (*func)(void *), void *arg) +long RPyThreadStart(void (*func)(void)) { unsigned long rv; callobj obj; obj.id = -1; /* guilty until proved innocent */ obj.func = func; - obj.arg = arg; obj.done = CreateSemaphore(NULL, 0, 1, NULL); if (obj.done == NULL) return -1; Modified: pypy/branch/build-external/pypy/translator/c/src/thread_pthread.h ============================================================================== --- pypy/branch/build-external/pypy/translator/c/src/thread_pthread.h (original) +++ pypy/branch/build-external/pypy/translator/c/src/thread_pthread.h Tue Jun 10 12:48:46 2008 @@ -75,7 +75,7 @@ /* prototypes */ long RPyThreadGetIdent(void); -long RPyThreadStart(void (*func)(void *), void *arg); +long RPyThreadStart(void (*func)(void)); int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock); void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock); int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag); @@ -105,7 +105,13 @@ #endif } -long RPyThreadStart(void (*func)(void *), void *arg) +static void *bootstrap_pthread(void *func) +{ + ((void(*)(void))func)(); + return NULL; +} + +long RPyThreadStart(void (*func)(void)) { pthread_t th; int status; @@ -129,8 +135,8 @@ #else (pthread_attr_t*)NULL, #endif - (void* (*)(void *))func, - (void *)arg + bootstrap_pthread, + (void *)func ); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) Modified: pypy/branch/build-external/pypy/translator/c/test/test_boehm.py ============================================================================== --- pypy/branch/build-external/pypy/translator/c/test/test_boehm.py (original) +++ pypy/branch/build-external/pypy/translator/c/test/test_boehm.py Tue Jun 10 12:48:46 2008 @@ -13,6 +13,7 @@ class AbstractGCTestClass(object): gcpolicy = "boehm" stacklessgc = False + use_threads = False # deal with cleanups def setup_method(self, meth): @@ -27,6 +28,7 @@ from pypy.config.pypyoption import get_pypy_config config = get_pypy_config(translating=True) config.translation.gc = self.gcpolicy + config.translation.thread = self.use_threads if self.stacklessgc: config.translation.gcrootfinder = "stackless" config.translation.simplifying = True Modified: pypy/branch/build-external/pypy/translator/goal/app_main.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/app_main.py (original) +++ pypy/branch/build-external/pypy/translator/goal/app_main.py Tue Jun 10 12:48:46 2008 @@ -141,6 +141,9 @@ sys.stdout = sys.__stdout__ = os.fdopen(1, 'wb', 0) sys.stderr = sys.__stderr__ = os.fdopen(2, 'wb', 0) +def set_fully_buffered_io(): + sys.stdout = sys.__stdout__ = os.fdopen(1, 'w') + # ____________________________________________________________ # Main entry point @@ -207,6 +210,7 @@ run_module = False run_stdin = False oldstyle_classes = False + unbuffered = False while i < len(argv): arg = argv[i] if not arg.startswith('-'): @@ -220,7 +224,7 @@ run_command = True break elif arg == '-u': - set_unbuffered_io() + unbuffered = True elif arg == '-O': pass elif arg == '--version': @@ -262,6 +266,12 @@ # but we need more in the translated PyPy for the compiler package sys.setrecursionlimit(5000) + if unbuffered: + set_unbuffered_io() + elif not sys.stdout.isatty(): + set_fully_buffered_io() + + mainmodule = type(sys)('__main__') sys.modules['__main__'] = mainmodule Modified: pypy/branch/build-external/pypy/translator/goal/bench-cronjob.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/bench-cronjob.py (original) +++ pypy/branch/build-external/pypy/translator/goal/bench-cronjob.py Tue Jun 10 12:48:46 2008 @@ -183,12 +183,10 @@ c c--stackless--_faassen c--_faassen--_allworkingmodules - c--thread - c--gc=marksweep--_faassen + c--thread--gc=hybrid--_faassen c--gc=semispace--_faassen c--gc=generation--_faassen c--gc=hybrid--_faassen - c--_objspace-std-withrope cli--_faassen jvm--_faassen """.split('\n') if backend.strip() and not backend.strip().startswith('#')] Modified: pypy/branch/build-external/pypy/translator/goal/gcbench.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/gcbench.py (original) +++ pypy/branch/build-external/pypy/translator/goal/gcbench.py Tue Jun 10 12:48:46 2008 @@ -45,8 +45,9 @@ # check for proper locking import os, time -def println(s): - os.write(1, s+"\n") +USAGE = """gcbench [num_repetitions] [--depths=N,N,N..] [--threads=N]""" +ENABLE_THREADS = True + class Node(object): @@ -92,36 +93,54 @@ def time_construction(depth): niters = num_iters(depth) - println("Creating %d trees of depth %d" % (niters, depth)) + print "Creating %d trees of depth %d" % (niters, depth) t_start = time.time() for i in range(niters): temp_tree = Node() populate(depth, temp_tree) temp_tree = None t_finish = time.time() - println("\tTop down constrution took %f ms" % ((t_finish-t_start)*1000.)) + print "\tTop down constrution took %f ms" % ((t_finish-t_start)*1000.) t_start = time.time() for i in range(niters): temp_tree = make_tree(depth) temp_tree = None t_finish = time.time() - println("\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.)) + print "\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.) + +DEFAULT_DEPTHS = range(kMinTreeDepth, kMaxTreeDepth+1, 2) -def main(depths=range(kMinTreeDepth, kMaxTreeDepth+1, 2)): - println("Garbage Collector Test") - println(" Stretching memory with a binary tree of depth %d" % kStretchTreeDepth) +def time_constructions(depths): + for d in depths: + time_construction(d) + +def time_parallel_constructions(depths, nthreads): + import threading + threadlist = [] + print "Starting %d parallel threads..." % (nthreads,) + for n in range(nthreads): + t = threading.Thread(target=time_constructions, args=(depths,)) + t.start() + threadlist.append(t) + for t in threadlist: + t.join() + print "All %d threads finished" % (nthreads,) + +def main(depths=DEFAULT_DEPTHS, threads=0): + print "Garbage Collector Test" + print " Stretching memory with a binary tree of depth %d" % kStretchTreeDepth print_diagnostics() t_start = time.time() temp_tree = make_tree(kStretchTreeDepth) temp_tree = None # Create a long lived object - println(" Creating a long-lived binary tree of depth %d" % kLongLivedTreeDepth) + print " Creating a long-lived binary tree of depth %d" % kLongLivedTreeDepth long_lived_tree = Node() populate(kLongLivedTreeDepth, long_lived_tree) # Create long-lived array, filling half of it - println(" Creating a long-lived array of %d doubles" % kArraySize) + print " Creating a long-lived array of %d doubles" % kArraySize array = [0.0] * kArraySize i = 1 while i < kArraySize/2: @@ -129,22 +148,57 @@ i += 1 print_diagnostics() - for d in depths: - time_construction(d) + if threads: + time_parallel_constructions(depths, threads) + else: + time_constructions(depths) if long_lived_tree is None or array[1024] != 1.0/1024: - println("FAILED") - return + raise Failed t_finish = time.time() print_diagnostics() - println("Completed in %f ms." % ((t_finish-t_start)*1000.)) + print "Completed in %f ms." % ((t_finish-t_start)*1000.) + +class Failed(Exception): + pass + + +def argerror(): + print "Usage:" + print " ", USAGE + return 2 + +def entry_point(argv): + depths = DEFAULT_DEPTHS + threads = 0 + repeatcount = 1 + for arg in argv[1:]: + if arg.startswith('--threads='): + arg = arg[len('--threads='):] + if not ENABLE_THREADS: + print "threads disabled (they cannot be translated)" + return 1 + try: + threads = int(arg) + except ValueError: + return argerror() + elif arg.startswith('--depths='): + arg = arg[len('--depths='):].split(',') + try: + depths = [int(s) for s in arg] + except ValueError: + return argerror() + else: + try: + repeatcount = int(arg) + except ValueError: + return argerror() + for i in range(repeatcount): + main(depths, threads) + return 0 if __name__ == '__main__': import sys - if len(sys.argv) > 1: - depths = [int(s) for s in sys.argv[1:]] - main(depths) - else: - main() + sys.exit(entry_point(sys.argv)) Modified: pypy/branch/build-external/pypy/translator/goal/targetgcbench.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/targetgcbench.py (original) +++ pypy/branch/build-external/pypy/translator/goal/targetgcbench.py Tue Jun 10 12:48:46 2008 @@ -1,20 +1,11 @@ import os, sys from pypy.translator.goal import gcbench -def entry_point(argv): - if len(argv) > 1: - n = int(argv[1]) - else: - n = 1 - while n > 0: - gcbench.main() - n -= 1 - return 0 - # _____ Define and setup target ___ def target(*args): - return entry_point, None + gcbench.ENABLE_THREADS = False # not RPython + return gcbench.entry_point, None """ Why is this a stand-alone target? Modified: pypy/branch/build-external/pypy/translator/goal/targetimageloadingsmalltalk.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/targetimageloadingsmalltalk.py (original) +++ pypy/branch/build-external/pypy/translator/goal/targetimageloadingsmalltalk.py Tue Jun 10 12:48:46 2008 @@ -10,32 +10,19 @@ mockclass = classtable.bootstrap_class -def new_interpreter(bytes): - assert isinstance(bytes, str) - w_method = model.W_CompiledMethod(0, bytes=bytes) - w_frame = w_method.create_frame(objtable.w_nil, []) - interp = interpreter.Interpreter() - interp.w_active_context = w_frame - return interp - - - def tinyBenchmarks(image): interp = interpreter.Interpreter() w_object = model.W_SmallInteger(0) # Should get this from w_object - w_smallint_class = image.special(constants.SO_SMALLINTEGER_CLASS) s_class = w_object.shadow_of_my_class() w_method = s_class.lookup("tinyBenchmarks") assert w_method w_frame = w_method.create_frame(w_object, []) - interp.w_active_context = w_frame + interp.store_w_active_context(w_frame) - print w_method - print "Going to execute %d toplevel bytecodes" % (len(w_method.bytes),) counter = 0 from pypy.lang.smalltalk.interpreter import BYTECODE_TABLE Modified: pypy/branch/build-external/pypy/translator/goal/targettinybenchsmalltalk.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/targettinybenchsmalltalk.py (original) +++ pypy/branch/build-external/pypy/translator/goal/targettinybenchsmalltalk.py Tue Jun 10 12:48:46 2008 @@ -1,9 +1,6 @@ -import os -from pypy.lang.smalltalk import model, interpreter, primitives, shadow -from pypy.lang.smalltalk import objtable -from pypy.lang.smalltalk.utility import wrap_int -from pypy.lang.smalltalk import classtable -from pypy.lang.smalltalk.tool.analyseimage import * +import os, sys +from pypy.lang.smalltalk import model, interpreter, primitives, shadow, constants +from pypy.lang.smalltalk.tool.analyseimage import create_squeakimage # This loads the whole mini.image in advance. At run-time, # it executes the tinyBenchmark. In this way we get an RPython @@ -18,22 +15,22 @@ def tinyBenchmarks(): - image = create_squeakimage() - interp = interpreter.Interpreter() + from pypy.lang.smalltalk import objspace + space = objspace.ObjSpace() + image = create_squeakimage(space) + interp = interpreter.Interpreter(space) w_object = model.W_SmallInteger(0) # Should get this from w_object w_smallint_class = image.special(constants.SO_SMALLINTEGER_CLASS) - s_class = w_object.shadow_of_my_class() + s_class = w_object.shadow_of_my_class(space) w_method = s_class.lookup("tinyBenchmarks") assert w_method - w_frame = w_method.create_frame(w_object, []) - interp.w_active_context = w_frame + w_frame = w_method.create_frame(space, w_object, []) + interp.store_w_active_context(w_frame) - print w_method - print "Going to execute %d toplevel bytecodes" % (len(w_method.bytes),) counter = 0 from pypy.lang.smalltalk.interpreter import BYTECODE_TABLE Modified: pypy/branch/build-external/pypy/translator/goal/test2/test_app_main.py ============================================================================== --- pypy/branch/build-external/pypy/translator/goal/test2/test_app_main.py (original) +++ pypy/branch/build-external/pypy/translator/goal/test2/test_app_main.py Tue Jun 10 12:48:46 2008 @@ -312,6 +312,22 @@ finally: os.environ['PYTHONINSPECT'] = old + def test_stdout_flushes_before_stdin_blocks(self): + # This doesn't really test app_main.py, but a behavior that + # can only be checked on top of py.py with pexpect. + path = getscript(""" + import sys + sys.stdout.write('Are you suggesting coconuts migrate? ') + line = sys.stdin.readline() + assert line.rstrip() == 'Not at all. They could be carried.' + print 'A five ounce bird could not carry a one pound coconut.' + """) + py_py = os.path.join(autopath.pypydir, 'bin', 'py.py') + child = self._spawn(sys.executable, [py_py, path]) + child.expect('Are you suggesting coconuts migrate?', timeout=120) + child.sendline('Not at all. They could be carried.') + child.expect('A five ounce bird could not carry a one pound coconut.') + class TestNonInteractive: @@ -402,3 +418,22 @@ expect_prompt=True, expect_banner=False) assert 'hello world\n' in data assert '42\n' in data + + def test_non_interactive_stdout_fully_buffered(self): + path = getscript(r""" + import sys, time + sys.stdout.write('\x00(STDOUT)\n\x00') # stays in buffers + time.sleep(1) + sys.stderr.write('\x00[STDERR]\n\x00') + time.sleep(1) + # stdout flushed automatically here + """) + cmdline = '%s -u "%s" %s' % (sys.executable, app_main, path) + print 'POPEN:', cmdline + child_in, child_out_err = os.popen4(cmdline) + data = child_out_err.read(11) + assert data == '\x00[STDERR]\n\x00' # from stderr + child_in.close() + data = child_out_err.read(11) + assert data == '\x00(STDOUT)\n\x00' # from stdout + child_out_err.close() Modified: pypy/branch/build-external/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/build-external/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/build-external/pypy/translator/tool/cbuild.py Tue Jun 10 12:48:46 2008 @@ -16,19 +16,18 @@ class ExternalCompilationInfo(object): - _ATTRIBUTES = ['pre_include_lines', 'includes', 'include_dirs', - 'post_include_lines', 'libraries', 'library_dirs', + _ATTRIBUTES = ['pre_include_bits', 'includes', 'include_dirs', + 'post_include_bits', 'libraries', 'library_dirs', 'separate_module_sources', 'separate_module_files', 'export_symbols', 'compile_extra', 'link_extra', 'extra_objects', 'frameworks'] - _AVOID_DUPLICATES = ['separate_module_files', 'libraries', 'includes', - 'include_dirs', 'library_dirs', 'separate_module_sources'] + _DUPLICATES_OK = ['compile_extra', 'link_extra'] def __init__(self, - pre_include_lines = [], + pre_include_bits = [], includes = [], include_dirs = [], - post_include_lines = [], + post_include_bits = [], libraries = [], library_dirs = [], separate_module_sources = [], @@ -39,17 +38,18 @@ extra_objects = [], frameworks = []): """ - pre_include_lines: list of lines that should be put at the top + pre_include_bits: list of pieces of text that should be put at the top of the generated .c files, before any #include. They shouldn't - contain an #include themselves. + contain an #include themselves. (Duplicate pieces are removed.) includes: list of .h file names to be #include'd from the generated .c files. include_dirs: list of dir names that is passed to the C compiler - post_include_lines: list of lines that should be put at the top - of the generated .c files, after the #includes. + post_include_bits: list of pieces of text that should be put at the top + of the generated .c files, after the #includes. (Duplicate pieces are + removed.) libraries: list of library names that is passed to the linker @@ -58,7 +58,7 @@ separate_module_sources: list of multiline strings that are each written to a .c file and compiled separately and linked later on. (If function prototypes are needed for other .c files - to access this, they can be put in post_include_lines.) + to access this, they can be put in post_include_bits.) separate_module_files: list of .c file names that are compiled separately and linked later on. (If an .h file is needed for @@ -89,7 +89,7 @@ """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix compiler flags format.""" - pre_include_lines = [] + pre_include_bits = [] include_dirs = [] compile_extra = [] for arg in flags.split(): @@ -101,13 +101,13 @@ macro, value = macro.split('=') else: value = '1' - pre_include_lines.append('#define %s %s' % (macro, value)) + pre_include_bits.append('#define %s %s' % (macro, value)) elif arg.startswith('-L') or arg.startswith('-l'): raise ValueError('linker flag found in compiler options: %r' % (arg,)) else: compile_extra.append(arg) - return cls(pre_include_lines=pre_include_lines, + return cls(pre_include_bits=pre_include_bits, include_dirs=include_dirs, compile_extra=compile_extra) from_compiler_flags = classmethod(from_compiler_flags) @@ -182,7 +182,7 @@ attrs = {} for name in self._ATTRIBUTES: - if name not in self._AVOID_DUPLICATES: + if name in self._DUPLICATES_OK: s = [] for i in [self] + others: s += getattr(i, name) @@ -199,12 +199,12 @@ return ExternalCompilationInfo(**attrs) def write_c_header(self, fileobj): - for line in self.pre_include_lines: - print >> fileobj, line + for piece in self.pre_include_bits: + print >> fileobj, piece for path in self.includes: print >> fileobj, '#include <%s>' % (path,) - for line in self.post_include_lines: - print >> fileobj, line + for piece in self.post_include_bits: + print >> fileobj, piece def _copy_attributes(self): d = {} @@ -536,6 +536,7 @@ def build(self, option): compiler = self.compiler + compiler.fix_gcc_random_seed = True compiler.compile_extra.append(option) compiler.link_extra.append(option) try: @@ -548,6 +549,7 @@ pass class CCompiler: + fix_gcc_random_seed = False def __init__(self, cfilenames, eci, outputfilename=None, compiler_exe=None, profbased=None): @@ -645,11 +647,21 @@ objects = list(self.eci.extra_objects) for cfile in self.cfilenames: cfile = py.path.local(cfile) + compile_extra = self.compile_extra[:] + # -frandom-seed is only to try to be as reproducable as possible + if self.fix_gcc_random_seed: + compile_extra.append('-frandom-seed=%s' % (cfile.basename,)) + # XXX horrible workaround for a bug of profiling in gcc on + # OS X with functions containing a direct call to fork() + if '/*--no-profiling-for-this-file!--*/' in cfile.read(): + compile_extra = [arg for arg in compile_extra + if not arg.startswith('-fprofile-')] + old = cfile.dirpath().chdir() try: res = compiler.compile([cfile.basename], include_dirs=self.eci.include_dirs, - extra_preargs=self.compile_extra) + extra_preargs=compile_extra) assert len(res) == 1 cobjfile = py.path.local(res[0]) assert cobjfile.check() Modified: pypy/branch/build-external/pypy/translator/tool/test/test_cbuild.py ============================================================================== --- pypy/branch/build-external/pypy/translator/tool/test/test_cbuild.py (original) +++ pypy/branch/build-external/pypy/translator/tool/test/test_cbuild.py Tue Jun 10 12:48:46 2008 @@ -58,38 +58,38 @@ def test_merge(self): e1 = ExternalCompilationInfo( - pre_include_lines = ['1'], + pre_include_bits = ['1'], includes = ['x.h'], - post_include_lines = ['p1'] + post_include_bits = ['p1'] ) e2 = ExternalCompilationInfo( - pre_include_lines = ['2'], + pre_include_bits = ['2'], includes = ['x.h', 'y.h'], - post_include_lines = ['p2'], + post_include_bits = ['p2'], ) e3 = ExternalCompilationInfo( - pre_include_lines = ['3'], + pre_include_bits = ['3'], includes = ['y.h', 'z.h'], - post_include_lines = ['p3'] + post_include_bits = ['p1', 'p3'] ) e = e1.merge(e2, e3) - assert e.pre_include_lines == ('1', '2', '3') + assert e.pre_include_bits == ('1', '2', '3') assert e.includes == ('x.h', 'y.h', 'z.h') - assert e.post_include_lines == ('p1', 'p2', 'p3') + assert e.post_include_bits == ('p1', 'p2', 'p3') def test_merge2(self): e1 = ExternalCompilationInfo( - pre_include_lines = ['1'], + pre_include_bits = ['1'], ) e2 = ExternalCompilationInfo( - pre_include_lines = ['2'], + pre_include_bits = ['2'], ) e3 = ExternalCompilationInfo( - pre_include_lines = ['3'], + pre_include_bits = ['3'], ) e = e1.merge(e2) e = e.merge(e3, e3) - assert e.pre_include_lines == ('1', '2', '3') + assert e.pre_include_bits == ('1', '2', '3') def test_convert_sources_to_c_files(self): cs = CompilationSet( @@ -130,8 +130,8 @@ flags = ('-I/some/include/path -I/other/include/path ' '-DMACRO1 -D_MACRO2=baz -?1 -!2') eci = ExternalCompilationInfo.from_compiler_flags(flags) - assert eci.pre_include_lines == ('#define MACRO1 1', - '#define _MACRO2 baz') + assert eci.pre_include_bits == ('#define MACRO1 1', + '#define _MACRO2 baz') assert eci.includes == () assert eci.include_dirs == ('/some/include/path', '/other/include/path') From antocuni at codespeak.net Tue Jun 10 14:54:38 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 10 Jun 2008 14:54:38 +0200 (CEST) Subject: [pypy-svn] r55736 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080610125438.798C0169E79@codespeak.net> Author: antocuni Date: Tue Jun 10 14:54:35 2008 New Revision: 55736 Modified: pypy/dist/pypy/interpreter/module.py pypy/dist/pypy/interpreter/test/test_module.py pypy/dist/pypy/interpreter/typedef.py Log: try to make the repr of module objects more similar to cpython's Modified: pypy/dist/pypy/interpreter/module.py ============================================================================== --- pypy/dist/pypy/interpreter/module.py (original) +++ pypy/dist/pypy/interpreter/module.py Tue Jun 10 14:54:35 2008 @@ -66,3 +66,11 @@ w_import = space.builtin.get('__import__') return space.newtuple([w_import, space.newtuple([w_name])]) + def descr_module__repr__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + name = space.str_w(space.repr(self.w_name)) + if isinstance(self, MixedModule): + return space.wrap("" % name) + w___file__ = space.getattr(self, space.wrap('__file__')) + __file__ = space.str_w(space.repr(w___file__)) + return space.wrap("" % (name, __file__)) Modified: pypy/dist/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_module.py (original) +++ pypy/dist/pypy/interpreter/test/test_module.py Tue Jun 10 14:54:35 2008 @@ -52,3 +52,14 @@ skip("need PyPy for sys.__file__ checking") assert sys.__file__ assert os.path.basename(sys.__file__) == 'sys' + + def test_repr(self): + import sys + r = repr(sys) + assert r == "" + + import _exceptions # known to be in pypy/lib + r = repr(_exceptions) + assert r.startswith("') Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Tue Jun 10 14:54:35 2008 @@ -704,6 +704,8 @@ __new__ = interp2app(Module.descr_module__new__.im_func, unwrap_spec=[ObjSpace, W_Root, Arguments]), __init__ = interp2app(Module.descr_module__init__), + __repr__ = interp2app(Module.descr_module__repr__, + unwrap_spec=['self', ObjSpace]), __reduce__ = interp2app(Module.descr__reduce__, unwrap_spec=['self', ObjSpace]), __dict__ = GetSetProperty(descr_get_dict, cls=Module), # module dictionaries are readonly attributes From antocuni at codespeak.net Tue Jun 10 17:08:31 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 10 Jun 2008 17:08:31 +0200 (CEST) Subject: [pypy-svn] r55737 - pypy/django/django/db/models Message-ID: <20080610150831.115E22A0191@codespeak.net> Author: antocuni Date: Tue Jun 10 17:08:30 2008 New Revision: 55737 Modified: pypy/django/django/db/models/base.py Log: revert this line to its original content, since the extra check is not needed when you use pypy-c --oldstyle, and pypy-c withouth --oldstyle doesn't work anyway Modified: pypy/django/django/db/models/base.py ============================================================================== --- pypy/django/django/db/models/base.py (original) +++ pypy/django/django/db/models/base.py Tue Jun 10 17:08:30 2008 @@ -135,7 +135,8 @@ def add_to_class(cls, name, value): if name == 'Admin': - assert type(value) in (types.ClassType, type), "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) + assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) + value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')])) if hasattr(value, 'contribute_to_class'): value.contribute_to_class(cls, name) From fijal at codespeak.net Tue Jun 10 21:27:35 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 10 Jun 2008 21:27:35 +0200 (CEST) Subject: [pypy-svn] r55742 - pypy/dist/pypy/lib Message-ID: <20080610192735.CB7382A00DB@codespeak.net> Author: fijal Date: Tue Jun 10 21:27:35 2008 New Revision: 55742 Modified: pypy/dist/pypy/lib/imp.py Log: Raise ImportError on load_dynamic, helps some apps Modified: pypy/dist/pypy/lib/imp.py ============================================================================== --- pypy/dist/pypy/lib/imp.py (original) +++ pypy/dist/pypy/lib/imp.py Tue Jun 10 21:27:35 2008 @@ -78,6 +78,9 @@ return load_compiled(name, filename, file) raise ValueError, 'invalid description argument: %r' % (description,) +def load_dynamic(name, *args, **kwds): + raise ImportError(name) + def load_source(name, pathname, file=None): autoopen = file is None if autoopen: From fijal at codespeak.net Wed Jun 11 04:55:34 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 11 Jun 2008 04:55:34 +0200 (CEST) Subject: [pypy-svn] r55745 - pypy/branch/faster-ctypes/pypy/rlib Message-ID: <20080611025534.564B3398008@codespeak.net> Author: fijal Date: Wed Jun 11 04:55:32 2008 New Revision: 55745 Modified: pypy/branch/faster-ctypes/pypy/rlib/libffi.py Log: Leave a comment about possible improvements Modified: pypy/branch/faster-ctypes/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/rlib/libffi.py (original) +++ pypy/branch/faster-ctypes/pypy/rlib/libffi.py Wed Jun 11 04:55:32 2008 @@ -446,6 +446,11 @@ self.funcsym = funcsym self.argnum = len(self.argtypes) self.pushed_args = 0 + # XXX consider doing the following: + # 1. make this thread-local, so we won't interfere with any + # other thread eventually + # 2. consider packing it into a struct, this might yield better + # cache-performance, but don't do this without benchmarking! self.ll_args = lltype.malloc(rffi.VOIDPP.TO, self.argnum, flavor='raw') for i in range(self.argnum): # space for each argument From fijal at codespeak.net Wed Jun 11 04:59:57 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 11 Jun 2008 04:59:57 +0200 (CEST) Subject: [pypy-svn] r55746 - pypy/branch/faster-ctypes/pypy/rlib/test Message-ID: <20080611025957.91A01398004@codespeak.net> Author: fijal Date: Wed Jun 11 04:59:57 2008 New Revision: 55746 Modified: pypy/branch/faster-ctypes/pypy/rlib/test/test_libffi.py Log: Fix a test by inserting explicit keepalive Modified: pypy/branch/faster-ctypes/pypy/rlib/test/test_libffi.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/rlib/test/test_libffi.py (original) +++ pypy/branch/faster-ctypes/pypy/rlib/test/test_libffi.py Wed Jun 11 04:59:57 2008 @@ -11,6 +11,7 @@ import os, sys import py import time +from pypy.rlib.objectmodel import keepalive_until_here def setup_module(mod): if not (sys.platform.startswith('linux') or @@ -38,12 +39,15 @@ return CDLL('msvcrt.dll') else: return CDLL('/lib/libc.so.6') - - def get_libm(self): + + def _libmname(self): if sys.platform == 'win32': - return CDLL('msvcrt.dll') + return 'msvcrt.dll' else: - return CDLL('libm.so') + return 'libm.so' + + def get_libm(self): + return CDLL(self._libmname()) def test_library_open(self): lib = self.get_libc() @@ -193,17 +197,17 @@ # forget this in code that is meant to be def test_compile(self): - import py - py.test.skip("Segfaulting test, skip") # XXX cannot run it on top of llinterp, some problems # with pointer casts + libname = self._libmname() def f(x, y): - libm = self.get_libm() + libm = CDLL(libname) c_pow = libm.getpointer('pow', [ffi_type_double, ffi_type_double], ffi_type_double) c_pow.push_arg(x) c_pow.push_arg(y) res = c_pow.call(rffi.DOUBLE) + keepalive_until_here(libm) return res fn = compile(f, [float, float]) From antocuni at codespeak.net Wed Jun 11 14:39:30 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 11 Jun 2008 14:39:30 +0200 (CEST) Subject: [pypy-svn] r55751 - in pypy/branch/eval-loop-experiments/pypy: config interpreter Message-ID: <20080611123930.5097C39B59D@codespeak.net> Author: antocuni Date: Wed Jun 11 14:39:28 2008 New Revision: 55751 Modified: pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py pypy/branch/eval-loop-experiments/pypy/interpreter/pyopcode.py Log: try yet another way to encode bytecodes; this time, opargs are decoded in advance, but they are stored togheter with the opcodes in a list of ints. This code is not very well tested nor well written, I commit it just to do benchmarks on different machines Modified: pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py (original) +++ pypy/branch/eval-loop-experiments/pypy/config/pypyoption.py Wed Jun 11 14:39:28 2008 @@ -143,6 +143,10 @@ default=False, requires=[("objspace.usepycfiles", False)]), + BoolOption("predecodeargs", "predecode opargs and opcodes, but store them in the same list", + default=False, + requires=[("objspace.usepycfiles", False)]), + BoolOption("honor__builtins__", "Honor the __builtins__ key of a module dictionary", default=False), Modified: pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py ============================================================================== --- pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py (original) +++ pypy/branch/eval-loop-experiments/pypy/interpreter/pycode.py Wed Jun 11 14:39:28 2008 @@ -117,12 +117,17 @@ return self._signature def precompute_code(self, code): - from pypy.interpreter.pyopcode import decode_opcode - if not self.space.config.objspace.usecodeargs: + if self.space.config.objspace.usecodeargs: + self.compute_codeargs(code) + elif self.space.config.objspace.predecodeargs: + self.precompute_codeargs(code) + else: + # "normal" case self.co_code = code self.co_codeargs = None - return + def compute_codeargs(self, code): + from pypy.interpreter.pyopcode import decode_opcode next_instr = 0 codeargs = [] codelist = [] @@ -162,6 +167,46 @@ self.co_code = ''.join(codelist) self.co_codeargs = codeargs + def precompute_codeargs(self, code): + from pypy.interpreter.pyopcode import decode_opcode + next_instr = 0 + codelist = [] + orig2new = {} # index in code --> index in codelist + new2orig = {} # index in codelist --> index in code + while next_instr < len(code): + opcode = ord(code[next_instr]) + orig2new[next_instr] = len(codelist) + new2orig[len(codelist)] = next_instr + next_instr += 1 + next_instr, opcode, oparg = decode_opcode(code, next_instr, opcode) + codelist.append(opcode) + codelist.append(oparg) + + # sanity check + for i, j in orig2new.iteritems(): + assert ord(code[i]) == codelist[j] + + # recompute target addresses + i = 0 + while i Author: antocuni Date: Wed Jun 11 15:40:22 2008 New Revision: 55757 Modified: pypy/django/django/db/models/options.py Log: remove this lines that we added, they are not needed when using pypy-c --oldstyle Modified: pypy/django/django/db/models/options.py ============================================================================== --- pypy/django/django/db/models/options.py (original) +++ pypy/django/django/db/models/options.py Wed Jun 11 15:40:22 2008 @@ -58,9 +58,6 @@ meta_attrs = self.meta.__dict__.copy() del meta_attrs['__module__'] del meta_attrs['__doc__'] - for name in ['__dict__', '__weakref__']: - if name in meta_attrs: - del meta_attrs[name] for attr_name in DEFAULT_NAMES: if attr_name in meta_attrs: setattr(self, attr_name, meta_attrs.pop(attr_name)) From cami at codespeak.net Thu Jun 12 09:53:05 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Thu, 12 Jun 2008 09:53:05 +0200 (CEST) Subject: [pypy-svn] r55774 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080612075305.0C288169F8C@codespeak.net> Author: cami Date: Thu Jun 12 09:53:03 2008 New Revision: 55774 Modified: pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Log: bug tracking, minor test cleanup Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Thu Jun 12 09:53:03 2008 @@ -791,8 +791,8 @@ delta |= 0x60 if (self.a.get() & 0x0F) > 0x09: delta |= 0x06 - if (self.a.get() & 0xF0) > 0x80: - delta |= 0x60 + if (self.a.get() & 0xF0) > 0x80: + delta |= 0x60 if (self.a.get() & 0xF0) > 0x90: delta |= 0x60 if not self.is_n(): Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu.py Thu Jun 12 09:53:03 2008 @@ -355,7 +355,7 @@ cpu.f.set(~flags[i]) cycle_test(cpu, opCode, 2) assert cpu.pc.get() == pc+1 - value += 3 + value += 3 opCode += 0x08 # ld_BC_nnnn to ld_SP_nnnn @@ -369,11 +369,11 @@ cycle_test(cpu, opCode, 3) assert registers[index].get_lo() == value+1 assert registers[index].get_hi() == value - value += 3 + value += 3 opCode += 0x10 # add_HL_BC to add_HL_SP -def test_0x09_0x19_0x29_0x39(): +def test_0x09_0x19_0x29_0x39_add_HL(): cpu = get_cpu() registers = [cpu.bc, cpu.de, cpu.hl, cpu.sp] value = 0x1234 @@ -384,7 +384,7 @@ assert registers[i].get() == value cycle_test(cpu, opCode, 2) assert cpu.hl.get() == value+value - value += 3 + value += 3 opCode += 0x10 # ld_BCi_A @@ -480,7 +480,7 @@ assert registers[i].get() == value + 1 cpu.reset() opCode += 0x10 - value += 3 + value += 3 # dec_BC def test_0x0B_to_0c38_dec_double_registers(): @@ -496,7 +496,7 @@ cpu.reset() cpu.reset() opCode += 0x10 - value += 3 + value += 3 def test_inc(): cpu = get_cpu() @@ -531,7 +531,7 @@ assert register.get() == value+1 cpu.reset() opCode += 0x08 - value += 3 + value += 3 # inc_HLi def test_0x34(): @@ -585,7 +585,7 @@ cycle_test(cpu, opCode, 1) assert register.get() == value-1 opCode += 0x08 - value += 3 + value += 3 # dec_HLi def test_0x35(): @@ -766,7 +766,7 @@ # add_A_B to add_A_A -def test_0x80_to_0x87(): +def test_0x80_to_0x87_add_A(): cpu = get_cpu() opCode = 0x80 valueA = 0x11 @@ -776,9 +776,10 @@ cpu.reset() cpu.a.set(valueA) register.set(value) - numCycles= 1 if register == cpu.hli: numCycles = 2 + else: + numCycles= 1 cycle_test(cpu, opCode, numCycles) if register == cpu.a: assert cpu.a.get() == 2*value @@ -815,8 +816,7 @@ assert cpu.a.get() == 2*value+1 else: assert cpu.a.get() == 2*value - - value += 3 + value += 3 opCode += 0x01 # sub_A_B to sub_A_A @@ -834,7 +834,7 @@ numCycles = 2 cycle_test(cpu, opCode, numCycles) assert cpu.a.get() == 0 - value += 3 + value += 3 opCode += 0x01 # sbc_A_B to sbc_A_A @@ -866,7 +866,7 @@ else: assert cpu.a.get() == 0 - value += 3 + value += 3 opCode += 0x01 # and_A_B to and_A_A @@ -888,7 +888,7 @@ assert cpu.a.get() == (value & value) else: assert cpu.a.get() == (valueA & value) - value += 1 + value += 1 opCode += 0x01 # xor_A_B to xor_A_A @@ -910,7 +910,7 @@ assert cpu.a.get() == (value ^ value) else: assert cpu.a.get() == (valueA ^ value) - value += 1 + value += 1 opCode += 0x01 @@ -933,7 +933,7 @@ assert cpu.a.get() == (value | value) else: assert cpu.a.get() == (valueA | value) - value += 1 + value += 1 opCode += 0x01 # cp_A_B to cp_A_A @@ -953,7 +953,7 @@ cycle_test(cpu, opCode, numCycles) if register == cpu.a: valueA = value - value += 1 + value += 1 opCode += 0x01 # ret_NZ to ret_C @@ -974,7 +974,7 @@ cpu.f.set(~flags[i]) cycle_test(cpu, opCode, 2) assert_default_registers(cpu, f=cpu.f.get()) - value += 3 + value += 3 opCode += 0x08 # ldh_mem_A @@ -1055,7 +1055,7 @@ prepare_for_pop(cpu, value >> 8, value & 0xFF) cycle_test(cpu, opCode, 3) assert register.get() == value - value += 3 + value += 3 opCode += 0x10 # ret @@ -1116,8 +1116,8 @@ assert cpu.cycles == 0 assert cpu.halted == False assert_default_registers(cpu, pc=cpu.interrupt.vblank.call_code, sp=sp-2) - assert cpu.pop() == 0x34 - assert cpu.pop() == 0x12 + assert cpu.pop() == 0x34 + assert cpu.pop() == 0x12 # ld_PC_HL def test_0xE9_store_hl_in_pc(): @@ -1157,7 +1157,7 @@ pc = cpu.pc.get() cycle_test(cpu, opCode, 3) assert_default_registers(cpu, f=~flags[i] & 0xFF, pc=pc+2) - value += 3 + value += 3 opCode += 0x08 # ldh_Ci_A @@ -1296,7 +1296,7 @@ assert cpu.memory.read(cpu.sp.get()+1) == value >> 8 assert cpu.memory.read(cpu.sp.get()) == value & 0xFF opCode += 0x10 - value += 0x0101 + value += 0x0101 # call_nnnn @@ -1403,7 +1403,7 @@ fetch_execute_cycle_test_second_order(cpu, opCode, cycles) assert register.get() == createFunction(value) opCode += 0x01 - value += 1 + value += 1 # rlc_B to rlc_A def test_0x00_to_0x07_rotateLeftCircular(): Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Thu Jun 12 09:53:03 2008 @@ -164,6 +164,7 @@ method_value_call(cpu, CPU.add_a, 0x00) assert cpu.a.get() == 0x00 assert_flags(cpu, z=True, n=False, h=False, c=False) + add_flag_test(cpu, CPU.add_a) @@ -222,9 +223,70 @@ assert cpu.sp.get() == 0xFF - i assert_flags(cpu, z=False, n=False, h=False, c=False) -def test_add_sp_cary_flags(): +def test_add_sp_carry(): cpu = get_cpu() - py.test.skip("test not yet implemented") + cpu.f.set(0xFF) + cpu.sp.set(0xFF) + prepare_for_fetch(cpu, 0xFF) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0xFE + assert_flags(cpu, z=False, n=False, h=False, c=False) + + cpu.f.set(0x00) + cpu.sp.set(0xFF) + prepare_for_fetch(cpu, 0xFF) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0xFE + assert_flags(cpu, z=False, n=False, h=False, c=False) + + cpu.f.set(0x00) + cpu.sp.set(0x00) + prepare_for_fetch(cpu, 0x01) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x01 + assert_flags(cpu, z=False, n=False, h=False, c=False) + + cpu.f.set(0xFF) + cpu.sp.set(0x00) + prepare_for_fetch(cpu, 0x01) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x01 + assert_flags(cpu, z=False, n=False, h=False, c=False) + + cpu.f.set(0xFF) + cpu.sp.set(0x02) + prepare_for_fetch(cpu, 0xFE) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x00 + assert_flags(cpu, z=False, n=False, h=False, c=False) + +def test_add_sp_carry_flags(): + cpu = get_cpu() + cpu.f.set(0xFF) + cpu.sp.set(0x0FFF) + prepare_for_fetch(cpu, 0x01) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x1000 + assert_flags(cpu, z=False, n=False, h=True, c=False) + + cpu.sp.set(0x1000) + prepare_for_fetch(cpu, 0xFF) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x0FFF + assert_flags(cpu, z=False, n=False, h=True, c=False) + + cpu.sp.set(0xFFFF) + prepare_for_fetch(cpu, 0x01) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0x0000 + assert_flags(cpu, z=False, n=False, h=True, c=True) + + cpu.sp.set(0x0000) + prepare_for_fetch(cpu, 0xFF) + cpu.increment_sp_by_fetch() + assert cpu.sp.get() == 0xFFFF + assert_flags(cpu, z=False, n=False, h=True, c=True) + def test_and_a(): cpu = get_cpu() @@ -457,10 +519,12 @@ py.test.skip("not yet implemented") cpu = get_cpu() cpu.f.set(0xFF) + cpu.a.set(0) cpu.decimal_adjust_a() assert_flags(cpu, z=False, n=True, h=False, c=False) cpu.f.set(0x00) + cpu.a.set(0) cpu.decimal_adjust_a() assert_flags(cpu, z=False, n=False, h=False, c=False) @@ -576,7 +640,7 @@ cpu.f.set(0xFF) prepare_for_double_fetch(cpu, 0x1234) cpu.jump() - assert cpu.f.get() == 0xFF + assert cpu.f.get() == 0xFF assert cpu.pc.get() == 0x1234 def test_conditional_jump(): @@ -584,13 +648,13 @@ cpu.f.set(0xFF) prepare_for_double_fetch(cpu, 0x1234) cpu.conditional_jump(True) - assert cpu.f.get() == 0xFF + assert cpu.f.get() == 0xFF assert cpu.pc.get() == 0x1234 cpu.pc.set(0x1234) prepare_for_double_fetch(cpu, 0x1234) cpu.conditional_jump(False) - assert cpu.f.get() == 0xFF + assert cpu.f.get() == 0xFF assert cpu.pc.get() == 0x1234+2 def test_process_2_complement(): @@ -610,16 +674,16 @@ cpu.pc.set(0x1234) prepare_for_fetch(cpu, i) cpu.relative_jump() - assert cpu.f.get() == 0xFF - #+1 fpr a single fetch + assert cpu.f.get() == 0xFF + #+1 for a single fetch assert cpu.pc.get() == 0x1234+1 + i for i in range(1, 0x7F): cpu.pc.set(0x1234) prepare_for_fetch(cpu, 0xFF - i+1) cpu.relative_jump() - assert cpu.f.get() == 0xFF - #+1 fpr a single fetch + assert cpu.f.get() == 0xFF + #+1 for a single fetch assert cpu.pc.get() == 0x1234+1 - i def test_conditional_relative_jump(): @@ -630,7 +694,7 @@ prepare_for_fetch(cpu, i) cpu.relative_conditional_jump(True) assert cpu.f.get() == 0xFF - #+1 fpr a single fetch + #+1 for a single fetch assert cpu.pc.get() == 0x1234+1 + i cpu.pc.set(0x1234) @@ -803,7 +867,6 @@ assert cpu.a.get() == 0x01 assert_flags(cpu, z=False, n=False, h=False, c=False) - def test_subtract_with_carry_a(): cpu = get_cpu() cpu.f.set(0xFF) @@ -830,7 +893,7 @@ assert cpu.a.get() == 0xFF assert_flags(cpu, z=False, n=True, h=True, c=True) - # FIXME add separated Test for each flag + subtract_flag_test(cpu, CPU.subtract_with_carry_a) def test_subtract_a(): cpu = get_cpu() @@ -840,31 +903,39 @@ assert cpu.a.get() == 0xFE assert_flags(cpu, z=False, n=True, h=False, c=False) + cpu.f.set(0xFF) + cpu.a.set(0x01) + method_value_call(cpu, CPU.subtract_a, 0x01) + assert cpu.a.get() == 0x00 + assert_flags(cpu, z=True, n=True, h=False, c=False) + + subtract_flag_test(cpu, CPU.subtract_a) + +def subtract_flag_test(cpu, method): cpu.f.set(0x00) cpu.a.set(0xFF) method_value_call(cpu, CPU.subtract_a, 0x01) assert cpu.a.get() == 0xFE assert_flags(cpu, z=False, n=True, h=False, c=False) - cpu.f.set(0xFF) + cpu.f.set(0x00) cpu.a.set(0x01) method_value_call(cpu, CPU.subtract_a, 0x01) assert cpu.a.get() == 0x00 assert_flags(cpu, z=True, n=True, h=False, c=False) - cpu.f.set(0xFF) + cpu.f.set(0x00) cpu.a.set(0x10) method_value_call(cpu, CPU.subtract_a, 0x01) assert cpu.a.get() == 0x0F assert_flags(cpu, z=False, n=True, h=True, c=False) - cpu.f.set(0xFF) + cpu.f.set(0x00) cpu.a.set(0x00) method_value_call(cpu, CPU.subtract_a, 0x01) assert cpu.a.get() == 0xFF assert_flags(cpu, z=False, n=True, h=True, c=True) - - + def test_swap(): cpu = get_cpu() cpu.f.set(0xFF) From cami at codespeak.net Thu Jun 12 12:36:37 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Thu, 12 Jun 2008 12:36:37 +0200 (CEST) Subject: [pypy-svn] r55779 - pypy/dist/pypy/lang/gameboy Message-ID: <20080612103637.1B25B69806A@codespeak.net> Author: cami Date: Thu Jun 12 12:36:36 2008 New Revision: 55779 Modified: pypy/dist/pypy/lang/gameboy/cpu.py Log: undo wrong replacement on lines 792++ in cpu.py some small code refactorings Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Thu Jun 12 12:36:36 2008 @@ -791,8 +791,8 @@ delta |= 0x60 if (self.a.get() & 0x0F) > 0x09: delta |= 0x06 - if (self.a.get() & 0xF0) > 0x80: - delta |= 0x60 + if (self.a.get() & 0xF0) > 0x80: + delta |= 0x60 if (self.a.get() & 0xF0) > 0x90: delta |= 0x60 if not self.is_n(): @@ -820,13 +820,11 @@ s = (self.sp.get() + offset) & 0xFFFF self.f.reset() if (offset >= 0): - if s < self.sp.get(): - self.f.c_flag = True + self.f.c_flag = (s < self.sp.get()) if (s & 0x0F00) < (self.sp.get() & 0x0F00): self.f.h_flag = True else: - if s > self.sp.get(): - self.f.c_flag = True + self.f.c_flag = (s > self.sp.get()) if (s & 0x0F00) > (self.sp.get() & 0x0F00): self.f.h_flag = True return s From cami at codespeak.net Thu Jun 12 16:21:57 2008 From: cami at codespeak.net (cami at codespeak.net) Date: Thu, 12 Jun 2008 16:21:57 +0200 (CEST) Subject: [pypy-svn] r55785 - in pypy/dist/pypy/lang/gameboy: . test Message-ID: <20080612142157.C55EF16A093@codespeak.net> Author: cami Date: Thu Jun 12 16:21:56 2008 New Revision: 55785 Modified: pypy/dist/pypy/lang/gameboy/cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu.py pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py pypy/dist/pypy/lang/gameboy/test/test_rom.py pypy/dist/pypy/lang/gameboy/test/test_video.py Log: small test improvements still annoying bucktracking Modified: pypy/dist/pypy/lang/gameboy/cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/cpu.py Thu Jun 12 16:21:56 2008 @@ -502,8 +502,7 @@ data = register.get() added = (self.hl.get() + data) # 1 cycle self.f.partial_reset(keep_z=True) - if ((added ^ self.hl.get() ^ data) & 0x1000) != 0: - self.f.h_flag = True + self.f.h_flag = (((added ^ self.hl.get() ^ data) & 0x1000) != 0) self.f.c_flag = (added >= 0x10000 or added < 0) self.hl.set(added & 0xFFFF) self.cycles -= 1 @@ -524,8 +523,7 @@ def add_sub_flag_finish(self, s, data): self.f.reset() # set the h flag if the 0x10 bit was affected - if ((s ^ self.a.get() ^ data) & 0x10) != 0: - self.f.h_flag = True + self.f.h_flag = (((s ^ self.a.get() ^ data) & 0x10) != 0) self.f.c_flag = (s >= 0x100 or s < 0) self.f.z_flag_compare(s) self.a.set(s & 0xFF) # 1 cycle @@ -551,12 +549,11 @@ self.f.reset() self.f.n_flag = True self.f.z_flag_compare(s) - self.hc_flag_finish(s) + self.subtract_hc_flag_finish(s) self.cycles -= 1 - def hc_flag_finish(self, data): - if data > self.a.get(): - self.f.c_flag = True + def subtract_hc_flag_finish(self, data): + self.f.c_flag = (data > self.a.get()) self.f.h_flag_compare(data, self.a.get()) def and_a(self, getCaller, setCaller=None): @@ -687,8 +684,7 @@ self.f.partial_reset(keep_c=True) self.f.h_flag = True self.f.z_flag = False - if (getCaller.get() & (1 << n)) == 0: - self.f.z_flag = True + self.f.z_flag = ((getCaller.get() & (1 << n)) == 0) self.cycles -= 1 def set_bit(self, getCaller, setCaller, n): Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu.py Thu Jun 12 16:21:56 2008 @@ -534,14 +534,13 @@ value += 3 # inc_HLi -def test_0x34(): +def test_0x34_increment_hli(): cpu = get_cpu() - value = 0x12 cpu.hl.set(0xCDEF) - cpu.write(cpu.hl.get(), value) - assert cpu.read(cpu.hl.get()) == value + cpu.write(cpu.hl.get(), 0x12) + assert cpu.read(cpu.hl.get()) == 0x12 cycle_test(cpu, 0x34, 3) - assert cpu.read(cpu.hl.get()) == value +1 + assert cpu.read(cpu.hl.get()) == 0x12 +1 def test_dec(): @@ -588,14 +587,13 @@ value += 3 # dec_HLi -def test_0x35(): +def test_0x35_decrement_hli(): cpu = get_cpu() - value = 0x12 cpu.hl.set(0xCDEF) - cpu.write(cpu.hl.get(), value) - assert cpu.read(cpu.hl.get()) == value + cpu.write(cpu.hl.get(), 0x12) + assert cpu.read(cpu.hl.get()) == 0x12 cycle_test(cpu, 0x35, 3) - assert cpu.read(cpu.hl.get()) == value -1 + assert cpu.read(cpu.hl.get()) == 0x12 -1 # ld_B_nn C D E H L A ) def test_0x06_to_0x3A(): @@ -788,8 +786,8 @@ value += 3 opCode += 0x01 -# adc_A_B to adx_A_A -def test_0x88_to_0x8F(): +# adc_A_B to adc_A_A +def test_0x88_to_0x8F_add_with_carry_a(): cpu = get_cpu() opCode = 0x88 value = 0x12 @@ -820,7 +818,7 @@ opCode += 0x01 # sub_A_B to sub_A_A -def test_0x90_to_0x98(): +def test_0x90_to_0x98_subtract_a(): cpu = get_cpu() opCode = 0x90 value = 0x12 @@ -838,7 +836,7 @@ opCode += 0x01 # sbc_A_B to sbc_A_A -def test_0x98_0x9F(): +def test_0x98_0x9F_subtract_with_carry_a(): cpu = get_cpu() opCode = 0x98 value = 0x12 @@ -940,20 +938,28 @@ def test_0xB8_to_0xBF_compare_a(): cpu = get_cpu() opCode = 0xB8 - value = 0x12 - valueA = 0x11 registers = [cpu.b, cpu.c, cpu.d, cpu.e, cpu.h, cpu.l, cpu.hli, cpu.a] for register in registers: cpu.reset() - cpu.a.set(valueA) - register.set(value) + cpu.a.set(0x12) + register.set(0x22) numCycles= 1 if register == cpu.hli: numCycles = 2 cycle_test(cpu, opCode, numCycles) if register == cpu.a: - valueA = value - value += 1 + assert cpu.f.z_flag == True + else: + assert cpu.f.z_flag == False + + cpu.a.set(0x12) + register.set(0x12) + numCycles= 1 + if register == cpu.hli: + numCycles = 2 + cycle_test(cpu, opCode, numCycles) + assert cpu.f.z_flag == True + opCode += 0x01 # ret_NZ to ret_C @@ -1138,7 +1144,7 @@ assert_default_registers(cpu, sp=value, hl=value) # jp_NZ_nnnn to jp_C_nnnn -def test_0xC2_to_0xDA(): +def test_0xC2_to_0xDA_conditional_jump(): cpu = get_cpu() flags = [~constants.Z_FLAG, constants.Z_FLAG, ~constants.C_FLAG, constants.C_FLAG] opCode = 0xC2 @@ -1326,19 +1332,19 @@ a_nn_test(0xC6, 2, lambda a, b, cpu: a+b) # adc_A_nn -def test_0xCE(): +def test_0xCE_add_a_with_carry_fetch(): a_nn_test(0xCE, 2, lambda a, b, cpu: a+b) # sub_A_nn -def test_0xD6(): +def test_0xD6_subtract_a_fetch(): a_nn_test(0xD6, 2, lambda a, b, cpu: a-b) # sbc_A_nn -def test_0xDE(): +def test_0xDE_subtract_with_carry_fetch(): a_nn_test(0xDE, 2, lambda a, b, cpu: a-b) # and_A_nn -def test_0xE6(): +def test_0xE6_and_a_fetch(): a_nn_test(0xE6, 2, lambda a, b, cpu: a&b) # xor_A_nn Modified: pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_cpu_2.py Thu Jun 12 16:21:56 2008 @@ -123,15 +123,26 @@ # Tests ----------------------------------------------------------------------- -def test_pa_with_carry(): +def test_add_with_carry(): cpu = get_cpu() cpu.f.set(0xFF) cpu.a.set(0x00) method_value_call(cpu, CPU.add_a_with_carry, 0x00) assert cpu.a.get() == 0x01 assert_flags(cpu, z=False, n=False, h=False, c=False) + add_flag_test(cpu, CPU.add_a_with_carry) + +def test_add_a(): + cpu = get_cpu() + cpu.f.set(0xFF) + cpu.a.set(0x00) + method_value_call(cpu, CPU.add_a, 0x00) + assert cpu.a.get() == 0x00 + assert_flags(cpu, z=True, n=False, h=False, c=False) + add_flag_test(cpu, CPU.add_a) + def add_flag_test(cpu, method): cpu.f.set(0x00) cpu.a.set(0x00) @@ -157,17 +168,6 @@ assert cpu.a.get() == 0x00 assert_flags(cpu, z=True, n=False, h=True, c=True) -def test_add_a(): - cpu = get_cpu() - cpu.f.set(0xFF) - cpu.a.set(0x00) - method_value_call(cpu, CPU.add_a, 0x00) - assert cpu.a.get() == 0x00 - assert_flags(cpu, z=True, n=False, h=False, c=False) - - add_flag_test(cpu, CPU.add_a) - - def test_add_hl(): cpu = get_cpu() cpu.f.set(0xFF) Modified: pypy/dist/pypy/lang/gameboy/test/test_rom.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_rom.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_rom.py Thu Jun 12 16:21:56 2008 @@ -31,7 +31,7 @@ pass def test_rom1_step(): - py.test.skip() + py.test.skip("rom has incorrect header") gameboy = GameBoy() gameboy.load_cartridge_file(ROM_PATH+"/rom1/rom1.raw", verify=False) cpu = gameboy.cpu @@ -58,12 +58,11 @@ def test_rom3_step(): - py.test.skip() gameboy = GameBoy() gameboy.load_cartridge_file(ROM_PATH+"/rom3/rom3.gb") cpu = gameboy.cpu # jp nop - emulate_step_op_codes_test(gameboy, [0xC3]) + emulate_step_op_codes_test(gameboy, [0, 0xC3]) emulate_step_op_codes_test(gameboy, [0]*12) emulate_step_op_codes_test(gameboy, [0xC3]*100) @@ -100,7 +99,7 @@ def test_rom5_step(): - py.test.skip("dec and inc dont work as excepted") + py.test.skip("wrong usage of inc and its c flag") gameboy = GameBoy() gameboy.load_cartridge_file(ROM_PATH+"/rom5/rom5.gb") cpu = gameboy.cpu @@ -120,7 +119,7 @@ emulate_step_op_codes_test(gameboy, [0x30]) assert cpu.pc.get() == pc-2 # looping in .loop2 - emulate_step_op_codes_test(gameboy, [0xC6, 0x30]*255) + emulate_step_op_codes_test(gameboy, [0xC6, 0x30]*0xFF) assert cpu.a.get() == 0 assert cpu.f.c_flag == True # debugg call reseting @@ -235,18 +234,18 @@ # ------------------------------------------------------------------------------ - -def test_rom7_load(): - py.test.skip("Current Default ROM Implemenation doesnt allow write") - gameboy = GameBoy() - gameboy.load_cartridge_file(ROM_PATH+"/rom7/rom7.gb") - gameboy.emulate(EMULATION_CYCLES) - cpu = gameboy.cpu - - -def test_rom7_step(): - py.test.skip("Current Default ROM Implemenation doesnt allow write") - +# +#def test_rom7_load(): +# py.test.skip("Current Default ROM Implemenation doesnt allow write") +# gameboy = GameBoy() +# gameboy.load_cartridge_file(ROM_PATH+"/rom7/rom7.gb") +# gameboy.emulate(EMULATION_CYCLES) +# cpu = gameboy.cpu +# +# +#def test_rom7_step(): +# py.test.skip("Current Default ROM Implemenation doesnt allow write") +# # ------------------------------------------------------------------------------ def test_rom8_load(): Modified: pypy/dist/pypy/lang/gameboy/test/test_video.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/test/test_video.py (original) +++ pypy/dist/pypy/lang/gameboy/test/test_video.py Thu Jun 12 16:21:56 2008 @@ -351,9 +351,3 @@ assert video.stat == 0xFE assert video.cycles == constants.MODE_2_TICKS assert not video.interrupt.lcd.is_pending() - - -def test_emulate_v_vblank_3(): - py.test.skip("not yet implemented") - - \ No newline at end of file From santagada at codespeak.net Thu Jun 12 21:50:43 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Thu, 12 Jun 2008 21:50:43 +0200 (CEST) Subject: [pypy-svn] r55796 - pypy/branch/js-refactoring-quickhacks Message-ID: <20080612195043.F27D1698096@codespeak.net> Author: santagada Date: Thu Jun 12 21:50:39 2008 New Revision: 55796 Added: pypy/branch/js-refactoring-quickhacks/ - copied from r55795, pypy/branch/js-refactoring/ Log: a branch to play with unicode and some other quick hacks From santagada at codespeak.net Thu Jun 12 21:53:28 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Thu, 12 Jun 2008 21:53:28 +0200 (CEST) Subject: [pypy-svn] r55797 - in pypy/branch/js-refactoring-quickhacks/pypy/lang/js: . test test/ecma Message-ID: <20080612195328.885E86980A2@codespeak.net> Author: santagada Date: Thu Jun 12 21:53:27 2008 New Revision: 55797 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/baseop.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jsobj.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_parser.py Log: unicode port, translates, but has limited funcionality tranlated, mostly because of missing split, lower, upper Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/baseop.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/baseop.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/baseop.py Thu Jun 12 21:53:27 2008 @@ -131,9 +131,9 @@ type1 = x.type() type2 = y.type() if type1 == type2: - if type1 == "undefined" or type1 == "null": + if type1 == u"undefined" or type1 == u"null": return True - if type1 == "number": + if type1 == u"number": n1 = x.ToNumber(ctx) n2 = y.ToNumber(ctx) if isnan(n1) or isnan(n2): @@ -141,37 +141,37 @@ if n1 == n2: return True return False - elif type1 == "string": + elif type1 == u"string": return x.ToString(ctx) == y.ToString(ctx) - elif type1 == "boolean": + elif type1 == u"boolean": return x.ToBoolean() == x.ToBoolean() # XXX rethink it here return x.ToString(ctx) == y.ToString(ctx) else: #step 14 - if (type1 == "undefined" and type2 == "null") or \ - (type1 == "null" and type2 == "undefined"): + if (type1 == u"undefined" and type2 == u"null") or \ + (type1 == u"null" and type2 == u"undefined"): return True - if type1 == "number" and type2 == "string": + if type1 == u"number" and type2 == u"string": return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber(ctx))) - if type1 == "string" and type2 == "number": + if type1 == u"string" and type2 == u"number": return AbstractEC(ctx, W_FloatNumber(x.ToNumber(ctx)), y) - if type1 == "boolean": + if type1 == u"boolean": return AbstractEC(ctx, W_FloatNumber(x.ToNumber(ctx)), y) - if type2 == "boolean": + if type2 == u"boolean": return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber(ctx))) - if (type1 == "string" or type1 == "number") and \ - type2 == "object": + if (type1 == u"string" or type1 == u"number") and \ + type2 == u"object": return AbstractEC(ctx, x, y.ToPrimitive(ctx)) - if (type2 == "string" or type2 == "number") and \ - type1 == "object": + if (type2 == u"string" or type2 == u"number") and \ + type1 == u"object": return AbstractEC(ctx, x.ToPrimitive(ctx), y) return False objtype = x.GetValue().type() if objtype == y.GetValue().type(): - if objtype == "undefined" or objtype == "null": + if objtype == u"undefined" or objtype == u"null": return True if isinstance(x, W_String) and isinstance(y, W_String): @@ -189,9 +189,9 @@ type2 = y.type() if type1 != type2: return False - if type1 == "undefined" or type1 == "null": + if type1 == u"undefined" or type1 == u"null": return True - if type1 == "number": + if type1 == u"number": n1 = x.ToNumber(ctx) n2 = y.ToNumber(ctx) if isnan(n1) or isnan(n2): @@ -199,20 +199,20 @@ if n1 == n2: return True return False - if type1 == "string": + if type1 == u"string": return x.ToString(ctx) == y.ToString(ctx) - if type1 == "boolean": + if type1 == u"boolean": return x.ToBoolean() == x.ToBoolean() return x == y def commonnew(ctx, obj, args): if not isinstance(obj, W_PrimitiveObject): - raise ThrowException(W_String('it is not a constructor')) + raise ThrowException(W_String(u'it is not a constructor')) try: res = obj.Construct(ctx=ctx, args=args) except JsTypeError: - raise ThrowException(W_String('it is not a constructor')) + raise ThrowException(W_String(u'it is not a constructor')) return res def uminus(obj, ctx): Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py Thu Jun 12 21:53:27 2008 @@ -48,7 +48,7 @@ args[0] is w_Null): # XXX later we could separate builtins and normal objects return args[0].ToObject(ctx) - return create_object(ctx, 'Object') + return create_object(ctx, u'Object') class W_BooleanObject(W_NativeObject): def Call(self, ctx, args=[], this=None): @@ -60,8 +60,8 @@ def Construct(self, ctx, args=[]): if len(args) >= 1 and not isnull_or_undefined(args[0]): Value = newbool(args[0].ToBoolean()) - return create_object(ctx, 'Boolean', Value = Value) - return create_object(ctx, 'Boolean', Value = newbool(False)) + return create_object(ctx, u'Boolean', Value = Value) + return create_object(ctx, u'Boolean', Value = newbool(False)) class W_NumberObject(W_NativeObject): def Call(self, ctx, args=[], this=None): @@ -78,28 +78,28 @@ def Construct(self, ctx, args=[]): if len(args) >= 1 and not isnull_or_undefined(args[0]): Value = W_FloatNumber(args[0].ToNumber(ctx)) - return create_object(ctx, 'Number', Value = Value) - return create_object(ctx, 'Number', Value = W_FloatNumber(0.0)) + return create_object(ctx, u'Number', Value = Value) + return create_object(ctx, u'Number', Value = W_FloatNumber(0.0)) class W_StringObject(W_NativeObject): def Call(self, ctx, args=[], this=None): if len(args) >= 1: return W_String(args[0].ToString(ctx)) else: - return W_String('') + return W_String(u'') def Construct(self, ctx, args=[]): if len(args) >= 1: Value = W_String(args[0].ToString(ctx)) - return create_object(ctx, 'String', Value = Value) - return create_object(ctx, 'String', Value = W_String('')) + return Value.ToObject(ctx) + return W_String(u'').ToObject(ctx) def create_array(ctx, elements=[]): - proto = ctx.get_global().Get(ctx, 'Array').Get(ctx, 'prototype') + proto = ctx.get_global().Get(ctx, u'Array').Get(ctx, u'prototype') array = W_Array(ctx, Prototype=proto, Class = proto.Class) i = 0 while i < len(elements): - array.Put(ctx, str(i), elements[i]) + array.Put(ctx, unicode(str(i)), elements[i]) i += 1 return array @@ -108,7 +108,7 @@ def Call(self, ctx, args=[], this=None): if len(args) == 1 and isinstance(args[0], W_BaseNumber): array = create_array(ctx) - array.Put(ctx, 'length', args[0]) + array.Put(ctx, u'length', args[0]) else: array = create_array(ctx, args) return array @@ -121,7 +121,7 @@ def evaljs(ctx, args, this): if len(args) >= 1: if isinstance(args[0], W_String): - src = args[0].strval + src = args[0].ToString(ctx).encode('ascii') # XXX what is the best aproach here? else: return args[0] else: @@ -129,7 +129,7 @@ try: node = load_source(src, 'evalcode') except ParseError, e: - raise ThrowException(W_String('SyntaxError: '+str(e))) + raise ThrowException(W_String(u'SyntaxError: ' + unicode(str(e)))) bytecode = JsCode() node.emit(bytecode) @@ -138,18 +138,18 @@ def parseIntjs(ctx, args, this): if len(args) < 1: return W_FloatNumber(NAN) - s = args[0].ToString(ctx).strip(" ") + s = args[0].ToString(ctx).strip(u' ') if len(args) > 1: radix = args[1].ToInt32(ctx) else: radix = 10 - if len(s) >= 2 and (s.startswith('0x') or s.startswith('0X')) : + if len(s) >= 2 and (s.startswith(u'0x') or s.startswith(u'0X')) : radix = 16 s = s[2:] - if s == '' or radix < 2 or radix > 36: + if s == u'' or radix < 2 or radix > 36: return W_FloatNumber(NAN) try: - n = int(s, radix) + n = int(s.encode('ascii'), radix) except ValueError: return W_FloatNumber(NAN) return W_IntNumber(n) @@ -157,16 +157,16 @@ def parseFloatjs(ctx, args, this): if len(args) < 1: return W_FloatNumber(NAN) - s = args[0].ToString(ctx).strip(" ") + s = args[0].ToString(ctx).strip(u' ') try: - n = float(s) + n = float(s.encode('ascii')) except ValueError: n = NAN return W_FloatNumber(n) def printjs(ctx, args, this): - writer(",".join([i.ToString(ctx) for i in args])) + writer(u','.join([i.ToString(ctx) for i in args])) return w_Undefined def isnanjs(ctx, args, this): @@ -204,35 +204,35 @@ return w_Undefined def _ishex(ch): - return ((ch >= 'a' and ch <= 'f') or (ch >= '0' and ch <= '9') or - (ch >= 'A' and ch <= 'F')) + return ((ch >= u'a' and ch <= u'f') or (ch >= u'0' and ch <= u'9') or + (ch >= u'A' and ch <= u'F')) def unescapejs(ctx, args, this): # XXX consider using StringBuilder here res = [] if not isinstance(args[0], W_String): - raise JsTypeError(W_String("Expected string")) + raise JsTypeError(W_String(u'Expected string')) strval = args[0].strval lgt = len(strval) i = 0 while i < lgt: ch = strval[i] - if ch == '%': + if ch == u'%': if (i + 2 < lgt and _ishex(strval[i+1]) and _ishex(strval[i+2])): - ch = chr(int(strval[i + 1] + strval[i + 2], 16)) + ch = unichr(int((strval[i + 1] + strval[i + 2]).encode('ascii'), 16)) i += 2 elif (i + 5 < lgt and strval[i + 1] == 'u' and _ishex(strval[i + 2]) and _ishex(strval[i + 3]) and _ishex(strval[i + 4]) and _ishex(strval[i + 5])): - ch = unichr(int(strval[i+2:i+6], 16)) + ch = unichr(int((strval[i+2:i+6]).encode('ascii'), 16)) i += 5 i += 1 res.append(ch) - return W_String(''.join(res)) + return W_String(u''.join(res)) class W_ToString(W_NewBuiltin): def Call(self, ctx, args=[], this=None): - return W_String("[object %s]"%this.Class) + return W_String(u'[object ' + this.Class + u']') class W_ValueOf(W_NewBuiltin): def Call(self, ctx, args=[], this=None): @@ -273,10 +273,12 @@ argslist = [] for i in range(tam-1): argslist.append(args[i].ToString(ctx)) - fargs = ','.join(argslist) - functioncode = "function (%s) {%s}"%(fargs, fbody) + fargs = u','.join(argslist) + functioncode = u'function (' + fargs + u') {' + fbody + u'}' else: - functioncode = "function () {}" + functioncode = u'function () {}' + + functioncode = unicode(functioncode).encode('ascii') # XXX this is potentialy very bad #remove program and sourcelements node funcnode = parse(functioncode).children[0].children[0] ast = ASTBUILDER.dispatch(funcnode) @@ -287,15 +289,15 @@ def Construct(self, ctx, args=[]): return self.Call(ctx, args, this=None) -functionstring= 'function (arguments go here!) {\n'+ \ - ' [lots of stuff :)]\n'+ \ - '}' +functionstring= u'function (arguments go here!) {\n'+ \ + u' [lots of stuff :)]\n'+ \ + u'}' class W_FToString(W_NewBuiltin): def Call(self, ctx, args=[], this=None): - if this.Class == 'Function': + if this.Class == u'Function': return W_String(functionstring) else: - raise JsTypeError('this is not a function object') + raise JsTypeError(u'this is not a function object') class W_Apply(W_NewBuiltin): def Call(self, ctx, args=[], this=None): @@ -314,7 +316,7 @@ elif isnull_or_undefined(arrayArgs): callargs = [] else: - raise JsTypeError('arrayArgs is not an Array or Arguments object') + raise JsTypeError(u'arrayArgs is not an Array or Arguments object') except IndexError: callargs = [] return this.Call(ctx, callargs, this=thisArg) @@ -334,21 +336,21 @@ class W_ValueToString(W_NewBuiltin): "this is the toString function for objects with Value" - mytype = '' + mytype = u'' def Call(self, ctx, args=[], this=None): if this.Value.type() != self.mytype: - raise JsTypeError('Wrong type') + raise JsTypeError(u'Wrong type') return W_String(this.Value.ToString(ctx)) class W_NumberValueToString(W_ValueToString): - mytype = 'number' + mytype = u'number' class W_BooleanValueToString(W_ValueToString): - mytype = 'boolean' + mytype = u'boolean' class W_StringValueToString(W_ValueToString): - mytype = 'string' + mytype = u'string' @specialize.memo() @@ -357,7 +359,7 @@ "this is the valueOf function for objects with Value" def Call(self, ctx, args=[], this=None): if type != this.Class: - raise JsTypeError('%s.prototype.valueOf called with incompatible type' % self.type()) + raise JsTypeError(self.type() + u'.prototype.valueOf called with incompatible type') return this.Value return W_ValueValueOf @@ -366,12 +368,27 @@ temp = [] for arg in args: i = arg.ToInt32(ctx) % 65536 # XXX should be uint16 - if i > 255: - temp.append(unichr(i)) - else: - temp.append(chr(i)) + temp.append(unichr(i)) - return W_String(''.join(temp)) + return W_String(u''.join(temp)) + +class W_ToLower(W_NewBuiltin): + def Call(self, ctx, args=[], this=None): + string = this.ToString(ctx) + if we_are_translated(): + temp = string.encode('ascii') + return W_String(unicode(temp.lower())) # XXX rpython unicode doesn't have lower + else: + return W_String(string.lower()) + +class W_ToUpper(W_NewBuiltin): + def Call(self, ctx, args=[], this=None): + string = this.ToString(ctx) + if we_are_translated(): + temp = string.encode('ascii') + return W_String(unicode(temp.upper())) # XXX rpython unicode doesn't have upper + else: + return W_String(string.upper()) class W_CharAt(W_NewBuiltin): def Call(self, ctx, args=[], this=None): @@ -379,16 +396,27 @@ if len(args)>=1: pos = args[0].ToInt32(ctx) if (not pos >=0) or (pos > len(string) - 1): - return W_String('') + return W_String(u'') else: - return W_String('') + return W_String(u'') return W_String(string[pos]) +class W_CharCodeAt(W_NewBuiltin): + def Call(self, ctx, args=[], this=None): + string = this.ToString(ctx) + if len(args)>=1: + pos = args[0].ToInt32(ctx) + if (not pos >=0) or (pos > len(string) - 1): + return W_String(u'') + else: + return W_String(u'') + return W_IntNumber(ord(string[pos])) + class W_Concat(W_NewBuiltin): def Call(self, ctx, args=[], this=None): string = this.ToString(ctx) others = [obj.ToString(ctx) for obj in args] - string += ''.join(others) + string += u''.join(others) return W_String(string) class W_IndexOf(W_NewBuiltin): @@ -434,30 +462,38 @@ separator = args[0].ToString(ctx) if len(args) >= 2: - limit = args[1].ToUInt32(ctx) - raise ThrowException(W_String("limit not implemented")) + #limit = args[1].ToUInt32(ctx) + raise ThrowException(W_String(u'limit not implemented')) # array = string.split(separator, limit) else: - array = string.split(separator) + if we_are_translated(): + temp = string.encode('ascii') + tempsep = separator.encode('ascii') + arrtemp = temp.split(tempsep) + array = [] + for i in arrtemp: + array.append(unicode(i)) + else: + array = string.split(separator) w_array = create_array(ctx) i = 0 while i < len(array): w_str = W_String(array[i]) - w_array.Put(ctx, str(i), w_str) + w_array.Put(ctx, unicode(str(i)), w_str) i += 1 return w_array -def common_join(ctx, this, sep=','): - length = this.Get(ctx, 'length').ToUInt32(ctx) +def common_join(ctx, this, sep=u','): + length = this.Get(ctx, u'length').ToUInt32(ctx) l = [] i = 0 while i < length: - item = this.Get(ctx, str(i)) + item = this.Get(ctx, unicode(str(i))) if isnull_or_undefined(item): - item_string = '' + item_string = u'' else: item_string = item.ToString(ctx) l.append(item_string) @@ -467,21 +503,21 @@ class W_ArrayToString(W_NewBuiltin): def Call(self, ctx, args=[], this=None): - return W_String(common_join(ctx, this, sep=',')) + return W_String(common_join(ctx, this, sep=u',')) class W_ArrayJoin(W_NewBuiltin): def Call(self, ctx, args=[], this=None): if len(args) >= 1 and not args[0] is w_Undefined: sep = args[0].ToString(ctx) else: - sep = ',' + sep = u',' return W_String(common_join(ctx, this, sep)) class W_ArrayReverse(W_NewBuiltin): length = 0 def Call(self, ctx, args=[], this=None): - r2 = this.Get(ctx, 'length').ToUInt32(ctx) + r2 = this.Get(ctx, u'length').ToUInt32(ctx) k = r_uint(0) r3 = r_uint(math.floor( float(r2)/2.0 )) if r3 == k: @@ -489,8 +525,8 @@ while k < r3: r6 = r2 - k - 1 - r7 = str(k) - r8 = str(r6) + r7 = unicode(str(k)) + r8 = unicode(str(r6)) r9 = this.Get(ctx, r7) r10 = this.Get(ctx, r8) @@ -503,10 +539,10 @@ class W_DateFake(W_NewBuiltin): # XXX This is temporary def Call(self, ctx, args=[], this=None): - return create_object(ctx, 'Object') + return create_object(ctx, u'Object') def Construct(self, ctx, args=[]): - return create_object(ctx, 'Object') + return create_object(ctx, u'Object') def pypy_repr(ctx, repr, w_arg): return W_String(w_arg.__class__.__name__) @@ -519,175 +555,178 @@ """Creates a js interpreter""" def __init__(self): allon = DE | DD | RO - w_Global = W_Object(Class="global") + w_Global = W_Object(Class=u'global') ctx = global_context(w_Global) - w_ObjPrototype = W_Object(Prototype=None, Class='Object') + w_ObjPrototype = W_Object(Prototype=None, Class=u'Object') - w_Function = W_Function(ctx, Class='Function', + w_Function = W_Function(ctx, Class=u'Function', Prototype=w_ObjPrototype) - w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon) - w_Global.Put(ctx, 'Function', w_Function) + w_Function.Put(ctx, u'length', W_IntNumber(1), flags = allon) + w_Global.Put(ctx, u'Function', w_Function) - w_Object = W_ObjectObject('Object', w_Function) - w_Object.Put(ctx, 'prototype', w_ObjPrototype, flags = allon) - w_Object.Put(ctx, 'length', W_IntNumber(1), flags = RO | DD) - w_Global.Put(ctx, 'Object', w_Object) + w_Object = W_ObjectObject(u'Object', w_Function) + w_Object.Put(ctx, u'prototype', w_ObjPrototype, flags = allon) + w_Object.Put(ctx, u'length', W_IntNumber(1), flags = RO | DD) + w_Global.Put(ctx, u'Object', w_Object) w_Global.Prototype = w_ObjPrototype w_FncPrototype = w_Function.Call(ctx, this=w_Function) - w_Function.Put(ctx, 'prototype', w_FncPrototype, flags = allon) - w_Function.Put(ctx, 'constructor', w_Function) + w_Function.Put(ctx, u'prototype', w_FncPrototype, flags = allon) + w_Function.Put(ctx, u'constructor', w_Function) toString = W_ToString(ctx) put_values(ctx, w_ObjPrototype, { - 'constructor': w_Object, - '__proto__': w_FncPrototype, - 'toString': toString, - 'toLocaleString': toString, - 'valueOf': W_ValueOf(ctx), - 'hasOwnProperty': W_HasOwnProperty(ctx), - 'isPrototypeOf': W_IsPrototypeOf(ctx), - 'propertyIsEnumerable': W_PropertyIsEnumerable(ctx), + u'constructor': w_Object, + u'__proto__': w_FncPrototype, + u'toString': toString, + u'toLocaleString': toString, + u'valueOf': W_ValueOf(ctx), + u'hasOwnProperty': W_HasOwnProperty(ctx), + u'isPrototypeOf': W_IsPrototypeOf(ctx), + u'propertyIsEnumerable': W_PropertyIsEnumerable(ctx), }) #properties of the function prototype put_values(ctx, w_FncPrototype, { - 'constructor': w_Function, - '__proto__': w_FncPrototype, - 'toString': W_FToString(ctx), - 'apply': W_Apply(ctx), - 'call': W_Call(ctx), - 'arguments': w_Null, + u'constructor': w_Function, + u'__proto__': w_FncPrototype, + u'toString': W_FToString(ctx), + u'apply': W_Apply(ctx), + u'call': W_Call(ctx), + u'arguments': w_Null, }) - w_Boolean = W_BooleanObject('Boolean', w_FncPrototype) - w_Boolean.Put(ctx, 'constructor', w_FncPrototype, flags = allon) - w_Boolean.Put(ctx, 'length', W_IntNumber(1), flags = allon) + w_Boolean = W_BooleanObject(u'Boolean', w_FncPrototype) + w_Boolean.Put(ctx, u'constructor', w_FncPrototype, flags = allon) + w_Boolean.Put(ctx, u'length', W_IntNumber(1), flags = allon) - w_BoolPrototype = create_object(ctx, 'Object', Value=newbool(False)) - w_BoolPrototype.Class = 'Boolean' + w_BoolPrototype = create_object(ctx, u'Object', Value=newbool(False)) + w_BoolPrototype.Class = u'Boolean' put_values(ctx, w_BoolPrototype, { - 'constructor': w_FncPrototype, - '__proto__': w_ObjPrototype, - 'toString': W_BooleanValueToString(ctx), - 'valueOf': get_value_of('Boolean')(ctx), + u'constructor': w_FncPrototype, + u'__proto__': w_ObjPrototype, + u'toString': W_BooleanValueToString(ctx), + u'valueOf': get_value_of(u'Boolean')(ctx), }) - w_Boolean.Put(ctx, 'prototype', w_BoolPrototype, flags = allon) - w_Global.Put(ctx, 'Boolean', w_Boolean) + w_Boolean.Put(ctx, u'prototype', w_BoolPrototype, flags = allon) + w_Global.Put(ctx, u'Boolean', w_Boolean) #Number - w_Number = W_NumberObject('Number', w_FncPrototype) + w_Number = W_NumberObject(u'Number', w_FncPrototype) - w_empty_fun = w_Function.Call(ctx, args=[W_String('')]) + w_empty_fun = w_Function.Call(ctx, args=[W_String(u'')]) - w_NumPrototype = create_object(ctx, 'Object', Value=W_FloatNumber(0.0)) - w_NumPrototype.Class = 'Number' + w_NumPrototype = create_object(ctx, u'Object', Value=W_FloatNumber(0.0)) + w_NumPrototype.Class = u'Number' put_values(ctx, w_NumPrototype, { - 'constructor': w_Number, - '__proto__': w_empty_fun, - 'toString': W_NumberValueToString(ctx), - 'valueOf': get_value_of('Number')(ctx), + u'constructor': w_Number, + u'__proto__': w_empty_fun, + u'toString': W_NumberValueToString(ctx), + u'valueOf': get_value_of(u'Number')(ctx), }) put_values(ctx, w_Number, { - 'constructor': w_FncPrototype, - 'prototype': w_NumPrototype, - '__proto__': w_empty_fun, - 'length' : W_IntNumber(1), + u'constructor': w_FncPrototype, + u'prototype': w_NumPrototype, + u'__proto__': w_empty_fun, + u'length' : W_IntNumber(1), }) - w_Number.propdict['prototype'].flags |= RO - w_Number.Put(ctx, 'MAX_VALUE', W_FloatNumber(1.7976931348623157e308), flags = RO|DD) - w_Number.Put(ctx, 'MIN_VALUE', W_FloatNumber(0), flags = RO|DD) - w_Number.Put(ctx, 'NaN', W_FloatNumber(NAN), flags = RO|DD) + w_Number.propdict[u'prototype'].flags |= RO + w_Number.Put(ctx, u'MAX_VALUE', W_FloatNumber(1.7976931348623157e308), flags = RO|DD) + w_Number.Put(ctx, u'MIN_VALUE', W_FloatNumber(0.0), flags = RO|DD) + w_Number.Put(ctx, u'NaN', W_FloatNumber(NAN), flags = RO|DD) # ^^^ this is exactly in test case suite - w_Number.Put(ctx, 'POSITIVE_INFINITY', W_FloatNumber(INFINITY), flags = RO|DD) - w_Number.Put(ctx, 'NEGATIVE_INFINITY', W_FloatNumber(-INFINITY), flags = RO|DD) + w_Number.Put(ctx, u'POSITIVE_INFINITY', W_FloatNumber(INFINITY), flags = RO|DD) + w_Number.Put(ctx, u'NEGATIVE_INFINITY', W_FloatNumber(-INFINITY), flags = RO|DD) - w_Global.Put(ctx, 'Number', w_Number) + w_Global.Put(ctx, u'Number', w_Number) #String - w_String = W_StringObject('String', w_FncPrototype) + w_String = W_StringObject(u'String', w_FncPrototype) - w_StrPrototype = create_object(ctx, 'Object', Value=W_String('')) - w_StrPrototype.Class = 'String' + w_StrPrototype = create_object(ctx, u'Object', Value=W_String(u'')) + w_StrPrototype.Class = u'String' put_values(ctx, w_StrPrototype, { - 'constructor': w_FncPrototype, - '__proto__': w_StrPrototype, - 'toString': W_StringValueToString(ctx), - 'valueOf': get_value_of('String')(ctx), - 'charAt': W_CharAt(ctx), - 'concat': W_Concat(ctx), - 'indexOf': W_IndexOf(ctx), - 'substring': W_Substring(ctx), - 'split': W_Split(ctx), + u'constructor': w_FncPrototype, + u'__proto__': w_StrPrototype, + u'toString': W_StringValueToString(ctx), + u'valueOf': get_value_of(u'String')(ctx), + u'toLowerCase': W_ToLower(ctx), + u'toUpperCase': W_ToUpper(ctx), + u'charAt': W_CharAt(ctx), + u'charCodeAt': W_CharCodeAt(ctx), + u'concat': W_Concat(ctx), + u'indexOf': W_IndexOf(ctx), + u'substring': W_Substring(ctx), + u'split': W_Split(ctx), }) - w_String.Put(ctx, 'prototype', w_StrPrototype) - w_String.Put(ctx, 'fromCharCode', W_FromCharCode(ctx)) - w_Global.Put(ctx, 'String', w_String) + w_String.Put(ctx, u'prototype', w_StrPrototype) + w_String.Put(ctx, u'fromCharCode', W_FromCharCode(ctx)) + w_Global.Put(ctx, u'String', w_String) - w_Array = W_ArrayObject('Array', w_FncPrototype) + w_Array = W_ArrayObject(u'Array', w_FncPrototype) w_ArrPrototype = W_Array(Prototype=w_ObjPrototype) w_arr_join = W_ArrayJoin(ctx) - w_arr_join.Put(ctx, 'length', W_IntNumber(1), flags=allon) + w_arr_join.Put(ctx, u'length', W_IntNumber(1), flags=allon) put_values(ctx, w_ArrPrototype, { - 'constructor': w_FncPrototype, - '__proto__': w_ArrPrototype, - 'toString': W_ArrayToString(ctx), - 'join': w_arr_join, - 'reverse': W_ArrayReverse(ctx), + u'constructor': w_FncPrototype, + u'__proto__': w_ArrPrototype, + u'toString': W_ArrayToString(ctx), + u'join': w_arr_join, + u'reverse': W_ArrayReverse(ctx), }) - w_Array.Put(ctx, 'prototype', w_ArrPrototype, flags = allon) - w_Array.Put(ctx, '__proto__', w_FncPrototype, flags = allon) - w_Array.Put(ctx, 'length', W_IntNumber(1), flags = allon) - w_Global.Put(ctx, 'Array', w_Array) + w_Array.Put(ctx, u'prototype', w_ArrPrototype, flags = allon) + w_Array.Put(ctx, u'__proto__', w_FncPrototype, flags = allon) + w_Array.Put(ctx, u'length', W_IntNumber(1), flags = allon) + w_Global.Put(ctx, u'Array', w_Array) #Math - w_math = W_Object(Class='Math') - w_Global.Put(ctx, 'Math', w_math) - w_math.Put(ctx, '__proto__', w_ObjPrototype) - w_math.Put(ctx, 'prototype', w_ObjPrototype, flags = allon) - w_math.Put(ctx, 'abs', W_Builtin(absjs, Class='function')) - w_math.Put(ctx, 'floor', W_Builtin(floorjs, Class='function')) - w_math.Put(ctx, 'pow', W_Builtin(powjs, Class='function')) - w_math.Put(ctx, 'sqrt', W_Builtin(sqrtjs, Class='function')) - w_math.Put(ctx, 'E', W_FloatNumber(math.e)) - w_math.Put(ctx, 'PI', W_FloatNumber(math.pi)) + w_math = W_Object(Class=u'Math') + w_Global.Put(ctx, u'Math', w_math) + w_math.Put(ctx, u'__proto__', w_ObjPrototype) + w_math.Put(ctx, u'prototype', w_ObjPrototype, flags = allon) + w_math.Put(ctx, u'abs', W_Builtin(absjs, Class=u'function')) + w_math.Put(ctx, u'floor', W_Builtin(floorjs, Class=u'function')) + w_math.Put(ctx, u'pow', W_Builtin(powjs, Class=u'function')) + w_math.Put(ctx, u'sqrt', W_Builtin(sqrtjs, Class=u'function')) + w_math.Put(ctx, u'E', W_FloatNumber(math.e)) + w_math.Put(ctx, u'PI', W_FloatNumber(math.pi)) - w_Global.Put(ctx, 'version', W_Builtin(versionjs)) + w_Global.Put(ctx, u'version', W_Builtin(versionjs)) #Date - w_Date = W_DateFake(ctx, Class='Date') - w_Global.Put(ctx, 'Date', w_Date) + w_Date = W_DateFake(ctx, Class=u'Date') + w_Global.Put(ctx, u'Date', w_Date) - w_Global.Put(ctx, 'NaN', W_FloatNumber(NAN), flags = DE|DD) - w_Global.Put(ctx, 'Infinity', W_FloatNumber(INFINITY), flags = DE|DD) - w_Global.Put(ctx, 'undefined', w_Undefined, flags = DE|DD) - w_Global.Put(ctx, 'eval', W_Builtin(evaljs)) - w_Global.Put(ctx, 'parseInt', W_Builtin(parseIntjs)) - w_Global.Put(ctx, 'parseFloat', W_Builtin(parseFloatjs)) - w_Global.Put(ctx, 'isNaN', W_Builtin(isnanjs)) - w_Global.Put(ctx, 'isFinite', W_Builtin(isfinitejs)) - w_Global.Put(ctx, 'print', W_Builtin(printjs)) - w_Global.Put(ctx, 'unescape', W_Builtin(unescapejs)) + w_Global.Put(ctx, u'NaN', W_FloatNumber(NAN), flags = DE|DD) + w_Global.Put(ctx, u'Infinity', W_FloatNumber(INFINITY), flags = DE|DD) + w_Global.Put(ctx, u'undefined', w_Undefined, flags = DE|DD) + w_Global.Put(ctx, u'eval', W_Builtin(evaljs)) + w_Global.Put(ctx, u'parseInt', W_Builtin(parseIntjs)) + w_Global.Put(ctx, u'parseFloat', W_Builtin(parseFloatjs)) + w_Global.Put(ctx, u'isNaN', W_Builtin(isnanjs)) + w_Global.Put(ctx, u'isFinite', W_Builtin(isfinitejs)) + w_Global.Put(ctx, u'print', W_Builtin(printjs)) + w_Global.Put(ctx, u'unescape', W_Builtin(unescapejs)) - w_Global.Put(ctx, 'this', w_Global) + w_Global.Put(ctx, u'this', w_Global) # DEBUGGING if 0: - w_Global.Put(ctx, 'pypy_repr', W_Builtin(pypy_repr)) + w_Global.Put(ctx, u'pypy_repr', W_Builtin(pypy_repr)) self.global_context = ctx self.w_Global = w_Global Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py Thu Jun 12 21:53:27 2008 @@ -50,9 +50,9 @@ code.InteractiveConsole.__init__(self, locals, filename) self.interpreter = Interpreter() ctx = self.interpreter.global_context - self.interpreter.w_Global.Put(ctx, 'quit', W_Builtin(quitjs)) - self.interpreter.w_Global.Put(ctx, 'load', W_Builtin(loadjs)) - self.interpreter.w_Global.Put(ctx, 'trace', W_Builtin(tracejs)) + self.interpreter.w_Global.Put(ctx, u'quit', W_Builtin(quitjs)) + self.interpreter.w_Global.Put(ctx, u'load', W_Builtin(loadjs)) + self.interpreter.w_Global.Put(ctx, u'trace', W_Builtin(tracejs)) def runcodefromfile(self, filename): @@ -68,11 +68,12 @@ """ try: res = self.interpreter.run(ast, interactive=True) + ctx = self.interpreter.global_context if res not in (None, w_Undefined): try: - print res.ToString(self.interpreter.w_Global) + print res.ToString(ctx) except ThrowException, exc: - print exc.exception.ToString(self.interpreter.w_Global) + print exc.exception.ToString(ctx) except SystemExit: raise except ThrowException, exc: Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py Thu Jun 12 21:53:27 2008 @@ -114,12 +114,12 @@ def emit_break(self): if not self.endlooplabel: - raise ThrowException(W_String("Break outside loop")) + raise ThrowException(W_String(u'Break outside loop')) self.emit('JUMP', self.endlooplabel[-1]) def emit_continue(self): if not self.startlooplabel: - raise ThrowError(W_String("Continue outside loop")) + raise ThrowError(W_String(u'Continue outside loop')) self.emit('JUMP', self.startlooplabel[-1]) def emit(self, operation, *args): @@ -324,10 +324,10 @@ self.counter = counter def eval(self, ctx, stack): - proto = ctx.get_global().Get(ctx, 'Array').Get(ctx, 'prototype') + proto = ctx.get_global().Get(ctx, u'Array').Get(ctx, u'prototype') array = W_Array(ctx, Prototype=proto, Class = proto.Class) for i in range(self.counter): - array.Put(ctx, str(self.counter - i - 1), stack.pop()) + array.Put(ctx, unicode(str(self.counter - i - 1)), stack.pop()) stack.append(array) def __repr__(self): @@ -352,13 +352,13 @@ self.funcobj = funcobj def eval(self, ctx, stack): - proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype') - w_func = W_Object(ctx=ctx, Prototype=proto, Class='Function', + proto = ctx.get_global().Get(ctx, u'Function').Get(ctx, u'prototype') + w_func = W_Object(ctx=ctx, Prototype=proto, Class=u'Function', callfunc=self.funcobj) - w_func.Put(ctx, 'length', W_IntNumber(len(self.funcobj.params))) - w_obj = create_object(ctx, 'Object') - w_obj.Put(ctx, 'constructor', w_func, flags = jsobj.DE) - w_func.Put(ctx, 'prototype', w_obj) + w_func.Put(ctx, u'length', W_IntNumber(len(self.funcobj.params))) + w_obj = create_object(ctx, u'Object') + w_obj.Put(ctx, u'constructor', w_func, flags = jsobj.DE) + w_func.Put(ctx, u'prototype', w_obj) stack.append(w_func) def __repr__(self): @@ -381,7 +381,7 @@ self.counter = counter def eval(self, ctx, stack): - w_obj = create_object(ctx, 'Object') + w_obj = create_object(ctx, u'Object') for _ in range(self.counter): name = stack.pop().ToString(ctx) w_elem = stack.pop() @@ -424,7 +424,7 @@ class IN(BaseBinaryOperation): def operation(self, ctx, left, right): if not isinstance(right, W_Object): - raise ThrowException(W_String("TypeError")) + raise ThrowException(W_String(u'TypeError')) name = left.ToString(ctx) return newbool(right.HasProperty(name)) @@ -442,7 +442,7 @@ var = ctx.resolve_identifier(ctx, self.name) stack.append(W_String(var.type())) except ThrowException: - stack.append(W_String('undefined')) + stack.append(W_String(u'undefined')) #class Typeof(UnaryOp): # def eval(self, ctx): @@ -732,12 +732,12 @@ def eval(self, ctx, stack): # function declaration actyally don't run anything - proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype') - w_func = W_Object(ctx=ctx, Prototype=proto, Class='Function', callfunc=self.funcobj) - w_func.Put(ctx, 'length', W_IntNumber(len(self.funcobj.params))) - w_obj = create_object(ctx, 'Object') - w_obj.Put(ctx, 'constructor', w_func, flags = jsobj.DE) - w_func.Put(ctx, 'prototype', w_obj) + proto = ctx.get_global().Get(ctx, u'Function').Get(ctx, u'prototype') + w_func = W_Object(ctx=ctx, Prototype=proto, Class=u'Function', callfunc=self.funcobj) + w_func.Put(ctx, u'length', W_IntNumber(len(self.funcobj.params))) + w_obj = create_object(ctx, u'Object') + w_obj.Put(ctx, u'constructor', w_func, flags = jsobj.DE) + w_func.Put(ctx, u'prototype', w_obj) if self.funcobj.name is not None: ctx.scope[-1].Put(ctx, self.funcobj.name, w_func) @@ -770,11 +770,11 @@ def common_call(ctx, r1, args, this, name): if not isinstance(r1, W_PrimitiveObject): - raise ThrowException(W_String("%s is not a callable (%s)"%(r1.ToString(ctx), name))) + raise ThrowException(W_String(r1.ToString(ctx) + u' is not a callable (' + name + u')')) try: res = r1.Call(ctx=ctx, args=args.tolist(), this=this) except JsTypeError: - raise ThrowException(W_String("%s is not a function (%s)"%(r1.ToString(ctx), name))) + raise ThrowException(W_String(r1.ToString(ctx) + u' is not a function (' + name + u')')) return res class CALL(Opcode): Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jsobj.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jsobj.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jsobj.py Thu Jun 12 21:53:27 2008 @@ -35,7 +35,7 @@ return self def ToString(self, ctx): - return '' + return u'' def ToObject(self, ctx): # XXX should raise not implemented @@ -82,36 +82,36 @@ return False def ToString(self, ctx): - return "undefined" + return u"undefined" def type(self): - return 'undefined' + return u'undefined' class W_Null(W_Root): def __str__(self): - return "null" + return u'null' def ToBoolean(self): return False def ToString(self, ctx): - return "null" + return u'null' def type(self): - return 'null' + return u'null' w_Undefined = W_Undefined() w_Null = W_Null() class W_PrimitiveObject(W_Root): - def __init__(self, ctx=None, Prototype=None, Class='Object', + def __init__(self, ctx=None, Prototype=None, Class=u'Object', Value=w_Undefined, callfunc=None): self.propdict = {} self.Prototype = Prototype if Prototype is None: Prototype = w_Undefined - self.propdict['prototype'] = Property('prototype', Prototype, flags = DE|DD) + self.propdict[u'prototype'] = Property(u'prototype', Prototype, flags = DE|DD) self.Class = Class self.callfunc = callfunc if callfunc is not None: @@ -122,7 +122,7 @@ def Call(self, ctx, args=[], this=None): if self.callfunc is None: # XXX Not sure if I should raise it here - raise JsTypeError('not a function') + raise JsTypeError(u'not a function') act = ActivationObject() paramn = len(self.callfunc.params) for i in range(paramn): @@ -132,21 +132,21 @@ except IndexError: value = w_Undefined act.Put(ctx, paramname, value) - act.Put(ctx, 'this', this) + act.Put(ctx, u'this', this) w_Arguments = W_Arguments(self, args) - act.Put(ctx, 'arguments', w_Arguments) + act.Put(ctx, u'arguments', w_Arguments) newctx = function_context(self.Scope, act, this) val = self.callfunc.run(ctx=newctx) return val def Construct(self, ctx, args=[]): - obj = W_Object(Class='Object') - prot = self.Get(ctx, 'prototype') + obj = W_Object(Class=u'Object') + prot = self.Get(ctx, u'prototype') if isinstance(prot, W_PrimitiveObject): obj.Prototype = prot else: # would love to test this #but I fail to find a case that falls into this - obj.Prototype = ctx.get_global().Get(ctx, 'Object').Get(ctx, 'prototype') + obj.Prototype = ctx.get_global().Get(ctx, u'Object').Get(ctx, u'prototype') try: #this is a hack to be compatible to spidermonkey self.Call(ctx, args, this=obj) return obj @@ -206,9 +206,9 @@ def DefaultValue(self, ctx, hint=""): if hint == "String": - return self.internal_def_value(ctx, "toString", "valueOf") + return self.internal_def_value(ctx, u"toString", u"valueOf") else: # hint can only be empty, String or Number - return self.internal_def_value(ctx, "valueOf", "toString") + return self.internal_def_value(ctx, u"valueOf", u"toString") ToPrimitive = DefaultValue @@ -219,17 +219,17 @@ try: res = self.ToPrimitive(ctx, 'String') except JsTypeError: - return "[object %s]"%(self.Class,) + return u'[object ' + self.Class + u']' return res.ToString(ctx) def __str__(self): - return "" % self.Class + return u"" % self.Class def type(self): if self.callfunc is not None: - return 'function' + return u'function' else: - return 'object' + return u'object' class W_Primitive(W_Root): @@ -241,19 +241,19 @@ return W_String(this.ToString(ctx)) class W_Object(W_PrimitiveObject): - def __init__(self, ctx=None, Prototype=None, Class='Object', + def __init__(self, ctx=None, Prototype=None, Class=u'Object', Value=w_Undefined, callfunc=None): W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc) def ToNumber(self, ctx): - return self.Get(ctx, 'valueOf').Call(ctx, args=[], this=self).ToNumber(ctx) + return self.Get(ctx, u'valueOf').Call(ctx, args=[], this=self).ToNumber(ctx) class W_NewBuiltin(W_PrimitiveObject): - def __init__(self, ctx, Prototype=None, Class='function', + def __init__(self, ctx, Prototype=None, Class=u'function', Value=w_Undefined, callfunc=None): if Prototype is None: - proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype') + proto = ctx.get_global().Get(ctx, u'Function').Get(ctx, u'prototype') Prototype = proto W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc) @@ -265,7 +265,7 @@ return self.Class class W_Builtin(W_PrimitiveObject): - def __init__(self, builtin=None, ctx=None, Prototype=None, Class='function', + def __init__(self, builtin=None, ctx=None, Prototype=None, Class=u'function', Value=w_Undefined, callfunc=None): W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc) self.set_builtin_call(builtin) @@ -280,60 +280,60 @@ return self.callfuncbi(ctx, args, None) def type(self): - return 'builtin' + return u'builtin' class W_ListObject(W_PrimitiveObject): def tolist(self): l = [] for i in range(self.length): - l.append(self.propdict[str(i)].value) + l.append(self.propdict[unicode(str(i))].value) return l class W_Arguments(W_ListObject): def __init__(self, callee, args): - W_PrimitiveObject.__init__(self, Class='Arguments') - del self.propdict["prototype"] + W_PrimitiveObject.__init__(self, Class=u'Arguments') + del self.propdict[u'prototype'] # XXX None can be dangerous here - self.Put(None, 'callee', callee) - self.Put(None, 'length', W_IntNumber(len(args))) + self.Put(None, u'callee', callee) + self.Put(None, u'length', W_IntNumber(len(args))) for i in range(len(args)): - self.Put(None, str(i), args[i]) + self.Put(None, unicode(str(i)), args[i]) self.length = len(args) class ActivationObject(W_PrimitiveObject): """The object used on function calls to hold arguments and this""" def __init__(self): - W_PrimitiveObject.__init__(self, Class='Activation') - del self.propdict["prototype"] + W_PrimitiveObject.__init__(self, Class=u'Activation') + del self.propdict[u'prototype'] def __repr__(self): - return str(self.propdict) + return unicode(self.propdict) class W_Array(W_ListObject): - def __init__(self, ctx=None, Prototype=None, Class='Array', + def __init__(self, ctx=None, Prototype=None, Class=u'Array', Value=w_Undefined, callfunc=None): W_ListObject.__init__(self, ctx, Prototype, Class, Value, callfunc) - self.Put(ctx, 'length', W_IntNumber(0), flags = DD) + self.Put(ctx, u'length', W_IntNumber(0), flags = DD) self.length = r_uint(0) def set_length(self, newlength): if newlength < self.length: i = newlength while i < self.length: - key = str(i) + key = unicode(str(i)) if key in self.propdict: del self.propdict[key] i += 1 self.length = newlength - self.propdict['length'].value = W_FloatNumber(newlength) + self.propdict[u'length'].value = W_FloatNumber(float(str(newlength))) def Put(self, ctx, P, V, flags = 0): if not self.CanPut(P): return if not P in self.propdict: self.propdict[P] = Property(P, V, flags = flags) else: - if P != 'length': + if P != u'length': self.propdict[P].value = V else: length = V.ToUInt32(ctx) @@ -344,11 +344,11 @@ return try: - arrayindex = r_uint(float(P)) + arrayindex = r_uint(float(P.encode('ascii'))) except ValueError: return - if (arrayindex < self.length) or (arrayindex != float(P)): + if (arrayindex < self.length) or (arrayindex != float(P.encode('ascii'))): return else: if (arrayindex + 1) == 0: @@ -360,12 +360,12 @@ self.boolval = bool(boolval) def ToObject(self, ctx): - return create_object(ctx, 'Boolean', Value=self) + return create_object(ctx, u'Boolean', Value=self) def ToString(self, ctx=None): if self.boolval == True: - return "true" - return "false" + return u"true" + return u"false" def ToNumber(self, ctx): if self.boolval: @@ -376,22 +376,23 @@ return self.boolval def type(self): - return 'boolean' + return u'boolean' def __repr__(self): - return "" + return u'' % unicode(str(self.boolval)) class W_String(W_Primitive): def __init__(self, strval): W_Primitive.__init__(self) + assert isinstance(strval, unicode) self.strval = strval def __repr__(self): - return 'W_String(%s)' % (self.strval,) + return u'W_String(%s)' % self.strval def ToObject(self, ctx): - o = create_object(ctx, 'String', Value=self) - o.Put(ctx, 'length', W_IntNumber(len(self.strval)), flags = RO|DD) + o = create_object(ctx, u'String', Value=self) + o.Put(ctx, u'length', W_IntNumber(len(self.strval)), flags = RO|DD|DE) return o def ToString(self, ctx=None): @@ -404,7 +405,7 @@ return True def type(self): - return 'string' + return u'string' def GetPropertyName(self): return self.ToString() @@ -413,7 +414,7 @@ if not self.strval: return 0.0 try: - return float(self.strval) + return float(self.strval.encode('ascii')) except ValueError: return NAN @@ -422,13 +423,13 @@ and those known to be integers """ def ToObject(self, ctx): - return create_object(ctx, 'Number', Value=self) + return create_object(ctx, u'Number', Value=self) def Get(self, ctx, P): return w_Undefined def type(self): - return 'number' + return u'number' class W_IntNumber(W_BaseNumber): """ Number known to be an integer @@ -439,7 +440,7 @@ def ToString(self, ctx=None): # XXX incomplete, this doesn't follow the 9.8.1 recommendation - return str(self.intval) + return unicode(str(self.intval)) def ToBoolean(self): return bool(self.intval) @@ -458,33 +459,34 @@ return self.ToString() def __repr__(self): - return 'W_IntNumber(%s)' % (self.intval,) + return u'W_IntNumber(%s)' % (self.intval,) class W_FloatNumber(W_BaseNumber): """ Number known to be a float """ def __init__(self, floatval): W_BaseNumber.__init__(self) - self.floatval = float(floatval) + assert isinstance(floatval, float) + self.floatval = floatval def ToString(self, ctx = None): # XXX incomplete, this doesn't follow the 9.8.1 recommendation if isnan(self.floatval): - return 'NaN' + return u'NaN' if isinf(self.floatval): if self.floatval > 0: - return 'Infinity' + return u'Infinity' else: - return '-Infinity' + return u'-Infinity' try: intval = ovfcheck_float_to_int(self.floatval) if intval == self.floatval: - return str(intval) + return unicode(str(intval)) except OverflowError: pass - res = str(self.floatval) - if (res[-3] == '+' or res[-3] == '-') and res[-2] == '0': + res = unicode(str(self.floatval)) + if (res[-3] == u'+' or res[-3] == u'-') and res[-2] == u'0': cut = len(res) - 2 assert cut >= 0 res = res[:cut] + res[-1] @@ -509,7 +511,7 @@ return r_uint(self.floatval) def __repr__(self): - return 'W_FloatNumber(%s)' % (self.floatval,) + return u'W_FloatNumber(%s)' % (self.floatval,) class W_List(W_Root): def __init__(self, list_w): @@ -528,7 +530,7 @@ return self.list_w def __repr__(self): - return 'W_List(%s)' % (self.list_w,) + return u'W_List(%s)' % (self.list_w,) class ExecutionContext(object): def __init__(self, scope, this=None, variable=None, @@ -546,12 +548,12 @@ self.debug = debug if jsproperty is None: #Attribute flags for new vars - self.property = Property('',w_Undefined) + self.property = Property(u'',w_Undefined) else: self.property = jsproperty def __str__(self): - return ""%(self.scope, self.variable) + return u'' % (self.scope, self.variable) def assign(self, name, value): assert name is not None @@ -601,21 +603,21 @@ assert isinstance(obj, W_PrimitiveObject) if obj.HasProperty(identifier): return obj.Get(ctx, identifier) - raise ThrowException(W_String("ReferenceError: %s is not defined" % identifier)) + raise ThrowException(W_String(u'ReferenceError: ' + identifier + u' is not defined')) def global_context(w_global): assert isinstance(w_global, W_PrimitiveObject) ctx = ExecutionContext([w_global], this = w_global, variable = w_global, - jsproperty = Property('', w_Undefined, flags = DD)) + jsproperty = Property(u'', w_Undefined, flags = DD)) return ctx def function_context(scope, activation, this=None): newscope = scope[:] ctx = ExecutionContext(newscope, this = this, - jsproperty = Property('', w_Undefined, flags = DD)) + jsproperty = Property(u'', w_Undefined, flags = DD)) ctx.push_object(activation) return ctx @@ -623,7 +625,7 @@ ctx = ExecutionContext(calling_context.scope[:], this = calling_context.this, variable = calling_context.variable, - jsproperty = Property('', w_Undefined)) + jsproperty = Property(u'', w_Undefined)) return ctx def empty_context(): @@ -631,7 +633,7 @@ ctx = ExecutionContext([obj], this = obj, variable = obj, - jsproperty = Property('', w_Undefined)) + jsproperty = Property(u'', w_Undefined)) return ctx class W_Iterator(W_Root): @@ -646,7 +648,7 @@ return len(self.elements_w) == 0 def create_object(ctx, prototypename, callfunc=None, Value=w_Undefined): - proto = ctx.get_global().Get(ctx, prototypename).Get(ctx, 'prototype') + proto = ctx.get_global().Get(ctx, prototypename).Get(ctx, u'prototype') obj = W_Object(ctx, callfunc = callfunc,Prototype=proto, Class = proto.Class, Value = Value) return obj Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py Thu Jun 12 21:53:27 2008 @@ -109,7 +109,7 @@ def emit(self, bytecode): self.expr.emit(bytecode) if isinstance(self.lefthand, Identifier): - bytecode.emit('LOAD_STRINGCONSTANT', self.lefthand.name) + bytecode.emit('LOAD_STRINGCONSTANT', unicode(self.lefthand.name)) else: self.lefthand.emit(bytecode) @@ -167,7 +167,7 @@ if self.right is not None: self.right.emit(bytecode) bytecode_name = 'STORE' + self._get_name() - bytecode.emit_store(bytecode_name, self.identifier) + bytecode.emit_store(bytecode_name, unicode(self.identifier)) class VariableAssignment(Assignment): def __init__(self, pos, left, right, operand): @@ -180,7 +180,7 @@ def emit(self, bytecode): self.right.emit(bytecode) - bytecode.emit('STORE_VAR', self.depth, self.identifier) + bytecode.emit('STORE_VAR', self.depth, unicode(self.identifier)) class MemberAssignment(Assignment): def __init__(self, pos, what, item, right, operand, prefix=''): @@ -213,7 +213,7 @@ # XXX optimize this a bit if self.right is not None: self.right.emit(bytecode) - bytecode.emit('LOAD_STRINGCONSTANT', self.itemname) + bytecode.emit('LOAD_STRINGCONSTANT', unicode(self.itemname)) self.what.emit(bytecode) bytecode.emit_store_member('STORE_MEMBER' + self._get_name()) @@ -262,7 +262,7 @@ if isinstance(left, MemberDot): left.left.emit(bytecode) # XXX optimise - bytecode.emit('LOAD_STRINGCONSTANT', left.name) + bytecode.emit('LOAD_STRINGCONSTANT', unicode(left.name)) bytecode.emit('CALL_METHOD') elif isinstance(left, Member): raise NotImplementedError @@ -300,7 +300,7 @@ def emit(self, bytecode): self.left.emit(bytecode) - bytecode.emit('LOAD_MEMBER', self.name) + bytecode.emit('LOAD_MEMBER', unicode(self.name)) class FunctionStatement(Statement): def __init__(self, pos, name, params, body): @@ -310,13 +310,19 @@ else: self.name = name.get_literal() self.body = body - self.params = params + self.params = [unicode(param) for param in params] def emit(self, bytecode): code = JsCode() if self.body is not None: self.body.emit(code) - funcobj = JsFunction(self.name, self.params, code) + + if self.name is None: + func_name = None + else: + func_name = unicode(self.name) + + funcobj = JsFunction(func_name, self.params, code) bytecode.emit('DECLARE_FUNCTION', funcobj) if self.name is None: bytecode.emit('LOAD_FUNCTION', funcobj) @@ -331,7 +337,7 @@ self.name = name def emit(self, bytecode): - bytecode.emit('LOAD_VARIABLE', self.name) + bytecode.emit('LOAD_VARIABLE', unicode(self.name)) def get_literal(self): return self.name @@ -442,7 +448,7 @@ def emit(self, bytecode): # obscure hack to be compatible if isinstance(self.left, Identifier): - bytecode.emit('TYPEOF_VARIABLE', self.left.name) + bytecode.emit('TYPEOF_VARIABLE', unicode(self.left.name)) else: self.left.emit(bytecode) bytecode.emit('TYPEOF') @@ -455,13 +461,13 @@ def emit(self, bytecode): what = self.what if isinstance(what, Identifier): - bytecode.emit('DELETE', what.name) + bytecode.emit('DELETE', unicode(what.name)) elif isinstance(what, VariableIdentifier): - bytecode.emit('DELETE', what.identifier) + bytecode.emit('DELETE', unicode(what.identifier)) elif isinstance(what, MemberDot): what.left.emit(bytecode) # XXX optimize - bytecode.emit('LOAD_STRINGCONSTANT', what.name) + bytecode.emit('LOAD_STRINGCONSTANT', unicode(what.name)) bytecode.emit('DELETE_MEMBER') elif isinstance(what, Member): what.left.emit(bytecode) @@ -553,7 +559,7 @@ self.strval = self.string_unquote(strval) def emit(self, bytecode): - bytecode.emit('LOAD_STRINGCONSTANT', self.strval) + bytecode.emit('LOAD_STRINGCONSTANT', unicode(self.strval)) def string_unquote(self, string): # XXX I don't think this works, it's very unlikely IMHO @@ -601,7 +607,7 @@ def emit(self, bytecode): for varname in self.var_decl: - bytecode.emit('DECLARE_VAR', varname) + bytecode.emit('DECLARE_VAR', unicode(varname)) for funcname, funccode in self.func_decl.items(): funccode.emit(bytecode) @@ -659,7 +665,7 @@ self.finallyblock.emit(finallycode) else: finallycode = None - bytecode.emit('TRYCATCHBLOCK', trycode, self.catchparam.get_literal(), + bytecode.emit('TRYCATCHBLOCK', trycode, unicode(self.catchparam.get_literal()), catchcode, finallycode) class VariableDeclaration(Expression): @@ -671,7 +677,7 @@ def emit(self, bytecode): if self.expr is not None: self.expr.emit(bytecode) - bytecode.emit('STORE', self.identifier) + bytecode.emit('STORE', unicode(self.identifier)) class VariableIdentifier(Expression): def __init__(self, pos, depth, identifier): @@ -680,7 +686,7 @@ self.identifier = identifier def emit(self, bytecode): - bytecode.emit('LOAD_VARIABLE', self.identifier) + bytecode.emit('LOAD_VARIABLE', unicode(self.identifier)) def get_literal(self): return self.identifier @@ -729,7 +735,7 @@ self.body = body def emit(self, bytecode): - bytecode.emit('WITH_START', self.identifier) + bytecode.emit('WITH_START', unicode(self.identifier)) self.body.emit(bytecode) bytecode.emit('WITH_END') @@ -770,13 +776,13 @@ def emit(self, bytecode): - bytecode.emit('DECLARE_VAR', self.iteratorname) + bytecode.emit('DECLARE_VAR', unicode(self.iteratorname)) self.object.emit(bytecode) bytecode.emit('LOAD_ITERATOR') precond = bytecode.emit_startloop_label() finish = bytecode.prealocate_endloop_label() bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) - bytecode.emit('NEXT_ITERATOR', self.iteratorname) + bytecode.emit('NEXT_ITERATOR', unicode(self.iteratorname)) self.body.emit(bytecode) bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) @@ -796,7 +802,7 @@ precond = bytecode.emit_startloop_label() finish = bytecode.prealocate_endloop_label() bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) - bytecode.emit('NEXT_ITERATOR', self.iteratorname) + bytecode.emit('NEXT_ITERATOR', unicode(self.iteratorname)) self.body.emit(bytecode) bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py Thu Jun 12 21:53:27 2008 @@ -16,7 +16,7 @@ try: return evaljs(ctx, args, this) except JsBaseExcept: - return W_String("error") + return W_String(u'error') passing_tests = ['Number', 'Boolean'] Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_parser.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_parser.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_parser.py Thu Jun 12 21:53:27 2008 @@ -451,7 +451,7 @@ def test_function_decl(self): self.check('function f(x, y, z) {x;}', - ['DECLARE_FUNCTION f [\'x\', \'y\', \'z\'] [\n LOAD_VARIABLE "x"\n POP\n]']) + ['DECLARE_FUNCTION f [u\'x\', u\'y\', u\'z\'] [\n LOAD_VARIABLE "x"\n POP\n]']) def test_function_expression(self): self.check('var x = function() {return x}',[ From santagada at codespeak.net Thu Jun 12 22:21:53 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Thu, 12 Jun 2008 22:21:53 +0200 (CEST) Subject: [pypy-svn] r55798 - in pypy/branch/js-refactoring-quickhacks/pypy/lang/js: . test/ecma Message-ID: <20080612202153.980902A808C@codespeak.net> Author: santagada Date: Thu Jun 12 22:21:51 2008 New Revision: 55798 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py Log: ObjectObjects added to passing tests Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py Thu Jun 12 22:21:51 2008 @@ -6,7 +6,7 @@ w_Undefined, W_NewBuiltin, W_IntNumber, w_Null, create_object, W_Boolean,\ W_FloatNumber, W_String, W_Builtin, W_Array, w_Null, newbool,\ isnull_or_undefined, W_PrimitiveObject, W_ListObject, W_BaseNumber,\ - DE, DD, RO, IT + DE, DD, RO, IT, Property from pypy.lang.js.execution import ThrowException, JsTypeError from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.streamio import open_file_as_stream @@ -41,14 +41,19 @@ if len(args) >= 1 and not isnull_or_undefined(args[0]): return args[0].ToObject(ctx) else: - return self.Construct(ctx) + return self.Construct(ctx, args) def Construct(self, ctx, args=[]): - if (len(args) >= 1 and not args[0] is w_Undefined and not - args[0] is w_Null): - # XXX later we could separate builtins and normal objects + if len(args) >= 1 and not isnull_or_undefined(args[0]): + if args[0].type() == u'Object': + return args[0] return args[0].ToObject(ctx) - return create_object(ctx, u'Object') + else: + obj = create_object(ctx, u'Object', Value = w_Null) + Object = ctx.get_global().Get(ctx, 'Object') + obj.propdict[u'prototype'] = Property(u'prototype', Object, DE | DD | RO) + obj.propdict[u'__proto__'] = Property(u'prototype', Object, DE | DD | RO) + return obj class W_BooleanObject(W_NativeObject): def Call(self, ctx, args=[], this=None): @@ -539,10 +544,12 @@ class W_DateFake(W_NewBuiltin): # XXX This is temporary def Call(self, ctx, args=[], this=None): - return create_object(ctx, u'Object') + o = create_object(ctx, u'Object') + o.Class = u'Date' + return o def Construct(self, ctx, args=[]): - return create_object(ctx, u'Object') + return self.Call(ctx, args) def pypy_repr(ctx, repr, w_arg): return W_String(w_arg.__class__.__name__) @@ -576,11 +583,13 @@ w_Function.Put(ctx, u'prototype', w_FncPrototype, flags = allon) w_Function.Put(ctx, u'constructor', w_Function) + w_Object.Put(ctx, u'__proto__', w_FncPrototype, flags = allon) + toString = W_ToString(ctx) put_values(ctx, w_ObjPrototype, { u'constructor': w_Object, - u'__proto__': w_FncPrototype, + u'__proto__': w_Null, u'toString': toString, u'toLocaleString': toString, u'valueOf': W_ValueOf(ctx), Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/ecma/conftest.py Thu Jun 12 22:21:51 2008 @@ -18,7 +18,7 @@ except JsBaseExcept: return W_String(u'error') -passing_tests = ['Number', 'Boolean'] +passing_tests = ['Number', 'Boolean', 'ObjectObjects'] class JSDirectory(py.test.collect.Directory): From santagada at codespeak.net Thu Jun 12 23:48:41 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Thu, 12 Jun 2008 23:48:41 +0200 (CEST) Subject: [pypy-svn] r55799 - in pypy/branch/js-refactoring-quickhacks/pypy/lang/js: . test Message-ID: <20080612214841.CCBCA69809C@codespeak.net> Author: santagada Date: Thu Jun 12 23:48:38 2008 New Revision: 55799 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/astbuilder.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_interp.py Log: better for with support for missing parts and continue, and a with statement that works Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/astbuilder.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/astbuilder.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/astbuilder.py Thu Jun 12 23:48:38 2008 @@ -432,6 +432,14 @@ else: target = None return operations.Break(pos, target) + + def visit_continuestatement(self, node): + pos = self.get_pos(node) + if len(node.children) > 0: + target = self.dispatch(node.children[0]) + else: + target = None + return operations.Continue(pos, target) def visit_returnstatement(self, node): pos = self.get_pos(node) @@ -469,7 +477,7 @@ def visit_withstatement(self, node): pos = self.get_pos(node) - identifier = self.dispatch(node.children[0]) + withpart = self.dispatch(node.children[0]) body = self.dispatch(node.children[1]) - return operations.With(pos, identifier, body) + return operations.With(pos, withpart, body) Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py Thu Jun 12 23:48:38 2008 @@ -748,6 +748,8 @@ if not we_are_translated(): # debugging self._code = bytecode + if interactive: + print bytecode if interactive: return bytecode.run(self.global_context, retlast=True) else: Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py Thu Jun 12 23:48:38 2008 @@ -881,11 +881,8 @@ # ---------------- with support --------------------- class WITH_START(Opcode): - def __init__(self, name): - self.name = name - def eval(self, ctx, stack): - ctx.push_object(ctx.resolve_identifier(ctx, self.name).ToObject(ctx)) + ctx.push_object(stack.pop().ToObject(ctx)) class WITH_END(Opcode): def eval(self, ctx, stack): Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/operations.py Thu Jun 12 23:48:38 2008 @@ -239,15 +239,14 @@ def __init__(self, pos, target): self.pos = pos self.target = target - + assert target is None + class Break(Unconditional): def emit(self, bytecode): - assert self.target is None bytecode.emit_break() class Continue(Unconditional): def emit(self, bytecode): - assert self.target is None bytecode.emit_continue() class Call(Expression): @@ -728,14 +727,14 @@ bytecode.emit('LOAD_UNDEFINED') class With(Statement): - def __init__(self, pos, identifier, body): + def __init__(self, pos, withpart, body): self.pos = pos - assert isinstance(identifier, VariableIdentifier) - self.identifier = identifier.identifier + self.withpart = withpart self.body = body def emit(self, bytecode): - bytecode.emit('WITH_START', unicode(self.identifier)) + self.withpart.emit(bytecode) + bytecode.emit('WITH_START') self.body.emit(bytecode) bytecode.emit('WITH_END') @@ -766,47 +765,40 @@ bytecode.emit('JUMP', startlabel) bytecode.emit_endloop_label(endlabel) +def common_forvar(bytecode, obj, body, itername): + obj.emit(bytecode) + bytecode.emit('LOAD_ITERATOR') + precond = bytecode.emit_startloop_label() + finish = bytecode.prealocate_endloop_label() + bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) + bytecode.emit('NEXT_ITERATOR', itername) + body.emit(bytecode) + bytecode.emit('JUMP', precond) + bytecode.emit_endloop_label(finish) + bytecode.emit('POP') + class ForVarIn(Statement): def __init__(self, pos, vardecl, lobject, body): self.pos = pos assert isinstance(vardecl, VariableDeclaration) - self.iteratorname = vardecl.identifier + self.iteratorname = unicode(vardecl.identifier) self.object = lobject self.body = body - def emit(self, bytecode): - bytecode.emit('DECLARE_VAR', unicode(self.iteratorname)) - self.object.emit(bytecode) - bytecode.emit('LOAD_ITERATOR') - precond = bytecode.emit_startloop_label() - finish = bytecode.prealocate_endloop_label() - bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) - bytecode.emit('NEXT_ITERATOR', unicode(self.iteratorname)) - self.body.emit(bytecode) - bytecode.emit('JUMP', precond) - bytecode.emit_endloop_label(finish) - bytecode.emit('POP') + bytecode.emit('DECLARE_VAR', self.iteratorname) + common_forvar(bytecode, self.object, self.body, self.iteratorname) class ForIn(Statement): def __init__(self, pos, name, lobject, body): self.pos = pos #assert isinstance(iterator, Node) - self.iteratorname = name + self.iteratorname = unicode(name) self.object = lobject self.body = body def emit(self, bytecode): - self.object.emit(bytecode) - bytecode.emit('LOAD_ITERATOR') - precond = bytecode.emit_startloop_label() - finish = bytecode.prealocate_endloop_label() - bytecode.emit('JUMP_IF_ITERATOR_EMPTY', finish) - bytecode.emit('NEXT_ITERATOR', unicode(self.iteratorname)) - self.body.emit(bytecode) - bytecode.emit('JUMP', precond) - bytecode.emit_endloop_label(finish) - bytecode.emit('POP') + common_forvar(bytecode, self.object, self.body, self.iteratorname) class For(Statement): def __init__(self, pos, setup, condition, update, body): @@ -817,16 +809,23 @@ self.body = body def emit(self, bytecode): - self.setup.emit(bytecode) - if isinstance(self.setup, Expression): - bytecode.emit('POP') + if self.setup is not None: + self.setup.emit(bytecode) + if isinstance(self.setup, Expression): + bytecode.emit('POP') + + firstep = bytecode.prealocate_label() + bytecode.emit('JUMP', firstep) precond = bytecode.emit_startloop_label() finish = bytecode.prealocate_endloop_label() - self.condition.emit(bytecode) - bytecode.emit('JUMP_IF_FALSE', finish) + if self.update is not None: + self.update.emit(bytecode) + bytecode.emit('POP') + bytecode.emit_label(firstep) + if self.condition is not None: + self.condition.emit(bytecode) + bytecode.emit('JUMP_IF_FALSE', finish) self.body.emit(bytecode) - self.update.emit(bytecode) - bytecode.emit('POP') bytecode.emit('JUMP', precond) bytecode.emit_endloop_label(finish) Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_interp.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/test/test_interp.py Thu Jun 12 23:48:38 2008 @@ -312,13 +312,23 @@ """, ["true", "false"]) def test_for(): - assertp(""" + yield assertp, """ i = 0; for (i; i<3; i++) { print(i); } print(i); - """, ["0","1","2","3"]) + """, ["0","1","2","3"] + + yield assertp, """ + i = 0; + for (;;) { + if(i >= 3) break; + print(i); + i++ + } + print(i); + """, ["0","1","2","3"] def test_eval(): yield assertp, """ @@ -342,6 +352,15 @@ } print('out');""", "out") +def test_continue(): + assertp(""" + for(x = 0; x < 3; x++) { + print(x); + continue; + print('error'); + } + print('out');""", ["0","1","2","out"]) + def test_typeof(): assertv(""" var x = 3; @@ -502,7 +521,7 @@ yield assertv, "2 !== 2;", False def test_with(): - assertp(""" + yield assertp, """ var mock = {x:2}; var x=4; print(x); @@ -517,7 +536,13 @@ print(y); } print(x); - """, ['4', '2', '3', '4']) + """, ['4', '2', '3', '4'] + + yield assertp, """ + with(new Array(1,2,3)) { + print(join('.')) + } + """, "1.2.3" def test_bitops(): yield assertv, "2 ^ 2;", 0 From arigo at codespeak.net Fri Jun 13 10:30:52 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 13 Jun 2008 10:30:52 +0200 (CEST) Subject: [pypy-svn] r55802 - pypy/dist/pypy/translator/tool Message-ID: <20080613083052.06888398005@codespeak.net> Author: arigo Date: Fri Jun 13 10:30:50 2008 New Revision: 55802 Modified: pypy/dist/pypy/translator/tool/pdbplus.py Log: Add the pdb+ command 'callgraph', which works like the --view option. Modified: pypy/dist/pypy/translator/tool/pdbplus.py ============================================================================== --- pypy/dist/pypy/translator/tool/pdbplus.py (original) +++ pypy/dist/pypy/translator/tool/pdbplus.py Fri Jun 13 10:30:50 2008 @@ -379,6 +379,12 @@ from pypy.translator.tool import graphpage self._show(graphpage.ClassHierarchyPage(self.translator)) + def do_callgraph(self, arg): + """callgraph +show the program's call graph""" + from pypy.translator.tool import graphpage + self._show(graphpage.TranslatorPage(self.translator, 100)) + def do_interact(self, arg): """invoke a code.py sub prompt""" ns = self.curframe.f_globals.copy() @@ -386,7 +392,7 @@ code.interact("*interactive*", local=ns) def help_graphs(self): - print "graph commands are: showg, flowg, callg, classhier, enable_graphic" + print "graph commands are: callgraph, showg, flowg, callg, classhier" def help_ann_other(self): print "other annotation related commands are: find, finddescs, attrs, attrsann, readpos" From antocuni at codespeak.net Fri Jun 13 16:25:22 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 13 Jun 2008 16:25:22 +0200 (CEST) Subject: [pypy-svn] r55816 - pypy/branch/oo-jit/pypy/jit/rainbow Message-ID: <20080613142522.70B1516A052@codespeak.net> Author: antocuni Date: Fri Jun 13 16:25:21 2008 New Revision: 55816 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Log: fix a comment Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Fri Jun 13 16:25:21 2008 @@ -27,8 +27,8 @@ for nonvoid results the result is appended to the varlist red vars are just indexes - green vars are positive indexes - green consts are negative indexes + green vars are even indexes + green consts are odd indexes """ is_portal = False dump_copy = None From antocuni at codespeak.net Fri Jun 13 16:27:35 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 13 Jun 2008 16:27:35 +0200 (CEST) Subject: [pypy-svn] r55817 - in pypy/branch/oo-jit/pypy/jit: rainbow/test timeshifter Message-ID: <20080613142735.AFA4916A051@codespeak.net> Author: antocuni Date: Fri Jun 13 16:27:35 2008 New Revision: 55817 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py Log: (antocuni, arigato around) since InstanceTypeDesc is a cachedtype, the fielddescs were shared between a typedesc and the typedescs of its superclasses. Fixing it makes test_raise_result_mixup passing. Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Fri Jun 13 16:27:35 2008 @@ -6,7 +6,7 @@ from pypy.jit.rainbow.test.test_vlist import P_OOPSPEC from pypy.jit.rainbow.test.test_interpreter import OOTypeMixin from pypy.rlib.jit import hint -from pypy.rpython.module.support import LLSupport +from pypy.rpython.module.support import LLSupport, OOSupport class BaseTestPromotion(InterpretationTest): small = True @@ -337,6 +337,7 @@ assert res == 22 def test_raise_result_mixup(self): + from pypy.rpython.annlowlevel import hlstr def w(x): pass class E(Exception): @@ -348,7 +349,9 @@ w(e) raise e return x - def ll_function(c, x): + def ll_function(c1, x): + # needed so that both lltype and ootype can index the string with [] + c = hlstr(c1) i = 0 while True: hint(None, global_merge_point=True) @@ -362,9 +365,9 @@ i = x r = hint(i, variable=True) return r - ll_function.convert_arguments = [LLSupport.to_rstr, int] + ll_function.convert_arguments = [self.to_rstr, int] - assert ll_function("oe", 1) == 1 + assert ll_function(self.to_rstr("oe"), 1) == 1 res = self.interpret(ll_function, ["oe", 1], [], policy=StopAtXPolicy(w)) @@ -470,12 +473,13 @@ class TestLLType(BaseTestPromotion): type_system = "lltype" + to_rstr = staticmethod(LLSupport.to_rstr) class TestOOType(OOTypeMixin, BaseTestPromotion): type_system = "ootype" + to_rstr = staticmethod(OOSupport.to_rstr) def skip(self): py.test.skip('in progress') - test_raise_result_mixup = skip test_raise_result_mixup_some_more = skip Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py Fri Jun 13 16:27:35 2008 @@ -281,10 +281,15 @@ def _iter_fields(self, TYPE): try: - fields = TYPE._fields + fields = TYPE._fields.items() + if isinstance(TYPE, ootype.Instance): + T = TYPE._superclass + while T is not None: + fields = T._fields.items() + fields + T = T._superclass except AttributeError: return - for name, (FIELDTYPE, defl) in fields.iteritems(): + for name, (FIELDTYPE, defl) in fields: yield name, FIELDTYPE def _get_type_name(self, TYPE): @@ -293,16 +298,6 @@ except AttributeError: return TYPE._short_name() - def _compute_fielddescs(self, RGenOp): - AbstractStructTypeDesc._compute_fielddescs(self, RGenOp) - TYPE = self.TYPE - if isinstance(TYPE, ootype.Instance): - SUPERTYPE = TYPE._superclass - if SUPERTYPE is not None: - desc = InstanceTypeDesc(RGenOp, SUPERTYPE) - self.fielddescs = desc.fielddescs + self.fielddescs - self.fielddesc_by_name.update(desc.fielddesc_by_name) - def create_varsize(jitstate, contdesc, sizebox): gv_size = sizebox.getgenvar(jitstate) alloctoken = contdesc.varsizealloctoken From antocuni at codespeak.net Fri Jun 13 17:04:30 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 13 Jun 2008 17:04:30 +0200 (CEST) Subject: [pypy-svn] r55820 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080613150430.2632E168575@codespeak.net> Author: antocuni Date: Fri Jun 13 17:04:29 2008 New Revision: 55820 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Log: yai, all promotion tests passes on ootype! Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Fri Jun 13 17:04:29 2008 @@ -374,6 +374,7 @@ res == 1 def test_raise_result_mixup_some_more(self): + from pypy.rpython.annlowlevel import hlstr def w(x): if x > 1000: return None @@ -387,7 +388,9 @@ e = w(x) raise e return x - def ll_function(c, x): + def ll_function(c1, x): + # needed so that both lltype and ootype can index the string with [] + c = hlstr(c1) i = 0 while True: hint(None, global_merge_point=True) @@ -401,9 +404,9 @@ i = x r = hint(i, variable=True) return r - ll_function.convert_arguments = [LLSupport.to_rstr, int] + ll_function.convert_arguments = [self.to_rstr, int] - assert ll_function("oe", 1) == 1 + assert ll_function(self.to_rstr("oe"), 1) == 1 res = self.interpret(ll_function, ["oe", 1], [], policy=StopAtXPolicy(w)) @@ -478,8 +481,3 @@ class TestOOType(OOTypeMixin, BaseTestPromotion): type_system = "ootype" to_rstr = staticmethod(OOSupport.to_rstr) - - def skip(self): - py.test.skip('in progress') - - test_raise_result_mixup_some_more = skip From antocuni at codespeak.net Fri Jun 13 17:15:44 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 13 Jun 2008 17:15:44 +0200 (CEST) Subject: [pypy-svn] r55826 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080613151544.70657169E29@codespeak.net> Author: antocuni Date: Fri Jun 13 17:15:43 2008 New Revision: 55826 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_tlr.py Log: port test_tlr to ootype Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_tlr.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_tlr.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_tlr.py Fri Jun 13 17:15:43 2008 @@ -10,19 +10,24 @@ def test_tlr(self): bytecode = ','.join([str(ord(c)) for c in tlr.SQUARE]) - tlr_interpret = func_with_new_name(tlr.interpret, "tlr_interpret") to_rstr = self.to_rstr - # to stick attributes on the new function object, not on tlr.interpret + def build_bytecode(s): result = ''.join([chr(int(t)) for t in s.split(',')]) return to_rstr(result) - tlr_interpret.convert_arguments = [build_bytecode, int] - res = self.timeshift_from_portal(tlr_interpret, tlr_interpret, [bytecode, 1764], + def ll_function(llbytecode, arg): + from pypy.rpython.annlowlevel import hlstr + # needed so that both lltype and ootype can index the string with [] + bytecode = hlstr(llbytecode) + return tlr.interpret(bytecode, arg) + ll_function.convert_arguments = [build_bytecode, int] + + res = self.timeshift_from_portal(ll_function, tlr.interpret, [bytecode, 1764], policy=P_OOPSPEC) assert res == 3111696 - res = self.timeshift_from_portal(tlr_interpret, tlr_interpret, [bytecode, 9], + res = self.timeshift_from_portal(ll_function, tlr.interpret, [bytecode, 9], policy=P_OOPSPEC) assert res == 81 @@ -30,6 +35,6 @@ type_system = "lltype" to_rstr = staticmethod(LLSupport.to_rstr) -##class TestOOType(BaseTestTLR): -## type_system = "ootype" -## to_rstr = staticmethod(OOSupport.to_rstr) +class TestOOType(BaseTestTLR): + type_system = "ootype" + to_rstr = staticmethod(OOSupport.to_rstr) From antocuni at codespeak.net Sat Jun 14 15:53:07 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 14 Jun 2008 15:53:07 +0200 (CEST) Subject: [pypy-svn] r55844 - in pypy/branch/oo-jit/pypy/jit: codegen codegen/llgraph rainbow rainbow/test timeshifter Message-ID: <20080614135307.DB85816856A@codespeak.net> Author: antocuni Date: Sat Jun 14 15:53:05 2008 New Revision: 55844 Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py pypy/branch/oo-jit/pypy/jit/codegen/model.py pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Log: implement red_instanceof Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py Sat Jun 14 15:53:05 2008 @@ -295,6 +295,12 @@ "genop_ooisnull: bad currently_writing") return LLVar(llimpl.genop(self.b, 'ooisnull', [gv_obj], gv_Bool.v)) + def genop_instanceof(self, gv_obj, (gv_TYPE, gv_OBJTYPE)): + ll_assert(self.rgenop.currently_writing is self, + "genop_instanceof: bad currently_writing") + vars_gv = [gv_obj.v, gv_TYPE.v] + return LLVar(llimpl.genop(self.b, 'instanceof', vars_gv, gv_Bool.v)) + def genop_cast_int_to_ptr(self, gv_PTRTYPE, gv_int): ll_assert(self.rgenop.currently_writing is self, "genop_cast_int_to_ptr: bad currently_writing") Modified: pypy/branch/oo-jit/pypy/jit/codegen/model.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/model.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/model.py Sat Jun 14 15:53:05 2008 @@ -323,7 +323,8 @@ #@staticmethod #@specialize.memo() #def allocToken(T): - # """Return a token describing the size of the fixed-size type T.""" + # """Return a token describing the size of the fixed-size type T. + # For ootype backends, it's also passed to genop_instanceof.""" # raise NotImplementedError #@staticmethod Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py Sat Jun 14 15:53:05 2008 @@ -879,7 +879,7 @@ def methdesc_position(self, TYPE, name): key = (TYPE, name) if key in self.methdesc_positions: - return self.methdesc_positions[tok] + return self.methdesc_positions[key] result = len(self.methdescs) desc = MethodDesc(self.RGenOp, self.exceptiondesc, TYPE, name) self.methdescs.append(desc) @@ -1703,6 +1703,20 @@ def serialize_op_oodowncast(self, op): return self.serialize_op_cast_pointer(op) + def serialize_op_instanceof(self, op): + color = self.opcolor(op) + if color == 'green': + # delegate to the default implementation in + # serialize_op, since it works just fine + raise NotImplementedError + assert color == 'red', 'unknown color %s' % color + v1, cType = op.args + arg1 = self.serialize_oparg('red', v1) + index = self.structtypedesc_position(cType.value) + self.emit('red_instanceof') + self.emit(arg1, index) + self.register_redvar(op.result) + def serialize_op_new(self, op): TYPE = op.args[0].value if TYPE.oopspec_name is not None: Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Sat Jun 14 15:53:05 2008 @@ -1084,6 +1084,16 @@ return rtimeshift.genptreq(self.jitstate, ptrbox1, ptrbox2, False) + @arguments("red", "structtypedesc", returns="red") + def opimpl_red_instanceof(self, objbox, typedesc): + if objbox.content is None: + return rtimeshift.geninstanceof(self.jitstate, objbox, + typedesc) + # else it's a vstruct + objtypedesc = objbox.content.typedesc + result = objtypedesc.issubtype(typedesc) + return rvalue.ll_fromvalue(self.jitstate, result) + @arguments("red", "jumptarget") def opimpl_goto_if_vstruct(self, objbox, target): if objbox.content is not None: Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Sat Jun 14 15:53:05 2008 @@ -2018,6 +2018,33 @@ res = self.interpret(main2, [5, 6], policy=StopAtXPolicy(g)) assert res == 11 + def test_red_isinstance(self): + class A: + pass + class B(A): + pass + def fn(flag): + obj = flag and B() or A() + return isinstance(obj, B) + res = self.interpret(fn, [True]) + assert res + self.check_insns({}) + + def test_red_isinstance_degenerated(self): + class A: + pass + class B(A): + pass + def g(obj): + return obj + def fn(flag): + obj = flag and B() or A() + g(obj) # force container + return isinstance(obj, B) + res = self.interpret(fn, [True], [], policy=StopAtXPolicy(g)) + assert res + #self.check_insns({}) + def test_manymanyvars(self): Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py Sat Jun 14 15:53:05 2008 @@ -259,11 +259,16 @@ StructFieldDesc = None # patched later with InstanceFieldDesc PtrRedBox = rvalue.InstanceRedBox - _attrs_ = ['methodcodes'] + _attrs_ = ['methodcodes', 'supertypedesc'] + supertypedesc = None def __init__(self, RGenOp, TYPE): AbstractStructTypeDesc.__init__(self, RGenOp, TYPE) self.methodcodes = {} # method name --> jitcode + if isinstance(TYPE, ootype.Instance): + SUPER = TYPE._superclass + if SUPER is not None: + self.supertypedesc = InstanceTypeDesc(RGenOp, SUPER) def Ptr(self, TYPE): return TYPE @@ -298,6 +303,14 @@ except AttributeError: return TYPE._short_name() + def issubtype(self, other): + desc = self + while desc is not None: + if desc is other: + return True + desc = desc.supertypedesc + return False + def create_varsize(jitstate, contdesc, sizebox): gv_size = sizebox.getgenvar(jitstate) alloctoken = contdesc.varsizealloctoken Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Sat Jun 14 15:53:05 2008 @@ -594,6 +594,14 @@ ##def ll_gvar_from_constant(jitstate, ll_value): ## return jitstate.curbuilder.rgenop.genconst(ll_value) +def geninstanceof(jitstate, objbox, typedesc): + builder = jitstate.curbuilder + gv_objbox = objbox.getgenvar(jitstate) + gv_res = builder.genop_instanceof(gv_objbox, typedesc.alloctoken) + boolbox = rvalue.BoolRedBox(gv_res) + #boolbox.iftrue.append(booleffect.PtrIsNonZeroEffect(argbox, reverse)) # ??? + return boolbox + def gen_residual_oosend(jitstate, argboxes, methdesc): builder = jitstate.curbuilder selfbox = argboxes[0] From antocuni at codespeak.net Sat Jun 14 16:07:06 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 14 Jun 2008 16:07:06 +0200 (CEST) Subject: [pypy-svn] r55845 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080614140706.031C0169E98@codespeak.net> Author: antocuni Date: Sat Jun 14 16:07:06 2008 New Revision: 55845 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_0tlc.py Log: port test_0tlc to ootype, but disable ootype tests because they fail right now Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_0tlc.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_0tlc.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_0tlc.py Sat Jun 14 16:07:06 2008 @@ -1,5 +1,5 @@ import py -from pypy.rpython.module.support import LLSupport +from pypy.rpython.module.support import LLSupport, OOSupport from pypy.jit.rainbow.test.test_portal import PortalTest from pypy.jit.rainbow.test.test_vlist import P_OOPSPEC from pypy.tool.sourcetools import func_with_new_name @@ -9,20 +9,23 @@ from pypy.jit.tl.test.test_tl import FACTORIAL_SOURCE -tlc_interp_without_call = func_with_new_name( - tlc.interp_without_call, "tlc_interp_without_call") -tlc_interp_eval_without_call = tlc.interp_eval_without_call - -# to stick attributes on the new function object, not on tlc.interp_wi* -def build_bytecode(s): - result = ''.join([chr(int(t)) for t in s.split(',')]) - return LLSupport.to_rstr(result) -tlc_interp_without_call.convert_arguments = [build_bytecode, int, int] +class BaseTestTLC(PortalTest): + small = False + def _get_interp(self): + def interp(llbytecode, pc, inputarg): + from pypy.rpython.annlowlevel import hlstr + bytecode = hlstr(llbytecode) + return tlc.interp_without_call(bytecode, pc, inputarg) + + to_rstr = self.to_rstr + def build_bytecode(s): + result = ''.join([chr(int(t)) for t in s.split(',')]) + return to_rstr(result) + interp.convert_arguments = [build_bytecode, int, int] + + return interp -class TestTLC(PortalTest): - small = False - type_system = "lltype" def test_factorial(self): code = tlc.compile(FACTORIAL_SOURCE) @@ -30,9 +33,10 @@ n = 5 expected = 120 - - res = self.timeshift_from_portal(tlc_interp_without_call, - tlc_interp_eval_without_call, + + interp = self._get_interp() + res = self.timeshift_from_portal(interp, + tlc.interp_eval_without_call, [bytecode, 0, n], policy=P_OOPSPEC)#, backendoptimize=True) assert res == expected @@ -52,8 +56,19 @@ DIV """) bytecode = ','.join([str(ord(c)) for c in code]) - res = self.timeshift_from_portal(tlc_interp_without_call, - tlc_interp_eval_without_call, + + interp = self._get_interp() + res = self.timeshift_from_portal(interp, + tlc.interp_eval_without_call, [bytecode, 0, 1], policy=P_OOPSPEC)#, backendoptimize=True) assert res == 20 + + +class TestLLType(BaseTestTLC): + type_system = "lltype" + to_rstr = staticmethod(LLSupport.to_rstr) + +##class TestOOType(BaseTestTLC): +## type_system = "ootype" +## to_rstr = staticmethod(OOSupport.to_rstr) From arigo at codespeak.net Sun Jun 15 13:07:20 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 15 Jun 2008 13:07:20 +0200 (CEST) Subject: [pypy-svn] r55854 - in pypy/dist/pypy: annotation/test bin config doc/config jit/codegen/demo jit/codegen/i386 jit/codegen/llvm jit/codegen/ppc/ppcgen jit/codegen/ppc/ppcgen/test lang/gameboy/tool lang/js lang/prolog/interpreter lang/scheme lang/smalltalk/tool lib/test2 module/__builtin__/test module/_codecs/test module/_sre/test module/sys/test rlib/parsing/test rlib/rsdl/test rpython/microbench tool tool/algo/test tool/pytest tool/test translator translator/benchmark translator/c translator/c/test translator/cli/test translator/goal translator/goal/test2 translator/js translator/js/examples translator/js/examples/bnb translator/microbench/pybench translator/sandbox translator/sandbox/test translator/test translator/tool Message-ID: <20080615110720.BBF1A698051@codespeak.net> Author: arigo Date: Sun Jun 15 13:07:18 2008 New Revision: 55854 Modified: pypy/dist/pypy/annotation/test/autopath.py pypy/dist/pypy/bin/autopath.py pypy/dist/pypy/config/autopath.py pypy/dist/pypy/doc/config/autopath.py pypy/dist/pypy/jit/codegen/demo/autopath.py pypy/dist/pypy/jit/codegen/i386/autopath.py pypy/dist/pypy/jit/codegen/llvm/autopath.py pypy/dist/pypy/jit/codegen/ppc/ppcgen/autopath.py pypy/dist/pypy/jit/codegen/ppc/ppcgen/test/autopath.py pypy/dist/pypy/lang/gameboy/tool/autopath.py pypy/dist/pypy/lang/js/autopath.py pypy/dist/pypy/lang/prolog/interpreter/autopath.py pypy/dist/pypy/lang/scheme/autopath.py pypy/dist/pypy/lang/smalltalk/tool/autopath.py pypy/dist/pypy/lib/test2/autopath.py pypy/dist/pypy/module/__builtin__/test/autopath.py pypy/dist/pypy/module/_codecs/test/autopath.py pypy/dist/pypy/module/_sre/test/autopath.py pypy/dist/pypy/module/sys/test/autopath.py pypy/dist/pypy/rlib/parsing/test/autopath.py pypy/dist/pypy/rlib/rsdl/test/autopath.py pypy/dist/pypy/rpython/microbench/autopath.py pypy/dist/pypy/tool/algo/test/autopath.py pypy/dist/pypy/tool/autopath.py pypy/dist/pypy/tool/pytest/autopath.py pypy/dist/pypy/tool/test/autopath.py pypy/dist/pypy/translator/autopath.py pypy/dist/pypy/translator/benchmark/autopath.py pypy/dist/pypy/translator/c/autopath.py pypy/dist/pypy/translator/c/test/autopath.py pypy/dist/pypy/translator/cli/test/autopath.py pypy/dist/pypy/translator/goal/autopath.py pypy/dist/pypy/translator/goal/test2/autopath.py pypy/dist/pypy/translator/js/autopath.py pypy/dist/pypy/translator/js/examples/autopath.py pypy/dist/pypy/translator/js/examples/bnb/autopath.py pypy/dist/pypy/translator/microbench/pybench/autopath.py pypy/dist/pypy/translator/sandbox/autopath.py pypy/dist/pypy/translator/sandbox/test/autopath.py pypy/dist/pypy/translator/test/autopath.py pypy/dist/pypy/translator/tool/autopath.py Log: Update autopath to detect bogus eol style. Modified: pypy/dist/pypy/annotation/test/autopath.py ============================================================================== --- pypy/dist/pypy/annotation/test/autopath.py (original) +++ pypy/dist/pypy/annotation/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/bin/autopath.py ============================================================================== --- pypy/dist/pypy/bin/autopath.py (original) +++ pypy/dist/pypy/bin/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/config/autopath.py ============================================================================== --- pypy/dist/pypy/config/autopath.py (original) +++ pypy/dist/pypy/config/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/doc/config/autopath.py ============================================================================== --- pypy/dist/pypy/doc/config/autopath.py (original) +++ pypy/dist/pypy/doc/config/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/jit/codegen/demo/autopath.py ============================================================================== --- pypy/dist/pypy/jit/codegen/demo/autopath.py (original) +++ pypy/dist/pypy/jit/codegen/demo/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/jit/codegen/i386/autopath.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/autopath.py (original) +++ pypy/dist/pypy/jit/codegen/i386/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/jit/codegen/llvm/autopath.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/autopath.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/jit/codegen/ppc/ppcgen/autopath.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/ppcgen/autopath.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/ppcgen/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/jit/codegen/ppc/ppcgen/test/autopath.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/ppcgen/test/autopath.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/ppcgen/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/lang/gameboy/tool/autopath.py ============================================================================== --- pypy/dist/pypy/lang/gameboy/tool/autopath.py (original) +++ pypy/dist/pypy/lang/gameboy/tool/autopath.py Sun Jun 15 13:07:18 2008 @@ -33,13 +33,32 @@ except NameError: head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) + error = None while head: partdir = head head, tail = os.path.split(head) if tail == part: + # check if "../py/__init__.py" exists + checkfile = os.path.join(partdir, os.pardir, 'py', '__init__.py') + if not os.path.exists(checkfile): + error = "Cannot find %r" % (os.path.normpath(checkfile),) break else: - raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + error = "Cannot find the parent directory %r of the path %r" % ( + partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") + if error: + raise EnvironmentError("Invalid source tree - bogus checkout! " + + error) pypy_root = os.path.join(head, '') try: Modified: pypy/dist/pypy/lang/js/autopath.py ============================================================================== --- pypy/dist/pypy/lang/js/autopath.py (original) +++ pypy/dist/pypy/lang/js/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/lang/prolog/interpreter/autopath.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/autopath.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/lang/scheme/autopath.py ============================================================================== --- pypy/dist/pypy/lang/scheme/autopath.py (original) +++ pypy/dist/pypy/lang/scheme/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/lang/smalltalk/tool/autopath.py ============================================================================== --- pypy/dist/pypy/lang/smalltalk/tool/autopath.py (original) +++ pypy/dist/pypy/lang/smalltalk/tool/autopath.py Sun Jun 15 13:07:18 2008 @@ -33,13 +33,32 @@ except NameError: head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) + error = None while head: partdir = head head, tail = os.path.split(head) if tail == part: + # check if "../py/__init__.py" exists + checkfile = os.path.join(partdir, os.pardir, 'py', '__init__.py') + if not os.path.exists(checkfile): + error = "Cannot find %r" % (os.path.normpath(checkfile),) break else: - raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + error = "Cannot find the parent directory %r of the path %r" % ( + partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") + if error: + raise EnvironmentError("Invalid source tree - bogus checkout! " + + error) pypy_root = os.path.join(head, '') try: Modified: pypy/dist/pypy/lib/test2/autopath.py ============================================================================== --- pypy/dist/pypy/lib/test2/autopath.py (original) +++ pypy/dist/pypy/lib/test2/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/module/__builtin__/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/autopath.py (original) +++ pypy/dist/pypy/module/__builtin__/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/module/_codecs/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/_codecs/test/autopath.py (original) +++ pypy/dist/pypy/module/_codecs/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/module/_sre/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/_sre/test/autopath.py (original) +++ pypy/dist/pypy/module/_sre/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/module/sys/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/sys/test/autopath.py (original) +++ pypy/dist/pypy/module/sys/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/rlib/parsing/test/autopath.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/autopath.py (original) +++ pypy/dist/pypy/rlib/parsing/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/rlib/rsdl/test/autopath.py ============================================================================== --- pypy/dist/pypy/rlib/rsdl/test/autopath.py (original) +++ pypy/dist/pypy/rlib/rsdl/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/rpython/microbench/autopath.py ============================================================================== --- pypy/dist/pypy/rpython/microbench/autopath.py (original) +++ pypy/dist/pypy/rpython/microbench/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/tool/algo/test/autopath.py ============================================================================== --- pypy/dist/pypy/tool/algo/test/autopath.py (original) +++ pypy/dist/pypy/tool/algo/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/tool/autopath.py ============================================================================== --- pypy/dist/pypy/tool/autopath.py (original) +++ pypy/dist/pypy/tool/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/tool/pytest/autopath.py ============================================================================== --- pypy/dist/pypy/tool/pytest/autopath.py (original) +++ pypy/dist/pypy/tool/pytest/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/tool/test/autopath.py ============================================================================== --- pypy/dist/pypy/tool/test/autopath.py (original) +++ pypy/dist/pypy/tool/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/autopath.py ============================================================================== --- pypy/dist/pypy/translator/autopath.py (original) +++ pypy/dist/pypy/translator/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/benchmark/autopath.py ============================================================================== --- pypy/dist/pypy/translator/benchmark/autopath.py (original) +++ pypy/dist/pypy/translator/benchmark/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/c/autopath.py ============================================================================== --- pypy/dist/pypy/translator/c/autopath.py (original) +++ pypy/dist/pypy/translator/c/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/c/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/c/test/autopath.py (original) +++ pypy/dist/pypy/translator/c/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/cli/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/autopath.py (original) +++ pypy/dist/pypy/translator/cli/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/goal/autopath.py ============================================================================== --- pypy/dist/pypy/translator/goal/autopath.py (original) +++ pypy/dist/pypy/translator/goal/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/goal/test2/autopath.py ============================================================================== --- pypy/dist/pypy/translator/goal/test2/autopath.py (original) +++ pypy/dist/pypy/translator/goal/test2/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/js/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/autopath.py (original) +++ pypy/dist/pypy/translator/js/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/js/examples/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/autopath.py (original) +++ pypy/dist/pypy/translator/js/examples/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/js/examples/bnb/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/bnb/autopath.py (original) +++ pypy/dist/pypy/translator/js/examples/bnb/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/microbench/pybench/autopath.py ============================================================================== --- pypy/dist/pypy/translator/microbench/pybench/autopath.py (original) +++ pypy/dist/pypy/translator/microbench/pybench/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/sandbox/autopath.py ============================================================================== --- pypy/dist/pypy/translator/sandbox/autopath.py (original) +++ pypy/dist/pypy/translator/sandbox/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/sandbox/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/sandbox/test/autopath.py (original) +++ pypy/dist/pypy/translator/sandbox/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/test/autopath.py (original) +++ pypy/dist/pypy/translator/test/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) Modified: pypy/dist/pypy/translator/tool/autopath.py ============================================================================== --- pypy/dist/pypy/translator/tool/autopath.py (original) +++ pypy/dist/pypy/translator/tool/autopath.py Sun Jun 15 13:07:18 2008 @@ -46,6 +46,16 @@ else: error = "Cannot find the parent directory %r of the path %r" % ( partdir, this_dir) + if not error: + # check for bogus end-of-line style (e.g. files checked out on + # Windows and moved to Unix) + f = open(__file__.replace('.pyc', '.py'), 'r') + data = f.read() + f.close() + if data.endswith('\r\n') or data.endswith('\r'): + error = ("Bad end-of-line style in the .py files. Typically " + "caused by a zip file or a checkout done on Windows and " + "moved to Unix or vice-versa.") if error: raise EnvironmentError("Invalid source tree - bogus checkout! " + error) From fijal at codespeak.net Sun Jun 15 21:11:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 15 Jun 2008 21:11:31 +0200 (CEST) Subject: [pypy-svn] r55858 - in pypy/branch/faster-ctypes/pypy/module/_ctypes: . test Message-ID: <20080615191131.5D778698125@codespeak.net> Author: fijal Date: Sun Jun 15 21:11:28 2008 New Revision: 55858 Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/ pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py (contents, props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py (contents, props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_lib.py (contents, props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/test/ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/__init__.py (contents, props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/test/_ctypes_test.c - copied unchanged from r55711, pypy/branch/faster-ctypes/pypy/lib/app_test/ctypes_tests/_ctypes_test.c pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py (contents, props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py (contents, props changed) Log: Beginning of _ctypes module Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py Sun Jun 15 21:11:28 2008 @@ -0,0 +1,12 @@ + +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + applevelname = '_ctypes' + + interpleveldefs = { + 'CDLL' : 'interp_lib.W_CDLL', + } + + appleveldefs = { + } Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Sun Jun 15 21:11:28 2008 @@ -0,0 +1,34 @@ + +from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable, \ + Arguments +from pypy.interpreter.error import OperationError, wrap_oserror +from pypy.interpreter.gateway import interp2app, NoneNotWrapped +from pypy.interpreter.typedef import TypeDef, GetSetProperty + +from pypy.module._rawffi.interp_rawffi import TYPEMAP +from pypy.rpython.lltypesystem import lltype, rffi + +class W_FuncPtr(Wrappable): + def __init__(self, lib, name): + self.lib = lib + self.name = name + # we create initial handle with no args, returning int + self.handle = self._gethandle([], 'i') + + def _gethandle(self, args, res): + args = [TYPEMAP[i] for i in args] + res = TYPEMAP[res] + return self.lib.getpointer(self.name, args, res) + + def call(self, space, args): + """ Calling routine - note that we cache handle to ll + lib, in order to speed up calls. In case arguments or restype + is defined, we invalidate a cache and call new handle + """ + return space.wrap(self.handle.call(lltype.Signed)) + call.unwrap_spec = ['self', ObjSpace, Arguments] + +W_FuncPtr.typedef = TypeDef( + '_FuncPtr', + __call__ = interp2app(W_FuncPtr.call), +) Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_lib.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_lib.py Sun Jun 15 21:11:28 2008 @@ -0,0 +1,45 @@ + +from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable, \ + Arguments +from pypy.interpreter.error import OperationError, wrap_oserror +from pypy.interpreter.gateway import interp2app, NoneNotWrapped +from pypy.interpreter.typedef import TypeDef, GetSetProperty + +from pypy.rlib.libffi import CDLL + +from pypy.module._ctypes.interp_func import W_FuncPtr + +class W_CDLL(Wrappable): + def __init__(self, space, name): + self.cdll = CDLL(name) + self.name = name + self.w_cache = space.newdict() + self.space = space + self.cache_w = {} + + def getattr(self, space, name): + try: + return self.cache_w[name] + except KeyError: + w_val = space.wrap(W_FuncPtr(self.cdll, name)) + self.cache_w[name] = w_val + return w_val + getattr.unwrap_spec = ['self', ObjSpace, str] + +def descr_new_cdll(space, w_type, name): + try: + return space.wrap(W_CDLL(space, name)) + except OSError, e: + raise wrap_oserror(space, e) +descr_new_cdll.unwrap_spec = [ObjSpace, W_Root, str] + +W_CDLL.typedef = TypeDef( + 'CDLL', + __new__ = interp2app(descr_new_cdll), + __getattr__ = interp2app(W_CDLL.getattr), + __doc__ = """ C Dynamically loaded library +use CDLL(libname) to create a handle to a C library (the argument is processed +the same way as dlopen processes it). On such a library you can call: +lib.ptr(func_name, argtype_list, restype) +""" +) Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/__init__.py ============================================================================== Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py Sun Jun 15 21:11:28 2008 @@ -0,0 +1,43 @@ + +from pypy.conftest import gettestobjspace +import py, os, sys + +def compile_so_file(): + from distutils.dist import Distribution + from distutils.extension import Extension + from distutils.ccompiler import get_default_compiler + udir = py.test.ensuretemp('_ctypes_test') + cfile = py.magic.autopath().dirpath().join("_ctypes_test.c") + saved_environ = os.environ.items() + olddir = udir.chdir() + try: + attrs = { + 'name': "_ctypes_test", + 'ext_modules': [ + Extension("_ctypes_test", [str(cfile)]), + ], + 'script_name': 'setup.py', + 'script_args': ['-q', 'build_ext', '--inplace'], + } + dist = Distribution(attrs) + if not dist.parse_command_line(): + raise ValueError, "distutils cmdline parse error" + dist.run_commands() + finally: + olddir.chdir() + for key, value in saved_environ: + if os.environ.get(key) != value: + os.environ[key] = value + + if sys.platform == 'win32': + so_ext = '.dll' + else: + so_ext = '.so' + return udir.join('_ctypes_test' + so_ext) + +class BasicAppTest(object): + def setup_class(cls): + space = gettestobjspace(usemodules=('_ctypes', 'struct')) + cls.space = space + cls.w_so_file = space.wrap(str(compile_so_file())) + Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Sun Jun 15 21:11:28 2008 @@ -0,0 +1,9 @@ + +from pypy.module._ctypes.test.support import BasicAppTest + +class AppTestBasic(BasicAppTest): + def test_int_base(self): + from _ctypes import CDLL + dll = CDLL(self.so_file) + assert dll.get_an_integer() == 42 + From fijal at codespeak.net Sun Jun 15 21:11:44 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 15 Jun 2008 21:11:44 +0200 (CEST) Subject: [pypy-svn] r55859 - in pypy/branch/faster-ctypes/pypy/module/_ctypes: . test Message-ID: <20080615191144.E8FE5698125@codespeak.net> Author: fijal Date: Sun Jun 15 21:11:44 2008 New Revision: 55859 Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/ (props changed) pypy/branch/faster-ctypes/pypy/module/_ctypes/test/ (props changed) Log: fixeol From fijal at codespeak.net Sun Jun 15 22:01:44 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 15 Jun 2008 22:01:44 +0200 (CEST) Subject: [pypy-svn] r55860 - in pypy/branch/faster-ctypes/pypy/module/_ctypes: . test Message-ID: <20080615200144.732C9169F97@codespeak.net> Author: fijal Date: Sun Jun 15 22:01:36 2008 New Revision: 55860 Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/app_stubs.py (contents, props changed) Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Log: Add some support for setting restype Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/__init__.py Sun Jun 15 22:01:36 2008 @@ -5,8 +5,9 @@ applevelname = '_ctypes' interpleveldefs = { - 'CDLL' : 'interp_lib.W_CDLL', + 'dlopen' : 'interp_lib.W_CDLL', } appleveldefs = { + '_SimpleCData' : 'app_stubs._SimpleCData', } Added: pypy/branch/faster-ctypes/pypy/module/_ctypes/app_stubs.py ============================================================================== --- (empty file) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/app_stubs.py Sun Jun 15 22:01:36 2008 @@ -0,0 +1,3 @@ + +class _SimpleCData(object): + pass Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Sun Jun 15 22:01:36 2008 @@ -13,12 +13,14 @@ self.lib = lib self.name = name # we create initial handle with no args, returning int - self.handle = self._gethandle([], 'i') + self.restype = 'i' + self.argtypes = [] + self._regen_handle() - def _gethandle(self, args, res): - args = [TYPEMAP[i] for i in args] - res = TYPEMAP[res] - return self.lib.getpointer(self.name, args, res) + def _regen_handle(self): + args = [TYPEMAP[i] for i in self.argtypes] + res = TYPEMAP[self.restype] + self.handle = self.lib.getpointer(self.name, args, res) def call(self, space, args): """ Calling routine - note that we cache handle to ll @@ -28,7 +30,28 @@ return space.wrap(self.handle.call(lltype.Signed)) call.unwrap_spec = ['self', ObjSpace, Arguments] + def getargtypes(space, self): + xxx + + def setargtypes(space, self, w_value): + xxx + + def getrestype(space, self): + return self.w_restype + + def setrestype(space, self, w_value): + # XXX isinstance check here + restype = space.str_w(space.getattr(w_value, space.wrap('_type_'))) + if len(restype) != 1 or restype[0] not in TYPEMAP: + raise OperationError(space.w_TypeError, space.wrap( + "Unknown type %d" % restype)) + self.w_restype = w_value + self.restype = restype[0] + self._regen_handle() + W_FuncPtr.typedef = TypeDef( '_FuncPtr', __call__ = interp2app(W_FuncPtr.call), + restype = GetSetProperty(W_FuncPtr.getrestype, W_FuncPtr.setrestype), + argtypes = GetSetProperty(W_FuncPtr.getargtypes, W_FuncPtr.setargtypes), ) Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/support.py Sun Jun 15 22:01:36 2008 @@ -40,4 +40,7 @@ space = gettestobjspace(usemodules=('_ctypes', 'struct')) cls.space = space cls.w_so_file = space.wrap(str(compile_so_file())) - + cls.w_dll = space.appexec([cls.w_so_file], """(so_file): + from _ctypes import dlopen + return dlopen(so_file) + """) Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Sun Jun 15 22:01:36 2008 @@ -3,7 +3,13 @@ class AppTestBasic(BasicAppTest): def test_int_base(self): - from _ctypes import CDLL - dll = CDLL(self.so_file) - assert dll.get_an_integer() == 42 + assert self.dll.get_an_integer() == 42 + def test_restype(self): + from _ctypes import _SimpleCData + class c_int(_SimpleCData): + _type_ = 'i' + + f = self.dll.get_an_integer + f.restype = c_int + assert f() == 42 From fijal at codespeak.net Sun Jun 15 22:15:45 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 15 Jun 2008 22:15:45 +0200 (CEST) Subject: [pypy-svn] r55861 - in pypy/branch/faster-ctypes/pypy/module/_ctypes: . test Message-ID: <20080615201545.624C916A041@codespeak.net> Author: fijal Date: Sun Jun 15 22:15:42 2008 New Revision: 55861 Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Log: Another dummy implementation to pass next test. Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Sun Jun 15 22:15:42 2008 @@ -15,6 +15,7 @@ # we create initial handle with no args, returning int self.restype = 'i' self.argtypes = [] + self.has_argtypes = False self._regen_handle() def _regen_handle(self): @@ -22,12 +23,34 @@ res = TYPEMAP[self.restype] self.handle = self.lib.getpointer(self.name, args, res) + def _guess_argtypes(self, args_w): + # XXX + return ['d'] + def call(self, space, args): """ Calling routine - note that we cache handle to ll lib, in order to speed up calls. In case arguments or restype is defined, we invalidate a cache and call new handle """ - return space.wrap(self.handle.call(lltype.Signed)) + assert not self.has_argtypes + if args: + args_w, kwds_w = args.unpack() + if kwds_w: + raise OperationError(space.w_ValueError, space.wrap( + "Cannot pass keyword arguments to C function")) + if args_w: + argtypes = self._guess_argtypes(args_w) + if self.argtypes != argtypes: + self.argtypes = argtypes + self._regen_handle() + for arg in args_w: + self.handle.push_arg(space.float_w(arg)) + if self.restype == 'i': + return space.wrap(self.handle.call(lltype.Signed)) + elif self.restype == 'd': + return space.wrap(self.handle.call(lltype.Float)) + else: + raise NotImplementedError("restype = %s" % self.restype) call.unwrap_spec = ['self', ObjSpace, Arguments] def getargtypes(space, self): Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Sun Jun 15 22:15:42 2008 @@ -13,3 +13,12 @@ f = self.dll.get_an_integer f.restype = c_int assert f() == 42 + + def test_float_restype(self): + from _ctypes import _SimpleCData + class c_float(_SimpleCData): + _type_ = 'd' + + f = self.dll.my_sqrt + f.restype = c_float + assert f(4.0) == 2.0 From arigo at codespeak.net Mon Jun 16 12:22:23 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 12:22:23 +0200 (CEST) Subject: [pypy-svn] r55867 - pypy/dist/pypy Message-ID: <20080616102223.801022A0188@codespeak.net> Author: arigo Date: Mon Jun 16 12:22:21 2008 New Revision: 55867 Modified: pypy/dist/pypy/conftest.py Log: Disable py.test recursion in symlinked subdirectories. Maybe it's a useful feature for py.test in general, or maybe not. For now it looks like a useful feature in PyPy. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Mon Jun 16 12:22:21 2008 @@ -481,3 +481,8 @@ py.test.skip("These are the original ctypes tests.\n" "You can try to run them with 'pypy-c runtests.py'.") return py.test.collect.Directory.run(self) + + def recfilter(self, path): + # disable recursion in symlinked subdirectories + return (py.test.collect.Directory.recfilter(self, path) + and path.check(link=0)) From arigo at codespeak.net Mon Jun 16 12:37:37 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 12:37:37 +0200 (CEST) Subject: [pypy-svn] r55871 - in pypy/dist/pypy/rlib/rsdl: . test Message-ID: <20080616103737.DD21E2A0188@codespeak.net> Author: arigo Date: Mon Jun 16 12:37:37 2008 New Revision: 55871 Added: pypy/dist/pypy/rlib/rsdl/eci.py pypy/dist/pypy/rlib/rsdl/test/conftest.py (contents, props changed) Modified: pypy/dist/pypy/rlib/rsdl/RSDL.py Log: Attempt to skip the rsdl tests if the sdl is not installed. Modified: pypy/dist/pypy/rlib/rsdl/RSDL.py ============================================================================== --- pypy/dist/pypy/rlib/rsdl/RSDL.py (original) +++ pypy/dist/pypy/rlib/rsdl/RSDL.py Mon Jun 16 12:37:37 2008 @@ -1,36 +1,15 @@ from pypy.rpython.lltypesystem import lltype, rffi from pypy.rpython.tool import rffi_platform as platform -from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rlib.rsdl.constants import _constants +from pypy.rlib.rsdl.eci import get_rsdl_compilation_info from pypy.rlib.objectmodel import we_are_translated import py import sys -if sys.platform == 'darwin': - eci = ExternalCompilationInfo( - includes = ['SDL.h', - #'Init.h', - #'SDLMain.m' - #'SDLMain.h'*/ - ], - include_dirs = ['/Library/Frameworks/SDL.framework/Versions/A/Headers', - #str(py.magic.autopath().dirpath().join('macosx-sdl-main')) - ], - link_extra = [ - str(py.magic.autopath().dirpath().join('macosx-sdl-main/SDLMain.m')), - #'macosx-sdl-main/SDLMain.m', - '-I', '/Library/Frameworks/SDL.framework/Versions/A/Headers', - ], - frameworks = ['SDL', 'Cocoa'] - ) -else: - eci = ExternalCompilationInfo( - includes=['SDL.h'], - ) - eci = eci.merge(ExternalCompilationInfo.from_config_tool('sdl-config')) - # ------------------------------------------------------------------------------ +eci = get_rsdl_compilation_info() + def external(name, args, result): return rffi.llexternal(name, args, result, compilation_info=eci) Added: pypy/dist/pypy/rlib/rsdl/eci.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/rsdl/eci.py Mon Jun 16 12:37:37 2008 @@ -0,0 +1,35 @@ +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.translator.tool.cbuild import CompilationError +import py +import sys + +def get_rsdl_compilation_info(): + if sys.platform == 'darwin': + eci = ExternalCompilationInfo( + includes = ['SDL.h', + #'Init.h', + #'SDLMain.m' + #'SDLMain.h'*/ + ], + include_dirs = ['/Library/Frameworks/SDL.framework/Versions/A/Headers', + #str(py.magic.autopath().dirpath().join('macosx-sdl-main')) + ], + link_extra = [ + str(py.magic.autopath().dirpath().join('macosx-sdl-main/SDLMain.m')), + #'macosx-sdl-main/SDLMain.m', + '-I', '/Library/Frameworks/SDL.framework/Versions/A/Headers', + ], + frameworks = ['SDL', 'Cocoa'] + ) + else: + eci = ExternalCompilationInfo( + includes=['SDL.h'], + ) + eci = eci.merge(ExternalCompilationInfo.from_config_tool('sdl-config')) + return eci + +def check_sdl_installation(): + from pypy.rpython.tool import rffi_platform as platform + platform.verify_eci(get_rsdl_compilation_info()) + +SDLNotInstalled = (ImportError, CompilationError) Added: pypy/dist/pypy/rlib/rsdl/test/conftest.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/rsdl/test/conftest.py Mon Jun 16 12:37:37 2008 @@ -0,0 +1,10 @@ +from pypy.rlib.rsdl.eci import check_sdl_installation, SDLNotInstalled +import py + +class Directory(py.test.collect.Directory): + def run(self): + try: + check_sdl_installation() + except SDLNotInstalled, e: + py.test.skip("SDL not installed(?): %s" % (e,)) + return py.test.collect.Directory.run(self) From arigo at codespeak.net Mon Jun 16 13:15:27 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 13:15:27 +0200 (CEST) Subject: [pypy-svn] r55873 - pypy/dist/pypy/rpython/lltypesystem/test Message-ID: <20080616111527.2015716857B@codespeak.net> Author: arigo Date: Mon Jun 16 13:15:26 2008 New Revision: 55873 Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py Log: Fix test. Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py Mon Jun 16 13:15:26 2008 @@ -469,19 +469,25 @@ assert fn() == len(d) def test_nonmovingbuffer_semispace(self): - d = 'some cool data that should not move' + d = 'cool data' def f(): - buf = get_nonmovingbuffer(d) - try: - counter = 0 - for i in range(len(d)): - if buf[i] == d[i]: - counter += 1 - return counter - finally: - free_nonmovingbuffer(d, buf) + counter = 0 + for n in range(32): + buf = get_nonmovingbuffer(d) + try: + for i in range(len(d)): + if buf[i] == d[i]: + counter += 1 + finally: + free_nonmovingbuffer(d, buf) + return counter fn = self.compile(f, [], gcpolicy='semispace') - assert fn(expected_extra_mallocs=9) == len(d) + # The semispace gc uses raw_malloc for its internal data structs + # but hopefully less than 30 times. So we should get < 30 leaks + # unless the get_nonmovingbuffer()/free_nonmovingbuffer() pair + # leaks at each iteration. This is what the following line checks. + res = fn(expected_extra_mallocs=range(30)) + assert res == 32 * len(d) class TestRffiInternals: def test_struct_create(self): From arigo at codespeak.net Mon Jun 16 13:16:58 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 13:16:58 +0200 (CEST) Subject: [pypy-svn] r55874 - pypy/dist/pypy/translator/c/test Message-ID: <20080616111658.253EF16857B@codespeak.net> Author: arigo Date: Mon Jun 16 13:16:57 2008 New Revision: 55874 Modified: pypy/dist/pypy/translator/c/test/test_newgc.py Log: Fix test (for ../gcc/test/test_asmgcroot) Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Mon Jun 16 13:16:57 2008 @@ -896,7 +896,7 @@ def fn(): return rgc.can_move(A()) - c_fn = self.getcompiled(fn, []) + c_fn = self.getcompiled(fn) assert c_fn() == self.GC_CAN_MOVE def test_malloc_nonmovable(self): From arigo at codespeak.net Mon Jun 16 13:25:09 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 13:25:09 +0200 (CEST) Subject: [pypy-svn] r55875 - in pypy/dist/pypy/rpython/lltypesystem: . test Message-ID: <20080616112509.EC62B169E9F@codespeak.net> Author: arigo Date: Mon Jun 16 13:25:09 2008 New Revision: 55875 Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py Log: Test and fix for running str_from_buffer() directly. Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rffi.py Mon Jun 16 13:25:09 2008 @@ -558,7 +558,7 @@ if gc_buf: src = cast_ptr_to_adr(gc_buf) + str_chars_offset else: - src = cast_ptr_to_adr(raw_buf) + src = cast_ptr_to_adr(raw_buf) + itemoffsetof(CCHARP.TO, 0) dest = cast_ptr_to_adr(new_buf) + str_chars_offset ## FIXME: This is bad, because dest could potentially move ## if there are threads involved. Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py Mon Jun 16 13:25:09 2008 @@ -449,6 +449,7 @@ return str_from_buffer(raw_buf, gc_buf, len(d), len(d)-1) finally: keep_buffer_alive_until_here(raw_buf, gc_buf) + assert f() == d[:-1] fn = self.compile(f, [], gcpolicy='ref') assert fn() == d[:-1] @@ -465,6 +466,7 @@ return counter finally: free_nonmovingbuffer(d, buf) + assert f() == len(d) fn = self.compile(f, [], gcpolicy='ref') assert fn() == len(d) From arigo at codespeak.net Mon Jun 16 13:54:57 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 16 Jun 2008 13:54:57 +0200 (CEST) Subject: [pypy-svn] r55877 - in pypy/dist/pypy/lib: . app_test Message-ID: <20080616115457.9F8A4698111@codespeak.net> Author: arigo Date: Mon Jun 16 13:54:55 2008 New Revision: 55877 Modified: pypy/dist/pypy/lib/app_test/test_imp_extra.py pypy/dist/pypy/lib/imp.py Log: Fix the testing of imp.py. Modified: pypy/dist/pypy/lib/app_test/test_imp_extra.py ============================================================================== --- pypy/dist/pypy/lib/app_test/test_imp_extra.py (original) +++ pypy/dist/pypy/lib/app_test/test_imp_extra.py Mon Jun 16 13:54:55 2008 @@ -44,15 +44,12 @@ return fn def _pyc_file(): - # XXX quick hack - # (that's the bytecode for the module containing only 'marker=42') + import marshal + co = compile("marker=42", "x.py", "exec") f = open('@TEST.pyc', 'wb') - f.write('m\xf2\r\n\xd6\x85\x0cCc\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00' - '\x00\x00@\x00\x00\x00s\n\x00\x00\x00d\x00\x00Z\x00\x00d\x01\x00' - 'S(\x02\x00\x00\x00i*\x00\x00\x00N(\x01\x00\x00\x00t\x06\x00\x00' - '\x00marker(\x01\x00\x00\x00R\x00\x00\x00\x00(\x00\x00\x00\x00(' - '\x00\x00\x00\x00t\x04\x00\x00\x00x.pyt\x01\x00\x00\x00?\x01\x00' - '\x00\x00s\x00\x00\x00\x00') + f.write(imp.get_magic()) + f.write('\x00\x00\x00\x00') + marshal.dump(co, f) f.close() return '@TEST.pyc' Modified: pypy/dist/pypy/lib/imp.py ============================================================================== --- pypy/dist/pypy/lib/imp.py (original) +++ pypy/dist/pypy/lib/imp.py Mon Jun 16 13:54:55 2008 @@ -19,10 +19,16 @@ import new import sys, os -def get_magic(): - """Return the magic number for .pyc or .pyo files.""" - import struct - return struct.pack('L', sys._magic()) +# PyPy-specific interface +try: + from sys import _magic as _get_magic_as_int + def get_magic(): + """Return the magic number for .pyc or .pyo files.""" + import struct + return struct.pack('L', _get_magic_as_int()) +except ImportError: + # XXX CPython testing hack: delegate to the real imp.get_magic + get_magic = __import__('imp').get_magic def get_suffixes(): """Return a list of (suffix, mode, type) tuples describing the files From antocuni at codespeak.net Mon Jun 16 16:13:00 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 16 Jun 2008 16:13:00 +0200 (CEST) Subject: [pypy-svn] r55887 - pypy/extradoc/sprintinfo/post-ep2008 Message-ID: <20080616141300.A3D5F2A8079@codespeak.net> Author: antocuni Date: Mon Jun 16 16:12:58 2008 New Revision: 55887 Modified: pypy/extradoc/sprintinfo/post-ep2008/announcement.txt Log: one more topic Modified: pypy/extradoc/sprintinfo/post-ep2008/announcement.txt ============================================================================== --- pypy/extradoc/sprintinfo/post-ep2008/announcement.txt (original) +++ pypy/extradoc/sprintinfo/post-ep2008/announcement.txt Mon Jun 16 16:12:58 2008 @@ -22,7 +22,7 @@ There are many possible and interesting sprint topics to work on - here we list some possible task areas: -* XXX fill me +* try out Python programs and fix them or fix PyPy or fix performance bottlenecks * some JIT improvement work * port the stackless transform to ootypesystem * other interesting stuff that you would like to work on ...;-) From antocuni at codespeak.net Mon Jun 16 16:17:37 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 16 Jun 2008 16:17:37 +0200 (CEST) Subject: [pypy-svn] r55888 - pypy/extradoc/sprintinfo/post-ep2008 Message-ID: <20080616141737.2E54A2A8089@codespeak.net> Author: antocuni Date: Mon Jun 16 16:17:36 2008 New Revision: 55888 Added: pypy/extradoc/sprintinfo/post-ep2008/people.txt (contents, props changed) Log: my dates Added: pypy/extradoc/sprintinfo/post-ep2008/people.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/post-ep2008/people.txt Mon Jun 16 16:17:36 2008 @@ -0,0 +1,54 @@ + +People coming to the Post EuroPython Sprint (Vilnius) 10-12 July 2008 +===================================================================== + +People who have a ``?`` in their arrive/depart or accomodation +column are known to be coming but there are no details +available yet from them. + + +==================== ============== ======================= + Name Arrive/Depart Accomodation +==================== ============== ======================= +Antonio Cuni 6-13 http://www.jnn.lt/ +==================== ============== ======================= + +People on the following list were present at previous sprints: + +==================== ============== ===================== + Name Arrive/Depart Accomodation +==================== ============== ===================== +Maciej Fijalkowski ? ? +Samuele Pedroni ? ? +Armin Rigo ? ? +Carl Friedrich Bolz ? ? +Alexander Schremmer ? ? +Holger Krekel ? ? +Stephan Diehl ? ? +Toon Verwaest ? ? +Camillo Bruni ? ? +Christian Tismer ? ? +Michael Hudson ? ? +Anders Lehmann ? ? +Niklaus Haldimann ? ? +Lene Wagner ? ? +Amaury Forgeot d'Arc ? ? +Valentino Volonghi ? ? +Boris Feigin ? ? +Andrew Thompson ? ? +Bert Freudenberg ? ? +Beatrice Duering ? ? +Richard Emslie ? ? +Johan Hahn ? ? +Niko Matsakis ? ? +Anders Chrigstroem ? ? +Eric van Riet Paap ? ? +Jacob Hallen ? ? +Laura Creighton ? ? +Guido Wesdorp ? ? +Leonardo Santagada ? ? +Alexandre Fayolle ? ? +Sylvain Th?nault ? ? +Toby Watson ? ? +Paul deGrandis ? ? +==================== ============== ===================== From bgola at codespeak.net Mon Jun 16 16:51:10 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Mon, 16 Jun 2008 16:51:10 +0200 (CEST) Subject: [pypy-svn] r55892 - in pypy/branch/2.5-features/pypy/objspace/std: . test Message-ID: <20080616145110.576FF2A8077@codespeak.net> Author: bgola Date: Mon Jun 16 16:51:09 2008 New Revision: 55892 Modified: pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: UnicodeWarning when you attempt to compare a Unicode string and an 8-bit string that can't be converted to Unicode using ASCII Modified: pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py Mon Jun 16 16:51:09 2008 @@ -1,6 +1,28 @@ import py import sys +from pypy.objspace.std.objspace import * +from pypy.objspace.std.stdtypedef import * + +class TestUnicodeObject: + def test_comparison_warning(self): + warnings = [] + def my_warn(msg, warningscls): + warnings.append(msg) + prev_warn(msg, warningscls) + space = self.space + prev_warn = space.warn + try: + space.warn = my_warn + space.appexec([], """(): + chr(128) == unichr(128) + chr(128) != unichr(128) + chr(127) == unichr(127) # no warnings + """) + finally: + space.warn = prev_warn + assert len(warnings) == 2 + class AppTestUnicodeStringStdOnly: def test_compares(self): @@ -13,6 +35,9 @@ assert not (u'a' == 5) assert u'a' != 5 assert u'a' < 5 or u'a' > 5 + assert not chr(128) == unichr(128) # UnicodeWarning + assert chr(128) != unichr(128) + class AppTestUnicodeString: def test_addition(self): Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Mon Jun 16 16:51:09 2008 @@ -83,6 +83,30 @@ def eq__Unicode_Unicode(space, w_left, w_right): return space.newbool(w_left._value == w_right._value) +def eq__Unicode_String(space, w_left, w_right): + from pypy.objspace.std.unicodetype import unicode_from_string + try: + w_uni = unicode_from_string(space, w_right) + except OperationError, e: + if e.match(space, space.w_UnicodeDecodeError): + msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + space.warn(msg, space.w_UnicodeWarning) + return space.w_False + raise + return space.newbool(w_left._value == w_uni._value) + +def ne__Unicode_String(space, w_left, w_right): + from pypy.objspace.std.unicodetype import unicode_from_string + try: + w_uni = unicode_from_string(space, w_right) + except OperationError, e: + if e.match(space, space.w_UnicodeDecodeError): + msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + space.warn(msg, space.w_UnicodeWarning) + return space.w_True + raise + return space.newbool(w_left._value != w_uni._value) + def lt__Unicode_Unicode(space, w_left, w_right): left = w_left._value right = w_right._value From afa at codespeak.net Mon Jun 16 20:13:16 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 16 Jun 2008 20:13:16 +0200 (CEST) Subject: [pypy-svn] r55899 - pypy/dist/pypy/module/__builtin__/test Message-ID: <20080616181316.15EEA398001@codespeak.net> Author: afa Date: Mon Jun 16 20:13:14 2008 New Revision: 55899 Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py Log: Correct test_import for win32: open .pyc files in binary mode Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_import.py Mon Jun 16 20:13:14 2008 @@ -324,7 +324,7 @@ mtime = 12345 co = compile('x = 42', '?', 'exec') cpathname = _testfile(importing.get_pyc_magic(space), mtime, co) - stream = streamio.open_file_as_stream(cpathname, "r") + stream = streamio.open_file_as_stream(cpathname, "rb") try: stream.seek(8, 0) w_code = importing.read_compiled_module( @@ -346,7 +346,7 @@ co = compile('x = 42', '?', 'exec') cpathname = _testfile(importing.get_pyc_magic(space), mtime, co) w_modulename = space.wrap('somemodule') - stream = streamio.open_file_as_stream(cpathname, "r") + stream = streamio.open_file_as_stream(cpathname, "rb") try: w_mod = space.wrap(Module(space, w_modulename)) magic = importing._r_long(stream) @@ -392,7 +392,7 @@ importing._w_long(stream, 128397198) finally: stream.close() - stream = streamio.open_file_as_stream(pathname, "r") + stream = streamio.open_file_as_stream(pathname, "rb") try: res = importing._r_long(stream) assert res == 42 @@ -452,8 +452,8 @@ cpathname) assert ret == 1 - # read compile module - stream = streamio.open_file_as_stream(cpathname, "r") + # read compiled module + stream = streamio.open_file_as_stream(cpathname, "rb") try: stream.seek(8, 0) w_code = importing.read_compiled_module(space, cpathname, @@ -487,7 +487,7 @@ cpathname = _testfile(importing.get_pyc_magic(space1), mtime, co) w_modulename = space2.wrap('somemodule') - stream = streamio.open_file_as_stream(cpathname, "r") + stream = streamio.open_file_as_stream(cpathname, "rb") try: w_mod = space2.wrap(Module(space2, w_modulename)) magic = importing._r_long(stream) From bgola at codespeak.net Mon Jun 16 20:59:35 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Mon, 16 Jun 2008 20:59:35 +0200 (CEST) Subject: [pypy-svn] r55901 - in pypy/branch/2.5-features/pypy/objspace/std: . test Message-ID: <20080616185935.84AF22A8078@codespeak.net> Author: bgola Date: Mon Jun 16 20:59:34 2008 New Revision: 55901 Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeobject.py pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeunicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: UnicodeWarning for Rope and RopeUnicode objects Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py Mon Jun 16 20:59:34 2008 @@ -177,9 +177,31 @@ def eq__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(_eq(w_str1, w_str2)) +def eq__RopeUnicode_Rope(space, w_str1, w_str2): + try: + w_uni = unicode_from_string(space, w_str2) + except OperationError, e: + if e.match(space, space.w_UnicodeDecodeError): + msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + space.warn(msg, space.w_UnicodeWarning) + return space.w_False + raise + return space.newbool(_eq(w_str1, w_str2)) + def ne__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(not _eq(w_str1, w_str2)) +def ne__RopeUnicode_Rope(space, w_str1, w_str2): + try: + w_uni = unicode_from_string(space, w_str2) + except OperationError, e: + if e.match(space, space.w_UnicodeDecodeError): + msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + space.warn(msg, space.w_UnicodeWarning) + return space.w_True + raise + return space.newbool(not _eq(w_str1, w_str2)) + def gt__RopeUnicode_RopeUnicode(space, w_str1, w_str2): n1 = w_str1._node n2 = w_str2._node Modified: pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeobject.py Mon Jun 16 20:59:34 2008 @@ -63,6 +63,13 @@ d = {u'abcdefg': 2} assert d['abcdefg'] == 2 + +class TestUnicodeRopeObject(test_unicodeobject.TestUnicodeObject): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withrope": True}) + + class AppTestUnicodeRopeStdOnly(test_unicodeobject.AppTestUnicodeStringStdOnly): def setup_class(cls): Modified: pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeunicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeunicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/test/test_ropeunicodeobject.py Mon Jun 16 20:59:34 2008 @@ -3,6 +3,12 @@ from pypy.objspace.std.test import test_stringobject, test_unicodeobject from pypy.conftest import gettestobjspace +class TestRopeUnicodeObject(test_unicodeobject.TestUnicodeObject): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withropeunicode": True}) + + class AppTestRopeObject(test_stringobject.AppTestStringObject): def setup_class(cls): Modified: pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/test/test_unicodeobject.py Mon Jun 16 20:59:34 2008 @@ -1,10 +1,8 @@ import py import sys -from pypy.objspace.std.objspace import * -from pypy.objspace.std.stdtypedef import * - class TestUnicodeObject: + def test_comparison_warning(self): warnings = [] def my_warn(msg, warningscls): @@ -21,6 +19,7 @@ """) finally: space.warn = prev_warn + print self.space.config.objspace.std.withrope assert len(warnings) == 2 Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Mon Jun 16 20:59:34 2008 @@ -95,6 +95,8 @@ raise return space.newbool(w_left._value == w_uni._value) +eq__Unicode_Rope = eq__Unicode_String + def ne__Unicode_String(space, w_left, w_right): from pypy.objspace.std.unicodetype import unicode_from_string try: @@ -107,6 +109,8 @@ raise return space.newbool(w_left._value != w_uni._value) +ne__Unicode_Rope = ne__Unicode_String + def lt__Unicode_Unicode(space, w_left, w_right): left = w_left._value right = w_right._value From fijal at codespeak.net Mon Jun 16 21:15:12 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 16 Jun 2008 21:15:12 +0200 (CEST) Subject: [pypy-svn] r55902 - in pypy/branch/faster-ctypes/pypy/module/_ctypes: . test Message-ID: <20080616191512.CD0CB2A8078@codespeak.net> Author: fijal Date: Mon Jun 16 21:15:11 2008 New Revision: 55902 Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Log: * Simplify a bit, by using args_w instead of Arguments * Support assigning to argtypes Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Mon Jun 16 21:15:11 2008 @@ -23,41 +23,63 @@ res = TYPEMAP[self.restype] self.handle = self.lib.getpointer(self.name, args, res) - def _guess_argtypes(self, args_w): - # XXX - return ['d'] + def _guess_argtypes(self, space, args_w): + res = [] + for w_arg in args_w: + if space.is_true(space.isinstance(w_arg, space.w_int)): + res.append('i') + elif space.is_true(space.isinstance(w_arg, space.w_float)): + res.append('d') + else: + raise NotImplementedError("Arg: %s" % str(w_arg)) + return res + + def push_arg(self, space, argtype, w_arg): + if argtype == 'i': + self.handle.push_arg(space.int_w(w_arg)) + elif argtype == 'd': + self.handle.push_arg(space.float_w(w_arg)) + elif argtype == 'f': + self.handle.push_arg(space.float_w(w_arg)) + else: + raise NotImplementedError("Argtype %s" % argtype) - def call(self, space, args): + def call(self, space, args_w): """ Calling routine - note that we cache handle to ll lib, in order to speed up calls. In case arguments or restype is defined, we invalidate a cache and call new handle """ - assert not self.has_argtypes - if args: - args_w, kwds_w = args.unpack() - if kwds_w: - raise OperationError(space.w_ValueError, space.wrap( - "Cannot pass keyword arguments to C function")) - if args_w: - argtypes = self._guess_argtypes(args_w) - if self.argtypes != argtypes: - self.argtypes = argtypes - self._regen_handle() - for arg in args_w: - self.handle.push_arg(space.float_w(arg)) + if args_w: + if self.has_argtypes: + if len(args_w) != len(self.argtypes): + raise OperationError(space.w_TypeError, space.wrap( + "Expected %d args, got %d" % (len(self.argtypes), + len(args_w)))) + argtypes = self.argtypes + else: + argtypes = self._guess_argtypes(space, args_w) + if self.argtypes != argtypes: + self.argtypes = argtypes + self._regen_handle() + for i in range(len(argtypes)): + argtype = argtypes[i] + w_arg = args_w[i] + self.push_arg(space, argtype, w_arg) if self.restype == 'i': return space.wrap(self.handle.call(lltype.Signed)) elif self.restype == 'd': return space.wrap(self.handle.call(lltype.Float)) else: raise NotImplementedError("restype = %s" % self.restype) - call.unwrap_spec = ['self', ObjSpace, Arguments] + call.unwrap_spec = ['self', ObjSpace, 'args_w'] def getargtypes(space, self): - xxx + return self.w_argtypes def setargtypes(space, self, w_value): - xxx + self.argtypes = [space.getattr(w_arg, space.wrap('_type_')) for + w_arg in space.unpackiterable(w_value)] + self.w_argtypes = w_value def getrestype(space, self): return self.w_restype Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/test/test_basic.py Mon Jun 16 21:15:11 2008 @@ -14,7 +14,7 @@ f.restype = c_int assert f() == 42 - def test_float_restype(self): + def test_double_restype(self): from _ctypes import _SimpleCData class c_float(_SimpleCData): _type_ = 'd' @@ -22,3 +22,14 @@ f = self.dll.my_sqrt f.restype = c_float assert f(4.0) == 2.0 + + def test_argtypes(self): + from _ctypes import _SimpleCData + class c_float(_SimpleCData): + _type_ = 'd' + + f = self.dll.my_sqrt + f.restype = c_float + f.argtypes = [c_float] + assert f(4.0) == 2.0 + From fijal at codespeak.net Mon Jun 16 21:27:50 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 16 Jun 2008 21:27:50 +0200 (CEST) Subject: [pypy-svn] r55903 - pypy/branch/faster-ctypes/pypy/module/_ctypes Message-ID: <20080616192750.998C72A8078@codespeak.net> Author: fijal Date: Mon Jun 16 21:27:50 2008 New Revision: 55903 Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Log: Collaps ifs to one Modified: pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py ============================================================================== --- pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py (original) +++ pypy/branch/faster-ctypes/pypy/module/_ctypes/interp_func.py Mon Jun 16 21:27:50 2008 @@ -37,9 +37,7 @@ def push_arg(self, space, argtype, w_arg): if argtype == 'i': self.handle.push_arg(space.int_w(w_arg)) - elif argtype == 'd': - self.handle.push_arg(space.float_w(w_arg)) - elif argtype == 'f': + elif argtype == 'd' or argtype == "f": self.handle.push_arg(space.float_w(w_arg)) else: raise NotImplementedError("Argtype %s" % argtype) From fijal at codespeak.net Mon Jun 16 22:57:05 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 16 Jun 2008 22:57:05 +0200 (CEST) Subject: [pypy-svn] r55904 - in pypy/branch/jit-hotpath/pypy/lang/automata: . test Message-ID: <20080616205705.0BF47169F97@codespeak.net> Author: fijal Date: Mon Jun 16 22:57:03 2008 New Revision: 55904 Added: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py (contents, props changed) pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py (contents, props changed) Log: Mostly for fun, include nfa engine Added: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py ============================================================================== --- (empty file) +++ pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py Mon Jun 16 22:57:03 2008 @@ -0,0 +1,76 @@ + +class NFA(object): + def __init__(self, num_states=0, transitions=None, final_states=None): + self.num_states = 0 + self.transitions = {} + self.final_states = {} + + def add_state(self, final=False): + state = self.num_states + self.num_states += 1 + if final: + self.final_states[state] = None + return self.num_states - 1 + + def add_transition(self, state, input, next_state): + if (state, input) in self.transitions: + self.transitions[state, input].append(next_state) + else: + self.transitions[state, input] = [next_state] + + def get_transitions(self, state, input): + return self.transitions[state, input] + + def get_language(self): + all_chars = {} + for state, input in self.transitions: + all_chars[input] = None + return all_chars + + def __repr__(self): + from pprint import pformat + return "NFA%s" % (pformat( + (self.num_states, self.transitions, self.final_states))) + +def getautomaton(): + a = NFA() + s0 = a.add_state() + s1 = a.add_state() + s2 = a.add_state(final=True) + a.add_transition(s0, "a", s0) + a.add_transition(s0, "c", s1) + a.add_transition(s0, "c", s0) + a.add_transition(s0, "b", s2) + a.add_transition(s1, "b", s2) + return a + +def recognize(automaton, s): + " a simple recognizer" + state = 0 + stack = [] + i = 0 + while True: + char = s[i] + try: + states = automaton.get_transitions(state, char) + except KeyError: + if len(stack) == 0: + return False + i, state = stack.pop() + else: + if len(states) == 1: + i += 1 + state = states[0] + else: + for next_state in states[1:]: + stack.append((i + 1, next_state)) + i += 1 + state = states[0] + while i == len(s): + if state in automaton.final_states: + return True + if len(stack) == 0: + return False + i, state = stack.pop() + + return state in automaton.final_states Added: pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py ============================================================================== --- (empty file) +++ pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Mon Jun 16 22:57:03 2008 @@ -0,0 +1,49 @@ +import py +from pypy import conftest + +from pypy.rpython.test.test_llinterp import interpret + +from pypy.lang.automata.nfa import * + +def rundfa(): + a = getautomaton() + assert 'a' in a.get_language() + assert 'b' in a.get_language() + assert 'c' in a.get_language() + assert 'd' not in a.get_language() + + assert recognize(a, "aaaaaaaaaab") + assert recognize(a, "b") + assert recognize(a, "aaaacb") + + assert not recognize(a, "a") + assert not recognize(a, "xyza") + + assert recognize(a, "acccb") + +def test_nfa_simple(): + rundfa() + +def test_nfa_interp(): + interpret(rundfa, []) + +def test_nfa_compiledummy(): + py.test.skip("not working") + def main(gets): + a = getautomaton() + dfatable, final_states = convertdfa(a) + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognizetable(dfatable, s, final_states) + assert interpret(main, [0]) + assert not interpret(main, [1]) + +def test_nfa_compiledummy2(): + py.test.skip("not working") + def main(gets): + a = getautomaton() + alltrans, final_states = convertagain(a) + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognizeparts(alltrans, final_states, s) + assert interpret(main, [0]) + assert not interpret(main, [1]) + From bgola at codespeak.net Mon Jun 16 23:12:25 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Mon, 16 Jun 2008 23:12:25 +0200 (CEST) Subject: [pypy-svn] r55905 - pypy/branch/2.5-features/pypy/objspace/std Message-ID: <20080616211225.E06EB16A027@codespeak.net> Author: bgola Date: Mon Jun 16 23:12:23 2008 New Revision: 55905 Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: refactoring comparison between unicode and strings (including rope) Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py Mon Jun 16 23:12:23 2008 @@ -177,30 +177,24 @@ def eq__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(_eq(w_str1, w_str2)) -def eq__RopeUnicode_Rope(space, w_str1, w_str2): - try: - w_uni = unicode_from_string(space, w_str2) - except OperationError, e: - if e.match(space, space.w_UnicodeDecodeError): - msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - space.warn(msg, space.w_UnicodeWarning) - return space.w_False - raise - return space.newbool(_eq(w_str1, w_str2)) +def eq__RopeUnicode_Rope(space, w_runi, w_rope): + from pypy.objspace.std.unicodeobject import check_unicode_from_string + msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + w_runi2 = check_unicode_from_string(space, w_rope, msg, unicode_from_string) + if w_runi2 is None: + return space.w_False + return space.newbool(_eq(w_runi, w_runi2)) def ne__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(not _eq(w_str1, w_str2)) -def ne__RopeUnicode_Rope(space, w_str1, w_str2): - try: - w_uni = unicode_from_string(space, w_str2) - except OperationError, e: - if e.match(space, space.w_UnicodeDecodeError): - msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - space.warn(msg, space.w_UnicodeWarning) - return space.w_True - raise - return space.newbool(not _eq(w_str1, w_str2)) +def ne__RopeUnicode_Rope(space, w_runi, w_rope): + from pypy.objspace.std.unicodeobject import check_unicode_from_string + msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + w_runi2 = check_unicode_from_string(space, w_rope, msg, unicode_from_string) + if w_runi2 is None: + return space.w_True + return space.newbool(not _eq(w_runi, w_runi2)) def gt__RopeUnicode_RopeUnicode(space, w_str1, w_str2): n1 = w_str1._node Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Mon Jun 16 23:12:23 2008 @@ -70,6 +70,17 @@ assert isinstance(w_uni, W_UnicodeObject) # help the annotator! return w_uni +# checks if should trigger an unicode warning +def check_unicode_from_string(space, w_str, msg, unicode_from_string): + try: + w_uni2 = unicode_from_string(space, w_str) + except OperationError, e: + if e.match(space, space.w_UnicodeDecodeError): + space.warn(msg, space.w_UnicodeWarning) + return None + raise + return w_uni2 + def str_w__Unicode(space, w_uni): return space.str_w(str__Unicode(space, w_uni)) @@ -83,31 +94,23 @@ def eq__Unicode_Unicode(space, w_left, w_right): return space.newbool(w_left._value == w_right._value) -def eq__Unicode_String(space, w_left, w_right): +def eq__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - try: - w_uni = unicode_from_string(space, w_right) - except OperationError, e: - if e.match(space, space.w_UnicodeDecodeError): - msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - space.warn(msg, space.w_UnicodeWarning) - return space.w_False - raise - return space.newbool(w_left._value == w_uni._value) + msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + w_uni2 = check_unicode_from_string(space, w_str, msg, unicode_from_string) + if w_uni2 is None: + return space.w_False + return space.newbool(w_uni._value == w_uni2._value) eq__Unicode_Rope = eq__Unicode_String -def ne__Unicode_String(space, w_left, w_right): +def ne__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - try: - w_uni = unicode_from_string(space, w_right) - except OperationError, e: - if e.match(space, space.w_UnicodeDecodeError): - msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - space.warn(msg, space.w_UnicodeWarning) - return space.w_True - raise - return space.newbool(w_left._value != w_uni._value) + msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" + w_uni2 = check_unicode_from_string(space, w_str, msg, unicode_from_string) + if w_uni2 is None: + return space.w_True + return space.newbool(w_uni._value != w_uni2._value) ne__Unicode_Rope = ne__Unicode_String From fijal at codespeak.net Mon Jun 16 23:54:45 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 16 Jun 2008 23:54:45 +0200 (CEST) Subject: [pypy-svn] r55906 - in pypy/branch/jit-hotpath/pypy/lang/automata: . test Message-ID: <20080616215445.99DF7169FA6@codespeak.net> Author: fijal Date: Mon Jun 16 23:54:43 2008 New Revision: 55906 Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Log: A simple nfa builder, with tests Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py Mon Jun 16 23:54:43 2008 @@ -74,3 +74,82 @@ i, state = stack.pop() return state in automaton.final_states + +class Builder(object): + def __init__(self): + self.nfa = NFA() + self.current_state = self.nfa.add_state() + + def add_transition(self, c, state=-1, final=False): + if state == -1: + state = self.nfa.add_state(final) + elif final: + self.nfa.final_states[state] = None + self.nfa.add_transition(self.current_state, c, state) + self.current_state = state + + def add_cycle(self, state): + """ We change all transitions pointing to current state + to point to state passed as argument + """ + to_replace = self.current_state + for (fr, ch), v in self.nfa.transitions.items(): + for i in range(len(v)): + if v[i] == to_replace: + v[i] = state + if fr == to_replace: + del self.nfa.transitions[(fr, ch)] + self.nfa.transitions[(state, ch)] = v + try: + del self.nfa.final_states[to_replace] + except KeyError: + pass + else: + self.nfa.final_states[state] = None + +def no_more_chars(i, input): + for k in range(i+1, len(input)): + if input[k] >= 'a' and input[k] <= 'z': + return False + return True + +def compile_regex(input): + """ Simple compilation routine, just in order to not have to mess + up with creating automaton by hand. We assume alphabet to be a-z + """ + builder = Builder() + i = 0 + last_anchor = builder.current_state + joint_point = -1 + paren_stack = [] + last_state = -1 + while i < len(input): + c = input[i] + if c >= 'a' and c <= 'z': + final = no_more_chars(i, input) + last_state = builder.current_state + if (final or input[i + 1] == ')') and joint_point != -1: + builder.add_transition(c, state=joint_point, final=final) + join_point = -1 + else: + builder.add_transition(c, final=final) + elif c == "|": + last_state = -1 + joint_point = builder.current_state + builder.current_state = last_anchor + elif c == '(': + paren_stack.append((builder.current_state, last_anchor, joint_point)) + last_anchor = builder.current_state + joint_point = -1 + elif c == ')': + if not paren_stack: + raise ValueError("Unmatched parentheses") + last_state, last_anchor, joint_point = paren_stack.pop() + elif c == '*': + if last_state == -1: + raise ValueError("Mismatched *") + builder.add_cycle(last_state) + else: + raise ValueError("Unknown char %s" % c) + i += 1 + return builder.nfa Modified: pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Mon Jun 16 23:54:43 2008 @@ -27,6 +27,36 @@ def test_nfa_interp(): interpret(rundfa, []) +def test_nfa_build(): + re = compile_regex("abcd") + assert re.transitions == {(0, "a"):[1], + (1, "b"):[2], + (2, "c"):[3], + (3, "d"):[4]} + assert re.final_states.keys() == [4] + re = compile_regex("ab|de") + assert re.transitions == {(0, "a"):[1], + (1, "b"):[2], + (0, "d"):[3], + (3, "e"):[2]} + assert re.final_states.keys() == [2] + re = compile_regex("a(b|c)(d)") + assert re.transitions == {(0, "a"):[1], + (1, "b"):[2], + (1, "c"):[2], + (2, "d"):[3]} + assert re.final_states.keys() == [3] + re = compile_regex("(a|c)(c|d)|ab") + assert re.transitions == {(0, "a"):[1,3], + (0, "c"):[1], + (1, "c"):[2], + (1, "d"):[2], + (3, "b"):[2]} + assert re.final_states.keys() == [2] + re = compile_regex("a*") + assert re.transitions == {(0, "a"):[0]} + assert re.final_states.keys() == [0] + def test_nfa_compiledummy(): py.test.skip("not working") def main(gets): From fijal at codespeak.net Mon Jun 16 23:58:08 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 16 Jun 2008 23:58:08 +0200 (CEST) Subject: [pypy-svn] r55907 - in pypy/branch/jit-hotpath/pypy/lang/automata: . test Message-ID: <20080616215808.026452A8078@codespeak.net> Author: fijal Date: Mon Jun 16 23:58:08 2008 New Revision: 55907 Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Log: typo Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py Mon Jun 16 23:58:08 2008 @@ -106,6 +106,7 @@ pass else: self.nfa.final_states[state] = None + self.current_state = state def no_more_chars(i, input): for k in range(i+1, len(input)): Modified: pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Mon Jun 16 23:58:08 2008 @@ -56,6 +56,8 @@ re = compile_regex("a*") assert re.transitions == {(0, "a"):[0]} assert re.final_states.keys() == [0] + re = compile_regex("a*b") + assert re.transitions == {(0, "a"):[0], (0, "b"):[2]} def test_nfa_compiledummy(): py.test.skip("not working") From bgola at codespeak.net Tue Jun 17 00:26:25 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Tue, 17 Jun 2008 00:26:25 +0200 (CEST) Subject: [pypy-svn] r55910 - pypy/branch/2.5-features/pypy/objspace/std Message-ID: <20080616222625.515A12A807A@codespeak.net> Author: bgola Date: Tue Jun 17 00:26:24 2008 New Revision: 55910 Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: more refactoring... Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py Tue Jun 17 00:26:24 2008 @@ -179,22 +179,16 @@ def eq__RopeUnicode_Rope(space, w_runi, w_rope): from pypy.objspace.std.unicodeobject import check_unicode_from_string - msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - w_runi2 = check_unicode_from_string(space, w_rope, msg, unicode_from_string) - if w_runi2 is None: - return space.w_False - return space.newbool(_eq(w_runi, w_runi2)) + return check_unicode_from_string(space, w_runi, w_rope, + space.w_False, unicode_from_string) def ne__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(not _eq(w_str1, w_str2)) def ne__RopeUnicode_Rope(space, w_runi, w_rope): from pypy.objspace.std.unicodeobject import check_unicode_from_string - msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - w_runi2 = check_unicode_from_string(space, w_rope, msg, unicode_from_string) - if w_runi2 is None: - return space.w_True - return space.newbool(not _eq(w_runi, w_runi2)) + return check_unicode_from_string(space, w_runi, w_rope, + space.w_True, unicode_from_string) def gt__RopeUnicode_RopeUnicode(space, w_str1, w_str2): n1 = w_str1._node Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Tue Jun 17 00:26:24 2008 @@ -71,15 +71,20 @@ return w_uni # checks if should trigger an unicode warning -def check_unicode_from_string(space, w_str, msg, unicode_from_string): +def check_unicode_from_string(space, w_uni, w_str, value, uni_from_str): try: - w_uni2 = unicode_from_string(space, w_str) + w_uni2 = uni_from_str(space, w_str) except OperationError, e: if e.match(space, space.w_UnicodeDecodeError): + word = "equal" if value == space.w_False else "unequal" + msg = "Unicode %s comparison failed to convert both arguments\ + to Unicode - interpreting them as being unequal" % word space.warn(msg, space.w_UnicodeWarning) - return None + return value raise - return w_uni2 + if value == space.w_False: + return space.eq(w_uni, w_uni2) + return space.not_(space.eq(w_uni, w_uni2)) def str_w__Unicode(space, w_uni): return space.str_w(str__Unicode(space, w_uni)) @@ -96,21 +101,15 @@ def eq__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - msg = "Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - w_uni2 = check_unicode_from_string(space, w_str, msg, unicode_from_string) - if w_uni2 is None: - return space.w_False - return space.newbool(w_uni._value == w_uni2._value) + return check_unicode_from_string(space, w_uni, w_str, + space.w_False, unicode_from_string) eq__Unicode_Rope = eq__Unicode_String def ne__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - msg = "Unicode unequal comparison failed to convert both arguments to Unicode - interpreting them as being unequal" - w_uni2 = check_unicode_from_string(space, w_str, msg, unicode_from_string) - if w_uni2 is None: - return space.w_True - return space.newbool(w_uni._value != w_uni2._value) + return check_unicode_from_string(space, w_uni, w_str, + space.w_True, unicode_from_string) ne__Unicode_Rope = ne__Unicode_String From bgola at codespeak.net Tue Jun 17 01:08:46 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Tue, 17 Jun 2008 01:08:46 +0200 (CEST) Subject: [pypy-svn] r55914 - pypy/branch/2.5-features/pypy/objspace/std Message-ID: <20080616230846.7A0012A807A@codespeak.net> Author: bgola Date: Tue Jun 17 01:08:45 2008 New Revision: 55914 Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: UnicodeWarning Modified: pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/ropeunicodeobject.py Tue Jun 17 01:08:45 2008 @@ -178,17 +178,17 @@ return space.newbool(_eq(w_str1, w_str2)) def eq__RopeUnicode_Rope(space, w_runi, w_rope): - from pypy.objspace.std.unicodeobject import check_unicode_from_string - return check_unicode_from_string(space, w_runi, w_rope, - space.w_False, unicode_from_string) + from pypy.objspace.std.unicodeobject import _unicode_string_comparison + return _unicode_string_comparison(space, w_runi, w_rope, + False, unicode_from_string) def ne__RopeUnicode_RopeUnicode(space, w_str1, w_str2): return space.newbool(not _eq(w_str1, w_str2)) def ne__RopeUnicode_Rope(space, w_runi, w_rope): - from pypy.objspace.std.unicodeobject import check_unicode_from_string - return check_unicode_from_string(space, w_runi, w_rope, - space.w_True, unicode_from_string) + from pypy.objspace.std.unicodeobject import _unicode_string_comparison + return _unicode_string_comparison(space, w_runi, w_rope, + True, unicode_from_string) def gt__RopeUnicode_RopeUnicode(space, w_str1, w_str2): n1 = w_str1._node Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Tue Jun 17 01:08:45 2008 @@ -71,20 +71,20 @@ return w_uni # checks if should trigger an unicode warning -def check_unicode_from_string(space, w_uni, w_str, value, uni_from_str): +def _unicode_string_comparison(space, w_uni, w_str, inverse, uni_from_str): try: w_uni2 = uni_from_str(space, w_str) except OperationError, e: if e.match(space, space.w_UnicodeDecodeError): - word = "equal" if value == space.w_False else "unequal" + word = "unequal" if inverse else "equal" msg = "Unicode %s comparison failed to convert both arguments\ to Unicode - interpreting them as being unequal" % word space.warn(msg, space.w_UnicodeWarning) - return value + return space.newbool(inverse) raise - if value == space.w_False: - return space.eq(w_uni, w_uni2) - return space.not_(space.eq(w_uni, w_uni2)) + if inverse: + return space.not_(space.eq(w_uni, w_uni2)) + return space.eq(w_uni, w_uni2) def str_w__Unicode(space, w_uni): return space.str_w(str__Unicode(space, w_uni)) @@ -101,15 +101,15 @@ def eq__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - return check_unicode_from_string(space, w_uni, w_str, - space.w_False, unicode_from_string) + return _unicode_string_comparison(space, w_uni, w_str, + False, unicode_from_string) eq__Unicode_Rope = eq__Unicode_String def ne__Unicode_String(space, w_uni, w_str): from pypy.objspace.std.unicodetype import unicode_from_string - return check_unicode_from_string(space, w_uni, w_str, - space.w_True, unicode_from_string) + return _unicode_string_comparison(space, w_uni, w_str, + True, unicode_from_string) ne__Unicode_Rope = ne__Unicode_String From fijal at codespeak.net Tue Jun 17 05:23:55 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 17 Jun 2008 05:23:55 +0200 (CEST) Subject: [pypy-svn] r55917 - in pypy/branch/jit-hotpath/pypy/lang/automata: . test Message-ID: <20080617032355.7C07F168573@codespeak.net> Author: fijal Date: Tue Jun 17 05:23:53 2008 New Revision: 55917 Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Log: Slightly different approach, bits of optimization. Let's see if this goes anywhere... Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py Tue Jun 17 05:23:53 2008 @@ -4,6 +4,7 @@ self.num_states = 0 self.transitions = {} self.final_states = {} + self.has_epsilon_moves = False def add_state(self, final=False): state = self.num_states @@ -13,6 +14,8 @@ return self.num_states - 1 def add_transition(self, state, input, next_state): + if input == '?': + self.has_epsilon_moves = True if (state, input) in self.transitions: self.transitions[state, input].append(next_state) else: @@ -27,6 +30,96 @@ all_chars[input] = None return all_chars + def _remove_identical_states(self): + """ Identical states are ones that have similiar e-moves + forward, merge them + """ + possible_merges = {} + prohibited_merges = {} + changed = False + for (s, v), next_s_l in self.transitions.items(): + if v == '?': + for next_s in next_s_l: + if next_s in possible_merges: + possible_merges[next_s][s] = None + else: + possible_merges[next_s] = {s:None} + else: + prohibited_merges[s] = None + for k, v in possible_merges.items(): + v = dict.fromkeys([i for i in v if i not in prohibited_merges]) + if len(v) > 1: + first = v.keys()[0] + self.merge_states(first, v) + changed = True + return changed + + def merge_states(self, to_what, vdict): + for (s, v), next_s_l in self.transitions.items(): + for i in range(len(next_s_l)): + next = next_s_l[i] + if next in vdict: + next_s_l[i] = to_what + for k in self.final_states.keys(): + if k in vdict: + self.final_states[to_what] = None + del final_states[k] + + def _remove_epsilon_moves(self): + for (s, v), next_s_l in self.transitions.items(): + if v == '?': # epsilon move + for next_s in next_s_l: + self.merge_moves(next_s, s) + if next_s in self.final_states: + self.final_states[s] = None + del self.transitions[(s, v)] + return False + return True + + def remove_epsilon_moves(self): + if not self.has_epsilon_moves: + return + changed = True + while changed: + changed = self._remove_identical_states() + self.cleanup() + changed = False + while not changed: + changed = self._remove_epsilon_moves() + self.cleanup() + self.has_epsilon_moves = False + + def _cleanup(self): + all = {0:None} + accessible = {0:None} + for (s, v), next_s_l in self.transitions.items(): + all[s] = None + for next in next_s_l: + accessible[next] = None + all[next] = None + for fs in self.final_states: + all[fs] = None + if all == accessible: + return False + else: + for (s, v), next_s_l in self.transitions.items(): + if s not in accessible: + del self.transitions[(s, v)] + for fs in self.final_states.keys(): + if fs not in accessible: + del self.final_states[fs] + return True + + def cleanup(self): + while self._cleanup(): + pass + + def merge_moves(self, to_replace, replacement): + for (s, c), targets in self.transitions.items(): + if s == to_replace: + for target in targets: + self.add_transition(replacement, c, target) + def __repr__(self): from pprint import pformat return "NFA%s" % (pformat( @@ -49,6 +142,7 @@ state = 0 stack = [] i = 0 + automaton.remove_epsilon_moves() while True: char = s[i] try: @@ -75,82 +169,45 @@ return state in automaton.final_states -class Builder(object): - def __init__(self): - self.nfa = NFA() - self.current_state = self.nfa.add_state() - - def add_transition(self, c, state=-1, final=False): - if state == -1: - state = self.nfa.add_state(final) - elif final: - self.nfa.final_states[state] = None - self.nfa.add_transition(self.current_state, c, state) - self.current_state = state - - def add_cycle(self, state): - """ We change all transitions pointing to current state - to point to state passed as argument - """ - to_replace = self.current_state - for (fr, ch), v in self.nfa.transitions.items(): - for i in range(len(v)): - if v[i] == to_replace: - v[i] = state - if fr == to_replace: - del self.nfa.transitions[(fr, ch)] - self.nfa.transitions[(state, ch)] = v - try: - del self.nfa.final_states[to_replace] - except KeyError: - pass - else: - self.nfa.final_states[state] = None - self.current_state = state - -def no_more_chars(i, input): - for k in range(i+1, len(input)): - if input[k] >= 'a' and input[k] <= 'z': - return False - return True +def in_alphabet(c): + return c >= 'a' and c <= 'z' -def compile_regex(input): - """ Simple compilation routine, just in order to not have to mess - up with creating automaton by hand. We assume alphabet to be a-z - """ - builder = Builder() - i = 0 - last_anchor = builder.current_state - joint_point = -1 - paren_stack = [] +def compile_part(nfa, start_state, input, pos): + i = pos last_state = -1 + state = start_state while i < len(input): c = input[i] - if c >= 'a' and c <= 'z': - final = no_more_chars(i, input) - last_state = builder.current_state - if (final or input[i + 1] == ')') and joint_point != -1: - builder.add_transition(c, state=joint_point, final=final) - join_point = -1 - else: - builder.add_transition(c, final=final) - elif c == "|": - last_state = -1 - joint_point = builder.current_state - builder.current_state = last_anchor - elif c == '(': - paren_stack.append((builder.current_state, last_anchor, joint_point)) - last_anchor = builder.current_state - joint_point = -1 + if in_alphabet(c): + next_state = nfa.add_state() + nfa.add_transition(state, c, next_state) + state = next_state elif c == ')': - if not paren_stack: - raise ValueError("Unmatched parentheses") - last_state, last_anchor, joint_point = paren_stack.pop() - elif c == '*': + break + elif c == '(': + i, state = compile_part(nfa, state, input, i + 1) + elif c == '|': if last_state == -1: - raise ValueError("Mismatched *") - builder.add_cycle(last_state) + last_state = nfa.add_state() + nfa.add_transition(state, '?', last_state) + state = start_state + elif c == '*': + nfa.add_transition(state, '?', start_state) + state = start_state else: raise ValueError("Unknown char %s" % c) i += 1 - return builder.nfa + if last_state != -1: + nfa.add_transition(state, '?', last_state) + state = last_state + return i, state + +def compile_regex(input): + start = 0 + nfa = NFA() + start_state = nfa.add_state() + pos, state = compile_part(nfa, start_state, input, 0) + if pos != len(input): + raise ValueError("Mismatched parenthesis") + nfa.final_states[state] = None + return nfa Modified: pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Tue Jun 17 05:23:53 2008 @@ -27,6 +27,18 @@ def test_nfa_interp(): interpret(rundfa, []) +def test_merge_states(): + nfa = NFA() + s0 = nfa.add_state() + s1 = nfa.add_state(final=True) + nfa.add_transition(s0, 'a', s0) + nfa.add_transition(s0, '?', s1) + assert nfa.has_epsilon_moves + nfa.remove_epsilon_moves() + assert not nfa.has_epsilon_moves + assert nfa.transitions == {(0, 'a'): [0]} + assert nfa.final_states.keys() == [0] + def test_nfa_build(): re = compile_regex("abcd") assert re.transitions == {(0, "a"):[1], @@ -35,29 +47,53 @@ (3, "d"):[4]} assert re.final_states.keys() == [4] re = compile_regex("ab|de") + re.remove_epsilon_moves() assert re.transitions == {(0, "a"):[1], (1, "b"):[2], - (0, "d"):[3], - (3, "e"):[2]} + (0, "d"):[4], + (4, "e"):[2]} assert re.final_states.keys() == [2] re = compile_regex("a(b|c)(d)") + re.remove_epsilon_moves() assert re.transitions == {(0, "a"):[1], (1, "b"):[2], (1, "c"):[2], - (2, "d"):[3]} - assert re.final_states.keys() == [3] + (2, "d"):[5]} + assert re.final_states.keys() == [5] + re = compile_regex("(a|c)(c|d)") + re.remove_epsilon_moves() + assert re.transitions == {(0, "a"):[1], + (0, "c"):[1], + (1, "c"):[4], + (1, "d"):[4]} + assert re.final_states.keys() == [4] re = compile_regex("(a|c)(c|d)|ab") - assert re.transitions == {(0, "a"):[1,3], + re.remove_epsilon_moves() + assert re.transitions == {(0, "a"):[1,8], + (8, "b"):[9], (0, "c"):[1], - (1, "c"):[2], - (1, "d"):[2], - (3, "b"):[2]} - assert re.final_states.keys() == [2] + (1, "c"):[4], + (1, "d"):[4]} + assert sorted(re.final_states.keys()) == [4, 9] re = compile_regex("a*") - assert re.transitions == {(0, "a"):[0]} - assert re.final_states.keys() == [0] + re.remove_epsilon_moves() + assert re.transitions == {(0, "a"):[1], + (1, "a"):[1]} + assert sorted(re.final_states.keys()) == [0, 1] re = compile_regex("a*b") - assert re.transitions == {(0, "a"):[0], (0, "b"):[2]} + re.remove_epsilon_moves() + assert re.transitions == {(0, "a"):[1], (1, "b"):[2], + (0, 'b'):[2], (1, 'a'):[1]} + assert re.final_states.keys() == [2] + re = compile_regex("|a") + re.remove_epsilon_moves() + assert re.transitions == {(0, "a"):[2]} + assert re.final_states.keys() == [0,2] + #re = compile_regex('a{0,3}') + #assert re.transitions == {(0, "a"):[0,1], + # (1, "a"):[0,2], + # (2, "a"):[0,3]} + #assert re.final_states.keys() == [0] def test_nfa_compiledummy(): py.test.skip("not working") From afa at codespeak.net Tue Jun 17 10:27:57 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 17 Jun 2008 10:27:57 +0200 (CEST) Subject: [pypy-svn] r55920 - in pypy/dist/pypy/module/__builtin__: . test Message-ID: <20080617082757.BE51D16A05B@codespeak.net> Author: afa Date: Tue Jun 17 10:27:56 2008 New Revision: 55920 Modified: pypy/dist/pypy/module/__builtin__/importing.py pypy/dist/pypy/module/__builtin__/test/test_import.py Log: Write the .pyc file before executing the module code (unless there is a SyntaxError, of course) This should speed up pypy-c a bit: the _locale module (which always raises ImportError) is imported at least twice on startup. Avoid to compile it every time... Added more tests around .pyc generation. Modified: pypy/dist/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/importing.py (original) +++ pypy/dist/pypy/module/__builtin__/importing.py Tue Jun 17 10:27:56 2008 @@ -416,20 +416,21 @@ Load a source module from a given file and return its module object. """ - w = space.wrap pycode = parse_source_module(space, pathname, source) + if space.config.objspace.usepycfiles and write_pyc: + mtime = os.stat(pathname)[stat.ST_MTIME] + cpathname = pathname + 'c' + print "write_compiled_module", cpathname + write_compiled_module(space, pycode, cpathname, mtime) + + w = space.wrap w_dict = space.getattr(w_mod, w('__dict__')) space.call_method(w_dict, 'setdefault', w('__builtins__'), w(space.builtin)) pycode.exec_code(space, w_dict, w_dict) - if space.config.objspace.usepycfiles and write_pyc: - mtime = os.stat(pathname)[stat.ST_MTIME] - cpathname = pathname + 'c' - write_compiled_module(space, pycode, cpathname, mtime) - return w_mod def _get_long(s): Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_import.py Tue Jun 17 10:27:56 2008 @@ -1,6 +1,7 @@ import py from pypy.interpreter.module import Module from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError import pypy.interpreter.pycode from pypy.tool.udir import udir from pypy.rlib import streamio @@ -271,10 +272,10 @@ f.close() return cpathname -def _testfilesource(): +def _testfilesource(source="x=42"): pathname = str(udir.join('test.py')) f = file(pathname, "wb") - f.write("x=42") + f.write(source) f.close() return pathname @@ -422,7 +423,70 @@ ret = space.int_w(w_ret) assert ret == 42 - #XXX Note tested while no writing + cpathname = udir.join('test.pyc') + assert cpathname.check() + cpathname.remove() + + def test_load_source_module_nowrite(self): + space = self.space + w_modulename = space.wrap('somemodule') + w_mod = space.wrap(Module(space, w_modulename)) + pathname = _testfilesource() + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.load_source_module(space, + w_modulename, + w_mod, + pathname, + stream.readall(), + write_pyc=False) + finally: + stream.close() + cpathname = udir.join('test.pyc') + assert not cpathname.check() + + def test_load_source_module_syntaxerror(self): + # No .pyc file on SyntaxError + space = self.space + w_modulename = space.wrap('somemodule') + w_mod = space.wrap(Module(space, w_modulename)) + pathname = _testfilesource(source="") + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.load_source_module(space, + w_modulename, + w_mod, + pathname, + stream.readall()) + except OperationError: + # OperationError("Syntax Error") + pass + stream.close() + + cpathname = udir.join('test.pyc') + assert not cpathname.check() + + def test_load_source_module_importerror(self): + # the .pyc file is created before executing the module + space = self.space + w_modulename = space.wrap('somemodule') + w_mod = space.wrap(Module(space, w_modulename)) + pathname = _testfilesource(source="a = unknown_name") + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.load_source_module(space, + w_modulename, + w_mod, + pathname, + stream.readall()) + except OperationError: + # OperationError("NameError", "global name 'unknown_name' is not defined") + pass + stream.close() + + # And the .pyc has been generated + cpathname = udir.join('test.pyc') + assert cpathname.check() def test_write_compiled_module(self): space = self.space From afa at codespeak.net Tue Jun 17 10:44:22 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 17 Jun 2008 10:44:22 +0200 (CEST) Subject: [pypy-svn] r55921 - pypy/dist/pypy/module/__builtin__ Message-ID: <20080617084422.1F2BB16A05B@codespeak.net> Author: afa Date: Tue Jun 17 10:44:20 2008 New Revision: 55921 Modified: pypy/dist/pypy/module/__builtin__/importing.py Log: Remove debug print Modified: pypy/dist/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/importing.py (original) +++ pypy/dist/pypy/module/__builtin__/importing.py Tue Jun 17 10:44:20 2008 @@ -421,7 +421,6 @@ if space.config.objspace.usepycfiles and write_pyc: mtime = os.stat(pathname)[stat.ST_MTIME] cpathname = pathname + 'c' - print "write_compiled_module", cpathname write_compiled_module(space, pycode, cpathname, mtime) w = space.wrap From antocuni at codespeak.net Tue Jun 17 15:17:24 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 17 Jun 2008 15:17:24 +0200 (CEST) Subject: [pypy-svn] r55923 - in pypy/branch/oo-jit/pypy: jit/rainbow/test jit/timeshifter rpython/ootypesystem Message-ID: <20080617131724.155E039B599@codespeak.net> Author: antocuni Date: Tue Jun 17 15:17:22 2008 New Revision: 55923 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py pypy/branch/oo-jit/pypy/jit/timeshifter/oop.py pypy/branch/oo-jit/pypy/jit/timeshifter/vlist.py pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py Log: port some array tests to ootype Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Tue Jun 17 15:17:22 2008 @@ -733,50 +733,6 @@ assert res == 42 self.check_insns({'int_add': 1}) - def test_simple_array(self): - A = lltype.GcArray(lltype.Signed, - hints={'immutable': True}) - def ll_function(a): - return a[0] * a[1] - - def int_array(string): - items = [int(x) for x in string.split(',')] - n = len(items) - a1 = lltype.malloc(A, n) - for i in range(n): - a1[i] = items[i] - return a1 - ll_function.convert_arguments = [int_array] - - res = self.interpret(ll_function, ["6,7"], []) - assert res == 42 - self.check_insns({'getarrayitem': 2, 'int_mul': 1}) - res = self.interpret(ll_function, ["8,3"], [0]) - assert res == 24 - self.check_insns({}) - - def test_arraysize(self): - A = lltype.GcArray(lltype.Signed) - def ll_function(a): - return len(a) - - def int_array(string): - items = [int(x) for x in string.split(',')] - n = len(items) - a1 = lltype.malloc(A, n) - for i in range(n): - a1[i] = items[i] - return a1 - ll_function.convert_arguments = [int_array] - - res = self.interpret(ll_function, ["6,7"], []) - assert res == 2 - self.check_insns({'getarraysize': 1}) - res = self.interpret(ll_function, ["8,3,3,4,5"], [0]) - assert res == 5 - self.check_insns({}) - - def test_simple_struct_malloc(self): py.test.skip("blue containers: to be reimplemented") S = lltype.GcStruct('helloworld', ('hello', lltype.Signed), @@ -2043,7 +1999,6 @@ return isinstance(obj, B) res = self.interpret(fn, [True], [], policy=StopAtXPolicy(g)) assert res - #self.check_insns({}) def test_manymanyvars(self): @@ -2139,6 +2094,49 @@ class TestLLType(SimpleTests): type_system = "lltype" + def test_simple_array(self): + A = lltype.GcArray(lltype.Signed, + hints={'immutable': True}) + def ll_function(a): + return a[0] * a[1] + + def int_array(string): + items = [int(x) for x in string.split(',')] + n = len(items) + a1 = lltype.malloc(A, n) + for i in range(n): + a1[i] = items[i] + return a1 + ll_function.convert_arguments = [int_array] + + res = self.interpret(ll_function, ["6,7"], []) + assert res == 42 + self.check_insns({'getarrayitem': 2, 'int_mul': 1}) + res = self.interpret(ll_function, ["8,3"], [0]) + assert res == 24 + self.check_insns({}) + + def test_arraysize(self): + A = lltype.GcArray(lltype.Signed) + def ll_function(a): + return len(a) + + def int_array(string): + items = [int(x) for x in string.split(',')] + n = len(items) + a1 = lltype.malloc(A, n) + for i in range(n): + a1[i] = items[i] + return a1 + ll_function.convert_arguments = [int_array] + + res = self.interpret(ll_function, ["6,7"], []) + assert res == 2 + self.check_insns({'getarraysize': 1}) + res = self.interpret(ll_function, ["8,3,3,4,5"], [0]) + assert res == 5 + self.check_insns({}) + def test_degenerated_before_return(self): S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) @@ -2311,6 +2309,49 @@ class TestOOType(OOTypeMixin, SimpleTests): + def test_simple_array(self): + A = ootype.Array(lltype.Signed, + _hints={'immutable': True}) + def ll_function(a): + return a.ll_getitem_fast(0) * a.ll_getitem_fast(1) + + def int_array(string): + items = [int(x) for x in string.split(',')] + n = len(items) + a1 = ootype.oonewarray(A, n) + for i in range(n): + a1.ll_setitem_fast(i, items[i]) + return a1 + ll_function.convert_arguments = [int_array] + + res = self.interpret(ll_function, ["6,7"], []) + assert res == 42 + self.check_insns({'oosend': 2, 'int_mul': 1}) + res = self.interpret(ll_function, ["8,3"], [0]) + assert res == 24 + self.check_insns({}) + + def test_arraysize(self): + A = ootype.Array(lltype.Signed) + def ll_function(a): + return a.ll_length() + + def int_array(string): + items = [int(x) for x in string.split(',')] + n = len(items) + a1 = ootype.oonewarray(A, n) + for i in range(n): + a1.ll_setitem_fast(i, items[i]) + return a1 + ll_function.convert_arguments = [int_array] + + res = self.interpret(ll_function, ["6,7"], []) + assert res == 2 + self.check_insns({'oosend': 1}) + res = self.interpret(ll_function, ["8,3,3,4,5"], [0]) + assert res == 5 + self.check_insns({}) + def test_degenerated_before_return(self): S = ootype.Instance('S', ootype.ROOT, {'x': ootype.Signed}) T = ootype.Instance('T', S, {'y': ootype.Float}) Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/oop.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/oop.py Tue Jun 17 15:17:22 2008 @@ -130,10 +130,13 @@ self.do_call = do_call + def isfoldable(self, deepfrozen): + return deepfrozen + def residual_call(self, jitstate, argboxes, deepfrozen=False): builder = jitstate.curbuilder args_gv = [] - fold = deepfrozen + fold = self.isfoldable(deepfrozen) for argsrc in self.residualargsources: gv_arg = argboxes[argsrc].getgenvar(jitstate) args_gv.append(gv_arg) @@ -292,10 +295,26 @@ self.residualargsources = range(len(self.OOPARGTYPES)) self.typename = self.SELFTYPE.oopspec_name methname = meth._name.lstrip('_') - methname = methname.lstrip('ll_') + assert methname.startswith('ll_') + methname = methname[3:] self.method = 'oop_%s_method_%s' % (self.typename, methname) self.is_method = True + self.methtoken = RGenOp.methToken(self.SELFTYPE, meth._name) + + self.foldable = False + if isinstance(self.SELFTYPE, ootype.Array): + if self.SELFTYPE._hints.get('immutable', False): + self.foldable = True + if getattr(meth, '_callable', None) and \ + getattr(meth._callable, 'foldable', False): + self.foldable = True + + def generate_call(self, builder, args_gv): + gv_self, args_gv = args_gv[0], args_gv[1:] + return builder.genop_oosend(self.methtoken, gv_self, args_gv) + def isfoldable(self, deepfrozen): + return deepfrozen or self.foldable class SendOopSpecDesc_list(SendOopSpecDesc): pass Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/vlist.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/vlist.py Tue Jun 17 15:17:22 2008 @@ -518,8 +518,6 @@ else: oopspecdesc.residual_call(jitstate, [selfbox, indexbox, itembox]) -oop_list_method_setitem_fast = oop_list_setitem - def oop_list_delitem(jitstate, oopspecdesc, deepfrozen, selfbox, indexbox): content = selfbox.content if isinstance(content, VirtualList) and indexbox.is_constant(): @@ -530,3 +528,8 @@ oopspecdesc.residual_exception(jitstate, IndexError) else: oopspecdesc.residual_call(jitstate, [selfbox, indexbox]) + + +oop_list_method_getitem_fast = oop_list_getitem +oop_list_method_setitem_fast = oop_list_setitem +oop_list_method_length = oop_list_len Modified: pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py Tue Jun 17 15:17:22 2008 @@ -587,8 +587,9 @@ oopspec_new = 'new(length)' oopspec_new_argnames = ('length',) - def __init__(self, ITEMTYPE=None): + def __init__(self, ITEMTYPE=None, _hints = {}): self.ITEM = ITEMTYPE + self._hints = frozendict(_hints) self._null = _null_array(self) if ITEMTYPE is not None: self._init_methods() @@ -1540,12 +1541,15 @@ def ll_length(self): # NOT_RPYTHON return len(self._array) + ll_length.oopargcheck = lambda a: bool(a) + ll_length.foldable = True def ll_getitem_fast(self, index): # NOT_RPYTHON assert typeOf(index) == Signed assert index >= 0 return self._array[index] + ll_getitem_fast.oopargcheck = lambda a, index: bool(a) def ll_setitem_fast(self, index, item): # NOT_RPYTHON @@ -1553,6 +1557,7 @@ assert typeOf(index) == Signed assert index >= 0 self._array[index] = item + ll_setitem_fast.oopargcheck = lambda a, index, item: bool(a) class _null_array(_null_mixin(_array), _array): From bgola at codespeak.net Tue Jun 17 15:45:26 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Tue, 17 Jun 2008 15:45:26 +0200 (CEST) Subject: [pypy-svn] r55924 - in pypy/branch/2.5-features/pypy: lib objspace/std Message-ID: <20080617134526.05011398002@codespeak.net> Author: bgola Date: Tue Jun 17 15:45:23 2008 New Revision: 55924 Modified: pypy/branch/2.5-features/pypy/lib/_exceptions.py pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Log: UnicodeWarning class... Modified: pypy/branch/2.5-features/pypy/lib/_exceptions.py ============================================================================== --- pypy/branch/2.5-features/pypy/lib/_exceptions.py (original) +++ pypy/branch/2.5-features/pypy/lib/_exceptions.py Tue Jun 17 15:45:23 2008 @@ -84,7 +84,8 @@ +-- SyntaxWarning +-- OverflowWarning +-- RuntimeWarning - +-- FutureWarning""" + +-- FutureWarning + +-- UnicodeWarning""" class Exception: """Common base class for all exceptions.""" @@ -383,6 +384,10 @@ class SyntaxWarning(Warning): """Base class for warnings about dubious syntax.""" +class UnicodeWarning(Warning): + """Base class for warnings about Unicode related problems, mostly + related to conversion problems.""" + class MemoryError(StandardError): """Out of memory.""" Modified: pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py (original) +++ pypy/branch/2.5-features/pypy/objspace/std/unicodeobject.py Tue Jun 17 15:45:23 2008 @@ -76,15 +76,19 @@ w_uni2 = uni_from_str(space, w_str) except OperationError, e: if e.match(space, space.w_UnicodeDecodeError): - word = "unequal" if inverse else "equal" + if inverse: + word = "unequal" + else : + word = "equal" msg = "Unicode %s comparison failed to convert both arguments\ to Unicode - interpreting them as being unequal" % word space.warn(msg, space.w_UnicodeWarning) return space.newbool(inverse) raise - if inverse: - return space.not_(space.eq(w_uni, w_uni2)) - return space.eq(w_uni, w_uni2) + result = space.eq(w_uni, w_uni2) + if inverse: + return space.not_(result) + return result def str_w__Unicode(space, w_uni): return space.str_w(str__Unicode(space, w_uni)) From hpk at codespeak.net Tue Jun 17 15:51:35 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 17 Jun 2008 15:51:35 +0200 (CEST) Subject: [pypy-svn] r55925 - pypy/extradoc/sprintinfo/post-ep2008 Message-ID: <20080617135135.AF7B4169ED7@codespeak.net> Author: hpk Date: Tue Jun 17 15:51:35 2008 New Revision: 55925 Modified: pypy/extradoc/sprintinfo/post-ep2008/people.txt Log: my dates Modified: pypy/extradoc/sprintinfo/post-ep2008/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/post-ep2008/people.txt (original) +++ pypy/extradoc/sprintinfo/post-ep2008/people.txt Tue Jun 17 15:51:35 2008 @@ -7,11 +7,12 @@ available yet from them. -==================== ============== ======================= +==================== ============== ============================ Name Arrive/Depart Accomodation -==================== ============== ======================= +==================== ============== ============================ Antonio Cuni 6-13 http://www.jnn.lt/ -==================== ============== ======================= +Holger Krekel 6-13 http://www.litinterp.lt/ +==================== ============== ============================ People on the following list were present at previous sprints: From arigo at codespeak.net Tue Jun 17 15:58:33 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 17 Jun 2008 15:58:33 +0200 (CEST) Subject: [pypy-svn] r55926 - pypy/dist/pypy/module/__builtin__/test Message-ID: <20080617135833.31704169EE7@codespeak.net> Author: arigo Date: Tue Jun 17 15:58:32 2008 New Revision: 55926 Modified: pypy/dist/pypy/module/__builtin__/test/test_descriptor.py Log: Subclassing the type 'super' is bogus. Add skipped test to show that. Modified: pypy/dist/pypy/module/__builtin__/test/test_descriptor.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_descriptor.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_descriptor.py Tue Jun 17 15:58:32 2008 @@ -134,6 +134,11 @@ assert F().meth(6) == "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)" + skip("in-progress: buggy implementation of 'super' subclasses") + x = mysuper(F, F()) + x.foobar = 42 + assert x.foobar == 42 + def test_super_lookup(self): class DDbase(object): From antocuni at codespeak.net Tue Jun 17 16:09:55 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 17 Jun 2008 16:09:55 +0200 (CEST) Subject: [pypy-svn] r55927 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080617140955.0FCB7398002@codespeak.net> Author: antocuni Date: Tue Jun 17 16:09:53 2008 New Revision: 55927 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Log: port more array tests to ootype Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Tue Jun 17 16:09:53 2008 @@ -813,93 +813,6 @@ assert res == 42 self.check_insns({}) - - def test_setarrayitem(self): - A = lltype.GcArray(lltype.Signed) - a = lltype.malloc(A, 2, immortal=True) - def ll_function(): - a[0] = 1 - a[1] = 2 - return a[0]+a[1] - - res = self.interpret(ll_function, [], []) - assert res == 3 - - def test_red_array(self): - A = lltype.GcArray(lltype.Signed) - def ll_function(x, y, n): - a = lltype.malloc(A, 2) - a[0] = x - a[1] = y - return a[n]*len(a) - - res = self.interpret(ll_function, [21, -21, 0], []) - assert res == 42 - self.check_insns({'malloc_varsize': 1, - 'setarrayitem': 2, 'getarrayitem': 1, - 'getarraysize': 1, 'int_mul': 1}) - - res = self.interpret(ll_function, [21, -21, 1], []) - assert res == -42 - self.check_insns({'malloc_varsize': 1, - 'setarrayitem': 2, 'getarrayitem': 1, - 'getarraysize': 1, 'int_mul': 1}) - - def test_red_struct_array(self): - S = lltype.Struct('s', ('x', lltype.Signed)) - A = lltype.GcArray(S) - def ll_function(x, y, n): - a = lltype.malloc(A, 2) - a[0].x = x - a[1].x = y - return a[n].x*len(a) - - res = self.interpret(ll_function, [21, -21, 0], []) - assert res == 42 - self.check_insns({'malloc_varsize': 1, - 'setinteriorfield': 2, 'getinteriorfield': 1, - 'getarraysize': 1, 'int_mul': 1}) - - res = self.interpret(ll_function, [21, -21, 1], []) - assert res == -42 - self.check_insns({'malloc_varsize': 1, - 'setinteriorfield': 2, 'getinteriorfield': 1, - 'getarraysize': 1, 'int_mul': 1}) - - - def test_red_varsized_struct(self): - A = lltype.Array(lltype.Signed) - S = lltype.GcStruct('S', ('foo', lltype.Signed), ('a', A)) - def ll_function(x, y, n): - s = lltype.malloc(S, 3) - s.foo = len(s.a)-1 - s.a[0] = x - s.a[1] = y - return s.a[n]*s.foo - - res = self.interpret(ll_function, [21, -21, 0], []) - assert res == 42 - self.check_insns(malloc_varsize=1, - getinteriorarraysize=1) - - res = self.interpret(ll_function, [21, -21, 1], []) - assert res == -42 - self.check_insns(malloc_varsize=1, - getinteriorarraysize=1) - - def test_array_of_voids(self): - A = lltype.GcArray(lltype.Void) - def ll_function(n): - a = lltype.malloc(A, 3) - a[1] = None - b = a[n] - res = a, b - keepalive_until_here(b) # to keep getarrayitem around - return res - - res = self.interpret(ll_function, [2], []) - assert len(res.item0) == 3 - def test_red_propagate(self): S = self.GcStruct('S', ('n', lltype.Signed)) malloc = self.malloc @@ -2137,6 +2050,38 @@ assert res == 5 self.check_insns({}) + def test_setarrayitem(self): + A = lltype.GcArray(lltype.Signed) + a = lltype.malloc(A, 2, immortal=True) + def ll_function(): + a[0] = 1 + a[1] = 2 + return a[0]+a[1] + + res = self.interpret(ll_function, [], []) + assert res == 3 + + def test_red_struct_array(self): + S = lltype.Struct('s', ('x', lltype.Signed)) + A = lltype.GcArray(S) + def ll_function(x, y, n): + a = lltype.malloc(A, 2) + a[0].x = x + a[1].x = y + return a[n].x*len(a) + + res = self.interpret(ll_function, [21, -21, 0], []) + assert res == 42 + self.check_insns({'malloc_varsize': 1, + 'setinteriorfield': 2, 'getinteriorfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + + res = self.interpret(ll_function, [21, -21, 1], []) + assert res == -42 + self.check_insns({'malloc_varsize': 1, + 'setinteriorfield': 2, 'getinteriorfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + def test_degenerated_before_return(self): S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) @@ -2214,6 +2159,59 @@ res = self.interpret(ll_function, [0], []) assert res == 4 * 4 + def test_red_array(self): + A = lltype.GcArray(lltype.Signed) + def ll_function(x, y, n): + a = lltype.malloc(A, 2) + a[0] = x + a[1] = y + return a[n]*len(a) + + res = self.interpret(ll_function, [21, -21, 0], []) + assert res == 42 + self.check_insns({'malloc_varsize': 1, + 'setarrayitem': 2, 'getarrayitem': 1, + 'getarraysize': 1, 'int_mul': 1}) + + res = self.interpret(ll_function, [21, -21, 1], []) + assert res == -42 + self.check_insns({'malloc_varsize': 1, + 'setarrayitem': 2, 'getarrayitem': 1, + 'getarraysize': 1, 'int_mul': 1}) + + def test_array_of_voids(self): + A = lltype.GcArray(lltype.Void) + def ll_function(n): + a = lltype.malloc(A, 3) + a[1] = None + b = a[n] + res = a, b + keepalive_until_here(b) # to keep getarrayitem around + return res + + res = self.interpret(ll_function, [2], []) + assert len(res.item0) == 3 + + def test_red_varsized_struct(self): + A = lltype.Array(lltype.Signed) + S = lltype.GcStruct('S', ('foo', lltype.Signed), ('a', A)) + def ll_function(x, y, n): + s = lltype.malloc(S, 3) + s.foo = len(s.a)-1 + s.a[0] = x + s.a[1] = y + return s.a[n]*s.foo + + res = self.interpret(ll_function, [21, -21, 0], []) + assert res == 42 + self.check_insns(malloc_varsize=1, + getinteriorarraysize=1) + + res = self.interpret(ll_function, [21, -21, 1], []) + assert res == -42 + self.check_insns(malloc_varsize=1, + getinteriorarraysize=1) + def test_red_subcontainer(self): S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) @@ -2352,6 +2350,49 @@ assert res == 5 self.check_insns({}) + def test_setarrayitem(self): + A = ootype.Array(lltype.Signed) + a = ootype.oonewarray(A, 2) + def ll_function(): + a.ll_setitem_fast(0, 1) + a.ll_setitem_fast(1, 2) + return a.ll_getitem_fast(0) + a.ll_getitem_fast(1) + + res = self.interpret(ll_function, [], []) + assert res == 3 + + def test_red_array(self): + A = ootype.Array(lltype.Signed) + def ll_function(x, y, n): + a = ootype.oonewarray(A, 2) + a.ll_setitem_fast(0, x) + a.ll_setitem_fast(1, y) + return a.ll_getitem_fast(n)*a.ll_length() + + res = self.interpret(ll_function, [21, -21, 0], []) + assert res == 42 + self.check_insns({'oonewarray': 1, + 'oosend': 4, 'int_mul': 1}) + + res = self.interpret(ll_function, [21, -21, 1], []) + assert res == -42 + self.check_insns({'oonewarray': 1, + 'oosend': 4, 'int_mul': 1}) + + def test_array_of_voids(self): + py.test.skip('XXX fixme') + A = ootype.Array(lltype.Void) + def ll_function(n): + a = ootype.oonewarray(A, 3) + a.ll_setitem_fast(1, None) + b = a.ll_setitem_fast(n) + res = a, b + keepalive_until_here(b) # to keep getarrayitem around + return res + + res = self.interpret(ll_function, [2], []) + assert len(res.item0) == 3 + def test_degenerated_before_return(self): S = ootype.Instance('S', ootype.ROOT, {'x': ootype.Signed}) T = ootype.Instance('T', S, {'y': ootype.Float}) @@ -2449,7 +2490,3 @@ def _skip(self): py.test.skip('in progress') - test_red_array = _skip - test_red_struct_array = _skip - test_red_varsized_struct = _skip - test_array_of_voids = _skip From pypy-svn at codespeak.net Tue Jun 17 21:07:28 2008 From: pypy-svn at codespeak.net (Jim Helton) Date: Tue, 17 Jun 2008 21:07:28 +0200 (CEST) Subject: [pypy-svn] Dear pypy-svn@codespeak.net Savings ...3 Days Only Message-ID: <20080617100534.14521.qmail@manz-590c3319.pool.einsundeins.de> An HTML attachment was scrubbed... URL: From arigo at codespeak.net Tue Jun 17 22:01:12 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 17 Jun 2008 22:01:12 +0200 (CEST) Subject: [pypy-svn] r55934 - pypy/dist/pypy/translator/tool Message-ID: <20080617200112.99E322A8090@codespeak.net> Author: arigo Date: Tue Jun 17 22:01:11 2008 New Revision: 55934 Modified: pypy/dist/pypy/translator/tool/pdbplus.py Log: Sanitize. Needed to make this work with http://codespeak.net/svn/user/antocuni/pdb.py. Modified: pypy/dist/pypy/translator/tool/pdbplus.py ============================================================================== --- pypy/dist/pypy/translator/tool/pdbplus.py (original) +++ pypy/dist/pypy/translator/tool/pdbplus.py Tue Jun 17 22:01:11 2008 @@ -1,4 +1,4 @@ -import pdb +import pdb, bdb import types import code import sys @@ -413,7 +413,7 @@ locals().update(self.exposed) fn(*args) pass # for debugger to land - except pdb.bdb.BdbQuit: + except bdb.BdbQuit: pass From fijal at codespeak.net Tue Jun 17 22:51:04 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 17 Jun 2008 22:51:04 +0200 (CEST) Subject: [pypy-svn] r55935 - pypy/dist/pypy/lib Message-ID: <20080617205104.A2ABD49801B@codespeak.net> Author: fijal Date: Tue Jun 17 22:51:02 2008 New Revision: 55935 Modified: pypy/dist/pypy/lib/pyexpat.py Log: Two simple getters and a function, exposed by Newov test suite/. Modified: pypy/dist/pypy/lib/pyexpat.py ============================================================================== --- pypy/dist/pypy/lib/pyexpat.py (original) +++ pypy/dist/pypy/lib/pyexpat.py Tue Jun 17 22:51:02 2008 @@ -61,6 +61,7 @@ declare_external('XML_StopParser', [XML_Parser, c_int], None) lib.XML_ErrorString.args = [c_int] lib.XML_ErrorString.result = c_int +declare_external('XML_SetBase', [XML_Parser, c_char_p], None) declare_external('XML_SetUnknownEncodingHandler', [XML_Parser, c_void_p, c_void_p], None) @@ -389,11 +390,18 @@ return self.buffer is not None elif name in currents: return getattr(lib, 'XML_Get' + name)(self.itself) + elif name == 'ErrorColumnNumber': + return lib.XML_GetCurrentColumnNumber(self.itself) + elif name == 'ErrorLineNumber': + return lib.XML_GetCurrentLineNumber(self.itself) return self.__dict__[name] def ParseFile(self, file): return self.Parse(file.read(), False) + def SetBase(self, base): + XML_SetBase(self.itself, base) + def ErrorString(errno): xxx From fijal at codespeak.net Wed Jun 18 00:05:13 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 18 Jun 2008 00:05:13 +0200 (CEST) Subject: [pypy-svn] r55937 - in pypy/dist/pypy/lib: . app_test Message-ID: <20080617220513.9AEE12A80CF@codespeak.net> Author: fijal Date: Wed Jun 18 00:05:12 2008 New Revision: 55937 Modified: pypy/dist/pypy/lib/app_test/test_pyexpat.py pypy/dist/pypy/lib/pyexpat.py Log: More tests for pyexpat (thanks therve). fix pyexpat.py to pass those. Modified: pypy/dist/pypy/lib/app_test/test_pyexpat.py ============================================================================== --- pypy/dist/pypy/lib/app_test/test_pyexpat.py (original) +++ pypy/dist/pypy/lib/app_test/test_pyexpat.py Wed Jun 18 00:05:12 2008 @@ -10,6 +10,7 @@ from test.test_support import sortdict, run_unittest + class TestSetAttribute: def setup_method(self, meth): self.parser = expat.ParserCreate(namespace_separator='!') @@ -42,6 +43,7 @@ + @@ -55,9 +57,11 @@ &external_entity; +&skipped_entity; ''' + # Produce UTF-8 output class TestParse: class Outputter: @@ -102,7 +106,7 @@ entityName, base, systemId, publicId, notationName = args self.out.append('Unparsed entity decl: %s' %(args,)) - def NotStandaloneHandler(self, userData): + def NotStandaloneHandler(self): self.out.append('Not standalone') return 1 @@ -111,6 +115,34 @@ self.out.append('External entity ref: %s' %(args[1:],)) return 1 + def StartDoctypeDeclHandler(self, *args): + self.out.append(('Start doctype', args)) + return 1 + + def EndDoctypeDeclHandler(self): + self.out.append("End doctype") + return 1 + + def EntityDeclHandler(self, *args): + self.out.append(('Entity declaration', args)) + return 1 + + def XmlDeclHandler(self, *args): + self.out.append(('XML declaration', args)) + return 1 + + def ElementDeclHandler(self, *args): + self.out.append(('Element declaration', args)) + return 1 + + def AttlistDeclHandler(self, *args): + self.out.append(('Attribute list declaration', args)) + return 1 + + def SkippedEntityHandler(self, *args): + self.out.append(("Skipped entity", args)) + return 1 + def DefaultHandler(self, userData): pass @@ -118,15 +150,15 @@ pass handler_names = [ - 'StartElementHandler', 'EndElementHandler', - 'CharacterDataHandler', 'ProcessingInstructionHandler', - 'UnparsedEntityDeclHandler', 'NotationDeclHandler', - 'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler', - 'CommentHandler', 'StartCdataSectionHandler', - 'EndCdataSectionHandler', - 'DefaultHandler', 'DefaultHandlerExpand', - #'NotStandaloneHandler', - 'ExternalEntityRefHandler' + 'StartElementHandler', 'EndElementHandler', 'CharacterDataHandler', + 'ProcessingInstructionHandler', 'UnparsedEntityDeclHandler', + 'NotationDeclHandler', 'StartNamespaceDeclHandler', + 'EndNamespaceDeclHandler', 'CommentHandler', + 'StartCdataSectionHandler', 'EndCdataSectionHandler', 'DefaultHandler', + 'DefaultHandlerExpand', 'NotStandaloneHandler', + 'ExternalEntityRefHandler', 'StartDoctypeDeclHandler', + 'EndDoctypeDeclHandler', 'EntityDeclHandler', 'XmlDeclHandler', + 'ElementDeclHandler', 'AttlistDeclHandler', 'SkippedEntityHandler', ] def test_utf8(self): @@ -139,24 +171,42 @@ parser.Parse(data, 1) # Verify output - op = out.out - assert op[0] == 'PI: \'xml-stylesheet\' \'href="stylesheet.css"\'' - assert op[1] == "Comment: ' comment data '" - assert op[2] == "Notation declared: ('notation', None, 'notation.jpeg', None)" - assert op[3] == "Unparsed entity decl: ('unparsed_entity', None, 'entity.file', None, 'notation')" - assert op[4] == "Start element: 'root' {'attr1': 'value1', 'attr2': 'value2\\xe1\\xbd\\x80'}" - assert op[5] == "NS decl: 'myns' 'http://www.python.org/namespace'" - assert op[6] == "Start element: 'http://www.python.org/namespace!subelement' {}" - assert op[7] == "Character data: 'Contents of subelements'" - assert op[8] == "End element: 'http://www.python.org/namespace!subelement'" - assert op[9] == "End of NS decl: 'myns'" - assert op[10] == "Start element: 'sub2' {}" - assert op[11] == 'Start of CDATA section' - assert op[12] == "Character data: 'contents of CDATA section'" - assert op[13] == 'End of CDATA section' - assert op[14] == "End element: 'sub2'" - assert op[15] == "External entity ref: (None, 'entity.file', None)" - assert op[16] == "End element: 'root'" + operations = out.out + expected_operations = [ + ('XML declaration', (u'1.0', u'iso-8859-1', 0)), + 'PI: \'xml-stylesheet\' \'href="stylesheet.css"\'', + "Comment: ' comment data '", + "Not standalone", + ("Start doctype", ('quotations', 'quotations.dtd', None, 1)), + ('Element declaration', (u'root', (2, 0, None, ()))), + ('Attribute list declaration', ('root', 'attr1', 'CDATA', None, + 1)), + ('Attribute list declaration', ('root', 'attr2', 'CDATA', None, + 0)), + "Notation declared: ('notation', None, 'notation.jpeg', None)", + ('Entity declaration', ('acirc', 0, '\xc3\xa2', None, None, None, None)), + ('Entity declaration', ('external_entity', 0, None, None, + 'entity.file', None, None)), + "Unparsed entity decl: ('unparsed_entity', None, 'entity.file', None, 'notation')", + "Not standalone", + "End doctype", + "Start element: 'root' {'attr1': 'value1', 'attr2': 'value2\\xe1\\xbd\\x80'}", + "NS decl: 'myns' 'http://www.python.org/namespace'", + "Start element: 'http://www.python.org/namespace!subelement' {}", + "Character data: 'Contents of subelements'", + "End element: 'http://www.python.org/namespace!subelement'", + "End of NS decl: 'myns'", + "Start element: 'sub2' {}", + 'Start of CDATA section', + "Character data: 'contents of CDATA section'", + 'End of CDATA section', + "End element: 'sub2'", + "External entity ref: (None, 'entity.file', None)", + ('Skipped entity', ('skipped_entity', 0)), + "End element: 'root'", + ] + for operation, expected_operation in zip(operations, expected_operations): + assert operation == expected_operation def test_unicode(self): # Try the parse again, this time producing Unicode output @@ -168,24 +218,43 @@ parser.Parse(data, 1) - op = out.out - assert op[0] == 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'' - assert op[1] == "Comment: u' comment data '" - assert op[2] == "Notation declared: (u'notation', None, u'notation.jpeg', None)" - assert op[3] == "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')" - assert op[4] == "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}" - assert op[5] == "NS decl: u'myns' u'http://www.python.org/namespace'" - assert op[6] == "Start element: u'http://www.python.org/namespace!subelement' {}" - assert op[7] == "Character data: u'Contents of subelements'" - assert op[8] == "End element: u'http://www.python.org/namespace!subelement'" - assert op[9] == "End of NS decl: u'myns'" - assert op[10] == "Start element: u'sub2' {}" - assert op[11] == 'Start of CDATA section' - assert op[12] == "Character data: u'contents of CDATA section'" - assert op[13] == 'End of CDATA section' - assert op[14] == "End element: u'sub2'" - assert op[15] == "External entity ref: (None, u'entity.file', None)" - assert op[16] == "End element: u'root'" + operations = out.out + expected_operations = [ + ('XML declaration', (u'1.0', u'iso-8859-1', 0)), + 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'', + "Comment: u' comment data '", + "Not standalone", + ("Start doctype", ('quotations', 'quotations.dtd', None, 1)), + ('Element declaration', (u'root', (2, 0, None, ()))), + ('Attribute list declaration', ('root', 'attr1', 'CDATA', None, + 1)), + ('Attribute list declaration', ('root', 'attr2', 'CDATA', None, + 0)), + "Notation declared: (u'notation', None, u'notation.jpeg', None)", + ('Entity declaration', (u'acirc', 0, u'\xe2', None, None, None, + None)), + ('Entity declaration', (u'external_entity', 0, None, None, + u'entity.file', None, None)), + "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')", + "Not standalone", + "End doctype", + "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}", + "NS decl: u'myns' u'http://www.python.org/namespace'", + "Start element: u'http://www.python.org/namespace!subelement' {}", + "Character data: u'Contents of subelements'", + "End element: u'http://www.python.org/namespace!subelement'", + "End of NS decl: u'myns'", + "Start element: u'sub2' {}", + 'Start of CDATA section', + "Character data: u'contents of CDATA section'", + 'End of CDATA section', + "End element: u'sub2'", + "External entity ref: (None, u'entity.file', None)", + ('Skipped entity', ('skipped_entity', 0)), + "End element: u'root'", + ] + for operation, expected_operation in zip(operations, expected_operations): + assert operation == expected_operation def test_parse_file(self): # Try parsing a file @@ -198,24 +267,41 @@ parser.ParseFile(file) - op = out.out - assert op[0] == 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'' - assert op[1] == "Comment: u' comment data '" - assert op[2] == "Notation declared: (u'notation', None, u'notation.jpeg', None)" - assert op[3] == "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')" - assert op[4] == "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}" - assert op[5] == "NS decl: u'myns' u'http://www.python.org/namespace'" - assert op[6] == "Start element: u'http://www.python.org/namespace!subelement' {}" - assert op[7] == "Character data: u'Contents of subelements'" - assert op[8] == "End element: u'http://www.python.org/namespace!subelement'" - assert op[9] == "End of NS decl: u'myns'" - assert op[10] == "Start element: u'sub2' {}" - assert op[11] == 'Start of CDATA section' - assert op[12] == "Character data: u'contents of CDATA section'" - assert op[13] == 'End of CDATA section' - assert op[14] == "End element: u'sub2'" - assert op[15] == "External entity ref: (None, u'entity.file', None)" - assert op[16] == "End element: u'root'" + operations = out.out + expected_operations = [ + ('XML declaration', (u'1.0', u'iso-8859-1', 0)), + 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'', + "Comment: u' comment data '", + "Not standalone", + ("Start doctype", ('quotations', 'quotations.dtd', None, 1)), + ('Element declaration', (u'root', (2, 0, None, ()))), + ('Attribute list declaration', ('root', 'attr1', 'CDATA', None, + 1)), + ('Attribute list declaration', ('root', 'attr2', 'CDATA', None, + 0)), + "Notation declared: (u'notation', None, u'notation.jpeg', None)", + ('Entity declaration', ('acirc', 0, u'\xe2', None, None, None, None)), + ('Entity declaration', (u'external_entity', 0, None, None, u'entity.file', None, None)), + "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')", + "Not standalone", + "End doctype", + "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}", + "NS decl: u'myns' u'http://www.python.org/namespace'", + "Start element: u'http://www.python.org/namespace!subelement' {}", + "Character data: u'Contents of subelements'", + "End element: u'http://www.python.org/namespace!subelement'", + "End of NS decl: u'myns'", + "Start element: u'sub2' {}", + 'Start of CDATA section', + "Character data: u'contents of CDATA section'", + 'End of CDATA section', + "End element: u'sub2'", + "External entity ref: (None, u'entity.file', None)", + ('Skipped entity', ('skipped_entity', 0)), + "End element: u'root'", + ] + for operation, expected_operation in zip(operations, expected_operations): + assert operation == expected_operation class TestNamespaceSeparator: @@ -312,7 +398,8 @@ # Make sure buffering is turned on assert self.parser.buffer_text self.parser.Parse("123", 1) - assert self.stuff == ['123'] + assert self.stuff == ['123'], ( + "buffered text not properly collapsed") def test1(self): # XXX This test exposes more detail of Expat's text chunking than we @@ -401,7 +488,7 @@ 'Expected position %s, got position %s' %(pos, expected)) self.upto += 1 - def test_x(self): + def test(self): self.parser = expat.ParserCreate() self.parser.StartElementHandler = self.StartElementHandler self.parser.EndElementHandler = self.EndElementHandler @@ -415,11 +502,6 @@ class Testsf1296433: def test_parse_only_xml_data(self): - try: - import __pypy__ - except ImportError: - import py - py.test.skip("segfaults cpython") # http://python.org/sf/1296433 # xml = "%s" % ('a' * 1025) @@ -441,13 +523,6 @@ """ test setting of chardata buffer size """ - def setup_class(cls): - import py - try: - import __pypy__ - except ImportError: - pass - #py.test.skip("Doesn't work on cpy 2.5") def test_1025_bytes(self): assert self.small_buffer_test(1025) == 2 Modified: pypy/dist/pypy/lib/pyexpat.py ============================================================================== --- pypy/dist/pypy/lib/pyexpat.py (original) +++ pypy/dist/pypy/lib/pyexpat.py Wed Jun 18 00:05:12 2008 @@ -27,6 +27,13 @@ ('convert', c_void_p), ('release', c_void_p), ('map', c_int * 256)]) + XML_Content = configure.Struct('XML_Content',[ + ('numchildren', c_int), + ('children', c_void_p), + ('name', c_char_p), + ('type', c_int), + ('quant', c_int), + ]) # this is insanely stupid XML_FALSE = configure.ConstantInteger('XML_FALSE') XML_TRUE = configure.ConstantInteger('XML_TRUE') @@ -34,6 +41,8 @@ info = configure.configure(CConfigure) for k, v in info.items(): globals()[k] = v + +XML_Content.children = POINTER(XML_Content) XML_Parser = ctypes.c_void_p # an opaque pointer assert XML_Char is ctypes.c_char # this assumption is everywhere in # cpython's expat, let's explode @@ -65,6 +74,8 @@ declare_external('XML_SetUnknownEncodingHandler', [XML_Parser, c_void_p, c_void_p], None) +declare_external('XML_FreeContentModel', [XML_Parser, POINTER(XML_Content)], + None) def XML_ErrorString(code): res = lib.XML_ErrorString(code) @@ -262,11 +273,21 @@ CB = ctypes.CFUNCTYPE(None, c_void_p, POINTER(c_char), c_int) return CB(CharacterData) + def get_cb_for_NotStandaloneHandler(self, real_cb): + def NotStandaloneHandler(unused): + return real_cb() + NotStandaloneHandler = self._wrap_cb(NotStandaloneHandler) + CB = ctypes.CFUNCTYPE(c_int, c_void_p) + return CB(NotStandaloneHandler) + def get_cb_for_EntityDeclHandler(self, real_cb): - def EntityDecl(unused, ename, is_param, value, _, base, system_id, - pub_id, not_name): - + def EntityDecl(unused, ename, is_param, value, value_len, base, + system_id, pub_id, not_name): self._flush_character_buffer() + if not value: + value = None + else: + value = value[:value_len] args = [ename, is_param, value, base, system_id, pub_id, not_name] args = [self.conv(arg) for arg in args] @@ -276,12 +297,21 @@ c_int, c_char_p, c_char_p, c_char_p, c_char_p) return CB(EntityDecl) + def _conv_content_model(self, model): + children = tuple([self._conv_content_model(model.children[i]) + for i in range(model.numchildren)]) + return (model.type, model.quant, self.conv(model.name), + children) + def get_cb_for_ElementDeclHandler(self, real_cb): - # XXX this is broken, needs tests - def ElementDecl(unused, *args): - print "WARNING! ElementDeclHandler Not supported" + def ElementDecl(unused, name, model): + self._flush_character_buffer() + modelobj = self._conv_content_model(model[0]) + real_cb(name, modelobj) + XML_FreeContentModel(self.itself, model) + ElementDecl = self._wrap_cb(ElementDecl) - CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, c_void_p) + CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, POINTER(XML_Content)) return CB(ElementDecl) def _new_callback_for_string_len(name, sign): @@ -342,7 +372,7 @@ def conv_unicode(self, s): if s is None or isinstance(s, int): return s - return s.decode(self.encoding) + return s.decode(self.encoding, "strict") def __setattr__(self, name, value): # forest of ifs... From fijal at codespeak.net Wed Jun 18 01:11:03 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 18 Jun 2008 01:11:03 +0200 (CEST) Subject: [pypy-svn] r55938 - pypy/dist/pypy/objspace/std Message-ID: <20080617231103.1175E39B5CC@codespeak.net> Author: fijal Date: Wed Jun 18 01:11:01 2008 New Revision: 55938 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: Remove pdb Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Wed Jun 18 01:11:01 2008 @@ -942,7 +942,6 @@ return decode_object(space, w_string, encoding, errors) def str_encode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): - #import pdb; pdb.set_trace() from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ encode_object encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) From fijal at codespeak.net Wed Jun 18 02:11:28 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 18 Jun 2008 02:11:28 +0200 (CEST) Subject: [pypy-svn] r55939 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20080618001128.E7D5E16A0AB@codespeak.net> Author: fijal Date: Wed Jun 18 02:11:25 2008 New Revision: 55939 Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py pypy/dist/pypy/objspace/std/unicodeobject.py pypy/dist/pypy/objspace/std/unicodetype.py Log: unicode.decode method Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stringobject.py Wed Jun 18 02:11:25 2008 @@ -645,6 +645,7 @@ def test_decode(self): assert 'hello'.decode('rot-13') == 'uryyb' assert 'hello'.decode('string-escape') == 'hello' + assert u'hello'.decode('rot-13') == 'uryyb' def test_encode(self): assert 'hello'.encode() == 'hello' Modified: pypy/dist/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/unicodeobject.py (original) +++ pypy/dist/pypy/objspace/std/unicodeobject.py Wed Jun 18 02:11:25 2008 @@ -773,6 +773,14 @@ w_retval = encode_object(space, w_unistr, encoding, errors) return w_retval +def unicode_decode__Unicode_ANY_ANY(space, w_unicode, w_encoding=None, w_errors=None): + from pypy.objspace.std.unicodetype import _get_encoding_and_errors,\ + decode_object + encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) + if encoding is None and errors is None: + return unicode_from_string(space, w_string) + return decode_object(space, w_unicode, encoding, errors) + def unicode_partition__Unicode_Unicode(space, w_unistr, w_unisub): unistr = w_unistr._value unisub = w_unisub._value Modified: pypy/dist/pypy/objspace/std/unicodetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/unicodetype.py (original) +++ pypy/dist/pypy/objspace/std/unicodetype.py Wed Jun 18 02:11:25 2008 @@ -147,6 +147,7 @@ from pypy.objspace.std.stringtype import str_strip as unicode_strip from pypy.objspace.std.stringtype import str_rstrip as unicode_rstrip from pypy.objspace.std.stringtype import str_lstrip as unicode_lstrip +from pypy.objspace.std.stringtype import str_decode as unicode_decode # ____________________________________________________________ From fijal at codespeak.net Wed Jun 18 02:23:05 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 18 Jun 2008 02:23:05 +0200 (CEST) Subject: [pypy-svn] r55940 - pypy/dist/pypy/objspace/std Message-ID: <20080618002305.78FCE16A107@codespeak.net> Author: fijal Date: Wed Jun 18 02:23:04 2008 New Revision: 55940 Modified: pypy/dist/pypy/objspace/std/unicodeobject.py Log: A test and a fix Modified: pypy/dist/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/unicodeobject.py (original) +++ pypy/dist/pypy/objspace/std/unicodeobject.py Wed Jun 18 02:23:04 2008 @@ -775,10 +775,10 @@ def unicode_decode__Unicode_ANY_ANY(space, w_unicode, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodetype import _get_encoding_and_errors,\ - decode_object + decode_object, unicode_from_string encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) if encoding is None and errors is None: - return unicode_from_string(space, w_string) + return unicode_from_string(space, w_unicode) return decode_object(space, w_unicode, encoding, errors) def unicode_partition__Unicode_Unicode(space, w_unistr, w_unisub): From bgola at codespeak.net Wed Jun 18 16:25:43 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Wed, 18 Jun 2008 16:25:43 +0200 (CEST) Subject: [pypy-svn] r55947 - pypy/branch/2.5-features/pypy/config Message-ID: <20080618142543.EE477398005@codespeak.net> Author: bgola Date: Wed Jun 18 16:25:43 2008 New Revision: 55947 Modified: pypy/branch/2.5-features/pypy/config/pypyoption.py Log: Grammar2.5 as default option Modified: pypy/branch/2.5-features/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/2.5-features/pypy/config/pypyoption.py (original) +++ pypy/branch/2.5-features/pypy/config/pypyoption.py Wed Jun 18 16:25:43 2008 @@ -87,7 +87,7 @@ cmdline='--compiler'), ChoiceOption("pyversion", "which grammar to use for app-level code", - ["2.3", "2.4", "2.5a", "2.5"], "2.4", + ["2.3", "2.4", "2.5"], "2.5", cmdline='--pyversion'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ From bgola at codespeak.net Wed Jun 18 22:09:58 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Wed, 18 Jun 2008 22:09:58 +0200 (CEST) Subject: [pypy-svn] r55951 - in pypy/branch/2.5-features/pypy: bin lib module/__builtin__ module/__builtin__/test Message-ID: <20080618200958.2A1812A01A6@codespeak.net> Author: bgola Date: Wed Jun 18 22:09:56 2008 New Revision: 55951 Modified: pypy/branch/2.5-features/pypy/bin/py.py pypy/branch/2.5-features/pypy/lib/_exceptions.py pypy/branch/2.5-features/pypy/module/__builtin__/importing.py pypy/branch/2.5-features/pypy/module/__builtin__/test/test_import.py Log: ImportWarning and -W command-line option. There are bugs in the parser (i think) that I need to fix because when using Grammar2.5 it raises SyntaxError where it shouldn't... Modified: pypy/branch/2.5-features/pypy/bin/py.py ============================================================================== --- pypy/branch/2.5-features/pypy/bin/py.py (original) +++ pypy/branch/2.5-features/pypy/bin/py.py Wed Jun 18 22:09:56 2008 @@ -37,6 +37,10 @@ StrOption("runcommand", "program passed in as CMD (terminates option list)", default=None, cmdline="-c"), + StrOption("warn", + "warning control (arg is action:message:category:module:lineno)", + default=None, cmdline="-W"), + ]) pypy_init = gateway.applevel(''' @@ -76,6 +80,13 @@ space.setitem(space.sys.w_dict, space.wrap('executable'), space.wrap(argv[0])) + # set warning control options (if any) + warn_arg = interactiveconfig.warn + if warn_arg is not None: + space.appexec([space.wrap(warn_arg)], """(arg): + import sys + sys.warnoptions.append(arg)""") + # store the command-line arguments into sys.argv go_interactive = interactiveconfig.interactive banner = '' Modified: pypy/branch/2.5-features/pypy/lib/_exceptions.py ============================================================================== --- pypy/branch/2.5-features/pypy/lib/_exceptions.py (original) +++ pypy/branch/2.5-features/pypy/lib/_exceptions.py Wed Jun 18 22:09:56 2008 @@ -85,7 +85,8 @@ +-- OverflowWarning +-- RuntimeWarning +-- FutureWarning - +-- UnicodeWarning""" + +-- UnicodeWarning + +-- ImportWarning""" class Exception: """Common base class for all exceptions.""" @@ -388,6 +389,9 @@ """Base class for warnings about Unicode related problems, mostly related to conversion problems.""" +class ImportWarning(Warning): + """Base class for warnings about probable mistakes in module imports""" + class MemoryError(StandardError): """Out of memory.""" Modified: pypy/branch/2.5-features/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/branch/2.5-features/pypy/module/__builtin__/importing.py (original) +++ pypy/branch/2.5-features/pypy/module/__builtin__/importing.py Wed Jun 18 22:09:56 2008 @@ -285,6 +285,10 @@ pkgdir=dir) if w_mod is not None: return w_mod + else: + msg = "Not importing directory " +\ + "'%s' missing __init__.py" % dir + space.warn(msg, space.w_ImportWarning) fn = os.path.join(space.str_w(path), partname) w_mod = try_import_mod(space, w_modulename, fn, w_parent, w(partname)) Modified: pypy/branch/2.5-features/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/branch/2.5-features/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/branch/2.5-features/pypy/module/__builtin__/test/test_import.py Wed Jun 18 22:09:56 2008 @@ -112,6 +112,18 @@ import notapackage raises(ImportError, imp) + def test_import_bare_dir_warns(self): + def imp(): + import notapackage + + import warnings + + warnings.simplefilter('error', ImportWarning) + try: + raises(ImportWarning, imp) + finally: + warnings.simplefilter('default', RuntimeWarning) + def test_import_sys(self): import sys From bgola at codespeak.net Wed Jun 18 23:24:52 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Wed, 18 Jun 2008 23:24:52 +0200 (CEST) Subject: [pypy-svn] r55952 - pypy/branch/2.5-features/pypy/config Message-ID: <20080618212452.BAD2D2A018A@codespeak.net> Author: bgola Date: Wed Jun 18 23:24:52 2008 New Revision: 55952 Modified: pypy/branch/2.5-features/pypy/config/pypyoption.py Log: changing back the default value of pyversion to 2.4 until the parser is fixed Modified: pypy/branch/2.5-features/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/2.5-features/pypy/config/pypyoption.py (original) +++ pypy/branch/2.5-features/pypy/config/pypyoption.py Wed Jun 18 23:24:52 2008 @@ -87,7 +87,7 @@ cmdline='--compiler'), ChoiceOption("pyversion", "which grammar to use for app-level code", - ["2.3", "2.4", "2.5"], "2.5", + ["2.3", "2.4", "2.5"], "2.4", cmdline='--pyversion'), OptionDescription("opcodes", "opcodes to enable in the interpreter", [ From arigo at codespeak.net Thu Jun 19 11:13:54 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 19 Jun 2008 11:13:54 +0200 (CEST) Subject: [pypy-svn] r55955 - in pypy/dist/pypy/tool/algo: . test Message-ID: <20080619091354.7430A169E19@codespeak.net> Author: arigo Date: Thu Jun 19 11:13:51 2008 New Revision: 55955 Modified: pypy/dist/pypy/tool/algo/graphlib.py pypy/dist/pypy/tool/algo/test/test_graphlib.py Log: The cycle breaking algorithm is broken: it doesn't break all cycles. To show this I added "assert is_acyclic()" at the end of break_cycles(). A simple fix, namely "repeat break_cycles() until is_acyclic()", requires more than 7 minutes to compute on the pypy call graph again. So this check-in contains an experimental tweak that reduces the run time to about 1 minute. I am quite unsure about the quality of the result but I am roughly guessing that it is similar to the 7-minutes-running version. Modified: pypy/dist/pypy/tool/algo/graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/graphlib.py (original) +++ pypy/dist/pypy/tool/algo/graphlib.py Thu Jun 19 11:13:51 2008 @@ -36,6 +36,11 @@ visit(root) return result +def vertices_reachable_from(root, vertices, edges): + for event, v in depth_first_search(root, vertices, edges): + if event == 'start': + yield v + def strong_components(vertices, edges): """Enumerates the strongly connected components of a graph. Each one is a set of vertices where any vertex can be reached from any other vertex by @@ -78,7 +83,9 @@ component_root[v] = vroot def all_cycles(root, vertices, edges): - """Enumerates cycles. Each cycle is a list of edges.""" + """Enumerates cycles. Each cycle is a list of edges. + This may not give stricly all cycles if they are many intermixed cycles. + """ stackpos = {} edgestack = [] result = [] @@ -97,45 +104,122 @@ visit(root) return result + +def find_roots(vertices, edges): + """Find roots, i.e. a minimal set of vertices such that all other + vertices are reachable from them.""" + + roots = set() + notseen = set(vertices) # set of vertices that are not reachable yet + # from any vertex in 'roots' + def addroot(root): + roots.add(root) + if root in notseen: + notseen.remove(root) + for v in vertices_reachable_from(root, notseen.union(roots), edges): + if v is not root: + if v in roots: + roots.remove(v) # this older root is no longer needed + else: + notseen.remove(v) + + while notseen: + addroot(notseen.pop()) + return roots + + +def is_acyclic(vertices, edges): + class CycleFound(Exception): + pass + def visit(vertex): + visiting[vertex] = True + for edge in edges[vertex]: + w = edge.target + if w in visiting: + raise CycleFound + if w in unvisited: + del unvisited[w] + visit(w) + del visiting[vertex] + try: + unvisited = vertices.copy() + while unvisited: + visiting = {} + root = unvisited.popitem()[0] + visit(root) + except CycleFound: + return False + else: + return True + + def break_cycles(vertices, edges): """Enumerates a reasonably minimal set of edges that must be removed to make the graph acyclic.""" - # the approach is as follows: for each strongly connected component, find - # all cycles (which takens exponential time, potentially). Then break the - # edges that are part of the most cycles, until all cycles in that - # component are broken. - for component in strong_components(vertices, edges): - #print '-->', ''.join(component) - random_vertex = component.iterkeys().next() - cycles = all_cycles(random_vertex, component, edges) - if not cycles: - continue - allcycles = dict.fromkeys([id(cycle) for cycle in cycles]) - edge2cycles = {} - edge_weights = {} - for cycle in cycles: - #print '\tcycle:', [e.source+e.target for e in cycle] - for edge in cycle: - edge2cycles.setdefault(edge, []).append(cycle) - edge_weights[edge] = edge_weights.get(edge, 0) + 1 - while allcycles: - max_weight = 0 - max_edge = None - for edge, weight in edge_weights.iteritems(): - if weight >= max_weight: - max_edge = edge - max_weight = weight - broken_cycles = edge2cycles[max_edge] - assert max_edge is not None - # kill this edge - yield max_edge - for broken_cycle in broken_cycles: - try: - del allcycles[id(broken_cycle)] - except KeyError: - pass - else: + + # the approach is as follows: starting from each root, find some set + # of cycles using a simple depth-first search. Then break the + # edge that is part of the most cycles. Repeat. + + remaining_edges = edges.copy() + progress = True + roots_finished = set() + while progress: + roots = list(find_roots(vertices, remaining_edges)) + #print '%d inital roots' % (len(roots,)) + progress = False + for root in roots: + if root in roots_finished: + continue + cycles = all_cycles(root, vertices, remaining_edges) + if not cycles: + roots_finished.add(root) + continue + #print 'from root %r: %d cycles' % (root, len(cycles)) + allcycles = {} + edge2cycles = {} + for cycle in cycles: + allcycles[id(cycle)] = cycle + for edge in cycle: + edge2cycles.setdefault(edge, []).append(id(cycle)) + edge_weights = {} + for edge, cycle in edge2cycles.iteritems(): + edge_weights[edge] = len(cycle) + while allcycles: + max_weight = 0 + max_edge = None + for edge, weight in edge_weights.iteritems(): + if weight > max_weight: + max_edge = edge + max_weight = weight + if max_edge is None: + break + # kill this edge + yield max_edge + progress = True + # unregister all cycles that have just been broken + for broken_cycle_id in edge2cycles[max_edge]: + broken_cycle = allcycles.pop(broken_cycle_id, ()) for edge in broken_cycle: edge_weights[edge] -= 1 - if edge_weights[edge] == 0: - del edge_weights[edge] + + lst = remaining_edges[max_edge.source][:] + lst.remove(max_edge) + remaining_edges[max_edge.source] = lst + assert is_acyclic(vertices, remaining_edges) + + +def show_graph(vertices, edges): + from pypy.translator.tool.graphpage import GraphPage, DotGen + class MathGraphPage(GraphPage): + def compute(self): + dotgen = DotGen('mathgraph') + names = {} + for i, v in enumerate(vertices): + names[v] = 'node%d' % i + for i, v in enumerate(vertices): + dotgen.emit_node(names[v], label=str(v)) + for edge in edges[v]: + dotgen.emit_edge(names[edge.source], names[edge.target]) + self.source = dotgen.generate(target=None) + MathGraphPage().display() Modified: pypy/dist/pypy/tool/algo/test/test_graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/test/test_graphlib.py (original) +++ pypy/dist/pypy/tool/algo/test/test_graphlib.py Thu Jun 19 11:13:51 2008 @@ -57,6 +57,11 @@ edges['B'][1] in result or edges['E'][0] in result) + def test_find_roots(self): + roots = list(find_roots(self.edges, self.edges)) + roots.sort() + assert ''.join(roots) in ('AG', 'BG', 'EG') + class TestLoops: # a graph with 20 loops of length 10 each, plus an edge from each loop to @@ -96,6 +101,12 @@ edges[190].append(Edge(190, 5)) self.test_break_cycles(edges) + def test_find_roots(self): + roots = find_roots(self.vertices, self.edges) + assert len(roots) == 1 + v = list(roots)[0] + assert v in range(10) + class TestTree: edges = make_edge_dict([Edge(i//2, i) for i in range(1, 52)]) @@ -118,6 +129,12 @@ result = list(break_cycles(self.edges, self.edges)) assert not result + def test_find_roots(self): + roots = find_roots(self.edges, self.edges) + assert len(roots) == 1 + v = list(roots)[0] + assert v == 0 + class TestChainAndLoop: edges = make_edge_dict([Edge(i,i+1) for i in range(100)] + [Edge(100,99)]) @@ -153,8 +170,14 @@ def test_break_cycles(self): result = list(break_cycles(self.edges, self.edges)) + print len(result) assert result + def test_find_roots(self): + roots = find_roots(self.edges, self.edges) + assert len(roots) == 1 + assert list(roots)[0] in self.edges + class TestRandom: edges = make_edge_dict([Edge(random.randrange(0,100), From antocuni at codespeak.net Thu Jun 19 14:04:24 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 19 Jun 2008 14:04:24 +0200 (CEST) Subject: [pypy-svn] r55958 - in pypy/branch/oo-jit/pypy: jit/rainbow/test objspace/flow Message-ID: <20080619120424.54B75398005@codespeak.net> Author: antocuni Date: Thu Jun 19 14:04:23 2008 New Revision: 55958 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py pypy/branch/oo-jit/pypy/objspace/flow/model.py Log: allow ootype values to be used in multiple-cases exitswitches. This makes all the portal tests to pass Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_portal.py Thu Jun 19 14:04:23 2008 @@ -630,13 +630,6 @@ def check_method_calls(self, n): self.check_insns(oosend=n) - def _skip(self): - py.test.skip('in progress') - - test_method_call_promote = _skip - test_float_promote = _skip - test_virt_obj_method_call_promote = _skip - class TestPortalLLType(BaseTestPortal): type_system = 'lltype' Modified: pypy/branch/oo-jit/pypy/objspace/flow/model.py ============================================================================== --- pypy/branch/oo-jit/pypy/objspace/flow/model.py (original) +++ pypy/branch/oo-jit/pypy/objspace/flow/model.py Thu Jun 19 14:04:23 2008 @@ -5,6 +5,7 @@ # a discussion in Berlin, 4th of october 2003 from __future__ import generators import py +from pypy.rpython.ootypesystem import ootype from pypy.tool.uid import uid, Hashable from pypy.tool.descriptor import roproperty from pypy.tool.sourcetools import PY_IDENTIFIER, nice_repr_for_func @@ -561,6 +562,8 @@ continue if isinstance(n, (str, unicode)) and len(n) == 1: continue + if isinstance(ootype.typeOf(n), ootype.OOType): + continue assert n != 'default', ( "'default' branch of a switch is not the last exit" ) From antocuni at codespeak.net Thu Jun 19 14:06:59 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 19 Jun 2008 14:06:59 +0200 (CEST) Subject: [pypy-svn] r55959 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080619120659.75FA6398005@codespeak.net> Author: antocuni Date: Thu Jun 19 14:06:58 2008 New Revision: 55959 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Log: no more tests to skip :-) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Thu Jun 19 14:06:58 2008 @@ -2486,7 +2486,3 @@ assert res == 42 self.check_insns({'int_lt': 1, 'int_mul': 1, 'int_sub': 1}) - - def _skip(self): - py.test.skip('in progress') - From arigo at codespeak.net Thu Jun 19 14:23:28 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 19 Jun 2008 14:23:28 +0200 (CEST) Subject: [pypy-svn] r55961 - in pypy/dist/pypy: tool/algo tool/algo/test translator Message-ID: <20080619122328.58AE149801A@codespeak.net> Author: arigo Date: Thu Jun 19 14:23:27 2008 New Revision: 55961 Modified: pypy/dist/pypy/tool/algo/graphlib.py pypy/dist/pypy/tool/algo/test/test_graphlib.py pypy/dist/pypy/translator/transform.py Log: Improve the results of the stack check insertion algo. This is done by using essentially the same algo, but detecting vertices instead of edges to remove. The vertices in this case are the blocks that contain the calls. Another improvement (which also should make results a bit more deterministic) is a bias that prefers picking vertices that are "as far as possible" from the root vertices. Modified: pypy/dist/pypy/tool/algo/graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/graphlib.py (original) +++ pypy/dist/pypy/tool/algo/graphlib.py Thu Jun 19 14:23:27 2008 @@ -71,11 +71,11 @@ if discovery_time[wroot] < discovery_time[vroot]: vroot = wroot if vroot == v: - component = {} + component = set() while True: w = stack.pop() del component_root[w] - component[w] = True + component.add(w) if w == v: break yield component @@ -109,25 +109,48 @@ """Find roots, i.e. a minimal set of vertices such that all other vertices are reachable from them.""" - roots = set() - notseen = set(vertices) # set of vertices that are not reachable yet - # from any vertex in 'roots' - def addroot(root): - roots.add(root) - if root in notseen: - notseen.remove(root) - for v in vertices_reachable_from(root, notseen.union(roots), edges): - if v is not root: - if v in roots: - roots.remove(v) # this older root is no longer needed - else: - notseen.remove(v) + rep = {} # maps all vertices to a random representing vertex + # from the same strongly connected component + for component in strong_components(vertices, edges): + random_vertex = component.pop() + rep[random_vertex] = random_vertex + for v in component: + rep[v] = random_vertex + + roots = set(rep.values()) + for v in vertices: + v1 = rep[v] + for edge in edges[v]: + try: + v2 = rep[edge.target] + if v1 is not v2: # cross-component edge: no root is needed + roots.remove(v2) # in the target component + except KeyError: + pass - while notseen: - addroot(notseen.pop()) return roots +def compute_depths(roots, vertices, edges): + """The 'depth' of a vertex is its minimal distance from any root.""" + depths = {} + curdepth = 0 + for v in roots: + depths[v] = 0 + pending = list(roots) + while pending: + curdepth += 1 + prev_generation = pending + pending = [] + for v in prev_generation: + for edge in edges[v]: + v2 = edge.target + if v2 in vertices and v2 not in depths: + depths[v2] = curdepth + pending.append(v2) + return depths + + def is_acyclic(vertices, edges): class CycleFound(Exception): pass @@ -209,6 +232,70 @@ assert is_acyclic(vertices, remaining_edges) +def break_cycles_v(vertices, edges): + """Enumerates a reasonably minimal set of vertices that must be removed to + make the graph acyclic.""" + + # the approach is as follows: starting from each root, find some set + # of cycles using a simple depth-first search. Then break the + # vertex that is part of the most cycles. Repeat. + + remaining_vertices = vertices.copy() + progress = True + roots_finished = set() + v_depths = None + while progress: + roots = list(find_roots(remaining_vertices, edges)) + if v_depths is None: + #print roots + v_depths = compute_depths(roots, remaining_vertices, edges) + assert len(v_depths) == len(remaining_vertices) + #print v_depths + factor = 1.0 / len(v_depths) + #print '%d inital roots' % (len(roots,)) + progress = False + for root in roots: + if root in roots_finished: + continue + cycles = all_cycles(root, remaining_vertices, edges) + if not cycles: + roots_finished.add(root) + continue + #print 'from root %r: %d cycles' % (root, len(cycles)) + allcycles = {} + v2cycles = {} + for cycle in cycles: + allcycles[id(cycle)] = cycle + for edge in cycle: + v2cycles.setdefault(edge.source, []).append(id(cycle)) + v_weights = {} + for v, cycles in v2cycles.iteritems(): + v_weights[v] = len(cycles) + v_depths.get(v, 0) * factor + # The weight of a vertex is the number of cycles going + # through it, plus a small value used as a bias in case of + # a tie. The bias is in favor of vertices of large depth. + while allcycles: + max_weight = 1 + max_vertex = None + for v, weight in v_weights.iteritems(): + if weight >= max_weight: + max_vertex = v + max_weight = weight + if max_vertex is None: + break + # kill this vertex + yield max_vertex + progress = True + # unregister all cycles that have just been broken + for broken_cycle_id in v2cycles[max_vertex]: + broken_cycle = allcycles.pop(broken_cycle_id, ()) + for edge in broken_cycle: + v_weights[edge.source] -= 1 + + del remaining_vertices[max_vertex] + assert is_acyclic(remaining_vertices, edges) + + def show_graph(vertices, edges): from pypy.translator.tool.graphpage import GraphPage, DotGen class MathGraphPage(GraphPage): Modified: pypy/dist/pypy/tool/algo/test/test_graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/test/test_graphlib.py (original) +++ pypy/dist/pypy/tool/algo/test/test_graphlib.py Thu Jun 19 14:23:27 2008 @@ -57,11 +57,30 @@ edges['B'][1] in result or edges['E'][0] in result) + def test_break_cycles_v(self): + edges = copy_edges(self.edges) + edges['R'] = [Edge('R', 'B')] + saved = copy_edges(edges) + result = list(break_cycles_v(edges, edges)) + assert edges == saved + assert len(result) == 2 + result.sort() + assert ''.join(result) == 'AD' + # the answers 'BD' and 'DE' are correct too, but 'AD' should + # be picked because 'A' is the node cycle that is the further + # from the root 'R'. + def test_find_roots(self): roots = list(find_roots(self.edges, self.edges)) roots.sort() assert ''.join(roots) in ('AG', 'BG', 'EG') + edges = copy_edges(self.edges) + edges['R'] = [Edge('R', 'B')] + roots = list(find_roots(edges, edges)) + roots.sort() + assert ''.join(roots) == 'GR' + class TestLoops: # a graph with 20 loops of length 10 each, plus an edge from each loop to @@ -80,10 +99,14 @@ edges = self.edges result = list(strong_components(self.vertices, edges)) assert len(result) == 20 - result.sort() - for i in range(20): - comp = list(result[i]) + result2 = [] + for comp in result: + comp = list(comp) comp.sort() + result2.append(comp) + result2.sort() + for i in range(20): + comp = result2[i] assert comp == range(i*10, (i+1)*10) def test_break_cycles(self, edges=None): @@ -107,6 +130,12 @@ v = list(roots)[0] assert v in range(10) + def test_find_roots_2(self): + edges = copy_edges(self.edges) + edges[190].append(Edge(190, 5)) + roots = find_roots(self.vertices, edges) + assert len(roots) == 1 + class TestTree: edges = make_edge_dict([Edge(i//2, i) for i in range(1, 52)]) @@ -192,3 +221,19 @@ expected = self.edges.keys() expected.sort() assert vertices == expected + + def test_break_cycles(self): + list(break_cycles(self.edges, self.edges)) + # assert is_acyclic(): included in break_cycles() itself + + def test_break_cycles_v(self): + list(break_cycles_v(self.edges, self.edges)) + # assert is_acyclic(): included in break_cycles_v() itself + + def test_find_roots(self): + roots = find_roots(self.edges, self.edges) + reachable = set() + for root in roots: + reachable |= set(vertices_reachable_from(root, self.edges, + self.edges)) + assert reachable == set(self.edges) Modified: pypy/dist/pypy/translator/transform.py ============================================================================== --- pypy/dist/pypy/translator/transform.py (original) +++ pypy/dist/pypy/translator/transform.py Thu Jun 19 14:23:27 2008 @@ -240,30 +240,29 @@ def insert_ll_stackcheck(translator): from pypy.translator.backendopt.support import find_calls_from from pypy.rlib.rstack import stack_check - from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles + from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles_v rtyper = translator.rtyper graph = rtyper.annotate_helper(stack_check, []) rtyper.specialize_more_blocks() stack_check_ptr = rtyper.getcallable(graph) stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr)) - edges = [] - graphs_to_patch = {} - insert_in = {} + edges = set() + insert_in = set() for caller in translator.graphs: for block, callee in find_calls_from(translator, caller): if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): - insert_in[callee.startblock] = True + insert_in.add(callee.startblock) continue - edge = Edge(caller, callee) - edge.block = block - edges.append(edge) + if block is not caller.startblock: + edges.add((caller.startblock, block)) + edges.add((block, callee.startblock)) + + edgelist = [Edge(block1, block2) for (block1, block2) in edges] + edgedict = make_edge_dict(edgelist) + for block in break_cycles_v(edgedict, edgedict): + insert_in.add(block) - edgedict = make_edge_dict(edges) - for edge in break_cycles(edgedict, edgedict): - block = edge.block - insert_in[block] = True - for block in insert_in: v = Variable() v.concretetype = lltype.Void From pedronis at codespeak.net Thu Jun 19 15:23:48 2008 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 19 Jun 2008 15:23:48 +0200 (CEST) Subject: [pypy-svn] r55962 - pypy/pysqlite2 Message-ID: <20080619132348.5C25D2D8001@codespeak.net> Author: pedronis Date: Thu Jun 19 15:23:45 2008 New Revision: 55962 Modified: pypy/pysqlite2/dbapi2.py Log: XXX about something we may want/need to do (based on looking at the C version) Modified: pypy/pysqlite2/dbapi2.py ============================================================================== --- pypy/pysqlite2/dbapi2.py (original) +++ pypy/pysqlite2/dbapi2.py Thu Jun 19 15:23:45 2008 @@ -599,6 +599,7 @@ def close(self): self.connection._check_thread() self.connection._check_closed() + # XXX this should do reset and set statement to None it seems def setinputsize(self, *args): pass From bgola at codespeak.net Thu Jun 19 17:36:54 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Thu, 19 Jun 2008 17:36:54 +0200 (CEST) Subject: [pypy-svn] r55963 - in pypy/branch/2.5-features/pypy/translator/goal: . test2 Message-ID: <20080619153654.72ED6498013@codespeak.net> Author: bgola Date: Thu Jun 19 17:36:53 2008 New Revision: 55963 Modified: pypy/branch/2.5-features/pypy/translator/goal/app_main.py pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py Log: supporting -W cmdline option in app_main Modified: pypy/branch/2.5-features/pypy/translator/goal/app_main.py ============================================================================== --- pypy/branch/2.5-features/pypy/translator/goal/app_main.py (original) +++ pypy/branch/2.5-features/pypy/translator/goal/app_main.py Thu Jun 19 17:36:53 2008 @@ -12,6 +12,7 @@ -m library module to be run as a script (terminates option list) -k, --oldstyle use old-style classes instead of newstyle classes everywhere %(oldstyle)s + -W arg warning control (arg is action:message:category:module:lineno) --version print the PyPy version --info print translation information about this PyPy executable """ @@ -206,6 +207,7 @@ i = 0 run_module = False run_stdin = False + warnoptions = [] oldstyle_classes = False while i < len(argv): arg = argv[i] @@ -246,9 +248,18 @@ break elif arg in ('-k', '--oldstyle'): oldstyle_classes = True + elif arg.startswith('-W'): + arg = arg.replace("-W", "") + if not arg: + i += 1 + if i >= len(argv): + print_error('Argument expected for the -W option') + return 2 + arg = argv[i] + warnoptions = arg elif arg == '--': i += 1 - break # terminates option list + break # terminates option list else: print_error('unrecognized option %r' % (arg,)) return 2 @@ -275,6 +286,10 @@ except: print >> sys.stderr, "'import site' failed" + if warnoptions: + sys.warnoptions.append(warnoptions) + from warnings import _processoptions + _processoptions(sys.warnoptions) # set up the Ctrl-C => KeyboardInterrupt signal handler, if the # signal module is available Modified: pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py ============================================================================== --- pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py (original) +++ pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py Thu Jun 19 17:36:53 2008 @@ -331,6 +331,20 @@ assert 'NameError' in data assert 'Goodbye2' not in data + def test_option_W(self): + data = self.run('-W d -c "print 42"') + assert '42' in data + data = self.run('-Wd -c "print 42"') + assert '42' in data + + def test_option_W_crashing(self): + data = self.run('-W') + assert 'Argument expected for the -W option' in data + + def test_option_W_arg_ignored(self): + data = self.run('-Wc') + assert "Invalid -W option ignored: invalid action: 'c'" in data + def test_option_c(self): data = self.run('-c "print 6**5"') assert '7776' in data From bgola at codespeak.net Thu Jun 19 17:50:19 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Thu, 19 Jun 2008 17:50:19 +0200 (CEST) Subject: [pypy-svn] r55964 - pypy/branch/2.5-features/pypy/interpreter/pyparser/data Message-ID: <20080619155019.8CBF8498013@codespeak.net> Author: bgola Date: Thu Jun 19 17:50:17 2008 New Revision: 55964 Removed: pypy/branch/2.5-features/pypy/interpreter/pyparser/data/Grammar2.5a Modified: pypy/branch/2.5-features/pypy/interpreter/pyparser/data/Grammar2.5 Log: removing Grammar2.5a and updating Grammar2.5 to match the Python2.5 Grammar (from CPython 2.5.1 src) Modified: pypy/branch/2.5-features/pypy/interpreter/pyparser/data/Grammar2.5 ============================================================================== --- pypy/branch/2.5-features/pypy/interpreter/pyparser/data/Grammar2.5 (original) +++ pypy/branch/2.5-features/pypy/interpreter/pyparser/data/Grammar2.5 Thu Jun 19 17:50:17 2008 @@ -62,8 +62,9 @@ raise_stmt: 'raise' [test [',' test [',' test]]] import_stmt: import_name | import_from import_name: 'import' dotted_as_names -import_from: 'from' dotted_name 'import' ('*' | '(' import_as_names [','] ')' | import_as_names) -import_as_name: NAME [('as'|NAME) NAME] +import_from: ('from' ('.'* dotted_name | '.'+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)) +import_as_name: NAME [('as' | NAME) NAME] dotted_as_name: dotted_name [('as' | NAME) NAME] import_as_names: import_as_name (',' import_as_name)* [','] dotted_as_names: dotted_as_name (',' dotted_as_name)* @@ -120,7 +121,7 @@ lambdef: 'lambda' [varargslist] ':' test trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] -subscript: '.' '.' '.' | [test] ':' [test] [sliceop] | test +subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] sliceop: ':' [test] exprlist: expr (',' expr)* [','] testlist: test (',' test)* [','] From cfbolz at codespeak.net Thu Jun 19 17:55:55 2008 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 19 Jun 2008 17:55:55 +0200 (CEST) Subject: [pypy-svn] r55965 - pypy/branch/2.5-features/pypy/translator/goal/test2 Message-ID: <20080619155555.7A95669802F@codespeak.net> Author: cfbolz Date: Thu Jun 19 17:55:49 2008 New Revision: 55965 Modified: pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py Log: failing test for the -W option Modified: pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py ============================================================================== --- pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py (original) +++ pypy/branch/2.5-features/pypy/translator/goal/test2/test_app_main.py Thu Jun 19 17:55:49 2008 @@ -345,6 +345,10 @@ data = self.run('-Wc') assert "Invalid -W option ignored: invalid action: 'c'" in data + def test_option_W_arg_ignored2(self): + data = self.run('-W-W') + assert "Invalid -W option ignored: invalid action:" in data + def test_option_c(self): data = self.run('-c "print 6**5"') assert '7776' in data From bgola at codespeak.net Thu Jun 19 18:05:08 2008 From: bgola at codespeak.net (bgola at codespeak.net) Date: Thu, 19 Jun 2008 18:05:08 +0200 (CEST) Subject: [pypy-svn] r55966 - pypy/branch/2.5-features/pypy/translator/goal Message-ID: <20080619160508.1A905698036@codespeak.net> Author: bgola Date: Thu Jun 19 18:05:07 2008 New Revision: 55966 Modified: pypy/branch/2.5-features/pypy/translator/goal/app_main.py Log: Passing the failng test for -W option Modified: pypy/branch/2.5-features/pypy/translator/goal/app_main.py ============================================================================== --- pypy/branch/2.5-features/pypy/translator/goal/app_main.py (original) +++ pypy/branch/2.5-features/pypy/translator/goal/app_main.py Thu Jun 19 18:05:07 2008 @@ -249,7 +249,7 @@ elif arg in ('-k', '--oldstyle'): oldstyle_classes = True elif arg.startswith('-W'): - arg = arg.replace("-W", "") + arg = arg[2:] if not arg: i += 1 if i >= len(argv): From fijal at codespeak.net Thu Jun 19 20:56:59 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 19 Jun 2008 20:56:59 +0200 (CEST) Subject: [pypy-svn] r55972 - in pypy/dist/pypy/module/_sre: . test Message-ID: <20080619185659.974CE69809C@codespeak.net> Author: fijal Date: Thu Jun 19 20:56:56 2008 New Revision: 55972 Modified: pypy/dist/pypy/module/_sre/app_sre.py pypy/dist/pypy/module/_sre/test/test_app_sre.py Log: Fix for #issue379 Modified: pypy/dist/pypy/module/_sre/app_sre.py ============================================================================== --- pypy/dist/pypy/module/_sre/app_sre.py (original) +++ pypy/dist/pypy/module/_sre/app_sre.py Thu Jun 19 20:56:56 2008 @@ -79,7 +79,9 @@ filter = sre._subx(self, repl) state = _sre._State(string, 0, sys.maxint, self.flags) sublist = [] - + + need_unicode = (isinstance(string, unicode) or + isinstance(self.pattern, unicode)) n = last_pos = 0 while not count or n < count: state.reset() @@ -91,9 +93,12 @@ last_pos == state.string_position and n > 0): # the above ignores empty matches on latest position if callable(filter): - sublist.append(filter(SRE_Match(self, state))) + to_app = filter(SRE_Match(self, state)) else: - sublist.append(filter) + to_app = filter + if isinstance(to_app, unicode): + need_unicode = True + sublist.append(to_app) last_pos = state.string_position n += 1 if state.string_position == state.start: @@ -103,7 +108,10 @@ if last_pos < state.end: sublist.append(string[last_pos:state.end]) - item = "".join(sublist) + if need_unicode: + item = u"".join(sublist) + else: + item = "".join(sublist) return item, n def sub(self, repl, string, count=0): Modified: pypy/dist/pypy/module/_sre/test/test_app_sre.py ============================================================================== --- pypy/dist/pypy/module/_sre/test/test_app_sre.py (original) +++ pypy/dist/pypy/module/_sre/test/test_app_sre.py Thu Jun 19 20:56:56 2008 @@ -179,6 +179,10 @@ assert ("rbd\nbr\n", 2) == re.subn("a(.)", r"b\1\n", "radar") assert ("bbbba", 2) == re.subn("a", "b", "ababa", 2) + def test_sub_unicode(self): + import re + assert isinstance(re.sub(u"a", u"b", u""), unicode) + def test_sub_callable(self): import re def call_me(match): From fijal at codespeak.net Fri Jun 20 01:52:23 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 20 Jun 2008 01:52:23 +0200 (CEST) Subject: [pypy-svn] r55980 - pypy/pysqlite2 Message-ID: <20080619235223.5A79239B5A3@codespeak.net> Author: fijal Date: Fri Jun 20 01:52:21 2008 New Revision: 55980 Modified: pypy/pysqlite2/dbapi2.py Log: Apparent typo Modified: pypy/pysqlite2/dbapi2.py ============================================================================== --- pypy/pysqlite2/dbapi2.py (original) +++ pypy/pysqlite2/dbapi2.py Fri Jun 20 01:52:21 2008 @@ -529,7 +529,7 @@ self.statement.set_params(params) ret = sqlite.sqlite3_step(self.statement.statement) if ret != SQLITE_DONE: - raise self.con._get_exception() + raise self.connection._get_exception() self.rowcount += sqlite.sqlite3_changes(self.connection.db) return self From xoraxax at codespeak.net Fri Jun 20 18:33:26 2008 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Fri, 20 Jun 2008 18:33:26 +0200 (CEST) Subject: [pypy-svn] r55999 - pypy/dist/pypy/translator/tool Message-ID: <20080620163326.C39F0169F0B@codespeak.net> Author: xoraxax Date: Fri Jun 20 18:33:25 2008 New Revision: 55999 Modified: pypy/dist/pypy/translator/tool/pdbplus.py Log: Make pdb+ prompt composable with the underlying pdbs if the prompt is different from the original prompt Modified: pypy/dist/pypy/translator/tool/pdbplus.py ============================================================================== --- pypy/dist/pypy/translator/tool/pdbplus.py (original) +++ pypy/dist/pypy/translator/tool/pdbplus.py Fri Jun 20 18:33:25 2008 @@ -11,7 +11,10 @@ def __init__(self, translator): pdb.Pdb.__init__(self) - self.prompt = "(Pdb+) " + if self.prompt == "(Pdb) ": + self.prompt = "(Pdb+) " + else: + self.prompt = self.prompt.replace("(", "(Pdb+ on ", 1) self.translator = translator self.exposed = {} From xoraxax at codespeak.net Sat Jun 21 20:48:44 2008 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Sat, 21 Jun 2008 20:48:44 +0200 (CEST) Subject: [pypy-svn] r56011 - pypy/dist/pypy/doc Message-ID: <20080621184844.85CFE2A8100@codespeak.net> Author: xoraxax Date: Sat Jun 21 20:48:42 2008 New Revision: 56011 Modified: pypy/dist/pypy/doc/getting-started.txt Log: Make the note about memory consumption a bit more detailed. Modified: pypy/dist/pypy/doc/getting-started.txt ============================================================================== --- pypy/dist/pypy/doc/getting-started.txt (original) +++ pypy/dist/pypy/doc/getting-started.txt Sat Jun 21 20:48:42 2008 @@ -558,7 +558,8 @@ libncurses-dev``. This whole process will take some time and quite a lot of memory (around -1GB). It creates an executable ``pypy-c`` in the current directory. +1200 MB on 32 bit machines). It creates an executable ``pypy-c`` in +the current directory. The ``--gc=hybrid`` option means that the ``pypy-c`` will use our own exact generational garbage collector implementation, whose performance is rather good nowadays. The ``--thread`` option enables the thread From pypy-svn at codespeak.net Sun Jun 22 05:40:31 2008 From: pypy-svn at codespeak.net (VIAGRA ® Official Site) Date: Sun, 22 Jun 2008 05:40:31 +0200 (CEST) Subject: [pypy-svn] Dear pypy-svn@codespeak.net June 89% 0FF Message-ID: <20080622083930.106921.qmail@CBL217-132-87-187.bb.netvision.net.il> An HTML attachment was scrubbed... URL: From arigo at codespeak.net Sun Jun 22 13:13:01 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 22 Jun 2008 13:13:01 +0200 (CEST) Subject: [pypy-svn] r56021 - pypy/dist/pypy/tool/algo Message-ID: <20080622111301.E939569804C@codespeak.net> Author: arigo Date: Sun Jun 22 13:12:59 2008 New Revision: 56021 Modified: pypy/dist/pypy/tool/algo/graphlib.py Log: Return a dict instead of a set again, as that change broke some callers. Modified: pypy/dist/pypy/tool/algo/graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/graphlib.py (original) +++ pypy/dist/pypy/tool/algo/graphlib.py Sun Jun 22 13:12:59 2008 @@ -71,11 +71,11 @@ if discovery_time[wroot] < discovery_time[vroot]: vroot = wroot if vroot == v: - component = set() + component = {} while True: w = stack.pop() del component_root[w] - component.add(w) + component[w] = True if w == v: break yield component From arigo at codespeak.net Sun Jun 22 13:20:40 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 22 Jun 2008 13:20:40 +0200 (CEST) Subject: [pypy-svn] r56022 - in pypy/dist/pypy/module/__builtin__: . test Message-ID: <20080622112040.79D15698037@codespeak.net> Author: arigo Date: Sun Jun 22 13:20:40 2008 New Revision: 56022 Modified: pypy/dist/pypy/module/__builtin__/descriptor.py pypy/dist/pypy/module/__builtin__/test/test_descriptor.py Log: issue377 resolved Although we need to officialize the API more, this is roughly how we are supposed to define subclassable built-in types from modules. Modified: pypy/dist/pypy/module/__builtin__/descriptor.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/descriptor.py (original) +++ pypy/dist/pypy/module/__builtin__/descriptor.py Sun Jun 22 13:20:40 2008 @@ -10,10 +10,9 @@ descr_set_dict, interp_attrproperty_w class W_Super(Wrappable): - def __init__(self, space, w_selftype, w_starttype, w_type, w_self): - self.w_selftype = w_selftype + def __init__(self, space, w_starttype, w_objtype, w_self): self.w_starttype = w_starttype - self.w_type = w_type + self.w_objtype = w_objtype self.w_self = w_self def get(self, space, w_obj, w_type=None): @@ -21,38 +20,38 @@ if self.w_self is None or space.is_w(w_obj, space.w_None): return w(self) else: - return space.call_function(self.w_selftype, self.w_starttype, w_obj - ) + # if type(self) is W_Super: + # XXX write a fast path for this common case + w_selftype = space.type(w(self)) + return space.call_function(w_selftype, self.w_starttype, w_obj) get.unwrap_spec = ['self', ObjSpace, W_Root, W_Root] def getattribute(self, space, name): w = space.wrap - if name == '__class__': - return self.w_selftype - if self.w_type is None: - return space.call_function(object_getattribute(space), - w(self), w(name)) - - w_value = space.lookup_in_type_starting_at(self.w_type, - self.w_starttype, - name) - if w_value is None: - return space.getattr(w(self), w(name)) - - try: - w_get = space.getattr(w_value, space.wrap('__get__')) - if space.is_w(self.w_self, self.w_type): - w_self = space.w_None - else: - w_self = self.w_self - except OperationError, o: - if not o.match(space, space.w_AttributeError): - raise - return w_value - return space.call_function(w_get, w_self, self.w_type) + # only use a special logic for bound super objects and not for + # getting the __class__ of the super object itself. + if self.w_objtype is not None and name != '__class__': + w_value = space.lookup_in_type_starting_at(self.w_objtype, + self.w_starttype, + name) + if w_value is not None: + w_get = space.lookup(w_value, '__get__') + if w_get is None: + return w_value + # Only pass 'obj' param if this is instance-mode super + # (see CPython sourceforge id #743627) + if self.w_self is self.w_objtype: + w_obj = space.w_None + else: + w_obj = self.w_self + return space.get_and_call_function(w_get, w_value, + w_obj, self.w_objtype) + # fallback to object.__getattribute__() + return space.call_function(object_getattribute(space), + w(self), w(name)) getattribute.unwrap_spec = ['self', ObjSpace, str] -def descr_new_super(space, w_self, w_starttype, w_obj_or_type=None): +def descr_new_super(space, w_subtype, w_starttype, w_obj_or_type=None): if space.is_w(w_obj_or_type, space.w_None): w_type = None # unbound super object else: @@ -73,7 +72,11 @@ raise OperationError(space.w_TypeError, space.wrap("super(type, obj): " "obj must be an instance or subtype of type")) - return space.wrap(W_Super(space, w_self, w_starttype, w_type, w_obj_or_type)) + # XXX the details of how allocate_instance() should be used are not + # really well defined + w_result = space.allocate_instance(W_Super, w_subtype) + W_Super.__init__(w_result, space, w_starttype, w_type, w_obj_or_type) + return w_result descr_new_super.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root] W_Super.typedef = TypeDef( @@ -99,8 +102,10 @@ self.w_fdel = w_fdel self.w_doc = w_doc - def new(space, w_type, w_fget=None, w_fset=None, w_fdel=None, w_doc=None): - return W_Property(space, w_fget, w_fset, w_fdel, w_doc) + def new(space, w_subtype, w_fget=None, w_fset=None, w_fdel=None, w_doc=None): + w_result = space.allocate_instance(W_Property, w_subtype) + W_Property.__init__(w_result, space, w_fget, w_fset, w_fdel, w_doc) + return w_result new.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root, W_Root, W_Root] def get(self, space, w_obj, w_objtype=None): @@ -129,6 +134,9 @@ delete.unwrap_spec = ['self', ObjSpace, W_Root] def getattribute(self, space, attr): + # XXX fixme: this is a workaround. It's hard but not impossible + # to have both a __doc__ on the 'property' type, and a __doc__ + # descriptor that can read the docstring of 'property' instances. if attr == '__doc__': return self.w_doc # shortcuts @@ -137,6 +145,9 @@ getattribute.unwrap_spec = ['self', ObjSpace, str] def setattr(self, space, attr, w_value): + # XXX kill me? This is mostly to make tests happy, raising + # a TypeError instead of an AttributeError and using "readonly" + # instead of "read-only" in the error message :-/ raise OperationError(space.w_TypeError, space.wrap( "Trying to set readonly attribute %s on property" % (attr,))) setattr.unwrap_spec = ['self', ObjSpace, str, W_Root] Modified: pypy/dist/pypy/module/__builtin__/test/test_descriptor.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_descriptor.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_descriptor.py Sun Jun 22 13:20:40 2008 @@ -134,7 +134,6 @@ assert F().meth(6) == "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)" - skip("in-progress: buggy implementation of 'super' subclasses") x = mysuper(F, F()) x.foobar = 42 assert x.foobar == 42 From arigo at codespeak.net Sun Jun 22 13:35:40 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 22 Jun 2008 13:35:40 +0200 (CEST) Subject: [pypy-svn] r56023 - in pypy/dist/pypy: bin module/sys translator/goal Message-ID: <20080622113540.4188E49800E@codespeak.net> Author: arigo Date: Sun Jun 22 13:35:39 2008 New Revision: 56023 Modified: pypy/dist/pypy/bin/py.py pypy/dist/pypy/module/sys/state.py pypy/dist/pypy/translator/goal/app_main.py Log: issue295 resolved Moved bits and pieces around to handle $PYTHONPATH when pypy-c and py.py start, instead of hard-coding it in the pypy-c. Modified: pypy/dist/pypy/bin/py.py ============================================================================== --- pypy/dist/pypy/bin/py.py (original) +++ pypy/dist/pypy/bin/py.py Sun Jun 22 13:35:39 2008 @@ -49,15 +49,6 @@ print >> sys.stderr, "import site\' failed" ''').interphook('pypy_init') -def getenv_w(space, name): - w_os = space.getbuiltinmodule('os') - w_environ = space.getattr(w_os, space.wrap('environ')) - w_v = space.call_method(w_environ, 'get', space.wrap(name)) - try: - return space.str_w(w_v) - except: - return None - def main_(argv=None): starttime = time.time() @@ -76,6 +67,16 @@ space.setitem(space.sys.w_dict, space.wrap('executable'), space.wrap(argv[0])) + w_path = space.sys.get('path') + path = os.getenv('PYTHONPATH') + if path: + path = path.split(os.pathsep) + else: + path = [] + path.insert(0, '') + for i, dir in enumerate(path): + space.call_method(w_path, 'insert', space.wrap(i), space.wrap(dir)) + # store the command-line arguments into sys.argv go_interactive = interactiveconfig.interactive banner = '' @@ -118,7 +119,7 @@ exit_status = 1 # start the interactive console - if go_interactive or getenv_w(space, 'PYTHONINSPECT'): + if go_interactive or os.getenv('PYTHONINSPECT'): try: import readline except: Modified: pypy/dist/pypy/module/sys/state.py ============================================================================== --- pypy/dist/pypy/module/sys/state.py (original) +++ pypy/dist/pypy/module/sys/state.py Sun Jun 22 13:35:39 2008 @@ -50,12 +50,7 @@ pypy_lib = os.path.join(pypydir, 'lib') checkdir(pypy_lib) - importlist = [''] - pythonpath = os.environ.get('PYTHONPATH') - if pythonpath: - for p in pythonpath.split(os.pathsep): - if p: - importlist.append(p) + importlist = [] importlist.append(pypy_lib) importlist.append(python_std_lib_modified) importlist.append(python_std_lib) Modified: pypy/dist/pypy/translator/goal/app_main.py ============================================================================== --- pypy/dist/pypy/translator/goal/app_main.py (original) +++ pypy/dist/pypy/translator/goal/app_main.py Sun Jun 22 13:35:39 2008 @@ -193,6 +193,7 @@ # not found! let's hope that the compiled-in path is ok print >> sys.stderr, ('debug: WARNING: library path not found, ' 'using compiled-in sys.path') + newpath = sys.path[:] break newpath = sys.pypy_initial_path(dirname) if newpath is None: @@ -200,9 +201,20 @@ if newpath is None: search = dirname # walk to the parent directory continue - sys.path = newpath # found! - break - + break # found! + path = os.getenv('PYTHONPATH') + if path: + newpath = path.split(os.pathsep) + newpath + newpath.insert(0, '') + # remove duplicates + _seen = {} + sys.path = [] + for dir in newpath: + if dir not in _seen: + sys.path.append(dir) + _seen[dir] = True + del newpath, _seen + go_interactive = False run_command = False import_site = True From arigo at codespeak.net Sun Jun 22 13:39:39 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 22 Jun 2008 13:39:39 +0200 (CEST) Subject: [pypy-svn] r56024 - pypy/dist/pypy/tool/algo Message-ID: <20080622113939.F19B749800E@codespeak.net> Author: arigo Date: Sun Jun 22 13:39:39 2008 New Revision: 56024 Modified: pypy/dist/pypy/tool/algo/graphlib.py Log: Fix. Modified: pypy/dist/pypy/tool/algo/graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/graphlib.py (original) +++ pypy/dist/pypy/tool/algo/graphlib.py Sun Jun 22 13:39:39 2008 @@ -112,7 +112,7 @@ rep = {} # maps all vertices to a random representing vertex # from the same strongly connected component for component in strong_components(vertices, edges): - random_vertex = component.pop() + random_vertex, _ = component.popitem() rep[random_vertex] = random_vertex for v in component: rep[v] = random_vertex From antocuni at codespeak.net Mon Jun 23 11:15:50 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 23 Jun 2008 11:15:50 +0200 (CEST) Subject: [pypy-svn] r56029 - pypy/branch/oo-jit/pypy/jit/codegen/llgraph Message-ID: <20080623091550.91D8B2A809C@codespeak.net> Author: antocuni Date: Mon Jun 23 11:15:48 2008 New Revision: 56029 Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py Log: introduce our own erasedType function, which knows about both lltype and ootype. This is needed, but not sufficient, to make test_0tlc passing on ootype. Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/llimpl.py Mon Jun 23 11:15:48 2008 @@ -51,6 +51,15 @@ assert isinstance(TYPE, ootype.StaticMethod) return ootype.static_meth(TYPE, name, **attrs) +def erasedType(T): + if isinstance(T, ootype.Instance): + if T is ootype.ROOT: + return T + while T._superclass is not ootype.ROOT: + T = T._superclass + return T + return lltype.erasedType(T) + def newgraph(gv_FUNCTYPE, name): FUNCTYPE = _from_opaque(gv_FUNCTYPE).value # 'name' is just a way to track things @@ -62,7 +71,7 @@ v.concretetype = ARG inputargs.append(v) v = flowmodel.Variable() - v.concretetype = lltype.erasedType(ARG) + v.concretetype = erasedType(ARG) erasedinputargs.append(v) startblock = flowmodel.Block(inputargs) # insert an exploding operation here which is removed by @@ -77,7 +86,7 @@ return_var.concretetype = FUNCTYPE.RESULT graph = flowmodel.FunctionGraph(name, startblock, return_var) v1 = flowmodel.Variable() - v1.concretetype = lltype.erasedType(FUNCTYPE.RESULT) + v1.concretetype = erasedType(FUNCTYPE.RESULT) graph.prereturnblock = flowmodel.Block([v1]) casting_link(graph.prereturnblock, [v1], graph.returnblock) substartblock = flowmodel.Block(erasedinputargs) @@ -112,7 +121,7 @@ assert block.exits == [], "block already closed" CONCRETE_TYPE = _from_opaque(gv_CONCRETE_TYPE).value v = flowmodel.Variable() - v.concretetype = lltype.erasedType(CONCRETE_TYPE) + v.concretetype = erasedType(CONCRETE_TYPE) block.inputargs.append(v) return _to_opaque(v) @@ -155,12 +164,9 @@ opname = 'cast_opaque_ptr' elif isinstance(TYPE, ootype.Instance): FROMTYPE = v.concretetype - if ootype.isSubclass(FROMTYPE, TYPE): - opname = 'ooupcast' - else: - opname = 'oodowncast' + opname = erasing_op(FROMTYPE, TYPE) else: - assert v.concretetype == lltype.erasedType(TYPE) + assert v.concretetype == erasedType(TYPE) opname = 'cast_pointer' block = _from_opaque(block) v2 = flowmodel.Variable() @@ -170,20 +176,21 @@ v = v2 return _to_opaque(v) +def erasing_op(FROMTYPE, TYPE): + if isinstance(TYPE, ootype.Instance): + if ootype.isSubclass(FROMTYPE, TYPE): + return 'ooupcast' + else: + return 'oodowncast' + return 'cast_pointer' + def erasedvar(v, block): - T = lltype.erasedType(v.concretetype) + T = erasedType(v.concretetype) if T != v.concretetype: v2 = flowmodel.Variable() v2.concretetype = T - op = flowmodel.SpaceOperation("cast_pointer", [v], v2) - block.operations.append(op) - return v2 - elif isinstance(T, ootype.Instance): - while T._superclass is not ootype.ROOT: - T = T._superclass - v2 = flowmodel.Variable() - v2.concretetype = T - op = flowmodel.SpaceOperation("ooupcast", [v], v2) + opname = erasing_op(v.concretetype, T) + op = flowmodel.SpaceOperation(opname, [v], v2) block.operations.append(op) return v2 return v @@ -244,9 +251,12 @@ v.concretetype = lltype.Void return _to_opaque(v) T = lltype.typeOf(llvalue) - T1 = lltype.erasedType(T) + T1 = erasedType(T) if T1 != T: - llvalue = lltype.cast_pointer(T1, llvalue) + if isinstance(T1, ootype.Instance): + llvalue = ootype.ooupcast(T1, llvalue) + else: + llvalue = lltype.cast_pointer(T1, llvalue) v = flowmodel.Constant(llvalue) v.concretetype = T1 if v.concretetype == lltype.Void: # XXX genconst should not really be used for Void constants @@ -255,7 +265,7 @@ def genzeroconst(gv_TYPE): TYPE = _from_opaque(gv_TYPE).value - TYPE = lltype.erasedType(TYPE) + TYPE = erasedType(TYPE) c = flowmodel.Constant(TYPE._defl()) c.concretetype = TYPE return _to_opaque(c) @@ -276,6 +286,11 @@ elif isinstance(T, ootype.StaticMethod): fn = value._obj return ootype._static_meth(T, graph=fn.graph, _callable=fn._callable) + elif isinstance(T, ootype.Instance): + T1 = lltype.typeOf(value) + if ootype.isSubclass(T, T1): + return ootype.oodowncast(T, value) + return ootype.ooupcast(T, value) else: T1 = lltype.typeOf(value) if isinstance(T1, ootype.OOType) and T is ootype.Signed: @@ -635,7 +650,8 @@ else: erasedv = flowmodel.Variable() erasedv.concretetype = target_v.concretetype - source.operations.append(flowmodel.SpaceOperation('cast_pointer', + opname = erasing_op(v.concretetype, erasedv.concretetype) + source.operations.append(flowmodel.SpaceOperation(opname, [v], erasedv)) linkargs.append(erasedv) From antocuni at codespeak.net Mon Jun 23 11:38:18 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 23 Jun 2008 11:38:18 +0200 (CEST) Subject: [pypy-svn] r56030 - pypy/branch/oo-jit/pypy/translator Message-ID: <20080623093818.A97BB2A8078@codespeak.net> Author: antocuni Date: Mon Jun 23 11:38:18 2008 New Revision: 56030 Modified: pypy/branch/oo-jit/pypy/translator/simplify.py Log: if there are multiple exits, it could not be an infinite loop Modified: pypy/branch/oo-jit/pypy/translator/simplify.py ============================================================================== --- pypy/branch/oo-jit/pypy/translator/simplify.py (original) +++ pypy/branch/oo-jit/pypy/translator/simplify.py Mon Jun 23 11:38:18 2008 @@ -84,7 +84,7 @@ exit = block1.exits[0] assert block1 is not exit.target, ( "the graph contains an empty infinite loop") - if exit.target.exits: + if len(exit.target.exits) == 1: assert block1 is not exit.target.exits[0].target, ( "the graph contains an empty infinite loop") outputargs = [] From antocuni at codespeak.net Mon Jun 23 15:07:23 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 23 Jun 2008 15:07:23 +0200 (CEST) Subject: [pypy-svn] r56032 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080623130723.51F2D2A8078@codespeak.net> Author: antocuni Date: Mon Jun 23 15:07:21 2008 New Revision: 56032 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Log: a failing test for ootype Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Mon Jun 23 15:07:21 2008 @@ -474,6 +474,32 @@ assert res == 11 self.check_insns(int_add=0) + def test_promote___class__(self): + class A: + def __init__(self, x): + self.x = x + def m(self, other): + return self.x + other.x + class B(A): + def m(self, other): + return self.x * other.x + + def make_obj(x, flag): + return flag and A(x) or B(x) + + def ll_function(x, flag): + hint(None, global_merge_point=True) + obj = make_obj(x, flag) + obj2 = flag and A(x+2) or B(x+2) + hint(obj.__class__, promote=True) + return obj.m(obj2) + + res = self.interpret(ll_function, [20, True], [], policy=StopAtXPolicy(make_obj)) + assert res == 42 + self.check_insns(malloc=0) + self.check_insns(new=0) + + class TestLLType(BaseTestPromotion): type_system = "lltype" to_rstr = staticmethod(LLSupport.to_rstr) @@ -481,3 +507,6 @@ class TestOOType(OOTypeMixin, BaseTestPromotion): type_system = "ootype" to_rstr = staticmethod(OOSupport.to_rstr) + + def test_promote___class__(self): + py.test.skip('fixme') From fijal at codespeak.net Mon Jun 23 19:05:50 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 19:05:50 +0200 (CEST) Subject: [pypy-svn] r56038 - pypy/extradoc/talk/ep2008 Message-ID: <20080623170550.37E9069806F@codespeak.net> Author: fijal Date: Mon Jun 23 19:05:48 2008 New Revision: 56038 Added: pypy/extradoc/talk/ep2008/gc.txt (contents, props changed) Log: Brain dump of gc talk Added: pypy/extradoc/talk/ep2008/gc.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/ep2008/gc.txt Mon Jun 23 19:05:48 2008 @@ -0,0 +1,62 @@ + +Intro +===== + +* Memory management model + +* GC is *not* only the part that takes + care of circular references + +... + +What is refcounting? +==================== + +XXX explain + +What is a generational moving GC? +================================= + +XXX explain + +Finalizers +========== + +* Semantic differencies + +* __del__ called immediately considered to be + implementation-dependent + +Finalizers - resurrection +========================= + +XXX + +Finalizers - cycles with __del__ +================================ + +XXX + +Calling C-level code +==================== + +* Problems with moving + +* Problems with write barriers + +... + +Strange operation costs +======================= + +* id + +XXX what else? + +Allocation cost +================ + +* refcounting/C malloc - expensive + +* generational gc - cheap + From fijal at codespeak.net Mon Jun 23 20:00:25 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 20:00:25 +0200 (CEST) Subject: [pypy-svn] r56039 - pypy/extradoc/talk/ep2008 Message-ID: <20080623180025.2571C2A00DF@codespeak.net> Author: fijal Date: Mon Jun 23 20:00:21 2008 New Revision: 56039 Modified: pypy/extradoc/talk/ep2008/gc.txt Log: A bit of update Modified: pypy/extradoc/talk/ep2008/gc.txt ============================================================================== --- pypy/extradoc/talk/ep2008/gc.txt (original) +++ pypy/extradoc/talk/ep2008/gc.txt Mon Jun 23 20:00:21 2008 @@ -19,6 +19,11 @@ XXX explain +Difference in performance +========================= + +XXX + Finalizers ========== @@ -60,3 +65,17 @@ * generational gc - cheap +Allocating large amount of objects +================================== + +* CPython - O(n^2) where n is number of objects + allocated + +* Any reasonable generational GC should do better + +Collection costs +================ + +* Full collection - costly (always the case with cpython) + +* Nursery collection - quick From antocuni at codespeak.net Mon Jun 23 20:12:04 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 23 Jun 2008 20:12:04 +0200 (CEST) Subject: [pypy-svn] r56040 - pypy/extradoc/talk/ep2008 Message-ID: <20080623181204.3A3BA169F42@codespeak.net> Author: antocuni Date: Mon Jun 23 20:12:02 2008 New Revision: 56040 Modified: pypy/extradoc/talk/ep2008/gc.txt Log: typo Modified: pypy/extradoc/talk/ep2008/gc.txt ============================================================================== --- pypy/extradoc/talk/ep2008/gc.txt (original) +++ pypy/extradoc/talk/ep2008/gc.txt Mon Jun 23 20:12:02 2008 @@ -27,7 +27,7 @@ Finalizers ========== -* Semantic differencies +* Semantic differences * __del__ called immediately considered to be implementation-dependent From fijal at codespeak.net Mon Jun 23 21:41:54 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 21:41:54 +0200 (CEST) Subject: [pypy-svn] r56041 - in pypy/branch/jit-hotpath/pypy/lang/automata: . test Message-ID: <20080623194154.C26812A8006@codespeak.net> Author: fijal Date: Mon Jun 23 21:41:53 2008 New Revision: 56041 Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Log: A version that passes tests, but fairly ugly. Eventual cleanup would be cool. Modified: pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/nfa.py Mon Jun 23 21:41:53 2008 @@ -5,6 +5,7 @@ self.transitions = {} self.final_states = {} self.has_epsilon_moves = False + self.last_transition = (-1, ' ') def add_state(self, final=False): state = self.num_states @@ -14,6 +15,7 @@ return self.num_states - 1 def add_transition(self, state, input, next_state): + self.last_transition = (state, input) if input == '?': self.has_epsilon_moves = True if (state, input) in self.transitions: @@ -21,6 +23,12 @@ else: self.transitions[state, input] = [next_state] + def fixup_last_transition(self, where): + if self.last_transition == (-1, ' '): + raise RuntimeError("Something went wrong...") + self.transitions[self.last_transition][-1] = where + self.last_transition = (-1, ' ') + def get_transitions(self, state, input): return self.transitions[state, input] @@ -40,14 +48,24 @@ for (s, v), next_s_l in self.transitions.items(): if v == '?': for next_s in next_s_l: - if next_s in possible_merges: - possible_merges[next_s][s] = None + if s == next_s: # complete nonsese + if len(next_s_l) == 1: + del self.transitions[(s, v)] + else: + self.transitions[(s, v)].remove(s) else: - possible_merges[next_s] = {s:None} + if next_s in possible_merges: + possible_merges[next_s][s] = None + else: + possible_merges[next_s] = {s:None} else: prohibited_merges[s] = None for k, v in possible_merges.items(): - v = dict.fromkeys([i for i in v if i not in prohibited_merges]) + new_v = {} + for i in v: + if i not in prohibited_merges: + new_v[i] = None + v = new_v if len(v) > 1: first = v.keys()[0] self.merge_states(first, v) @@ -63,7 +81,7 @@ for k in self.final_states.keys(): if k in vdict: self.final_states[to_what] = None - del final_states[k] + del self.final_states[k] def _remove_epsilon_moves(self): for (s, v), next_s_l in self.transitions.items(): @@ -99,7 +117,8 @@ all[next] = None for fs in self.final_states: all[fs] = None - if all == accessible: + # we cannot compare dicts in rpython + if len(all) == len(accessible): return False else: for (s, v), next_s_l in self.transitions.items(): @@ -176,24 +195,32 @@ i = pos last_state = -1 state = start_state + previous_state = -1 while i < len(input): c = input[i] if in_alphabet(c): next_state = nfa.add_state() nfa.add_transition(state, c, next_state) + previous_state = state state = next_state elif c == ')': break elif c == '(': + previous_state = state i, state = compile_part(nfa, state, input, i + 1) elif c == '|': if last_state == -1: last_state = nfa.add_state() nfa.add_transition(state, '?', last_state) state = start_state + previous_state = -1 elif c == '*': - nfa.add_transition(state, '?', start_state) - state = start_state + if nfa.last_transition[0] != -1: + nfa.fixup_last_transition(previous_state) + else: + nfa.add_transition(state, '?', previous_state) + state = previous_state + previous_state = -1 else: raise ValueError("Unknown char %s" % c) i += 1 Modified: pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py (original) +++ pypy/branch/jit-hotpath/pypy/lang/automata/test/test_nfa.py Mon Jun 23 21:41:53 2008 @@ -77,24 +77,31 @@ assert sorted(re.final_states.keys()) == [4, 9] re = compile_regex("a*") re.remove_epsilon_moves() - assert re.transitions == {(0, "a"):[1], - (1, "a"):[1]} - assert sorted(re.final_states.keys()) == [0, 1] + assert re.transitions == {(0, "a"):[0]} + assert re.final_states.keys() == [0] re = compile_regex("a*b") re.remove_epsilon_moves() - assert re.transitions == {(0, "a"):[1], (1, "b"):[2], - (0, 'b'):[2], (1, 'a'):[1]} + assert re.transitions == {(0, "a"):[0], (0, "b"):[2]} assert re.final_states.keys() == [2] re = compile_regex("|a") re.remove_epsilon_moves() assert re.transitions == {(0, "a"):[2]} assert re.final_states.keys() == [0,2] + re = compile_regex("abc(ced)*") + re.remove_epsilon_moves() + assert re.transitions == {(3, 'c'): [4], (0, 'a'): [1], (5, 'd'): [3], + (4, 'e'): [5], (1, 'b'): [2], (2, 'c'): [3]} + assert re.final_states.keys() == [3] #re = compile_regex('a{0,3}') #assert re.transitions == {(0, "a"):[0,1], # (1, "a"):[0,2], # (2, "a"):[0,3]} #assert re.final_states.keys() == [0] +def test_nfa_recognize(): + nfa = compile_regex("abcc*") + assert recognize(nfa, "abc") + def test_nfa_compiledummy(): py.test.skip("not working") def main(gets): From fijal at codespeak.net Mon Jun 23 21:52:13 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 21:52:13 +0200 (CEST) Subject: [pypy-svn] r56042 - pypy/branch/jit-hotpath/pypy/jit/timeshifter Message-ID: <20080623195213.77C702A8006@codespeak.net> Author: fijal Date: Mon Jun 23 21:52:10 2008 New Revision: 56042 Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/vdict.py Log: Never tested typo? Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/vdict.py ============================================================================== --- pypy/branch/jit-hotpath/pypy/jit/timeshifter/vdict.py (original) +++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/vdict.py Mon Jun 23 21:52:10 2008 @@ -191,8 +191,8 @@ args_gv) def gen_insertclean(self, builder, args_gv): - return builder.genop_call(typedesc.tok_ll_insertclean, - typedesc.gv_ll_insertclean, + return builder.genop_call(self.tok_ll_insertclean, + self.gv_ll_insertclean, args_gv) From fijal at codespeak.net Mon Jun 23 22:23:20 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 22:23:20 +0200 (CEST) Subject: [pypy-svn] r56043 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080623202320.0E17D2A8006@codespeak.net> Author: fijal Date: Mon Jun 23 22:23:18 2008 New Revision: 56043 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py Log: A test for dict escapes. Fail on lltypesystem for some obscure reason Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py Mon Jun 23 22:23:18 2008 @@ -76,6 +76,39 @@ self.check_insns({}) + + def test_dict_escape(self): + d1 = {1: 123, 2: 54, 3:84} + d2 = {1: 831, 2: 32, 3:81} + + def getdict(n): + if n: + return d1 + else: + return d2 + + class A: + pass + + def f(n): + d = getdict(n) + x = A() + x.d = d + return x + + a = [] + + def ll_function(n, i): + x = f(n) + a.append(x) + d = hint(x.d, deepfreeze=True) + res = d[i] + res = hint(res, variable=True) + return res + + res = self.interpret(ll_function, [3, 2], [0, 1], policy=P_OOPSPEC) + assert res == 54 + class TestOOType(OOTypeMixin, VDictTest): type_system = "ootype" From fijal at codespeak.net Mon Jun 23 22:33:01 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 23 Jun 2008 22:33:01 +0200 (CEST) Subject: [pypy-svn] r56044 - pypy/branch/oo-jit/pypy/jit/rainbow/test Message-ID: <20080623203301.A354839B596@codespeak.net> Author: fijal Date: Mon Jun 23 22:32:59 2008 New Revision: 56044 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py Log: Skip this test Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_vdict.py Mon Jun 23 22:32:59 2008 @@ -114,3 +114,6 @@ class TestLLType(VDictTest): type_system = "lltype" + + def test_dict_escape(self): + py.test.skip("Fails for some obscure reason") From fijal at codespeak.net Tue Jun 24 00:19:59 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 24 Jun 2008 00:19:59 +0200 (CEST) Subject: [pypy-svn] r56046 - pypy/branch/oo-jit/pypy/jit/timeshifter Message-ID: <20080623221959.88A63169E89@codespeak.net> Author: fijal Date: Tue Jun 24 00:19:57 2008 New Revision: 56046 Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Log: Add an assert Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rtimeshift.py Tue Jun 24 00:19:57 2008 @@ -738,6 +738,7 @@ class PromotionPathNode(AbstractPromotionPath): def __init__(self, next): + assert next self.next = next def follow_path(self, path): path.append(self) From fijal at codespeak.net Tue Jun 24 03:45:57 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 24 Jun 2008 03:45:57 +0200 (CEST) Subject: [pypy-svn] r56047 - in pypy/build/bot: . test Message-ID: <20080624014557.DECE82A80AD@codespeak.net> Author: fijal Date: Tue Jun 24 03:45:55 2008 New Revision: 56047 Added: pypy/build/bot/test/test_netstring.py (contents, props changed) Modified: pypy/build/bot/netstring.py Log: Move netstring's tests into it's own test file. It'll go away at some point anyway Modified: pypy/build/bot/netstring.py ============================================================================== --- pypy/build/bot/netstring.py (original) +++ pypy/build/bot/netstring.py Tue Jun 24 03:45:55 2008 @@ -14,9 +14,3 @@ length = int(netstrings[position:lengthEnd]) yield netstrings[lengthEnd + 1:lengthEnd + 1 + length] position = lengthEnd + length + 2 - -input = "\n1:x\n2:ab\n3:123\n3:\nxy\n4:a\nb\n\n1:a\n" -output = ["x", "ab", "123", "\nxy", "a\nb\n", "a"] -assert map(str, netstringparser(input)) == output -input = input.replace('\n', '\r\n') -assert map(str, netstringparser(input)) == output Added: pypy/build/bot/test/test_netstring.py ============================================================================== --- (empty file) +++ pypy/build/bot/test/test_netstring.py Tue Jun 24 03:45:55 2008 @@ -0,0 +1,9 @@ + +from bot.netstring import netstringparser + +def test_netstring(): + input = "\n1:x\n2:ab\n3:123\n3:\nxy\n4:a\nb\n\n1:a\n" + output = ["x", "ab", "123", "\nxy", "a\nb\n", "a"] + assert map(str, netstringparser(input)) == output + input = input.replace('\n', '\r\n') + assert map(str, netstringparser(input)) == output From arigo at codespeak.net Tue Jun 24 10:25:06 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 24 Jun 2008 10:25:06 +0200 (CEST) Subject: [pypy-svn] r56048 - in pypy/dist/pypy/tool/algo: . test Message-ID: <20080624082506.8C0E82A80A3@codespeak.net> Author: arigo Date: Tue Jun 24 10:25:03 2008 New Revision: 56048 Modified: pypy/dist/pypy/tool/algo/graphlib.py pypy/dist/pypy/tool/algo/test/test_graphlib.py Log: Change the stack check insertion logic. Now, when translating pypy: - it runs in about 35 secs, only slightly slower than before this check-in - it puts 4 times more stack checks than before - but when the pypy-c runs pystone or richards, there is a lower number of calls to stack_check being actually done and it gives a minor speed-up. All in all the check-in makes sense also because the algorithm sounds kind of reasonable, and a bit more deterministic (which could reduce random effects from translation to translation). Modified: pypy/dist/pypy/tool/algo/graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/graphlib.py (original) +++ pypy/dist/pypy/tool/algo/graphlib.py Tue Jun 24 10:25:03 2008 @@ -236,64 +236,60 @@ """Enumerates a reasonably minimal set of vertices that must be removed to make the graph acyclic.""" - # the approach is as follows: starting from each root, find some set - # of cycles using a simple depth-first search. Then break the - # vertex that is part of the most cycles. Repeat. + # Consider where each cycle should be broken -- we go for the idea + # that it is often better to break it as far as possible from the + # cycle's entry point, so that the stack check occurs as late as + # possible. For the distance we use a global "depth" computed as + # the distance from the roots. The algo below is: + # - get a list of cycles + # - let maxdepth(cycle) = max(depth(vertex) for vertex in cycle) + # - sort the list of cycles by their maxdepth, nearest first + # - for each cycle in the list, if the cycle is not broken yet, + # remove the vertex with the largest depth + # - repeat the whole procedure until no more cycles are found. + # Ordering the cycles themselves nearest first maximizes the chances + # that when breaking a nearby cycle - which must be broken in any + # case - we remove a vertex and break some further cycles by chance. - remaining_vertices = vertices.copy() + v_depths = vertices progress = True roots_finished = set() - v_depths = None while progress: - roots = list(find_roots(remaining_vertices, edges)) - if v_depths is None: - #print roots - v_depths = compute_depths(roots, remaining_vertices, edges) - assert len(v_depths) == len(remaining_vertices) - #print v_depths - factor = 1.0 / len(v_depths) - #print '%d inital roots' % (len(roots,)) + roots = list(find_roots(v_depths, edges)) + if v_depths is vertices: # first time only + v_depths = compute_depths(roots, vertices, edges) + assert len(v_depths) == len(vertices) # ...so far. We remove + # from v_depths the vertices at which we choose to break cycles + print '%d inital roots' % (len(roots,)) progress = False for root in roots: if root in roots_finished: continue - cycles = all_cycles(root, remaining_vertices, edges) + cycles = all_cycles(root, v_depths, edges) if not cycles: roots_finished.add(root) continue - #print 'from root %r: %d cycles' % (root, len(cycles)) - allcycles = {} - v2cycles = {} + print 'from root %r: %d cycles' % (root, len(cycles)) + # compute the "depth" of each cycles: how far it goes from any root + allcycles = [] for cycle in cycles: - allcycles[id(cycle)] = cycle - for edge in cycle: - v2cycles.setdefault(edge.source, []).append(id(cycle)) - v_weights = {} - for v, cycles in v2cycles.iteritems(): - v_weights[v] = len(cycles) + v_depths.get(v, 0) * factor - # The weight of a vertex is the number of cycles going - # through it, plus a small value used as a bias in case of - # a tie. The bias is in favor of vertices of large depth. - while allcycles: - max_weight = 1 - max_vertex = None - for v, weight in v_weights.iteritems(): - if weight >= max_weight: - max_vertex = v - max_weight = weight - if max_vertex is None: - break - # kill this vertex - yield max_vertex - progress = True - # unregister all cycles that have just been broken - for broken_cycle_id in v2cycles[max_vertex]: - broken_cycle = allcycles.pop(broken_cycle_id, ()) - for edge in broken_cycle: - v_weights[edge.source] -= 1 - - del remaining_vertices[max_vertex] - assert is_acyclic(remaining_vertices, edges) + cycledepth = max([v_depths[edge.source] for edge in cycle]) + allcycles.append((cycledepth, cycle)) + allcycles.sort() + # consider all cycles starting from the ones with smallest depth + for _, cycle in allcycles: + try: + choices = [(v_depths[edge.source], edge.source) + for edge in cycle] + except KeyError: + pass # this cycle was already broken + else: + # break this cycle by removing the furthest vertex + max_depth, max_vertex = max(choices) + del v_depths[max_vertex] + yield max_vertex + progress = True + assert is_acyclic(v_depths, edges) def show_graph(vertices, edges): Modified: pypy/dist/pypy/tool/algo/test/test_graphlib.py ============================================================================== --- pypy/dist/pypy/tool/algo/test/test_graphlib.py (original) +++ pypy/dist/pypy/tool/algo/test/test_graphlib.py Tue Jun 24 10:25:03 2008 @@ -67,7 +67,7 @@ result.sort() assert ''.join(result) == 'AD' # the answers 'BD' and 'DE' are correct too, but 'AD' should - # be picked because 'A' is the node cycle that is the further + # be picked because 'A' is the cycle's node that is the further # from the root 'R'. def test_find_roots(self): @@ -227,8 +227,9 @@ # assert is_acyclic(): included in break_cycles() itself def test_break_cycles_v(self): - list(break_cycles_v(self.edges, self.edges)) + result = list(break_cycles_v(self.edges, self.edges)) # assert is_acyclic(): included in break_cycles_v() itself + print len(result), 'vertices removed' def test_find_roots(self): roots = find_roots(self.edges, self.edges) From fijal at codespeak.net Wed Jun 25 06:15:39 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 25 Jun 2008 06:15:39 +0200 (CEST) Subject: [pypy-svn] r56056 - pypy/dist/pypy/module/select/test Message-ID: <20080625041539.F228D2A805E@codespeak.net> Author: fijal Date: Wed Jun 25 06:15:36 2008 New Revision: 56056 Modified: pypy/dist/pypy/module/select/test/test_select.py Log: * Add a test from issue346, fails on top of pypy-c, but on other test hangs when run on top of py.py anyway for me * Make py.test -A work. Modified: pypy/dist/pypy/module/select/test/test_select.py ============================================================================== --- pypy/dist/pypy/module/select/test/test_select.py (original) +++ pypy/dist/pypy/module/select/test/test_select.py Wed Jun 25 06:15:36 2008 @@ -9,7 +9,7 @@ to report that no results are available. """ import time, select - readend, writeend = getpair() + readend, writeend = self.getpair() try: start = time.time() iwtd, owtd, ewtd = select.select([readend], [], [], 0.3) @@ -22,9 +22,9 @@ def test_list_tuple(self): import time, select - readend, writeend = getpair() + readend, writeend = self.getpair() try: - iwtd, owtd, ewtd = select.select([readend], (), (), 0) + iwtd, owtd, ewtd = select.select([readend], (), (), .3) finally: readend.close() writeend.close() @@ -35,7 +35,7 @@ parameter) which may have data available to be read. """ import select - readend, writeend = getpair() + readend, writeend = self.getpair() try: iwtd, owtd, ewtd = select.select([readend], [], [], 0) assert iwtd == owtd == ewtd == [] @@ -53,7 +53,7 @@ parameter) on which a write/send may be possible. """ import select - readend, writeend = getpair() + readend, writeend = self.getpair() try: iwtd, owtd, ewtd = select.select([], [writeend], [], 0) assert iwtd == ewtd == [] @@ -71,7 +71,7 @@ overlaps significantly with test_readable. -exarkun) """ import select - readend, writeend = getpair() + readend, writeend = self.getpair() try: total_out = 0 while True: @@ -103,7 +103,7 @@ parameter) which have no data to be read but which have been closed. """ import select, sys - readend, writeend = getpair() + readend, writeend = self.getpair() try: try: total_out = writeend.send('x' * 512) @@ -137,7 +137,7 @@ pipe). """ import select - readend, writeend = getpair() + readend, writeend = self.getpair() try: readend.close() iwtd, owtd, ewtd = select.select([writeend], [], [], 0) @@ -157,7 +157,7 @@ writeends = [] try: for i in range(10): - fd1, fd2 = getpair() + fd1, fd2 = self.getpair() readends.append(fd1) writeends.append(fd2) iwtd, owtd, ewtd = select.select(readends, [], [], 0) @@ -184,7 +184,7 @@ write end non-writable before testing its selectability. -exarkun) """ import select - readend, writeend = getpair() + readend, writeend = self.getpair() readend.close() try: iwtd, owtd, ewtd = select.select([], [writeend], []) @@ -193,6 +193,21 @@ finally: writeend.close() + def test_select_bug(self): + import select, os + read, write = os.pipe() + pid = os.fork() + if pid == 0: + os._exit(0) + else: + os.close(read) + os.waitpid(pid, 0) + res = select.select([write], [write], [write]) + assert len(res[0]) == 1 + assert len(res[1]) == 1 + assert len(res[2]) == 0 + assert res[0][0] == res[1][0] + class AppTestSelectWithPipes(_AppTestSelect): "Use a pipe to get pairs of file descriptors" def setup_class(cls): @@ -202,7 +217,7 @@ cls.space = space # Wraps a file descriptor in an socket-like object - space.exec_('''if 1: + cls.w_getpair = space.appexec([], '''(): import os class FileAsSocket: def __init__(self, fd): @@ -217,19 +232,18 @@ return os.close(self.fd) def getpair(): s1, s2 = os.pipe() - return FileAsSocket(s1), FileAsSocket(s2)''', - space.builtin.w_dict, space.builtin.w_dict) + return FileAsSocket(s1), FileAsSocket(s2) + return getpair''') class AppTestSelectWithSockets(_AppTestSelect): """Same tests with connected sockets. socket.socketpair() does not exists on win32, so we start our own server.""" def setup_class(cls): - space = gettestobjspace(usemodules=('select',)) + space = gettestobjspace(usemodules=('select','_socket')) cls.space = space - space.setitem(space.builtin.w_dict, space.wrap('getpair'), - space.wrap(cls.getsocketpair)) + cls.w_getpair = space.wrap(cls.getsocketpair) import socket cls.sock = socket.socket() @@ -259,3 +273,4 @@ s1, addr2 = cls.sock.accept() return s1, s2 + From fijal at codespeak.net Wed Jun 25 06:16:30 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 25 Jun 2008 06:16:30 +0200 (CEST) Subject: [pypy-svn] r56057 - pypy/dist/pypy/module/select Message-ID: <20080625041630.F00F92A8078@codespeak.net> Author: fijal Date: Wed Jun 25 06:16:30 2008 New Revision: 56057 Modified: pypy/dist/pypy/module/select/app_select.py Log: A fix for a test. Not sure exactly why this is an issue. Copied from http://twistedmatrix.com/trac/ticket/3218 (last comment) Modified: pypy/dist/pypy/module/select/app_select.py ============================================================================== --- pypy/dist/pypy/module/select/app_select.py (original) +++ pypy/dist/pypy/module/select/app_select.py Wed Jun 25 06:16:30 2008 @@ -66,9 +66,12 @@ else: ret = dict(p.poll()) + #iretd = [ f for f in iwtd if ret.get(fddict[id(f)], 0) & (POLLIN|POLLHUP|POLLERR)] + #oretd = [ f for f in owtd if ret.get(fddict[id(f)], 0) & POLLOUT] + #eretd = [ f for f in ewtd if ret.get(fddict[id(f)], 0) & (POLLERR|POLLPRI)] iretd = [ f for f in iwtd if ret.get(fddict[id(f)], 0) & (POLLIN|POLLHUP|POLLERR)] - oretd = [ f for f in owtd if ret.get(fddict[id(f)], 0) & POLLOUT] - eretd = [ f for f in ewtd if ret.get(fddict[id(f)], 0) & (POLLERR|POLLPRI)] + oretd = [ f for f in owtd if ret.get(fddict[id(f)], 0) & (POLLOUT|POLLERR)] + eretd = [ f for f in ewtd if ret.get(fddict[id(f)], 0) & POLLPRI] return iretd, oretd, eretd From fijal at codespeak.net Wed Jun 25 06:48:08 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 25 Jun 2008 06:48:08 +0200 (CEST) Subject: [pypy-svn] r56058 - pypy/dist/pypy/module/gc Message-ID: <20080625044808.D4BDE169E2C@codespeak.net> Author: fijal Date: Wed Jun 25 06:48:05 2008 New Revision: 56058 Modified: pypy/dist/pypy/module/gc/interp_gc.py Log: CPython's gc.collect returns number of unreachable cycles. In our case this is always 0 Modified: pypy/dist/pypy/module/gc/interp_gc.py ============================================================================== --- pypy/dist/pypy/module/gc/interp_gc.py (original) +++ pypy/dist/pypy/module/gc/interp_gc.py Wed Jun 25 06:48:05 2008 @@ -5,6 +5,7 @@ def collect(space): "Run a full collection." rgc.collect() + return space.wrap(0) collect.unwrap_spec = [ObjSpace] From antocuni at codespeak.net Wed Jun 25 16:04:59 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 25 Jun 2008 16:04:59 +0200 (CEST) Subject: [pypy-svn] r56068 - pypy/branch/oo-jit/pypy/annotation Message-ID: <20080625140459.03D45169E87@codespeak.net> Author: antocuni Date: Wed Jun 25 16:04:59 2008 New Revision: 56068 Modified: pypy/branch/oo-jit/pypy/annotation/annrpython.py Log: use py.code.Source instead of a plain exec Modified: pypy/branch/oo-jit/pypy/annotation/annrpython.py ============================================================================== --- pypy/branch/oo-jit/pypy/annotation/annrpython.py (original) +++ pypy/branch/oo-jit/pypy/annotation/annrpython.py Wed Jun 25 16:04:59 2008 @@ -770,18 +770,20 @@ d = {} for opname in model.UNARY_OPERATIONS: fnname = 'consider_op_' + opname - exec """ + src = py.code.Source(""" def consider_op_%s(self, arg, *args): return arg.%s(*args) -""" % (opname, opname) in globals(), d +""" % (opname, opname)) + exec src.compile() in globals(), d setattr(cls, fnname, d[fnname]) # All binary operations for opname in model.BINARY_OPERATIONS: fnname = 'consider_op_' + opname - exec """ + src = py.code.Source(""" def consider_op_%s(self, arg1, arg2, *args): return pair(arg1,arg2).%s(*args) -""" % (opname, opname) in globals(), d +""" % (opname, opname)) + exec src.compile() in globals(), d setattr(cls, fnname, d[fnname]) _registeroperations = classmethod(_registeroperations) From arigo at codespeak.net Thu Jun 26 10:46:48 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 10:46:48 +0200 (CEST) Subject: [pypy-svn] r56083 - pypy/branch/async-del Message-ID: <20080626084648.233162A0151@codespeak.net> Author: arigo Date: Thu Jun 26 10:46:47 2008 New Revision: 56083 Added: pypy/branch/async-del/ - copied from r56082, pypy/dist/ Log: issue371 in-progress A branch in which to avoid having app-level __del__() methods called from random places. From arigo at codespeak.net Thu Jun 26 11:25:39 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 11:25:39 +0200 (CEST) Subject: [pypy-svn] r56084 - pypy/branch/async-del/pypy/objspace/std/test Message-ID: <20080626092539.6E05C169F5B@codespeak.net> Author: arigo Date: Thu Jun 26 11:25:37 2008 New Revision: 56084 Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Log: A test that shows what all this is about. Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Thu Jun 26 11:25:37 2008 @@ -737,3 +737,16 @@ # does not crash l.remove(5) assert l[10:] == [0, 1, 2, 3, 4, 6, 7, 8, 9] + + def test_mutate_while_extend(self): + # this segfaults pypy-c (try py.test -A) + class A(object): + def __del__(self): + print 'del' + del lst[:] + keepalive = [] + for i in range(10): + lst = list(str(i)) * 100 + A() + while lst: + keepalive.append(lst[:]) From arigo at codespeak.net Thu Jun 26 11:26:12 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 11:26:12 +0200 (CEST) Subject: [pypy-svn] r56085 - in pypy/branch/async-del/pypy: interpreter interpreter/test module/gc Message-ID: <20080626092612.7EE2C169F5B@codespeak.net> Author: arigo Date: Thu Jun 26 11:26:11 2008 New Revision: 56085 Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py pypy/branch/async-del/pypy/interpreter/executioncontext.py pypy/branch/async-del/pypy/interpreter/test/test_typedef.py pypy/branch/async-del/pypy/interpreter/typedef.py pypy/branch/async-del/pypy/module/gc/interp_gc.py Log: Attempting to fix the issue by delaying calls to app-level dels. Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/async-del/pypy/interpreter/baseobjspace.py Thu Jun 26 11:26:11 2008 @@ -1,4 +1,4 @@ -from pypy.interpreter.executioncontext import ExecutionContext +from pypy.interpreter.executioncontext import ExecutionContext, UserDelAction from pypy.interpreter.error import OperationError from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack from pypy.interpreter.pycompiler import CPythonCompiler, PythonAstCompiler @@ -137,6 +137,9 @@ self.setweakref(lifeline.space, None) lifeline.clear_all_weakrefs() + def _call_builtin_destructor(self): + pass # method overridden in typedef.py + class Wrappable(W_Root): """A subclass of Wrappable is an internal, interpreter-level class @@ -218,7 +221,8 @@ import pypy.interpreter.nestedscope # register *_DEREF bytecodes self.interned_strings = {} - self.pending_actions = [] + self.user_del_action = UserDelAction(self) + self.pending_actions = [self.user_del_action] self.setoptions(**kw) # if self.config.objspace.logbytecodes: Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 11:26:11 2008 @@ -118,9 +118,9 @@ def _do_bytecode_trace(self, frame): if self.ticker < 0: + self.ticker = self.space.sys.checkinterval Action.perform_actions(self.space.pending_actions) Action.perform_actions(self.pending_actions) - self.ticker = self.space.sys.checkinterval if frame.w_f_trace is None or self.is_tracing: return code = frame.pycode @@ -278,3 +278,42 @@ raise Exception("ExecutionContext instances should not be seen during" " translation. Now is a good time to inspect the" " traceback and see where this one comes from :-)") + + +class UserDelAction(Action): + """An action that invokes all pending app-level __del__() method. + This is done as an action instead of immediately when the + interp-level __del__() is invoked, because the latter can occur more + or less anywhere in the middle of code that might not be happy with + random app-level code mutating data structures under its feet. + """ + def __init__(self, space): + self.space = space + self.dying_objects_w = [] + + def register_dying_object(self, w_obj): + self.dying_objects_w.append(w_obj) + # XXX should force the action to occur as soon as possible. + # "space.getexectuion().ticker = 0" is both expensive and not + # exactly what we need because it's ok if the action occurs + # in any thread + + def perform(self): + # Each call to perform() first grabs the self.dying_objects_w + # and replaces it with an empty list. We do this to try to + # avoid too deep recursions of the kind of __del__ being called + # while in the middle of another __del__ call. + pending_w = self.dying_objects_w + if len(pending_w) == 0: + return # shortcut + self.dying_objects_w = [] + space = self.space + for w_obj in pending_w: + try: + space.userdel(w_obj) + except OperationError, e: + e.write_unraisable(space, 'method __del__ of ', w_obj) + e.clear(space) # break up reference cycles + # finally, this calls the interp-level destructor for the + # cases where there is both an app-level and a built-in __del__. + w_obj._call_builtin_destructor() Modified: pypy/branch/async-del/pypy/interpreter/test/test_typedef.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/test/test_typedef.py (original) +++ pypy/branch/async-del/pypy/interpreter/test/test_typedef.py Thu Jun 26 11:26:11 2008 @@ -1,4 +1,5 @@ from pypy.interpreter import typedef +from pypy.tool.udir import udir # this test isn't so much to test that the objspace interface *works* # -- it's more to test that it's *there* @@ -130,3 +131,27 @@ for cls, set in subclasses.items(): assert len(set) <= 6, "%s has %d subclasses:\n%r" % ( cls, len(set), [subcls.__name__ for subcls in set]) + + +class AppTestTypeDef: + + def setup_class(cls): + path = udir.join('AppTestTypeDef.txt') + path.write('hello world\n') + cls.w_path = cls.space.wrap(str(path)) + + def test_destructor(self): + import gc, os + seen = [] + class MyFile(file): + def __del__(self): + seen.append(10) + seen.append(os.lseek(self.fileno(), 2, 0)) + f = MyFile(self.path, 'r') + fd = f.fileno() + seen.append(os.lseek(fd, 5, 0)) + del f + gc.collect(); gc.collect(); gc.collect() + lst = seen[:] + assert lst == [5, 10, 2] + raises(OSError, os.lseek, fd, 7, 0) Modified: pypy/branch/async-del/pypy/interpreter/typedef.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/typedef.py (original) +++ pypy/branch/async-del/pypy/interpreter/typedef.py Thu Jun 26 11:26:11 2008 @@ -9,7 +9,7 @@ DescrMismatch from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import compile2, func_with_new_name -from pypy.rlib.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate, we_are_translated from pypy.rlib.rarithmetic import intmask class TypeDef: @@ -247,12 +247,27 @@ add(Proto) if "del" in features: - parent_destructor = getattr(supercls, '__del__', None) class Proto(object): + _del_was_called = False def __del__(self): - call_user_destructor(self.space, self) - if parent_destructor is not None: - parent_destructor(self) + # the logic below always resurect the objects, so when + # running on top of CPython we must manually ensure that + # we do it only once + if not we_are_translated(): + if self._del_was_called: + return + self._del_was_called = True + self.clear_all_weakrefs() + self.space.user_del_action.register_dying_object(self) + # if the base class needs its own interp-level __del__, + # we override the _call_builtin_destructor() method to invoke it + # after the app-level destructor. + parent_destructor = getattr(supercls, '__del__', None) + if parent_destructor is not None: + def _call_builtin_destructor(self): + parent_destructor(self) + Proto._call_builtin_destructor = _call_builtin_destructor + add(Proto) if "slots" in features: @@ -323,15 +338,6 @@ return w_dict check_new_dictionary._dont_inline_ = True -def call_user_destructor(space, w_self): - w_self.clear_all_weakrefs() - try: - space.userdel(w_self) - except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_self) - e.clear(space) # break up reference cycles -call_user_destructor._dont_inline_ = True - # ____________________________________________________________ def make_descr_typecheck_wrapper(func, extraargs=(), cls=None): Modified: pypy/branch/async-del/pypy/module/gc/interp_gc.py ============================================================================== --- pypy/branch/async-del/pypy/module/gc/interp_gc.py (original) +++ pypy/branch/async-del/pypy/module/gc/interp_gc.py Thu Jun 26 11:26:11 2008 @@ -5,6 +5,7 @@ def collect(space): "Run a full collection." rgc.collect() + space.user_del_action.perform() return space.wrap(0) collect.unwrap_spec = [ObjSpace] From arigo at codespeak.net Thu Jun 26 13:08:31 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 13:08:31 +0200 (CEST) Subject: [pypy-svn] r56086 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080626110831.E95692A8005@codespeak.net> Author: arigo Date: Thu Jun 26 13:08:30 2008 New Revision: 56086 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py Log: Duh. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 13:08:30 2008 @@ -287,6 +287,8 @@ or less anywhere in the middle of code that might not be happy with random app-level code mutating data structures under its feet. """ + repeat = True + def __init__(self, space): self.space = space self.dying_objects_w = [] From arigo at codespeak.net Thu Jun 26 18:12:12 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 18:12:12 +0200 (CEST) Subject: [pypy-svn] r56088 - in pypy/branch/async-del/pypy: interpreter module/signal module/sys translator/c/src Message-ID: <20080626161212.431D2169FD6@codespeak.net> Author: arigo Date: Thu Jun 26 18:12:10 2008 New Revision: 56088 Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py pypy/branch/async-del/pypy/interpreter/executioncontext.py pypy/branch/async-del/pypy/module/signal/__init__.py pypy/branch/async-del/pypy/module/signal/interp_signal.py pypy/branch/async-del/pypy/module/sys/vm.py pypy/branch/async-del/pypy/translator/c/src/signals.h Log: Intermediate check-in. Refactoring the "periodic actions" approach. This should allow signals and app-level destructors to be handled promptly, i.e. before the next opcode is run (so far they have to wait for up to sys.checkinterval opcodes). The 2nd goal is to decrease the overhead in the fast path of executioncontext.bytecode_trace() by making the checks here simpler. It also seems that a non-threaded pypy-c doesn't even need to increment a bytecode counter there. Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/async-del/pypy/interpreter/baseobjspace.py Thu Jun 26 18:12:10 2008 @@ -1,4 +1,5 @@ from pypy.interpreter.executioncontext import ExecutionContext, UserDelAction +from pypy.interpreter.executioncontext import ActionFlag from pypy.interpreter.error import OperationError from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack from pypy.interpreter.pycompiler import CPythonCompiler, PythonAstCompiler @@ -221,8 +222,9 @@ import pypy.interpreter.nestedscope # register *_DEREF bytecodes self.interned_strings = {} + self.actionflag = ActionFlag() # changed by the signal module self.user_del_action = UserDelAction(self) - self.pending_actions = [self.user_del_action] + self.register_async_action(self.user_del_action) self.setoptions(**kw) # if self.config.objspace.logbytecodes: Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 18:12:10 2008 @@ -1,6 +1,8 @@ import sys from pypy.interpreter.miscutils import Stack, Action from pypy.interpreter.error import OperationError +from pypy.rlib.rarithmetic import LONG_BIT +from pypy.rlib.unroll import unrolling_iterable def new_framestack(): return Stack() @@ -19,8 +21,6 @@ self.framestack = new_framestack() self.w_tracefunc = None self.is_tracing = 0 - self.ticker = 0 - self.pending_actions = [] self.compiler = space.createcompiler() self.profilefunc = None self.w_profilefuncarg = None @@ -110,17 +110,17 @@ "Trace function called before each bytecode." # this is split into a fast path and a slower path that is # not invoked every time bytecode_trace() is. - ticker = self.ticker - 1 - self.ticker = ticker - if ticker < 0 or frame.w_f_trace is not None: - self._do_bytecode_trace(frame) + actionflag = self.space.actionflag + ticker = actionflag.get() + if actionflag.has_bytecode_counter: # this "if" is constant-folded + ticker += 1 + actionflag.set(ticker) + if ticker & actionflag.interesting_bits: # fast check + actionflag.action_dispatcher() # slow path bytecode_trace._always_inline_ = True def _do_bytecode_trace(self, frame): - if self.ticker < 0: - self.ticker = self.space.sys.checkinterval - Action.perform_actions(self.space.pending_actions) - Action.perform_actions(self.pending_actions) + ./. if frame.w_f_trace is None or self.is_tracing: return code = frame.pycode @@ -164,7 +164,8 @@ self._trace(frame, 'line', self.space.w_None) frame.instr_prev = frame.last_instr - + _do_bytecode_trace._dont_inline_ = True + def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() @@ -280,14 +281,137 @@ " traceback and see where this one comes from :-)") +class ActionFlag: + """This holds the global 'action flag'. It is a single bitfield + integer, with bits corresponding to AsyncAction objects that need to + be immediately triggered. The correspondance from bits to + AsyncAction instances is built at translation time. We can quickly + check if there is anything at all to do by checking if any of the + relevant bits is set. If threads are enabled, they consume the 20 + lower bits to hold a counter incremented at each bytecode, to know + when to release the GIL. + """ + def __init__(self): + self.__flags = 0 + self._periodic_actions = [] + self._nonperiodic_actions = [] + self.unused_bits = self.FREE_BITS[:] + self.has_bytecode_counter = False + self.interesting_bits = 0 + self._rebuild_action_dispatcher() + + # '__flags' is "very private" -- don't access it even from elsewhere + # in this class. The get()/set() accessors are meant to be overriden + # by the signal module, if it is used. + def get(self): + return self.__flags + + def set(self, value): + self.__flags = value + + def fire(self, action): + """Request for the action to be run before the next opcode. + The action must have been registered at space initalization time.""" + ticker = self.get() + self.set(ticker | action.bitmask) + + def register_action(self, action): + "NOT_RPYTHON" + assert isinstance(action, AsyncAction) + if action.bitmask == 'auto': + while True: + action.bitmask = self.unused_bits.pop(0) + if not (action.bitmask & self.interesting_bits): + break + self.interesting_bits |= action.bitmask + if action.bitmask & self.BYTECODE_COUNTER_OVERFLOW_BIT: + assert action.bitmask == self.BYTECODE_COUNTER_OVERFLOW_BIT + self._periodic_actions.append(action) + self.has_bytecode_counter = True + else: + self._nonperiodic_actions.append((action, action.bitmask)) + self._rebuild_action_dispatcher() + + def setcheckinterval(self, space, interval): + if interval < self.CHECK_INTERVAL_MIN: + interval = self.CHECK_INTERVAL_MIN + elif interval > self.CHECK_INTERVAL_MAX: + interval = self.CHECK_INTERVAL_MAX + space.sys.checkinterval = interval + # force the tick counter to a correct value + ticker = self.get() + ticker |= self.BYTECODE_COUNTER_MASK + self.set(ticker) + + def _rebuild_action_dispatcher(self): + periodic_actions = unrolling_iterable(self._periodic_actions) + nonperiodic_actions = unrolling_iterable(self._nonperiodic_actions) + has_bytecode_counter = self.has_bytecode_counter + + def action_dispatcher(ec): + # periodic actions + if has_bytecode_counter: + ticker = self.get() + if ticker & self.BYTECODE_COUNTER_OVERFLOW_BIT: + # We must run the periodic actions now, but first + # reset the bytecode counter (the following logic + # works because the BYTECODE_COUNTER_OVERFLOW_BIT + # is currently set) + ticker &= ~ self.BYTECODE_COUNTER_MASK + ticker -= ec.space.sys.checkinterval + self.set(ticker) + for action in periodic_actions: + action.perform() + + # nonperiodic actions + for action, bitmask in nonperiodic_actions: + ticker = self.get() + if ticker & bitmask: + self.set(ticker & ~ bitmask) + action.perform() + + action_dispatcher._dont_inline_ = True + self.action_dispatcher = action_dispatcher + + # Bits reserved for the bytecode counter, if used + BYTECODE_COUNTER_MASK = (1 << 20) - 1 + BYTECODE_COUNTER_OVERFLOW_BIT = (1 << 20) + + # Free bits + FREE_BITS = [1 << _b for _b in range(21, LONG_BIT)] + + # The acceptable range of values for sys.checkinterval, so that + # the bytecode_counter fits in 20 bits + CHECK_INTERVAL_MIN = 1 + CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT + + +class AsyncAction(object): + """Abstract base class for actions that must be performed + asynchronously with regular bytecode execution, but that still need + to occur between two opcodes, not at a completely random time. + """ + bitmask = 'auto' + + def perform(self): + """To be overridden.""" + + +class PeriodicAsyncAction(AsyncAction): + """Abstract base class for actions that occur automatically + every sys.checkinterval bytecodes. + """ + bitmask = ActionFlag.BYTECODE_COUNTER_OVERFLOW_BIT + + class UserDelAction(Action): + ./. """An action that invokes all pending app-level __del__() method. This is done as an action instead of immediately when the interp-level __del__() is invoked, because the latter can occur more or less anywhere in the middle of code that might not be happy with random app-level code mutating data structures under its feet. """ - repeat = True def __init__(self, space): self.space = space Modified: pypy/branch/async-del/pypy/module/signal/__init__.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/__init__.py (original) +++ pypy/branch/async-del/pypy/module/signal/__init__.py Thu Jun 26 18:12:10 2008 @@ -25,7 +25,11 @@ def __init__(self, space, *args): "NOT_RPYTHON" - from pypy.module.signal.interp_signal import CheckSignalAction + from pypy.module.signal import interp_signal MixedModule.__init__(self, space, *args) # add the signal-checking callback as an action on the space - space.pending_actions.append(CheckSignalAction(space)) + space.pending_actions.append(interp_signal.CheckSignalAction(space)) + # use the C-level pypysig_occurred variable as the tick counter + space.actionflag.get = interp_signal.pypysig_get_occurred + space.actionflag.set = interp_signal.pypysig_set_occurred + Modified: pypy/branch/async-del/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/interp_signal.py (original) +++ pypy/branch/async-del/pypy/module/signal/interp_signal.py Thu Jun 26 18:12:10 2008 @@ -35,6 +35,11 @@ # don't bother releasing the GIL around a call to pypysig_poll: it's # pointless and a performance issue +pypysig_get_occurred = external('pypysig_get_occurred', [], + lltype.Signed, _nowrapper=True) +pypysig_set_occurred = external('pypysig_set_occurred', [lltype.Signed], + lltype.Void, _nowrapper=True) + class CheckSignalAction(Action): """A repeatitive action at the space level, checking if the signal_occurred flag is set and if so, scheduling ReportSignal actions. Modified: pypy/branch/async-del/pypy/module/sys/vm.py ============================================================================== --- pypy/branch/async-del/pypy/module/sys/vm.py (original) +++ pypy/branch/async-del/pypy/module/sys/vm.py Thu Jun 26 18:12:10 2008 @@ -2,6 +2,7 @@ Implementation of interpreter-level 'sys' routines. """ from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import ObjSpace import sys # ____________________________________________________________ @@ -57,11 +58,11 @@ return space.wrap(space.sys.recursionlimit) -def setcheckinterval(space, w_interval): +def setcheckinterval(space, interval): """Tell the Python interpreter to check for asynchronous events every n instructions. This also affects how often thread switches occur.""" - space.sys.checkinterval = space.int_w(w_interval) - space.getexecutioncontext().ticker = 0 + space.actionflag.setcheckinterval(space, interval) +setcheckinterval.unwrap_spec = [ObjSpace, int] def getcheckinterval(space): """Return the current check interval; see setcheckinterval().""" Modified: pypy/branch/async-del/pypy/translator/c/src/signals.h ============================================================================== --- pypy/branch/async-del/pypy/translator/c/src/signals.h (original) +++ pypy/branch/async-del/pypy/translator/c/src/signals.h Thu Jun 26 18:12:10 2008 @@ -49,12 +49,25 @@ /* utility to poll for signals that arrived */ int pypysig_poll(void); /* => signum or -1 */ +/* When a signal is received, the high bit of pypysig_occurred is set. + After all signals are processed by pypysig_poll(), the high bit is + cleared again. The variable is exposed and RPython code is free to + use the other bits in any way. */ +#define PENDING_SIGNAL_BIT (LONG_MIN) /* high bit */ +extern long pypysig_occurred; + +/* inlinable helpers to get/set the variable as efficiently as possible */ +static long pypysig_get_occurred(void) { return pypysig_occurred; } +static void pypysig_set_occurred(long x) { pypysig_occurred = x; } + /************************************************************/ /* Implementation */ #ifndef PYPY_NOT_MAIN_FILE -static volatile int pypysig_occurred; + +long pypysig_occurred; +static volatile long *pypysig_occurred_v = (volatile long *)&pypysig_occurred; static volatile int pypysig_flags[NSIG]; void pypysig_ignore(int signum) @@ -89,7 +102,9 @@ { if (0 <= signum && signum < NSIG) pypysig_flags[signum] = 1; - pypysig_occurred = 1; + /* the point of "*pypysig_occurred_v" instead of just "pypysig_occurred" + is the volatile declaration */ + *pypysig_occurred_v |= PENDING_SIGNAL_BIT; } void pypysig_setflag(int signum) @@ -108,15 +123,16 @@ int pypysig_poll(void) { - if (pypysig_occurred) + if (pypysig_occurred & PENDING_SIGNAL_BIT) { int i; - pypysig_occurred = 0; + pypysig_occurred &= ~PENDING_SIGNAL_BIT; for (i=0; i Author: fijal Date: Thu Jun 26 19:03:35 2008 New Revision: 56089 Modified: pypy/extradoc/sprintinfo/post-ep2008/people.txt Log: my dates Modified: pypy/extradoc/sprintinfo/post-ep2008/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/post-ep2008/people.txt (original) +++ pypy/extradoc/sprintinfo/post-ep2008/people.txt Thu Jun 26 19:03:35 2008 @@ -12,6 +12,7 @@ ==================== ============== ============================ Antonio Cuni 6-13 http://www.jnn.lt/ Holger Krekel 6-13 http://www.litinterp.lt/ +Maciej Fijalkowski 6-13 http://www.jnn.lt/ ==================== ============== ============================ People on the following list were present at previous sprints: @@ -19,7 +20,6 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== -Maciej Fijalkowski ? ? Samuele Pedroni ? ? Armin Rigo ? ? Carl Friedrich Bolz ? ? From arigo at codespeak.net Thu Jun 26 21:22:27 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:22:27 +0200 (CEST) Subject: [pypy-svn] r56090 - in pypy/branch/async-del/pypy: interpreter interpreter/test module/_file Message-ID: <20080626192227.00EE4698173@codespeak.net> Author: arigo Date: Thu Jun 26 21:22:26 2008 New Revision: 56090 Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py pypy/branch/async-del/pypy/interpreter/executioncontext.py pypy/branch/async-del/pypy/interpreter/miscutils.py pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py pypy/branch/async-del/pypy/interpreter/test/test_pyframe.py pypy/branch/async-del/pypy/module/_file/interp_stream.py Log: Still in-progress. Added some tests. Modified: pypy/branch/async-del/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/async-del/pypy/interpreter/baseobjspace.py Thu Jun 26 21:22:26 2008 @@ -1,5 +1,5 @@ -from pypy.interpreter.executioncontext import ExecutionContext, UserDelAction -from pypy.interpreter.executioncontext import ActionFlag +from pypy.interpreter.executioncontext import ExecutionContext, ActionFlag +from pypy.interpreter.executioncontext import UserDelAction, FrameTraceAction from pypy.interpreter.error import OperationError from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack from pypy.interpreter.pycompiler import CPythonCompiler, PythonAstCompiler @@ -224,7 +224,9 @@ self.interned_strings = {} self.actionflag = ActionFlag() # changed by the signal module self.user_del_action = UserDelAction(self) - self.register_async_action(self.user_del_action) + self.frame_trace_action = FrameTraceAction(self) + self.actionflag.register_action(self.user_del_action) + self.actionflag.register_action(self.frame_trace_action) self.setoptions(**kw) # if self.config.objspace.logbytecodes: Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 21:22:26 2008 @@ -1,5 +1,5 @@ import sys -from pypy.interpreter.miscutils import Stack, Action +from pypy.interpreter.miscutils import Stack from pypy.interpreter.error import OperationError from pypy.rlib.rarithmetic import LONG_BIT from pypy.rlib.unroll import unrolling_iterable @@ -19,6 +19,9 @@ def __init__(self, space): self.space = space self.framestack = new_framestack() + # tracing: space.frame_trace_action.fire() must be called to ensure + # that tracing occurs whenever self.w_tracefunc or self.is_tracing + # is modified. self.w_tracefunc = None self.is_tracing = 0 self.compiler = space.createcompiler() @@ -61,6 +64,7 @@ ec.profilefunc = self.profilefunc ec.w_profilefuncarg = self.w_profilefuncarg ec.is_tracing = self.is_tracing + ec.space.frame_trace_action.fire() def leave(self, ec): self.framestack = ec.framestack @@ -116,56 +120,9 @@ ticker += 1 actionflag.set(ticker) if ticker & actionflag.interesting_bits: # fast check - actionflag.action_dispatcher() # slow path + actionflag.action_dispatcher(self) # slow path bytecode_trace._always_inline_ = True - def _do_bytecode_trace(self, frame): - ./. - if frame.w_f_trace is None or self.is_tracing: - return - code = frame.pycode - if frame.instr_lb <= frame.last_instr < frame.instr_ub: - if frame.last_instr <= frame.instr_prev: - # We jumped backwards in the same line. - self._trace(frame, 'line', self.space.w_None) - else: - size = len(code.co_lnotab) / 2 - addr = 0 - line = code.co_firstlineno - p = 0 - lineno = code.co_lnotab - while size > 0: - c = ord(lineno[p]) - if (addr + c) > frame.last_instr: - break - addr += c - if c: - frame.instr_lb = addr - - line += ord(lineno[p + 1]) - p += 2 - size -= 1 - - if size > 0: - while True: - size -= 1 - if size < 0: - break - addr += ord(lineno[p]) - if ord(lineno[p + 1]): - break - p += 2 - frame.instr_ub = addr - else: - frame.instr_ub = sys.maxint - - if frame.instr_lb == frame.last_instr: # At start of line! - frame.f_lineno = line - self._trace(frame, 'line', self.space.w_None) - - frame.instr_prev = frame.last_instr - _do_bytecode_trace._dont_inline_ = True - def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() @@ -188,6 +145,7 @@ self.w_tracefunc = None else: self.w_tracefunc = w_func + self.space.frame_trace_action.fire() def setprofile(self, w_func): """Set the global trace function.""" @@ -208,6 +166,7 @@ is_tracing = self.is_tracing self.is_tracing = 0 try: + self.space.frame_trace_action.fire() return self.space.call(w_func, w_args) finally: self.is_tracing = is_tracing @@ -271,10 +230,6 @@ frame.last_exception = last_exception self.is_tracing -= 1 - def add_pending_action(self, action): - self.pending_actions.append(action) - self.ticker = 0 - def _freeze_(self): raise Exception("ExecutionContext instances should not be seen during" " translation. Now is a good time to inspect the" @@ -328,6 +283,7 @@ assert action.bitmask == self.BYTECODE_COUNTER_OVERFLOW_BIT self._periodic_actions.append(action) self.has_bytecode_counter = True + self.force_tick_counter() else: self._nonperiodic_actions.append((action, action.bitmask)) self._rebuild_action_dispatcher() @@ -338,7 +294,11 @@ elif interval > self.CHECK_INTERVAL_MAX: interval = self.CHECK_INTERVAL_MAX space.sys.checkinterval = interval - # force the tick counter to a correct value + self.force_tick_counter() + + def force_tick_counter(self): + # force the tick counter to a valid value -- this actually forces + # it to reach BYTECODE_COUNTER_OVERFLOW_BIT at the next opcode. ticker = self.get() ticker |= self.BYTECODE_COUNTER_MASK self.set(ticker) @@ -361,14 +321,14 @@ ticker -= ec.space.sys.checkinterval self.set(ticker) for action in periodic_actions: - action.perform() + action.perform(ec) # nonperiodic actions for action, bitmask in nonperiodic_actions: ticker = self.get() if ticker & bitmask: self.set(ticker & ~ bitmask) - action.perform() + action.perform(ec) action_dispatcher._dont_inline_ = True self.action_dispatcher = action_dispatcher @@ -382,8 +342,8 @@ # The acceptable range of values for sys.checkinterval, so that # the bytecode_counter fits in 20 bits - CHECK_INTERVAL_MIN = 1 - CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT + CHECK_INTERVAL_MIN = 1 + CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT class AsyncAction(object): @@ -393,7 +353,15 @@ """ bitmask = 'auto' - def perform(self): + def __init__(self, space): + self.space = space + + def fire(self): + """Request for the action to be run before the next opcode. + The action must have been registered at space initalization time.""" + self.space.actionflag.fire(self) + + def perform(self, executioncontext): """To be overridden.""" @@ -404,8 +372,7 @@ bitmask = ActionFlag.BYTECODE_COUNTER_OVERFLOW_BIT -class UserDelAction(Action): - ./. +class UserDelAction(AsyncAction): """An action that invokes all pending app-level __del__() method. This is done as an action instead of immediately when the interp-level __del__() is invoked, because the latter can occur more @@ -414,24 +381,19 @@ """ def __init__(self, space): - self.space = space + AsyncAction.__init__(self, space) self.dying_objects_w = [] def register_dying_object(self, w_obj): self.dying_objects_w.append(w_obj) - # XXX should force the action to occur as soon as possible. - # "space.getexectuion().ticker = 0" is both expensive and not - # exactly what we need because it's ok if the action occurs - # in any thread + self.fire() - def perform(self): + def perform(self, executioncontext): # Each call to perform() first grabs the self.dying_objects_w # and replaces it with an empty list. We do this to try to # avoid too deep recursions of the kind of __del__ being called # while in the middle of another __del__ call. pending_w = self.dying_objects_w - if len(pending_w) == 0: - return # shortcut self.dying_objects_w = [] space = self.space for w_obj in pending_w: @@ -443,3 +405,54 @@ # finally, this calls the interp-level destructor for the # cases where there is both an app-level and a built-in __del__. w_obj._call_builtin_destructor() + + +class FrameTraceAction(AsyncAction): + """An action that calls the local trace functions (w_f_trace).""" + + def perform(self, executioncontext): + frame = executioncontext.framestack.top() + if frame.w_f_trace is None or executioncontext.is_tracing: + return + code = frame.pycode + if frame.instr_lb <= frame.last_instr < frame.instr_ub: + if frame.last_instr <= frame.instr_prev: + # We jumped backwards in the same line. + executioncontext._trace(frame, 'line', self.space.w_None) + else: + size = len(code.co_lnotab) / 2 + addr = 0 + line = code.co_firstlineno + p = 0 + lineno = code.co_lnotab + while size > 0: + c = ord(lineno[p]) + if (addr + c) > frame.last_instr: + break + addr += c + if c: + frame.instr_lb = addr + + line += ord(lineno[p + 1]) + p += 2 + size -= 1 + + if size > 0: + while True: + size -= 1 + if size < 0: + break + addr += ord(lineno[p]) + if ord(lineno[p + 1]): + break + p += 2 + frame.instr_ub = addr + else: + frame.instr_ub = sys.maxint + + if frame.instr_lb == frame.last_instr: # At start of line! + frame.f_lineno = line + executioncontext._trace(frame, 'line', self.space.w_None) + + frame.instr_prev = frame.last_instr + self.space.frame_trace_action.fire() # continue tracing Modified: pypy/branch/async-del/pypy/interpreter/miscutils.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/miscutils.py (original) +++ pypy/branch/async-del/pypy/interpreter/miscutils.py Thu Jun 26 21:22:26 2008 @@ -167,26 +167,3 @@ def getmainthreadvalue(self): return self._value - - -class Action(object): - """Abstract base class for actions that must be performed regularly, - every Nth bytecode (as selected by sys.setcheckinterval()).""" - - # set repeat to True for actions that must be kept around and - # re-performed regularly - repeat = False - - def perform(self): - """To be overridden.""" - - def perform_actions(actionlist): - i = 0 - while i < len(actionlist): - a = actionlist[i] - if a.repeat: - i += 1 # keep action - else: - del actionlist[i] - a.perform() - perform_actions = staticmethod(perform_actions) Modified: pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py Thu Jun 26 21:22:26 2008 @@ -1,39 +1,65 @@ import py -from pypy.interpreter import miscutils +from pypy.interpreter import executioncontext + + +class Finished(Exception): + pass class TestExecutionContext: def test_action(self): - class Finished(Exception): - pass - class DemoAction(miscutils.Action): - def __init__(self, repeat): - self.repeat = repeat - self.counter = 0 + class DemoAction(executioncontext.AsyncAction): + counter = 0 def perform(self): self.counter += 1 if self.counter == 10: raise Finished - a1 = DemoAction(False) - a2 = DemoAction(True) - a3 = DemoAction(False) + space = self.space + a1 = DemoAction(space) + space.actionflag.register_action(a1) + for i in range(20): + # assert does not raise: + space.appexec([], """(): + n = 5 + return n + 2 + """) + try: + for i in range(20): + a1.fire() + space.appexec([], """(): + n = 5 + return n + 2 + """) + assert a1.counter == i + 1 + except Finished: + pass + assert i == 9 + + def test_periodic_action(self): + + class DemoAction(executioncontext.PeriodicAsyncAction): + counter = 0 + def perform(self): + self.counter += 1 + print '->', self.counter + if self.counter == 3: + raise Finished space = self.space - space.pending_actions.append(a1) - space.getexecutioncontext().add_pending_action(a2) - space.getexecutioncontext().add_pending_action(a3) - - py.test.raises(Finished, space.appexec, [], """(): - n = 50000 - while n > 0: - n -= 1 - """) - assert a1.counter == 1 - assert a2.counter == 10 - assert a3.counter == 1 + a2 = DemoAction(space) + space.actionflag.register_action(a2) + try: + for i in range(500): + space.appexec([], """(): + n = 5 + return n + 2 + """) + except Finished: + pass + assert space.sys.checkinterval / 10 < i < space.sys.checkinterval * 3 def test_llprofile(self): l = [] Modified: pypy/branch/async-del/pypy/interpreter/test/test_pyframe.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/test/test_pyframe.py (original) +++ pypy/branch/async-del/pypy/interpreter/test/test_pyframe.py Thu Jun 26 21:22:26 2008 @@ -73,7 +73,54 @@ raise OuterException except: g(sys.exc_info()) - + + def test_trace_basic(self): + import sys + l = [] + class Tracer: + def __init__(self, i): + self.i = i + def trace(self, frame, event, arg): + l.append((self.i, frame.f_code.co_name, event, arg)) + if frame.f_code.co_name == 'g2': + return None # don't trace g2 + return Tracer(self.i+1).trace + def g3(n): + n -= 5 + return n + def g2(n): + n += g3(2) + n += g3(7) + return n + def g(n): + n += g2(3) + return n + def f(n): + n = g(n) + return n * 7 + sys.settrace(Tracer(0).trace) + x = f(4) + sys.settrace(None) + assert x == 42 + print l + assert l == [(0, 'f', 'call', None), + (1, 'f', 'line', None), + (0, 'g', 'call', None), + (1, 'g', 'line', None), + (0, 'g2', 'call', None), + (0, 'g3', 'call', None), + (1, 'g3', 'line', None), + (2, 'g3', 'line', None), + (3, 'g3', 'return', -3), + (0, 'g3', 'call', None), + (1, 'g3', 'line', None), + (2, 'g3', 'line', None), + (3, 'g3', 'return', 2), + (2, 'g', 'line', None), + (3, 'g', 'return', 6), + (2, 'f', 'line', None), + (3, 'f', 'return', 42)] + def test_trace_exc(self): import sys l = [] Modified: pypy/branch/async-del/pypy/module/_file/interp_stream.py ============================================================================== --- pypy/branch/async-del/pypy/module/_file/interp_stream.py (original) +++ pypy/branch/async-del/pypy/module/_file/interp_stream.py Thu Jun 26 21:22:26 2008 @@ -7,7 +7,6 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.miscutils import Action import os @@ -25,14 +24,6 @@ def wrap_oserror_as_ioerror(space, e): assert isinstance(e, OSError) errno = e.errno - if errno == EINTR: - # A signal was sent to the process and interupted - # a systemcall. We want to trigger running of - # any installed interrupt handlers. - # XXX: is there a better way? - ec = space.getexecutioncontext() - Action.perform_actions(space.pending_actions) - Action.perform_actions(ec.pending_actions) try: msg = os.strerror(errno) except ValueError: From arigo at codespeak.net Thu Jun 26 21:27:06 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:27:06 +0200 (CEST) Subject: [pypy-svn] r56091 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080626192706.F332A2A017F@codespeak.net> Author: arigo Date: Thu Jun 26 21:27:03 2008 New Revision: 56091 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py Log: Minimal fix for test_pyframe. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 21:27:03 2008 @@ -43,6 +43,8 @@ def leave(self, frame): if self.profilefunc: self._trace(frame, 'leaveframe', None) + # xxx optimize a bit + self.space.frame_trace_action.fire() if not frame.hide(): self.framestack.pop() From arigo at codespeak.net Thu Jun 26 21:29:02 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:29:02 +0200 (CEST) Subject: [pypy-svn] r56092 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080626192902.761372A017F@codespeak.net> Author: arigo Date: Thu Jun 26 21:28:58 2008 New Revision: 56092 Modified: pypy/branch/async-del/pypy/interpreter/pyframe.py Log: Obscure cases, untested :-/ Modified: pypy/branch/async-del/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/pyframe.py (original) +++ pypy/branch/async-del/pypy/interpreter/pyframe.py Thu Jun 26 21:28:58 2008 @@ -348,6 +348,7 @@ new_frame.instr_prev = space.int_w(w_instr_prev) self._setcellvars(cellvars) + space.frame_trace_action.fire() def hide(self): return self.pycode.hidden_applevel @@ -539,6 +540,7 @@ else: self.w_f_trace = w_trace self.f_lineno = self.get_last_lineno() + space.frame_trace_action.fire() def fdel_f_trace(space, self): self.w_f_trace = None From arigo at codespeak.net Thu Jun 26 21:29:22 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:29:22 +0200 (CEST) Subject: [pypy-svn] r56093 - pypy/branch/async-del/pypy/interpreter/test Message-ID: <20080626192922.CEED42A017F@codespeak.net> Author: arigo Date: Thu Jun 26 21:29:22 2008 New Revision: 56093 Modified: pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py Log: Fix test. Modified: pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/test/test_executioncontext.py Thu Jun 26 21:29:22 2008 @@ -12,7 +12,7 @@ class DemoAction(executioncontext.AsyncAction): counter = 0 - def perform(self): + def perform(self, ec): self.counter += 1 if self.counter == 10: raise Finished @@ -42,7 +42,7 @@ class DemoAction(executioncontext.PeriodicAsyncAction): counter = 0 - def perform(self): + def perform(self, ec): self.counter += 1 print '->', self.counter if self.counter == 3: From arigo at codespeak.net Thu Jun 26 21:30:26 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:30:26 +0200 (CEST) Subject: [pypy-svn] r56094 - pypy/branch/async-del/pypy/module/gc Message-ID: <20080626193026.8F005698095@codespeak.net> Author: arigo Date: Thu Jun 26 21:30:25 2008 New Revision: 56094 Modified: pypy/branch/async-del/pypy/module/gc/interp_gc.py Log: This line is no longer necessary. Modified: pypy/branch/async-del/pypy/module/gc/interp_gc.py ============================================================================== --- pypy/branch/async-del/pypy/module/gc/interp_gc.py (original) +++ pypy/branch/async-del/pypy/module/gc/interp_gc.py Thu Jun 26 21:30:25 2008 @@ -5,7 +5,6 @@ def collect(space): "Run a full collection." rgc.collect() - space.user_del_action.perform() return space.wrap(0) collect.unwrap_spec = [ObjSpace] From arigo at codespeak.net Thu Jun 26 21:41:32 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:41:32 +0200 (CEST) Subject: [pypy-svn] r56095 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080626194132.D7EB6698133@codespeak.net> Author: arigo Date: Thu Jun 26 21:41:32 2008 New Revision: 56095 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py Log: Another potential fix. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 21:41:32 2008 @@ -43,11 +43,11 @@ def leave(self, frame): if self.profilefunc: self._trace(frame, 'leaveframe', None) - # xxx optimize a bit - self.space.frame_trace_action.fire() if not frame.hide(): self.framestack.pop() + if self.w_tracefunc is not None: + self.space.frame_trace_action.fire() class Subcontext(object): @@ -206,6 +206,7 @@ finally: self.is_tracing -= 1 frame.locals2fast() + space.frame_trace_action.fire() # Profile cases if self.profilefunc is not None: From arigo at codespeak.net Thu Jun 26 21:44:25 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 26 Jun 2008 21:44:25 +0200 (CEST) Subject: [pypy-svn] r56096 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080626194425.C78E4168571@codespeak.net> Author: arigo Date: Thu Jun 26 21:44:25 2008 New Revision: 56096 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py Log: Small optimizations for the case where we don't use tracing. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Thu Jun 26 21:44:25 2008 @@ -106,11 +106,13 @@ def call_trace(self, frame): "Trace the call of a function" - self._trace(frame, 'call', self.space.w_None) + if self.w_tracefunc is not None or self.profilefunc is not None: + self._trace(frame, 'call', self.space.w_None) def return_trace(self, frame, w_retval): "Trace the return from a function" - self._trace(frame, 'return', w_retval) + if self.w_tracefunc is not None: + self._trace(frame, 'return', w_retval) def bytecode_trace(self, frame): "Trace function called before each bytecode." @@ -128,8 +130,8 @@ def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() - space = self.space - self._trace(frame, 'exception', None, operationerr) + if self.w_tracefunc is not None: + self._trace(frame, 'exception', None, operationerr) #operationerr.print_detailed_traceback(self.space) def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!! From fijal at codespeak.net Thu Jun 26 22:26:42 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 26 Jun 2008 22:26:42 +0200 (CEST) Subject: [pypy-svn] r56098 - in pypy/dist/pypy/rlib: . test Message-ID: <20080626202642.4BA5D2A8081@codespeak.net> Author: fijal Date: Thu Jun 26 22:26:41 2008 New Revision: 56098 Modified: pypy/dist/pypy/rlib/_rsocket_rffi.py pypy/dist/pypy/rlib/rpoll.py pypy/dist/pypy/rlib/test/test_rpoll.py Log: Rpython level implementation of select with a single test Modified: pypy/dist/pypy/rlib/_rsocket_rffi.py ============================================================================== --- pypy/dist/pypy/rlib/_rsocket_rffi.py (original) +++ pypy/dist/pypy/rlib/_rsocket_rffi.py Thu Jun 26 22:26:41 2008 @@ -19,6 +19,7 @@ 'sys/un.h', 'sys/poll.h', 'sys/select.h', + 'sys/types.h', 'netinet/in.h', 'netinet/tcp.h', 'unistd.h', @@ -52,10 +53,33 @@ COND_HEADER = '' constants = {} +if _POSIX: + sources = [""" + void pypy_macro_wrapper_FD_SET(int fd, fd_set *set) + { + FD_SET(fd, set); + } + void pypy_macro_wrapper_FD_ZERO(fd_set *set) + { + FD_ZERO(set); + } + void pypy_macro_wrapper_FD_CLR(int fd, fd_set *set) + { + FD_CLR(fd, set); + } + int pypy_macro_wrapper_FD_ISSET(int fd, fd_set *set) + { + return FD_ISSET(fd, set); + } + """] + +else: + sources = [] eci = ExternalCompilationInfo( post_include_bits = [HEADER, COND_HEADER], includes = includes, libraries = libraries, + separate_module_sources = sources, ) class CConfig: @@ -183,6 +207,7 @@ ('POLLOUT', 4), ('POLLERR', 8), ('POLLHUP', 16), + ('FD_SETSIZE', 64), ] for name, default in constants_w_defaults: setattr(CConfig, name, platform.DefinedConstantInteger(name)) @@ -281,9 +306,11 @@ if _MS_WINDOWS: CConfig.fd_set = platform.Struct('struct fd_set', - [('fd_count', rffi.UINT), - # XXX use FD_SETSIZE - ('fd_array', rffi.CFixedArray(socketfd_type, 64))]) + [('fd_count', rffi.UINT), + # XXX use FD_SETSIZE + ('fd_array', rffi.CFixedArray(socketfd_type, 64))]) +else: + fd_set = rffi.COpaquePtr('fd_set', compilation_info=eci) if _MS_WINDOWS: CConfig.WSAData = platform.Struct('struct WSAData', @@ -373,16 +400,16 @@ WSAEVENT = cConfig.WSAEVENT WSANETWORKEVENTS = cConfig.WSANETWORKEVENTS timeval = cConfig.timeval -if MS_WINDOWS: +if _MS_WINDOWS: fd_set = cConfig.fd_set - -if _POSIX: - includes = list(includes) - for _name, _header in cond_includes: - if getattr(cConfig, _name) is not None: - includes.append(_header) - eci = ExternalCompilationInfo(includes=includes, libraries=libraries) +#if _POSIX: +# includes = list(includes) +# for _name, _header in cond_includes: +# if getattr(cConfig, _name) is not None: +# includes.append(_header) +# eci = ExternalCompilationInfo(includes=includes, libraries=libraries, +# separate_module_sources=sources) def external(name, args, result): return rffi.llexternal(name, args, result, compilation_info=eci, @@ -480,6 +507,16 @@ pollfdarray = rffi.CArray(pollfd) poll = external('poll', [lltype.Ptr(pollfdarray), nfds_t, rffi.INT], rffi.INT) + select = external('select', + [rffi.INT, fd_set, fd_set, + fd_set, lltype.Ptr(timeval)], + rffi.INT) + + FD_CLR = external('pypy_macro_wrapper_FD_CLR', [rffi.INT, fd_set], lltype.Void) + FD_ISSET = external('pypy_macro_wrapper_FD_ISSET', [rffi.INT, fd_set], rffi.INT) + FD_SET = external('pypy_macro_wrapper_FD_SET', [rffi.INT, fd_set], lltype.Void) + FD_ZERO = external('pypy_macro_wrapper_FD_ZERO', [fd_set], lltype.Void) + elif MS_WINDOWS: select = external('select', [rffi.INT, lltype.Ptr(fd_set), lltype.Ptr(fd_set), Modified: pypy/dist/pypy/rlib/rpoll.py ============================================================================== --- pypy/dist/pypy/rlib/rpoll.py (original) +++ pypy/dist/pypy/rlib/rpoll.py Thu Jun 26 22:26:41 2008 @@ -9,6 +9,7 @@ from pypy.rlib import _rsocket_rffi as _c from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rarithmetic import intmask, r_uint +import math # ____________________________________________________________ # events @@ -28,6 +29,12 @@ def get_msg(self): return _c.socket_strerror_str(self.errno) +class SelectError(Exception): + def __init__(self, errno): + self.errno = errno + def get_msg(self): + return _c.socket_strerror_str(self.errno) + # ____________________________________________________________ # poll() for POSIX systems # @@ -65,6 +72,63 @@ lltype.free(pollfds, flavor='raw') return retval +def select(inl, outl, excl, timeout=-1.0): + nfds = 0 + if inl: + ll_inl = lltype.malloc(_c.fd_set.TO, flavor='raw') + _c.FD_ZERO(ll_inl) + for i in inl: + _c.FD_SET(i, ll_inl) + if i > nfds: + nfds = i + else: + ll_inl = lltype.nullptr(_c.fd_set.TO) + if outl: + ll_outl = lltype.malloc(_c.fd_set.TO, flavor='raw') + _c.FD_ZERO(ll_outl) + for i in outl: + _c.FD_SET(i, ll_outl) + if i > nfds: + nfds = i + else: + ll_outl = lltype.nullptr(_c.fd_set.TO) + if excl: + ll_excl = lltype.malloc(_c.fd_set.TO, flavor='raw') + _c.FD_ZERO(ll_excl) + for i in excl: + _c.FD_SET(i, ll_excl) + if i > nfds: + nfds = i + else: + ll_excl = lltype.nullptr(_c.fd_set.TO) + if timeout != -1.0: + ll_timeval = lltype.malloc(_c.timeval, flavor='raw') + frac = math.fmod(timeout, 1.0) + ll_timeval.c_tv_sec = int(timeout) + ll_timeval.c_tv_usec = int(timeout*1000000.0) + else: + ll_timeval = lltype.nullptr(_c.timeval) + try: + res = _c.select(nfds + 1, ll_inl, ll_outl, ll_excl, ll_timeval) + if res == -1: + raise SelectError(_c.geterrno()) + if res == 0: + return ([], [], []) + else: + return ( + [i for i in inl if _c.FD_ISSET(i, ll_inl)], + [i for i in outl if _c.FD_ISSET(i, ll_outl)], + [i for i in excl if _c.FD_ISSET(i, ll_excl)]) + finally: + if ll_inl: + lltype.free(ll_inl, flavor='raw') + if ll_outl: + lltype.free(ll_outl, flavor='raw') + if ll_excl: + lltype.free(ll_excl, flavor='raw') + if ll_timeval: + lltype.free(ll_timeval, flavor='raw') + # ____________________________________________________________ # poll() for Win32 # Modified: pypy/dist/pypy/rlib/test/test_rpoll.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rpoll.py (original) +++ pypy/dist/pypy/rlib/test/test_rpoll.py Thu Jun 26 22:26:41 2008 @@ -1,6 +1,7 @@ import thread from pypy.rlib.rsocket import * from pypy.rlib.rpoll import * +from pypy.rpython.test.test_llinterp import interpret def setup_module(mod): rsocket_startup() @@ -48,6 +49,23 @@ servconn.close() serv.close() +def test_select(): + def f(): + readend, writeend = os.pipe() + try: + iwtd, owtd, ewtd = select([readend], [], [], 0.0) + assert iwtd == owtd == ewtd == [] + os.write(writeend, 'X') + iwtd, owtd, ewtd = select([readend], [], []) + assert iwtd == [readend] + assert owtd == ewtd == [] + finally: + os.close(readend) + os.close(writeend) + + f() + interpret(f, []) + def test_translate(): from pypy.translator.c.test.test_genc import compile From fijal at codespeak.net Thu Jun 26 22:50:34 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 26 Jun 2008 22:50:34 +0200 (CEST) Subject: [pypy-svn] r56099 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20080626205034.75DAA2A808A@codespeak.net> Author: fijal Date: Thu Jun 26 22:50:32 2008 New Revision: 56099 Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py Log: Cache results and don't invoke gcc over and over again Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rffi.py Thu Jun 26 22:50:32 2008 @@ -379,10 +379,14 @@ hints = hints.copy() hints['external'] = 'C' hints['c_name'] = name - def lazy_getsize(): + def lazy_getsize(cache={}): from pypy.rpython.tool import rffi_platform - k = {} - return rffi_platform.sizeof(name, compilation_info) + try: + return cache[name] + except KeyError: + val = rffi_platform.sizeof(name, compilation_info) + cache[name] = val + return val hints['getsize'] = lazy_getsize return lltype.OpaqueType(name, hints) From fijal at codespeak.net Thu Jun 26 22:52:29 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 26 Jun 2008 22:52:29 +0200 (CEST) Subject: [pypy-svn] r56100 - pypy/dist/pypy/module/select Message-ID: <20080626205229.208102A808A@codespeak.net> Author: fijal Date: Thu Jun 26 22:52:28 2008 New Revision: 56100 Modified: pypy/dist/pypy/module/select/__init__.py pypy/dist/pypy/module/select/app_select.py pypy/dist/pypy/module/select/interp_select.py Log: Implement select using select and not poll. This is somewhat faster and doesn't hang tests, which is a win already. Modified: pypy/dist/pypy/module/select/__init__.py ============================================================================== --- pypy/dist/pypy/module/select/__init__.py (original) +++ pypy/dist/pypy/module/select/__init__.py Thu Jun 26 22:52:28 2008 @@ -5,11 +5,11 @@ class Module(MixedModule): appleveldefs = { 'error': 'app_select.error', - 'select': 'app_select.select', } interpleveldefs = { 'poll' : 'interp_select.poll', + 'select': 'interp_select.select', } def buildloaders(cls): Modified: pypy/dist/pypy/module/select/app_select.py ============================================================================== --- pypy/dist/pypy/module/select/app_select.py (original) +++ pypy/dist/pypy/module/select/app_select.py Thu Jun 26 22:52:28 2008 @@ -1,77 +1,2 @@ class error(Exception): pass - -def as_fd(f): - if not isinstance(f, (int, long)): - try: - fileno = f.fileno - except AttributeError: - raise TypeError("argument must be an int, or have a fileno() method.") - f = f.fileno() - if not isinstance(f, (int, long)): - raise TypeError("fileno() returned a non-integer") - fd = int(f) - if fd < 0 or isinstance(fd, long): - raise ValueError("file descriptor cannot be a negative integer (%i)"%fd) - return fd - -def select(iwtd, owtd, ewtd, timeout=None): - """Wait until one or more file descriptors are ready for some kind of I/O. -The first three arguments are sequences of file descriptors to be waited for: -rlist -- wait until ready for reading -wlist -- wait until ready for writing -xlist -- wait for an ``exceptional condition'' -If only one kind of condition is required, pass [] for the other lists. -A file descriptor is either a socket or file object, or a small integer -gotten from a fileno() method call on one of those. - -The optional 4th argument specifies a timeout in seconds; it may be -a floating point number to specify fractions of seconds. If it is absent -or None, the call will never time out. - -The return value is a tuple of three lists corresponding to the first three -arguments; each contains the subset of the corresponding file descriptors -that are ready. - -*** IMPORTANT NOTICE *** -On Windows, only sockets are supported; on Unix, all file descriptors. -""" - iwtd = tuple(iwtd) - owtd = tuple(owtd) - ewtd = tuple(ewtd) - from select import poll, POLLIN, POLLOUT, POLLPRI, POLLERR, POLLHUP - fddict = {} - polldict = {} - fd = 0 - for f in iwtd + owtd + ewtd: - fddict[id(f)] = as_fd(f) - for f in iwtd: - fd = fddict[id(f)] - polldict[fd] = polldict.get(fd, 0) | POLLIN - for f in owtd: - fd = fddict[id(f)] - polldict[fd] = polldict.get(fd, 0) | POLLOUT - for f in ewtd: - fd = fddict[id(f)] - polldict[fd] = polldict.get(fd, 0) | POLLPRI - - p = poll() - for fd, mask in polldict.iteritems(): - p.register(fd, mask) - if timeout is not None: - if (not hasattr(timeout, '__int__') and - not hasattr(timeout, '__float__')): - raise TypeError('timeout must be a float or None') - ret = dict(p.poll(float(timeout) * 1000.0)) - else: - ret = dict(p.poll()) - - #iretd = [ f for f in iwtd if ret.get(fddict[id(f)], 0) & (POLLIN|POLLHUP|POLLERR)] - #oretd = [ f for f in owtd if ret.get(fddict[id(f)], 0) & POLLOUT] - #eretd = [ f for f in ewtd if ret.get(fddict[id(f)], 0) & (POLLERR|POLLPRI)] - iretd = [ f for f in iwtd if ret.get(fddict[id(f)], 0) & (POLLIN|POLLHUP|POLLERR)] - oretd = [ f for f in owtd if ret.get(fddict[id(f)], 0) & (POLLOUT|POLLERR)] - eretd = [ f for f in ewtd if ret.get(fddict[id(f)], 0) & POLLPRI] - - return iretd, oretd, eretd - Modified: pypy/dist/pypy/module/select/interp_select.py ============================================================================== --- pypy/dist/pypy/module/select/interp_select.py (original) +++ pypy/dist/pypy/module/select/interp_select.py Thu Jun 26 22:52:28 2008 @@ -87,3 +87,56 @@ assert method.im_func.func_code.co_argcount == len(method.unwrap_spec), methodname pollmethods[methodname] = interp2app(method, unwrap_spec=method.unwrap_spec) Poll.typedef = TypeDef('select.poll', **pollmethods) + +def select(space, w_iwtd, w_owtd, w_ewtd, w_timeout=None): + """Wait until one or more file descriptors are ready for some kind of I/O. +The first three arguments are sequences of file descriptors to be waited for: +rlist -- wait until ready for reading +wlist -- wait until ready for writing +xlist -- wait for an ``exceptional condition'' +If only one kind of condition is required, pass [] for the other lists. +A file descriptor is either a socket or file object, or a small integer +gotten from a fileno() method call on one of those. + +The optional 4th argument specifies a timeout in seconds; it may be +a floating point number to specify fractions of seconds. If it is absent +or None, the call will never time out. + +The return value is a tuple of three lists corresponding to the first three +arguments; each contains the subset of the corresponding file descriptors +that are ready. + +*** IMPORTANT NOTICE *** +On Windows, only sockets are supported; on Unix, all file descriptors. +""" + + iwtd_w = space.unpackiterable(w_iwtd) + owtd_w = space.unpackiterable(w_owtd) + ewtd_w = space.unpackiterable(w_ewtd) + iwtd = [as_fd_w(space, w_f) for w_f in iwtd_w] + owtd = [as_fd_w(space, w_f) for w_f in owtd_w] + ewtd = [as_fd_w(space, w_f) for w_f in ewtd_w] + iwtd_d = {} + owtd_d = {} + ewtd_d = {} + for i in range(len(iwtd)): + iwtd_d[iwtd[i]] = iwtd_w[i] + for i in range(len(owtd)): + owtd_d[owtd[i]] = owtd_w[i] + for i in range(len(ewtd)): + ewtd_d[ewtd[i]] = ewtd_w[i] + try: + if space.is_w(w_timeout, space.w_None): + iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd) + else: + iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd, space.float_w(w_timeout)) + except rpoll.SelectErorr, s: + w_module = space.getbuiltinmodule('select') + w_errortype = space.getattr(w_module, space.wrap('error')) + raise OperationError(w_errortype, space.newtuple( + space.wrap(s.errno), space.wrap(s.get_msg()))) + + return space.newtuple([ + space.newlist([iwtd_d[i] for i in iwtd]), + space.newlist([owtd_d[i] for i in owtd]), + space.newlist([ewtd_d[i] for i in ewtd])]) From fijal at codespeak.net Thu Jun 26 22:57:04 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 26 Jun 2008 22:57:04 +0200 (CEST) Subject: [pypy-svn] r56101 - pypy/dist/pypy/module/select Message-ID: <20080626205704.297162A80CF@codespeak.net> Author: fijal Date: Thu Jun 26 22:57:03 2008 New Revision: 56101 Modified: pypy/dist/pypy/module/select/interp_select.py Log: typo Modified: pypy/dist/pypy/module/select/interp_select.py ============================================================================== --- pypy/dist/pypy/module/select/interp_select.py (original) +++ pypy/dist/pypy/module/select/interp_select.py Thu Jun 26 22:57:03 2008 @@ -130,7 +130,7 @@ iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd) else: iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd, space.float_w(w_timeout)) - except rpoll.SelectErorr, s: + except rpoll.SelectError, s: w_module = space.getbuiltinmodule('select') w_errortype = space.getattr(w_module, space.wrap('error')) raise OperationError(w_errortype, space.newtuple( From fijal at codespeak.net Thu Jun 26 23:19:39 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 26 Jun 2008 23:19:39 +0200 (CEST) Subject: [pypy-svn] r56102 - pypy/dist/pypy/module/select Message-ID: <20080626211939.D99DC169FDA@codespeak.net> Author: fijal Date: Thu Jun 26 23:19:39 2008 New Revision: 56102 Modified: pypy/dist/pypy/module/select/interp_select.py Log: Fix translation Modified: pypy/dist/pypy/module/select/interp_select.py ============================================================================== --- pypy/dist/pypy/module/select/interp_select.py (original) +++ pypy/dist/pypy/module/select/interp_select.py Thu Jun 26 23:19:39 2008 @@ -133,8 +133,8 @@ except rpoll.SelectError, s: w_module = space.getbuiltinmodule('select') w_errortype = space.getattr(w_module, space.wrap('error')) - raise OperationError(w_errortype, space.newtuple( - space.wrap(s.errno), space.wrap(s.get_msg()))) + raise OperationError(w_errortype, space.newtuple([ + space.wrap(s.errno), space.wrap(s.get_msg())])) return space.newtuple([ space.newlist([iwtd_d[i] for i in iwtd]), From fijal at codespeak.net Fri Jun 27 06:47:45 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 06:47:45 +0200 (CEST) Subject: [pypy-svn] r56106 - pypy/dist/pypy/interpreter Message-ID: <20080627044745.BFBAA698095@codespeak.net> Author: fijal Date: Fri Jun 27 06:47:43 2008 New Revision: 56106 Modified: pypy/dist/pypy/interpreter/module.py Log: Don't explode when __file__ is missing or bogus Modified: pypy/dist/pypy/interpreter/module.py ============================================================================== --- pypy/dist/pypy/interpreter/module.py (original) +++ pypy/dist/pypy/interpreter/module.py Fri Jun 27 06:47:43 2008 @@ -71,6 +71,9 @@ name = space.str_w(space.repr(self.w_name)) if isinstance(self, MixedModule): return space.wrap("" % name) - w___file__ = space.getattr(self, space.wrap('__file__')) - __file__ = space.str_w(space.repr(w___file__)) + try: + w___file__ = space.getattr(self, space.wrap('__file__')) + __file__ = space.str_w(space.repr(w___file__)) + except OperationError: + __file__ = '?' return space.wrap("" % (name, __file__)) From exarkun at codespeak.net Fri Jun 27 14:16:42 2008 From: exarkun at codespeak.net (exarkun at codespeak.net) Date: Fri, 27 Jun 2008 14:16:42 +0200 (CEST) Subject: [pypy-svn] r56116 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080627121642.E617F169F7F@codespeak.net> Author: exarkun Date: Fri Jun 27 14:16:42 2008 New Revision: 56116 Modified: pypy/dist/pypy/interpreter/module.py pypy/dist/pypy/interpreter/test/test_module.py Log: test and fix for r56106 Modified: pypy/dist/pypy/interpreter/module.py ============================================================================== --- pypy/dist/pypy/interpreter/module.py (original) +++ pypy/dist/pypy/interpreter/module.py Fri Jun 27 14:16:42 2008 @@ -3,6 +3,7 @@ """ from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.error import OperationError class Module(Wrappable): """A module.""" Modified: pypy/dist/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_module.py (original) +++ pypy/dist/pypy/interpreter/test/test_module.py Fri Jun 27 14:16:42 2008 @@ -63,3 +63,5 @@ assert r.startswith("') + nofile = type(_exceptions)('nofile', 'foo') + assert repr(nofile) == "" From antocuni at codespeak.net Fri Jun 27 17:04:25 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 27 Jun 2008 17:04:25 +0200 (CEST) Subject: [pypy-svn] r56124 - pypy/branch/less-meta-instances/pypy/translator/jvm Message-ID: <20080627150425.3CFF06980B3@codespeak.net> Author: antocuni Date: Fri Jun 27 17:04:24 2008 New Revision: 56124 Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/opcodes.py Log: implement classof Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/opcodes.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/opcodes.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/opcodes.py Fri Jun 27 17:04:24 2008 @@ -79,6 +79,7 @@ 'oodowncast': [DownCast, StoreResult], 'instanceof': [CastTo, StoreResult], 'subclassof': [PushAllArgs, jvm.SWAP, jvm.CLASSISASSIGNABLEFROM, StoreResult], + 'classof': [PushAllArgs, jvm.OBJECTGETCLASS, StoreResult], 'ooidentityhash': [PushAllArgs, jvm.OBJHASHCODE, StoreResult], 'oohash': [PushAllArgs, jvm.OBJHASHCODE, StoreResult], 'oostring': [OOString, StoreResult], From niko at codespeak.net Fri Jun 27 18:09:40 2008 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 27 Jun 2008 18:09:40 +0200 (CEST) Subject: [pypy-svn] r56125 - in pypy/branch/less-meta-instances/pypy/translator: cli/test jvm jvm/src/pypy jvm/test oosupport/test_template Message-ID: <20080627160940.EA45269808F@codespeak.net> Author: niko Date: Fri Jun 27 18:09:38 2008 New Revision: 56125 Added: pypy/branch/less-meta-instances/pypy/translator/jvm/src/pypy/PyPyThrowable.java pypy/branch/less-meta-instances/pypy/translator/oosupport/test_template/exception.py Modified: pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py pypy/branch/less-meta-instances/pypy/translator/jvm/database.py pypy/branch/less-meta-instances/pypy/translator/jvm/node.py pypy/branch/less-meta-instances/pypy/translator/jvm/test/test_exception.py pypy/branch/less-meta-instances/pypy/translator/jvm/typesystem.py Log: start fixing jvm: test try_nested in test/test_exceptions still doesn't work Modified: pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py Fri Jun 27 18:09:38 2008 @@ -1,6 +1,6 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_exception import BaseTestException +from pypy.translator.oosupport.test_template.exception import BaseTestException class TestCliException(CliTest, BaseTestException): use_exception_transformer = False @@ -9,73 +9,12 @@ kwds['exctrans'] = self.use_exception_transformer return CliTest.interpret(self, *args, **kwds) - def test_nested_try(self): - def helper(x): - if x == 0: - raise ValueError - def dummy(): - pass - def fn(x): - try: - try: - helper(x) - finally: - dummy() - except ValueError, e: - raise - - self.interpret_raises(ValueError, fn, [0]) - - def test_exception_not_last(self): - def helper(x): - if x == 0: - raise ValueError - def fn(x): - helper(x) - try: - helper(1) - finally: - return -1 - return x - self.interpret_raises(ValueError, fn, [0]) - def test_raise_and_catch_other(self): pass def test_raise_prebuilt_and_catch_other(self): pass - def test_missing_return_block(self): - class Base: - def foo(self): - raise ValueError - - class Derived(Base): - def foo(self): - return 42 - - def fn(x): - if x: - obj = Base() - else: - obj = Derived() - return obj.foo() - assert self.interpret(fn, [0]) == 42 - - def test_missing_handler(self): - def foo(x): - if x: - raise ValueError - - def fn(x): - try: - foo(x) - except ValueError: - raise - return 42 - assert self.interpret(fn, [0], backendopt=False) == 42 - self.interpret_raises(ValueError, fn, [1], backendopt=False) - class TestCliExceptionTransformer(TestCliException): use_exception_transformer = True Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/database.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/database.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/database.py Fri Jun 27 18:09:38 2008 @@ -40,11 +40,11 @@ self._constants = {} # flowmodel.Variable --> jvm.Const - # Special fields for the Object class, see _translate_Object - self._object_interf = None - self._object_impl = None - self._object_exc_impl = None - +# # Special fields for the Object class, see _translate_Object +# self._object_interf = None +# self._object_impl = None +# self._object_exc_impl = None +# # Create information about the Main class we will build: # # It will have two static fields, 'ilink' and 'pypy'. The @@ -182,67 +182,6 @@ self.pending_node(clsobj) return clsobj - def _translate_Object(self, OBJ): - """ - We handle the class 'Object' quite specially: we translate it - into an interface with two implementations. One - implementation serves as the root of most objects, and the - other as the root for all exceptions. - """ - assert self.is_Object(OBJ) - assert OBJ._superclass == ootype.ROOT - - # Have we already translated Object? - if self._object_interf: return self._object_interf - - # Create the interface and two implementations: - def gen_name(): return self._pkg(self._uniq(OBJ._name)) - internm, implnm, exc_implnm = gen_name(), gen_name(), gen_name() - self._object_interf = node.Interface(internm) - self._object_impl = node.Class(implnm, supercls=jvm.jObject) - self._object_exc_impl = node.Class(exc_implnm, supercls=jvm.jThrowable) - self._object_impl.add_interface(self._object_interf) - self._object_exc_impl.add_interface(self._object_interf) - - # Translate the fields into properties on the interface, - # and into actual fields on the implementations. - for fieldnm, (FIELDOOTY, fielddef) in OBJ._fields.iteritems(): - if FIELDOOTY is ootype.Void: continue - fieldty = self.lltype_to_cts(FIELDOOTY) - - # Currently use hacky convention of _jvm_FieldName for the name - methodnm = "_jvm_"+fieldnm - - def getter_method_obj(node): - return jvm.Method.v(node, methodnm+"_g", [], fieldty) - def putter_method_obj(node): - return jvm.Method.v(node, methodnm+"_p", [fieldty], jvm.jVoid) - - # Add get/put methods to the interface: - prop = jvm.Property( - fieldnm, - getter_method_obj(self._object_interf), - putter_method_obj(self._object_interf), - OOTYPE=FIELDOOTY) - self._object_interf.add_property(prop) - - # Generate implementations: - def generate_impl(clsobj): - clsnm = clsobj.name - fieldobj = jvm.Field(clsnm, fieldnm, fieldty, False, FIELDOOTY) - clsobj.add_field(fieldobj, fielddef) - clsobj.add_method(node.GetterFunction( - self, clsobj, getter_method_obj(clsobj), fieldobj)) - clsobj.add_method(node.PutterFunction( - self, clsobj, putter_method_obj(clsobj), fieldobj)) - generate_impl(self._object_impl) - generate_impl(self._object_exc_impl) - - # Ensure that we generate all three classes. - self.pending_node(self._object_interf) - self.pending_node(self._object_impl) - self.pending_node(self._object_exc_impl) - def _translate_superclass_of(self, OOSUB): """ Invoked to translate OOSUB's super class. Normally just invokes @@ -250,12 +189,9 @@ make all exceptions descend from Throwable. """ OOSUPER = OOSUB._superclass - if not self.is_Object(OOSUPER): - return self.pending_class(OOSUPER) - self._translate_Object(OOSUPER) # ensure this has been done if OOSUB._name == "exceptions.Exception": - return self._object_exc_impl - return self._object_impl + return jvm.jPyPyThrowable + return self.pending_class(OOSUPER) def _translate_instance(self, OOTYPE): assert isinstance(OOTYPE, ootype.Instance) @@ -564,15 +500,6 @@ TP = annotation_to_lltype(s_tp) return self.lltype_to_cts(TP) - def exception_root_object(self): - """ - Returns a JvmType representing the version of Object that - serves as the root of all exceptions. - """ - self.lltype_to_cts(rclass.OBJECT) - assert self._object_interf - return self._object_exc_impl - # _________________________________________________________________ # Uh.... # Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/node.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/node.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/node.py Fri Jun 27 18:09:38 2008 @@ -22,7 +22,8 @@ from pypy.translator.jvm.typesystem import \ JvmGeneratedClassType, jString, jStringArray, jVoid, jThrowable, jInt, \ jObject, JvmType, jStringBuilder, jPyPyInterlink, jCallbackInterfaces, \ - JvmGeneratedInterfaceType, jPyPy, jPyPyAbstractMethodException + JvmGeneratedInterfaceType, jPyPy, jPyPyAbstractMethodException, \ + jPyPyThrowable, OBJECTGETCLASS from pypy.translator.jvm.opcodes import \ opcodes from pypy.translator.jvm.option import \ @@ -173,8 +174,7 @@ gen.goto(done_printing) gen.end_try() - jexc = self.db.exception_root_object() - gen.begin_catch(jexc) + gen.begin_catch(jPyPyThrowable) gen.emit(jvm.PYPYDUMPEXCWRAPPER) # dumps to stdout gen.end_catch() @@ -366,7 +366,7 @@ def begin_catch(self, llexitcase): ll_meta_exc = llexitcase - ll_exc = ll_meta_exc._inst.class_._INSTANCE + ll_exc = ll_meta_exc._INSTANCE jtype = self.cts.lltype_to_cts(ll_exc) assert jtype.throwable # SHOULD only try to catch subtypes of Exception self.ilasm.begin_catch(jtype) @@ -384,11 +384,12 @@ else: # the exception value is on the stack, store it in the proper place if isinstance(link.last_exception, flowmodel.Variable): - self.ilasm.emit(jvm.DUP) + # if the code that follows is interested in the class + # of the exception, extract it + #self.ilasm.dup_jtype(jPyPyThrowable) self.ilasm.store(link.last_exc_value) - fld = self.db.lltype_to_cts(rclass.OBJECT).lookup_field('meta') - self.ilasm.emit(fld) - self.ilasm.store(link.last_exception) + #self.ilasm.emit(OBJECTGETCLASS) + #self.ilasm.store(link.last_exception) else: self.ilasm.store(link.last_exc_value) self._setup_link(link) @@ -450,8 +451,15 @@ can_branch_directly(last_op.opname) and not_in_link_args(block.exitswitch)): + self.generator.add_comment( + "short-circuit final comparison on %s, block has %d ops" % ( + block.exitswitch, len(block.operations))) + for op in block.operations[:-1]: self._render_op(op) + + self.generator.add_comment( + "inlining comparison: %r" % (last_op),) for arg in last_op.args: self.ilasm.load(arg) truelink, falselink = true_false_exits() @@ -503,12 +511,12 @@ self.ilasm.load(exc) # Check whether the static type is known to be throwable. - # If not, emit a CHECKCAST to the base exception type. + # If not, emit a CHECKCAST to throwable. # According to Samuele, no non-Exceptions should be thrown, # but this is not enforced by the RTyper or annotator. jtype = self.db.lltype_to_cts(exc.concretetype) if not jtype.throwable: - self.ilasm.downcast_jtype(self.db.exception_root_object()) + self.ilasm.downcast_jtype(jThrowable) self.ilasm.throw() Added: pypy/branch/less-meta-instances/pypy/translator/jvm/src/pypy/PyPyThrowable.java ============================================================================== --- (empty file) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/src/pypy/PyPyThrowable.java Fri Jun 27 18:09:38 2008 @@ -0,0 +1,8 @@ +package pypy; + +// This class is used as the superclass of RPython's +// exception.Exception class. We use this rather than Throwable +// because it makes it easy to catch RPython exceptions in our +// automated tests (just catch any PyPyThrowable instance) +public class PyPyThrowable extends Throwable +{} \ No newline at end of file Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/test/test_exception.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/test/test_exception.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/test/test_exception.py Fri Jun 27 18:09:38 2008 @@ -1,57 +1,11 @@ import py from pypy.translator.jvm.test.runtest import JvmTest -from pypy.rpython.test.test_exception import BaseTestException +from pypy.translator.oosupport.test_template.exception import BaseTestException class TestJvmException(JvmTest, BaseTestException): - def test_nested_try(self): - def helper(x): - if x == 0: - raise ValueError - def dummy(): - pass - def fn(x): - try: - try: - helper(x) - finally: - dummy() - except ValueError, e: - raise - - self.interpret_raises(ValueError, fn, [0]) - - def test_exception_not_last(self): - def helper(x): - if x == 0: - raise ValueError - def fn(x): - helper(x) - try: - helper(1) - finally: - return -1 - return x - self.interpret_raises(ValueError, fn, [0]) def test_raise_and_catch_other(self): pass def test_raise_prebuilt_and_catch_other(self): pass - - def test_missing_return_block(self): - class Base: - def foo(self): - raise ValueError - - class Derived(Base): - def foo(self): - return 42 - - def fn(x): - if x: - obj = Base() - else: - obj = Derived() - return obj.foo() - assert self.interpret(fn, [0]) == 42 Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/typesystem.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/typesystem.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/typesystem.py Fri Jun 27 18:09:38 2008 @@ -186,6 +186,7 @@ jCharClass = JvmClassType('java.lang.Character') jBoolClass = JvmClassType('java.lang.Boolean') jThrowable = JvmClassType('java.lang.Throwable', throwable=True) +jPyPyThrowable = JvmClassType('pypy.PyPyThrowable', throwable=True) jObject = JvmClassType('java.lang.Object') jString = JvmClassType('java.lang.String') jCharSequence = JvmClassType('java.lang.CharSequence') Added: pypy/branch/less-meta-instances/pypy/translator/oosupport/test_template/exception.py ============================================================================== --- (empty file) +++ pypy/branch/less-meta-instances/pypy/translator/oosupport/test_template/exception.py Fri Jun 27 18:09:38 2008 @@ -0,0 +1,51 @@ +import py +from pypy.rpython.test.test_exception \ + import BaseTestException as RBaseTestException + +class BaseTestException(RBaseTestException): + def test_nested_try(self): + def helper(x): + if x == 0: + raise ValueError + def dummy(): + pass + def fn(x): + try: + try: + helper(x) + finally: + dummy() + except ValueError, e: + raise + + self.interpret_raises(ValueError, fn, [0]) + + def test_exception_not_last(self): + def helper(x): + if x == 0: + raise ValueError + def fn(x): + helper(x) + try: + helper(1) + finally: + return -1 + return x + self.interpret_raises(ValueError, fn, [0]) + + def test_missing_return_block(self): + class Base: + def foo(self): + raise ValueError + + class Derived(Base): + def foo(self): + return 42 + + def fn(x): + if x: + obj = Base() + else: + obj = Derived() + return obj.foo() + assert self.interpret(fn, [0]) == 42 From niko at codespeak.net Fri Jun 27 18:24:22 2008 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 27 Jun 2008 18:24:22 +0200 (CEST) Subject: [pypy-svn] r56126 - pypy/branch/less-meta-instances/pypy/translator/jvm Message-ID: <20080627162422.BDC9D6980B3@codespeak.net> Author: niko Date: Fri Jun 27 18:24:21 2008 New Revision: 56126 Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/node.py Log: uncomment the code in the if which stores both the exception class and value. this fixes various tests in test_exception. Modified: pypy/branch/less-meta-instances/pypy/translator/jvm/node.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/jvm/node.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/jvm/node.py Fri Jun 27 18:24:21 2008 @@ -386,10 +386,10 @@ if isinstance(link.last_exception, flowmodel.Variable): # if the code that follows is interested in the class # of the exception, extract it - #self.ilasm.dup_jtype(jPyPyThrowable) + self.ilasm.dup_jtype(jPyPyThrowable) self.ilasm.store(link.last_exc_value) - #self.ilasm.emit(OBJECTGETCLASS) - #self.ilasm.store(link.last_exception) + self.ilasm.emit(OBJECTGETCLASS) + self.ilasm.store(link.last_exception) else: self.ilasm.store(link.last_exc_value) self._setup_link(link) From arigo at codespeak.net Fri Jun 27 18:33:13 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 27 Jun 2008 18:33:13 +0200 (CEST) Subject: [pypy-svn] r56127 - in pypy/branch/async-del/pypy: interpreter module/signal module/thread translator/c/src Message-ID: <20080627163313.AEE2716801B@codespeak.net> Author: arigo Date: Fri Jun 27 18:33:10 2008 New Revision: 56127 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py pypy/branch/async-del/pypy/module/signal/__init__.py pypy/branch/async-del/pypy/module/signal/interp_signal.py pypy/branch/async-del/pypy/module/thread/gil.py pypy/branch/async-del/pypy/translator/c/src/signals.h Log: Not completely nice, but this should make signals and threads work again. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Fri Jun 27 18:33:10 2008 @@ -343,7 +343,7 @@ BYTECODE_COUNTER_OVERFLOW_BIT = (1 << 20) # Free bits - FREE_BITS = [1 << _b for _b in range(21, LONG_BIT)] + FREE_BITS = [1 << _b for _b in range(21, LONG_BIT-1)] # The acceptable range of values for sys.checkinterval, so that # the bytecode_counter fits in 20 bits @@ -366,6 +366,14 @@ The action must have been registered at space initalization time.""" self.space.actionflag.fire(self) + def fire_after_thread_switch(self): + """Bit of a hack: fire() the action but only the next time the GIL + is released and re-acquired (i.e. after a portential thread switch). + Don't call this if threads are not enabled. + """ + from pypy.module.thread.gil import spacestate + spacestate.set_actionflag_bit_after_thread_switch |= self.bitmask + def perform(self, executioncontext): """To be overridden.""" Modified: pypy/branch/async-del/pypy/module/signal/__init__.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/__init__.py (original) +++ pypy/branch/async-del/pypy/module/signal/__init__.py Fri Jun 27 18:33:10 2008 @@ -28,8 +28,10 @@ from pypy.module.signal import interp_signal MixedModule.__init__(self, space, *args) # add the signal-checking callback as an action on the space - space.pending_actions.append(interp_signal.CheckSignalAction(space)) - # use the C-level pypysig_occurred variable as the tick counter + space.check_signal_action = interp_signal.CheckSignalAction(space) + space.actionflag.register_action(space.check_signal_action) + # use the C-level pypysig_occurred variable as the action flag + # (the result is that the C-level signal handler will directly + # set the flag for the CheckSignalAction) space.actionflag.get = interp_signal.pypysig_get_occurred space.actionflag.set = interp_signal.pypysig_set_occurred - Modified: pypy/branch/async-del/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/interp_signal.py (original) +++ pypy/branch/async-del/pypy/module/signal/interp_signal.py Fri Jun 27 18:33:10 2008 @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace -from pypy.interpreter.miscutils import Action +from pypy.interpreter.executioncontext import AsyncAction +from pypy.rlib.rarithmetic import LONG_BIT, intmask import signal as cpy_signal from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -40,55 +41,89 @@ pypysig_set_occurred = external('pypysig_set_occurred', [lltype.Signed], lltype.Void, _nowrapper=True) -class CheckSignalAction(Action): - """A repeatitive action at the space level, checking if the - signal_occurred flag is set and if so, scheduling ReportSignal actions. - """ - repeat = True +class CheckSignalAction(AsyncAction): + """An action that is automatically invoked when a signal is received.""" + + # The C-level signal handler sets the highest bit of pypysig_occurred: + bitmask = intmask(1 << (LONG_BIT-1)) def __init__(self, space): - self.space = space + AsyncAction.__init__(self, space) self.handlers_w = {} + if space.config.objspace.usemodules.thread: + # need a helper action in case signals arrive in a non-main thread + self.pending_signals = {} + self.reissue_signal_action = ReissueSignalAction(space) + space.actionflag.register_action(self.reissue_signal_action) + else: + self.reissue_signal_action = None - def perform(self): + def perform(self, executioncontext): while True: n = pypysig_poll() if n < 0: break - main_ec = self.space.threadlocals.getmainthreadvalue() - main_ec.add_pending_action(ReportSignal(self, n)) + if self.reissue_signal_action is None: + # no threads: we can report the signal immediately + self.report_signal(n) + else: + main_ec = self.space.threadlocals.getmainthreadvalue() + if executioncontext is main_ec: + # running in the main thread: we can report the + # signal immediately + self.report_signal(n) + else: + # running in another thread: we need to hack a bit + self.pending_signals[n] = None + self.reissue_signal_action.fire_after_thread_switch() - def get(space): - for action in space.pending_actions: - if isinstance(action, CheckSignalAction): - return action - raise OperationError(space.w_RuntimeError, - space.wrap("lost CheckSignalAction")) - get = staticmethod(get) - - -class ReportSignal(Action): - """A one-shot action for the main thread's execution context.""" - - def __init__(self, action, signum): - self.action = action - self.signum = signum - - def perform(self): + def report_signal(self, n): try: - w_handler = self.action.handlers_w[self.signum] + w_handler = self.handlers_w[n] except KeyError: return # no handler, ignore signal # re-install signal handler, for OSes that clear it - pypysig_setflag(self.signum) + pypysig_setflag(n) # invoke the app-level handler - space = self.action.space + space = self.space ec = space.getexecutioncontext() try: w_frame = ec.framestack.top() except IndexError: w_frame = space.w_None - space.call_function(w_handler, space.wrap(self.signum), w_frame) + space.call_function(w_handler, space.wrap(n), w_frame) + + def report_pending_signals(self): + # XXX this logic isn't so complicated but I have no clue how + # to test it :-( + pending_signals = self.pending_signals.keys() + self.pending_signals.clear() + try: + while pending_signals: + self.report_signal(pending_signals.pop()) + finally: + # in case of exception, put the undelivered signals back + # into the dict instead of silently swallowing them + if pending_signals: + for n in pending_signals: + self.pending_signals[n] = None + self.reissue_signal_action.fire() + + +class ReissueSignalAction(AsyncAction): + """A special action to help deliver signals to the main thread. If + a non-main thread caught a signal, this action fires after every + thread switch until we land in the main thread. + """ + + def perform(self): + main_ec = self.space.threadlocals.getmainthreadvalue() + if executioncontext is main_ec: + # now running in the main thread: we can really report the signals + self.space.check_signal_action.report_pending_signals() + else: + # still running in some other thread: try again later + self.fire_after_thread_switch() def getsignal(space, signum): @@ -101,7 +136,7 @@ None -- if an unknown handler is in effect (XXX UNIMPLEMENTED) anything else -- the callable Python object used as a handler """ - action = CheckSignalAction.get(space) + action = space.check_signal_action if signum in action.handlers_w: return action.handlers_w[signum] return space.wrap(SIG_DFL) @@ -129,7 +164,7 @@ raise OperationError(space.w_ValueError, space.wrap("signal() must be called from the " "main thread")) - action = CheckSignalAction.get(space) + action = space.check_signal_action if space.eq_w(w_handler, space.wrap(SIG_DFL)): pypysig_default(signum) action.handlers_w[signum] = w_handler Modified: pypy/branch/async-del/pypy/module/thread/gil.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/gil.py (original) +++ pypy/branch/async-del/pypy/module/thread/gil.py Fri Jun 27 18:33:10 2008 @@ -42,6 +42,7 @@ # test_compile_lock. As a workaround, we repatch these global # fields systematically. spacestate.ll_GIL = self.ll_GIL + spacestate.actionflag = space.actionflag invoke_around_extcall(before_external_call, after_external_call) return result @@ -68,9 +69,22 @@ class SpaceState: + def _freeze_(self): self.ll_GIL = thread.null_ll_lock + self.actionflag = None + self.set_actionflag_bit_after_thread_switch = 0 return False + + def after_thread_switch(self): + # this is support logic for the signal module, to help it deliver + # signals to the main thread. + actionflag = self.actionflag + if actionflag is not None: + flag = actionflag.get() + flag |= self.set_actionflag_bit_after_thread_switch + actionflag.set(flag) + spacestate = SpaceState() # Fragile code below. We have to preserve the C-level errno manually... @@ -87,5 +101,6 @@ e = get_errno() thread.acquire_NOAUTO(spacestate.ll_GIL, True) thread.gc_thread_run() + spacestate.after_thread_switch() set_errno(e) after_external_call._gctransformer_hint_cannot_collect_ = True Modified: pypy/branch/async-del/pypy/translator/c/src/signals.h ============================================================================== --- pypy/branch/async-del/pypy/translator/c/src/signals.h (original) +++ pypy/branch/async-del/pypy/translator/c/src/signals.h Fri Jun 27 18:33:10 2008 @@ -4,6 +4,8 @@ #ifndef _PYPY_SIGNALS_H #define _PYPY_SIGNALS_H +#include "Python.h" /* XXX for LONG_MIN */ + #include #ifdef MS_WINDOWS @@ -56,9 +58,19 @@ #define PENDING_SIGNAL_BIT (LONG_MIN) /* high bit */ extern long pypysig_occurred; -/* inlinable helpers to get/set the variable as efficiently as possible */ -static long pypysig_get_occurred(void) { return pypysig_occurred; } -static void pypysig_set_occurred(long x) { pypysig_occurred = x; } +/* some C tricks to get/set the variable as efficiently as possible: + use macros when compiling as a stand-alone program, but still + export a function with the correct name for testing */ +#undef pypysig_get_occurred +#undef pypysig_set_occurred +long pypysig_get_occurred(void); +void pypysig_set_occurred(long x); +#ifndef PYPY_NOT_MAIN_FILE +long pypysig_get_occurred(void) { return pypysig_occurred; } +void pypysig_set_occurred(long x) { pypysig_occurred = x; } +#endif +#define pypysig_get_occurred() (pypysig_occurred) +#define pypysig_set_occurred(x) (pypysig_occurred=(x)) /************************************************************/ /* Implementation */ @@ -123,10 +135,15 @@ int pypysig_poll(void) { - if (pypysig_occurred & PENDING_SIGNAL_BIT) + /* the two commented out lines below are useful for performance in + normal usage of pypysig_poll(); however, pypy/module/signal/ is + not normal usage. It only calls pypysig_poll() if the + PENDING_SIGNAL_BIT is set, and it clears that bit first. */ + +/* if (pypysig_occurred & PENDING_SIGNAL_BIT) */ { int i; - pypysig_occurred &= ~PENDING_SIGNAL_BIT; +/* pypysig_occurred &= ~PENDING_SIGNAL_BIT; */ for (i=0; i Author: antocuni Date: Fri Jun 27 18:33:47 2008 New Revision: 56128 Modified: pypy/branch/less-meta-instances/pypy/translator/cli/function.py pypy/branch/less-meta-instances/pypy/translator/cli/test/runtest.py pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py Log: because of backendopts, the various try/finally/except clauses were inlined, so the tests were not testing anything. Disable backendopts for them, and fix a bug Modified: pypy/branch/less-meta-instances/pypy/translator/cli/function.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/cli/function.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/cli/function.py Fri Jun 27 18:33:47 2008 @@ -129,10 +129,10 @@ else: # the exception value is on the stack, store it in the proper place if isinstance(link.last_exception, flowmodel.Variable): - #self.ilasm.opcode('dup') + self.ilasm.opcode('dup') self.store(link.last_exc_value) - #self.ilasm.get_field(('class Object_meta', 'Object', 'meta')) - #self.store(link.last_exception) + self.ilasm.call_method('[mscorlib]System.Type object::GetType()', virtual=True) + self.store(link.last_exception) else: self.store(link.last_exc_value) self._setup_link(link) Modified: pypy/branch/less-meta-instances/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/cli/test/runtest.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/cli/test/runtest.py Fri Jun 27 18:33:47 2008 @@ -277,15 +277,22 @@ def _skip_llinterpreter(self, reason, skipLL=True, skipOO=True): pass - def interpret(self, fn, args, annotation=None, backendopt=True, exctrans=False): + def _get_backendopt(self, backendopt): + if backendopt is None: + backendopt = getattr(self, 'backendopt', True) # enable it by default + return backendopt + + def interpret(self, fn, args, annotation=None, backendopt=None, exctrans=False): + backendopt = self._get_backendopt(backendopt) f = self._compile(fn, args, annotation, backendopt=backendopt, exctrans=exctrans) res = f(*args) if isinstance(res, ExceptionWrapper): raise res return res - def interpret_raises(self, exception, fn, args, backendopt=True, exctrans=False): + def interpret_raises(self, exception, fn, args, backendopt=None, exctrans=False): import exceptions # needed by eval + backendopt = self._get_backendopt(backendopt) try: self.interpret(fn, args, backendopt=backendopt, exctrans=exctrans) except ExceptionWrapper, ex: Modified: pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py (original) +++ pypy/branch/less-meta-instances/pypy/translator/cli/test/test_exception.py Fri Jun 27 18:33:47 2008 @@ -4,6 +4,7 @@ class TestCliException(CliTest, BaseTestException): use_exception_transformer = False + backendopt = False def interpret(self, *args, **kwds): kwds['exctrans'] = self.use_exception_transformer @@ -18,3 +19,4 @@ class TestCliExceptionTransformer(TestCliException): use_exception_transformer = True + backendopt = False From fijal at codespeak.net Fri Jun 27 18:49:47 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 18:49:47 +0200 (CEST) Subject: [pypy-svn] r56129 - pypy/dist/pypy/module/zipimport/test Message-ID: <20080627164947.17391698037@codespeak.net> Author: fijal Date: Fri Jun 27 18:49:45 2008 New Revision: 56129 Modified: pypy/dist/pypy/module/zipimport/test/test_undocumented.py Log: port this to python2.4 Modified: pypy/dist/pypy/module/zipimport/test/test_undocumented.py ============================================================================== --- pypy/dist/pypy/module/zipimport/test/test_undocumented.py (original) +++ pypy/dist/pypy/module/zipimport/test/test_undocumented.py Fri Jun 27 18:49:45 2008 @@ -30,37 +30,39 @@ zip_path = TESTFN + '.zip' bytecode_suffix = 'c'# if __debug__ else 'o' zip_file = zipfile.ZipFile(zip_path, 'w') - try: - for path in created_paths: - if os.sep in path: - directory = os.path.split(path)[0] - if not os.path.exists(directory): - os.makedirs(directory) - code_path = path + '.py' - try: - temp_file = open(code_path, 'w') - temp_file.write(example_code) - finally: - temp_file.close() - if source: - zip_file.write(code_path) - if bytecode: - py_compile.compile(code_path, doraise=True) - zip_file.write(code_path + bytecode_suffix) - zip_file.close() - yield os.path.abspath(zip_path) - finally: - zip_file.close() - for path in created_paths: - if os.sep in path: - directory = os.path.split(path)[0] - if os.path.exists(directory): - shutil.rmtree(directory) - else: - for suffix in ('.py', '.py' + bytecode_suffix): - if os.path.exists(path + suffix): - os.unlink(path + suffix) - os.unlink(zip_path) + for path in created_paths: + if os.sep in path: + directory = os.path.split(path)[0] + if not os.path.exists(directory): + os.makedirs(directory) + code_path = path + '.py' + try: + temp_file = open(code_path, 'w') + temp_file.write(example_code) + finally: + temp_file.close() + if source: + zip_file.write(code_path) + if bytecode: + py_compile.compile(code_path, doraise=True) + zip_file.write(code_path + bytecode_suffix) + zip_file.close() + return os.path.abspath(zip_path) + +def cleanup_zipfile(created_paths): + import os, shutil + bytecode_suffix = 'c'# if __debug__ else 'o' + zip_path = '@test.zip' + for path in created_paths: + if os.sep in path: + directory = os.path.split(path)[0] + if os.path.exists(directory): + shutil.rmtree(directory) + else: + for suffix in ('.py', '.py' + bytecode_suffix): + if os.path.exists(path + suffix): + os.unlink(path + suffix) + os.unlink(zip_path) class AppTestZipImport: def setup_class(cls): @@ -68,6 +70,8 @@ cls.space = space source = "():\n" + str(py.code.Source(temp_zipfile).indent()) + "\n return temp_zipfile" cls.w_temp_zipfile = space.appexec([], source) + source = "():\n" + str(py.code.Source(cleanup_zipfile).indent())+ "\n return cleanup_zipfile" + cls.w_cleanup_zipfile = space.appexec([], source) cls.w_created_paths = space.wrap(created_paths) def test_inheritance(self): @@ -100,18 +104,22 @@ def test_direct_path(self): # A zipfile should return an instance of zipimporter. import zipimport - for zip_path in self.temp_zipfile(self.created_paths): + zip_path = self.temp_zipfile(self.created_paths) + try: zip_importer = zipimport.zipimporter(zip_path) assert isinstance(zip_importer, zipimport.zipimporter) assert zip_importer.archive == zip_path assert zip_importer.prefix == '' assert zip_path in zipimport._zip_directory_cache + finally: + self.cleanup_zipfile(self.created_paths) def test_pkg_path(self): # Thanks to __path__, need to be able to work off of a path with a zip # file at the front and a path for the rest. import zipimport, os - for zip_path in self.temp_zipfile(self.created_paths): + zip_path = self.temp_zipfile(self.created_paths) + try: prefix = '_pkg' path = os.path.join(zip_path, prefix) zip_importer = zipimport.zipimporter(path) @@ -119,14 +127,19 @@ assert zip_importer.archive == zip_path assert zip_importer.prefix == prefix assert zip_path in zipimport._zip_directory_cache + finally: + self.cleanup_zipfile(self.created_paths) def test_zip_directory_cache(self): # Test that _zip_directory_cache is set properly. # Using a package entry to test using a hard example. import zipimport, os - for zip_path in self.temp_zipfile(self.created_paths, bytecode=False): + zip_path = self.temp_zipfile(self.created_paths, bytecode=False) + try: importer = zipimport.zipimporter(os.path.join(zip_path, '_pkg')) assert zip_path in zipimport._zip_directory_cache file_set = set(zipimport._zip_directory_cache[zip_path].iterkeys()) compare_set = set(path + '.py' for path in self.created_paths) assert file_set == compare_set + finally: + self.cleanup_zipfile(self.created_paths) From antocuni at codespeak.net Fri Jun 27 19:09:29 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 27 Jun 2008 19:09:29 +0200 (CEST) Subject: [pypy-svn] r56130 - pypy/branch/less-meta-instances/pypy/config Message-ID: <20080627170929.9A3BD698059@codespeak.net> Author: antocuni Date: Fri Jun 27 19:09:29 2008 New Revision: 56130 Modified: pypy/branch/less-meta-instances/pypy/config/translationoption.py Log: backport this constraint from dist/, as without it translation is broken Modified: pypy/branch/less-meta-instances/pypy/config/translationoption.py ============================================================================== --- pypy/branch/less-meta-instances/pypy/config/translationoption.py (original) +++ pypy/branch/less-meta-instances/pypy/config/translationoption.py Fri Jun 27 19:09:29 2008 @@ -21,6 +21,7 @@ ("translation.backendopt.constfold", False), ("translation.backendopt.heap2stack", False), ("translation.backendopt.clever_malloc_removal", False), + ("translation.list_comprehension_operations", False), ] }), ChoiceOption("backend", "Backend to use for code generation", From arigo at codespeak.net Fri Jun 27 19:16:32 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 27 Jun 2008 19:16:32 +0200 (CEST) Subject: [pypy-svn] r56131 - pypy/dist/pypy/module/thread Message-ID: <20080627171632.EF6C76980D3@codespeak.net> Author: arigo Date: Fri Jun 27 19:16:32 2008 New Revision: 56131 Modified: pypy/dist/pypy/module/thread/threadlocals.py Log: Oups! A race condition in the thread "minicache" code. Mea culpa. Hard to write a failing test, but at least test_perthread_excinfo fails because of this issue in the async-del branch. Modified: pypy/dist/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/dist/pypy/module/thread/threadlocals.py (original) +++ pypy/dist/pypy/module/thread/threadlocals.py Fri Jun 27 19:16:32 2008 @@ -55,11 +55,7 @@ exit_func, w_obj = ec.thread_exit_funcs.pop() exit_func(w_obj) finally: - ident = thread.get_ident() - try: - del self._valuedict[ident] - except KeyError: - pass + self.setvalue(None) def atthreadexit(self, space, exit_func, w_obj): ec = space.getexecutioncontext() From arigo at codespeak.net Fri Jun 27 19:17:51 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 27 Jun 2008 19:17:51 +0200 (CEST) Subject: [pypy-svn] r56132 - in pypy/branch/async-del/pypy/module/thread: . test Message-ID: <20080627171751.6B62B6980D3@codespeak.net> Author: arigo Date: Fri Jun 27 19:17:51 2008 New Revision: 56132 Modified: pypy/branch/async-del/pypy/module/thread/__init__.py pypy/branch/async-del/pypy/module/thread/gil.py pypy/branch/async-del/pypy/module/thread/test/test_gil.py pypy/branch/async-del/pypy/module/thread/threadlocals.py Log: Some progress in the thread module. Modified: pypy/branch/async-del/pypy/module/thread/__init__.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/__init__.py (original) +++ pypy/branch/async-del/pypy/module/thread/__init__.py Fri Jun 27 19:17:51 2008 @@ -30,4 +30,5 @@ MixedModule.__init__(self, space, *args) prev = space.threadlocals.getvalue() space.threadlocals = gil.GILThreadLocals() + space.threadlocals.initialize(space) space.threadlocals.setvalue(prev) Modified: pypy/branch/async-del/pypy/module/thread/gil.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/gil.py (original) +++ pypy/branch/async-del/pypy/module/thread/gil.py Fri Jun 27 19:17:51 2008 @@ -9,7 +9,7 @@ from pypy.module.thread import ll_thread as thread from pypy.module.thread.error import wrap_thread_error -from pypy.interpreter.miscutils import Action +from pypy.interpreter.executioncontext import PeriodicAsyncAction from pypy.module.thread.threadlocals import OSThreadLocals from pypy.rlib.objectmodel import invoke_around_extcall from pypy.rlib.rposix import get_errno, set_errno @@ -18,6 +18,10 @@ """A version of OSThreadLocals that enforces a GIL.""" ll_GIL = thread.null_ll_lock + def initialize(self, space): + # add the GIL-releasing callback as an action on the space + space.actionflag.register_action(GILReleaseAction(space)) + def setup_threads(self, space): """Enable threads in the object space, if they haven't already been.""" if not self.ll_GIL: @@ -27,8 +31,6 @@ raise wrap_thread_error(space, "can't allocate GIL") thread.acquire_NOAUTO(self.ll_GIL, True) self.enter_thread(space) # setup the main thread - # add the GIL-releasing callback as an action on the space - space.pending_actions.append(GILReleaseAction(self)) result = True else: result = False # already set up @@ -47,25 +49,19 @@ return result def yield_thread(self): - """Notification that the current thread is between two bytecodes: - release the GIL for a little while.""" - # Other threads can run between the release() and the acquire() - # implicit in the following external function call (which has - # otherwise no effect). - thread.yield_thread() + thread.yield_thread() # explicitly release the gil (used by test_gil) -class GILReleaseAction(Action): - """An action called when the current thread is between two bytecodes - (so that it's a good time to yield some time to other threads). +class GILReleaseAction(PeriodicAsyncAction): + """An action called every sys.checkinterval bytecodes. It releases + the GIL to give some other thread a chance to run. """ - repeat = True - def __init__(self, threadlocals): - self.threadlocals = threadlocals - - def perform(self): - self.threadlocals.yield_thread() + def perform(self, executioncontext): + # Other threads can run between the release() and the acquire() + # implicit in the following external function call (which has + # otherwise no effect). + thread.yield_thread() class SpaceState: @@ -86,6 +82,7 @@ actionflag.set(flag) spacestate = SpaceState() +spacestate._freeze_() # Fragile code below. We have to preserve the C-level errno manually... Modified: pypy/branch/async-del/pypy/module/thread/test/test_gil.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/test/test_gil.py (original) +++ pypy/branch/async-del/pypy/module/thread/test/test_gil.py Fri Jun 27 19:17:51 2008 @@ -8,9 +8,17 @@ class FakeEC(object): pass +class FakeActionFlag(object): + def register_action(self, action): + pass + def get(self): + return 0 + def set(self, x): + pass + class FakeSpace(object): def __init__(self): - self.pending_actions = [] + self.actionflag = FakeActionFlag() def _freeze_(self): return True def getexecutioncontext(self): Modified: pypy/branch/async-del/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/threadlocals.py (original) +++ pypy/branch/async-del/pypy/module/thread/threadlocals.py Fri Jun 27 19:17:51 2008 @@ -7,6 +7,7 @@ os_thread.bootstrap().""" def __init__(self): + print 'FRESH NEW THREADLOCALS' self._valuedict = {} # {thread_ident: ExecutionContext()} self._mainthreadident = 0 self._mostrecentkey = 0 # fast minicaching for the common case @@ -15,16 +16,20 @@ def getvalue(self): ident = thread.get_ident() if ident == self._mostrecentkey: - return self._mostrecentvalue + result = self._mostrecentvalue + print '(cached)', else: value = self._valuedict.get(ident, None) # slow path: update the minicache self._mostrecentkey = ident self._mostrecentvalue = value - return value + result = value + print '%d => %r' % (ident, result) + return result def setvalue(self, value): ident = thread.get_ident() + print 'SET %d => %r' % (ident, value) if value is not None: if len(self._valuedict) == 0: self._mainthreadident = ident @@ -37,6 +42,7 @@ # update the minicache to prevent it from containing an outdated value self._mostrecentkey = ident self._mostrecentvalue = value + print self._valuedict def getmainthreadvalue(self): ident = self._mainthreadident @@ -45,21 +51,19 @@ def enter_thread(self, space): "Notification that the current thread is just starting." ec = space.getexecutioncontext() + print 'ENTER_THREAD', thread.get_ident(), ec ec.thread_exit_funcs = [] def leave_thread(self, space): "Notification that the current thread is about to stop." try: ec = space.getexecutioncontext() + print 'LEAVE_THREAD', thread.get_ident(), ec while ec.thread_exit_funcs: exit_func, w_obj = ec.thread_exit_funcs.pop() exit_func(w_obj) finally: - ident = thread.get_ident() - try: - del self._valuedict[ident] - except KeyError: - pass + self.setvalue(None) def atthreadexit(self, space, exit_func, w_obj): ec = space.getexecutioncontext() From fijal at codespeak.net Fri Jun 27 19:23:35 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 19:23:35 +0200 (CEST) Subject: [pypy-svn] r56133 - in pypy/dist/pypy/lib: . app_test Message-ID: <20080627172335.13338168518@codespeak.net> Author: fijal Date: Fri Jun 27 19:23:34 2008 New Revision: 56133 Added: pypy/dist/pypy/lib/app_test/test_functools.py (contents, props changed) pypy/dist/pypy/lib/functools.py (contents, props changed) Log: Lousy implementation of functools with some tests. Not as compliant, but working Added: pypy/dist/pypy/lib/app_test/test_functools.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/app_test/test_functools.py Fri Jun 27 19:23:34 2008 @@ -0,0 +1,271 @@ +import functools +import unittest +from test import test_support +from weakref import proxy +import py + + at staticmethod +def PythonPartial(func, *args, **keywords): + 'Pure Python approximation of partial()' + def newfunc(*fargs, **fkeywords): + newkeywords = keywords.copy() + newkeywords.update(fkeywords) + return func(*(args + fargs), **newkeywords) + newfunc.func = func + newfunc.args = args + newfunc.keywords = keywords + return newfunc + +def capture(*args, **kw): + """capture all positional and keyword arguments""" + return args, kw + +class TestPartial: + + thetype = functools.partial + + def test_basic_examples(self): + p = self.thetype(capture, 1, 2, a=10, b=20) + assert p(3, 4, b=30, c=40) == ( + ((1, 2, 3, 4), dict(a=10, b=30, c=40))) + p = self.thetype(map, lambda x: x*10) + assert p([1,2,3,4]) == [10, 20, 30, 40] + + def test_attributes(self): + p = self.thetype(capture, 1, 2, a=10, b=20) + # attributes should be readable + assert p.func == capture + assert p.args == (1, 2) + assert p.keywords == dict(a=10, b=20) + # attributes should not be writable + if not isinstance(self.thetype, type): + return + py.test.raises(TypeError, setattr, p, 'func', map) + py.test.raises(TypeError, setattr, p, 'args', (1, 2)) + py.test.raises(TypeError, setattr, p, 'keywords', dict(a=1, b=2)) + + def test_argument_checking(self): + py.test.raises(TypeError, self.thetype) # need at least a func arg + try: + self.thetype(2)() + except TypeError: + pass + else: + raise AssertionError, 'First arg not checked for callability' + + def test_protection_of_callers_dict_argument(self): + # a caller's dictionary should not be altered by partial + def func(a=10, b=20): + return a + d = {'a':3} + p = self.thetype(func, a=5) + assert p(**d) == 3 + assert d == {'a':3} + p(b=7) + assert d == {'a':3} + + def test_arg_combinations(self): + # exercise special code paths for zero args in either partial + # object or the caller + p = self.thetype(capture) + assert p() == ((), {}) + assert p(1,2) == ((1,2), {}) + p = self.thetype(capture, 1, 2) + assert p() == ((1,2), {}) + assert p(3,4) == ((1,2,3,4), {}) + + def test_kw_combinations(self): + # exercise special code paths for no keyword args in + # either the partial object or the caller + p = self.thetype(capture) + assert p() == ((), {}) + assert p(a=1) == ((), {'a':1}) + p = self.thetype(capture, a=1) + assert p() == ((), {'a':1}) + assert p(b=2) == ((), {'a':1, 'b':2}) + # keyword args in the call override those in the partial object + assert p(a=3, b=2) == ((), {'a':3, 'b':2}) + + def test_positional(self): + # make sure positional arguments are captured correctly + for args in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]: + p = self.thetype(capture, *args) + expected = args + ('x',) + got, empty = p('x') + assert expected == got and empty == {} + + def test_keyword(self): + # make sure keyword arguments are captured correctly + for a in ['a', 0, None, 3.5]: + p = self.thetype(capture, a=a) + expected = {'a':a,'x':None} + empty, got = p(x=None) + assert expected == got and empty == () + + def test_no_side_effects(self): + # make sure there are no side effects that affect subsequent calls + p = self.thetype(capture, 0, a=1) + args1, kw1 = p(1, b=2) + assert args1 == (0,1) and kw1 == {'a':1,'b':2} + args2, kw2 = p() + assert args2 == (0,) and kw2 == {'a':1} + + def test_error_propagation(self): + def f(x, y): + x / y + py.test.raises(ZeroDivisionError, self.thetype(f, 1, 0)) + py.test.raises(ZeroDivisionError, self.thetype(f, 1), 0) + py.test.raises(ZeroDivisionError, self.thetype(f), 1, 0) + py.test.raises(ZeroDivisionError, self.thetype(f, y=0), 1) + + def test_attributes(self): + py.test.skip("Unsupported") + p = self.thetype(hex) + try: + del p.__dict__ + except TypeError: + pass + else: + raise AssertionError, 'partial object allowed __dict__ to be deleted' + + def test_weakref(self): + py.test.skip("unsupported") + f = self.thetype(int, base=16) + p = proxy(f) + assert f.func == p.func + f = None + py.test.raises(ReferenceError, getattr, p, 'func') + + def test_with_bound_and_unbound_methods(self): + data = map(str, range(10)) + join = self.thetype(str.join, '') + assert join(data) == '0123456789' + join = self.thetype(''.join) + assert join(data) == '0123456789' + +#class PartialSubclass(functools.partial): +# pass + +#class TestPartialSubclass(TestPartial): + +# thetype = PartialSubclass + + +class TestPythonPartial(TestPartial): + + thetype = PythonPartial + +class TestUpdateWrapper: + + def check_wrapper(self, wrapper, wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + # Check attributes were assigned + for name in assigned: + assert getattr(wrapper, name) == getattr(wrapped, name) + # Check attributes were updated + for name in updated: + wrapper_attr = getattr(wrapper, name) + wrapped_attr = getattr(wrapped, name) + for key in wrapped_attr: + assert wrapped_attr[key] == wrapper_attr[key] + + def test_default_update(self): + def f(): + """This is a test""" + pass + f.attr = 'This is also a test' + def wrapper(): + pass + functools.update_wrapper(wrapper, f) + self.check_wrapper(wrapper, f) + assert wrapper.__name__ == 'f' + assert wrapper.__doc__ == 'This is a test' + assert wrapper.attr == 'This is also a test' + + def test_no_update(self): + def f(): + """This is a test""" + pass + f.attr = 'This is also a test' + def wrapper(): + pass + functools.update_wrapper(wrapper, f, (), ()) + self.check_wrapper(wrapper, f, (), ()) + assert wrapper.__name__ == 'wrapper' + assert wrapper.__doc__ == None + assert not hasattr(wrapper, 'attr') + + def test_selective_update(self): + def f(): + pass + f.attr = 'This is a different test' + f.dict_attr = dict(a=1, b=2, c=3) + def wrapper(): + pass + wrapper.dict_attr = {} + assign = ('attr',) + update = ('dict_attr',) + functools.update_wrapper(wrapper, f, assign, update) + self.check_wrapper(wrapper, f, assign, update) + assert wrapper.__name__ == 'wrapper' + assert wrapper.__doc__ == None + assert wrapper.attr == 'This is a different test' + assert wrapper.dict_attr == f.dict_attr + + def test_builtin_update(self): + py.test.skip("Unsupported") + # Test for bug #1576241 + def wrapper(): + pass + functools.update_wrapper(wrapper, max) + assert wrapper.__name__ == 'max' + assert wrapper.__doc__.startswith('max(') + +class TestWraps(TestUpdateWrapper): + + def test_default_update(self): + def f(): + """This is a test""" + pass + f.attr = 'This is also a test' + @functools.wraps(f) + def wrapper(): + pass + self.check_wrapper(wrapper, f) + assert wrapper.__name__ == 'f' + assert wrapper.__doc__ == 'This is a test' + assert wrapper.attr == 'This is also a test' + + def test_no_update(self): + def f(): + """This is a test""" + pass + f.attr = 'This is also a test' + @functools.wraps(f, (), ()) + def wrapper(): + pass + self.check_wrapper(wrapper, f, (), ()) + assert wrapper.__name__ == 'wrapper' + assert wrapper.__doc__ == None + assert not hasattr(wrapper, 'attr') + + def test_selective_update(self): + def f(): + pass + f.attr = 'This is a different test' + f.dict_attr = dict(a=1, b=2, c=3) + def add_dict_attr(f): + f.dict_attr = {} + return f + assign = ('attr',) + update = ('dict_attr',) + @functools.wraps(f, assign, update) + @add_dict_attr + def wrapper(): + pass + self.check_wrapper(wrapper, f, assign, update) + assert wrapper.__name__ == 'wrapper' + assert wrapper.__doc__ == None + assert wrapper.attr == 'This is a different test' + assert wrapper.dict_attr == f.dict_attr Added: pypy/dist/pypy/lib/functools.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/functools.py Fri Jun 27 19:23:34 2008 @@ -0,0 +1,56 @@ + +def partial_func(func, *args, **keywords): + def newfunc(*fargs, **fkeywords): + newkeywords = keywords.copy() + newkeywords.update(fkeywords) + return func(*(args + fargs), **newkeywords) + newfunc.func = func + newfunc.args = args + newfunc.keywords = keywords + newfunc.__doc__ = getattr(func, '__doc__', '') + return newfunc + +partial = staticmethod(partial_func) + +from __builtin__ import reduce + +# update_wrapper() and wraps() are tools to help write +# wrapper functions that can handle naive introspection + +WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') +WRAPPER_UPDATES = ('__dict__',) +def update_wrapper(wrapper, + wrapped, + assigned = WRAPPER_ASSIGNMENTS, + updated = WRAPPER_UPDATES): + """Update a wrapper function to look like the wrapped function + + wrapper is the function to be updated + wrapped is the original function + assigned is a tuple naming the attributes assigned directly + from the wrapped function to the wrapper function (defaults to + functools.WRAPPER_ASSIGNMENTS) + updated is a tuple naming the attributes of the wrapper that + are updated with the corresponding attribute from the wrapped + function (defaults to functools.WRAPPER_UPDATES) + """ + for attr in assigned: + setattr(wrapper, attr, getattr(wrapped, attr)) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + # Return the wrapper so this can be used as a decorator via partial() + return wrapper + +def wraps(wrapped, + assigned = WRAPPER_ASSIGNMENTS, + updated = WRAPPER_UPDATES): + """Decorator factory to apply update_wrapper() to a wrapper function + + Returns a decorator that invokes update_wrapper() with the decorated + function as the wrapper argument and the arguments to wraps() as the + remaining arguments. Default arguments are as for update_wrapper(). + This is a convenience function to simplify applying partial() to + update_wrapper(). + """ + return partial_func(update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) From fijal at codespeak.net Fri Jun 27 19:45:42 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 19:45:42 +0200 (CEST) Subject: [pypy-svn] r56134 - pypy/extradoc/talk/ep2008 Message-ID: <20080627174542.4093716A02A@codespeak.net> Author: fijal Date: Fri Jun 27 19:45:41 2008 New Revision: 56134 Added: pypy/extradoc/talk/ep2008/status.txt (contents, props changed) Log: Draft of my slides Added: pypy/extradoc/talk/ep2008/status.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/ep2008/status.txt Fri Jun 27 19:45:41 2008 @@ -0,0 +1,88 @@ + +PyPy status +=========== + +* more details recent developements + +* where we're going + +* sponsorship (?) + +Production ready +===================== + +* We concentrated on running + existing applications on top of pypy + +* Sometimes requiring this application changes + +Ctypes +====== + +* Official way of having bindings to + external (C) libraries for pypy + +* Slow, but getting better + +* Sponsored by google + +* Can handle ie pyglet, pymunk or Sole Scion + +Ctypes configure +================ + +* Our own small addition to general + ctypes usefulness + +* Invokes C compiler for small details + +* Can handle #defines, types, structure layout + etc. + +Sqlite +====== + +* Part of cpython stdlib + +* We use Gerhard Haering's version + (XXX link) + +* Works reasonably well after fixes + +Django +====== + +* We run (almost) unmodified django + +* We'll run 1.0 definitely + +Pylons +====== + +* Worked almost out of the box once eggs + are working (1 day) + +* No sqlalchemy yet + +Twisted & Nevow +=============== + +* Twisted have some glitches + +* Nevow works + +* We don't support pycrypto nor pyopenssl + +Speed - decent gcs +================== + +* Faster than refcounting + +* Still need some glitches + +Speed - JIT +=========== + +* Not ready yet! + +XXX anything else? From arigo at codespeak.net Fri Jun 27 19:47:55 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 27 Jun 2008 19:47:55 +0200 (CEST) Subject: [pypy-svn] r56135 - in pypy/branch/async-del/pypy: interpreter module/signal Message-ID: <20080627174755.C59B116A02C@codespeak.net> Author: arigo Date: Fri Jun 27 19:47:54 2008 New Revision: 56135 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py pypy/branch/async-del/pypy/module/signal/__init__.py pypy/branch/async-del/pypy/module/signal/interp_signal.py Log: Translation fix. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Fri Jun 27 19:47:54 2008 @@ -241,7 +241,7 @@ " traceback and see where this one comes from :-)") -class ActionFlag: +class AbstractActionFlag: """This holds the global 'action flag'. It is a single bitfield integer, with bits corresponding to AsyncAction objects that need to be immediately triggered. The correspondance from bits to @@ -252,7 +252,6 @@ when to release the GIL. """ def __init__(self): - self.__flags = 0 self._periodic_actions = [] self._nonperiodic_actions = [] self.unused_bits = self.FREE_BITS[:] @@ -260,15 +259,6 @@ self.interesting_bits = 0 self._rebuild_action_dispatcher() - # '__flags' is "very private" -- don't access it even from elsewhere - # in this class. The get()/set() accessors are meant to be overriden - # by the signal module, if it is used. - def get(self): - return self.__flags - - def set(self, value): - self.__flags = value - def fire(self, action): """Request for the action to be run before the next opcode. The action must have been registered at space initalization time.""" @@ -351,6 +341,18 @@ CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT +class ActionFlag(AbstractActionFlag): + """The normal class for space.actionflag. The signal module provides + a different one.""" + _flags = 0 + + def get(self): + return self._flags + + def set(self, value): + self._flags = value + + class AsyncAction(object): """Abstract base class for actions that must be performed asynchronously with regular bytecode execution, but that still need Modified: pypy/branch/async-del/pypy/module/signal/__init__.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/__init__.py (original) +++ pypy/branch/async-del/pypy/module/signal/__init__.py Fri Jun 27 19:47:54 2008 @@ -33,5 +33,5 @@ # use the C-level pypysig_occurred variable as the action flag # (the result is that the C-level signal handler will directly # set the flag for the CheckSignalAction) - space.actionflag.get = interp_signal.pypysig_get_occurred - space.actionflag.set = interp_signal.pypysig_set_occurred + space.actionflag.__class__ = interp_signal.SignalActionFlag + # xxx yes I know the previous line is a hack Modified: pypy/branch/async-del/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/interp_signal.py (original) +++ pypy/branch/async-del/pypy/module/signal/interp_signal.py Fri Jun 27 19:47:54 2008 @@ -1,6 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace -from pypy.interpreter.executioncontext import AsyncAction +from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag from pypy.rlib.rarithmetic import LONG_BIT, intmask import signal as cpy_signal from pypy.rpython.lltypesystem import lltype, rffi @@ -41,6 +41,12 @@ pypysig_set_occurred = external('pypysig_set_occurred', [lltype.Signed], lltype.Void, _nowrapper=True) + +class SignalActionFlag(AbstractActionFlag): + get = staticmethod(pypysig_get_occurred) + set = staticmethod(pypysig_set_occurred) + + class CheckSignalAction(AsyncAction): """An action that is automatically invoked when a signal is received.""" From fijal at codespeak.net Fri Jun 27 20:07:27 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 20:07:27 +0200 (CEST) Subject: [pypy-svn] r56136 - pypy/extradoc/talk/ep2008 Message-ID: <20080627180727.BCA8216A106@codespeak.net> Author: fijal Date: Fri Jun 27 20:07:26 2008 New Revision: 56136 Modified: pypy/extradoc/talk/ep2008/status.txt Log: Update Modified: pypy/extradoc/talk/ep2008/status.txt ============================================================================== --- pypy/extradoc/talk/ep2008/status.txt (original) +++ pypy/extradoc/talk/ep2008/status.txt Fri Jun 27 20:07:26 2008 @@ -73,6 +73,25 @@ * We don't support pycrypto nor pyopenssl +Conclusion +========== + +* There is no feature obscure enough for people + not to rely on it + +* Generally it's fairly unlikely we'll ever try + to support stuff without tests + +Examples of obscure features +============================ + +XXX - non-string keys in typedict + +XXX - list comprehension variable in __all__ + +XXX - relying on untested and undocumented private stuff + (zipimport._zip_directory_cache) + Speed - decent gcs ================== From fijal at codespeak.net Fri Jun 27 20:09:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 20:09:31 +0200 (CEST) Subject: [pypy-svn] r56137 - pypy/dist/pypy/module/gc Message-ID: <20080627180931.6615516A10B@codespeak.net> Author: fijal Date: Fri Jun 27 20:09:30 2008 New Revision: 56137 Modified: pypy/dist/pypy/module/gc/app_gc.py Log: Potentialy questionable commit. Implement gc.enable and gc.disable as enable/disable finalizers. It fits in one of two use cases, the other one is for performance reasons, where it does not harm. Modified: pypy/dist/pypy/module/gc/app_gc.py ============================================================================== --- pypy/dist/pypy/module/gc/app_gc.py (original) +++ pypy/dist/pypy/module/gc/app_gc.py Fri Jun 27 20:09:30 2008 @@ -1,9 +1,17 @@ +enabled = [True] + def isenabled(): - return True + return enabled[0] def enable(): - "Not implemented." + import gc + if not enabled[0]: + gc.enable_finalizers() + enabled[0] = True def disable(): - "Not implemented." + import gc + if enabled[0]: + gc.disable_finalizers() + enabled[0] = False From fijal at codespeak.net Fri Jun 27 20:19:58 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 20:19:58 +0200 (CEST) Subject: [pypy-svn] r56138 - pypy/dist/pypy/module/gc Message-ID: <20080627181958.F184F16A173@codespeak.net> Author: fijal Date: Fri Jun 27 20:19:58 2008 New Revision: 56138 Modified: pypy/dist/pypy/module/gc/app_gc.py Log: Make non-rpython version of it, with global statement Modified: pypy/dist/pypy/module/gc/app_gc.py ============================================================================== --- pypy/dist/pypy/module/gc/app_gc.py (original) +++ pypy/dist/pypy/module/gc/app_gc.py Fri Jun 27 20:19:58 2008 @@ -1,17 +1,21 @@ +# NOT_RPYTHON -enabled = [True] +enabled = True def isenabled(): - return enabled[0] + global enabled + return enabled def enable(): + global enabled import gc - if not enabled[0]: + if not enabled: gc.enable_finalizers() - enabled[0] = True + enabled = True def disable(): + global enabled import gc - if enabled[0]: + if enabled: gc.disable_finalizers() - enabled[0] = False + enabled = False From fijal at codespeak.net Fri Jun 27 20:21:31 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 20:21:31 +0200 (CEST) Subject: [pypy-svn] r56139 - pypy/dist/pypy/module/gc/test Message-ID: <20080627182131.7894916A173@codespeak.net> Author: fijal Date: Fri Jun 27 20:21:31 2008 New Revision: 56139 Modified: pypy/dist/pypy/module/gc/test/test_gc.py Log: And while we're at it, a test Modified: pypy/dist/pypy/module/gc/test/test_gc.py ============================================================================== --- pypy/dist/pypy/module/gc/test/test_gc.py (original) +++ pypy/dist/pypy/module/gc/test/test_gc.py Fri Jun 27 20:21:31 2008 @@ -23,3 +23,14 @@ assert gc.estimate_heap_size() > 1024 else: raises(RuntimeError, gc.estimate_heap_size) + + def test_enable(self): + import gc + assert gc.isenabled() + gc.disable() + assert not gc.isenabled() + gc.enable() + assert gc.isenabled() + gc.enable() + assert gc.isenabled() + From antocuni at codespeak.net Fri Jun 27 21:03:18 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 27 Jun 2008 21:03:18 +0200 (CEST) Subject: [pypy-svn] r56140 - pypy/extradoc/talk/ep2008 Message-ID: <20080627190318.202EC168511@codespeak.net> Author: antocuni Date: Fri Jun 27 21:03:17 2008 New Revision: 56140 Modified: pypy/extradoc/talk/ep2008/status.txt Log: some language tweaks, some new points/paragraphs Modified: pypy/extradoc/talk/ep2008/status.txt ============================================================================== --- pypy/extradoc/talk/ep2008/status.txt (original) +++ pypy/extradoc/talk/ep2008/status.txt Fri Jun 27 21:03:17 2008 @@ -14,19 +14,19 @@ * We concentrated on running existing applications on top of pypy -* Sometimes requiring this application changes +* Sometimes requiring to change applications slightly Ctypes ====== -* Official way of having bindings to +* Official way to have bindings to external (C) libraries for pypy * Slow, but getting better * Sponsored by google -* Can handle ie pyglet, pymunk or Sole Scion +* Can handle ie pysqlite-ctypes, pyglet, pymunk or Sole Scion Ctypes configure ================ @@ -44,7 +44,7 @@ * Part of cpython stdlib -* We use Gerhard Haering's version +* We use Gerhard Haering's ctypes version (XXX link) * Works reasonably well after fixes @@ -54,6 +54,8 @@ * We run (almost) unmodified django +* Only sqlite DB backend for now + * We'll run 1.0 definitely Pylons @@ -73,6 +75,13 @@ * We don't support pycrypto nor pyopenssl +Bittorrent +========== + +XXX fill me +http://morepypy.blogspot.com/2008/03/bittorrent-on-pypy.html + + Conclusion ========== @@ -92,6 +101,11 @@ XXX - relying on untested and undocumented private stuff (zipimport._zip_directory_cache) +Speed - comparison with CPython +=============================== + +XXX fill me + Speed - decent gcs ================== @@ -104,4 +118,15 @@ * Not ready yet! +Other backends +============== + +* pypy-jvm runs! + +* more integration between pypy-cli and .NET + +* general speed improvements + +* both backends are progressing - very slowly though + XXX anything else? From arigo at codespeak.net Fri Jun 27 21:13:18 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 27 Jun 2008 21:13:18 +0200 (CEST) Subject: [pypy-svn] r56141 - pypy/branch/async-del/pypy/interpreter Message-ID: <20080627191318.51E4C169E4A@codespeak.net> Author: arigo Date: Fri Jun 27 21:13:15 2008 New Revision: 56141 Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py Log: Translation fix. Modified: pypy/branch/async-del/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/async-del/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/async-del/pypy/interpreter/executioncontext.py Fri Jun 27 21:13:15 2008 @@ -268,7 +268,7 @@ def register_action(self, action): "NOT_RPYTHON" assert isinstance(action, AsyncAction) - if action.bitmask == 'auto': + if action.bitmask == 0: while True: action.bitmask = self.unused_bits.pop(0) if not (action.bitmask & self.interesting_bits): @@ -358,7 +358,7 @@ asynchronously with regular bytecode execution, but that still need to occur between two opcodes, not at a completely random time. """ - bitmask = 'auto' + bitmask = 0 # means 'please choose one bit automatically' def __init__(self, space): self.space = space From antocuni at codespeak.net Fri Jun 27 21:31:08 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 27 Jun 2008 21:31:08 +0200 (CEST) Subject: [pypy-svn] r56142 - in pypy/branch/oo-jit/pypy: jit/codegen/llgraph jit/hintannotator jit/rainbow jit/rainbow/test jit/timeshifter rlib rpython/ootypesystem Message-ID: <20080627193108.D303F169F11@codespeak.net> Author: antocuni Date: Fri Jun 27 21:31:06 2008 New Revision: 56142 Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py pypy/branch/oo-jit/pypy/jit/hintannotator/model.py pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py pypy/branch/oo-jit/pypy/jit/rainbow/typesystem.py pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py pypy/branch/oo-jit/pypy/rlib/jit.py pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py pypy/branch/oo-jit/pypy/rpython/ootypesystem/rclass.py Log: tentative checkin; introduce a new hint "promote_class=True"; the promotion is done on the class of the argument, and the resulting var is red. On lltype, this has the same effect as hint(obj.__class__, promote=True), but the latter has no chance to work on ootype. Modified: pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/branch/oo-jit/pypy/jit/codegen/llgraph/rgenop.py Fri Jun 27 21:31:06 2008 @@ -419,6 +419,9 @@ def getfieldtype(T, name): if isinstance(T, ootype.OOType): + if name == '__class__': + # XXX hack hack hack + return ootype.Class _, TYPE = T._lookup_field(name) return TYPE else: Modified: pypy/branch/oo-jit/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/hintannotator/model.py (original) +++ pypy/branch/oo-jit/pypy/jit/hintannotator/model.py Fri Jun 27 21:31:06 2008 @@ -346,7 +346,7 @@ def same_as(hs_v1): return hs_v1 - def hint(hs_v1, hs_flags): + def hint(hs_v1, hs_flags, hs_class=None): if hs_flags.const.get('variable', False): # only for testing purposes!!! return variableoftype(hs_v1.concretetype, cause='a hint variable=True') @@ -362,6 +362,9 @@ hs_clone = hs_v1.clone() hs_clone.deepfrozen = True return hs_clone + if hs_flags.const.get('promote_class', False): + assert hs_class is not None + return hs_v1 # XXX? for name in ["reverse_split_queue", "global_merge_point", "access_directly"]: if hs_flags.const.get(name, False): @@ -524,7 +527,7 @@ # version of same_as() return hs_c1 - def hint(hs_c1, hs_flags): + def hint(hs_c1, hs_flags, hs_class=None): if hs_flags.const.get('concrete', False): for o in hs_c1.origins: o.set_fixed() @@ -534,7 +537,7 @@ if hs_flags.const.get('forget', False): assert isinstance(hs_c1, SomeLLAbstractConstant) return reorigin(hs_c1) - return SomeLLAbstractValue.hint(hs_c1, hs_flags) + return SomeLLAbstractValue.hint(hs_c1, hs_flags, hs_class) def direct_call(hs_f1, *args_hs): bookkeeper = getbookkeeper() Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py Fri Jun 27 21:31:06 2008 @@ -984,6 +984,30 @@ self.emit(self.promotiondesc_position(arg.concretetype)) self.register_greenvar(result) + def handle_promote_class_hint(self, op, v_obj, result): + from pypy.rpython.lltypesystem.rclass import OBJECT + from pypy.rpython.ootypesystem.rclass import OBJECT + # TODO write tests for these cases +## if arg.concretetype is lltype.Void: +## return +## if self.varcolor(arg) == "green": +## self.register_greenvar(result, self.green_position(arg)) +## return + v_class = op.args[2] + self.emit("promote") + self.emit(self.serialize_oparg("red", v_class)) + self.emit(self.promotiondesc_position(v_class.concretetype)) + g_class = self.register_greenvar(("promoted class", op), + check=False) + fielddescindex = self.fielddesc_position(self.OBJECT, + self.classfieldname) + self.emit("assert_class") + self.emit(self.serialize_oparg("red", v_obj)) + self.emit(g_class) + self.emit(fielddescindex) + + self.register_redvar(result) + def handle_global_merge_point_hint(self, op, arg, result): if self.hannotator.policy.hotpath: raise JitHintError("'global_merge_point' not supported by hotpath") @@ -1639,6 +1663,9 @@ Ptr = staticmethod(lltype.Ptr) functionptr = staticmethod(lltype.functionptr) + from pypy.rpython.lltypesystem.rclass import OBJECT + classfieldname = 'typeptr' + def cast_fnptr_to_root(self, fnptr): return llmemory.cast_ptr_to_adr(fnptr) @@ -1678,7 +1705,10 @@ FuncType = staticmethod(ootype.StaticMethod) Ptr = staticmethod(lambda x: x) functionptr = staticmethod(ootype.static_meth) - + + from pypy.rpython.ootypesystem.rclass import OBJECT + classfieldname = '__class__' + def decompose_oosend(self, op): name = op.args[0].value opargs = op.args[1:] @@ -1815,17 +1845,17 @@ continue emitted_args.append(self.serialize_oparg("red", v)) - self.emit("goto_if_vstruct", emitted_args[0], - tlabel(("virtual struct oosend", op))) + self.emit("goto_if_known_class", emitted_args[0], + tlabel(("constant class oosend", op))) self.emit_residual_oosend(SELFTYPE, name, emitted_args, has_result) self.emit("goto", tlabel(("after oosend", op))) # virtual struct case - self.emit(label(("virtual struct oosend", op))) + self.emit(label(("constant class oosend", op))) args = graph2tsgraph.values()[0].getargs() emitted_args = self.args_of_call(op.args[1:], args) - self.emit("vstruct_oosend") + self.emit("const_oosend") self.emit(*emitted_args) methnameindex = self.string_position(name) self.emit(methnameindex) @@ -1863,10 +1893,13 @@ def fill_methodcodes(self, INSTANCE, methname, graph2tsgraph): + class2typedesc = self.interpreter.class2typedesc TYPES = [INSTANCE] + INSTANCE._subclasses for T in TYPES: descindex = self.structtypedesc_position(T) desc = self.structtypedescs[descindex] + ooclass = ootype.runtimeClass(T) + class2typedesc[ooclass] = desc if methname in desc.methodcodes: break # we already filled the codes for this type _, meth = T._lookup(methname) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Fri Jun 27 21:31:06 2008 @@ -629,6 +629,12 @@ assert gv_switchvar.is_const self.green_result(gv_switchvar) + @arguments("red", "green", "fielddesc", returns="red") + def opimpl_assert_class(self, objbox, gv_class, fielddesc): + classbox = self.PtrRedBox(gv_class) + objbox.remember_field(fielddesc, classbox) + return objbox + @arguments() def opimpl_reverse_split_queue(self): rtimeshift.reverse_split_queue(self.frame.dispatchqueue) @@ -1050,9 +1056,16 @@ class LLTypeJitInterpreter(JitInterpreter): ts = typesystem.llhelper + PtrRedBox = rvalue.PtrRedBox class OOTypeJitInterpreter(JitInterpreter): ts = typesystem.oohelper + PtrRedBox = rvalue.InstanceRedBox + + def __init__(self, exceptiondesc, RGenOp): + JitInterpreter.__init__(self, exceptiondesc, RGenOp) + self.class2typedesc = {} + self.class_fielddesc = rcontainer.InstanceFieldDesc(RGenOp, ootype.ROOT, '__class__', 0) @arguments("red", "fielddesc", "bool", returns="red") def opimpl_red_oogetfield(self, structbox, fielddesc, deepfrozen): @@ -1095,17 +1108,36 @@ return rvalue.ll_fromvalue(self.jitstate, result) @arguments("red", "jumptarget") - def opimpl_goto_if_vstruct(self, objbox, target): - if objbox.content is not None: + def opimpl_goto_if_known_class(self, objbox, target): + known_class = False + content = objbox.content + if content is not None: + if isinstance(content, rcontainer.VirtualStruct): + known_class = True + elif isinstance(content, rcontainer.PartialDataStruct): + known_class = content.op_getfield(self.jitstate, self.class_fielddesc) is not None + else: + assert False, 'TODO?' + if known_class: self.frame.pc = target @arguments("green_varargs", "red_varargs", "string") - def opimpl_vstruct_oosend(self, greenargs, redargs, methname): + def opimpl_const_oosend(self, greenargs, redargs, methname): + from pypy.rpython.ootypesystem.rclass import CLASSTYPE selfbox = redargs[0] vstruct = selfbox.content assert vstruct is not None - assert isinstance(vstruct, rcontainer.VirtualStruct), 'TODO???' - bytecode = vstruct.typedesc.methodcodes[methname] + if isinstance(vstruct, rcontainer.PartialDataStruct): + classbox = vstruct.op_getfield(self.jitstate, self.class_fielddesc) + assert classbox.is_constant() + gv_meta = classbox.getgenvar(self.jitstate) + meta = gv_meta.revealconst(CLASSTYPE) + cls = meta.class_ # to be removed after the merging of the less-meta-instances branch + typedesc = self.class2typedesc[cls] + else: + assert isinstance(vstruct, rcontainer.VirtualStruct) + typedesc = vstruct.typedesc + bytecode = typedesc.methodcodes[methname] self.run(self.jitstate, bytecode, greenargs, redargs, start_bytecode_loop=False) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Fri Jun 27 21:31:06 2008 @@ -474,7 +474,7 @@ assert res == 11 self.check_insns(int_add=0) - def test_promote___class__(self): + def test_promote_class(self): class A: def __init__(self, x): self.x = x @@ -491,8 +491,8 @@ hint(None, global_merge_point=True) obj = make_obj(x, flag) obj2 = flag and A(x+2) or B(x+2) - hint(obj.__class__, promote=True) - return obj.m(obj2) + promoted_obj = hint(obj, promote_class=True) + return promoted_obj.m(obj2) res = self.interpret(ll_function, [20, True], [], policy=StopAtXPolicy(make_obj)) assert res == 42 @@ -508,5 +508,3 @@ type_system = "ootype" to_rstr = staticmethod(OOSupport.to_rstr) - def test_promote___class__(self): - py.test.skip('fixme') Modified: pypy/branch/oo-jit/pypy/jit/rainbow/typesystem.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/typesystem.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/typesystem.py Fri Jun 27 21:31:06 2008 @@ -14,6 +14,9 @@ if isinstance(T, lltype.Struct): return getattr(T, name) elif isinstance(T, (ootype.Instance, ootype.Record)): + if name == '__class__': + # XXX hack hack hack + return ootype.Class _, FIELD = T._lookup_field(name) return FIELD else: Modified: pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/oo-jit/pypy/jit/timeshifter/rcontainer.py Fri Jun 27 21:31:06 2008 @@ -80,6 +80,7 @@ materialize = None StructFieldDesc = None PtrRedBox = rvalue.PtrRedBox + firstfielddesc = 0 def __init__(self, RGenOp, TYPE): self.TYPE = TYPE @@ -261,6 +262,7 @@ _attrs_ = ['methodcodes', 'supertypedesc'] supertypedesc = None + firstfielddesc = 1 # number 0 is __class__, which is special def __init__(self, RGenOp, TYPE): AbstractStructTypeDesc.__init__(self, RGenOp, TYPE) @@ -285,6 +287,10 @@ return 'gc' # all instances and records are garbage collected def _iter_fields(self, TYPE): + if isinstance(TYPE, ootype.Instance): + # the first field is fake, it's used to remember the class of + # the object, if known + yield '__class__', ootype.Class try: fields = TYPE._fields.items() if isinstance(TYPE, ootype.Instance): @@ -928,7 +934,7 @@ # force the box pointing to this VirtualStruct self.setforced(genvar) fielddescs = typedesc.fielddescs - for i in range(len(fielddescs)): + for i in range(typedesc.firstfielddesc, len(fielddescs)): fielddesc = fielddescs[i] box = boxes[i] fielddesc.generate_set(jitstate, genvar, box.getgenvar(jitstate)) Modified: pypy/branch/oo-jit/pypy/rlib/jit.py ============================================================================== --- pypy/branch/oo-jit/pypy/rlib/jit.py (original) +++ pypy/branch/oo-jit/pypy/rlib/jit.py Fri Jun 27 21:31:06 2008 @@ -41,8 +41,13 @@ hints[key[2:]] = s_value.const v = hop.inputarg(hop.args_r[0], arg=0) c_hint = hop.inputconst(lltype.Void, hints) + vlist = [v, c_hint] + if hints.get('promote_class', False): + ll_type = hop.rtyper.type_system.rclass.ll_type + v_class = hop.gendirectcall(ll_type, v) + vlist.append(v_class) hop.exception_cannot_occur() - return hop.genop('hint', [v, c_hint], resulttype=v.concretetype) + return hop.genop('hint', vlist, resulttype=v.concretetype) def we_are_jitted(): Modified: pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/oo-jit/pypy/rpython/ootypesystem/ootype.py Fri Jun 27 21:31:06 2008 @@ -872,6 +872,9 @@ def _cast_to_object(self): return make_object(self) + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self._INSTANCE) + nullruntimeclass = _class(None) class _instance(object): Modified: pypy/branch/oo-jit/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/branch/oo-jit/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/branch/oo-jit/pypy/rpython/ootypesystem/rclass.py Fri Jun 27 21:31:06 2008 @@ -548,3 +548,5 @@ else: # type(None) -> NULL (for now) return ootype.null(CLASSTYPE) + +ll_type = ll_inst_type From fijal at codespeak.net Fri Jun 27 22:44:11 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 27 Jun 2008 22:44:11 +0200 (CEST) Subject: [pypy-svn] r56143 - in pypy/dist/pypy/objspace: . test Message-ID: <20080627204411.15AF6698053@codespeak.net> Author: fijal Date: Fri Jun 27 22:44:09 2008 New Revision: 56143 Modified: pypy/dist/pypy/objspace/descroperation.py pypy/dist/pypy/objspace/test/test_descroperation.py Log: A test and a fix Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Fri Jun 27 22:44:09 2008 @@ -501,8 +501,8 @@ w_right_impl = None else: w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2, right) - if (w_left_src is not w_right_src # XXX see binop_impl - and space.is_true(space.issubtype(w_typ2, w_typ1))): + # XXX see binop_impl + if space.is_true(space.issubtype(w_typ2, w_typ1)): w_obj1, w_obj2 = w_obj2, w_obj1 w_left_impl, w_right_impl = w_right_impl, w_left_impl Modified: pypy/dist/pypy/objspace/test/test_descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_descroperation.py (original) +++ pypy/dist/pypy/objspace/test/test_descroperation.py Fri Jun 27 22:44:09 2008 @@ -328,6 +328,25 @@ setattr(P, "__weakref__", 0) + def test_subclass_comparison(self): + l = [] + class A(object): + def __eq__(self, other): + l.append(self.__class__) + l.append(other.__class__) + return False + + def __lt__(self, other): + l.append(self.__class__) + l.append(other.__class__) + return False + + class B(A): + pass + + A() == B() + A() < B() + assert l == [B, A, A, B] class AppTestWithBuiltinShortcut(AppTest_Descroperation): OPTIONS = {'objspace.std.builtinshortcut': True} From arigo at codespeak.net Sat Jun 28 12:25:08 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 12:25:08 +0200 (CEST) Subject: [pypy-svn] r56147 - pypy/branch/async-del/pypy/module/thread Message-ID: <20080628102508.794AF16A0C5@codespeak.net> Author: arigo Date: Sat Jun 28 12:25:06 2008 New Revision: 56147 Modified: pypy/branch/async-del/pypy/module/thread/threadlocals.py Log: Remove debugging prints. Modified: pypy/branch/async-del/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/threadlocals.py (original) +++ pypy/branch/async-del/pypy/module/thread/threadlocals.py Sat Jun 28 12:25:06 2008 @@ -7,7 +7,6 @@ os_thread.bootstrap().""" def __init__(self): - print 'FRESH NEW THREADLOCALS' self._valuedict = {} # {thread_ident: ExecutionContext()} self._mainthreadident = 0 self._mostrecentkey = 0 # fast minicaching for the common case @@ -17,19 +16,16 @@ ident = thread.get_ident() if ident == self._mostrecentkey: result = self._mostrecentvalue - print '(cached)', else: value = self._valuedict.get(ident, None) # slow path: update the minicache self._mostrecentkey = ident self._mostrecentvalue = value result = value - print '%d => %r' % (ident, result) return result def setvalue(self, value): ident = thread.get_ident() - print 'SET %d => %r' % (ident, value) if value is not None: if len(self._valuedict) == 0: self._mainthreadident = ident @@ -42,7 +38,6 @@ # update the minicache to prevent it from containing an outdated value self._mostrecentkey = ident self._mostrecentvalue = value - print self._valuedict def getmainthreadvalue(self): ident = self._mainthreadident @@ -51,14 +46,12 @@ def enter_thread(self, space): "Notification that the current thread is just starting." ec = space.getexecutioncontext() - print 'ENTER_THREAD', thread.get_ident(), ec ec.thread_exit_funcs = [] def leave_thread(self, space): "Notification that the current thread is about to stop." try: ec = space.getexecutioncontext() - print 'LEAVE_THREAD', thread.get_ident(), ec while ec.thread_exit_funcs: exit_func, w_obj = ec.thread_exit_funcs.pop() exit_func(w_obj) From arigo at codespeak.net Sat Jun 28 12:25:13 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 12:25:13 +0200 (CEST) Subject: [pypy-svn] r56148 - pypy/branch/async-del/pypy/module/signal Message-ID: <20080628102513.0C32716A0CB@codespeak.net> Author: arigo Date: Sat Jun 28 12:25:13 2008 New Revision: 56148 Modified: pypy/branch/async-del/pypy/module/signal/interp_signal.py Log: Fix. Modified: pypy/branch/async-del/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/branch/async-del/pypy/module/signal/interp_signal.py (original) +++ pypy/branch/async-del/pypy/module/signal/interp_signal.py Sat Jun 28 12:25:13 2008 @@ -122,7 +122,7 @@ thread switch until we land in the main thread. """ - def perform(self): + def perform(self, executioncontext): main_ec = self.space.threadlocals.getmainthreadvalue() if executioncontext is main_ec: # now running in the main thread: we can really report the signals From arigo at codespeak.net Sat Jun 28 13:03:58 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 13:03:58 +0200 (CEST) Subject: [pypy-svn] r56149 - in pypy/branch/async-del/pypy/module/thread: . test Message-ID: <20080628110358.00DA02A00E1@codespeak.net> Author: arigo Date: Sat Jun 28 13:03:57 2008 New Revision: 56149 Modified: pypy/branch/async-del/pypy/module/thread/gil.py pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py Log: Fix the test. Threads are not fun. Modified: pypy/branch/async-del/pypy/module/thread/gil.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/gil.py (original) +++ pypy/branch/async-del/pypy/module/thread/gil.py Sat Jun 28 13:03:57 2008 @@ -101,3 +101,10 @@ spacestate.after_thread_switch() set_errno(e) after_external_call._gctransformer_hint_cannot_collect_ = True + +# The _gctransformer_hint_cannot_collect_ hack is needed for +# translations in which the *_external_call() functions are not inlined. +# They tell the gctransformer not to save and restore the local GC +# pointers in the shadow stack. This is necessary because the GIL is +# not held after the call to before_external_call() or before the call +# to after_external_call(). Modified: pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py ============================================================================== --- pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py (original) +++ pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py Sat Jun 28 13:03:57 2008 @@ -7,7 +7,8 @@ def setup_module(mod): # Hack to avoid a deadlock if the module is run after other test files :-( # In this module, we assume that ll_thread.start_new_thread() is not - # providing us with a GIL equivalent. + # providing us with a GIL equivalent, except in test_gc_locking + # which installs its own aroundstate. rffi.aroundstate._freeze_() def test_lock(): @@ -89,6 +90,9 @@ def test_gc_locking(self): import time + from pypy.rlib.objectmodel import invoke_around_extcall + from pypy.rlib.objectmodel import we_are_translated + from pypy.rlib.debug import ll_assert class State: pass @@ -102,63 +106,82 @@ j = self.j if self.i > 1: g(self.i-1, self.j * 2) - assert j == self.j + ll_assert(j == self.j, "1: bad j") g(self.i-2, self.j * 2 + 1) else: if len(state.answers) % 7 == 5: gc.collect() state.answers.append(self.j) - assert j == self.j + ll_assert(j == self.j, "2: bad j") run._dont_inline_ = True - def bootstrap(): + def before_extcall(): + release_NOAUTO(state.gil) + before_extcall._gctransformer_hint_cannot_collect_ = True + # ^^^ see comments in gil.py about this hint + + def after_extcall(): acquire_NOAUTO(state.gil, True) gc_thread_run() + after_extcall._gctransformer_hint_cannot_collect_ = True + # ^^^ see comments in gil.py about this hint + + def bootstrap(): + # after_extcall() is called before we arrive here. + # We can't just acquire and release the GIL manually here, + # because it is unsafe: bootstrap() is called from a rffi + # callback which checks for and reports exceptions after + # bootstrap() returns. The exception checking code must be + # protected by the GIL too. z = state.z state.z = None + state.bootstrapping.release() z.run() gc_thread_die() - release_NOAUTO(state.gil) + # before_extcall() is called after we leave here def g(i, j): + state.bootstrapping.acquire(True) state.z = Z(i, j) gc_thread_prepare() start_new_thread(bootstrap, ()) - # now wait until the new thread really started and consumed 'z' - willing_to_wait_more = 1000 - while state.z is not None: - assert willing_to_wait_more > 0 - willing_to_wait_more -= 1 - release_NOAUTO(state.gil) - time.sleep(0.005) - acquire_NOAUTO(state.gil, True) - gc_thread_run() def f(): state.gil = allocate_ll_lock() acquire_NOAUTO(state.gil, True) + state.bootstrapping = allocate_lock() state.answers = [] state.finished = 0 - g(7, 1) + # the next line installs before_extcall() and after_extcall() + # to be called automatically around external function calls. + # When not translated it does not work around time.sleep(), + # so we have to call them manually for this test. + invoke_around_extcall(before_extcall, after_extcall) + + g(10, 1) done = False - willing_to_wait_more = 1000 + willing_to_wait_more = 2000 while not done: if not willing_to_wait_more: - raise Exception("didn't get enough answers: got %d," - " expected %d" % (len(state.answers), - expected)) + break willing_to_wait_more -= 1 done = len(state.answers) == expected - release_NOAUTO(state.gil) + + if not we_are_translated(): before_extcall() time.sleep(0.01) - acquire_NOAUTO(state.gil, True) - gc_thread_run() - release_NOAUTO(state.gil) + if not we_are_translated(): after_extcall() + + if not we_are_translated(): before_extcall() time.sleep(0.1) + if not we_are_translated(): after_extcall() + return len(state.answers) - expected = 21 - fn = self.getcompiled(f, []) + expected = 89 + try: + fn = self.getcompiled(f, []) + finally: + rffi.aroundstate._freeze_() answers = fn() assert answers == expected From arigo at codespeak.net Sat Jun 28 15:00:05 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 15:00:05 +0200 (CEST) Subject: [pypy-svn] r56150 - pypy/branch/async-del/pypy/objspace/std/test Message-ID: <20080628130005.61C742A01C9@codespeak.net> Author: arigo Date: Sat Jun 28 15:00:02 2008 New Revision: 56150 Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Log: This test now passes, also with pypy-c. Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Sat Jun 28 15:00:02 2008 @@ -739,13 +739,13 @@ assert l[10:] == [0, 1, 2, 3, 4, 6, 7, 8, 9] def test_mutate_while_extend(self): - # this segfaults pypy-c (try py.test -A) + # this used to segfault pypy-c (with py.test -A) class A(object): def __del__(self): print 'del' del lst[:] - keepalive = [] for i in range(10): + keepalive = [] lst = list(str(i)) * 100 A() while lst: From arigo at codespeak.net Sat Jun 28 15:02:47 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 15:02:47 +0200 (CEST) Subject: [pypy-svn] r56151 - pypy/branch/async-del/pypy/objspace/std/test Message-ID: <20080628130247.0A8D02A01BD@codespeak.net> Author: arigo Date: Sat Jun 28 15:02:46 2008 New Revision: 56151 Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Log: The __del__ may be never called if we're unlucky with Boehm. Modified: pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/branch/async-del/pypy/objspace/std/test/test_listobject.py Sat Jun 28 15:02:46 2008 @@ -740,6 +740,10 @@ def test_mutate_while_extend(self): # this used to segfault pypy-c (with py.test -A) + import sys + if hasattr(sys, 'pypy_translation_info'): + if sys.pypy_translation_info['translation.gc'] == 'boehm': + skip("not reliable on top of Boehm") class A(object): def __del__(self): print 'del' From antocuni at codespeak.net Sat Jun 28 17:36:49 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 28 Jun 2008 17:36:49 +0200 (CEST) Subject: [pypy-svn] r56152 - in pypy/branch/oo-jit/pypy/jit/rainbow: . test Message-ID: <20080628153649.3F886168447@codespeak.net> Author: antocuni Date: Sat Jun 28 17:36:47 2008 New Revision: 56152 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Log: add a failing test and the corresponding fix Modified: pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/codewriter.py Sat Jun 28 17:36:47 2008 @@ -988,10 +988,10 @@ from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.ootypesystem.rclass import OBJECT # TODO write tests for these cases -## if arg.concretetype is lltype.Void: +## if v_obj.concretetype is lltype.Void: ## return -## if self.varcolor(arg) == "green": -## self.register_greenvar(result, self.green_position(arg)) +## if self.varcolor(v_obj) == "green": +## self.register_greenvar(result, self.green_position(v_obj)) ## return v_class = op.args[2] self.emit("promote") @@ -1859,12 +1859,19 @@ self.emit(*emitted_args) methnameindex = self.string_position(name) self.emit(methnameindex) + result_color = self.varcolor(op.result) if kind == 'yellow': - self.emit("yellow_retrieve_result_as_red") - self.emit(self.type_position(op.result.concretetype)) - + if result_color == 'red': + self.emit("yellow_retrieve_result_as_red") + self.emit(self.type_position(op.result.concretetype)) + else: + self.emit("yellow_retrieve_result") + if has_result: - self.register_redvar(op.result) + if result_color == 'red': + self.register_redvar(op.result) + else: + self.register_greenvar(op.result) self.emit(label(("after oosend", op))) Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_interpreter.py Sat Jun 28 17:36:47 2008 @@ -1030,6 +1030,19 @@ assert res == 44 self.check_insns({'int_mul': 1, 'int_add': 1, 'int_sub': 1}) + def test_yellow_meth_with_green_result(self): + class A: + def m(self): + return 42 + + def fn(): + x = A() + return x.m() + res = self.interpret(fn, []) + assert res == 42 + self.check_insns(malloc=0) + self.check_insns(new=0) + def test_green_red_mismatch_in_call(self): def add(a,b, u): return a+b @@ -1913,7 +1926,6 @@ res = self.interpret(fn, [True], [], policy=StopAtXPolicy(g)) assert res - def test_manymanyvars(self): def h(i00, i01, i02, i03, i04, i05, i06, i07, i08, i09, From antocuni at codespeak.net Sat Jun 28 17:38:21 2008 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 28 Jun 2008 17:38:21 +0200 (CEST) Subject: [pypy-svn] r56153 - in pypy/branch/oo-jit/pypy/jit/rainbow: . test Message-ID: <20080628153821.E019916A03A@codespeak.net> Author: antocuni Date: Sat Jun 28 17:38:21 2008 New Revision: 56153 Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Log: if we are asserting the class of a vstruct, we don't need to do anything Modified: pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/interpreter.py Sat Jun 28 17:38:21 2008 @@ -631,6 +631,8 @@ @arguments("red", "green", "fielddesc", returns="red") def opimpl_assert_class(self, objbox, gv_class, fielddesc): + if isinstance(objbox.content, rcontainer.VirtualStruct): + return objbox classbox = self.PtrRedBox(gv_class) objbox.remember_field(fielddesc, classbox) return objbox Modified: pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py ============================================================================== --- pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py (original) +++ pypy/branch/oo-jit/pypy/jit/rainbow/test/test_promotion.py Sat Jun 28 17:38:21 2008 @@ -499,6 +499,19 @@ self.check_insns(malloc=0) self.check_insns(new=0) + def test_promote_class_vstruct(self): + class A: + def m(self): + return 42 + + def ll_function(): + x = A() + y = hint(x, promote_class=True) + return y.m() + res = self.interpret(ll_function, [], []) + assert res == 42 + self.check_insns(malloc=0) + self.check_insns(new=0) class TestLLType(BaseTestPromotion): type_system = "lltype" From arigo at codespeak.net Sat Jun 28 18:43:20 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 18:43:20 +0200 (CEST) Subject: [pypy-svn] r56154 - in pypy/dist/pypy: interpreter interpreter/test module/_file module/signal module/sys module/thread module/thread/test objspace/std/test translator/c/src Message-ID: <20080628164320.70CB72A00E3@codespeak.net> Author: arigo Date: Sat Jun 28 18:43:18 2008 New Revision: 56154 Modified: pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/test/test_executioncontext.py pypy/dist/pypy/interpreter/test/test_pyframe.py pypy/dist/pypy/interpreter/test/test_typedef.py pypy/dist/pypy/interpreter/typedef.py pypy/dist/pypy/module/_file/interp_stream.py pypy/dist/pypy/module/signal/__init__.py pypy/dist/pypy/module/signal/interp_signal.py pypy/dist/pypy/module/sys/vm.py pypy/dist/pypy/module/thread/__init__.py pypy/dist/pypy/module/thread/gil.py pypy/dist/pypy/module/thread/test/test_gil.py pypy/dist/pypy/module/thread/test/test_ll_thread.py pypy/dist/pypy/module/thread/threadlocals.py pypy/dist/pypy/objspace/std/test/test_listobject.py pypy/dist/pypy/translator/c/src/signals.h Log: issue371 resolved Merge the async-del branch: * Don't call the app-level __del__() methods when the gc calls the interp-level __del__() methods; instead, queue them for later. This fixes potential segfaults (see test_listobject.py). * Refactor the Action system. The goal is to let actions like calling __del__() or delivering a signal occur immediately, i.e. before the next opcode, instead of having to wait for sys.checkinterval opcodes. * Use this to detect signals immediately; removes the need for a hack in module/_file's wrap_oserror_as_ioerror(). * Whack at threads (most notably, fix a bogus test). * A few new tests relating to the above features. The new Action classes are a bit more static (and quite more efficient, reducing overhead). The idea is to register during space initialization which async actions can possibly occur, and allocate one bit of an integer to each of them; in this way, the ExecutionContext's bytecode_trace() can check if there is anything special to do or not just by checking if this integer is != 0. Line-by-line tracing is now done as an action too, which also reduces the overhead when it is not used. Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Sat Jun 28 18:43:18 2008 @@ -1,4 +1,5 @@ -from pypy.interpreter.executioncontext import ExecutionContext +from pypy.interpreter.executioncontext import ExecutionContext, ActionFlag +from pypy.interpreter.executioncontext import UserDelAction, FrameTraceAction from pypy.interpreter.error import OperationError from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack from pypy.interpreter.pycompiler import CPythonCompiler, PythonAstCompiler @@ -137,6 +138,9 @@ self.setweakref(lifeline.space, None) lifeline.clear_all_weakrefs() + def _call_builtin_destructor(self): + pass # method overridden in typedef.py + class Wrappable(W_Root): """A subclass of Wrappable is an internal, interpreter-level class @@ -218,7 +222,11 @@ import pypy.interpreter.nestedscope # register *_DEREF bytecodes self.interned_strings = {} - self.pending_actions = [] + self.actionflag = ActionFlag() # changed by the signal module + self.user_del_action = UserDelAction(self) + self.frame_trace_action = FrameTraceAction(self) + self.actionflag.register_action(self.user_del_action) + self.actionflag.register_action(self.frame_trace_action) self.setoptions(**kw) # if self.config.objspace.logbytecodes: Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sat Jun 28 18:43:18 2008 @@ -1,6 +1,8 @@ import sys -from pypy.interpreter.miscutils import Stack, Action +from pypy.interpreter.miscutils import Stack from pypy.interpreter.error import OperationError +from pypy.rlib.rarithmetic import LONG_BIT +from pypy.rlib.unroll import unrolling_iterable def new_framestack(): return Stack() @@ -17,10 +19,11 @@ def __init__(self, space): self.space = space self.framestack = new_framestack() + # tracing: space.frame_trace_action.fire() must be called to ensure + # that tracing occurs whenever self.w_tracefunc or self.is_tracing + # is modified. self.w_tracefunc = None self.is_tracing = 0 - self.ticker = 0 - self.pending_actions = [] self.compiler = space.createcompiler() self.profilefunc = None self.w_profilefuncarg = None @@ -43,6 +46,8 @@ if not frame.hide(): self.framestack.pop() + if self.w_tracefunc is not None: + self.space.frame_trace_action.fire() class Subcontext(object): @@ -61,6 +66,7 @@ ec.profilefunc = self.profilefunc ec.w_profilefuncarg = self.w_profilefuncarg ec.is_tracing = self.is_tracing + ec.space.frame_trace_action.fire() def leave(self, ec): self.framestack = ec.framestack @@ -100,76 +106,32 @@ def call_trace(self, frame): "Trace the call of a function" - self._trace(frame, 'call', self.space.w_None) + if self.w_tracefunc is not None or self.profilefunc is not None: + self._trace(frame, 'call', self.space.w_None) def return_trace(self, frame, w_retval): "Trace the return from a function" - self._trace(frame, 'return', w_retval) + if self.w_tracefunc is not None: + self._trace(frame, 'return', w_retval) def bytecode_trace(self, frame): "Trace function called before each bytecode." # this is split into a fast path and a slower path that is # not invoked every time bytecode_trace() is. - ticker = self.ticker - 1 - self.ticker = ticker - if ticker < 0 or frame.w_f_trace is not None: - self._do_bytecode_trace(frame) + actionflag = self.space.actionflag + ticker = actionflag.get() + if actionflag.has_bytecode_counter: # this "if" is constant-folded + ticker += 1 + actionflag.set(ticker) + if ticker & actionflag.interesting_bits: # fast check + actionflag.action_dispatcher(self) # slow path bytecode_trace._always_inline_ = True - def _do_bytecode_trace(self, frame): - if self.ticker < 0: - Action.perform_actions(self.space.pending_actions) - Action.perform_actions(self.pending_actions) - self.ticker = self.space.sys.checkinterval - if frame.w_f_trace is None or self.is_tracing: - return - code = frame.pycode - if frame.instr_lb <= frame.last_instr < frame.instr_ub: - if frame.last_instr <= frame.instr_prev: - # We jumped backwards in the same line. - self._trace(frame, 'line', self.space.w_None) - else: - size = len(code.co_lnotab) / 2 - addr = 0 - line = code.co_firstlineno - p = 0 - lineno = code.co_lnotab - while size > 0: - c = ord(lineno[p]) - if (addr + c) > frame.last_instr: - break - addr += c - if c: - frame.instr_lb = addr - - line += ord(lineno[p + 1]) - p += 2 - size -= 1 - - if size > 0: - while True: - size -= 1 - if size < 0: - break - addr += ord(lineno[p]) - if ord(lineno[p + 1]): - break - p += 2 - frame.instr_ub = addr - else: - frame.instr_ub = sys.maxint - - if frame.instr_lb == frame.last_instr: # At start of line! - frame.f_lineno = line - self._trace(frame, 'line', self.space.w_None) - - frame.instr_prev = frame.last_instr - def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() - space = self.space - self._trace(frame, 'exception', None, operationerr) + if self.w_tracefunc is not None: + self._trace(frame, 'exception', None, operationerr) #operationerr.print_detailed_traceback(self.space) def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!! @@ -187,6 +149,7 @@ self.w_tracefunc = None else: self.w_tracefunc = w_func + self.space.frame_trace_action.fire() def setprofile(self, w_func): """Set the global trace function.""" @@ -207,6 +170,7 @@ is_tracing = self.is_tracing self.is_tracing = 0 try: + self.space.frame_trace_action.fire() return self.space.call(w_func, w_args) finally: self.is_tracing = is_tracing @@ -244,6 +208,7 @@ finally: self.is_tracing -= 1 frame.locals2fast() + space.frame_trace_action.fire() # Profile cases if self.profilefunc is not None: @@ -270,11 +235,239 @@ frame.last_exception = last_exception self.is_tracing -= 1 - def add_pending_action(self, action): - self.pending_actions.append(action) - self.ticker = 0 - def _freeze_(self): raise Exception("ExecutionContext instances should not be seen during" " translation. Now is a good time to inspect the" " traceback and see where this one comes from :-)") + + +class AbstractActionFlag: + """This holds the global 'action flag'. It is a single bitfield + integer, with bits corresponding to AsyncAction objects that need to + be immediately triggered. The correspondance from bits to + AsyncAction instances is built at translation time. We can quickly + check if there is anything at all to do by checking if any of the + relevant bits is set. If threads are enabled, they consume the 20 + lower bits to hold a counter incremented at each bytecode, to know + when to release the GIL. + """ + def __init__(self): + self._periodic_actions = [] + self._nonperiodic_actions = [] + self.unused_bits = self.FREE_BITS[:] + self.has_bytecode_counter = False + self.interesting_bits = 0 + self._rebuild_action_dispatcher() + + def fire(self, action): + """Request for the action to be run before the next opcode. + The action must have been registered at space initalization time.""" + ticker = self.get() + self.set(ticker | action.bitmask) + + def register_action(self, action): + "NOT_RPYTHON" + assert isinstance(action, AsyncAction) + if action.bitmask == 0: + while True: + action.bitmask = self.unused_bits.pop(0) + if not (action.bitmask & self.interesting_bits): + break + self.interesting_bits |= action.bitmask + if action.bitmask & self.BYTECODE_COUNTER_OVERFLOW_BIT: + assert action.bitmask == self.BYTECODE_COUNTER_OVERFLOW_BIT + self._periodic_actions.append(action) + self.has_bytecode_counter = True + self.force_tick_counter() + else: + self._nonperiodic_actions.append((action, action.bitmask)) + self._rebuild_action_dispatcher() + + def setcheckinterval(self, space, interval): + if interval < self.CHECK_INTERVAL_MIN: + interval = self.CHECK_INTERVAL_MIN + elif interval > self.CHECK_INTERVAL_MAX: + interval = self.CHECK_INTERVAL_MAX + space.sys.checkinterval = interval + self.force_tick_counter() + + def force_tick_counter(self): + # force the tick counter to a valid value -- this actually forces + # it to reach BYTECODE_COUNTER_OVERFLOW_BIT at the next opcode. + ticker = self.get() + ticker |= self.BYTECODE_COUNTER_MASK + self.set(ticker) + + def _rebuild_action_dispatcher(self): + periodic_actions = unrolling_iterable(self._periodic_actions) + nonperiodic_actions = unrolling_iterable(self._nonperiodic_actions) + has_bytecode_counter = self.has_bytecode_counter + + def action_dispatcher(ec): + # periodic actions + if has_bytecode_counter: + ticker = self.get() + if ticker & self.BYTECODE_COUNTER_OVERFLOW_BIT: + # We must run the periodic actions now, but first + # reset the bytecode counter (the following logic + # works because the BYTECODE_COUNTER_OVERFLOW_BIT + # is currently set) + ticker &= ~ self.BYTECODE_COUNTER_MASK + ticker -= ec.space.sys.checkinterval + self.set(ticker) + for action in periodic_actions: + action.perform(ec) + + # nonperiodic actions + for action, bitmask in nonperiodic_actions: + ticker = self.get() + if ticker & bitmask: + self.set(ticker & ~ bitmask) + action.perform(ec) + + action_dispatcher._dont_inline_ = True + self.action_dispatcher = action_dispatcher + + # Bits reserved for the bytecode counter, if used + BYTECODE_COUNTER_MASK = (1 << 20) - 1 + BYTECODE_COUNTER_OVERFLOW_BIT = (1 << 20) + + # Free bits + FREE_BITS = [1 << _b for _b in range(21, LONG_BIT-1)] + + # The acceptable range of values for sys.checkinterval, so that + # the bytecode_counter fits in 20 bits + CHECK_INTERVAL_MIN = 1 + CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT + + +class ActionFlag(AbstractActionFlag): + """The normal class for space.actionflag. The signal module provides + a different one.""" + _flags = 0 + + def get(self): + return self._flags + + def set(self, value): + self._flags = value + + +class AsyncAction(object): + """Abstract base class for actions that must be performed + asynchronously with regular bytecode execution, but that still need + to occur between two opcodes, not at a completely random time. + """ + bitmask = 0 # means 'please choose one bit automatically' + + def __init__(self, space): + self.space = space + + def fire(self): + """Request for the action to be run before the next opcode. + The action must have been registered at space initalization time.""" + self.space.actionflag.fire(self) + + def fire_after_thread_switch(self): + """Bit of a hack: fire() the action but only the next time the GIL + is released and re-acquired (i.e. after a portential thread switch). + Don't call this if threads are not enabled. + """ + from pypy.module.thread.gil import spacestate + spacestate.set_actionflag_bit_after_thread_switch |= self.bitmask + + def perform(self, executioncontext): + """To be overridden.""" + + +class PeriodicAsyncAction(AsyncAction): + """Abstract base class for actions that occur automatically + every sys.checkinterval bytecodes. + """ + bitmask = ActionFlag.BYTECODE_COUNTER_OVERFLOW_BIT + + +class UserDelAction(AsyncAction): + """An action that invokes all pending app-level __del__() method. + This is done as an action instead of immediately when the + interp-level __del__() is invoked, because the latter can occur more + or less anywhere in the middle of code that might not be happy with + random app-level code mutating data structures under its feet. + """ + + def __init__(self, space): + AsyncAction.__init__(self, space) + self.dying_objects_w = [] + + def register_dying_object(self, w_obj): + self.dying_objects_w.append(w_obj) + self.fire() + + def perform(self, executioncontext): + # Each call to perform() first grabs the self.dying_objects_w + # and replaces it with an empty list. We do this to try to + # avoid too deep recursions of the kind of __del__ being called + # while in the middle of another __del__ call. + pending_w = self.dying_objects_w + self.dying_objects_w = [] + space = self.space + for w_obj in pending_w: + try: + space.userdel(w_obj) + except OperationError, e: + e.write_unraisable(space, 'method __del__ of ', w_obj) + e.clear(space) # break up reference cycles + # finally, this calls the interp-level destructor for the + # cases where there is both an app-level and a built-in __del__. + w_obj._call_builtin_destructor() + + +class FrameTraceAction(AsyncAction): + """An action that calls the local trace functions (w_f_trace).""" + + def perform(self, executioncontext): + frame = executioncontext.framestack.top() + if frame.w_f_trace is None or executioncontext.is_tracing: + return + code = frame.pycode + if frame.instr_lb <= frame.last_instr < frame.instr_ub: + if frame.last_instr <= frame.instr_prev: + # We jumped backwards in the same line. + executioncontext._trace(frame, 'line', self.space.w_None) + else: + size = len(code.co_lnotab) / 2 + addr = 0 + line = code.co_firstlineno + p = 0 + lineno = code.co_lnotab + while size > 0: + c = ord(lineno[p]) + if (addr + c) > frame.last_instr: + break + addr += c + if c: + frame.instr_lb = addr + + line += ord(lineno[p + 1]) + p += 2 + size -= 1 + + if size > 0: + while True: + size -= 1 + if size < 0: + break + addr += ord(lineno[p]) + if ord(lineno[p + 1]): + break + p += 2 + frame.instr_ub = addr + else: + frame.instr_ub = sys.maxint + + if frame.instr_lb == frame.last_instr: # At start of line! + frame.f_lineno = line + executioncontext._trace(frame, 'line', self.space.w_None) + + frame.instr_prev = frame.last_instr + self.space.frame_trace_action.fire() # continue tracing Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Sat Jun 28 18:43:18 2008 @@ -167,26 +167,3 @@ def getmainthreadvalue(self): return self._value - - -class Action(object): - """Abstract base class for actions that must be performed regularly, - every Nth bytecode (as selected by sys.setcheckinterval()).""" - - # set repeat to True for actions that must be kept around and - # re-performed regularly - repeat = False - - def perform(self): - """To be overridden.""" - - def perform_actions(actionlist): - i = 0 - while i < len(actionlist): - a = actionlist[i] - if a.repeat: - i += 1 # keep action - else: - del actionlist[i] - a.perform() - perform_actions = staticmethod(perform_actions) Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Sat Jun 28 18:43:18 2008 @@ -348,6 +348,7 @@ new_frame.instr_prev = space.int_w(w_instr_prev) self._setcellvars(cellvars) + space.frame_trace_action.fire() def hide(self): return self.pycode.hidden_applevel @@ -539,6 +540,7 @@ else: self.w_f_trace = w_trace self.f_lineno = self.get_last_lineno() + space.frame_trace_action.fire() def fdel_f_trace(space, self): self.w_f_trace = None Modified: pypy/dist/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/dist/pypy/interpreter/test/test_executioncontext.py Sat Jun 28 18:43:18 2008 @@ -1,39 +1,65 @@ import py -from pypy.interpreter import miscutils +from pypy.interpreter import executioncontext + + +class Finished(Exception): + pass class TestExecutionContext: def test_action(self): - class Finished(Exception): - pass - class DemoAction(miscutils.Action): - def __init__(self, repeat): - self.repeat = repeat - self.counter = 0 - def perform(self): + class DemoAction(executioncontext.AsyncAction): + counter = 0 + def perform(self, ec): self.counter += 1 if self.counter == 10: raise Finished - a1 = DemoAction(False) - a2 = DemoAction(True) - a3 = DemoAction(False) + space = self.space + a1 = DemoAction(space) + space.actionflag.register_action(a1) + for i in range(20): + # assert does not raise: + space.appexec([], """(): + n = 5 + return n + 2 + """) + try: + for i in range(20): + a1.fire() + space.appexec([], """(): + n = 5 + return n + 2 + """) + assert a1.counter == i + 1 + except Finished: + pass + assert i == 9 + + def test_periodic_action(self): + + class DemoAction(executioncontext.PeriodicAsyncAction): + counter = 0 + def perform(self, ec): + self.counter += 1 + print '->', self.counter + if self.counter == 3: + raise Finished space = self.space - space.pending_actions.append(a1) - space.getexecutioncontext().add_pending_action(a2) - space.getexecutioncontext().add_pending_action(a3) - - py.test.raises(Finished, space.appexec, [], """(): - n = 50000 - while n > 0: - n -= 1 - """) - assert a1.counter == 1 - assert a2.counter == 10 - assert a3.counter == 1 + a2 = DemoAction(space) + space.actionflag.register_action(a2) + try: + for i in range(500): + space.appexec([], """(): + n = 5 + return n + 2 + """) + except Finished: + pass + assert space.sys.checkinterval / 10 < i < space.sys.checkinterval * 3 def test_llprofile(self): l = [] Modified: pypy/dist/pypy/interpreter/test/test_pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_pyframe.py (original) +++ pypy/dist/pypy/interpreter/test/test_pyframe.py Sat Jun 28 18:43:18 2008 @@ -73,7 +73,54 @@ raise OuterException except: g(sys.exc_info()) - + + def test_trace_basic(self): + import sys + l = [] + class Tracer: + def __init__(self, i): + self.i = i + def trace(self, frame, event, arg): + l.append((self.i, frame.f_code.co_name, event, arg)) + if frame.f_code.co_name == 'g2': + return None # don't trace g2 + return Tracer(self.i+1).trace + def g3(n): + n -= 5 + return n + def g2(n): + n += g3(2) + n += g3(7) + return n + def g(n): + n += g2(3) + return n + def f(n): + n = g(n) + return n * 7 + sys.settrace(Tracer(0).trace) + x = f(4) + sys.settrace(None) + assert x == 42 + print l + assert l == [(0, 'f', 'call', None), + (1, 'f', 'line', None), + (0, 'g', 'call', None), + (1, 'g', 'line', None), + (0, 'g2', 'call', None), + (0, 'g3', 'call', None), + (1, 'g3', 'line', None), + (2, 'g3', 'line', None), + (3, 'g3', 'return', -3), + (0, 'g3', 'call', None), + (1, 'g3', 'line', None), + (2, 'g3', 'line', None), + (3, 'g3', 'return', 2), + (2, 'g', 'line', None), + (3, 'g', 'return', 6), + (2, 'f', 'line', None), + (3, 'f', 'return', 42)] + def test_trace_exc(self): import sys l = [] Modified: pypy/dist/pypy/interpreter/test/test_typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_typedef.py (original) +++ pypy/dist/pypy/interpreter/test/test_typedef.py Sat Jun 28 18:43:18 2008 @@ -1,4 +1,5 @@ from pypy.interpreter import typedef +from pypy.tool.udir import udir # this test isn't so much to test that the objspace interface *works* # -- it's more to test that it's *there* @@ -130,3 +131,27 @@ for cls, set in subclasses.items(): assert len(set) <= 6, "%s has %d subclasses:\n%r" % ( cls, len(set), [subcls.__name__ for subcls in set]) + + +class AppTestTypeDef: + + def setup_class(cls): + path = udir.join('AppTestTypeDef.txt') + path.write('hello world\n') + cls.w_path = cls.space.wrap(str(path)) + + def test_destructor(self): + import gc, os + seen = [] + class MyFile(file): + def __del__(self): + seen.append(10) + seen.append(os.lseek(self.fileno(), 2, 0)) + f = MyFile(self.path, 'r') + fd = f.fileno() + seen.append(os.lseek(fd, 5, 0)) + del f + gc.collect(); gc.collect(); gc.collect() + lst = seen[:] + assert lst == [5, 10, 2] + raises(OSError, os.lseek, fd, 7, 0) Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Sat Jun 28 18:43:18 2008 @@ -9,7 +9,7 @@ DescrMismatch from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import compile2, func_with_new_name -from pypy.rlib.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate, we_are_translated from pypy.rlib.rarithmetic import intmask class TypeDef: @@ -247,12 +247,27 @@ add(Proto) if "del" in features: - parent_destructor = getattr(supercls, '__del__', None) class Proto(object): + _del_was_called = False def __del__(self): - call_user_destructor(self.space, self) - if parent_destructor is not None: - parent_destructor(self) + # the logic below always resurect the objects, so when + # running on top of CPython we must manually ensure that + # we do it only once + if not we_are_translated(): + if self._del_was_called: + return + self._del_was_called = True + self.clear_all_weakrefs() + self.space.user_del_action.register_dying_object(self) + # if the base class needs its own interp-level __del__, + # we override the _call_builtin_destructor() method to invoke it + # after the app-level destructor. + parent_destructor = getattr(supercls, '__del__', None) + if parent_destructor is not None: + def _call_builtin_destructor(self): + parent_destructor(self) + Proto._call_builtin_destructor = _call_builtin_destructor + add(Proto) if "slots" in features: @@ -323,15 +338,6 @@ return w_dict check_new_dictionary._dont_inline_ = True -def call_user_destructor(space, w_self): - w_self.clear_all_weakrefs() - try: - space.userdel(w_self) - except OperationError, e: - e.write_unraisable(space, 'method __del__ of ', w_self) - e.clear(space) # break up reference cycles -call_user_destructor._dont_inline_ = True - # ____________________________________________________________ def make_descr_typecheck_wrapper(func, extraargs=(), cls=None): Modified: pypy/dist/pypy/module/_file/interp_stream.py ============================================================================== --- pypy/dist/pypy/module/_file/interp_stream.py (original) +++ pypy/dist/pypy/module/_file/interp_stream.py Sat Jun 28 18:43:18 2008 @@ -7,7 +7,6 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app -from pypy.interpreter.miscutils import Action import os @@ -25,14 +24,6 @@ def wrap_oserror_as_ioerror(space, e): assert isinstance(e, OSError) errno = e.errno - if errno == EINTR: - # A signal was sent to the process and interupted - # a systemcall. We want to trigger running of - # any installed interrupt handlers. - # XXX: is there a better way? - ec = space.getexecutioncontext() - Action.perform_actions(space.pending_actions) - Action.perform_actions(ec.pending_actions) try: msg = os.strerror(errno) except ValueError: Modified: pypy/dist/pypy/module/signal/__init__.py ============================================================================== --- pypy/dist/pypy/module/signal/__init__.py (original) +++ pypy/dist/pypy/module/signal/__init__.py Sat Jun 28 18:43:18 2008 @@ -25,7 +25,13 @@ def __init__(self, space, *args): "NOT_RPYTHON" - from pypy.module.signal.interp_signal import CheckSignalAction + from pypy.module.signal import interp_signal MixedModule.__init__(self, space, *args) # add the signal-checking callback as an action on the space - space.pending_actions.append(CheckSignalAction(space)) + space.check_signal_action = interp_signal.CheckSignalAction(space) + space.actionflag.register_action(space.check_signal_action) + # use the C-level pypysig_occurred variable as the action flag + # (the result is that the C-level signal handler will directly + # set the flag for the CheckSignalAction) + space.actionflag.__class__ = interp_signal.SignalActionFlag + # xxx yes I know the previous line is a hack Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Sat Jun 28 18:43:18 2008 @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace -from pypy.interpreter.miscutils import Action +from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag +from pypy.rlib.rarithmetic import LONG_BIT, intmask import signal as cpy_signal from pypy.rpython.lltypesystem import lltype, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo @@ -35,55 +36,100 @@ # don't bother releasing the GIL around a call to pypysig_poll: it's # pointless and a performance issue -class CheckSignalAction(Action): - """A repeatitive action at the space level, checking if the - signal_occurred flag is set and if so, scheduling ReportSignal actions. - """ - repeat = True +pypysig_get_occurred = external('pypysig_get_occurred', [], + lltype.Signed, _nowrapper=True) +pypysig_set_occurred = external('pypysig_set_occurred', [lltype.Signed], + lltype.Void, _nowrapper=True) + + +class SignalActionFlag(AbstractActionFlag): + get = staticmethod(pypysig_get_occurred) + set = staticmethod(pypysig_set_occurred) + + +class CheckSignalAction(AsyncAction): + """An action that is automatically invoked when a signal is received.""" + + # The C-level signal handler sets the highest bit of pypysig_occurred: + bitmask = intmask(1 << (LONG_BIT-1)) def __init__(self, space): - self.space = space + AsyncAction.__init__(self, space) self.handlers_w = {} + if space.config.objspace.usemodules.thread: + # need a helper action in case signals arrive in a non-main thread + self.pending_signals = {} + self.reissue_signal_action = ReissueSignalAction(space) + space.actionflag.register_action(self.reissue_signal_action) + else: + self.reissue_signal_action = None - def perform(self): + def perform(self, executioncontext): while True: n = pypysig_poll() if n < 0: break - main_ec = self.space.threadlocals.getmainthreadvalue() - main_ec.add_pending_action(ReportSignal(self, n)) - - def get(space): - for action in space.pending_actions: - if isinstance(action, CheckSignalAction): - return action - raise OperationError(space.w_RuntimeError, - space.wrap("lost CheckSignalAction")) - get = staticmethod(get) - - -class ReportSignal(Action): - """A one-shot action for the main thread's execution context.""" - - def __init__(self, action, signum): - self.action = action - self.signum = signum + if self.reissue_signal_action is None: + # no threads: we can report the signal immediately + self.report_signal(n) + else: + main_ec = self.space.threadlocals.getmainthreadvalue() + if executioncontext is main_ec: + # running in the main thread: we can report the + # signal immediately + self.report_signal(n) + else: + # running in another thread: we need to hack a bit + self.pending_signals[n] = None + self.reissue_signal_action.fire_after_thread_switch() - def perform(self): + def report_signal(self, n): try: - w_handler = self.action.handlers_w[self.signum] + w_handler = self.handlers_w[n] except KeyError: return # no handler, ignore signal # re-install signal handler, for OSes that clear it - pypysig_setflag(self.signum) + pypysig_setflag(n) # invoke the app-level handler - space = self.action.space + space = self.space ec = space.getexecutioncontext() try: w_frame = ec.framestack.top() except IndexError: w_frame = space.w_None - space.call_function(w_handler, space.wrap(self.signum), w_frame) + space.call_function(w_handler, space.wrap(n), w_frame) + + def report_pending_signals(self): + # XXX this logic isn't so complicated but I have no clue how + # to test it :-( + pending_signals = self.pending_signals.keys() + self.pending_signals.clear() + try: + while pending_signals: + self.report_signal(pending_signals.pop()) + finally: + # in case of exception, put the undelivered signals back + # into the dict instead of silently swallowing them + if pending_signals: + for n in pending_signals: + self.pending_signals[n] = None + self.reissue_signal_action.fire() + + +class ReissueSignalAction(AsyncAction): + """A special action to help deliver signals to the main thread. If + a non-main thread caught a signal, this action fires after every + thread switch until we land in the main thread. + """ + + def perform(self, executioncontext): + main_ec = self.space.threadlocals.getmainthreadvalue() + if executioncontext is main_ec: + # now running in the main thread: we can really report the signals + self.space.check_signal_action.report_pending_signals() + else: + # still running in some other thread: try again later + self.fire_after_thread_switch() def getsignal(space, signum): @@ -96,7 +142,7 @@ None -- if an unknown handler is in effect (XXX UNIMPLEMENTED) anything else -- the callable Python object used as a handler """ - action = CheckSignalAction.get(space) + action = space.check_signal_action if signum in action.handlers_w: return action.handlers_w[signum] return space.wrap(SIG_DFL) @@ -124,7 +170,7 @@ raise OperationError(space.w_ValueError, space.wrap("signal() must be called from the " "main thread")) - action = CheckSignalAction.get(space) + action = space.check_signal_action if space.eq_w(w_handler, space.wrap(SIG_DFL)): pypysig_default(signum) action.handlers_w[signum] = w_handler Modified: pypy/dist/pypy/module/sys/vm.py ============================================================================== --- pypy/dist/pypy/module/sys/vm.py (original) +++ pypy/dist/pypy/module/sys/vm.py Sat Jun 28 18:43:18 2008 @@ -2,6 +2,7 @@ Implementation of interpreter-level 'sys' routines. """ from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import ObjSpace import sys # ____________________________________________________________ @@ -57,11 +58,11 @@ return space.wrap(space.sys.recursionlimit) -def setcheckinterval(space, w_interval): +def setcheckinterval(space, interval): """Tell the Python interpreter to check for asynchronous events every n instructions. This also affects how often thread switches occur.""" - space.sys.checkinterval = space.int_w(w_interval) - space.getexecutioncontext().ticker = 0 + space.actionflag.setcheckinterval(space, interval) +setcheckinterval.unwrap_spec = [ObjSpace, int] def getcheckinterval(space): """Return the current check interval; see setcheckinterval().""" Modified: pypy/dist/pypy/module/thread/__init__.py ============================================================================== --- pypy/dist/pypy/module/thread/__init__.py (original) +++ pypy/dist/pypy/module/thread/__init__.py Sat Jun 28 18:43:18 2008 @@ -30,4 +30,5 @@ MixedModule.__init__(self, space, *args) prev = space.threadlocals.getvalue() space.threadlocals = gil.GILThreadLocals() + space.threadlocals.initialize(space) space.threadlocals.setvalue(prev) Modified: pypy/dist/pypy/module/thread/gil.py ============================================================================== --- pypy/dist/pypy/module/thread/gil.py (original) +++ pypy/dist/pypy/module/thread/gil.py Sat Jun 28 18:43:18 2008 @@ -9,7 +9,7 @@ from pypy.module.thread import ll_thread as thread from pypy.module.thread.error import wrap_thread_error -from pypy.interpreter.miscutils import Action +from pypy.interpreter.executioncontext import PeriodicAsyncAction from pypy.module.thread.threadlocals import OSThreadLocals from pypy.rlib.objectmodel import invoke_around_extcall from pypy.rlib.rposix import get_errno, set_errno @@ -18,6 +18,10 @@ """A version of OSThreadLocals that enforces a GIL.""" ll_GIL = thread.null_ll_lock + def initialize(self, space): + # add the GIL-releasing callback as an action on the space + space.actionflag.register_action(GILReleaseAction(space)) + def setup_threads(self, space): """Enable threads in the object space, if they haven't already been.""" if not self.ll_GIL: @@ -27,8 +31,6 @@ raise wrap_thread_error(space, "can't allocate GIL") thread.acquire_NOAUTO(self.ll_GIL, True) self.enter_thread(space) # setup the main thread - # add the GIL-releasing callback as an action on the space - space.pending_actions.append(GILReleaseAction(self)) result = True else: result = False # already set up @@ -42,36 +44,45 @@ # test_compile_lock. As a workaround, we repatch these global # fields systematically. spacestate.ll_GIL = self.ll_GIL + spacestate.actionflag = space.actionflag invoke_around_extcall(before_external_call, after_external_call) return result def yield_thread(self): - """Notification that the current thread is between two bytecodes: - release the GIL for a little while.""" - # Other threads can run between the release() and the acquire() - # implicit in the following external function call (which has - # otherwise no effect). - thread.yield_thread() + thread.yield_thread() # explicitly release the gil (used by test_gil) -class GILReleaseAction(Action): - """An action called when the current thread is between two bytecodes - (so that it's a good time to yield some time to other threads). +class GILReleaseAction(PeriodicAsyncAction): + """An action called every sys.checkinterval bytecodes. It releases + the GIL to give some other thread a chance to run. """ - repeat = True - - def __init__(self, threadlocals): - self.threadlocals = threadlocals - def perform(self): - self.threadlocals.yield_thread() + def perform(self, executioncontext): + # Other threads can run between the release() and the acquire() + # implicit in the following external function call (which has + # otherwise no effect). + thread.yield_thread() class SpaceState: + def _freeze_(self): self.ll_GIL = thread.null_ll_lock + self.actionflag = None + self.set_actionflag_bit_after_thread_switch = 0 return False + + def after_thread_switch(self): + # this is support logic for the signal module, to help it deliver + # signals to the main thread. + actionflag = self.actionflag + if actionflag is not None: + flag = actionflag.get() + flag |= self.set_actionflag_bit_after_thread_switch + actionflag.set(flag) + spacestate = SpaceState() +spacestate._freeze_() # Fragile code below. We have to preserve the C-level errno manually... @@ -87,5 +98,13 @@ e = get_errno() thread.acquire_NOAUTO(spacestate.ll_GIL, True) thread.gc_thread_run() + spacestate.after_thread_switch() set_errno(e) after_external_call._gctransformer_hint_cannot_collect_ = True + +# The _gctransformer_hint_cannot_collect_ hack is needed for +# translations in which the *_external_call() functions are not inlined. +# They tell the gctransformer not to save and restore the local GC +# pointers in the shadow stack. This is necessary because the GIL is +# not held after the call to before_external_call() or before the call +# to after_external_call(). Modified: pypy/dist/pypy/module/thread/test/test_gil.py ============================================================================== --- pypy/dist/pypy/module/thread/test/test_gil.py (original) +++ pypy/dist/pypy/module/thread/test/test_gil.py Sat Jun 28 18:43:18 2008 @@ -8,9 +8,17 @@ class FakeEC(object): pass +class FakeActionFlag(object): + def register_action(self, action): + pass + def get(self): + return 0 + def set(self, x): + pass + class FakeSpace(object): def __init__(self): - self.pending_actions = [] + self.actionflag = FakeActionFlag() def _freeze_(self): return True def getexecutioncontext(self): Modified: pypy/dist/pypy/module/thread/test/test_ll_thread.py ============================================================================== --- pypy/dist/pypy/module/thread/test/test_ll_thread.py (original) +++ pypy/dist/pypy/module/thread/test/test_ll_thread.py Sat Jun 28 18:43:18 2008 @@ -7,7 +7,8 @@ def setup_module(mod): # Hack to avoid a deadlock if the module is run after other test files :-( # In this module, we assume that ll_thread.start_new_thread() is not - # providing us with a GIL equivalent. + # providing us with a GIL equivalent, except in test_gc_locking + # which installs its own aroundstate. rffi.aroundstate._freeze_() def test_lock(): @@ -89,6 +90,9 @@ def test_gc_locking(self): import time + from pypy.rlib.objectmodel import invoke_around_extcall + from pypy.rlib.objectmodel import we_are_translated + from pypy.rlib.debug import ll_assert class State: pass @@ -102,63 +106,82 @@ j = self.j if self.i > 1: g(self.i-1, self.j * 2) - assert j == self.j + ll_assert(j == self.j, "1: bad j") g(self.i-2, self.j * 2 + 1) else: if len(state.answers) % 7 == 5: gc.collect() state.answers.append(self.j) - assert j == self.j + ll_assert(j == self.j, "2: bad j") run._dont_inline_ = True - def bootstrap(): + def before_extcall(): + release_NOAUTO(state.gil) + before_extcall._gctransformer_hint_cannot_collect_ = True + # ^^^ see comments in gil.py about this hint + + def after_extcall(): acquire_NOAUTO(state.gil, True) gc_thread_run() + after_extcall._gctransformer_hint_cannot_collect_ = True + # ^^^ see comments in gil.py about this hint + + def bootstrap(): + # after_extcall() is called before we arrive here. + # We can't just acquire and release the GIL manually here, + # because it is unsafe: bootstrap() is called from a rffi + # callback which checks for and reports exceptions after + # bootstrap() returns. The exception checking code must be + # protected by the GIL too. z = state.z state.z = None + state.bootstrapping.release() z.run() gc_thread_die() - release_NOAUTO(state.gil) + # before_extcall() is called after we leave here def g(i, j): + state.bootstrapping.acquire(True) state.z = Z(i, j) gc_thread_prepare() start_new_thread(bootstrap, ()) - # now wait until the new thread really started and consumed 'z' - willing_to_wait_more = 1000 - while state.z is not None: - assert willing_to_wait_more > 0 - willing_to_wait_more -= 1 - release_NOAUTO(state.gil) - time.sleep(0.005) - acquire_NOAUTO(state.gil, True) - gc_thread_run() def f(): state.gil = allocate_ll_lock() acquire_NOAUTO(state.gil, True) + state.bootstrapping = allocate_lock() state.answers = [] state.finished = 0 - g(7, 1) + # the next line installs before_extcall() and after_extcall() + # to be called automatically around external function calls. + # When not translated it does not work around time.sleep(), + # so we have to call them manually for this test. + invoke_around_extcall(before_extcall, after_extcall) + + g(10, 1) done = False - willing_to_wait_more = 1000 + willing_to_wait_more = 2000 while not done: if not willing_to_wait_more: - raise Exception("didn't get enough answers: got %d," - " expected %d" % (len(state.answers), - expected)) + break willing_to_wait_more -= 1 done = len(state.answers) == expected - release_NOAUTO(state.gil) + + if not we_are_translated(): before_extcall() time.sleep(0.01) - acquire_NOAUTO(state.gil, True) - gc_thread_run() - release_NOAUTO(state.gil) + if not we_are_translated(): after_extcall() + + if not we_are_translated(): before_extcall() time.sleep(0.1) + if not we_are_translated(): after_extcall() + return len(state.answers) - expected = 21 - fn = self.getcompiled(f, []) + expected = 89 + try: + fn = self.getcompiled(f, []) + finally: + rffi.aroundstate._freeze_() answers = fn() assert answers == expected Modified: pypy/dist/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/dist/pypy/module/thread/threadlocals.py (original) +++ pypy/dist/pypy/module/thread/threadlocals.py Sat Jun 28 18:43:18 2008 @@ -15,13 +15,14 @@ def getvalue(self): ident = thread.get_ident() if ident == self._mostrecentkey: - return self._mostrecentvalue + result = self._mostrecentvalue else: value = self._valuedict.get(ident, None) # slow path: update the minicache self._mostrecentkey = ident self._mostrecentvalue = value - return value + result = value + return result def setvalue(self, value): ident = thread.get_ident() Modified: pypy/dist/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_listobject.py Sat Jun 28 18:43:18 2008 @@ -737,3 +737,20 @@ # does not crash l.remove(5) assert l[10:] == [0, 1, 2, 3, 4, 6, 7, 8, 9] + + def test_mutate_while_extend(self): + # this used to segfault pypy-c (with py.test -A) + import sys + if hasattr(sys, 'pypy_translation_info'): + if sys.pypy_translation_info['translation.gc'] == 'boehm': + skip("not reliable on top of Boehm") + class A(object): + def __del__(self): + print 'del' + del lst[:] + for i in range(10): + keepalive = [] + lst = list(str(i)) * 100 + A() + while lst: + keepalive.append(lst[:]) Modified: pypy/dist/pypy/translator/c/src/signals.h ============================================================================== --- pypy/dist/pypy/translator/c/src/signals.h (original) +++ pypy/dist/pypy/translator/c/src/signals.h Sat Jun 28 18:43:18 2008 @@ -4,6 +4,8 @@ #ifndef _PYPY_SIGNALS_H #define _PYPY_SIGNALS_H +#include "Python.h" /* XXX for LONG_MIN */ + #include #ifdef MS_WINDOWS @@ -49,12 +51,35 @@ /* utility to poll for signals that arrived */ int pypysig_poll(void); /* => signum or -1 */ +/* When a signal is received, the high bit of pypysig_occurred is set. + After all signals are processed by pypysig_poll(), the high bit is + cleared again. The variable is exposed and RPython code is free to + use the other bits in any way. */ +#define PENDING_SIGNAL_BIT (LONG_MIN) /* high bit */ +extern long pypysig_occurred; + +/* some C tricks to get/set the variable as efficiently as possible: + use macros when compiling as a stand-alone program, but still + export a function with the correct name for testing */ +#undef pypysig_get_occurred +#undef pypysig_set_occurred +long pypysig_get_occurred(void); +void pypysig_set_occurred(long x); +#ifndef PYPY_NOT_MAIN_FILE +long pypysig_get_occurred(void) { return pypysig_occurred; } +void pypysig_set_occurred(long x) { pypysig_occurred = x; } +#endif +#define pypysig_get_occurred() (pypysig_occurred) +#define pypysig_set_occurred(x) (pypysig_occurred=(x)) + /************************************************************/ /* Implementation */ #ifndef PYPY_NOT_MAIN_FILE -static volatile int pypysig_occurred; + +long pypysig_occurred; +static volatile long *pypysig_occurred_v = (volatile long *)&pypysig_occurred; static volatile int pypysig_flags[NSIG]; void pypysig_ignore(int signum) @@ -89,7 +114,9 @@ { if (0 <= signum && signum < NSIG) pypysig_flags[signum] = 1; - pypysig_occurred = 1; + /* the point of "*pypysig_occurred_v" instead of just "pypysig_occurred" + is the volatile declaration */ + *pypysig_occurred_v |= PENDING_SIGNAL_BIT; } void pypysig_setflag(int signum) @@ -108,15 +135,21 @@ int pypysig_poll(void) { - if (pypysig_occurred) + /* the two commented out lines below are useful for performance in + normal usage of pypysig_poll(); however, pypy/module/signal/ is + not normal usage. It only calls pypysig_poll() if the + PENDING_SIGNAL_BIT is set, and it clears that bit first. */ + +/* if (pypysig_occurred & PENDING_SIGNAL_BIT) */ { int i; - pypysig_occurred = 0; +/* pypysig_occurred &= ~PENDING_SIGNAL_BIT; */ for (i=0; i Author: arigo Date: Sat Jun 28 18:43:27 2008 New Revision: 56155 Removed: pypy/branch/async-del/ Log: Remove merged branch. From pedronis at codespeak.net Sat Jun 28 19:16:12 2008 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 28 Jun 2008 19:16:12 +0200 (CEST) Subject: [pypy-svn] r56158 - pypy/build/pypy-c-testing Message-ID: <20080628171612.AE52E2A01DD@codespeak.net> Author: pedronis Date: Sat Jun 28 19:16:12 2008 New Revision: 56158 Removed: pypy/build/pypy-c-testing/ Log: swapping in a more recent version and bless it as the official one From pedronis at codespeak.net Sat Jun 28 19:16:28 2008 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 28 Jun 2008 19:16:28 +0200 (CEST) Subject: [pypy-svn] r56159 - pypy/build/tarball-testing/pypy-c-testing Message-ID: <20080628171628.4A8602A01DD@codespeak.net> Author: pedronis Date: Sat Jun 28 19:16:27 2008 New Revision: 56159 Added: pypy/build/tarball-testing/pypy-c-testing/ - copied from r56157, user/pedronis/pypy-c-testing/ Log: do it From pedronis at codespeak.net Sat Jun 28 19:17:13 2008 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 28 Jun 2008 19:17:13 +0200 (CEST) Subject: [pypy-svn] r56160 - pypy/build/tarball-testing/pypy-c-testing Message-ID: <20080628171713.2B53E2A019E@codespeak.net> Author: pedronis Date: Sat Jun 28 19:17:12 2008 New Revision: 56160 Removed: pypy/build/tarball-testing/pypy-c-testing/ Log: oops From pedronis at codespeak.net Sat Jun 28 19:17:40 2008 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 28 Jun 2008 19:17:40 +0200 (CEST) Subject: [pypy-svn] r56161 - pypy/build/pypy-c-testing Message-ID: <20080628171740.BAD4B2A01A7@codespeak.net> Author: pedronis Date: Sat Jun 28 19:17:40 2008 New Revision: 56161 Added: pypy/build/pypy-c-testing/ - copied from r56157, user/pedronis/pypy-c-testing/ Log: try again From arigo at codespeak.net Sat Jun 28 19:51:43 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 19:51:43 +0200 (CEST) Subject: [pypy-svn] r56164 - pypy/dist/pypy/module/_weakref/test Message-ID: <20080628175143.E7841169F27@codespeak.net> Author: arigo Date: Sat Jun 28 19:51:41 2008 New Revision: 56164 Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py Log: Ensure these are new-style classes. Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py ============================================================================== --- pypy/dist/pypy/module/_weakref/test/test_weakref.py (original) +++ pypy/dist/pypy/module/_weakref/test/test_weakref.py Sat Jun 28 19:51:41 2008 @@ -7,7 +7,7 @@ def test_simple(self): import _weakref, gc - class A: + class A(object): pass a = A() assert _weakref.getweakrefcount(a) == 0 @@ -21,7 +21,7 @@ def test_callback(self): import _weakref, gc - class A: + class A(object): pass a1 = A() a2 = A() @@ -37,7 +37,7 @@ def test_callback_order(self): import _weakref, gc - class A: + class A(object): pass a1 = A() a2 = A() @@ -53,7 +53,7 @@ def test_dont_callback_if_weakref_dead(self): import _weakref, gc - class A: + class A(object): pass a1 = A() a1.x = 40 @@ -72,7 +72,7 @@ def test_callback_cannot_ressurect(self): import _weakref, gc - class A: + class A(object): pass a = A() alive = A() @@ -87,7 +87,7 @@ def test_weakref_reusing(self): import _weakref, gc - class A: + class A(object): pass a = A() ref1 = _weakref.ref(a) @@ -100,7 +100,7 @@ def test_correct_weakrefcount_after_death(self): import _weakref, gc - class A: + class A(object): pass a = A() ref1 = _weakref.ref(a) @@ -115,7 +115,7 @@ def test_weakref_equality(self): import _weakref, gc - class A: + class A(object): def __eq__(self, other): return True a1 = A() @@ -134,7 +134,7 @@ def test_getweakrefs(self): import _weakref, gc - class A: + class A(object): pass a = A() assert _weakref.getweakrefs(a) == [] @@ -332,7 +332,7 @@ def test_callable_proxy_type(self): import _weakref, gc - class Callable: + class Callable(object): def __call__(self, x): pass o = Callable() From arigo at codespeak.net Sat Jun 28 19:54:07 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 28 Jun 2008 19:54:07 +0200 (CEST) Subject: [pypy-svn] r56165 - pypy/dist/pypy/module/_weakref/test Message-ID: <20080628175407.D98E1169F32@codespeak.net> Author: arigo Date: Sat Jun 28 19:54:07 2008 New Revision: 56165 Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py Log: Fix this test for "pypy-c py.test -A". Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py ============================================================================== --- pypy/dist/pypy/module/_weakref/test/test_weakref.py (original) +++ pypy/dist/pypy/module/_weakref/test/test_weakref.py Sat Jun 28 19:54:07 2008 @@ -363,7 +363,9 @@ def test_repr(self): import _weakref, gc for kind in ('ref', 'proxy'): - def foobaz(): pass + def foobaz(): + "A random function not returning None." + return 42 w = getattr(_weakref, kind)(foobaz) s = repr(w) print s @@ -377,10 +379,10 @@ try: for i in range(10): if w() is None: - break + break # only reachable if kind == 'ref' gc.collect() except ReferenceError: - pass + pass # only reachable if kind == 'proxy' s = repr(w) print s assert "dead" in s From xoraxax at codespeak.net Sat Jun 28 22:09:42 2008 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Sat, 28 Jun 2008 22:09:42 +0200 (CEST) Subject: [pypy-svn] r56166 - pypy/dist/pypy/doc Message-ID: <20080628200942.A40BC2A0194@codespeak.net> Author: xoraxax Date: Sat Jun 28 22:09:41 2008 New Revision: 56166 Modified: pypy/dist/pypy/doc/getting-started.txt Log: Added C compiler hint. Modified: pypy/dist/pypy/doc/getting-started.txt ============================================================================== --- pypy/dist/pypy/doc/getting-started.txt (original) +++ pypy/dist/pypy/doc/getting-started.txt Sat Jun 28 22:09:41 2008 @@ -54,6 +54,7 @@ python pypy-dist/pypy/bin/py.py have fun :-) +Note that you will need a C compiler that is supported by CPython's distutils. This gives you a PyPy prompt, i.e. a very compliant Python interpreter implemented in Python. PyPy passes around `98% of CPythons core language regression tests`_. Because this invocation of @@ -140,7 +141,8 @@ The py.py interpreter +++++++++++++++++++++ -To start interpreting Python with PyPy, use Python 2.4 or greater:: +To start interpreting Python with PyPy, install a C compiler that is +supported by distutils and use Python 2.4 or greater to run PyPy:: cd pypy python bin/py.py From arigo at codespeak.net Sun Jun 29 00:02:22 2008 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 29 Jun 2008 00:02:22 +0200 (CEST) Subject: [pypy-svn] r56168 - in pypy/dist/pypy/interpreter: . test Message-ID: <20080628220222.597922A01A1@codespeak.net> Author: arigo Date: Sun Jun 29 00:02:20 2008 New Revision: 56168 Modified: pypy/dist/pypy/interpreter/module.py pypy/dist/pypy/interpreter/test/test_module.py Log: Test and fix. Modified: pypy/dist/pypy/interpreter/module.py ============================================================================== --- pypy/dist/pypy/interpreter/module.py (original) +++ pypy/dist/pypy/interpreter/module.py Sun Jun 29 00:02:20 2008 @@ -69,7 +69,10 @@ def descr_module__repr__(self, space): from pypy.interpreter.mixedmodule import MixedModule - name = space.str_w(space.repr(self.w_name)) + if self.w_name is not None: + name = space.str_w(space.repr(self.w_name)) + else: + name = "'?'" if isinstance(self, MixedModule): return space.wrap("" % name) try: Modified: pypy/dist/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_module.py (original) +++ pypy/dist/pypy/interpreter/test/test_module.py Sun Jun 29 00:02:20 2008 @@ -65,3 +65,6 @@ r.endswith('>') nofile = type(_exceptions)('nofile', 'foo') assert repr(nofile) == "" + + m = type(_exceptions).__new__(type(_exceptions)) + assert repr(m).startswith(" Author: xoraxax Date: Sun Jun 29 23:53:47 2008 New Revision: 56176 Modified: pypy/dist/pypy/rlib/libffi.py Log: A few small changes in libffi.py: * Introduce a DEBUG flag to write dlerror() msgs to stderr. * Add a mode parameter to dlopen(). * Remove CDLL.ll_libname. * Add a new parameter to CDLL.__init__ to disable the dlclose() call in __del__. Modified: pypy/dist/pypy/rlib/libffi.py ============================================================================== --- pypy/dist/pypy/rlib/libffi.py (original) +++ pypy/dist/pypy/rlib/libffi.py Sun Jun 29 23:53:47 2008 @@ -12,6 +12,9 @@ import py import os + +DEBUG = False # writes dlerror() messages to stderr + _MS_WINDOWS = os.name == "nt" if _MS_WINDOWS: @@ -186,16 +189,23 @@ return "" return rffi.charp2str(res) - def dlopen(name): + def dlopen(name, mode=-1): """ Wrapper around C-level dlopen """ - if RTLD_LOCAL is not None: - mode = RTLD_LOCAL | RTLD_NOW - else: - mode = RTLD_NOW + if mode == -1: + if RTLD_LOCAL is not None: + mode = RTLD_LOCAL | RTLD_NOW + else: + mode = RTLD_NOW res = c_dlopen(name, rffi.cast(rffi.INT, mode)) if not res: - raise OSError(-1, dlerror()) + err = dlerror() + # because the message would be lost in a translated program (OSError only has an errno), + # we offer a way to write it to stderr + if DEBUG: + import os + os.write(2, err) + raise OSError(-1, err) return res dlclose = c_dlclose @@ -514,20 +524,18 @@ class CDLL: flags = FUNCFLAG_CDECL - - def __init__(self, libname): - self.ll_libname = lltype.nullptr(rffi.CCHARP.TO) + + def __init__(self, libname, unload_on_finalization=True): + self.unload_on_finalization = unload_on_finalization self.lib = lltype.nullptr(rffi.CCHARP.TO) - self.ll_libname = rffi.str2charp(libname) - self.lib = dlopen(self.ll_libname) + ll_libname = rffi.str2charp(libname) + self.lib = dlopen(ll_libname) + lltype.free(ll_libname, flavor='raw') def __del__(self): - if self.lib: + if self.lib and self.unload_on_finalization: dlclose(self.lib) self.lib = lltype.nullptr(rffi.CCHARP.TO) - if self.ll_libname: - lltype.free(self.ll_libname, flavor='raw') - self.ll_libname = lltype.nullptr(rffi.CCHARP.TO) def getpointer(self, name, argtypes, restype): # these arguments are already casted to proper ffi From afa at codespeak.net Mon Jun 30 19:20:00 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 30 Jun 2008 19:20:00 +0200 (CEST) Subject: [pypy-svn] r56185 - in pypy/dist/pypy: module/rctime module/rctime/test rpython/lltypesystem rpython/module Message-ID: <20080630172000.1F2A41684E6@codespeak.net> Author: afa Date: Mon Jun 30 19:19:59 2008 New Revision: 56185 Modified: pypy/dist/pypy/module/rctime/interp_time.py pypy/dist/pypy/module/rctime/test/test_rctime.py pypy/dist/pypy/rpython/lltypesystem/rffi.py pypy/dist/pypy/rpython/module/ll_os.py pypy/dist/pypy/rpython/module/ll_time.py Log: Export rffi.TIME_T, and use it consistently in all time modules. This is needed by some platforms (win32 with VS8.0) which define long as 32bit, but time_t as 64bit. Modified: pypy/dist/pypy/module/rctime/interp_time.py ============================================================================== --- pypy/dist/pypy/module/rctime/interp_time.py (original) +++ pypy/dist/pypy/module/rctime/interp_time.py Mon Jun 30 19:19:59 2008 @@ -24,8 +24,6 @@ ) CLOCKS_PER_SEC = platform.ConstantInteger("CLOCKS_PER_SEC") clock_t = platform.SimpleType("clock_t", rffi.ULONG) - time_t = platform.SimpleType("time_t", rffi.LONG) - size_t = platform.SimpleType("size_t", rffi.LONG) has_gettimeofday = platform.Has('gettimeofday') if _POSIX: @@ -64,26 +62,23 @@ CLOCKS_PER_SEC = cConfig.CLOCKS_PER_SEC clock_t = cConfig.clock_t -time_t = cConfig.time_t -size_t = cConfig.size_t tm = cConfig.tm glob_buf = lltype.malloc(tm, flavor='raw', zero=True) if cConfig.has_gettimeofday: c_gettimeofday = external('gettimeofday', [rffi.VOIDP, rffi.VOIDP], rffi.INT) -TIME_TP = rffi.CArrayPtr(time_t) TM_P = lltype.Ptr(tm) -c_clock = external('clock', [TIME_TP], clock_t) -c_time = external('time', [TIME_TP], time_t) -c_ctime = external('ctime', [TIME_TP], rffi.CCHARP) -c_gmtime = external('gmtime', [TIME_TP], TM_P) -c_mktime = external('mktime', [TM_P], time_t) +c_clock = external('clock', [rffi.TIME_TP], clock_t) +c_time = external('time', [rffi.TIME_TP], rffi.TIME_T) +c_ctime = external('ctime', [rffi.TIME_TP], rffi.CCHARP) +c_gmtime = external('gmtime', [rffi.TIME_TP], TM_P) +c_mktime = external('mktime', [TM_P], rffi.TIME_T) c_asctime = external('asctime', [TM_P], rffi.CCHARP) -c_localtime = external('localtime', [TIME_TP], TM_P) +c_localtime = external('localtime', [rffi.TIME_TP], TM_P) if _POSIX: c_tzset = external('tzset', [], lltype.Void) -c_strftime = external('strftime', [rffi.CCHARP, size_t, rffi.CCHARP, TM_P], - size_t) +c_strftime = external('strftime', [rffi.CCHARP, rffi.SIZE_T, rffi.CCHARP, TM_P], + rffi.SIZE_T) def _init_accept2dyear(): return (1, 0)[bool(os.getenv("PYTHONY2K"))] @@ -109,9 +104,9 @@ if _POSIX: YEAR = (365 * 24 + 6) * 3600 - t = (((c_time(lltype.nullptr(TIME_TP.TO))) / YEAR) * YEAR) + t = (((c_time(lltype.nullptr(rffi.TIME_TP.TO))) / YEAR) * YEAR) # we cannot have reference to stack variable, put it on the heap - t_ref = lltype.malloc(TIME_TP.TO, 1, flavor='raw') + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = t p = c_localtime(t_ref) janzone = -p.c_tm_gmtoff @@ -164,10 +159,11 @@ else: seconds = space.float_w(w_seconds) try: - return ovfcheck_float_to_int(seconds) + ovfcheck_float_to_int(seconds) except OverflowError: raise OperationError(space.w_ValueError, space.wrap("time argument too large")) + return rffi.r_time_t(seconds) def _tm_to_tuple(space, t): time_tuple = [] @@ -189,8 +185,8 @@ def _gettmarg(space, w_tup, allowNone=True): if allowNone and space.is_w(w_tup, space.w_None): # default to the current local time - tt = int(pytime.time()) - t_ref = lltype.malloc(TIME_TP.TO, 1, flavor='raw') + tt = rffi.r_time_t(pytime.time()) + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = tt pbuf = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') @@ -283,7 +279,7 @@ seconds = _get_inttime(space, w_seconds) - t_ref = lltype.malloc(TIME_TP.TO, 1, flavor='raw') + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_ctime(t_ref) lltype.free(t_ref, flavor='raw') @@ -322,7 +318,7 @@ # rpython does not support that a variable has two incompatible builtins # as value so we have to duplicate the code. NOT GOOD! see localtime() too seconds = _get_inttime(space, w_seconds) - t_ref = lltype.malloc(TIME_TP.TO, 1, flavor='raw') + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_gmtime(t_ref) lltype.free(t_ref, flavor='raw') @@ -340,7 +336,7 @@ When 'seconds' is not passed in, convert the current time instead.""" seconds = _get_inttime(space, w_seconds) - t_ref = lltype.malloc(TIME_TP.TO, 1, flavor='raw') + t_ref = lltype.malloc(rffi.TIME_TP.TO, 1, flavor='raw') t_ref[0] = seconds p = c_localtime(t_ref) lltype.free(t_ref, flavor='raw') Modified: pypy/dist/pypy/module/rctime/test/test_rctime.py ============================================================================== --- pypy/dist/pypy/module/rctime/test/test_rctime.py (original) +++ pypy/dist/pypy/module/rctime/test/test_rctime.py Mon Jun 30 19:19:59 2008 @@ -76,6 +76,7 @@ def test_mktime(self): import time as rctime + import os, sys raises(TypeError, rctime.mktime, "foo") raises(TypeError, rctime.mktime, None) raises(TypeError, rctime.mktime, (1, 2)) @@ -93,7 +94,8 @@ ltime = list(ltime) ltime[0] = 67 ltime = tuple(ltime) - raises(OverflowError, rctime.mktime, ltime) + if os.name != "nt" and sys.maxint < 1<<32: # time_t may be 64bit + raises(OverflowError, rctime.mktime, ltime) ltime = list(ltime) ltime[0] = 100 Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rffi.py Mon Jun 30 19:19:59 2008 @@ -286,7 +286,8 @@ for name in (_name, 'unsigned ' + _name): TYPES.append(name) TYPES += ['signed char', 'unsigned char', - 'long long', 'unsigned long long', 'size_t'] + 'long long', 'unsigned long long', + 'size_t', 'time_t'] if os.name != 'nt': TYPES.append('mode_t') TYPES.append('pid_t') @@ -331,6 +332,7 @@ # LONGLONG r_longlong # ULONGLONG r_ulonglong # SIZE_T r_size_t +# TIME_T r_time_t # -------------------------------------------------------------------- # Note that rffi.r_int is not necessarily the same as # rarithmetic.r_int, etc! rffi.INT/r_int correspond to the C-level Modified: pypy/dist/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/dist/pypy/rpython/module/ll_os.py (original) +++ pypy/dist/pypy/rpython/module/ll_os.py Mon Jun 30 19:19:59 2008 @@ -261,8 +261,8 @@ # we only have utime(), which does not allow sub-second resolution def os_utime_platform(path, actime, modtime): l_utimbuf = lltype.malloc(UTIMBUFP.TO, flavor='raw') - l_utimbuf.c_actime = int(actime) - l_utimbuf.c_modtime = int(modtime) + l_utimbuf.c_actime = rffi.r_time_t(actime) + l_utimbuf.c_modtime = rffi.r_time_t(modtime) error = os_utime(path, l_utimbuf) lltype.free(l_utimbuf, flavor='raw') return error Modified: pypy/dist/pypy/rpython/module/ll_time.py ============================================================================== --- pypy/dist/pypy/rpython/module/ll_time.py (original) +++ pypy/dist/pypy/rpython/module/ll_time.py Mon Jun 30 19:19:59 2008 @@ -25,7 +25,6 @@ CLOCK_T = platform.SimpleType('clock_t', rffi.INT) TIMEVAL = platform.Struct('struct timeval', [('tv_sec', rffi.INT), ('tv_usec', rffi.INT)]) - TIME_T = platform.SimpleType('time_t', rffi.INT) HAVE_GETTIMEOFDAY = platform.Has('gettimeofday') HAVE_FTIME = platform.Has('ftime') @@ -78,7 +77,7 @@ else: c_ftime = None # to not confuse the flow space - c_time = self.llexternal('time', [rffi.VOIDP], self.TIME_T, + c_time = self.llexternal('time', [rffi.VOIDP], rffi.TIME_T, _nowrapper=True, threadsafe=False) def time_time_llimpl(): From afa at codespeak.net Mon Jun 30 19:33:59 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 30 Jun 2008 19:33:59 +0200 (CEST) Subject: [pypy-svn] r56186 - pypy/dist/pypy/rlib Message-ID: <20080630173359.CDE8669802F@codespeak.net> Author: afa Date: Mon Jun 30 19:33:57 2008 New Revision: 56186 Modified: pypy/dist/pypy/rlib/_rsocket_rffi.py pypy/dist/pypy/rlib/rsocket.py Log: win32 now uses the same select() implementation as posix platforms. This should correct the translation of the socket module on windows. Modified: pypy/dist/pypy/rlib/_rsocket_rffi.py ============================================================================== --- pypy/dist/pypy/rlib/_rsocket_rffi.py (original) +++ pypy/dist/pypy/rlib/_rsocket_rffi.py Mon Jun 30 19:33:57 2008 @@ -53,8 +53,7 @@ COND_HEADER = '' constants = {} -if _POSIX: - sources = [""" +sources = [""" void pypy_macro_wrapper_FD_SET(int fd, fd_set *set) { FD_SET(fd, set); @@ -73,13 +72,16 @@ } """] -else: - sources = [] eci = ExternalCompilationInfo( post_include_bits = [HEADER, COND_HEADER], includes = includes, libraries = libraries, separate_module_sources = sources, + export_symbols = ['pypy_macro_wrapper_FD_ZERO', + 'pypy_macro_wrapper_FD_SET', + 'pypy_macro_wrapper_FD_CLR', + 'pypy_macro_wrapper_FD_ISSET', + ], ) class CConfig: @@ -304,13 +306,7 @@ [('tv_sec', rffi.LONG), ('tv_usec', rffi.LONG)]) -if _MS_WINDOWS: - CConfig.fd_set = platform.Struct('struct fd_set', - [('fd_count', rffi.UINT), - # XXX use FD_SETSIZE - ('fd_array', rffi.CFixedArray(socketfd_type, 64))]) -else: - fd_set = rffi.COpaquePtr('fd_set', compilation_info=eci) +fd_set = rffi.COpaquePtr('fd_set', compilation_info=eci) if _MS_WINDOWS: CConfig.WSAData = platform.Struct('struct WSAData', @@ -400,8 +396,6 @@ WSAEVENT = cConfig.WSAEVENT WSANETWORKEVENTS = cConfig.WSANETWORKEVENTS timeval = cConfig.timeval -if _MS_WINDOWS: - fd_set = cConfig.fd_set #if _POSIX: # includes = list(includes) @@ -415,6 +409,10 @@ return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv=calling_conv) +def external_c(name, args, result): + return rffi.llexternal(name, args, result, compilation_info=eci, + calling_conv='c') + if _POSIX: dup = external('dup', [socketfd_type], socketfd_type) gai_strerror = external('gai_strerror', [rffi.INT], CCHARP) @@ -503,25 +501,22 @@ [socketfd_type, rffi.LONG, rffi.ULONGP], rffi.INT) +select = external('select', + [rffi.INT, fd_set, fd_set, + fd_set, lltype.Ptr(timeval)], + rffi.INT) + +FD_CLR = external_c('pypy_macro_wrapper_FD_CLR', [rffi.INT, fd_set], lltype.Void) +FD_ISSET = external_c('pypy_macro_wrapper_FD_ISSET', [rffi.INT, fd_set], rffi.INT) +FD_SET = external_c('pypy_macro_wrapper_FD_SET', [rffi.INT, fd_set], lltype.Void) +FD_ZERO = external_c('pypy_macro_wrapper_FD_ZERO', [fd_set], lltype.Void) + if _POSIX: pollfdarray = rffi.CArray(pollfd) poll = external('poll', [lltype.Ptr(pollfdarray), nfds_t, rffi.INT], rffi.INT) - select = external('select', - [rffi.INT, fd_set, fd_set, - fd_set, lltype.Ptr(timeval)], - rffi.INT) - - FD_CLR = external('pypy_macro_wrapper_FD_CLR', [rffi.INT, fd_set], lltype.Void) - FD_ISSET = external('pypy_macro_wrapper_FD_ISSET', [rffi.INT, fd_set], rffi.INT) - FD_SET = external('pypy_macro_wrapper_FD_SET', [rffi.INT, fd_set], lltype.Void) - FD_ZERO = external('pypy_macro_wrapper_FD_ZERO', [fd_set], lltype.Void) elif MS_WINDOWS: - select = external('select', - [rffi.INT, lltype.Ptr(fd_set), lltype.Ptr(fd_set), - lltype.Ptr(fd_set), lltype.Ptr(timeval)], - rffi.INT) # # The following is for pypy.rlib.rpoll # Modified: pypy/dist/pypy/rlib/rsocket.py ============================================================================== --- pypy/dist/pypy/rlib/rsocket.py (original) +++ pypy/dist/pypy/rlib/rsocket.py Mon Jun 30 19:33:57 2008 @@ -587,10 +587,10 @@ rffi.setintfield(tv, 'c_tv_sec', int(timeout)) rffi.setintfield(tv, 'c_tv_usec', int((timeout-int(timeout)) * 1000000)) - fds = rffi.make(_c.fd_set) - rffi.setintfield(fds, 'c_fd_count', 1) - fds.c_fd_array[0] = rffi.cast(_c.socketfd_type, self.fd) - null = lltype.nullptr(_c.fd_set) + fds = rffi.malloc(_c.fd_set.TO, flavor='raw') + _c.FD_ZERO(fds) + _c.FD_SET(self.fd, fds) + null = lltype.nullptr(_c.fd_set.TO) if for_writing: n = _c.select(self.fd + 1, null, fds, null, tv) else: From afa at codespeak.net Mon Jun 30 19:36:29 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 30 Jun 2008 19:36:29 +0200 (CEST) Subject: [pypy-svn] r56187 - pypy/dist/pypy/module/signal Message-ID: <20080630173629.42B54498013@codespeak.net> Author: afa Date: Mon Jun 30 19:36:28 2008 New Revision: 56187 Modified: pypy/dist/pypy/module/signal/interp_signal.py Log: Adapt the new signal module to win32 platform Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Mon Jun 30 19:36:28 2008 @@ -23,7 +23,9 @@ includes = ['stdlib.h', 'src/signals.h'], separate_module_sources = ['#include '], include_dirs = [str(py.path.local(autopath.pypydir).join('translator', 'c'))], - export_symbols = ['pypysig_poll'], + export_symbols = ['pypysig_poll', 'pypysig_default', + 'pypysig_ignore', 'pypysig_setflag', + 'pypysig_get_occurred', 'pypysig_set_occurred'], ) def external(name, args, result, **kwds): From santagada at codespeak.net Mon Jun 30 21:43:53 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Mon, 30 Jun 2008 21:43:53 +0200 (CEST) Subject: [pypy-svn] r56190 - pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench Message-ID: <20080630194353.40759698057@codespeak.net> Author: santagada Date: Mon Jun 30 21:43:51 2008 New Revision: 56190 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ackermann.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ary.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/binarytrees.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fannkuch.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fasta.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fibo.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/harmonic.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash2.javascript pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/heapsort.javascript Log: made the benchmark run on jspypy Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ackermann.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ackermann.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ackermann.javascript Mon Jun 30 21:43:51 2008 @@ -11,5 +11,5 @@ : ack(m - 1, ack(m, n - 1)))); } -var n = arguments[0]; +var n = 6; print("ack(3, " + n + "): " + ack(3, n)); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ary.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ary.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/ary.javascript Mon Jun 30 21:43:51 2008 @@ -6,7 +6,7 @@ var i, k; -var n = arguments[0]; +var n = 1; var x = Array(n); var y = Array(n); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/binarytrees.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/binarytrees.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/binarytrees.javascript Mon Jun 30 21:43:51 2008 @@ -6,12 +6,12 @@ this.left = left; this.right = right; this.item = item; -} +}; TreeNode.prototype.itemCheck = function(){ if (this.left==null) return this.item; else return this.item + this.left.itemCheck() - this.right.itemCheck(); -} +}; function bottomUpTree(item,depth){ if (depth>0){ @@ -28,8 +28,12 @@ var minDepth = 4; -var n = arguments[0]; -var maxDepth = Math.max(minDepth + 2, n); +var n = 12; +if(minDepth+2 >= n) + maxDepth = minDepth+2; +else + maxDepth = n; + var stretchDepth = maxDepth + 1; var check = bottomUpTree(0,stretchDepth).itemCheck(); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fannkuch.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fannkuch.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fannkuch.javascript Mon Jun 30 21:43:51 2008 @@ -62,5 +62,5 @@ } } -var n = arguments[0]; +var n = 8; print("Pfannkuchen(" + n + ") = " + fannkuch(n)); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fasta.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fasta.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fasta.javascript Mon Jun 30 21:43:51 2008 @@ -24,14 +24,14 @@ B:0.02, D:0.02, H:0.02, K:0.02, M:0.02, N:0.02, R:0.02, S:0.02, V:0.02, W:0.02, Y:0.02 -} +}; var HomoSap = { a: 0.3029549426680, c: 0.1979883004921, g: 0.1975473066391, t: 0.3015094502008 -} +}; function makeCumulative(table) { var last = null; @@ -76,13 +76,13 @@ } } -var n = arguments[0] +var n = 45000; -print(">ONE Homo sapiens alu") -fastaRepeat(2*n, ALU) +print(">ONE Homo sapiens alu"); +fastaRepeat(2*n, ALU); -print(">TWO IUB ambiguity codes") -fastaRandom(3*n, IUB) +print(">TWO IUB ambiguity codes"); +fastaRandom(3*n, IUB); -print(">THREE Homo sapiens frequency") -fastaRandom(5*n, HomoSap) +print(">THREE Homo sapiens frequency"); +fastaRandom(5*n, HomoSap); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fibo.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fibo.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/fibo.javascript Mon Jun 30 21:43:51 2008 @@ -9,6 +9,6 @@ return fib(n-2) + fib(n-1); } -var n = arguments[0]; +var n = 32; print(fib(n)); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/harmonic.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/harmonic.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/harmonic.javascript Mon Jun 30 21:43:51 2008 @@ -3,7 +3,8 @@ // // contributed by Isaac Gouy -var n = arguments[0], partialSum = 0.0; +var n = 10000000; +var partialSum = 0.0; for (var d = 1; d <= n; d++) partialSum += 1.0/d; -print(partialSum.toFixed(9)); +print(partialSum); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash.javascript Mon Jun 30 21:43:51 2008 @@ -5,7 +5,7 @@ // modified by Isaac Gouy var i, c = 0; -var n = arguments[0]; +var n = 600000; var X = new Object(); for (i=1; i<=n; i++) { Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash2.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash2.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/hash2.javascript Mon Jun 30 21:43:51 2008 @@ -4,7 +4,7 @@ // contributed by David Hedbor // modified by Isaac Gouy -var n = arguments[0]; +var n = 10; var hash1 = Object(); var hash2 = Object(); var arr = Array(10000); Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/heapsort.javascript ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/heapsort.javascript (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/bench/heapsort.javascript Mon Jun 30 21:43:51 2008 @@ -10,7 +10,7 @@ var last = 42; -function gen_random(max) { return(max * (last = (last * IA + IC) % IM) / IM); } +function gen_random(max) { return(max * (last = (last * IA + IC) % IM) / IM); }; function heapsort(n, ra) { var l, j, ir, i; @@ -42,16 +42,16 @@ } ra[i] = rra; } -} +}; -var n = arguments[0]; +var n = 1000; var ary, i; // create an array of N random floats ary = Array(n+1); for (i=1; i<=n; i++) { ary[i] = gen_random(1.0); -} +}; heapsort(n, ary); print(ary[n].toFixed(10)); From santagada at codespeak.net Mon Jun 30 21:45:21 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Mon, 30 Jun 2008 21:45:21 +0200 (CEST) Subject: [pypy-svn] r56191 - pypy/branch/js-refactoring-quickhacks/pypy/lang/js Message-ID: <20080630194521.AC00B698071@codespeak.net> Author: santagada Date: Mon Jun 30 21:45:21 2008 New Revision: 56191 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py Log: translation fixes Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/interpreter.py Mon Jun 30 21:45:21 2008 @@ -50,7 +50,7 @@ return args[0].ToObject(ctx) else: obj = create_object(ctx, u'Object', Value = w_Null) - Object = ctx.get_global().Get(ctx, 'Object') + Object = ctx.get_global().Get(ctx, u'Object') obj.propdict[u'prototype'] = Property(u'prototype', Object, DE | DD | RO) obj.propdict[u'__proto__'] = Property(u'prototype', Object, DE | DD | RO) return obj Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/jscode.py Mon Jun 30 21:45:21 2008 @@ -119,7 +119,7 @@ def emit_continue(self): if not self.startlooplabel: - raise ThrowError(W_String(u'Continue outside loop')) + raise ThrowException(W_String(u'Continue outside loop')) self.emit('JUMP', self.startlooplabel[-1]) def emit(self, operation, *args): From santagada at codespeak.net Mon Jun 30 21:46:03 2008 From: santagada at codespeak.net (santagada at codespeak.net) Date: Mon, 30 Jun 2008 21:46:03 +0200 (CEST) Subject: [pypy-svn] r56192 - pypy/branch/js-refactoring-quickhacks/pypy/lang/js Message-ID: <20080630194603.9FB18698057@codespeak.net> Author: santagada Date: Mon Jun 30 21:46:03 2008 New Revision: 56192 Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py Log: better traceback information Modified: pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py ============================================================================== --- pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py (original) +++ pypy/branch/js-refactoring-quickhacks/pypy/lang/js/js_interactive.py Mon Jun 30 21:46:03 2008 @@ -115,6 +115,7 @@ ' '*exc.source_pos.columnno + \ '^' print 'Syntax Error' + print exc.nice_error_message() def interact(self, banner=None): if banner is None: From afa at codespeak.net Mon Jun 30 23:45:52 2008 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 30 Jun 2008 23:45:52 +0200 (CEST) Subject: [pypy-svn] r56193 - pypy/dist/pypy/rlib Message-ID: <20080630214552.4B41F498073@codespeak.net> Author: afa Date: Mon Jun 30 23:45:51 2008 New Revision: 56193 Modified: pypy/dist/pypy/rlib/rsocket.py Log: Correct a typo Modified: pypy/dist/pypy/rlib/rsocket.py ============================================================================== --- pypy/dist/pypy/rlib/rsocket.py (original) +++ pypy/dist/pypy/rlib/rsocket.py Mon Jun 30 23:45:51 2008 @@ -587,7 +587,7 @@ rffi.setintfield(tv, 'c_tv_sec', int(timeout)) rffi.setintfield(tv, 'c_tv_usec', int((timeout-int(timeout)) * 1000000)) - fds = rffi.malloc(_c.fd_set.TO, flavor='raw') + fds = lltype.malloc(_c.fd_set.TO, flavor='raw') _c.FD_ZERO(fds) _c.FD_SET(self.fd, fds) null = lltype.nullptr(_c.fd_set.TO) From fijal at codespeak.net Mon Jun 30 23:56:48 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 30 Jun 2008 23:56:48 +0200 (CEST) Subject: [pypy-svn] r56194 - in pypy/dist: lib-python/modified-2.4.1 pypy/lib pypy/lib/app_test Message-ID: <20080630215648.DE1BC498184@codespeak.net> Author: fijal Date: Mon Jun 30 23:56:46 2008 New Revision: 56194 Added: pypy/dist/lib-python/modified-2.4.1/functools.py Removed: pypy/dist/pypy/lib/functools.py Modified: pypy/dist/pypy/lib/app_test/test_functools.py Log: Do a proper thing. Put functools.py from python svn to lib-python/modified, so it'll reuse existing _functools.py. thx xoraxax for pointing out. Pass more tests. Added: pypy/dist/lib-python/modified-2.4.1/functools.py ============================================================================== --- (empty file) +++ pypy/dist/lib-python/modified-2.4.1/functools.py Mon Jun 30 23:56:46 2008 @@ -0,0 +1,52 @@ +"""functools.py - Tools for working with functions and callable objects +""" +# Python module wrapper for _functools C module +# to allow utilities written in Python to be added +# to the functools module. +# Written by Nick Coghlan +# Copyright (C) 2006 Python Software Foundation. +# See C source code for _functools credits/copyright + +from _functools import partial +from __builtin__ import reduce + +# update_wrapper() and wraps() are tools to help write +# wrapper functions that can handle naive introspection + +WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') +WRAPPER_UPDATES = ('__dict__',) +def update_wrapper(wrapper, + wrapped, + assigned = WRAPPER_ASSIGNMENTS, + updated = WRAPPER_UPDATES): + """Update a wrapper function to look like the wrapped function + + wrapper is the function to be updated + wrapped is the original function + assigned is a tuple naming the attributes assigned directly + from the wrapped function to the wrapper function (defaults to + functools.WRAPPER_ASSIGNMENTS) + updated is a tuple naming the attributes of the wrapper that + are updated with the corresponding attribute from the wrapped + function (defaults to functools.WRAPPER_UPDATES) + """ + for attr in assigned: + setattr(wrapper, attr, getattr(wrapped, attr)) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + # Return the wrapper so this can be used as a decorator via partial() + return wrapper + +def wraps(wrapped, + assigned = WRAPPER_ASSIGNMENTS, + updated = WRAPPER_UPDATES): + """Decorator factory to apply update_wrapper() to a wrapper function + + Returns a decorator that invokes update_wrapper() with the decorated + function as the wrapper argument and the arguments to wraps() as the + remaining arguments. Default arguments are as for update_wrapper(). + This is a convenience function to simplify applying partial() to + update_wrapper(). + """ + return partial(update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) Modified: pypy/dist/pypy/lib/app_test/test_functools.py ============================================================================== --- pypy/dist/pypy/lib/app_test/test_functools.py (original) +++ pypy/dist/pypy/lib/app_test/test_functools.py Mon Jun 30 23:56:46 2008 @@ -119,7 +119,6 @@ py.test.raises(ZeroDivisionError, self.thetype(f, y=0), 1) def test_attributes(self): - py.test.skip("Unsupported") p = self.thetype(hex) try: del p.__dict__ @@ -129,7 +128,6 @@ raise AssertionError, 'partial object allowed __dict__ to be deleted' def test_weakref(self): - py.test.skip("unsupported") f = self.thetype(int, base=16) p = proxy(f) assert f.func == p.func @@ -143,12 +141,12 @@ join = self.thetype(''.join) assert join(data) == '0123456789' -#class PartialSubclass(functools.partial): -# pass +class PartialSubclass(functools.partial): + pass -#class TestPartialSubclass(TestPartial): +class TestPartialSubclass(TestPartial): -# thetype = PartialSubclass + thetype = PartialSubclass class TestPythonPartial(TestPartial): @@ -214,7 +212,6 @@ assert wrapper.dict_attr == f.dict_attr def test_builtin_update(self): - py.test.skip("Unsupported") # Test for bug #1576241 def wrapper(): pass