Author: Manuel Jacob <m...@manueljacob.de> Branch: py3k Changeset: r78397:2ac10a3a0884 Date: 2015-07-02 01:54 +0200 http://bitbucket.org/pypy/pypy/changeset/2ac10a3a0884/
Log: hg merge default diff --git a/lib-python/2.7/test/test_urllib2.py b/lib-python/2.7/test/test_urllib2.py --- a/lib-python/2.7/test/test_urllib2.py +++ b/lib-python/2.7/test/test_urllib2.py @@ -291,6 +291,7 @@ self.req_headers = [] self.data = None self.raise_on_endheaders = False + self.sock = None self._tunnel_headers = {} def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): diff --git a/lib-python/2.7/urllib2.py b/lib-python/2.7/urllib2.py --- a/lib-python/2.7/urllib2.py +++ b/lib-python/2.7/urllib2.py @@ -1200,6 +1200,12 @@ r = h.getresponse(buffering=True) except TypeError: # buffering kw not supported r = h.getresponse() + # If the server does not send us a 'Connection: close' header, + # HTTPConnection assumes the socket should be left open. Manually + # mark the socket to be closed when this response object goes away. + if h.sock: + h.sock.close() + h.sock = None # Pick apart the HTTPResponse object to get the addinfourl # object initialized properly. diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -135,7 +135,7 @@ Here are some more technical details. This issue affects the precise time at which ``__del__`` methods are called, which is not reliable in PyPy (nor Jython nor IronPython). It also means that -weak references may stay alive for a bit longer than expected. This +**weak references** may stay alive for a bit longer than expected. This makes "weak proxies" (as returned by ``weakref.proxy()``) somewhat less useful: they will appear to stay alive for a bit longer in PyPy, and suddenly they will really be dead, raising a ``ReferenceError`` on the @@ -143,6 +143,24 @@ ``ReferenceError`` at any place that uses them. (Or, better yet, don't use ``weakref.proxy()`` at all; use ``weakref.ref()``.) +Note a detail in the `documentation for weakref callbacks`__: + + If callback is provided and not None, *and the returned weakref + object is still alive,* the callback will be called when the object + is about to be finalized. + +There are cases where, due to CPython's refcount semantics, a weakref +dies immediately before or after the objects it points to (typically +with some circular reference). If it happens to die just after, then +the callback will be invoked. In a similar case in PyPy, both the +object and the weakref will be considered as dead at the same time, +and the callback will not be invoked. (Issue `#2030`__) + +.. __: https://docs.python.org/2/library/weakref.html +.. __: https://bitbucket.org/pypy/pypy/issue/2030/ + +--------------------------------- + There are a few extra implications from 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 @@ -321,9 +339,8 @@ Miscellaneous ------------- -* Hash randomization (``-R``) is ignored in PyPy. As documented in - http://bugs.python.org/issue14621, some of us believe it has no - purpose in CPython either. +* Hash randomization (``-R``) `is ignored in PyPy`_. In CPython + before 3.4 it has `little point`_. * You can't store non-string keys in type objects. For example:: @@ -338,7 +355,8 @@ for about 1400 calls. * since the implementation of dictionary is different, the exact number - which ``__hash__`` and ``__eq__`` are called is different. Since CPython + of times that ``__hash__`` and ``__eq__`` are called is different. + Since CPython does not give any specific guarantees either, don't rely on it. * assignment to ``__class__`` is limited to the cases where it @@ -395,3 +413,12 @@ interactive mode. In a released version, this behaviour is suppressed, but setting the environment variable PYPY_IRC_TOPIC will bring it back. Note that downstream package providers have been known to totally disable this feature. + +* PyPy's readline module was rewritten from scratch: it is not GNU's + readline. It should be mostly compatible, and it adds multiline + support (see ``multiline_input()``). On the other hand, + ``parse_and_bind()`` calls are ignored (issue `#2072`_). + +.. _`is ignored in PyPy`: http://bugs.python.org/issue14621 +.. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html +.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/ diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -225,9 +225,13 @@ if (isinstance(w_cdata, cdataobj.W_CDataNewOwning) or isinstance(w_cdata, cdataobj.W_CDataPtrToStructOrUnion)): if i != 0: - space = self.space - raise oefmt(space.w_IndexError, + raise oefmt(self.space.w_IndexError, "cdata '%s' can only be indexed by 0", self.name) + else: + if not w_cdata.unsafe_escaping_ptr(): + raise oefmt(self.space.w_RuntimeError, + "cannot dereference null pointer from cdata '%s'", + self.name) return self def _check_slice_index(self, w_cdata, start, stop): diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py --- a/pypy/module/_cffi_backend/lib_obj.py +++ b/pypy/module/_cffi_backend/lib_obj.py @@ -175,6 +175,8 @@ return self.dir1(ignore_type=cffi_opcode.OP_GLOBAL_VAR) if is_getattr and attr == '__dict__': return self.full_dict_copy() + if is_getattr and attr == '__name__': + return self.descr_repr() raise oefmt(self.space.w_AttributeError, "cffi library '%s' has no function, constant " "or global variable named '%s'", diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -2099,8 +2099,7 @@ p = cast(BVoidP, 123456) py.test.raises(TypeError, "p[0]") p = cast(BVoidP, 0) - if 'PY_DOT_PY' in globals(): py.test.skip("NULL crashes early on py.py") - py.test.raises(TypeError, "p[0]") + py.test.raises((TypeError, RuntimeError), "p[0]") def test_iter(): BInt = new_primitive_type("int") @@ -3333,6 +3332,15 @@ check(4 | 8, "CHB", "GTB") check(4 | 16, "CHB", "ROB") +def test_dereference_null_ptr(): + BInt = new_primitive_type("int") + BIntPtr = new_pointer_type(BInt) + p = cast(BIntPtr, 0) + py.test.raises(RuntimeError, "p[0]") + py.test.raises(RuntimeError, "p[0] = 42") + py.test.raises(RuntimeError, "p[42]") + py.test.raises(RuntimeError, "p[42] = -1") + def test_version(): # this test is here mostly for PyPy assert __version__ == "1.1.2" diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py --- a/pypy/module/_cffi_backend/test/test_recompiler.py +++ b/pypy/module/_cffi_backend/test/test_recompiler.py @@ -1011,3 +1011,4 @@ assert MYFOO == 42 assert hasattr(lib, '__dict__') assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar' + assert lib.__name__ == repr(lib) diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -457,6 +457,8 @@ {"mode": "w+", "buffering": 2}, {"mode": "w+b", "buffering": 0}, ]: + if "b" not in kwargs["mode"]: + kwargs["encoding"] = "ascii" f = _io.open(self.tmpfile, **kwargs) f.close() raises(ValueError, f.flush) diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -27,8 +27,10 @@ callback_ptr = global_counter.get(userdata.addarg) w_callable = callback_ptr.w_callable argtypes = callback_ptr.argtypes + must_leave = False space = callback_ptr.space try: + must_leave = space.threadlocals.try_enter_thread(space) args_w = [None] * len(argtypes) for i in range(len(argtypes)): argtype = argtypes[i] @@ -50,6 +52,8 @@ resshape = letter2tp(space, callback_ptr.result) for i in range(resshape.size): ll_res[i] = '\x00' + if must_leave: + space.threadlocals.leave_thread(space) class W_CallbackPtr(W_DataInstance): @@ -75,6 +79,14 @@ if tracker.DO_TRACING: addr = rffi.cast(lltype.Signed, self.ll_callback.ll_closure) tracker.trace_allocation(addr, self) + # + # We must setup the GIL here, in case the callback is invoked in + # some other non-Pythonic thread. This is the same as ctypes on + # CPython (but only when creating a callback; on CPython it occurs + # as soon as we import _ctypes) + if space.config.translation.thread: + from pypy.module.thread.os_thread import setup_threads + setup_threads(space) def free(self): if tracker.DO_TRACING: diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -141,7 +141,7 @@ def __init__(self, ctx, protos): self.protos = protos self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos) - NPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self) + NPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self) # set both server and client callbacks, because the context # can be used to create both types of sockets @@ -156,7 +156,7 @@ @staticmethod def advertiseNPN_cb(s, data_ptr, len_ptr, args): - npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args))) + npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args)) if npn and npn.protos: data_ptr[0] = npn.buf len_ptr[0] = rffi.cast(rffi.UINT, len(npn.protos)) @@ -168,7 +168,7 @@ @staticmethod def selectNPN_cb(s, out_ptr, outlen_ptr, server, server_len, args): - npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args))) + npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args)) if npn and npn.protos: client = npn.buf client_len = len(npn.protos) @@ -187,7 +187,7 @@ def __init__(self, ctx, protos): self.protos = protos self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos) - ALPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self) + ALPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self) with rffi.scoped_str2charp(protos) as protos_buf: if libssl_SSL_CTX_set_alpn_protos( @@ -202,7 +202,7 @@ @staticmethod def selectALPN_cb(s, out_ptr, outlen_ptr, client, client_len, args): - alpn = ALPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args))) + alpn = ALPN_STORAGE.get(rffi.cast(lltype.Unsigned, args)) if alpn and alpn.protos: server = alpn.buf server_len = len(alpn.protos) diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py --- a/pypy/module/_vmprof/interp_vmprof.py +++ b/pypy/module/_vmprof/interp_vmprof.py @@ -26,7 +26,7 @@ eci_kwds = dict( include_dirs = [SRC], includes = ['vmprof.h', 'trampoline.h'], - separate_module_files = [SRC.join('trampoline.asmgcc.s')], + separate_module_files = [SRC.join('trampoline.vmprof.s')], libraries = ['dl'], post_include_bits=[""" diff --git a/pypy/module/_vmprof/src/trampoline.asmgcc.s b/pypy/module/_vmprof/src/trampoline.asmgcc.s deleted file mode 100644 --- a/pypy/module/_vmprof/src/trampoline.asmgcc.s +++ /dev/null @@ -1,16 +0,0 @@ -// NOTE: you need to use TABs, not spaces! - - .text - .p2align 4,,-1 - .globl pypy_execute_frame_trampoline - .type pypy_execute_frame_trampoline, @function -pypy_execute_frame_trampoline: - .cfi_startproc - pushq %rcx - .cfi_def_cfa_offset 16 - call pypy_pyframe_execute_frame@PLT - popq %rcx - .cfi_def_cfa_offset 8 - ret - .cfi_endproc - .size pypy_execute_frame_trampoline, .-pypy_execute_frame_trampoline diff --git a/pypy/module/_vmprof/src/trampoline.vmprof.s b/pypy/module/_vmprof/src/trampoline.vmprof.s new file mode 100644 --- /dev/null +++ b/pypy/module/_vmprof/src/trampoline.vmprof.s @@ -0,0 +1,15 @@ +// NOTE: you need to use TABs, not spaces! + + .text + .globl pypy_execute_frame_trampoline + .type pypy_execute_frame_trampoline, @function +pypy_execute_frame_trampoline: + .cfi_startproc + pushq %rcx + .cfi_def_cfa_offset 16 + call pypy_pyframe_execute_frame@PLT + popq %rcx + .cfi_def_cfa_offset 8 + ret + .cfi_endproc + .size pypy_execute_frame_trampoline, .-pypy_execute_frame_trampoline diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c --- a/pypy/module/_vmprof/src/vmprof.c +++ b/pypy/module/_vmprof/src/vmprof.c @@ -305,7 +305,6 @@ static int remove_sigprof_timer(void) { static struct itimerval timer; - last_period_usec = 0; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 0; @@ -317,11 +316,15 @@ } static void atfork_disable_timer(void) { - remove_sigprof_timer(); + if (last_period_usec) { + remove_sigprof_timer(); + } } static void atfork_enable_timer(void) { - install_sigprof_timer(last_period_usec); + if (last_period_usec) { + install_sigprof_timer(last_period_usec); + } } static int install_pthread_atfork_hooks(void) { @@ -412,6 +415,7 @@ if (remove_sigprof_timer() == -1) { return -1; } + last_period_usec = 0; if (remove_sigprof_handler() == -1) { return -1; } diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -338,9 +338,11 @@ w_all = try_getattr(space, w_mod, space.wrap('__all__')) if w_all is not None: fromlist_w = space.fixedview(w_all) - for w_name in fromlist_w: - if try_getattr(space, w_mod, w_name) is None: - return None + else: + # this only runs if fromlist_w != ['*'] + for w_name in fromlist_w: + if try_getattr(space, w_mod, w_name) is None: + return None return w_mod return first @@ -378,10 +380,12 @@ w_all = try_getattr(space, w_mod, w('__all__')) if w_all is not None: fromlist_w = space.fixedview(w_all) - for w_name in fromlist_w: - if try_getattr(space, w_mod, w_name) is None: - load_part(space, w_path, prefix, space.str0_w(w_name), - w_mod, tentative=1) + else: + # this only runs if fromlist_w != ['*'] + for w_name in fromlist_w: + if try_getattr(space, w_mod, w_name) is None: + load_part(space, w_path, prefix, space.str0_w(w_name), + w_mod, tentative=1) return w_mod else: return first diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -1373,6 +1373,53 @@ finally: sys.path_hooks.pop() + def test_meta_path_import_error_1(self): + # as far as I can tell, the problem is that in CPython, if you + # use an import hook that doesn't update sys.modules, then the + # import succeeds; but at the same time, you can have the same + # result without an import hook (see test_del_from_sys_modules) + # and then the import fails. This looks like even more mess + # to replicate, so we ignore it until someone really hits this + # case... + skip("looks like an inconsistency in CPython") + + class ImportHook(object): + def find_module(self, fullname, path=None): + assert not fullname.endswith('*') + if fullname == 'meta_path_pseudo_module': + return self + def load_module(self, fullname): + assert fullname == 'meta_path_pseudo_module' + # we "forget" to update sys.modules + return new.module('meta_path_pseudo_module') + + import sys, new + sys.meta_path.append(ImportHook()) + try: + import meta_path_pseudo_module + finally: + sys.meta_path.pop() + + def test_meta_path_import_star_2(self): + class ImportHook(object): + def find_module(self, fullname, path=None): + if fullname.startswith('meta_path_2_pseudo_module'): + return self + def load_module(self, fullname): + assert fullname == 'meta_path_2_pseudo_module' + m = new.module('meta_path_2_pseudo_module') + m.__path__ = ['/some/random/dir'] + sys.modules['meta_path_2_pseudo_module'] = m + return m + + import sys, new + sys.meta_path.append(ImportHook()) + try: + exec "from meta_path_2_pseudo_module import *" in {} + finally: + sys.meta_path.pop() + + class AppTestPyPyExtension(object): spaceconfig = dict(usemodules=['imp', 'zipimport', '__pypy__']) 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 @@ -645,7 +645,7 @@ next_item = _new_next('item') -def create_iterator_classes(dictimpl, override_next_item=None): +def create_iterator_classes(dictimpl): if not hasattr(dictimpl, 'wrapkey'): wrapkey = lambda space, key: key else: @@ -688,15 +688,12 @@ self.iterator = strategy.getiteritems(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) - if override_next_item is not None: - next_item_entry = override_next_item - else: - def next_item_entry(self): - for key, value in self.iterator: - return (wrapkey(self.space, key), - wrapvalue(self.space, value)) - else: - return None, None + def next_item_entry(self): + for key, value in self.iterator: + return (wrapkey(self.space, key), + wrapvalue(self.space, value)) + else: + return None, None class IterClassReversed(BaseKeyIterator): def __init__(self, space, strategy, impl): @@ -729,22 +726,7 @@ def rev_update1_dict_dict(self, w_dict, w_updatedict): # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. - if override_next_item is not None: - # this is very similar to the general version, but the difference - # is that it is specialized to call a specific next_item() - iteritems = IterClassItems(self.space, self, w_dict) - w_key, w_value = iteritems.next_item() - if w_key is None: - return - w_updatedict.setitem(w_key, w_value) - w_updatedict.strategy.prepare_update(w_updatedict, - w_dict.length() - 1) - while True: - w_key, w_value = iteritems.next_item() - if w_key is None: - return - w_updatedict.setitem(w_key, w_value) - else: + if 1: # (preserve indentation) iteritems = self.getiteritems(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -167,19 +167,26 @@ return iter(self.unerase(w_dict.dstorage)[1]) def getiteritems(self, w_dict): - keys = self.unerase(w_dict.dstorage)[0] - return iter(range(len(keys))) + return Zip(*self.unerase(w_dict.dstorage)) wrapkey = _wrapkey -def next_item(self): - strategy = self.strategy - assert isinstance(strategy, KwargsDictStrategy) - for i in self.iterator: - keys, values_w = strategy.unerase(self.dictimplementation.dstorage) - return _wrapkey(self.space, keys[i]), values_w[i] - else: - return None, None +class Zip(object): + def __init__(self, list1, list2): + assert len(list1) == len(list2) + self.list1 = list1 + self.list2 = list2 + self.i = 0 -create_iterator_classes(KwargsDictStrategy, override_next_item=next_item) + def __iter__(self): + return self + + def next(self): + i = self.i + if i >= len(self.list1): + raise StopIteration + self.i = i + 1 + return (self.list1[i], self.list2[i]) + +create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -193,9 +193,9 @@ def switch_to_object_strategy(self): list_w = self.getitems() - self.strategy = self.space.fromcache(ObjectListStrategy) - # XXX this is quite indirect - self.init_from_list_w(list_w) + object_strategy = self.space.fromcache(ObjectListStrategy) + self.strategy = object_strategy + object_strategy.init_from_list_w(self, list_w) def _temporarily_as_objects(self): if self.strategy is self.space.fromcache(ObjectListStrategy): diff --git a/pypy/objspace/std/test/test_kwargsdict.py b/pypy/objspace/std/test/test_kwargsdict.py --- a/pypy/objspace/std/test/test_kwargsdict.py +++ b/pypy/objspace/std/test/test_kwargsdict.py @@ -160,6 +160,14 @@ assert a == 3 assert "KwargsDictStrategy" in self.get_strategy(d) + def test_iteritems_bug(self): + def f(**args): + return args + + d = f(a=2, b=3, c=4) + for key, value in d.items(): + None in d + def test_unicode(self): """ def f(**kwargs): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -187,7 +187,12 @@ [i0] jump(i0) """ - self.optimize_loop(ops, expected) + short = """ + [i2] + p3 = cast_int_to_ptr(i2) + jump(i2) + """ + self.optimize_loop(ops, expected, expected_short=short) def test_reverse_of_cast_2(self): ops = """ diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -439,8 +439,8 @@ mk.definition('PYTHON', get_recent_cpython_executable()) - mk.definition('GCMAPFILES', '$(subst .asmgcc.s,.gcmap,$(subst .c,.gcmap,$(SOURCES)))') - mk.definition('OBJECTS1', '$(subst .asmgcc.s,.o,$(subst .c,.o,$(SOURCES)))') + mk.definition('GCMAPFILES', '$(subst .vmprof.s,.gcmap,$(subst .c,.gcmap,$(SOURCES)))') + mk.definition('OBJECTS1', '$(subst .vmprof.s,.o,$(subst .c,.o,$(SOURCES)))') mk.definition('OBJECTS', '$(OBJECTS1) gcmaptable.s') # the CFLAGS passed to gcc when invoked to assembler the .s file @@ -462,12 +462,12 @@ 'rm $*.s $*.lbl.s']) # this is for manually written assembly files which needs to be parsed by asmgcc - mk.rule('%.o %.gcmap', '%.asmgcc.s', [ + mk.rule('%.o %.gcmap', '%.vmprof.s', [ '$(PYTHON) $(RPYDIR)/translator/c/gcc/trackgcroot.py ' - '-t $*.asmgcc.s > $*.gctmp', - '$(CC) -o $*.o -c $*.asmgcc.lbl.s', + '-t $*.vmprof.s > $*.gctmp', + '$(CC) -o $*.o -c $*.vmprof.lbl.s', 'mv $*.gctmp $*.gcmap', - 'rm $*.asmgcc.lbl.s']) + 'rm $*.vmprof.lbl.s']) # the rule to compute gcmaptable.s mk.rule('gcmaptable.s', '$(GCMAPFILES)', _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit