Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r46828:f41530743442 Date: 2011-08-27 21:10 +0200 http://bitbucket.org/pypy/pypy/changeset/f41530743442/
Log: merge heads diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -24,6 +24,7 @@ 'last_exception', 'lastblock', 'is_being_profiled', + 'w_globals', ] JUMP_ABSOLUTE = opmap['JUMP_ABSOLUTE'] diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -67,24 +67,14 @@ assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value", "getfield_gc", "guard_value", - "getfield_gc", "guard_nonnull_class"] - # LOAD_GLOBAL of OFFSET but in different function partially folded - # away - # XXX could be improved + "guard_not_invalidated"] ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["guard_value", "getfield_gc", "guard_value"] + assert log.opnames(ops) == ["guard_not_invalidated"] # - # two LOAD_GLOBAL of f, the second is folded away ops = entry_bridge.ops_by_id('call', opcode='LOAD_GLOBAL') - assert log.opnames(ops) == ["getfield_gc", "guard_nonnull_class"] + assert log.opnames(ops) == [] # assert entry_bridge.match_by_id('call', """ - p29 = getfield_gc(ConstPtr(ptr28), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value .*>) - guard_nonnull_class(p29, ConstClass(Function), descr=...) - p33 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code .*>) - guard_value(p33, ConstPtr(ptr34), descr=...) - p35 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals .*>) - p36 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure .*>) p38 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>) p39 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>) i40 = force_token() @@ -100,19 +90,16 @@ # ----------------------------- loop, = log.loops_by_id('call') assert loop.match(""" - i12 = int_lt(i5, i6) - guard_true(i12, descr=...) + guard_not_invalidated(descr=...) + i9 = int_lt(i5, i6) + guard_true(i9, descr=...) + i10 = force_token() + i12 = int_add(i5, 1) i13 = force_token() - i15 = int_add(i5, 1) - i16 = int_add_ovf(i15, i7) - guard_no_overflow(descr=...) - i18 = force_token() - i20 = int_add_ovf(i16, 1) - guard_no_overflow(descr=...) - i21 = int_add_ovf(i20, i7) + i15 = int_add_ovf(i12, 1) guard_no_overflow(descr=...) --TICK-- - jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, p10, p11, descr=<Loop0>) + jump(p0, p1, p2, p3, p4, i15, i6, p7, p8, descr=<Loop0>) """) def test_method_call(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py --- a/pypy/module/pypyjit/test_pypy_c/test_globals.py +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -20,11 +20,9 @@ guard_value(p10, ConstPtr(ptr11), descr=...) p12 = getfield_gc(p10, descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>) guard_value(p12, ConstPtr(ptr13), descr=...) - p15 = getfield_gc(ConstPtr(ptr14), descr=<GcPtrFieldDescr .*ModuleCell.inst_w_value .*>) - guard_isnull(p15, descr=...) guard_not_invalidated(descr=...) p19 = getfield_gc(ConstPtr(p17), descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>) guard_value(p19, ConstPtr(ptr20), descr=...) p22 = getfield_gc(ConstPtr(ptr21), descr=<GcPtrFieldDescr .*ModuleCell.inst_w_value .*>) guard_nonnull(p22, descr=...) - """) \ No newline at end of file + """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -52,7 +52,7 @@ i10 = int_add_ovf(i5, i7) guard_no_overflow(descr=...) --TICK-- - jump(p0, p1, p2, p3, p4, i10, i6, p7, i7, p8, descr=<Loop0>) + jump(p0, p1, p2, p3, p4, i10, i6, i7, p8, descr=<Loop0>) """) def test_getattr_with_dynamic_attribute(self): @@ -151,6 +151,7 @@ assert loop.match_by_id('loadattr', ''' guard_not_invalidated(descr=...) + i16 = arraylen_gc(p10, descr=<GcPtrArrayDescr>) i19 = call(ConstClass(ll_dict_lookup), _, _, _, descr=...) guard_no_exception(descr=...) i21 = int_and(i19, _) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -47,6 +47,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) f1 = cast_int_to_float(i0) i3 = float_eq(f1, inf) i4 = float_eq(f1, -inf) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -234,3 +234,18 @@ return total # self.run_and_check(main, []) + + + def test_global(self): + log = self.run(""" + i = 0 + globalinc = 1 + def main(n): + global i + while i < n: + l = globalinc # ID: globalread + i += l + """, [1000]) + + loop, = log.loops_by_id("globalread", is_entry_bridge=True) + assert len(loop.ops_by_id("globalread")) == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -34,9 +34,9 @@ i25 = unicodegetitem(p13, i19) p27 = newstr(1) strsetitem(p27, 0, i23) - p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=<GcPtrCallDescr>) + p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) guard_no_exception(descr=...) - i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=<SignedCallDescr>) + i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- @@ -105,5 +105,5 @@ i58 = int_add_ovf(i6, i57) guard_no_overflow(descr=...) --TICK-- - jump(p0, p1, p2, p3, p4, p5, i58, i7, i8, p9, p10, descr=<Loop4>) + jump(p0, p1, p2, p3, p4, p5, i58, i7, descr=<Loop4>) """) diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -1,50 +1,57 @@ -""" A very simple cell dict implementation. The dictionary maps keys to cell. -This ensures that the function (dict, key) -> cell is pure. By itself, this -optimization is not helping at all, but in conjunction with the JIT it can -speed up global lookups a lot.""" +""" A very simple cell dict implementation using a version tag. The dictionary +maps keys to objects. If a specific key is changed a lot, a level of +indirection is introduced to make the version tag change less often. +""" +from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import IteratorImplementation from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string from pypy.objspace.std.dictmultiobject import ObjectDictStrategy from pypy.rlib import jit, rerased -class ModuleCell(object): +class VersionTag(object): + pass + +class ModuleCell(W_Root): def __init__(self, w_value=None): self.w_value = w_value - def invalidate(self): - w_value = self.w_value - self.w_value = None - return w_value - def __repr__(self): return "<ModuleCell: %s>" % (self.w_value, ) +def unwrap_cell(w_value): + if isinstance(w_value, ModuleCell): + return w_value.w_value + return w_value + class ModuleDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("modulecell") erase = staticmethod(erase) unerase = staticmethod(unerase) + _immutable_fields_ = ["version?"] + def __init__(self, space): self.space = space + self.version = VersionTag() def get_empty_storage(self): return self.erase({}) - def getcell(self, w_dict, key, makenew): - if makenew or jit.we_are_jitted(): - # when we are jitting, we always go through the pure function - # below, to ensure that we have no residual dict lookup - w_dict = jit.promote(w_dict) - self = jit.promote(self) - return self._getcell_makenew(w_dict, key) + def mutated(self): + self.version = VersionTag() + + def getdictvalue_no_unwrapping(self, w_dict, key): + # NB: it's important to promote self here, so that self.version is a + # no-op due to the quasi-immutable field + self = jit.promote(self) + return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key) + + @jit.elidable_promote('0,1,2') + def _getdictvalue_no_unwrapping_pure(self, version, w_dict, key): return self.unerase(w_dict.dstorage).get(key, None) - @jit.elidable - def _getcell_makenew(self, w_dict, key): - return self.unerase(w_dict.dstorage).setdefault(key, ModuleCell()) - def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): @@ -54,15 +61,24 @@ w_dict.setitem(w_key, w_value) def setitem_str(self, w_dict, key, w_value): - self.getcell(w_dict, key, True).w_value = w_value + cell = self.getdictvalue_no_unwrapping(w_dict, key) + if isinstance(cell, ModuleCell): + cell.w_value = w_value + return + if cell is not None: + w_value = ModuleCell(w_value) + self.mutated() + self.unerase(w_dict.dstorage)[key] = w_value def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): - cell = self.getcell(w_dict, space.str_w(w_key), True) - if cell.w_value is None: - cell.w_value = w_default - return cell.w_value + key = space.str_w(w_key) + w_result = self.getitem_str(w_dict, key) + if w_result is not None: + return w_result + self.setitem_str(w_dict, key, w_default) + return w_default else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -72,14 +88,13 @@ w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) - cell = self.getcell(w_dict, key, False) - if cell is None or cell.w_value is None: - raise KeyError - # note that we don't remove the cell from self.content, to make - # sure that a key that was found at any point in the dict, still - # maps to the same cell later (even if this cell no longer - # represents a key) - cell.invalidate() + dict_w = self.unerase(w_dict.dstorage) + try: + del dict_w[key] + except KeyError: + raise + else: + self.mutated() elif _never_equal_to_string(space, w_key_type): raise KeyError else: @@ -87,12 +102,7 @@ w_dict.delitem(w_key) def length(self, w_dict): - # inefficient, but do we care? - res = 0 - for cell in self.unerase(w_dict.dstorage).itervalues(): - if cell.w_value is not None: - res += 1 - return res + return len(self.unerase(w_dict.dstorage)) def getitem(self, w_dict, w_key): space = self.space @@ -107,11 +117,8 @@ return w_dict.getitem(w_key) def getitem_str(self, w_dict, key): - res = self.getcell(w_dict, key, False) - if res is None: - return None - # note that even if the res.w_value is None, the next line is fine - return res.w_value + w_res = self.getdictvalue_no_unwrapping(w_dict, key) + return unwrap_cell(w_res) def iter(self, w_dict): return ModuleDictIteratorImplementation(self.space, self, w_dict) @@ -119,44 +126,34 @@ def keys(self, w_dict): space = self.space iterator = self.unerase(w_dict.dstorage).iteritems - return [space.wrap(key) for key, cell in iterator() - if cell.w_value is not None] + return [space.wrap(key) for key, cell in iterator()] def values(self, w_dict): iterator = self.unerase(w_dict.dstorage).itervalues - return [cell.w_value for cell in iterator() - if cell.w_value is not None] + return [unwrap_cell(cell) for cell in iterator()] def items(self, w_dict): space = self.space iterator = self.unerase(w_dict.dstorage).iteritems - return [space.newtuple([space.wrap(key), cell.w_value]) - for (key, cell) in iterator() - if cell.w_value is not None] + return [space.newtuple([space.wrap(key), unwrap_cell(cell)]) + for key, cell in iterator()] def clear(self, w_dict): - iterator = self.unerase(w_dict.dstorage).iteritems - for k, cell in iterator(): - cell.invalidate() + iterator = self.unerase(w_dict.dstorage).clear() + self.mutated() def popitem(self, w_dict): - # This is O(n) if called repeatadly, you probably shouldn't be on a - # Module's dict though - for k, cell in self.unerase(w_dict.dstorage).iteritems(): - if cell.w_value is not None: - w_value = cell.w_value - cell.invalidate() - return self.space.wrap(k), w_value - else: - raise KeyError + d = self.unerase(w_dict.dstorage) + key, w_value = d.popitem() + self.mutated() + return self.space.wrap(key), unwrap_cell(w_value) def switch_to_object_strategy(self, w_dict): d = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): - if cell.w_value is not None: - d_new[self.space.wrap(key)] = cell.w_value + d_new[self.space.wrap(key)] = unwrap_cell(cell) w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) @@ -168,7 +165,6 @@ def next_entry(self): for key, cell in self.iterator: - if cell.w_value is not None: - return (self.space.wrap(key), cell.w_value) + return (self.space.wrap(key), unwrap_cell(cell)) else: return None, None diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -38,7 +38,9 @@ if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None - strategy = space.fromcache(ModuleDictStrategy) + # every module needs its own strategy, because the strategy stores + # the version tag + strategy = ModuleDictStrategy(space) elif instance or strdict or module: assert w_type is None diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -2,42 +2,111 @@ from pypy.conftest import gettestobjspace, option from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.celldict import ModuleCell, ModuleDictStrategy -from pypy.objspace.std.test.test_dictmultiobject import FakeSpace +from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, \ + BaseTestRDictImplementation, BaseTestDevolvedDictImplementation from pypy.interpreter import gateway +from pypy.conftest import gettestobjspace, option + space = FakeSpace() class TestCellDict(object): - def test_basic_property(self): + def test_basic_property_cells(self): strategy = ModuleDictStrategy(space) storage = strategy.get_empty_storage() d = W_DictMultiObject(space, strategy, storage) - # replace getcell with getcell from strategy - def f(key, makenew): - return strategy.getcell(d, key, makenew) - d.getcell = f + v1 = strategy.version + d.setitem("a", 1) + v2 = strategy.version + assert v1 is not v2 + assert d.getitem("a") == 1 + assert d.strategy.getdictvalue_no_unwrapping(d, "a") == 1 - d.setitem("a", 1) - assert d.getcell("a", False) is d.getcell("a", False) - acell = d.getcell("a", False) - d.setitem("b", 2) - assert d.getcell("b", False) is d.getcell("b", False) - assert d.getcell("c", True) is d.getcell("c", True) + d.setitem("a", 2) + v3 = strategy.version + assert v2 is not v3 + assert d.getitem("a") == 2 + assert d.strategy.getdictvalue_no_unwrapping(d, "a").w_value == 2 - assert d.getitem("a") == 1 - assert d.getitem("b") == 2 + d.setitem("a", 3) + v4 = strategy.version + assert v3 is v4 + assert d.getitem("a") == 3 + assert d.strategy.getdictvalue_no_unwrapping(d, "a").w_value == 3 d.delitem("a") - py.test.raises(KeyError, d.delitem, "a") + v5 = strategy.version + assert v5 is not v4 assert d.getitem("a") is None - assert d.getcell("a", False) is acell - assert d.length() == 1 + assert d.strategy.getdictvalue_no_unwrapping(d, "a") is None - d.clear() - assert d.getitem("a") is None - assert d.getcell("a", False) is acell - assert d.length() == 0 +class AppTestModuleDict(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) + + def w_impl_used(self, obj): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + import __pypy__ + assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) + + def test_check_module_uses_module_dict(self): + m = type(__builtins__)("abc") + self.impl_used(m.__dict__) + + def test_key_not_there(self): + d = type(__builtins__)("abc").__dict__ + raises(KeyError, "d['def']") + + def test_fallback_evil_key(self): + class F(object): + def __hash__(self): + return hash("s") + def __eq__(self, other): + return other == "s" + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + assert d["s"] == 12 + assert d[F()] == d["s"] + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault("s", 12) + assert x == 12 + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + x = d.setdefault(F(), 12) + assert x == 12 + + d = type(__builtins__)("abc").__dict__ + d["s"] = 12 + del d[F()] + + assert "s" not in d + assert F() not in d + + +class TestModuleDictImplementation(BaseTestRDictImplementation): + StrategyClass = ModuleDictStrategy + +class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): + StrategyClass = ModuleDictStrategy + + string = "int" + string2 = "isinstance" + + +class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): + StrategyClass = ModuleDictStrategy + +class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): + StrategyClass = ModuleDictStrategy + + string = "int" + string2 = "isinstance" + class AppTestCellDict(object): OPTIONS = {"objspace.std.withcelldict": True} @@ -67,4 +136,4 @@ d["a"] = 3 del d["a"] d[object()] = 5 - assert d.values() == [5] \ No newline at end of file + assert d.values() == [5] diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -5,7 +5,6 @@ W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \ StringDictStrategy, ObjectDictStrategy -from pypy.objspace.std.celldict import ModuleDictStrategy from pypy.conftest import gettestobjspace from pypy.conftest import option @@ -731,52 +730,6 @@ set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) -class AppTestModuleDict(object): - def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.withcelldict": True}) - if option.runappdirect: - py.test.skip("__repr__ doesn't work on appdirect") - - def w_impl_used(self, obj): - import __pypy__ - assert "ModuleDictStrategy" in __pypy__.internal_repr(obj) - - def test_check_module_uses_module_dict(self): - m = type(__builtins__)("abc") - self.impl_used(m.__dict__) - - def test_key_not_there(self): - d = type(__builtins__)("abc").__dict__ - raises(KeyError, "d['def']") - - def test_fallback_evil_key(self): - class F(object): - def __hash__(self): - return hash("s") - def __eq__(self, other): - return other == "s" - d = type(__builtins__)("abc").__dict__ - d["s"] = 12 - assert d["s"] == 12 - assert d[F()] == d["s"] - - d = type(__builtins__)("abc").__dict__ - x = d.setdefault("s", 12) - assert x == 12 - x = d.setdefault(F(), 12) - assert x == 12 - - d = type(__builtins__)("abc").__dict__ - x = d.setdefault(F(), 12) - assert x == 12 - - d = type(__builtins__)("abc").__dict__ - d["s"] = 12 - del d[F()] - - assert "s" not in d - assert F() not in d - class AppTestStrategies(object): def setup_class(cls): if option.runappdirect: @@ -1071,16 +1024,6 @@ ## ImplementionClass = MeasuringDictImplementation ## DevolvedClass = MeasuringDictImplementation -class TestModuleDictImplementation(BaseTestRDictImplementation): - StrategyClass = ModuleDictStrategy - -class TestModuleDictImplementationWithBuiltinNames(BaseTestRDictImplementation): - StrategyClass = ModuleDictStrategy - - string = "int" - string2 = "isinstance" - - class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) @@ -1092,15 +1035,6 @@ class TestDevolvedStrDictImplementation(BaseTestDevolvedDictImplementation): StrategyClass = StringDictStrategy -class TestDevolvedModuleDictImplementation(BaseTestDevolvedDictImplementation): - StrategyClass = ModuleDictStrategy - -class TestDevolvedModuleDictImplementationWithBuiltinNames(BaseTestDevolvedDictImplementation): - StrategyClass = ModuleDictStrategy - - string = "int" - string2 = "isinstance" - def test_module_uses_strdict(): fakespace = FakeSpace() diff --git a/pypy/rpython/extfuncregistry.py b/pypy/rpython/extfuncregistry.py --- a/pypy/rpython/extfuncregistry.py +++ b/pypy/rpython/extfuncregistry.py @@ -56,10 +56,16 @@ for module, methods in _register: for name, arg_types, return_type in methods: method_name = 'll_math_%s' % name + oofake = None + # Things with a tuple return type have a fake impl for RPython, check + # to see if the method has one. + if hasattr(oo_math, method_name): + oofake = getattr(oo_math, method_name) register_external(getattr(module, name), arg_types, return_type, export_name='ll_math.%s' % method_name, sandboxsafe=True, - llimpl=getattr(ll_math, method_name)) + llimpl=getattr(ll_math, method_name), + oofakeimpl=oofake) # ___________________________ # os.path functions _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit