Author: Hakan Ardo <ha...@debian.org> Branch: jit-short_from_state Changeset: r44467:2bd1326af39e Date: 2011-05-25 14:23 +0200 http://bitbucket.org/pypy/pypy/changeset/2bd1326af39e/
Log: hg merge default diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/test/calling_convention_test.py @@ -0,0 +1,190 @@ +from pypy.jit.metainterp.history import (AbstractFailDescr, + AbstractDescr, + BasicFailDescr, + BoxInt, Box, BoxPtr, + LoopToken, + ConstInt, ConstPtr, + BoxObj, Const, + ConstObj, BoxFloat, ConstFloat) +from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.typesystem import deref +from pypy.jit.tool.oparser import parse +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi, rclass +from pypy.rpython.ootypesystem import ootype +from pypy.rpython.annlowlevel import llhelper +from pypy.rpython.llinterp import LLException +from pypy.jit.codewriter import heaptracker, longlong +from pypy.rlib.rarithmetic import intmask +from pypy.jit.backend.detect_cpu import getcpuclass +from pypy.jit.backend.test.runner_test import Runner + +def boxfloat(x): + return BoxFloat(longlong.getfloatstorage(x)) + +def constfloat(x): + return ConstFloat(longlong.getfloatstorage(x)) +class FakeStats(object): + pass +class TestCallingConv(Runner): + type_system = 'lltype' + Ptr = lltype.Ptr + FuncType = lltype.FuncType + + def __init__(self): + self.cpu = getcpuclass()(rtyper=None, stats=FakeStats()) + self.cpu.setup_once() + + @classmethod + def get_funcbox(cls, cpu, func_ptr): + addr = llmemory.cast_ptr_to_adr(func_ptr) + return ConstInt(heaptracker.adr2int(addr)) + + def test_call_aligned_with_args_on_the_stack(self): + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') + + + def func(*args): + return float(sum(args)) + + F = lltype.Float + I = lltype.Signed + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 13, -42, 1111, 95, 1] + for case in range(256): + result = 0.0 + args = [] + argslist = [] + local_floats = list(floats) + local_ints = list(ints) + for i in range(8): + if case & (1<<i): + args.append(F) + arg = local_floats.pop() + result += arg + argslist.append(boxfloat(arg)) + else: + args.append(I) + arg = local_ints.pop() + result += arg + argslist.append(BoxInt(arg)) + FUNC = self.FuncType(args, F) + FPTR = self.Ptr(FUNC) + func_ptr = llhelper(FPTR, func) + calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(cpu, func_ptr) + + res = self.execute_operation(rop.CALL, + [funcbox] + argslist, + 'float', descr=calldescr) + assert abs(res.getfloat() - result) < 0.0001 + + def test_call_alignment_call_assembler(self): + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') + + fdescr3 = BasicFailDescr(3) + fdescr4 = BasicFailDescr(4) + + def assembler_helper(failindex, virtualizable): + assert 0, 'should not be called, but was with failindex (%d)' % failindex + return 13 + + FUNCPTR = lltype.Ptr(lltype.FuncType([lltype.Signed, llmemory.GCREF], + lltype.Signed)) + class FakeJitDriverSD: + index_of_virtualizable = -1 + _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper) + assembler_helper_adr = llmemory.cast_ptr_to_adr( + _assembler_helper_ptr) + + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 42, -42, 1111, 95, 1] + def _prepare_args(args): + local_floats = list(floats) + local_ints = list(ints) + expected_result = 0.0 + for i in range(len(args)): + x = args[i] + if x[0] == 'f': + x = local_floats.pop() + t = longlong.getfloatstorage(x) + cpu.set_future_value_float(i, t) + else: + x = local_ints.pop() + cpu.set_future_value_int(i, x) + expected_result += x + return expected_result + + for case in range(256): + float_count = 0 + int_count = 0 + args = [] + called_ops = '' + total_index = -1 + for i in range(8): + if case & (1<<i): + args.append('f%d' % float_count) + else: + args.append('i%d' % int_count) + called_ops += 'f%d = cast_int_to_float(i%d)\n' % ( + float_count, int_count) + int_count += 1 + if total_index == -1: + total_index = float_count + float_count += 1 + else: + called_ops += 'f%d = float_add(f%d, f%d)\n' % ( + float_count + 1, total_index, float_count) + total_index = float_count + 1 + float_count += 2 + arguments = ', '.join(args) + called_ops = '[%s]\n' % arguments + called_ops + called_ops += 'finish(f%d, descr=fdescr3)\n' % total_index + # compile called loop + called_loop = parse(called_ops, namespace=locals()) + called_looptoken = LoopToken() + called_looptoken.outermost_jitdriver_sd = FakeJitDriverSD() + done_number = self.cpu.get_fail_descr_number(called_loop.operations[-1].getdescr()) + self.cpu.compile_loop(called_loop.inputargs, called_loop.operations, called_looptoken) + + expected_result = _prepare_args(args) + res = cpu.execute_token(called_looptoken) + assert res.identifier == 3 + t = longlong.getrealfloat(cpu.get_latest_value_float(0)) + assert abs(t - expected_result) < 0.0001 + + ARGS = [] + RES = lltype.Float + for x in args: + if x[0] == 'f': + ARGS.append(lltype.Float) + else: + ARGS.append(lltype.Signed) + FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof( + lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES) + ops = ''' + [%s] + f99 = call_assembler(%s, descr=called_looptoken) + guard_not_forced()[] + finish(f99, descr=fdescr4) + ''' % (arguments, arguments) + loop = parse(ops, namespace=locals()) + # we want to take the fast path + self.cpu.done_with_this_frame_float_v = done_number + try: + othertoken = LoopToken() + self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken) + + # prepare call to called_loop + _prepare_args(args) + res = cpu.execute_token(othertoken) + x = longlong.getrealfloat(cpu.get_latest_value_float(0)) + assert res.identifier == 4 + assert abs(x - expected_result) < 0.0001 + finally: + del self.cpu.done_with_this_frame_float_v diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -137,10 +137,11 @@ self.current_clt = looptoken.compiled_loop_token self.pending_guard_tokens = [] self.mc = codebuf.MachineCodeBlockWrapper() - if self.datablockwrapper is None: - allblocks = self.get_asmmemmgr_blocks(looptoken) - self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, - allblocks) + #assert self.datablockwrapper is None --- but obscure case + # possible, e.g. getting MemoryError and continuing + allblocks = self.get_asmmemmgr_blocks(looptoken) + self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, + allblocks) def teardown(self): self.pending_guard_tokens = None @@ -678,27 +679,29 @@ nonfloatlocs, floatlocs = arglocs self._call_header_with_stack_check() self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth)) - for i in range(len(nonfloatlocs)): - loc = nonfloatlocs[i] - if isinstance(loc, RegLoc): - assert not loc.is_xmm - self.mc.MOV_rb(loc.value, (2 + i) * WORD) - loc = floatlocs[i] - if isinstance(loc, RegLoc): - assert loc.is_xmm - self.mc.MOVSD_xb(loc.value, (1 + i) * 2 * WORD) + offset = 2 * WORD tmp = eax xmmtmp = xmm0 for i in range(len(nonfloatlocs)): loc = nonfloatlocs[i] - if loc is not None and not isinstance(loc, RegLoc): - self.mc.MOV_rb(tmp.value, (2 + i) * WORD) - self.mc.MOV(loc, tmp) + if loc is not None: + if isinstance(loc, RegLoc): + assert not loc.is_xmm + self.mc.MOV_rb(loc.value, offset) + else: + self.mc.MOV_rb(tmp.value, offset) + self.mc.MOV(loc, tmp) + offset += WORD loc = floatlocs[i] - if loc is not None and not isinstance(loc, RegLoc): - self.mc.MOVSD_xb(xmmtmp.value, (1 + i) * 2 * WORD) - assert isinstance(loc, StackLoc) - self.mc.MOVSD_bx(loc.value, xmmtmp.value) + if loc is not None: + if isinstance(loc, RegLoc): + assert loc.is_xmm + self.mc.MOVSD_xb(loc.value, offset) + else: + self.mc.MOVSD_xb(xmmtmp.value, offset) + assert isinstance(loc, StackLoc) + self.mc.MOVSD_bx(loc.value, xmmtmp.value) + offset += 2 * WORD endpos = self.mc.get_relative_pos() + 5 self.mc.JMP_l(jmppos - endpos) assert endpos == self.mc.get_relative_pos() diff --git a/pypy/jit/backend/x86/test/test_calling_convention.py b/pypy/jit/backend/x86/test/test_calling_convention.py new file mode 100644 --- /dev/null +++ b/pypy/jit/backend/x86/test/test_calling_convention.py @@ -0,0 +1,1 @@ +from pypy.jit.backend.test.calling_convention_test import TestCallingConv diff --git a/pypy/module/__builtin__/app_inspect.py b/pypy/module/__builtin__/app_inspect.py --- a/pypy/module/__builtin__/app_inspect.py +++ b/pypy/module/__builtin__/app_inspect.py @@ -5,6 +5,8 @@ import sys +from __pypy__ import lookup_special + def _caller_locals(): # note: the reason why this is working is because the functions in here are # compiled by geninterp, so they don't have a frame @@ -62,7 +64,22 @@ obj = args[0] - if isinstance(obj, types.ModuleType): + dir_meth = None + if isinstance(obj, types.InstanceType): + try: + dir_meth = getattr(obj, "__dir__") + except AttributeError: + pass + else: + dir_meth = lookup_special(obj, "__dir__") + if dir_meth is not None: + result = dir_meth() + if not isinstance(result, list): + raise TypeError("__dir__() must return a list, not %r" % ( + type(result),)) + result.sort() + return result + elif isinstance(obj, types.ModuleType): try: result = list(obj.__dict__) result.sort() @@ -76,14 +93,6 @@ result.sort() return result - elif hasattr(type(obj), '__dir__'): - result = type(obj).__dir__(obj) - if not isinstance(result, list): - raise TypeError("__dir__() must return a list, not %r" % ( - type(result),)) - result.sort() - return result - else: #(regular item) Dict = {} try: diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -120,15 +120,32 @@ def test_dir_custom(self): class Foo(object): def __dir__(self): - return [1, 3, 2] + return ["1", "2", "3"] f = Foo() - assert dir(f) == [1, 2, 3] - # + assert dir(f) == ["1", "2", "3"] + class Foo: + def __dir__(self): + return ["apple"] + assert dir(Foo()) == ["apple"] class Foo(object): def __dir__(self): return 42 f = Foo() raises(TypeError, dir, f) + import types + class Foo(types.ModuleType): + def __dir__(self): + return ["blah"] + assert dir(Foo("a_mod")) == ["blah"] + + def test_dir_custom_lookup(self): + class M(type): + def __dir__(self, *args): return ["14"] + class X(object): + __metaclass__ = M + x = X() + x.__dir__ = lambda x: ["14"] + assert dir(x) != ["14"] def test_format(self): assert format(4) == "4" diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -16,6 +16,7 @@ 'debug_stop' : 'interp_debug.debug_stop', 'debug_print_once' : 'interp_debug.debug_print_once', 'builtinify' : 'interp_magic.builtinify', + 'lookup_special' : 'interp_magic.lookup_special', } def setup_after_space_initialization(self): diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,9 +1,9 @@ +from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import unwrap_spec from pypy.rlib.objectmodel import we_are_translated from pypy.objspace.std.typeobject import MethodCache from pypy.objspace.std.mapdict import IndexCache -from pypy.module._file.interp_file import W_File def internal_repr(space, w_object): @@ -59,3 +59,14 @@ func = space.interp_w(Function, w_func) bltn = BuiltinFunction(func) return space.wrap(bltn) + +@unwrap_spec(ObjSpace, W_Root, str) +def lookup_special(space, w_obj, meth): + """Lookup up a special method on an object.""" + if space.is_oldstyle_instance(w_obj): + w_msg = space.wrap("this doesn't do what you want on old-style classes") + raise OperationError(space.w_TypeError, w_msg) + w_descr = space.lookup(w_obj, meth) + if w_descr is None: + return space.w_None + return space.get(w_descr, w_obj) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -36,3 +36,16 @@ assert not hasattr(A.b, 'im_func') assert A.a is not A.__dict__['a'] assert A.b is A.__dict__['b'] + + def test_lookup_special(self): + from __pypy__ import lookup_special + class X(object): + def foo(self): return 42 + x = X() + x.foo = 23 + x.bar = 80 + assert lookup_special(x, "foo")() == 42 + assert lookup_special(x, "bar") is None + class X: + pass + raises(TypeError, lookup_special, X(), "foo") diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py --- a/pypy/module/_weakref/interp__weakref.py +++ b/pypy/module/_weakref/interp__weakref.py @@ -1,9 +1,10 @@ import py +from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import Wrappable, W_Root -from pypy.interpreter.argument import Arguments from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app, ObjSpace from pypy.interpreter.typedef import GetSetProperty, TypeDef -from pypy.interpreter.gateway import interp2app, ObjSpace +from pypy.rlib import jit import weakref @@ -13,7 +14,7 @@ self.refs_weak = [] self.cached_weakref_index = -1 self.cached_proxy_index = -1 - + def __del__(self): """This runs when the interp-level object goes away, and allows its lifeline to go away. The purpose of this is to activate the @@ -37,6 +38,7 @@ # weakref callbacks are not invoked eagerly here. They are # invoked by self.__del__() anyway. + @jit.dont_look_inside def get_or_make_weakref(self, space, w_subtype, w_obj, w_callable): w_weakreftype = space.gettypeobject(W_Weakref.typedef) is_weakreftype = space.is_w(w_weakreftype, w_subtype) @@ -55,6 +57,7 @@ self.cached_weakref_index = index return w_ref + @jit.dont_look_inside def get_or_make_proxy(self, space, w_obj, w_callable): can_reuse = space.is_w(w_callable, space.w_None) if can_reuse and self.cached_proxy_index >= 0: @@ -81,7 +84,7 @@ w_weakreftype = space.gettypeobject(W_Weakref.typedef) for i in range(len(self.refs_weak)): w_ref = self.refs_weak[i]() - if (w_ref is not None and + if (w_ref is not None and space.is_true(space.isinstance(w_ref, w_weakreftype))): return w_ref return space.w_None @@ -106,6 +109,7 @@ w_self.w_obj_weak = weakref.ref(w_obj) w_self.w_callable = w_callable + @jit.dont_look_inside def dereference(self): w_obj = self.w_obj_weak() return w_obj @@ -244,7 +248,7 @@ lifeline = w_obj.getweakref() if lifeline is None: lifeline = WeakrefLifeline(space) - w_obj.setweakref(space, lifeline) + w_obj.setweakref(space, lifeline) return lifeline.get_or_make_proxy(space, w_obj, w_callable) def descr__new__proxy(space, w_subtype, w_obj, w_callable=None): diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -14,7 +14,7 @@ modname, _ = modname.split('.', 1) if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', 'imp', 'sys', 'array', '_ffi', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof']: + 'posix', '_socket', '_sre', '_lsprof', '_weakref']: return True return False diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py --- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py +++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py @@ -270,9 +270,8 @@ i17 = int_add_ovf(i8, 1) guard_no_overflow(descr=<Guard5>) i18 = force_token() - i20 = int_sub(i17, 1) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=<Loop0>) + jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=<Loop0>) """) def test_default_and_kw(self): diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py --- a/pypy/module/zipimport/test/test_zipimport.py +++ b/pypy/module/zipimport/test/test_zipimport.py @@ -1,7 +1,7 @@ from pypy.conftest import gettestobjspace import marshal -import py +import py, os import time import struct from pypy.module.imp.importing import get_pyc_magic, _w_long @@ -15,6 +15,7 @@ cpy's regression tests """ compression = ZIP_STORED + pathsep = '/' def make_pyc(cls, space, co, mtime): data = marshal.dumps(co) @@ -57,6 +58,7 @@ test_pyc = cls.make_pyc(space, co, now) cls.w_test_pyc = space.wrap(test_pyc) cls.w_compression = space.wrap(cls.compression) + cls.w_pathsep = space.wrap(cls.pathsep) #ziptestmodule = tmpdir.ensure('ziptestmodule.zip').write( ziptestmodule = tmpdir.join("somezip.zip") cls.w_tmpzip = space.wrap(str(ziptestmodule)) @@ -100,6 +102,7 @@ from zipfile import ZipFile, ZipInfo z = ZipFile(self.zipfile, 'w') write_files = self.write_files + filename = filename.replace('/', self.pathsep) write_files.append((filename, data)) for filename, data in write_files: zinfo = ZipInfo(filename, time.localtime(self.now)) @@ -121,6 +124,7 @@ del _zip_directory_cache[self.zipfile] def test_cache_subdir(self): + import os self.writefile('x.py', '') self.writefile('sub/__init__.py', '') self.writefile('sub/yy.py', '') @@ -130,7 +134,7 @@ assert main_importer is not sub_importer assert main_importer.prefix == "" - assert sub_importer.prefix == "sub/" + assert sub_importer.prefix == "sub" + os.path.sep def test_good_bad_arguments(self): from zipimport import zipimporter @@ -262,7 +266,7 @@ import zipimport data = "saddsadsa" self.writefile("xxx", data) - self.writefile("xx"+os.sep+"__init__.py", "5") + self.writefile("xx/__init__.py", "5") self.writefile("yy.py", "3") self.writefile('uu.pyc', self.test_pyc) z = zipimport.zipimporter(self.zipfile) @@ -287,8 +291,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") # Grab this so if the assertion fails, py.test will display its # value. Not sure why it doesn't the assertion uses import.archive @@ -296,15 +299,14 @@ archive = importer.archive realprefix = importer.prefix allbutlast = self.zipfile.split(os.path.sep)[:-1] - prefix = 'directory/' + prefix = 'directory' + os.path.sep assert archive == self.zipfile assert realprefix == prefix def test_subdirectory_importer(self): import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") z = zipimport.zipimporter(self.zipfile + "/directory") mod = z.load_module("package") assert z.is_package("package") @@ -313,14 +315,9 @@ def test_subdirectory_twice(self): import os, zipimport - self.writefile( - os.sep.join(("package", "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "__init__.py")), "") - self.writefile( - os.sep.join(("package", "subpackage", - "foo.py")), "") + self.writefile("package/__init__.py", "") + self.writefile("package/subpackage/__init__.py", "") + self.writefile("package/subpackage/foo.py", "") import sys print sys.path mod = __import__('package.subpackage.foo', None, None, []) @@ -331,8 +328,7 @@ """ import os import zipimport - self.writefile( - os.sep.join(("directory", "package", "__init__.py")), "") + self.writefile("directory/package/__init__.py", "") importer = zipimport.zipimporter(self.zipfile + "/directory") l = [i for i in zipimport._zip_directory_cache] assert len(l) @@ -370,3 +366,8 @@ except ImportError: py.test.skip("zlib not available, cannot test compressed zipfiles") cls.make_class() + + +if os.sep != '/': + class AppTestNativePathSep(AppTestZipimport): + pathsep = os.sep diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -207,34 +207,51 @@ return space.get_and_call_function(w_descr, w_obj, w_name) def is_true(space, w_obj): - w_descr = space.lookup(w_obj, '__nonzero__') + method = "__nonzero__" + w_descr = space.lookup(w_obj, method) if w_descr is None: - w_descr = space.lookup(w_obj, '__len__') + method = "__len__" + w_descr = space.lookup(w_obj, method) if w_descr is None: return True w_res = space.get_and_call_function(w_descr, w_obj) # more shortcuts for common cases - if w_res is space.w_False: + if space.is_w(w_res, space.w_False): return False - if w_res is space.w_True: + if space.is_w(w_res, space.w_True): return True w_restype = space.type(w_res) - if (space.is_w(w_restype, space.w_bool) or - space.is_w(w_restype, space.w_int)): + # Note there is no check for bool here because the only possible + # instances of bool are w_False and w_True, which are checked above. + if (space.is_w(w_restype, space.w_int) or + space.is_w(w_restype, space.w_long)): return space.int_w(w_res) != 0 else: - raise OperationError(space.w_TypeError, - space.wrap('__nonzero__ should return ' - 'bool or int')) + msg = "%s should return bool or integer" % (method,) + raise OperationError(space.w_TypeError, space.wrap(msg)) - def nonzero(self, w_obj): - if self.is_true(w_obj): - return self.w_True + def nonzero(space, w_obj): + if space.is_true(w_obj): + return space.w_True else: - return self.w_False + return space.w_False -## def len(self, w_obj): -## XXX needs to check that the result is an int (or long?) >= 0 + def len(space, w_obj): + w_descr = space.lookup(w_obj, '__len__') + if w_descr is None: + name = space.type(w_obj).getname(space) + msg = "'%s' has no length" % (name,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_res = space.get_and_call_function(w_descr, w_obj) + space._check_len_result(w_res) + return w_res + + def _check_len_result(space, w_obj): + # Will complain if result is too big. + result = space.int_w(w_obj) + if result < 0: + raise OperationError(space.w_ValueError, + space.wrap("__len__() should return >= 0")) def iter(space, w_obj): w_descr = space.lookup(w_obj, '__iter__') diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -266,6 +266,7 @@ return None def unwrap(self, w_obj): + """NOT_RPYTHON""" if isinstance(w_obj, Wrappable): return w_obj if isinstance(w_obj, model.W_Object): diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py --- a/pypy/objspace/test/test_descroperation.py +++ b/pypy/objspace/test/test_descroperation.py @@ -524,6 +524,31 @@ assert issubclass(B, B) assert issubclass(23, B) + def test_truth_of_long(self): + class X(object): + def __len__(self): return 1L + __nonzero__ = __len__ + assert X() + del X.__nonzero__ + assert X() + + def test_len_overflow(self): + import sys + class X(object): + def __len__(self): + return sys.maxsize + 1 + raises(OverflowError, len, X()) + + def test_len_underflow(self): + import sys + class X(object): + def __len__(self): + return -1 + raises(ValueError, len, X()) + class Y(object): + def __len__(self): + return -1L + raises(ValueError, len, Y()) class AppTestWithBuiltinShortcut(AppTest_Descroperation): OPTIONS = {'objspace.std.builtinshortcut': True} diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -2,7 +2,7 @@ import py from pypy.rlib.debug import check_annotation, make_sure_not_resized from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset +from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative from pypy.rlib import debug from pypy.rpython.test.test_llinterp import interpret _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit