Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r82259:39811a0085e6 Date: 2016-02-15 12:28 +0100 http://bitbucket.org/pypy/pypy/changeset/39811a0085e6/
Log: merged deafult diff --git a/lib-python/2.7/distutils/command/build_ext.py b/lib-python/2.7/distutils/command/build_ext.py --- a/lib-python/2.7/distutils/command/build_ext.py +++ b/lib-python/2.7/distutils/command/build_ext.py @@ -188,7 +188,7 @@ # the 'libs' directory is for binary installs - we assume that # must be the *native* platform. But we don't really support # cross-compiling via a binary install anyway, so we let it go. - self.library_dirs.append(os.path.join(sys.exec_prefix, 'include')) + self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) if self.debug: self.build_temp = os.path.join(self.build_temp, "Debug") else: diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.5.1 +Version: 1.5.2 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.5.1" -__version_info__ = (1, 5, 1) +__version__ = "1.5.2" +__version_info__ = (1, 5, 2) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.5.1" + "\ncompiled with cffi version: 1.5.2" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py --- a/lib_pypy/cffi/api.py +++ b/lib_pypy/cffi/api.py @@ -1,4 +1,4 @@ -import sys, sysconfig, types +import sys, types from .lock import allocate_lock try: @@ -550,16 +550,29 @@ lst.append(value) # if '__pypy__' in sys.builtin_module_names: - if hasattr(sys, 'prefix'): - import os - ensure('library_dirs', os.path.join(sys.prefix, 'bin')) - pythonlib = "pypy-c" + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python27" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' + pythonlib = "pypy-c" + if hasattr(sys, 'prefix'): + import os + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) else: if sys.platform == "win32": template = "python%d%d" if hasattr(sys, 'gettotalrefcount'): template += '_d' else: + try: + import sysconfig + except ImportError: # 2.6 + from distutils import sysconfig template = "python%d.%d" if sysconfig.get_config_var('DEBUG_EXT'): template += sysconfig.get_config_var('DEBUG_EXT') diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -1,3 +1,6 @@ +# +# DEPRECATED: implementation for ffi.verify() +# import sys, imp from . import model, ffiplatform diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,3 +1,6 @@ +# +# DEPRECATED: implementation for ffi.verify() +# import sys, os import types diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -1,3 +1,6 @@ +# +# DEPRECATED: implementation for ffi.verify() +# import sys, os, binascii, shutil, io from . import __version_verifier_modules__ from . import ffiplatform diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -36,13 +36,13 @@ "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_continuation", "_cffi_backend", - "_csv", "cppyy", "_pypyjson" + "_csv", "cppyy", "_pypyjson", "_vmprof", ]) -if ((sys.platform.startswith('linux') or sys.platform == 'darwin') - and os.uname()[4] == 'x86_64' and sys.maxint > 2**32): +#if ((sys.platform.startswith('linux') or sys.platform == 'darwin') +# and os.uname()[4] == 'x86_64' and sys.maxint > 2**32): # it's not enough that we get x86_64 - working_modules.add('_vmprof') +# working_modules.add('_vmprof') translation_modules = default_modules.copy() translation_modules.update([ diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -7,6 +7,9 @@ Fixed ``_PyLong_FromByteArray()``, which was buggy. +Fixed a crash with stacklets (or greenlets) on non-Linux machines +which showed up if you forget stacklets without resuming them. + .. branch: numpy-1.10 Fix tests to run cleanly with -A and start to fix micronumpy for upstream numpy @@ -38,7 +41,8 @@ .. branch: compress-numbering -Improve the memory signature of numbering instances in the JIT. +Improve the memory signature of numbering instances in the JIT. This should massively +decrease the amount of memory consumed by the JIT, which is significant for most programs. .. branch: fix-trace-too-long-heuristic @@ -144,6 +148,11 @@ Refactor vmprof to work cross-operating-system. +.. branch: seperate-strucmember_h + +Seperate structmember.h from Python.h Also enhance creating api functions +to specify which header file they appear in (previously only pypy_decl.h) + .. branch: memop-simplify3 Further simplifying the backend operations malloc_cond_varsize and zero_array. diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -239,6 +239,9 @@ raise Exception("Cannot use the --output option with PyPy " "when --shared is on (it is by default). " "See issue #1971.") + if sys.platform == 'win32': + config.translation.libname = '..\\..\\libs\\python27.lib' + thisdir.join('..', '..', 'libs').ensure(dir=1) if config.translation.thread: config.objspace.usemodules.thread = True diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -306,7 +306,7 @@ return None -class W_InterpIterable(W_Root): +class InterpIterable(object): def __init__(self, space, w_iterable): self.w_iter = space.iter(w_iterable) self.space = space @@ -745,9 +745,13 @@ return self.int_w(self.hash(w_obj)) def len_w(self, w_obj): - """shotcut for space.int_w(space.len(w_obj))""" + """shortcut for space.int_w(space.len(w_obj))""" return self.int_w(self.len(w_obj)) + def contains_w(self, w_container, w_item): + """shortcut for space.is_true(space.contains(w_container, w_item))""" + return self.is_true(self.contains(w_container, w_item)) + def setitem_str(self, w_obj, key, w_value): return self.setitem(w_obj, self.wrap(key), w_value) @@ -846,7 +850,7 @@ return lst_w[:] # make the resulting list resizable def iteriterable(self, w_iterable): - return W_InterpIterable(self, w_iterable) + return InterpIterable(self, w_iterable) def _unpackiterable_unknown_length(self, w_iterator, w_iterable): """Unpack an iterable of unknown length into an interp-level @@ -1237,7 +1241,7 @@ if not isinstance(statement, PyCode): raise TypeError('space.exec_(): expected a string, code or PyCode object') w_key = self.wrap('__builtins__') - if not self.is_true(self.contains(w_globals, w_key)): + if not self.contains_w(w_globals, w_key): self.setitem(w_globals, w_key, self.wrap(self.builtin)) return statement.exec_code(self, w_globals, w_locals) diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -20,7 +20,7 @@ if not space.isinstance_w(w_dict, space.w_dict): raise_type_err(space, 'bases', 'tuple', w_bases) - if not space.is_true(space.contains(w_dict, space.wrap("__doc__"))): + if not space.contains_w(w_dict, space.wrap("__doc__")): space.setitem(w_dict, space.wrap("__doc__"), space.w_None) # XXX missing: lengthy and obscure logic about "__module__" diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi, entrypoint from rpython.rtyper.lltypesystem import rffi -VERSION = "1.5.1" +VERSION = "1.5.2" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: @@ -69,6 +69,7 @@ def startup(self, space): from pypy.module._cffi_backend import embedding embedding.glob.space = space + embedding.glob.patched_sys = False def get_dict_rtld_constants(): diff --git a/pypy/module/_cffi_backend/embedding.py b/pypy/module/_cffi_backend/embedding.py --- a/pypy/module/_cffi_backend/embedding.py +++ b/pypy/module/_cffi_backend/embedding.py @@ -45,6 +45,26 @@ pass glob = Global() +def patch_sys(space): + # Annoying: CPython would just use the C-level std{in,out,err} as + # configured by the main application, for example in binary mode + # on Windows or with buffering turned off. We can't easily do the + # same. Instead, go for the safest bet (but possibly bad for + # performance) and open sys.std{in,out,err} unbuffered. On + # Windows I guess binary mode is a better default choice. + # + # XXX if needed, we could add support for a flag passed to + # pypy_init_embedded_cffi_module(). + if not glob.patched_sys: + space.appexec([], """(): + import os + sys.stdin = sys.__stdin__ = os.fdopen(0, 'rb', 0) + sys.stdout = sys.__stdout__ = os.fdopen(1, 'wb', 0) + sys.stderr = sys.__stderr__ = os.fdopen(2, 'wb', 0) + """) + glob.patched_sys = True + + def pypy_init_embedded_cffi_module(version, init_struct): # called from __init__.py name = "?" @@ -56,6 +76,7 @@ must_leave = False try: must_leave = space.threadlocals.try_enter_thread(space) + patch_sys(space) load_embedded_cffi_module(space, version, init_struct) res = 0 except OperationError, operr: @@ -84,72 +105,87 @@ return rffi.cast(rffi.INT, res) # ____________________________________________________________ + if os.name == 'nt': - do_startup = r''' -#include <stdio.h> -#define WIN32_LEAN_AND_MEAN + + do_includes = r""" +#define _WIN32_WINNT 0x0501 #include <windows.h> -RPY_EXPORTED void rpython_startup_code(void); -RPY_EXPORTED int pypy_setup_home(char *, int); -static unsigned char _cffi_ready = 0; -static const char *volatile _cffi_module_name; +#define CFFI_INIT_HOME_PATH_MAX _MAX_PATH +static void _cffi_init(void); +static void _cffi_init_error(const char *msg, const char *extra); -static void _cffi_init_error(const char *msg, const char *extra) +static int _cffi_init_home(char *output_home_path) { - fprintf(stderr, - "\nPyPy initialization failure when loading module '%s':\n%s%s\n", - _cffi_module_name, msg, extra); -} - -BOOL CALLBACK _cffi_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) -{ - - HMODULE hModule; - TCHAR home[_MAX_PATH]; - rpython_startup_code(); - RPyGilAllocate(); + HMODULE hModule = 0; + DWORD res; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&_cffi_init, &hModule); + if (hModule == 0 ) { - /* TODO turn the int into a string with FormatMessage */ - - _cffi_init_error("dladdr() failed: ", ""); - return TRUE; + _cffi_init_error("GetModuleHandleEx() failed", ""); + return -1; } - GetModuleFileName(hModule, home, _MAX_PATH); - if (pypy_setup_home(home, 1) != 0) { - _cffi_init_error("pypy_setup_home() failed", ""); - return TRUE; + res = GetModuleFileName(hModule, output_home_path, CFFI_INIT_HOME_PATH_MAX); + if (res >= CFFI_INIT_HOME_PATH_MAX) { + return -1; } - _cffi_ready = 1; - fprintf(stderr, "startup succeeded, home %s\n", home); - return TRUE; + return 0; } -RPY_EXPORTED -int pypy_carefully_make_gil(const char *name) +static void _cffi_init_once(void) { - /* For CFFI: this initializes the GIL and loads the home path. - It can be called completely concurrently from unrelated threads. - It assumes that we don't hold the GIL before (if it exists), and we - don't hold it afterwards. - */ - static INIT_ONCE s_init_once; + static LONG volatile lock = 0; + static int _init_called = 0; - _cffi_module_name = name; /* not really thread-safe, but better than - nothing */ - InitOnceExecuteOnce(&s_init_once, _cffi_init, NULL, NULL); - return (int)_cffi_ready - 1; -}''' + while (InterlockedCompareExchange(&lock, 1, 0) != 0) { + SwitchToThread(); /* spin loop */ + } + if (!_init_called) { + _cffi_init(); + _init_called = 1; + } + InterlockedCompareExchange(&lock, 0, 1); +} +""" + else: - do_startup = r""" -#include <stdio.h> + + do_includes = r""" #include <dlfcn.h> #include <pthread.h> +#define CFFI_INIT_HOME_PATH_MAX PATH_MAX +static void _cffi_init(void); +static void _cffi_init_error(const char *msg, const char *extra); + +static int _cffi_init_home(char *output_home_path) +{ + Dl_info info; + dlerror(); /* reset */ + if (dladdr(&_cffi_init, &info) == 0) { + _cffi_init_error("dladdr() failed: ", dlerror()); + return -1; + } + if (realpath(info.dli_fname, output_home_path) == NULL) { + perror("realpath() failed"); + _cffi_init_error("realpath() failed", ""); + return -1; + } + return 0; +} + +static void _cffi_init_once(void) +{ + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + pthread_once(&once_control, _cffi_init); +} +""" + +do_startup = do_includes + r""" RPY_EXPORTED void rpython_startup_code(void); RPY_EXPORTED int pypy_setup_home(char *, int); @@ -165,17 +201,13 @@ static void _cffi_init(void) { - Dl_info info; - char *home; + char home[CFFI_INIT_HOME_PATH_MAX + 1]; rpython_startup_code(); RPyGilAllocate(); - if (dladdr(&_cffi_init, &info) == 0) { - _cffi_init_error("dladdr() failed: ", dlerror()); + if (_cffi_init_home(home) != 0) return; - } - home = realpath(info.dli_fname, NULL); if (pypy_setup_home(home, 1) != 0) { _cffi_init_error("pypy_setup_home() failed", ""); return; @@ -191,11 +223,9 @@ It assumes that we don't hold the GIL before (if it exists), and we don't hold it afterwards. */ - static pthread_once_t once_control = PTHREAD_ONCE_INIT; - _cffi_module_name = name; /* not really thread-safe, but better than nothing */ - pthread_once(&once_control, _cffi_init); + _cffi_init_once(); return (int)_cffi_ready - 1; } """ 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 @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.5.1", ("This test_c.py file is for testing a version" +assert __version__ == "1.5.2", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): diff --git a/pypy/module/_cffi_backend/test/test_ztranslation.py b/pypy/module/_cffi_backend/test/test_ztranslation.py --- a/pypy/module/_cffi_backend/test/test_ztranslation.py +++ b/pypy/module/_cffi_backend/test/test_ztranslation.py @@ -4,15 +4,18 @@ # side-effect: FORMAT_LONGDOUBLE must be built before test_checkmodule() from pypy.module._cffi_backend import misc -from pypy.module._cffi_backend import cffi1_module +from pypy.module._cffi_backend import embedding def test_checkmodule(): # prepare_file_argument() is not working without translating the _file # module too def dummy_prepare_file_argument(space, fileobj): - # call load_cffi1_module() too, from a random place like here - cffi1_module.load_cffi1_module(space, "foo", "foo", 42) + # call pypy_init_embedded_cffi_module() from a random place like here + # --- this calls load_cffi1_module(), too + embedding.pypy_init_embedded_cffi_module( + rffi.cast(rffi.INT, embedding.EMBED_VERSION_MIN), + 42) return lltype.nullptr(rffi.CCHARP.TO) old = ctypeptr.prepare_file_argument try: diff --git a/pypy/module/_demo/test/test_import.py b/pypy/module/_demo/test/test_import.py --- a/pypy/module/_demo/test/test_import.py +++ b/pypy/module/_demo/test/test_import.py @@ -12,8 +12,7 @@ w_modules = space.sys.get('modules') assert _demo.Module.demo_events == ['setup'] - assert not space.is_true(space.contains(w_modules, - space.wrap('_demo'))) + assert not space.contains_w(w_modules, space.wrap('_demo')) # first import w_import = space.builtin.get('__import__') 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 @@ -60,7 +60,7 @@ Must be smaller than 1.0 """ w_modules = space.sys.get('modules') - if space.is_true(space.contains(w_modules, space.wrap('_continuation'))): + if space.contains_w(w_modules, space.wrap('_continuation')): space.warn(space.wrap("Using _continuation/greenlet/stacklet together " "with vmprof will crash"), space.w_RuntimeWarning) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -59,7 +59,7 @@ class CConfig: _compilation_info_ = ExternalCompilationInfo( include_dirs=include_dirs, - includes=['Python.h', 'stdarg.h'], + includes=['Python.h', 'stdarg.h', 'structmember.h'], compile_extra=['-DPy_BUILD_CORE'], ) @@ -129,6 +129,7 @@ for name in constant_names: setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name)) udir.join('pypy_decl.h').write("/* Will be filled later */\n") +udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n") udir.join('pypy_macros.h').write("/* Will be filled later */\n") globals().update(rffi_platform.configure(CConfig_constants)) @@ -147,7 +148,7 @@ # XXX: 20 lines of code to recursively copy a directory, really?? assert dstdir.check(dir=True) headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl') - for name in ("pypy_decl.h", "pypy_macros.h"): + for name in ("pypy_decl.h", "pypy_macros.h", "pypy_structmember_decl.h"): headers.append(udir.join(name)) _copy_header_files(headers, dstdir) @@ -232,7 +233,7 @@ wrapper.c_name = cpyext_namespace.uniquename(self.c_name) return wrapper -def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True, +def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header='pypy_decl.h', gil=None): """ Declares a function to be exported. @@ -241,8 +242,8 @@ special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual exception into a wrapped SystemError. Unwrapped exceptions also cause a SytemError. - - set `external` to False to get a C function pointer, but not exported by - the API headers. + - `header` is the header file to export the function in, Set to None to get + a C function pointer, but not exported by the API headers. - set `gil` to "acquire", "release" or "around" to acquire the GIL, release the GIL, or both """ @@ -263,7 +264,7 @@ def decorate(func): func_name = func.func_name - if external: + if header is not None: c_name = None else: c_name = func_name @@ -271,7 +272,7 @@ c_name=c_name, gil=gil) func.api_func = api_function - if external: + if header is not None: assert func_name not in FUNCTIONS, ( "%s already registered" % func_name) @@ -363,8 +364,9 @@ unwrapper_catch = make_unwrapper(True) unwrapper_raise = make_unwrapper(False) - if external: + if header is not None: FUNCTIONS[func_name] = api_function + FUNCTIONS_BY_HEADER.setdefault(header, {})[func_name] = api_function INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests return unwrapper_raise # used in 'normal' RPython code. return decorate @@ -383,6 +385,7 @@ INTERPLEVEL_API = {} FUNCTIONS = {} +FUNCTIONS_BY_HEADER = {} # These are C symbols which cpyext will export, but which are defined in .c # files somewhere in the implementation of cpyext (rather than being defined in @@ -811,6 +814,7 @@ global_code = '\n'.join(global_objects) prologue = ("#include <Python.h>\n" + "#include <structmember.h>\n" "#include <src/thread.c>\n") code = (prologue + struct_declaration_code + @@ -960,7 +964,8 @@ "NOT_RPYTHON" # implement function callbacks and generate function decls functions = [] - pypy_decls = [] + decls = {} + pypy_decls = decls['pypy_decl.h'] = [] pypy_decls.append("#ifndef _PYPY_PYPY_DECL_H\n") pypy_decls.append("#define _PYPY_PYPY_DECL_H\n") pypy_decls.append("#ifndef PYPY_STANDALONE\n") @@ -973,17 +978,23 @@ for decl in FORWARD_DECLS: pypy_decls.append("%s;" % (decl,)) - for name, func in sorted(FUNCTIONS.iteritems()): - restype, args = c_function_signature(db, func) - pypy_decls.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args)) - if api_struct: - callargs = ', '.join('arg%d' % (i,) - for i in range(len(func.argtypes))) - if func.restype is lltype.Void: - body = "{ _pypyAPI.%s(%s); }" % (name, callargs) - else: - body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) - functions.append('%s %s(%s)\n%s' % (restype, name, args, body)) + for header_name, header_functions in FUNCTIONS_BY_HEADER.iteritems(): + if header_name not in decls: + header = decls[header_name] = [] + else: + header = decls[header_name] + + for name, func in sorted(header_functions.iteritems()): + restype, args = c_function_signature(db, func) + header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args)) + if api_struct: + callargs = ', '.join('arg%d' % (i,) + for i in range(len(func.argtypes))) + if func.restype is lltype.Void: + body = "{ _pypyAPI.%s(%s); }" % (name, callargs) + else: + body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) + functions.append('%s %s(%s)\n%s' % (restype, name, args, body)) for name in VA_TP_LIST: name_no_star = process_va_name(name) header = ('%s pypy_va_get_%s(va_list* vp)' % @@ -1007,8 +1018,9 @@ pypy_decls.append("#endif /*PYPY_STANDALONE*/\n") pypy_decls.append("#endif /*_PYPY_PYPY_DECL_H*/\n") - pypy_decl_h = udir.join('pypy_decl.h') - pypy_decl_h.write('\n'.join(pypy_decls)) + for header_name, header_decls in decls.iteritems(): + decl_h = udir.join(header_name) + decl_h.write('\n'.join(header_decls)) return functions separate_module_files = [source_dir / "varargwrapper.c", diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py --- a/pypy/module/cpyext/bufferobject.py +++ b/pypy/module/cpyext/bufferobject.py @@ -73,7 +73,7 @@ "Don't know how to realize a buffer")) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def buffer_dealloc(space, py_obj): py_buf = rffi.cast(PyBufferObject, py_obj) if py_buf.c_b_base: diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -39,7 +39,7 @@ py_frame.c_f_locals = make_ref(space, frame.get_w_locals()) rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def frame_dealloc(space, py_obj): py_frame = rffi.cast(PyFrameObject, py_obj) py_code = rffi.cast(PyObject, py_frame.c_f_code) diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py --- a/pypy/module/cpyext/funcobject.py +++ b/pypy/module/cpyext/funcobject.py @@ -56,7 +56,7 @@ assert isinstance(w_obj, Function) py_func.c_func_name = make_ref(space, space.wrap(w_obj.name)) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def function_dealloc(space, py_obj): py_func = rffi.cast(PyFunctionObject, py_obj) Py_DecRef(space, py_func.c_func_name) @@ -75,7 +75,7 @@ rffi.setintfield(py_code, 'c_co_flags', co_flags) rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def code_dealloc(space, py_obj): py_code = rffi.cast(PyCodeObject, py_obj) Py_DecRef(space, py_code.c_co_name) diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h --- a/pypy/module/cpyext/include/Python.h +++ b/pypy/module/cpyext/include/Python.h @@ -84,6 +84,7 @@ #include "pyconfig.h" #include "object.h" +#include "pymath.h" #include "pyport.h" #include "warnings.h" @@ -115,7 +116,6 @@ #include "compile.h" #include "frameobject.h" #include "eval.h" -#include "pymath.h" #include "pymem.h" #include "pycobject.h" #include "pycapsule.h" @@ -132,9 +132,6 @@ /* Missing definitions */ #include "missing.h" -// XXX This shouldn't be included here -#include "structmember.h" - #include <pypy_decl.h> /* Define macros for inline documentation. */ diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h --- a/pypy/module/cpyext/include/floatobject.h +++ b/pypy/module/cpyext/include/floatobject.h @@ -7,6 +7,18 @@ extern "C" { #endif +#define PyFloat_STR_PRECISION 12 + +#ifdef Py_NAN +#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN) +#endif + +#define Py_RETURN_INF(sign) do \ + if (copysign(1., sign) == 1.) { \ + return PyFloat_FromDouble(Py_HUGE_VAL); \ + } else { \ + return PyFloat_FromDouble(-Py_HUGE_VAL); \ + } while(0) #ifdef __cplusplus } diff --git a/pypy/module/cpyext/include/pymath.h b/pypy/module/cpyext/include/pymath.h --- a/pypy/module/cpyext/include/pymath.h +++ b/pypy/module/cpyext/include/pymath.h @@ -17,4 +17,35 @@ #define Py_HUGE_VAL HUGE_VAL #endif +/* Py_NAN + * A value that evaluates to a NaN. On IEEE 754 platforms INF*0 or + * INF/INF works. Define Py_NO_NAN in pyconfig.h if your platform + * doesn't support NaNs. + */ +#if !defined(Py_NAN) && !defined(Py_NO_NAN) +#if !defined(__INTEL_COMPILER) + #define Py_NAN (Py_HUGE_VAL * 0.) +#else /* __INTEL_COMPILER */ + #if defined(ICC_NAN_STRICT) + #pragma float_control(push) + #pragma float_control(precise, on) + #pragma float_control(except, on) + #if defined(_MSC_VER) + __declspec(noinline) + #else /* Linux */ + __attribute__((noinline)) + #endif /* _MSC_VER */ + static double __icc_nan() + { + return sqrt(-1.0); + } + #pragma float_control (pop) + #define Py_NAN __icc_nan() + #else /* ICC_NAN_RELAXED as default for Intel Compiler */ + static union { unsigned char buf[8]; double __icc_nan; } __nan_store = {0,0,0,0,0,0,0xf8,0x7f}; + #define Py_NAN (__nan_store.__icc_nan) + #endif /* ICC_NAN_STRICT */ +#endif /* __INTEL_COMPILER */ +#endif + #endif /* Py_PYMATH_H */ diff --git a/pypy/module/cpyext/include/structmember.h b/pypy/module/cpyext/include/structmember.h --- a/pypy/module/cpyext/include/structmember.h +++ b/pypy/module/cpyext/include/structmember.h @@ -4,54 +4,85 @@ extern "C" { #endif + +/* Interface to map C struct members to Python object attributes */ + #include <stddef.h> /* For offsetof */ + +/* The offsetof() macro calculates the offset of a structure member + in its structure. Unfortunately this cannot be written down + portably, hence it is provided by a Standard C header file. + For pre-Standard C compilers, here is a version that usually works + (but watch out!): */ + #ifndef offsetof #define offsetof(type, member) ( (int) & ((type*)0) -> member ) #endif +/* An array of memberlist structures defines the name, type and offset + of selected members of a C structure. These can be read by + PyMember_Get() and set by PyMember_Set() (except if their READONLY flag + is set). The array must be terminated with an entry whose name + pointer is NULL. */ + + typedef struct PyMemberDef { - /* Current version, use this */ - char *name; - int type; - Py_ssize_t offset; - int flags; - char *doc; + /* Current version, use this */ + char *name; + int type; + Py_ssize_t offset; + int flags; + char *doc; } PyMemberDef; +/* Types */ +#define T_SHORT 0 +#define T_INT 1 +#define T_LONG 2 +#define T_FLOAT 3 +#define T_DOUBLE 4 +#define T_STRING 5 +#define T_OBJECT 6 +/* XXX the ordering here is weird for binary compatibility */ +#define T_CHAR 7 /* 1-character string */ +#define T_BYTE 8 /* 8-bit signed int */ +/* unsigned variants: */ +#define T_UBYTE 9 +#define T_USHORT 10 +#define T_UINT 11 +#define T_ULONG 12 -/* Types. These constants are also in structmemberdefs.py. */ -#define T_SHORT 0 -#define T_INT 1 -#define T_LONG 2 -#define T_FLOAT 3 -#define T_DOUBLE 4 -#define T_STRING 5 -#define T_OBJECT 6 -#define T_CHAR 7 /* 1-character string */ -#define T_BYTE 8 /* 8-bit signed int */ -#define T_UBYTE 9 -#define T_USHORT 10 -#define T_UINT 11 -#define T_ULONG 12 -#define T_STRING_INPLACE 13 /* Strings contained in the structure */ -#define T_BOOL 14 -#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError - when the value is NULL, instead of - converting to None. */ -#define T_LONGLONG 17 -#define T_ULONGLONG 18 -#define T_PYSSIZET 19 +/* Added by Jack: strings contained in the structure */ +#define T_STRING_INPLACE 13 + +/* Added by Lillo: bools contained in the structure (assumed char) */ +#define T_BOOL 14 + +#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError + when the value is NULL, instead of + converting to None. */ +#ifdef HAVE_LONG_LONG +#define T_LONGLONG 17 +#define T_ULONGLONG 18 +#endif /* HAVE_LONG_LONG */ + +#define T_PYSSIZET 19 /* Py_ssize_t */ /* Flags. These constants are also in structmemberdefs.py. */ -#define READONLY 1 -#define RO READONLY /* Shorthand */ +#define READONLY 1 +#define RO READONLY /* Shorthand */ #define READ_RESTRICTED 2 #define PY_WRITE_RESTRICTED 4 -#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED) +#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED) + + +/* API functions. */ +#include "pypy_structmember_decl.h" #ifdef __cplusplus } #endif #endif /* !Py_STRUCTMEMBER_H */ + diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -50,7 +50,7 @@ py_func.c_m_self = make_ref(space, w_obj.w_self) py_func.c_m_module = make_ref(space, w_obj.w_module) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def cfunction_dealloc(space, py_obj): py_func = rffi.cast(PyCFunctionObject, py_obj) Py_DecRef(space, py_func.c_m_self) diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -70,7 +70,7 @@ alloc : allocate and basic initialization of a raw PyObject attach : Function called to tie a raw structure to a pypy object realize : Function called to create a pypy object from a raw struct - dealloc : a cpython_api(external=False), similar to PyObject_dealloc + dealloc : a cpython_api(header=None), similar to PyObject_dealloc """ tp_basestruct = kw.pop('basestruct', PyObject.TO) diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py --- a/pypy/module/cpyext/pytraceback.py +++ b/pypy/module/cpyext/pytraceback.py @@ -41,7 +41,7 @@ rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti) rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno()) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def traceback_dealloc(space, py_obj): py_traceback = rffi.cast(PyTracebackObject, py_obj) Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next)) diff --git a/pypy/module/cpyext/sliceobject.py b/pypy/module/cpyext/sliceobject.py --- a/pypy/module/cpyext/sliceobject.py +++ b/pypy/module/cpyext/sliceobject.py @@ -36,7 +36,7 @@ py_slice.c_stop = make_ref(space, w_obj.w_stop) py_slice.c_step = make_ref(space, w_obj.w_step) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def slice_dealloc(space, py_obj): """Frees allocated PyStringObject resources. """ diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -309,7 +309,7 @@ return space.wrap(generic_cpy_call(space, func_target, w_self, w_other)) -@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, header=None) def slot_tp_new(space, type, w_args, w_kwds): from pypy.module.cpyext.tupleobject import PyTuple_Check pyo = rffi.cast(PyObject, type) @@ -320,30 +320,30 @@ w_args_new = space.newtuple(args_w) return space.call(w_func, w_args_new, w_kwds) -@cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, external=False) +@cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, header=None) def slot_tp_init(space, w_self, w_args, w_kwds): w_descr = space.lookup(w_self, '__init__') args = Arguments.frompacked(space, w_args, w_kwds) space.get_and_call_args(w_descr, w_self, args) return 0 -@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None) def slot_tp_call(space, w_self, w_args, w_kwds): return space.call(w_self, w_args, w_kwds) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_str(space, w_self): return space.str(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_nb_int(space, w_self): return space.int(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_iter(space, w_self): return space.iter(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_iternext(space, w_self): return space.next(w_self) @@ -371,7 +371,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1) # XXX should be header=None @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: @@ -385,8 +385,7 @@ if getattr_fn is None: return - @cpython_api([PyObject, PyObject], PyObject, - external=True) + @cpython_api([PyObject, PyObject], PyObject) @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,)) def slot_tp_getattro(space, w_self, w_name): return space.call_function(getattr_fn, w_self, w_name) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -103,7 +103,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def string_dealloc(space, py_obj): """Frees allocated PyStringObject resources. """ diff --git a/pypy/module/cpyext/structmember.py b/pypy/module/cpyext/structmember.py --- a/pypy/module/cpyext/structmember.py +++ b/pypy/module/cpyext/structmember.py @@ -31,8 +31,10 @@ (T_PYSSIZET, rffi.SSIZE_T, PyLong_AsSsize_t), ]) +_HEADER = 'pypy_structmember_decl.h' -@cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject) + +@cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject, header=_HEADER) def PyMember_GetOne(space, obj, w_member): addr = rffi.cast(ADDR, obj) addr += w_member.c_offset @@ -83,7 +85,8 @@ return w_result -@cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real, error=-1) +@cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real, + error=-1, header=_HEADER) def PyMember_SetOne(space, obj, w_member, w_value): addr = rffi.cast(ADDR, obj) addr += w_member.c_offset diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -863,3 +863,15 @@ os.unlink('_imported_already') except OSError: pass + + def test_no_structmember(self): + """structmember.h should not be included by default.""" + mod = self.import_extension('foo', [ + ('bar', 'METH_NOARGS', + ''' + /* reuse a name that is #defined in structmember.h */ + int RO; + Py_RETURN_NONE; + ''' + ), + ]) diff --git a/pypy/module/cpyext/test/test_dictobject.py b/pypy/module/cpyext/test/test_dictobject.py --- a/pypy/module/cpyext/test/test_dictobject.py +++ b/pypy/module/cpyext/test/test_dictobject.py @@ -146,7 +146,7 @@ def test_dictproxy(self, space, api): w_dict = space.sys.get('modules') w_proxy = api.PyDictProxy_New(w_dict) - assert space.is_true(space.contains(w_proxy, space.wrap('sys'))) + assert space.contains_w(w_proxy, space.wrap('sys')) raises(OperationError, space.setitem, w_proxy, space.wrap('sys'), space.w_None) raises(OperationError, space.delitem, diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py --- a/pypy/module/cpyext/test/test_floatobject.py +++ b/pypy/module/cpyext/test/test_floatobject.py @@ -45,3 +45,35 @@ ]) assert module.from_string() == 1234.56 assert type(module.from_string()) is float + +class AppTestFloatMacros(AppTestCpythonExtensionBase): + def test_return_nan(self): + import math + + module = self.import_extension('foo', [ + ("return_nan", "METH_NOARGS", + "Py_RETURN_NAN;"), + ]) + assert math.isnan(module.return_nan()) + + def test_return_inf(self): + import math + + module = self.import_extension('foo', [ + ("return_inf", "METH_NOARGS", + "Py_RETURN_INF(10);"), + ]) + inf = module.return_inf() + assert inf > 0 + assert math.isinf(inf) + + def test_return_inf_negative(self): + import math + + module = self.import_extension('foo', [ + ("return_neginf", "METH_NOARGS", + "Py_RETURN_INF(-10);"), + ]) + neginf = module.return_neginf() + assert neginf < 0 + assert math.isinf(neginf) diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py --- a/pypy/module/cpyext/test/test_import.py +++ b/pypy/module/cpyext/test/test_import.py @@ -21,7 +21,7 @@ def test_getmoduledict(self, space, api): testmod = "_functools" w_pre_dict = api.PyImport_GetModuleDict() - assert not space.is_true(space.contains(w_pre_dict, space.wrap(testmod))) + assert not space.contains_w(w_pre_dict, space.wrap(testmod)) with rffi.scoped_str2charp(testmod) as modname: w_module = api.PyImport_ImportModule(modname) @@ -29,7 +29,7 @@ assert w_module w_dict = api.PyImport_GetModuleDict() - assert space.is_true(space.contains(w_dict, space.wrap(testmod))) + assert space.contains_w(w_dict, space.wrap(testmod)) def test_reload(self, space, api): stat = api.PyImport_Import(space.wrap("stat")) diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py --- a/pypy/module/cpyext/test/test_intobject.py +++ b/pypy/module/cpyext/test/test_intobject.py @@ -99,6 +99,7 @@ """), ], prologue=""" + #include "structmember.h" typedef struct { PyObject_HEAD diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py --- a/pypy/module/cpyext/test/test_object.py +++ b/pypy/module/cpyext/test/test_object.py @@ -202,7 +202,7 @@ def test_dir(self, space, api): w_dir = api.PyObject_Dir(space.sys) assert space.isinstance_w(w_dir, space.w_list) - assert space.is_true(space.contains(w_dir, space.wrap('modules'))) + assert space.contains_w(w_dir, space.wrap('modules')) class AppTestObject(AppTestCpythonExtensionBase): def setup_class(cls): diff --git a/pypy/module/cpyext/test/test_translate.py b/pypy/module/cpyext/test/test_translate.py --- a/pypy/module/cpyext/test/test_translate.py +++ b/pypy/module/cpyext/test/test_translate.py @@ -19,7 +19,7 @@ @specialize.memo() def get_tp_function(space, typedef): - @cpython_api([], lltype.Signed, error=-1, external=False) + @cpython_api([], lltype.Signed, error=-1, header=None) def slot_tp_function(space): return typedef.value diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -183,7 +183,7 @@ if pto.c_tp_new: add_tp_new_wrapper(space, dict_w, pto) -@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None) def tp_new_wrapper(space, self, w_args, w_kwds): tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new @@ -311,7 +311,7 @@ dealloc=type_dealloc) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto @@ -327,7 +327,7 @@ # hopefully this does not clash with the memory model assumed in # extension modules -@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False, +@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None, error=CANNOT_FAIL) def str_segcount(space, w_obj, ref): if ref: @@ -335,7 +335,7 @@ return 1 @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def str_getreadbuffer(space, w_str, segment, ref): from pypy.module.cpyext.stringobject import PyString_AsString if segment != 0: @@ -348,7 +348,7 @@ return space.len_w(w_str) @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def str_getcharbuffer(space, w_str, segment, ref): from pypy.module.cpyext.stringobject import PyString_AsString if segment != 0: @@ -361,7 +361,7 @@ return space.len_w(w_str) @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def buf_getreadbuffer(space, pyref, segment, ref): from pypy.module.cpyext.bufferobject import PyBufferObject if segment != 0: @@ -393,7 +393,7 @@ buf_getreadbuffer.api_func.get_wrapper(space)) pto.c_tp_as_buffer = c_buf -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def type_dealloc(space, obj): from pypy.module.cpyext.object import PyObject_dealloc obj_pto = rffi.cast(PyTypeObjectPtr, obj) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -75,7 +75,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def unicode_dealloc(space, py_obj): py_unicode = rffi.cast(PyUnicodeObject, py_obj) if py_unicode.c_buffer: diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py --- a/pypy/module/sys/interp_encoding.py +++ b/pypy/module/sys/interp_encoding.py @@ -34,11 +34,15 @@ elif sys.platform == "darwin": base_encoding = "utf-8" else: - base_encoding = None + # In CPython, the default base encoding is NULL. This is paired with a + # comment that says "If non-NULL, this is different than the default + # encoding for strings". Therefore, the default filesystem encoding is the + # default encoding for strings, which is ASCII. + base_encoding = "ascii" def _getfilesystemencoding(space): encoding = base_encoding - if rlocale.HAVE_LANGINFO and rlocale.CODESET: + if rlocale.HAVE_LANGINFO: try: oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None) rlocale.setlocale(rlocale.LC_CTYPE, "") diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py @@ -5,6 +5,9 @@ if sys.platform == 'win32': py.test.skip('snippets do not run on win32') +if sys.version_info < (2, 7): + py.test.skip('fails e.g. on a Debian/Ubuntu which patches virtualenv' + ' in a non-2.6-friendly way') def create_venv(name): tmpdir = udir.join(name) diff --git a/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py b/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py --- a/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py +++ b/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py @@ -101,6 +101,7 @@ c = distutils.ccompiler.new_compiler() print('compiling %s with %r' % (name, modules)) extra_preargs = [] + debug = True if sys.platform == 'win32': libfiles = [] for m in modules: @@ -109,9 +110,12 @@ libfiles.append('Release\\%s.lib' % m[:-4]) modules = libfiles extra_preargs.append('/MANIFEST') + debug = False # you need to install extra stuff + # for this to work elif threads: extra_preargs.append('-pthread') - objects = c.compile([filename], macros=sorted(defines.items()), debug=True) + objects = c.compile([filename], macros=sorted(defines.items()), + debug=debug) c.link_executable(objects + modules, name, extra_preargs=extra_preargs) finally: os.chdir(curdir) @@ -119,12 +123,18 @@ def execute(self, name): path = self.get_path() env_extra = {'PYTHONPATH': prefix_pythonpath()} - libpath = os.environ.get('LD_LIBRARY_PATH') - if libpath: - libpath = path + ':' + libpath + if sys.platform == 'win32': + _path = os.environ.get('PATH') + # for libpypy-c.dll or Python27.dll + _path = os.path.split(sys.executable)[0] + ';' + _path + env_extra['PATH'] = _path else: - libpath = path - env_extra['LD_LIBRARY_PATH'] = libpath + libpath = os.environ.get('LD_LIBRARY_PATH') + if libpath: + libpath = path + ':' + libpath + else: + libpath = path + env_extra['LD_LIBRARY_PATH'] = libpath print('running %r in %r' % (name, path)) executable_name = name if sys.platform == 'win32': diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -397,9 +397,14 @@ space.wrap(value) class FakeCompiler(object): - pass + def compile(self, code, name, mode, flags): + return FakePyCode() FakeObjSpace.default_compiler = FakeCompiler() +class FakePyCode(W_Root): + def exec_code(self, space, w_globals, w_locals): + return W_Root() + class FakeModule(W_Root): def __init__(self): 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 @@ -1419,9 +1419,8 @@ return space.len(self.w_dict) def _all_contained_in(space, w_dictview, w_other): - w_iter = space.iter(w_dictview) - for w_item in space.iteriterable(w_iter): - if not space.is_true(space.contains(w_other, w_item)): + for w_item in space.iteriterable(w_dictview): + if not space.contains_w(w_other, w_item): return space.w_False return space.w_True diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -108,13 +108,8 @@ # builddir = py.path.local(options.builddir) pypydir = builddir.ensure(name, dir=True) + includedir = basedir.join('include') - # Recursively copy all headers, shutil has only ignore - # so we do a double-negative to include what we want - def copyonly(dirpath, contents): - return set(contents) - set( # XXX function not used? - shutil.ignore_patterns('*.h', '*.incl')(dirpath, contents), - ) shutil.copytree(str(includedir), str(pypydir.join('include'))) pypydir.ensure('include', dir=True) @@ -139,22 +134,27 @@ continue print "Picking %s" % p binaries.append((p, p.basename)) - importlib_name = 'python27.lib' - if pypy_c.dirpath().join(importlib_name).check(): - shutil.copyfile(str(pypy_c.dirpath().join(importlib_name)), - str(pypydir.join('include/python27.lib'))) - print "Picking %s as %s" % (pypy_c.dirpath().join(importlib_name), - pypydir.join('include/python27.lib')) + libsdir = basedir.join('libs') + if libsdir.exists(): + print 'Picking %s (and contents)' % libsdir + shutil.copytree(str(libsdir), str(pypydir.join('libs'))) else: - pass - # XXX users will complain that they cannot compile cpyext - # modules for windows, has the lib moved or are there no - # exported functions in the dll so no import library is created? + print '"libs" dir with import library not found.' + print 'You have to create %r' % (str(libsdir),) + print 'and copy libpypy-c.lib in there, renamed to python27.lib' + # XXX users will complain that they cannot compile capi (cpyext) + # modules for windows, also embedding pypy (i.e. in cffi) + # will fail. + # Has the lib moved, was translation not 'shared', or are + # there no exported functions in the dll so no import + # library was created? if not options.no_tk: try: p = pypy_c.dirpath().join('tcl85.dll') if not p.check(): p = py.path.local.sysfind('tcl85.dll') + if p is None: + raise WindowsError("tcl85.dll not found") tktcldir = p.dirpath().join('..').join('lib') shutil.copytree(str(tktcldir), str(pypydir.join('tcl'))) except WindowsError: diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -192,6 +192,8 @@ "If true, makes an lldebug0 build", default=False, cmdline="--lldebug0"), StrOption("icon", "Path to the (Windows) icon to use for the executable"), + StrOption("libname", + "Windows: name and possibly location of the lib file to create"), OptionDescription("backendopt", "Backend Optimization Options", [ # control inlining diff --git a/rpython/doc/rlib.rst b/rpython/doc/rlib.rst --- a/rpython/doc/rlib.rst +++ b/rpython/doc/rlib.rst @@ -52,7 +52,7 @@ backend emits code, the function is called to determine the value. ``CDefinedIntSymbolic``: - Instances of ``ComputedIntSymbolic`` are also treated like integers of + Instances of ``CDefinedIntSymbolic`` are also treated like integers of unknown value by the annotator. When C code is emitted they will be represented by the attribute ``expr`` of the symbolic (which is also the first argument of the constructor). diff --git a/rpython/jit/backend/llsupport/test/zrpy_vmprof_test.py b/rpython/jit/backend/llsupport/test/zrpy_vmprof_test.py --- a/rpython/jit/backend/llsupport/test/zrpy_vmprof_test.py +++ b/rpython/jit/backend/llsupport/test/zrpy_vmprof_test.py @@ -3,16 +3,13 @@ from rpython.jit.backend.test.support import CCompiledMixin from rpython.rlib.jit import JitDriver from rpython.tool.udir import udir +from rpython.rlib import rthread from rpython.translator.translator import TranslationContext from rpython.jit.backend.detect_cpu import getcpuclass class CompiledVmprofTest(CCompiledMixin): CPUClass = getcpuclass() - def setup(self): - if self.CPUClass.backend_name != 'x86_64': - py.test.skip("vmprof only supports x86-64 CPUs at the moment") - def _get_TranslationContext(self): t = TranslationContext() t.config.translation.gc = 'incminimark' @@ -62,6 +59,7 @@ tmpfilename = str(udir.join('test_rvmprof')) def f(num): + rthread.get_ident() # register TLOFS_thread_ident code = MyCode("py:x:foo:3") rvmprof.register_code(code, get_name) fd = os.open(tmpfilename, os.O_WRONLY | os.O_CREAT, 0666) diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -30,6 +30,11 @@ mixlevelannotator.finish() lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr) +# Note: it's important that this is a light finalizer, otherwise +# the GC will call it but still expect the object to stay around for +# a while---and it can't stay around, because s_sscopy points to +# freed nonsense and customtrace() will crash +@rgc.must_be_light_finalizer def stacklet_destructor(stacklet): sscopy = stacklet.s_sscopy if sscopy: diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py --- a/rpython/rlib/rvmprof/cintf.py +++ b/rpython/rlib/rvmprof/cintf.py @@ -33,11 +33,11 @@ if detect_cpu.autodetect().startswith(detect_cpu.MODEL_S390_64): raise VMProfPlatformUnsupported("rvmprof not supported on" " s390x CPUs for now") + compile_extra = ['-DRPYTHON_LL2CTYPES'] platform.verify_eci(ExternalCompilationInfo( - compile_extra=['-DRPYTHON_LL2CTYPES'], + compile_extra=compile_extra, **eci_kwds)) - eci = global_eci vmprof_init = rffi.llexternal("vmprof_init", [rffi.INT, rffi.DOUBLE, rffi.CCHARP], diff --git a/rpython/rlib/rvmprof/src/rvmprof.c b/rpython/rlib/rvmprof/src/rvmprof.c --- a/rpython/rlib/rvmprof/src/rvmprof.c +++ b/rpython/rlib/rvmprof/src/rvmprof.c @@ -1,23 +1,21 @@ #define _GNU_SOURCE 1 - #ifdef RPYTHON_LL2CTYPES /* only for testing: ll2ctypes sets RPY_EXTERN from the command-line */ -# ifndef RPY_EXTERN -# define RPY_EXTERN RPY_EXPORTED -# endif -# define RPY_EXPORTED extern __attribute__((visibility("default"))) -# define VMPROF_ADDR_OF_TRAMPOLINE(addr) 0 +#ifndef RPY_EXTERN +#define RPY_EXTERN RPY_EXPORTED +#endif +#ifdef _WIN32 +#define RPY_EXPORTED __declspec(dllexport) +#else +#define RPY_EXPORTED extern __attribute__((visibility("default"))) +#endif #else - # include "common_header.h" # include "structdef.h" # include "src/threadlocal.h" # include "rvmprof.h" -/*# ifndef VMPROF_ADDR_OF_TRAMPOLINE -# error "RPython program using rvmprof, but not calling vmprof_execute_code()" -# endif*/ #endif diff --git a/rpython/rlib/rvmprof/src/vmprof_common.h b/rpython/rlib/rvmprof/src/vmprof_common.h --- a/rpython/rlib/rvmprof/src/vmprof_common.h +++ b/rpython/rlib/rvmprof/src/vmprof_common.h @@ -7,9 +7,6 @@ static long profile_interval_usec = 0; static int opened_profile(char *interp_name); -#define MAX_STACK_DEPTH \ - ((SINGLE_BUF_SIZE - sizeof(struct prof_stacktrace_s)) / sizeof(void *)) - #define MARKER_STACKTRACE '\x01' #define MARKER_VIRTUAL_IP '\x02' #define MARKER_TRAILER '\x03' @@ -20,6 +17,9 @@ #define VERSION_THREAD_ID '\x01' #define VERSION_TAG '\x02' +#define MAX_STACK_DEPTH \ + ((SINGLE_BUF_SIZE - sizeof(struct prof_stacktrace_s)) / sizeof(void *)) + typedef struct prof_stacktrace_s { char padding[sizeof(long) - 1]; char marker; @@ -71,6 +71,43 @@ return _write_all((char*)&header, 5 * sizeof(long) + 4 + namelen); } +/* ************************************************************* + * functions to dump the stack trace + * ************************************************************* + */ + + +static int get_stack_trace(vmprof_stack_t* stack, intptr_t *result, int max_depth, intptr_t pc) +{ + int n = 0; + intptr_t addr = 0; + int bottom_jitted = 0; + // check if the pc is in JIT +#ifdef PYPY_JIT_CODEMAP + if (pypy_find_codemap_at_addr((intptr_t)pc, &addr)) { + // the bottom part is jitted, means we can fill up the first part + // from the JIT + n = vmprof_write_header_for_jit_addr(result, n, pc, max_depth); + stack = stack->next; // skip the first item as it contains garbage + } +#endif + while (n < max_depth - 1 && stack) { + if (stack->kind == VMPROF_CODE_TAG) { + result[n] = stack->kind; + result[n + 1] = stack->value; + n += 2; + } +#ifdef PYPY_JIT_CODEMAP + else if (stack->kind == VMPROF_JITTED_TAG) { + pc = ((intptr_t*)(stack->value - sizeof(intptr_t)))[0]; + n = vmprof_write_header_for_jit_addr(result, n, pc, max_depth); + } +#endif + stack = stack->next; + } + return n; +} + #ifndef RPYTHON_LL2CTYPES static vmprof_stack_t *get_vmprof_stack(void) { diff --git a/rpython/rlib/rvmprof/src/vmprof_main.h b/rpython/rlib/rvmprof/src/vmprof_main.h --- a/rpython/rlib/rvmprof/src/vmprof_main.h +++ b/rpython/rlib/rvmprof/src/vmprof_main.h @@ -35,6 +35,7 @@ #include "vmprof_stack.h" #include "vmprof_getpc.h" #include "vmprof_mt.h" +#include "vmprof_get_custom_offset.h" #include "vmprof_common.h" /************************************************************/ @@ -78,46 +79,6 @@ static char atfork_hook_installed = 0; -#include "vmprof_get_custom_offset.h" - -/* ************************************************************* - * functions to dump the stack trace - * ************************************************************* - */ - - -static int get_stack_trace(intptr_t *result, int max_depth, intptr_t pc, ucontext_t *ucontext) -{ - vmprof_stack_t* stack = get_vmprof_stack(); - int n = 0; - intptr_t addr = 0; - int bottom_jitted = 0; - // check if the pc is in JIT -#ifdef PYPY_JIT_CODEMAP - if (pypy_find_codemap_at_addr((intptr_t)pc, &addr)) { - // the bottom part is jitted, means we can fill up the first part - // from the JIT - n = vmprof_write_header_for_jit_addr(result, n, pc, max_depth); - stack = stack->next; // skip the first item as it contains garbage - } -#endif - while (n < max_depth - 1 && stack) { - if (stack->kind == VMPROF_CODE_TAG) { - result[n] = stack->kind; - result[n + 1] = stack->value; - n += 2; - } -#ifdef PYPY_JIT_CODEMAP - else if (stack->kind == VMPROF_JITTED_TAG) { - pc = ((intptr_t*)(stack->value - sizeof(intptr_t)))[0]; - n = vmprof_write_header_for_jit_addr(result, n, pc, max_depth); - } -#endif - stack = stack->next; - } - return n; -} - static intptr_t get_current_thread_id(void) { /* xxx This function is a hack on two fronts: @@ -194,8 +155,8 @@ struct prof_stacktrace_s *st = (struct prof_stacktrace_s *)p->data; st->marker = MARKER_STACKTRACE; st->count = 1; - depth = get_stack_trace(st->stack, - MAX_STACK_DEPTH-2, GetPC((ucontext_t*)ucontext), ucontext); + depth = get_stack_trace(get_vmprof_stack(), st->stack, + MAX_STACK_DEPTH-2, GetPC((ucontext_t*)ucontext)); st->depth = depth; st->stack[depth++] = get_current_thread_id(); p->data_offset = offsetof(struct prof_stacktrace_s, marker); diff --git a/rpython/rlib/rvmprof/src/vmprof_main_win32.h b/rpython/rlib/rvmprof/src/vmprof_main_win32.h --- a/rpython/rlib/rvmprof/src/vmprof_main_win32.h +++ b/rpython/rlib/rvmprof/src/vmprof_main_win32.h @@ -10,13 +10,30 @@ return 0; } +#if defined(_MSC_VER) +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#endif + +#include <assert.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/types.h> +#include <signal.h> +#include <stddef.h> +#include <sys/stat.h> +#include <fcntl.h> #include "vmprof_stack.h" +#include "vmprof_get_custom_offset.h" #include "vmprof_common.h" #include <tlhelp32.h> // This file has been inspired (but not copied from since the LICENSE // would not allow it) from verysleepy profiler +#define SINGLE_BUF_SIZE 8192 + volatile int thread_started = 0; volatile int enabled = 0; @@ -55,52 +72,75 @@ return 0; } -int vmprof_snapshot_thread(DWORD thread_id, PyThreadState *tstate, prof_stacktrace_s *stack) +int vmprof_snapshot_thread(struct pypy_threadlocal_s *p, prof_stacktrace_s *stack) { - HRESULT result; - HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); - int depth; + void *addr; + vmprof_stack_t *cur; + long tid; + HANDLE hThread; + long depth; + DWORD result; + CONTEXT ctx; + +#ifdef RPYTHON_LL2CTYPES + return 0; // not much we can do +#else +#ifndef RPY_TLOFS_thread_ident + return 0; // we can't freeze threads, unsafe +#else + hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, p->thread_ident); if (!hThread) { return -1; } result = SuspendThread(hThread); if(result == 0xffffffff) return -1; // possible, e.g. attached debugger or thread alread suspended - // find the correct thread - depth = read_trace_from_cpy_frame(tstate->frame, stack->stack, - MAX_STACK_DEPTH); + ctx.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext(hThread, &ctx)) + return -1; + depth = get_stack_trace(p->vmprof_tl_stack, + stack->stack, MAX_STACK_DEPTH-2, ctx.Eip); stack->depth = depth; - stack->stack[depth++] = (void*)thread_id; + stack->stack[depth++] = (void*)p->thread_ident; stack->count = 1; stack->marker = MARKER_STACKTRACE; ResumeThread(hThread); return depth; +#endif +#endif } long __stdcall vmprof_mainloop(void *arg) { +#ifndef RPYTHON_LL2CTYPES + struct pypy_threadlocal_s *p; prof_stacktrace_s *stack = (prof_stacktrace_s*)malloc(SINGLE_BUF_SIZE); - HANDLE hThreadSnap = INVALID_HANDLE_VALUE; int depth; - PyThreadState *tstate; while (1) { - Sleep(profile_interval_usec * 1000); + //Sleep(profile_interval_usec * 1000); + Sleep(10); if (!enabled) { continue; } - tstate = PyInterpreterState_Head()->tstate_head; - while (tstate) { - depth = vmprof_snapshot_thread(tstate->thread_id, tstate, stack); - if (depth > 0) { - _write_all((char*)stack + offsetof(prof_stacktrace_s, marker), - depth * sizeof(void *) + - sizeof(struct prof_stacktrace_s) - - offsetof(struct prof_stacktrace_s, marker)); + _RPython_ThreadLocals_Acquire(); + p = _RPython_ThreadLocals_Head(); // the first one is one behind head + p = _RPython_ThreadLocals_Enum(p); + while (p) { + if (p->ready == 42) { + depth = vmprof_snapshot_thread(p, stack); + if (depth > 0) { + _write_all((char*)stack + offsetof(prof_stacktrace_s, marker), + depth * sizeof(void *) + + sizeof(struct prof_stacktrace_s) - + offsetof(struct prof_stacktrace_s, marker)); + } } - tstate = tstate->next; + p = _RPython_ThreadLocals_Enum(p); } + _RPython_ThreadLocals_Release(); } +#endif } RPY_EXTERN diff --git a/rpython/rlib/rvmprof/src/vmprof_stack.h b/rpython/rlib/rvmprof/src/vmprof_stack.h --- a/rpython/rlib/rvmprof/src/vmprof_stack.h +++ b/rpython/rlib/rvmprof/src/vmprof_stack.h @@ -1,7 +1,11 @@ #ifndef _VMPROF_STACK_H_ #define _VMPROF_STACK_H_ +#ifdef _WIN32 +#define intptr_t long // XXX windows VC++ 2008 lacks stdint.h +#else #include <unistd.h> +#endif #define VMPROF_CODE_TAG 1 /* <- also in cintf.py */ #define VMPROF_BLACKHOLE_TAG 2 diff --git a/rpython/rlib/rvmprof/test/test_ztranslation.py b/rpython/rlib/rvmprof/test/test_ztranslation.py --- a/rpython/rlib/rvmprof/test/test_ztranslation.py +++ b/rpython/rlib/rvmprof/test/test_ztranslation.py @@ -3,11 +3,10 @@ sys.path += ['../../../..'] # for subprocess in test_interpreted import py from rpython.tool.udir import udir -from rpython.rlib import rvmprof +from rpython.rlib import rvmprof, rthread from rpython.translator.c.test.test_genc import compile from rpython.rlib.nonconst import NonConstant - class MyCode: def __init__(self, count): self.count = count @@ -39,6 +38,7 @@ PROF_FILE = str(udir.join('test_ztranslation.prof')) def main(argv=[]): + rthread.get_ident() # force TLOFS_thread_ident if NonConstant(False): # Hack to give os.open() the correct annotation os.open('foo', 1, 1) diff --git a/rpython/translator/backendopt/finalizer.py b/rpython/translator/backendopt/finalizer.py --- a/rpython/translator/backendopt/finalizer.py +++ b/rpython/translator/backendopt/finalizer.py @@ -18,7 +18,7 @@ """ ok_operations = ['ptr_nonzero', 'ptr_eq', 'ptr_ne', 'free', 'same_as', 'direct_ptradd', 'force_cast', 'track_alloc_stop', - 'raw_free'] + 'raw_free', 'adr_eq', 'adr_ne'] def analyze_light_finalizer(self, graph): result = self.analyze_direct_call(graph) diff --git a/rpython/translator/c/src/threadlocal.c b/rpython/translator/c/src/threadlocal.c --- a/rpython/translator/c/src/threadlocal.c +++ b/rpython/translator/c/src/threadlocal.c @@ -85,6 +85,11 @@ return prev->next; } +struct pypy_threadlocal_s *_RPython_ThreadLocals_Head(void) +{ + return &linkedlist_head; +} + static void _RPy_ThreadLocals_Init(void *p) { struct pypy_threadlocal_s *tls = (struct pypy_threadlocal_s *)p; diff --git a/rpython/translator/c/src/threadlocal.h b/rpython/translator/c/src/threadlocal.h --- a/rpython/translator/c/src/threadlocal.h +++ b/rpython/translator/c/src/threadlocal.h @@ -27,6 +27,9 @@ RPY_EXTERN struct pypy_threadlocal_s * _RPython_ThreadLocals_Enum(struct pypy_threadlocal_s *prev); +/* will return the head of the list */ +RPY_EXTERN struct pypy_threadlocal_s *_RPython_ThreadLocals_Head(); + #define OP_THREADLOCALREF_ACQUIRE(r) _RPython_ThreadLocals_Acquire() #define OP_THREADLOCALREF_RELEASE(r) _RPython_ThreadLocals_Release() #define OP_THREADLOCALREF_ENUM(p, r) r = _RPython_ThreadLocals_Enum(p) diff --git a/rpython/translator/driver.py b/rpython/translator/driver.py --- a/rpython/translator/driver.py +++ b/rpython/translator/driver.py @@ -487,13 +487,14 @@ exe = py.path.local(exename) exename = exe.new(purebasename=exe.purebasename + 'w') shutil_copy(str(exename), str(newexename)) - # the import library is named python27.lib, according - # to the pragma in pyconfig.h - libname = str(newsoname.dirpath().join('python27.lib')) + # for pypy, the import library is renamed and moved to + # libs/python27.lib, according to the pragma in pyconfig.h + libname = self.config.translation.libname + libname = libname or soname.new(ext='lib').basename + libname = str(newsoname.dirpath().join(libname)) shutil.copyfile(str(soname.new(ext='lib')), libname) self.log.info("copied: %s" % (libname,)) - # XXX TODO : replace the nonsense above with - # ext_to_copy = ['lib', 'pdb'] + # the pdb file goes in the same place as pypy(w).exe ext_to_copy = ['pdb',] for ext in ext_to_copy: name = soname.new(ext=ext) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit