diff -Nru pypy-7.3.5+dfsg/debian/changelog pypy-7.3.6+dfsg/debian/changelog --- pypy-7.3.5+dfsg/debian/changelog 2021-05-23 14:16:05.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/changelog 2021-10-17 19:51:19.000000000 +0000 @@ -1,9 +1,39 @@ -pypy (7.3.5+dfsg-1~ppa1~ubuntu16.04) xenial; urgency=medium +pypy (7.3.6+dfsg-1~ppa1~ubuntu16.04) xenial; urgency=medium - * Rebuild for the PyPy PPA. + * Build for the PyPy PPA. * The python2 binary package didn't exist yet, use python. - -- Stefano Rivera Sun, 23 May 2021 10:16:05 -0400 + -- Stefano Rivera Sun, 17 Oct 2021 12:51:19 -0700 + +pypy (7.3.6+dfsg-1) unstable; urgency=medium + + * New upstream release (same as RC2). + * Upload to unstable. + + -- Stefano Rivera Sun, 17 Oct 2021 10:23:26 -0700 + +pypy (7.3.6~rc2+dfsg-1) experimental; urgency=medium + + * New upstream RC. + * Refresh patches. + * Update copyright. + * Bump Standards-Version to 4.6.0, no changes needed. + * Handle RCs correctly in get-packaged-orig-source. + * Drop patch ppc-jit-backend, superseded upstream. + + -- Stefano Rivera Wed, 06 Oct 2021 20:56:34 -0700 + +pypy (7.3.5+dfsg-3) unstable; urgency=medium + + * Fix PPC JIT backend code generation. (Closes: #994265) + + -- Stefano Rivera Sat, 25 Sep 2021 09:12:52 -0700 + +pypy (7.3.5+dfsg-2) unstable; urgency=medium + + * Upload to unstable. + + -- Stefano Rivera Tue, 17 Aug 2021 22:09:48 -0400 pypy (7.3.5+dfsg-1) experimental; urgency=medium diff -Nru pypy-7.3.5+dfsg/debian/control pypy-7.3.6+dfsg/debian/control --- pypy-7.3.5+dfsg/debian/control 2021-05-23 14:16:05.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/control 2021-10-17 19:51:19.000000000 +0000 @@ -25,7 +25,7 @@ valgrind [amd64 arm64 armhf i386 mips mips64el mipsel powerpc ppc64 ppc64el s390x], zlib1g-dev Build-Depends-Indep: graphviz -Standards-Version: 4.5.1 +Standards-Version: 4.6.0 Homepage: https://www.pypy.org/ Vcs-Git: https://salsa.debian.org/debian/pypy.git Vcs-Browser: https://salsa.debian.org/debian/pypy diff -Nru pypy-7.3.5+dfsg/debian/copyright pypy-7.3.6+dfsg/debian/copyright --- pypy-7.3.5+dfsg/debian/copyright 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/copyright 2021-10-17 17:23:26.000000000 +0000 @@ -30,8 +30,8 @@ Christian Tismer Hakan Ardo Benjamin Peterson - Anders Chrigstrom Wim Lavrijsen + Anders Chrigstrom Eric van Riet Paap Dan Villiom Podlaski Christiansen Remi Meier @@ -58,27 +58,29 @@ Guido Wesdorp Lawrence Oluyede Bartosz Skowron - Daniel Roberts Stefano Rivera + Daniel Roberts Adrien Di Mascio Niko Matsakis Alexander Hesse Ludovic Aubry + Batuhan Taskaya stian Jacob Hallen Jason Creighton Mark Young Andrew Lawrence Alex Martelli + Ondrej Baranovič Spenser Bauman Michal Bendowski - Ondrej Baranovič Jan de Mooij Stefan Beyer Tyler Wade Vincent Legoll Michael Foord Stephan Diehl + muke101 Simon Cross Jean-Paul Calderone Stefan Schwarzer @@ -95,7 +97,6 @@ Edd Barrett Marius Gedminas Laurence Tratt - Batuhan Taskaya Alexandre Fayolle Nicolas Truessel Simon Burton @@ -109,10 +110,11 @@ Greg Price Ivan Sichmann Freitas Mark Pearse - Andreas Stührk Tobias Pape + Andreas Stührk Jean-Philippe St. Pierre Stian Andreassen + Yusuke Izawa Guido van Rossum Pavel Vinogradov William Leslie @@ -128,8 +130,8 @@ Joannah Nanjekye Georg Brandl quejebo - muke101 - Bert Freudenberg + Vanessa Freudenberg + Michał Górny Gerald Klix Wanja Saatkamp Mike Blume @@ -137,7 +139,6 @@ Rami Chowdhury Stefan H. Muller Dodan Mihai - Michał Górny Tim Felgentreff Eugene Oden Colin Valliant @@ -171,6 +172,7 @@ Yichao Yu Lucian Branescu Mihaila anatoly techtonik + olliemath Mariano Anaya Olivier Dormond Jared Grubb @@ -198,6 +200,7 @@ Berkin Ilbeyi Mihnea Saracin Matt Jackson + Ricky Zhou Jonathan David Riehl Anders Qvist Beatrice During @@ -207,7 +210,6 @@ Faye Zhao Pauli Virtanen Mike Pavone - Ricky Zhou Alan McIntyre Alexander Sedov Alex Perry @@ -218,6 +220,8 @@ Reuben Cummings Robert Zaremba David C Ellis + cptpcrd + Felix C. Stegerman Jens-Uwe Mager Dan Stromberg Carl Meyer @@ -251,7 +255,6 @@ Thomas Hisch Barry Hart Tomasz Dziopa - cptpcrd Lutz Paelike Ignas Mikalajunas Martin Blais @@ -280,8 +283,9 @@ Miro Hrončok Antoine Dupre Bernd Schoeller - olliemath Catalin Fierut + nimaje + Pierre-Yves DAVID Gustavo Niemeyer Andrew Thompson Joshua Gilbert @@ -321,6 +325,7 @@ afteryu Andrew Stepanov Radu Ciorba + Ian Clester Carl Bordum Hansen Paul Ganssle Michal Kuffa @@ -339,6 +344,7 @@ Alex Orange alexprengere Dennis Sweeney + Kevin Lee Anna Ravencroft Dinu Gherman Michael Chermside @@ -442,6 +448,7 @@ Chris AtLee Christoph Reiter Chris Burr + Brad Kish . Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden @@ -637,14 +644,6 @@ Permission to use, copy, modify, and distribute this software is freely granted, provided that this notice is preserved. -Files: rpython/translator/c/src/libffi_msvc/* -Copyright: 1996-2003, Red Hat, Inc - 2002, Bo Thorsen - 2001, John Beniton - 2002, Ranjit Mathew - 2002, Roger Sayle -License: Expat - Files: rpython/translator/revdb/src-revdb/ancillary.h rpython/translator/revdb/src-revdb/fd_recv.c Copyright: Nicolas George @@ -664,6 +663,10 @@ Copyright: 2008, The Android Open Source Project License: Apache-2.0 +Files: dotviewer/font/FiraMath* +Copyright: 2018-2021 by Xiangdong Zeng +License: OFL-1.1-no-RFN + Files: debian/* Copyright: 2011-2021, Stefano Rivera License: Expat @@ -970,6 +973,94 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +License: OFL-1.1-no-RFN + This Font Software is licensed under the SIL Open Font License, Version 1.1. + This license is copied below, and is also available with a FAQ at: + http://scripts.sil.org/OFL + . + ----------------------------------------------------------- + SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + ----------------------------------------------------------- + . + PREAMBLE + The goals of the Open Font License (OFL) are to stimulate worldwide + development of collaborative font projects, to support the font creation + efforts of academic and linguistic communities, and to provide a free and open + framework in which fonts may be shared and improved in partnership with + others. + . + The OFL allows the licensed fonts to be used, studied, modified and + redistributed freely as long as they are not sold by themselves. The fonts, + including any derivative works, can be bundled, embedded, redistributed and/or + sold with any software provided that any reserved names are not used by + derivative works. The fonts and derivatives, however, cannot be released under + any other type of license. The requirement for fonts to remain under this + license does not apply to any document created using the fonts or their + derivatives. + . + DEFINITIONS + "Font Software" refers to the set of files released by the Copyright Holder(s) + under this license and clearly marked as such. This may include source files, + build scripts and documentation. + . + "Reserved Font Name" refers to any names specified as such after the copyright + statement(s). + . + "Original Version" refers to the collection of Font Software components as + distributed by the Copyright Holder(s). + . + "Modified Version" refers to any derivative made by adding to, deleting, or + substituting -- in part or in whole -- any of the components of the Original + Version, by changing formats or by porting the Font Software to a new + environment. + . + "Author" refers to any designer, engineer, programmer, technical writer or + other person who contributed to the Font Software. + . + PERMISSION AND CONDITIONS + Permission is hereby granted, free of charge, to any person obtaining a copy + of the Font Software, to use, study, copy, merge, embed, modify, redistribute, + and sell modified and unmodified copies of the Font Software, subject to the + following conditions: + . + 1) Neither the Font Software nor any of its individual components, in Original + or Modified Versions, may be sold by itself. + . + 2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy contains + the above copyright notice and this license. These can be included either as + stand-alone text files, human-readable headers or in the appropriate + machine-readable metadata fields within text or binary files as long as those + fields can be easily viewed by the user. + . + 3) No Modified Version of the Font Software may use the Reserved Font Name(s) + unless explicit written permission is granted by the corresponding Copyright + Holder. This restriction only applies to the primary font name as presented to + the users. + . + 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any Modified + Version, except to acknowledge the contribution(s) of the Copyright Holder(s) + and the Author(s) or with their explicit written permission. + . + 5) The Font Software, modified or unmodified, in part or in whole, must be + distributed entirely under this license, and must not be distributed under any + other license. The requirement for fonts to remain under this license does not + apply to any document created using the Font Software. + . + TERMINATION + This license becomes null and void if any of the above conditions are not met. + . + DISCLAIMER + THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, + TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, + INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE + THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + License: Python-2.0 PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- diff -Nru pypy-7.3.5+dfsg/debian/patches/ctypes-arm pypy-7.3.6+dfsg/debian/patches/ctypes-arm --- pypy-7.3.5+dfsg/debian/patches/ctypes-arm 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/patches/ctypes-arm 2021-10-17 17:23:26.000000000 +0000 @@ -5,7 +5,7 @@ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit -Workaround the presentce of hard-float in ldconfig -p output. +Workaround the presence of hard-float in ldconfig -p output. Also, handle the wide variety of ARM unames. Author: Loïc Minier diff -Nru pypy-7.3.5+dfsg/debian/patches/pep3147-core pypy-7.3.6+dfsg/debian/patches/pep3147-core --- pypy-7.3.5+dfsg/debian/patches/pep3147-core 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/patches/pep3147-core 2021-10-17 17:23:26.000000000 +0000 @@ -49,10 +49,10 @@ Apart from the basic Module used for importing diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py -index b695384..6f2513f 100755 +index d6cbf2c..1a8fda7 100755 --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py -@@ -755,6 +755,7 @@ def run_command_line(interactive, +@@ -758,6 +758,7 @@ def run_command_line(interactive, # on the command-line. filename = sys.argv[0] mainmodule.__file__ = filename diff -Nru pypy-7.3.5+dfsg/debian/patches/python3-sphinx pypy-7.3.6+dfsg/debian/patches/python3-sphinx --- pypy-7.3.5+dfsg/debian/patches/python3-sphinx 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/patches/python3-sphinx 2021-10-17 17:23:26.000000000 +0000 @@ -14,7 +14,7 @@ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py -index 92321d0..c91380a 100644 +index a5c4871..8a61cee 100644 --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -13,12 +13,6 @@ @@ -68,10 +68,10 @@ + +.. _`online`: https://doc.pypy.org/en/latest/config/index.html diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst -index 66ed789..0da3b7c 100644 +index 4a62a07..7b57a2c 100644 --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst -@@ -522,7 +522,7 @@ List of extension modules that we support: +@@ -525,7 +525,7 @@ List of extension modules that we support: _locale _lsprof _md5 diff -Nru pypy-7.3.5+dfsg/debian/patches/version-info pypy-7.3.6+dfsg/debian/patches/version-info --- pypy-7.3.5+dfsg/debian/patches/version-info 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/patches/version-info 2021-10-17 17:23:26.000000000 +0000 @@ -15,10 +15,10 @@ 2 files changed, 11 insertions(+) diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py -index 13b7c6c..77adadd 100644 +index f3df1e3..c761b3e 100644 --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py -@@ -90,6 +90,7 @@ def get_subversion_info(space): +@@ -104,6 +104,7 @@ def get_subversion_info(space): return space.wrap(('PyPy', '', '')) def get_repo_info(space): @@ -27,7 +27,7 @@ if info: repo_tag, repo_version = info diff --git a/rpython/tool/version.py b/rpython/tool/version.py -index a776f7e..245ab9d 100644 +index 6ba0c04..db60f6f 100644 --- a/rpython/tool/version.py +++ b/rpython/tool/version.py @@ -17,6 +17,16 @@ def maywarn(err, repo_type='Mercurial'): diff -Nru pypy-7.3.5+dfsg/debian/rules pypy-7.3.6+dfsg/debian/rules --- pypy-7.3.5+dfsg/debian/rules 2021-05-23 12:02:48.000000000 +0000 +++ pypy-7.3.6+dfsg/debian/rules 2021-10-17 17:23:26.000000000 +0000 @@ -79,28 +79,29 @@ override_dh_installdeb: set -e; for maintscript in preinst postinst prerm; do \ - sed -e 's/#VERSION#/$(VER)/g' \ + sed -e 's/#VERSION#/$(DVER)/g' \ -e 's/#ARCH#/$(shell dpkg-architecture -qDEB_HOST_ARCH)/g' \ debian/pypy.$$maintscript.in > debian/pypy.$$maintscript; \ done dh_installdeb HG_REPO ?= https://bitbucket.org/pypy/pypy -REV=$(shell dpkg-parsechangelog | sed -rne 's,^Version: .*hg([0-9]+).*,\1,p') -VER=$(shell dpkg-parsechangelog | sed -rne 's,^Version: (.+)\+dfsg-.*,\1,p' | sed -e 's/~//') +REV = $(shell dpkg-parsechangelog | sed -rne 's,^Version: .*hg([0-9]+).*,\1,p') +DVER = $(shell dpkg-parsechangelog | sed -rne 's,^Version: (.+)\+dfsg-.*,\1,p') +UVER = $(shell echo $(DVER) | sed -e 's/~//') get-packaged-orig-source: @echo "You can build this from a local repo by supplying the HG_REPO variable" - rm -rf pypy-$(VER).orig - hg clone $(HG_REPO) pypy-$(VER).orig + rm -rf pypy-$(DVER).orig + hg clone $(HG_REPO) pypy-$(DVER).orig ifeq (,$(REV)) - cd pypy-$(VER).orig && hg up -r release-pypy2.7-v$(VER) + cd pypy-$(DVER).orig && hg up -r release-pypy2.7-v$(UVER) else - cd pypy-$(VER).orig && hg up -r $(REV) + cd pypy-$(DVER).orig && hg up -r $(REV) endif - rm -rf pypy-$(VER).orig/.hg* - rm pypy-$(VER).orig/lib-python/2.7/distutils/command/*.exe - rm pypy-$(VER).orig/rpython/rlib/test/loadtest/loadtest*.dll - rm -rf pypy-$(VER).orig/lib-python/2.7/ensurepip/_bundled/ + rm -rf pypy-$(DVER).orig/.hg* + rm pypy-$(DVER).orig/lib-python/2.7/distutils/command/*.exe + rm pypy-$(DVER).orig/rpython/rlib/test/loadtest/loadtest*.dll + rm -rf pypy-$(DVER).orig/lib-python/2.7/ensurepip/_bundled/ tar -cJ --owner root --group root --mode a+rX \ - -f pypy_$(VER)+dfsg.orig.tar.xz pypy-$(VER).orig - rm -rf pypy-$(VER).orig + -f pypy_$(DVER)+dfsg.orig.tar.xz pypy-$(DVER).orig + rm -rf pypy-$(DVER).orig diff -Nru pypy-7.3.5+dfsg/dotviewer/dotviewer.py pypy-7.3.6+dfsg/dotviewer/dotviewer.py --- pypy-7.3.5+dfsg/dotviewer/dotviewer.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/dotviewer.py 2021-10-17 16:14:51.000000000 +0000 @@ -9,26 +9,34 @@ In the second form, the graph was already compiled to a .plain file. """ +from __future__ import print_function +import os + +PARENTDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + import sys +import getopt def main(args = sys.argv[1:]): - import getopt + # make the dotviewer *package* importable + sys.path.insert(0, PARENTDIR) + options, args = getopt.getopt(args, 's:h', ['server=', 'help']) server_addr = None for option, value in options: if option in ('-h', '--help'): - print >> sys.stderr, __doc__ + print(__doc__, file=sys.stderr) sys.exit(2) if option in ('-s', '--server'): # deprecated server_addr = value if not args and server_addr is None: - print >> sys.stderr, __doc__ + print(__doc__, file=sys.stderr) sys.exit(2) for filename in args: - import graphclient + from dotviewer import graphclient graphclient.display_dot_file(filename) if server_addr is not None: - import graphserver + from dotviewer import graphserver graphserver.listen_server(server_addr) if __name__ == '__main__': diff -Nru pypy-7.3.5+dfsg/dotviewer/drawgraph.py pypy-7.3.6+dfsg/dotviewer/drawgraph.py --- pypy-7.3.5+dfsg/dotviewer/drawgraph.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/drawgraph.py 2021-10-17 16:14:51.000000000 +0000 @@ -3,16 +3,17 @@ """ -from __future__ import generators +from __future__ import absolute_import, print_function import re, os, math +os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" import pygame from pygame.locals import * -from strunicode import forceunicode +from dotviewer.strunicode import forcestr, forceunicode this_dir = os.path.dirname(os.path.abspath(__file__)) -FONT = os.path.join(this_dir, 'font', 'DroidSans.ttf') +FONT = os.path.join(this_dir, 'font', 'FiraMath-Regular.otf') FIXEDFONT = os.path.join(this_dir, 'font', 'DroidSansMono.ttf') COLOR = { 'aliceblue': (240, 248, 255), @@ -671,8 +672,18 @@ 'yellow4': (139, 139, 0), 'yellowgreen': (154, 205, 50), } + +GONS = { + b'triangle': 3, + b'diamond': 4, + b'pentagon': 5, + b'hexagon': 6, + b'septagon': 7, + b'octagon': 8, +} + re_nonword=re.compile(r'([^0-9a-zA-Z_.]+)') -re_linewidth=re.compile(r'setlinewidth\((\d+(\.\d*)?|\.\d+)\)') +re_linewidth=re.compile(forcestr(r'setlinewidth\((\d+(\.\d*)?|\.\d+)\)')) def combine(color1, color2, alpha): r1, g1, b1 = color1 @@ -731,7 +742,7 @@ self.edges.append(Edge(self.nodes, *args)) def get_display(self): - from graphdisplay import GraphDisplay + from dotviewer.graphdisplay import GraphDisplay return GraphDisplay(self) def display(self): @@ -775,8 +786,8 @@ self.label = forceunicode(label) self.style = style self.shape = shape - self.color = color - self.fillcolor = fillcolor + self.color = forceunicode(color) + self.fillcolor = forceunicode(fillcolor) self.highlight = False def sethighlight(self, which): @@ -799,6 +810,7 @@ self.yl = float(yl) rest = rest[3:] self.style, self.color = rest + self.color = forceunicode(self.color) linematch = re_linewidth.match(self.style) if linematch: num = linematch.group(1) @@ -874,7 +886,11 @@ self.cachedarrowhead = result return result -def beziercurve((x0,y0), (x1,y1), (x2,y2), (x3,y3), resolution=8): +def beziercurve(p0, p1, p2, p3, resolution=8): + (x0, y0) = p0 + (x1, y1) = p1 + (x2, y2) = p2 + (x3, y3) = p3 result = [] f = 1.0/(resolution-1) append = result.append @@ -888,10 +904,13 @@ y0*t0 + y1*t1 + y2*t2 + y3*t3)) return result -def segmentdistance((x0,y0), (x1,y1), (x,y)): +def segmentdistance(p0, p1, p): "Distance between the point (x,y) and the segment (x0,y0)-(x1,y1)." - vx = x1-x0 - vy = y1-y0 + (x0, y0) = p0 + (x1, y1) = p1 + (x, y) = p + vx = x1 - x0 + vy = y1 - y0 try: l = math.hypot(vx, vy) vx /= l @@ -906,6 +925,11 @@ else: return abs(vy*(x-x0) - vx*(y-y0)) +def ellipse(t, center, a, b): + """ compute points on an elliplse, with t running from 0 to 2*math.pi, a + and b being the radii and center as the origin of the ellipse. """ + xcenter, ycenter = center + return int(xcenter - a / 2.0 * math.sin(t)), int(ycenter - b / 2.0 * math.cos(t)) class GraphRenderer: MARGIN = 0.6 @@ -1041,6 +1065,8 @@ if x-nw2 < w and x+nw2 > 0 and y-nh2 < h and y+nh2 > 0: self.visiblenodes.append(node) for edge in self.graphlayout.edges: + if edge.style == b"invis": + continue x1, y1, x2, y2 = edge.limits() x1, y1 = self.map(x1, y1) if x1 < w and y1 < h: @@ -1057,6 +1083,9 @@ self.bboxh - (py + (self.ofsy - self.margin)) / self.scale) def draw_node_commands(self, node): + if node.shape in (b"record", b'Mrecord'): + return self.draw_record_commands(node) + xcenter, ycenter = self.map(node.x, node.y) boxwidth = int(node.w * self.scale) boxheight = int(node.h * self.scale) @@ -1075,7 +1104,6 @@ hmax = 0 commands = [] bkgndcommands = [] - if self.font is None: if lines: raw_line = lines[0].replace('\\l','').replace('\r','') @@ -1143,16 +1171,31 @@ ytop = ycenter - hmax//2 x = xcenter-boxwidth//2 y = ycenter-boxheight//2 + center = (xcenter, ycenter) - if node.shape == 'box': + if node.shape in (b'box', b'rect', b'rectangle'): rect = (x-1, y-1, boxwidth+2, boxheight+2) + if rect[0] < 0: + rect = (0, y-1, boxwidth+2 + x-1, boxheight+2) + if rect[1] < 0: + rect = (rect[0], 0, rect[2], boxheight+2 + y-1) + def cmd(): + self.screen.fill(bgcolor, rect) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.rect(self.screen, fgcolor, rect, 1) + commands.append(cmd) + elif node.shape == b'square': + width = max(boxwidth+2, boxheight+2) + rect = (x-1, y-1, width, width) def cmd(): self.screen.fill(bgcolor, rect) bkgndcommands.append(cmd) def cmd(): pygame.draw.rect(self.screen, fgcolor, rect, 1) commands.append(cmd) - elif node.shape == 'ellipse': + + elif node.shape == b'ellipse': rect = (x-1, y-1, boxwidth+2, boxheight+2) def cmd(): pygame.draw.ellipse(self.screen, bgcolor, rect, 0) @@ -1160,7 +1203,25 @@ def cmd(): pygame.draw.ellipse(self.screen, fgcolor, rect, 1) commands.append(cmd) - elif node.shape == 'octagon': + elif node.shape == b'circle': + radius = max(boxwidth+2, boxheight+2) // 2 + def cmd(): + pygame.draw.circle(self.screen, bgcolor, center, radius, 0) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.circle(self.screen, fgcolor, center, radius, 1) + commands.append(cmd) + elif node.shape == b'doublecircle': + radius = max(boxwidth+2, boxheight+2) // 2 + bigradius = int(radius * 1.05) + def cmd(): + pygame.draw.circle(self.screen, bgcolor, center, bigradius, 0) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.circle(self.screen, fgcolor, center, radius, 1) + pygame.draw.circle(self.screen, fgcolor, center, bigradius, 1) + commands.append(cmd) + elif node.shape == b'octagon': step = 1-math.sqrt(2)/2 points = [(int(x+boxwidth*fx), int(y+boxheight*fy)) for fx, fy in [(step,0), (1-step,0), @@ -1173,6 +1234,43 @@ def cmd(): pygame.draw.polygon(self.screen, fgcolor, points, 1) commands.append(cmd) + elif node.shape == b'doubleoctagon' or node.shape == b'tripleoctagon': + radius = max(boxwidth+2, boxheight+2) + # not quite right: not all sides are parallel + width = int(radius * 1.05) - radius + count = 8 + points = [ellipse((2 * math.pi) / float(count) * (i + 0.5), + center, boxwidth, boxheight) + for i in range(count)] + points2 = [ellipse((2 * math.pi) / float(count) * (i + 0.5), + center, boxwidth + width, boxheight + width) + for i in range(count)] + points3 = [ellipse((2 * math.pi) / float(count) * (i + 0.5), + center, boxwidth + 2 * width, boxheight + 2 * width) + for i in range(count)] + if node.shape != b'tripleoctagon': + points3 = points2 + def cmd(): + pygame.draw.polygon(self.screen, bgcolor, points3, 0) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.polygon(self.screen, fgcolor, points, 1) + pygame.draw.polygon(self.screen, fgcolor, points2, 1) + pygame.draw.polygon(self.screen, fgcolor, points3, 1) + commands.append(cmd) + elif node.shape in GONS: + count = GONS[node.shape] + points = [ellipse((2 * math.pi) / float(count) * i, center, boxwidth, boxheight) + for i in range(count)] + def cmd(): + pygame.draw.polygon(self.screen, bgcolor, points, 0) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.polygon(self.screen, fgcolor, points, 1) + commands.append(cmd) + + elif node.shape in (b'none', b'plain', b'plaintext'): + pass return bkgndcommands, commands def draw_commands(self): @@ -1213,6 +1311,44 @@ return edgebodycmd + nodebkgndcmd + edgeheadcmd + nodecmd + def draw_record_commands(self, node): + xcenter, ycenter = self.map(node.x, node.y) + boxwidth = int(node.w * self.scale) + boxheight = int(node.h * self.scale) + fgcolor = getcolor(node.color, (0,0,0)) + bgcolor = getcolor(node.fillcolor, (255,255,255)) + if node.highlight: + fgcolor = highlight_color(fgcolor) + bgcolor = highlight_color(bgcolor) + + text = node.label + + img = TextSnippetRecordLR.make(self, text, (boxwidth, boxheight), fgcolor, bgcolor) + wmax, hmax = img.get_size() + xleft = xcenter - boxwidth//2 + ytop = ycenter - boxheight//2 + def cmd(img=img, y=0): + img.draw(xleft, ytop+y) + commands = [cmd] + bkgndcommands = [] + + x = xcenter-boxwidth//2 + y = ycenter-boxheight//2 + + # draw box + rect = (x-1, y-1, boxwidth+2, boxheight+2) + if rect[0] < 0: + rect = (0, y-1, boxwidth+2 + x-1, boxheight+2) + if rect[1] < 0: + rect = (rect[0], 0, rect[2], boxheight+2 + y-1) + def cmd(): + self.screen.fill(bgcolor, rect) + bkgndcommands.append(cmd) + def cmd(): + pygame.draw.rect(self.screen, fgcolor, rect, 1) + commands.append(cmd) + return bkgndcommands, commands + def render(self): self.computevisible() @@ -1254,30 +1390,33 @@ def findall(self, searchstr): """Return an iterator for all nodes and edges that contain a searchstr. """ - for item in self.graphlayout.nodes.itervalues(): + for item in self.graphlayout.nodes.values(): if item.label and searchstr in item.label: yield item for item in self.graphlayout.edges: if item.label and searchstr in item.label: yield item - def at_position(self, (x, y)): + def at_position(self, p): """Figure out the word under the cursor.""" + x, y = p for rx, ry, rw, rh, word in self.textzones: if rx <= x < rx+rw and ry <= y < ry+rh: return word return None - def node_at_position(self, (x, y)): + def node_at_position(self, p): """Return the Node under the cursor.""" + x, y = p x, y = self.revmap(x, y) for node in self.visiblenodes: if 2.0*abs(x-node.x) <= node.w and 2.0*abs(y-node.y) <= node.h: return node return None - def edge_at_position(self, (x, y), distmax=14): + def edge_at_position(self, p, distmax=14): """Return the Edge near the cursor.""" + x, y = p # XXX this function is very CPU-intensive and makes the display kinda sluggish distmax /= self.scale xy = self.revmap(x, y) @@ -1351,3 +1490,156 @@ self.renderer.textzones.append((x, y, w, h, word)) x += w + +def record_to_nested_lists(s): + try: + # Python 2 + from HTMLParser import HTMLParser + unescape = HTMLParser().unescape + except ImportError: + # Python 3 + from html import unescape + def delimit_string(): + curr.append(unescape("".join(curr_string).strip("\n"))) + del curr_string[:] + curr = [] + stack = [] + curr_string = [] + index = 0 + prev = '' + while index < len(s): + char = s[index] + if char == "|": + if prev != '}': + delimit_string() + elif char == "{": + if prev == "\\": + curr_string[-1] = "{" + else: + stack.append(curr) + curr = [] + elif char == "}": + if prev == "\\": + curr_string[-1] = "}" + else: + delimit_string() + stack[-1].append(curr) + curr = stack.pop() + elif char == "<": + index = s.find(">", index) + 1 + if index == 0: + assert 0 + else: + prev = ">" + continue + else: + curr_string.append(char) + index += 1 + prev = char + if curr_string or prev == "|": + delimit_string() + assert not stack + return curr + + +class TextSnippetRecordLR: + def __init__(self, renderer, snippets, fgcolor, bgcolor=None, font=None): + if font is None: + font = renderer.font + self.snippets = snippets + self.renderer = renderer + self.fgcolor = fgcolor + + @staticmethod + def make(renderer, s, bbox, fgcolor, bgcolor=None, font=None): + fgcolor = ensure_readable(fgcolor, bgcolor) + l = record_to_nested_lists(s) + res = TextSnippetRecordLR.make_from_list(renderer, l, fgcolor, bgcolor, font) + res._compute_offsets(bbox) + return res + + @classmethod + def make_from_list(cls, renderer, l, fgcolor, bgcolor, font): + snippets = [] + for element in l: + if isinstance(element, list): + snippets.append(cls.othercls.make_from_list(renderer, element, fgcolor, bgcolor, font)) + else: + snippets.append(TextSnippet(renderer, element, fgcolor, bgcolor, font)) + return cls(renderer, snippets, fgcolor, bgcolor, font) + + def get_size(self): + if self.snippets: + sizes = [img.get_size() for img in self.snippets] + return sum([w for w,h in sizes]), max([h for w,h in sizes]) + else: + return 0, 0 + + def draw(self, x, y): + for i, img in enumerate(self.snippets): + w, h = img.get_size() + if not isinstance(img, TextSnippetRecordLR): + img.draw(x + self.offsets[i] + self.spacing, y + (self.bbox[1] - h) // 2) + else: + img.draw(x + self.offsets[i], y) + if i != 0: + start = x + self.offsets[i], y + end = x + self.offsets[i], y + self.bbox[1] + pygame.draw.line(self.renderer.screen, self.fgcolor, start, end) + + def _compute_offsets(self, bbox): + self.bbox = bbox + width_content, height_content = self.get_size() + width, height = bbox + spacing = (width - width_content) / 2.0 / len(self.snippets) + offset = 0 + offsets = [] + for i, img in enumerate(self.snippets): + w, h = img.get_size() + offsets.append(int(offset)) + offset += w + 2 * spacing + if not isinstance(img, TextSnippet): + img._compute_offsets((w + 2 * spacing, height)) + self.offsets = offsets + self.spacing = spacing + +class TextSnippetRecordTD(TextSnippetRecordLR): + othercls = TextSnippetRecordLR + + def get_size(self): + if self.snippets: + sizes = [img.get_size() for img in self.snippets] + return max([w for w,h in sizes]), sum([h for w,h in sizes]) + else: + return 0, 0 + + def draw(self, x, y): + for i, img in enumerate(self.snippets): + w, h = img.get_size() + if not isinstance(img, TextSnippetRecordLR): + img.draw(x + (self.bbox[0] - w) // 2, y + self.offsets[i] + self.spacing) + else: + img.draw(x, y + self.offsets[i]) + if i != 0: + start = x, y + self.offsets[i] + end = x + self.bbox[0], y + self.offsets[i] + pygame.draw.line(self.renderer.screen, self.fgcolor, start, end) + + def _compute_offsets(self, bbox): + self.bbox = bbox + width_content, height_content = self.get_size() + width, height = bbox + spacing = (height - height_content) / 2.0 / len(self.snippets) + offset = 0 + offsets = [] + for i, img in enumerate(self.snippets): + w, h = img.get_size() + offsets.append(int(offset)) + offset += h + 2 * spacing + if not isinstance(img, TextSnippet): + img._compute_offsets((width, h + 2 * spacing)) + self.offsets = offsets + self.spacing = spacing + + +TextSnippetRecordLR.othercls = TextSnippetRecordTD Binary files /tmp/tmp907jn4wf/p30JwFu9g7/pypy-7.3.5+dfsg/dotviewer/font/FiraMath-Regular.otf and /tmp/tmp907jn4wf/jyIOOj2ngL/pypy-7.3.6+dfsg/dotviewer/font/FiraMath-Regular.otf differ diff -Nru pypy-7.3.5+dfsg/dotviewer/font/LICENSE pypy-7.3.6+dfsg/dotviewer/font/LICENSE --- pypy-7.3.5+dfsg/dotviewer/font/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/font/LICENSE 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,93 @@ +Copyright (C) 2018--2021 by Xiangdong Zeng + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + diff -Nru pypy-7.3.5+dfsg/dotviewer/font/README.txt pypy-7.3.6+dfsg/dotviewer/font/README.txt --- pypy-7.3.5+dfsg/dotviewer/font/README.txt 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/font/README.txt 2021-10-17 16:14:51.000000000 +0000 @@ -16,3 +16,6 @@ This directory contains the fonts for the platform. They are licensed under the Apache 2 license. + +FiraMath-Regular.otf is licensed under the Open Font License 1.1, see LICENSE. +Source: https://github.com/firamath/firamath diff -Nru pypy-7.3.5+dfsg/dotviewer/graphclient.py pypy-7.3.6+dfsg/dotviewer/graphclient.py --- pypy-7.3.5+dfsg/dotviewer/graphclient.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/graphclient.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,7 +1,9 @@ +from __future__ import absolute_import + import os, sys, re import subprocess -import msgstruct -from strunicode import forcestr +from dotviewer import msgstruct +from dotviewer.strunicode import forcestr this_dir = os.path.dirname(os.path.abspath(__file__)) GRAPHSERVER = os.path.join(this_dir, 'graphserver.py') @@ -12,7 +14,7 @@ """ if not os.path.exists(str(dotfile)): raise IOError("No such file: %s" % (dotfile,)) - import graphpage + from dotviewer import graphpage page = graphpage.DotFileGraphPage(str(dotfile)) display_page(page, wait=wait, save_tmp_file=save_tmp_file) @@ -69,13 +71,13 @@ reload(graph_id) except EOFError: pass - except Exception, e: + except Exception as e: send_error(io, e) raise io.close() def page_messages(page, graph_id): - import graphparse + from dotviewer import graphparse return graphparse.parse_dot(graph_id, forcestr(page.source), page.links, getattr(page, 'fixedfont', False)) @@ -84,7 +86,7 @@ for msg in messages: try: io.sendmsg(*msg) - except IOError, ioerror: + except IOError as ioerror: break # wait for MSG_OK or MSG_ERROR try: @@ -114,7 +116,7 @@ if not gsvar: try: return spawn_sshgraphserver_handler() - except Exception, e: + except Exception as e: return spawn_local_handler() else: try: @@ -130,7 +132,11 @@ python = os.getenv('PYPY_PYGAME_PYTHON') if not python: python = sys.executable - args = [python, '-u', GRAPHSERVER, '--stdio'] + # hack to pick the right file to run: + if "__main__.py" in sys.modules['__main__'].__file__: + args = [python, '-m', "dotviewer.graphserver", '--stdio'] + else: + args = [python, GRAPHSERVER, '--stdio'] p = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE) child_in, child_out = p.stdin, p.stdout diff -Nru pypy-7.3.5+dfsg/dotviewer/graphdisplay.py pypy-7.3.6+dfsg/dotviewer/graphdisplay.py --- pypy-7.3.5+dfsg/dotviewer/graphdisplay.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/graphdisplay.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,11 +1,12 @@ -from __future__ import generators +from __future__ import print_function, absolute_import import os, time, sys +os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" import pygame from pygame.locals import * -from drawgraph import GraphRenderer, FIXEDFONT -from drawgraph import Node, Edge -from drawgraph import EventQueue, wait_for_events -from strunicode import forceunicode, forcestr +from dotviewer.drawgraph import GraphRenderer, FIXEDFONT +from dotviewer.drawgraph import Node, Edge +from dotviewer.drawgraph import EventQueue, wait_for_events +from dotviewer.strunicode import forceunicode, forcestr, unicode METAKEYS = dict([ @@ -26,6 +27,7 @@ for ident in dir(pygame.locals) if ident.startswith('K_') ]) + KEYS['plus'] = ('=', '+', '.') KEYS['quit'] = ('q', 'escape') KEYS['help'] = ('h', '?', 'f1') @@ -46,7 +48,8 @@ class Display(object): - def __init__(self, (w,h)=(800,680)): + def __init__(self, size=(800,680)): + w, h = size # initialize the modules by hand, to avoid initializing too much # (e.g. the sound system) pygame.display.init() @@ -57,7 +60,8 @@ pygame.font.init() self.resize((w,h)) - def resize(self, (w,h)): + def resize(self, size): + w, h = size self.width = w self.height = h self.screen = pygame.display.set_mode((w, h), HWSURFACE|RESIZABLE, 32) @@ -65,7 +69,7 @@ class GraphDisplay(Display): STATUSBARFONT = FIXEDFONT ANIM_STEP = 0.03 - KEY_REPEAT = (500, 30) + KEY_REPEAT = (500, 50) STATUSBAR_ALPHA = 0.75 STATUSBAR_FGCOLOR = (255, 255, 80) STATUSBAR_BGCOLOR = (128, 0, 0) @@ -171,16 +175,14 @@ mask = 0 - for strnames, methodname in self.KEYS.iteritems(): + for strnames, methodname in self.KEYS.items(): names = strnames.split() - if not isinstance(methodname, basestring): + if not isinstance(methodname, (bytes, unicode)): methodname, args = methodname[0], methodname[1:] else: args = () method = getattr(self, methodname, None) if method is None: - print 'Can not implement key mapping %r, %s.%s does not exist' % ( - strnames, self.__class__.__name__, methodname) continue mods = [] @@ -196,7 +198,7 @@ else: val = GET_KEY(name) assert len(keys) == 0 - if not isinstance(val, (int, basestring)): + if not isinstance(val, (int, bytes, unicode)): keys.extend([GET_KEY(k) for k in val]) else: keys.append(val) @@ -295,7 +297,7 @@ if e.key == K_ESCAPE: return None elif e.key == K_RETURN: - return forcestr(text) # return encoded unicode + return forceunicode(text) # return encoded unicode elif e.key == K_BACKSPACE: text = text[:-1] elif e.unicode and ord(e.unicode) >= ord(' '): @@ -317,6 +319,7 @@ if not searchstr: return self.searchstr = searchstr + self.viewer.highlightwords[searchstr] = searchstr self.searchpos = -1 self.searchresults = list(self.viewer.findall(self.searchstr)) self.find_next() @@ -390,11 +393,13 @@ def reoffset(self): self.viewer.reoffset(self.width, self.height) - def pan(self, (x, y)): + def pan(self, p): + x, y = p self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8)) self.updated_viewer() - def fast_pan(self, (x, y)): + def fast_pan(self, p): + x, y = p self.pan((x * 4, y * 4)) def update_status_bar(self): @@ -591,7 +596,7 @@ method = self.method_cache.get(event.type, KeyError) if method is KeyError: method = getattr(self, 'process_%s' % (pygame.event.event_name(event.type),), None) - self.method_cache[method] = method + self.method_cache[event.type] = method if method is not None: method(event) @@ -722,7 +727,7 @@ return label and label.replace('\\l', '\n').splitlines()[0] -def renderline(text, font, fgcolor, width, maxheight=sys.maxint, +def renderline(text, font, fgcolor, width, maxheight=sys.maxsize, overflowcolor=None): """Render a single line of text into a list of images. @@ -757,7 +762,7 @@ return lines -def rendertext(text, font, fgcolor, width, maxheight=sys.maxint, +def rendertext(text, font, fgcolor, width, maxheight=sys.maxsize, overflowcolor=None): """Render a multiline string into a list of images. diff -Nru pypy-7.3.5+dfsg/dotviewer/graphpage.py pypy-7.3.6+dfsg/dotviewer/graphpage.py --- pypy-7.3.5+dfsg/dotviewer/graphpage.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/graphpage.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,3 +1,4 @@ +from __future__ import absolute_import class GraphPage(object): """Base class for the client-side content of one of the 'pages' @@ -27,25 +28,26 @@ def display(self): "Display a graph page." - import graphclient, msgstruct + from dotviewer import graphclient, msgstruct try: graphclient.display_page(self, save_tmp_file=self.save_tmp_file) - except msgstruct.RemoteError, e: + except msgstruct.RemoteError as e: import sys print >> sys.stderr, "Exception in the graph viewer:", str(e) def display_background(self): "Display a graph page in a background thread." try: - import thread - thread.start_new_thread(self.display, ()) + import threading + t = threading.Thread(target=self.display) + t.start() except ImportError: self.display() class DotFileGraphPage(GraphPage): def compute(self, dotfile): import codecs - from strunicode import RAW_ENCODING + from dotviewer.strunicode import RAW_ENCODING f = codecs.open(dotfile, 'r', RAW_ENCODING) self.source = f.read() f.close() diff -Nru pypy-7.3.5+dfsg/dotviewer/graphparse.py pypy-7.3.6+dfsg/dotviewer/graphparse.py --- pypy-7.3.5+dfsg/dotviewer/graphparse.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/graphparse.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,15 +1,18 @@ """ Graph file parsing. """ +from __future__ import print_function, absolute_import import sys, re import subprocess -import msgstruct +from dotviewer import msgstruct -re_nonword = re.compile(r'([^0-9a-zA-Z_.]+)') -re_plain = re.compile(r'graph [-0-9.]+ [-0-9.]+ [-0-9.]+$', re.MULTILINE) -re_digraph = re.compile(r'\b(graph|digraph)\b', re.IGNORECASE) +from dotviewer.strunicode import forcestr, forceunicode + +re_nonword = re.compile(forcestr(r'([^0-9a-zA-Z_.]+)')) +re_plain = re.compile(forcestr(r'graph [-0-9.]+ [-0-9.]+ [-0-9.]+$'), re.MULTILINE) +re_digraph = re.compile(forcestr(r'\b(graph|digraph)\b'), re.IGNORECASE) def guess_type(content): # try to see whether it is a directed graph or not, @@ -23,17 +26,17 @@ for match in re_digraph.finditer(content): position = match.start() if bracepos is None: - bracepos = content.find('{', position) + bracepos = content.find(b'{', position) if bracepos < 0: break elif position > bracepos: break lastfound = match.group() - if lastfound.lower() == 'digraph': + if lastfound.lower() == b'digraph': return 'dot' - if lastfound.lower() == 'graph': + if lastfound.lower() == b'graph': return 'neato' - print >> sys.stderr, "Warning: could not guess file type, using 'dot'" + print("Warning: could not guess file type, using 'dot'", file=sys.stderr) return 'unknown' def dot2plain_graphviz(content, contenttype, use_codespeak=False): @@ -47,11 +50,12 @@ stdin=subprocess.PIPE, stdout=subprocess.PIPE) (child_in, child_out) = (p.stdin, p.stdout) try: - import thread + import threading except ImportError: bkgndwrite(child_in, content) else: - thread.start_new_thread(bkgndwrite, (child_in, content)) + t = threading.Thread(target=bkgndwrite, args=(child_in, content)) + t.start() plaincontent = child_out.read() child_out.close() if not plaincontent: # 'dot' is likely not installed @@ -65,41 +69,41 @@ class PlainParseError(Exception): pass -def splitline(line, re_word = re.compile(r'[^\s"]\S*|["]["]|["].*?[^\\]["]')): +def splitline(line, re_word = re.compile(forcestr(r'[^\s"]\S*|["]["]|["].*?[^\\]["]'))): import ast result = [] for word in re_word.findall(line): - if word.startswith('"'): - word = ast.literal_eval(word) + if word.startswith(b'"'): + word = ast.literal_eval(forceunicode(word)) result.append(word) return result def parse_plain(graph_id, plaincontent, links={}, fixedfont=False): - plaincontent = plaincontent.replace('\r\n', '\n') # fix Windows EOL + plaincontent = plaincontent.replace(b'\r\n', b'\n') # fix Windows EOL lines = plaincontent.splitlines(True) for i in range(len(lines)-2, -1, -1): - if lines[i].endswith('\\\n'): # line ending in '\' + if lines[i].endswith(b'\\\n'): # line ending in '\' lines[i] = lines[i][:-2] + lines[i+1] del lines[i+1] header = splitline(lines.pop(0)) - if header[0] != 'graph': + if header[0] != b'graph': raise PlainParseError("should start with 'graph'") yield (msgstruct.CMSG_START_GRAPH, graph_id) + tuple(header[1:]) texts = [] for line in lines: line = splitline(line) - if line[0] == 'node': + if line[0] == B'node': if len(line) != 11: raise PlainParseError("bad 'node'") yield (msgstruct.CMSG_ADD_NODE,) + tuple(line[1:]) texts.append(line[6]) - if line[0] == 'edge': + if line[0] == b'edge': yield (msgstruct.CMSG_ADD_EDGE,) + tuple(line[1:]) i = 4 + 2 * int(line[3]) if len(line) > i + 2: texts.append(line[i]) - if line[0] == 'stop': + if line[0] == b'stop': break if links: @@ -133,6 +137,6 @@ else: try: plaincontent = dot2plain_graphviz(content, contenttype) - except PlainParseError, e: + except PlainParseError as e: raise return list(parse_plain(graph_id, plaincontent, links, fixedfont)) diff -Nru pypy-7.3.5+dfsg/dotviewer/graphserver.py pypy-7.3.6+dfsg/dotviewer/graphserver.py --- pypy-7.3.5+dfsg/dotviewer/graphserver.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/graphserver.py 2021-10-17 16:14:51.000000000 +0000 @@ -4,10 +4,25 @@ From the command-line it's easier to use sshgraphserver.py instead of this. """ -import sys -import msgstruct -from cStringIO import StringIO +from __future__ import print_function, absolute_import +import os, sys + +PARENTDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# make dotviewer importable +sys.path.insert(0, PARENTDIR) + +from dotviewer import msgstruct +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + +try: + import thread +except ImportError: + import _thread as thread class Server(object): @@ -25,7 +40,6 @@ self.process_next_message() # start a background thread to process further messages if not only_one_graph: - import thread thread.start_new_thread(self.process_all_messages, ()) # give control to pygame self.display.run1() @@ -35,7 +49,7 @@ while True: self.process_next_message() except EOFError: - from drawgraph import display_async_quit + from dotviewer.drawgraph import display_async_quit display_async_quit() def process_next_message(self): @@ -47,20 +61,20 @@ self.log("unknown message code %r" % (msg[0],)) def log(self, info): - print >> sys.stderr, info + print(info, file=sys.stderr) def setlayout(self, layout): if self.display is None: # make the initial display - from graphdisplay import GraphDisplay + from dotviewer.graphdisplay import GraphDisplay self.display = GraphDisplay(layout) else: # send an async command to the display running the main thread - from drawgraph import display_async_cmd + from dotviewer.drawgraph import display_async_cmd display_async_cmd(layout=layout) def cmsg_start_graph(self, graph_id, scale, width, height, *rest): - from drawgraph import GraphLayout + from dotviewer.drawgraph import GraphLayout self.newlayout = GraphLayout(float(scale), float(width), float(height)) def request_reload(): @@ -123,10 +137,10 @@ s1 = socket.socket() s1.bind(local_address) s1.listen(5) - print 'listening on %r...' % (s1.getsockname(),) + print('listening on %r...' % (s1.getsockname(),)) while True: conn, addr = s1.accept() - print 'accepted connection from %r' % (addr,) + print('accepted connection from %r' % (addr,)) sock_io = msgstruct.SocketIO(conn) handler_io = graphclient.spawn_local_handler() thread.start_new_thread(copy_all, (sock_io, handler_io)) @@ -148,15 +162,16 @@ import sshgraphserver sshgraphserver.ssh_graph_server(['LOCAL']) sys.exit(0) - print >> sys.stderr, __doc__ + print(__doc__, file=sys.stderr) sys.exit(2) if sys.argv[1] == '--stdio': # a one-shot server running on stdin/stdout - io = msgstruct.FileIO(sys.stdin, sys.stdout) + io = msgstruct.FileIO(getattr(sys.stdin, 'buffer', sys.stdin), + getattr(sys.stdout, 'buffer', sys.stdout)) srv = Server(io) try: srv.run() - except Exception, e: + except Exception as e: import traceback f = StringIO() traceback.print_exc(file=f) @@ -164,15 +179,16 @@ help = (" | if you want to debug on a remote machine, see\n" " | instructions in dotviewer/sshgraphserver.py\n") try: + os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" import pygame if isinstance(e, pygame.error): - print >> f, help - except Exception, e: + print(help, file=f) + except Exception as e: f.seek(0) f.truncate() - print >> f, "%s: %s" % (e.__class__.__name__, e) - print >> f, " | Pygame is not installed; either install it, or" - print >> f, help + print("%s: %s" % (e.__class__.__name__, e), file=f) + print(" | Pygame is not installed; either install it, or", file=f) + print(help, file=f) io.sendmsg(msgstruct.MSG_ERROR, f.getvalue()) else: listen_server(sys.argv[1]) diff -Nru pypy-7.3.5+dfsg/dotviewer/__main__.py pypy-7.3.6+dfsg/dotviewer/__main__.py --- pypy-7.3.5+dfsg/dotviewer/__main__.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/__main__.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,16 @@ +# alternative entry point when packaged +from __future__ import absolute_import + +import argparse + +from dotviewer import graphclient + +parser = argparse.ArgumentParser(description='Show a graphviz file') +parser.add_argument('filename', metavar='FILE', + help='a .dot file or a .plain file to show') + +if __name__ == '__main__': + args = parser.parse_args() + graphclient.display_dot_file(args.filename) + + diff -Nru pypy-7.3.5+dfsg/dotviewer/msgstruct.py pypy-7.3.6+dfsg/dotviewer/msgstruct.py --- pypy-7.3.5+dfsg/dotviewer/msgstruct.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/msgstruct.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,23 +1,24 @@ +from __future__ import absolute_import import sys, os from struct import pack, unpack, calcsize -from strunicode import tryencode +from dotviewer.strunicode import tryencode, ord_byte_index MAGIC = -0x3b83728b -CMSG_INIT = 'i' -CMSG_START_GRAPH = '[' -CMSG_ADD_NODE = 'n' -CMSG_ADD_EDGE = 'e' -CMSG_ADD_LINK = 'l' -CMSG_FIXED_FONT = 'f' -CMSG_STOP_GRAPH = ']' -CMSG_MISSING_LINK= 'm' -CMSG_SAY = 's' - -MSG_OK = 'O' -MSG_ERROR = 'E' -MSG_RELOAD = 'R' -MSG_FOLLOW_LINK = 'L' +CMSG_INIT = b'i' +CMSG_START_GRAPH = b'[' +CMSG_ADD_NODE = b'n' +CMSG_ADD_EDGE = b'e' +CMSG_ADD_LINK = b'l' +CMSG_FIXED_FONT = b'f' +CMSG_STOP_GRAPH = b']' +CMSG_MISSING_LINK= b'm' +CMSG_SAY = b's' + +MSG_OK = b'O' +MSG_ERROR = b'E' +MSG_RELOAD = b'R' +MSG_FOLLOW_LINK = b'L' # ____________________________________________________________ @@ -27,20 +28,20 @@ def message(tp, *values): #print >> sys.stderr, tp, values - typecodes = [''] - values = map(tryencode, values) + typecodes = [b''] + values = list(map(tryencode, values)) for v in values: - if type(v) is str: - typecodes.append('%ds' % len(v)) + if type(v) is bytes: + typecodes.append(b'%ds' % len(v)) elif 0 <= v < 256: - typecodes.append('B') + typecodes.append(b'B') elif long_min <= v <= long_max: - typecodes.append('l') + typecodes.append(b'l') else: - typecodes.append('q') - typecodes = ''.join(typecodes) + typecodes.append(b'q') + typecodes = b''.join(typecodes) if len(typecodes) < 256: - return pack(("!B%dsc" % len(typecodes)) + typecodes, + return pack((b"!B%dsc" % len(typecodes)) + typecodes, len(typecodes), typecodes, tp, *values) else: # too many values - encapsulate the message in another one @@ -48,14 +49,14 @@ def decodemessage(data): if data: - limit = ord(data[0]) + 1 + limit = ord_byte_index(data, 0) + 1 if len(data) >= limit: - typecodes = "!c" + data[1:limit] + typecodes = b"!c" + data[1:limit] end = limit + calcsize(typecodes) if len(data) >= end: msg = unpack(typecodes, data[limit:end]) - if msg[0] == '\x00': - msg = unpack("!c" + msg[1], msg[2]) + if msg[0] == b'\x00': + msg = unpack(b"!c" + msg[1], msg[2]) return msg, data[end:] #elif end > 1000000: # raise OverflowError @@ -68,7 +69,7 @@ class IO(object): - _buffer = '' + _buffer = b'' def sendmsg(self, tp, *values): self.sendall(message(tp, *values)) diff -Nru pypy-7.3.5+dfsg/dotviewer/sshgraphserver.py pypy-7.3.6+dfsg/dotviewer/sshgraphserver.py --- pypy-7.3.5+dfsg/dotviewer/sshgraphserver.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/sshgraphserver.py 2021-10-17 16:14:51.000000000 +0000 @@ -14,7 +14,19 @@ If 'hostname' is the string 'LOCAL', then it starts locally without ssh. """ -import graphserver, socket, subprocess, random +from __future__ import print_function, absolute_import + +import os, sys + +PARENTDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# make dotviewer importable +sys.path.insert(0, PARENTDIR) + +from dotviewer import graphserver +from dotviewer.strunicode import forcestr + +import socket, subprocess, random def ssh_graph_server(sshargs): @@ -33,11 +45,11 @@ remoteport = localport args = ['python', '-u', '-c', 'exec input()'] - print ' '.join(args) + print(' '.join(args)) p = subprocess.Popen(args, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - p.stdin.write(repr('port=%d\n%s' % (remoteport, REMOTE_SOURCE)) + '\n') + p.stdin.write(forcestr(repr('port=%d\n%s' % (remoteport, REMOTE_SOURCE)) + '\n')) line = p.stdout.readline() assert line == 'OK\n' @@ -56,7 +68,7 @@ except OSError: pass f = open(fn, 'w') - print >> f, port + f.write("%s\n" % port) f.close() try: sys.stdout.write('OK\n') @@ -76,6 +88,6 @@ if __name__ == '__main__': import sys if len(sys.argv) <= 1: - print __doc__ + print(__doc__) sys.exit(2) ssh_graph_server(sys.argv[1:]) diff -Nru pypy-7.3.5+dfsg/dotviewer/strunicode.py pypy-7.3.6+dfsg/dotviewer/strunicode.py --- pypy-7.3.5+dfsg/dotviewer/strunicode.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/strunicode.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,6 +1,14 @@ RAW_ENCODING = "utf-8" ENCODING_ERROR_HANDLING = "replace" +try: + unicode = unicode + def ord_byte_index(b, index): + return ord(b[index]) +except NameError: + unicode = str + def ord_byte_index(b, index): + return b[index] def forceunicode(name): """ returns `name` as unicode, even if it wasn't before """ @@ -9,7 +17,7 @@ def forcestr(name): """ returns `name` as string, even if it wasn't before """ - return name if isinstance(name, str) else name.encode(RAW_ENCODING, ENCODING_ERROR_HANDLING) + return name if isinstance(name, bytes) else name.encode(RAW_ENCODING, ENCODING_ERROR_HANDLING) def tryencode(name): diff -Nru pypy-7.3.5+dfsg/dotviewer/test/test_record.py pypy-7.3.6+dfsg/dotviewer/test/test_record.py --- pypy-7.3.5+dfsg/dotviewer/test/test_record.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/dotviewer/test/test_record.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,36 @@ +import py +from dotviewer.drawgraph import TextSnippetRecordLR, record_to_nested_lists +from dotviewer.conftest import option + +def test_split_record(): + s = "a|{b|c|d|e}|{f|{g|h}|{i|j}|k|l}" + l = record_to_nested_lists(s) + assert l == ['a', ['b', 'c', 'd', 'e'], ['f', ['g', 'h'], ['i', 'j'], 'k', 'l']] + s = "{An Mrecord|has rounded|corners}" + l = record_to_nested_lists(s) + s = "a|b|c" + l = record_to_nested_lists(s) + assert l == s.split("|") + +def test_split_record_escape(): + s = '|{(\\{process1\\}->(0->1->\\{process3\\}))\n|# states: 1}|' + l = record_to_nested_lists(s) + assert l == ['', ['({process1}->(0->1->{process3}))', '# states: 1'], ''] + +def test_html_entity(): + s = '(∅↦1↦∅)' + l = record_to_nested_lists(s) + assert l == [u'(\u2205\u21a61\u21a6\u2205)'] + +def test_ignore_angular(): + s = "a|{b|c|d|e}|{f|{g|h}|{i|j}|k|l}" + l = record_to_nested_lists(s) + assert l == ['a', ['b', 'c', 'd', 'e'], ['f', ['g', 'h'], ['i', 'j'], 'k', 'l']] + +def test_show(): + if not option.pygame: + py.test.skip("--pygame not enabled") + from dotviewer.drawgraph import GraphLayout + layout = GraphLayout(1, 2.0972, 0.97222) + layout.add_node('rec', 1.0486, 0.48611, 2.0972, 0.97222, "{a|b|c}|d|e|f|{{g|h}|i}", 'solid', 'record', 'black', 'lightgrey') + layout.display() diff -Nru pypy-7.3.5+dfsg/extra_tests/cffi_tests/cffi0/test_function.py pypy-7.3.6+dfsg/extra_tests/cffi_tests/cffi0/test_function.py --- pypy-7.3.5+dfsg/extra_tests/cffi_tests/cffi0/test_function.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/cffi_tests/cffi0/test_function.py 2021-10-17 16:14:51.000000000 +0000 @@ -6,7 +6,7 @@ import ctypes.util from cffi.backend_ctypes import CTypesBackend from extra_tests.cffi_tests.udir import udir -from extra_tests.cffi_tests.support import FdWriteCapture +from extra_tests.cffi_tests.support import FdWriteCapture, StdErrCapture from .backend_tests import needs_dlopen_none try: @@ -228,13 +228,9 @@ def cb(): return returnvalue fptr = ffi.callback("void(*)(void)", cb) - old_stderr = sys.stderr - try: - sys.stderr = StringIO() + with StdErrCapture() as f: returned = fptr() - printed = sys.stderr.getvalue() - finally: - sys.stderr = old_stderr + printed = f.getvalue() assert returned is None if returnvalue is None: assert printed == '' diff -Nru pypy-7.3.5+dfsg/extra_tests/cffi_tests/cffi1/test_recompiler.py pypy-7.3.6+dfsg/extra_tests/cffi_tests/cffi1/test_recompiler.py --- pypy-7.3.5+dfsg/extra_tests/cffi_tests/cffi1/test_recompiler.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/cffi_tests/cffi1/test_recompiler.py 2021-10-17 16:14:51.000000000 +0000 @@ -1670,9 +1670,10 @@ with StdErrCapture() as f: res = lib.bar(321) assert res is None - assert f.getvalue() == ( - "From cffi callback %r:\n" % (bar,) + - "Trying to convert the result back to C:\n" + msg = f.getvalue() + assert "rom cffi callback %r" % (bar,) in msg + assert "rying to convert the result back to C:\n" in msg + assert msg.endswith( "TypeError: callback with the return type 'void' must return None\n") def test_extern_python_redefine(): diff -Nru pypy-7.3.5+dfsg/extra_tests/cffi_tests/support.py pypy-7.3.6+dfsg/extra_tests/cffi_tests/support.py --- pypy-7.3.5+dfsg/extra_tests/cffi_tests/support.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/cffi_tests/support.py 2021-10-17 16:14:51.000000000 +0000 @@ -34,9 +34,14 @@ from io import StringIO self.old_stderr = sys.stderr sys.stderr = f = StringIO() + if hasattr(sys, '__unraisablehook__'): # work around pytest + self.old_unraisablebook = sys.unraisablehook # on recent CPythons + sys.unraisablehook = sys.__unraisablehook__ return f def __exit__(self, *args): sys.stderr = self.old_stderr + if hasattr(self, 'old_unraisablebook'): + sys.unraisablehook = self.old_unraisablebook class FdWriteCapture(object): diff -Nru pypy-7.3.5+dfsg/extra_tests/cffi_tests/test_c.py pypy-7.3.6+dfsg/extra_tests/cffi_tests/test_c.py --- pypy-7.3.5+dfsg/extra_tests/cffi_tests/test_c.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/cffi_tests/test_c.py 2021-10-17 16:14:51.000000000 +0000 @@ -17,7 +17,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.14.5", ("This test_c.py file is for testing a version" +assert __version__ == "1.14.6", ("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,): @@ -1366,6 +1366,8 @@ try: linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests sys.stderr = cStringIO.StringIO() + if hasattr(sys, '__unraisablehook__'): # work around pytest + sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons assert f(100) == 300 assert sys.stderr.getvalue() == '' assert f(10000) == -42 @@ -1452,6 +1454,8 @@ sys.stderr = cStringIO.StringIO() seen = "not a list" # this makes the oops() function crash assert ff(bigvalue) == -42 + # the $ after the AttributeError message are for the suggestions that + # will be added in Python 3.10 assert matches(sys.stderr.getvalue(), """\ From cffi callback : Trying to convert the result back to C: @@ -1462,7 +1466,7 @@ Traceback (most recent call last): File "$", line $, in oops $ -AttributeError: 'str' object has no attribute 'append' +AttributeError: 'str' object has no attribute 'append$ """, """\ Exception ignored from cffi callback , trying to convert the result back to C: Traceback (most recent call last): @@ -1473,7 +1477,7 @@ Traceback (most recent call last): File "$", line $, in oops $ -AttributeError: 'str' object has no attribute 'append' +AttributeError: 'str' object has no attribute 'append$ """) finally: sys.stderr = orig_stderr diff -Nru pypy-7.3.5+dfsg/extra_tests/test_greenlet_thread.py pypy-7.3.6+dfsg/extra_tests/test_greenlet_thread.py --- pypy-7.3.5+dfsg/extra_tests/test_greenlet_thread.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/test_greenlet_thread.py 2021-10-17 16:14:54.000000000 +0000 @@ -0,0 +1,145 @@ +import pytest +import sys, time +if sys.version_info < (3,): + import thread +else: + import _thread as thread +greenlet = pytest.importorskip('greenlet') + + +class TestThread: + + def test_cannot_switch_to_main_of_different_thread(self): + mains = [] + mains.append(greenlet.getcurrent()) + lock = thread.allocate_lock() + lock.acquire() + got_exception = [] + # + def run_thread(): + main = greenlet.getcurrent() + assert main not in mains + mains.append(main) + try: + mains[0].switch() + except Exception as e: + got_exception.append(e) + lock.release() + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + assert isinstance(got_exception[0], greenlet.error) + + def test_nonstarted_greenlet_is_still_attached_to_thread(self): + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g = greenlet.greenlet(lambda *args: None) + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + pytest.raises(greenlet.error, g.switch) + + def test_noninited_greenlet_is_still_attached_to_thread(self): + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g = greenlet.greenlet.__new__(greenlet.greenlet) + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + pytest.raises(greenlet.error, g.switch) + g.__init__(lambda *args: None) + pytest.raises(greenlet.error, g.switch) + + def test_noninited_greenlet_change_thread_via_parent(self): + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g = greenlet.greenlet.__new__(greenlet.greenlet) + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + g.__init__(lambda *args: 44) + g.parent = greenlet.getcurrent() + x = g.switch() + assert x == 44 + + def test_nonstarted_greenlet_change_thread_via_parent(self): + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g = greenlet.greenlet(lambda *args: 42) + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + g.parent = greenlet.getcurrent() + x = g.switch() + assert x == 42 + + def test_started_greenlet_cannot_change_thread_via_parent(self): + pytest.skip("not implemented on PyPy") + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g_parent = greenlet.getcurrent() + g = greenlet.greenlet(lambda *args: g_parent.switch(42)) + x = g.switch() + assert x == 42 + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + with pytest.raises(ValueError) as e: + g.parent = greenlet.getcurrent() + assert str(e.value) == "parent cannot be on a different thread" + + def test_finished_greenlet_cannot_change_thread_via_parent(self): + pytest.skip("not implemented on PyPy") + subs = [] + lock = thread.allocate_lock() + lock.acquire() + # + def run_thread(): + g = greenlet.greenlet(lambda *args: 42) + x = g.switch() + assert x == 42 + subs.append(g) + lock.release() + time.sleep(1) + # + thread.start_new_thread(run_thread, ()) + lock.acquire() + [g] = subs + with pytest.raises(ValueError) as e: + g.parent = greenlet.getcurrent() + assert str(e.value) == "parent cannot be on a different thread" diff -Nru pypy-7.3.5+dfsg/extra_tests/test_greenlet_tracing.py pypy-7.3.6+dfsg/extra_tests/test_greenlet_tracing.py --- pypy-7.3.5+dfsg/extra_tests/test_greenlet_tracing.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/test_greenlet_tracing.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,51 @@ +import pytest +greenlet = pytest.importorskip('greenlet') + + +class SomeError(Exception): + pass + +class TestTracing: + def test_greenlet_tracing(self): + main = greenlet.getcurrent() + actions = [] + def trace(*args): + actions.append(args) + def dummy(): + pass + def dummyexc(): + raise SomeError() + oldtrace = greenlet.settrace(trace) + try: + g1 = greenlet.greenlet(dummy) + g1.switch() + g2 = greenlet.greenlet(dummyexc) + pytest.raises(SomeError, g2.switch) + finally: + greenlet.settrace(oldtrace) + assert actions == [ + ('switch', (main, g1)), + ('switch', (g1, main)), + ('switch', (main, g2)), + ('throw', (g2, main)), + ] + + def test_exception_disables_tracing(self): + main = greenlet.getcurrent() + actions = [] + def trace(*args): + actions.append(args) + raise SomeError() + def dummy(): + main.switch() + g = greenlet.greenlet(dummy) + g.switch() + oldtrace = greenlet.settrace(trace) + try: + pytest.raises(SomeError, g.switch) + assert greenlet.gettrace() is None + finally: + greenlet.settrace(oldtrace) + assert actions == [ + ('switch', (main, g)), + ] diff -Nru pypy-7.3.5+dfsg/extra_tests/test_pypy_util_cffi.py pypy-7.3.6+dfsg/extra_tests/test_pypy_util_cffi.py --- pypy-7.3.5+dfsg/extra_tests/test_pypy_util_cffi.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/test_pypy_util_cffi.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,12 @@ +import pytest +_pypy_util_cffi = pytest.importorskip('_pypy_util_cffi') +StackNew = _pypy_util_cffi.StackNew + +def test_one(): + with StackNew("char[]", 1) as p: + p[0] = b'\x13' + assert p[0] == b'\x13' + + # assert did not crash + with StackNew("char*") as p: + pass diff -Nru pypy-7.3.5+dfsg/extra_tests/test_sqlite3.py pypy-7.3.6+dfsg/extra_tests/test_sqlite3.py --- pypy-7.3.5+dfsg/extra_tests/test_sqlite3.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/extra_tests/test_sqlite3.py 2021-10-17 16:14:51.000000000 +0000 @@ -322,3 +322,11 @@ gc.collect() gc.collect() assert SQLiteBackend.success + +def test_empty_statement(): + r = _sqlite3.connect(":memory:") + cur = r.cursor() + for sql in ["", " ", "/*comment*/"]: + r = cur.execute(sql) + assert r.description is None + assert cur.fetchall() == [] diff -Nru pypy-7.3.5+dfsg/lib_pypy/_audioop_build.py pypy-7.3.6+dfsg/lib_pypy/_audioop_build.py --- pypy-7.3.5+dfsg/lib_pypy/_audioop_build.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_audioop_build.py 2021-10-17 16:14:51.000000000 +0000 @@ -338,6 +338,7 @@ return a; } +static int ratecv(char* rv, char* cp, size_t len, int size, int nchannels, int inrate, int outrate, int* state_d, int* prev_i, int* cur_i, @@ -400,6 +401,7 @@ } } +static void tostereo(char* rv, char* cp, size_t len, int size, double fac1, double fac2) { @@ -432,6 +434,7 @@ } } +static void add(char* rv, char* cp1, char* cp2, size_t len1, int size) { int i; @@ -470,6 +473,7 @@ } } +static void lin2adcpm(unsigned char* ncp, unsigned char* cp, size_t len, size_t size, int* state) { @@ -555,6 +559,7 @@ } +static void adcpm2lin(unsigned char* ncp, unsigned char* cp, size_t len, size_t size, int* state) { diff -Nru pypy-7.3.5+dfsg/lib_pypy/cffi/_cffi_errors.h pypy-7.3.6+dfsg/lib_pypy/cffi/_cffi_errors.h --- pypy-7.3.5+dfsg/lib_pypy/cffi/_cffi_errors.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/cffi/_cffi_errors.h 2021-10-17 16:14:51.000000000 +0000 @@ -54,6 +54,8 @@ " of.write(x)\n" " except: pass\n" " self.buf += x\n" + " def flush(self):\n" + " pass\n" "fl = FileLike()\n" "fl.buf = ''\n" "of = sys.stderr\n" diff -Nru pypy-7.3.5+dfsg/lib_pypy/cffi/_embedding.h pypy-7.3.6+dfsg/lib_pypy/cffi/_embedding.h --- pypy-7.3.5+dfsg/lib_pypy/cffi/_embedding.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/cffi/_embedding.h 2021-10-17 16:14:51.000000000 +0000 @@ -224,7 +224,7 @@ if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.14.5" + "\ncompiled with cffi version: 1.14.6" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff -Nru pypy-7.3.5+dfsg/lib_pypy/cffi/__init__.py pypy-7.3.6+dfsg/lib_pypy/cffi/__init__.py --- pypy-7.3.5+dfsg/lib_pypy/cffi/__init__.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/cffi/__init__.py 2021-10-17 16:14:51.000000000 +0000 @@ -5,8 +5,8 @@ from .error import CDefError, FFIError, VerificationError, VerificationMissing from .error import PkgConfigError -__version__ = "1.14.5" -__version_info__ = (1, 14, 5) +__version__ = "1.14.6" +__version_info__ = (1, 14, 6) # 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 -Nru pypy-7.3.5+dfsg/lib_pypy/cffi.egg-info/PKG-INFO pypy-7.3.6+dfsg/lib_pypy/cffi.egg-info/PKG-INFO --- pypy-7.3.5+dfsg/lib_pypy/cffi.egg-info/PKG-INFO 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/cffi.egg-info/PKG-INFO 2021-10-17 16:14:51.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.14.5 +Version: 1.14.6 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff -Nru pypy-7.3.5+dfsg/lib_pypy/_cffi_ssl/_stdssl/__init__.py pypy-7.3.6+dfsg/lib_pypy/_cffi_ssl/_stdssl/__init__.py --- pypy-7.3.5+dfsg/lib_pypy/_cffi_ssl/_stdssl/__init__.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_cffi_ssl/_stdssl/__init__.py 2021-10-17 16:14:51.000000000 +0000 @@ -30,6 +30,7 @@ SSL_ERROR_EOF, SSL_ERROR_NO_SOCKET, SSL_ERROR_INVALID_ERROR_CODE, pyerr_write_unraisable) from _cffi_ssl._stdssl import error +from _pypy_util_cffi import StackNew from select import select import socket @@ -417,7 +418,6 @@ return _decode_certificate(self.peer_cert) def write(self, bytestring): - deadline = 0 b = _str_to_ffi_buffer(bytestring) sock = self.get_socket_or_connection_gone() ssl = self.ssl @@ -467,26 +467,70 @@ raise pyssl_error(self, length) def read(self, length, buffer_into=None): - ssl = self.ssl - if length < 0 and buffer_into is None: raise ValueError("size should not be negative") + if buffer_into is None: + return self._read_no_buf(length) + return self._read_buf(length, buffer_into) + + def _read_no_buf(self, length): + ssl = self.ssl sock = self.get_socket_or_connection_gone() - if buffer_into is None: - dest = ffi.new("char[]", length) - if length == 0: - return b"" + if length == 0: + return b"" + with StackNew("char[]", length) as dest: mem = dest - else: - mem = ffi.from_buffer(buffer_into) - if length <= 0 or length > len(buffer_into): - length = len(buffer_into) - if length > _MAX_INT: - raise OverflowError("maximum length can't fit in a C 'int'") - if len(buffer_into) == 0: - return 0 + + if sock: + timeout = _socket_timeout(sock) + nonblocking = timeout >= 0 + lib.BIO_set_nbio(lib.SSL_get_rbio(ssl), nonblocking) + lib.BIO_set_nbio(lib.SSL_get_wbio(ssl), nonblocking) + + timeout = _socket_timeout(sock) + shutdown = False + while True: + count = lib.SSL_read(self.ssl, mem, length); + err = lib.SSL_get_error(self.ssl, count); + + check_signals() + + if err == SSL_ERROR_WANT_READ: + sockstate = _ssl_select(sock, 0, timeout) + elif err == SSL_ERROR_WANT_WRITE: + sockstate = _ssl_select(sock, 1, timeout) + elif err == SSL_ERROR_ZERO_RETURN and \ + lib.SSL_get_shutdown(self.ssl) == lib.SSL_RECEIVED_SHUTDOWN: + shutdown = True + break; + else: + sockstate = SOCKET_OPERATION_OK + + if sockstate == SOCKET_HAS_TIMED_OUT: + raise socket.timeout("The read operation timed out") + elif sockstate == SOCKET_IS_NONBLOCKING: + break + if not (err == SSL_ERROR_WANT_READ or err == SSL_ERROR_WANT_WRITE): + break + + if count <= 0 and not shutdown: + raise pyssl_error(self, count) + + return _bytes_with_len(dest, count) + + def _read_buf(self, length, buffer_into): + ssl = self.ssl + sock = self.get_socket_or_connection_gone() + + mem = ffi.from_buffer(buffer_into) + if length <= 0 or length > len(buffer_into): + length = len(buffer_into) + if length > _MAX_INT: + raise OverflowError("maximum length can't fit in a C 'int'") + if len(buffer_into) == 0: + return 0 if sock: timeout = _socket_timeout(sock) @@ -494,7 +538,6 @@ lib.BIO_set_nbio(lib.SSL_get_rbio(ssl), nonblocking) lib.BIO_set_nbio(lib.SSL_get_wbio(ssl), nonblocking) - deadline = 0 timeout = _socket_timeout(sock) shutdown = False while True: @@ -524,9 +567,6 @@ if count <= 0 and not shutdown: raise pyssl_error(self, count) - if not buffer_into: - return _bytes_with_len(dest, count) - return count if HAS_ALPN: diff -Nru pypy-7.3.5+dfsg/lib_pypy/pypy_tools/build_cffi_imports.py pypy-7.3.6+dfsg/lib_pypy/pypy_tools/build_cffi_imports.py --- pypy-7.3.5+dfsg/lib_pypy/pypy_tools/build_cffi_imports.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/pypy_tools/build_cffi_imports.py 2021-10-17 16:14:51.000000000 +0000 @@ -25,6 +25,7 @@ cffi_build_scripts = collections.OrderedDict({ ("_ctypes._ctypes_cffi", "_ctypes/_ctypes_build.py" if sys.platform == 'darwin' else None), + ("_pypy_util_cffi_inner", "_pypy_util_build.py"), # this needs to come before ssl ("_ssl", "_ssl_build.py"), ("sqlite3", "_sqlite3_build.py"), ("audioop", "_audioop_build.py"), diff -Nru pypy-7.3.5+dfsg/lib_pypy/_pypy_util_build.py pypy-7.3.6+dfsg/lib_pypy/_pypy_util_build.py --- pypy-7.3.5+dfsg/lib_pypy/_pypy_util_build.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_pypy_util_build.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,13 @@ + +from cffi import FFI as _FFI + +_ffi = _FFI() + +_ffi.cdef(""" +void* malloc(size_t size); +void free(void *ptr); +""") +_ffi.set_source("_pypy_util_cffi_inner", "") + +if __name__ == '__main__': + _ffi.compile() diff -Nru pypy-7.3.5+dfsg/lib_pypy/_pypy_util_cffi.py pypy-7.3.6+dfsg/lib_pypy/_pypy_util_cffi.py --- pypy-7.3.5+dfsg/lib_pypy/_pypy_util_cffi.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_pypy_util_cffi.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,21 @@ + +from _pypy_util_cffi_inner import ffi, lib + +class StackNew(object): + def __init__(self, tp, size=None): + if size is None: + total_size = ffi.sizeof(tp) + else: + if tp.endswith("[]"): + total_size = ffi.sizeof(tp[:-2] + "[1]") * size + else: + total_size = ffi.sizeof(tp) * size + if tp.endswith("[]"): + tp = tp[:-2] + "*" # XXX dodgu? + self._p = ffi.cast(tp, lib.malloc(total_size)) + + def __enter__(self): + return self._p + + def __exit__(self, tp, val, tb): + lib.free(ffi.cast("void*", self._p)) diff -Nru pypy-7.3.5+dfsg/lib_pypy/_sqlite3.py pypy-7.3.6+dfsg/lib_pypy/_sqlite3.py --- pypy-7.3.5+dfsg/lib_pypy/_sqlite3.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_sqlite3.py 2021-10-17 16:14:51.000000000 +0000 @@ -1032,7 +1032,7 @@ raise ValueError("the query contains a null character") - if sql: + if sql.strip(): first_word = sql.lstrip().split()[0].upper() if first_word == '': self._type = _STMT_TYPE_INVALID @@ -1053,6 +1053,9 @@ if isinstance(sql, unicode): sql = sql.encode('utf-8') + + self._valid = True + statement_star = _ffi.new('sqlite3_stmt **') next_char = _ffi.new('char **') c_sql = _ffi.new("char[]", sql) @@ -1063,10 +1066,11 @@ if ret == _lib.SQLITE_OK and not self._statement: # an empty statement, work around that, as it's the least trouble self._type = _STMT_TYPE_SELECT - c_sql = _ffi.new("char[]", b"select 42") + c_sql = _ffi.new("char[]", b"select 42 where 42 = 23") ret = _lib.sqlite3_prepare_v2(self.__con._db, c_sql, -1, statement_star, next_char) self._statement = statement_star[0] + self._valid = False if ret != _lib.SQLITE_OK: raise self.__con._get_exception(ret) @@ -1188,7 +1192,7 @@ _STMT_TYPE_UPDATE, _STMT_TYPE_DELETE, _STMT_TYPE_REPLACE - ): + ) or not self._valid: return None desc = [] for i in xrange(_lib.sqlite3_column_count(self._statement)): diff -Nru pypy-7.3.5+dfsg/lib_pypy/_structseq.py pypy-7.3.6+dfsg/lib_pypy/_structseq.py --- pypy-7.3.5+dfsg/lib_pypy/_structseq.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib_pypy/_structseq.py 2021-10-17 16:14:51.000000000 +0000 @@ -61,6 +61,7 @@ dict['__reduce__'] = structseq_reduce dict['__setattr__'] = structseq_setattr dict['__repr__'] = structseq_repr + dict['__str__'] = structseq_repr dict['_name'] = dict.get('name', '') return type.__new__(metacls, classname, (tuple,), dict) diff -Nru pypy-7.3.5+dfsg/lib-python/2.7/httplib.py pypy-7.3.6+dfsg/lib-python/2.7/httplib.py --- pypy-7.3.5+dfsg/lib-python/2.7/httplib.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib-python/2.7/httplib.py 2021-10-17 16:14:51.000000000 +0000 @@ -453,11 +453,14 @@ if status != CONTINUE: break # skip the header from the 100 response + header_count = 0 while True: skip = self.fp.readline(_MAXLINE + 1) if len(skip) > _MAXLINE: raise LineTooLong("header line") - skip = skip.strip() + header_count += 1 + if header_count > _MAXHEADERS: + raise HTTPException("got more than %d headers" % _MAXHEADERS) if not skip: break if self.debuglevel > 0: diff -Nru pypy-7.3.5+dfsg/lib-python/2.7/test/test_httplib.py pypy-7.3.6+dfsg/lib-python/2.7/test/test_httplib.py --- pypy-7.3.5+dfsg/lib-python/2.7/test/test_httplib.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/lib-python/2.7/test/test_httplib.py 2021-10-17 16:14:51.000000000 +0000 @@ -675,6 +675,19 @@ resp = httplib.HTTPResponse(FakeSocket(body)) self.assertRaises(httplib.LineTooLong, resp.begin) + def test_overflowing_header_limit_after_100(self): + body = ( + 'HTTP/1.1 100 OK\r\n' + 'r\n' * 32768 + ) + resp = httplib.HTTPResponse(FakeSocket(body)) + with self.assertRaises(httplib.HTTPException) as cm: + resp.begin() + # We must assert more because other reasonable errors that we + # do not want can also be HTTPException derived. + self.assertIn('got more than ', str(cm.exception)) + self.assertIn('headers', str(cm.exception)) + def test_overflowing_chunked_line(self): body = ( 'HTTP/1.1 200 OK\r\n' diff -Nru pypy-7.3.5+dfsg/LICENSE pypy-7.3.6+dfsg/LICENSE --- pypy-7.3.5+dfsg/LICENSE 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/LICENSE 2021-10-17 16:14:51.000000000 +0000 @@ -57,8 +57,8 @@ Christian Tismer Hakan Ardo Benjamin Peterson - Anders Chrigstrom Wim Lavrijsen + Anders Chrigstrom Eric van Riet Paap Dan Villiom Podlaski Christiansen Remi Meier @@ -85,27 +85,29 @@ Guido Wesdorp Lawrence Oluyede Bartosz Skowron - Daniel Roberts Stefano Rivera + Daniel Roberts Adrien Di Mascio Niko Matsakis Alexander Hesse Ludovic Aubry + Batuhan Taskaya stian Jacob Hallen Jason Creighton Mark Young Andrew Lawrence Alex Martelli + Ondrej Baranovič Spenser Bauman Michal Bendowski - Ondrej Baranovič Jan de Mooij Stefan Beyer Tyler Wade Vincent Legoll Michael Foord Stephan Diehl + muke101 Simon Cross Jean-Paul Calderone Stefan Schwarzer @@ -122,7 +124,6 @@ Edd Barrett Marius Gedminas Laurence Tratt - Batuhan Taskaya Alexandre Fayolle Nicolas Truessel Simon Burton @@ -136,10 +137,11 @@ Greg Price Ivan Sichmann Freitas Mark Pearse - Andreas Stührk Tobias Pape + Andreas Stührk Jean-Philippe St. Pierre Stian Andreassen + Yusuke Izawa Guido van Rossum Pavel Vinogradov William Leslie @@ -155,8 +157,8 @@ Joannah Nanjekye Georg Brandl quejebo - muke101 - Bert Freudenberg + Vanessa Freudenberg + Michał Górny Gerald Klix Wanja Saatkamp Mike Blume @@ -164,7 +166,6 @@ Rami Chowdhury Stefan H. Muller Dodan Mihai - Michał Górny Tim Felgentreff Eugene Oden Colin Valliant @@ -199,6 +200,7 @@ Lucian Branescu Mihaila anatoly techtonik Mariano Anaya + olliemath Olivier Dormond Jared Grubb Karl Bartel @@ -225,6 +227,7 @@ Berkin Ilbeyi Mihnea Saracin Matt Jackson + Ricky Zhou Jonathan David Riehl Anders Qvist Beatrice During @@ -234,7 +237,6 @@ Faye Zhao Pauli Virtanen Mike Pavone - Ricky Zhou Alan McIntyre Alexander Sedov Alex Perry @@ -245,6 +247,8 @@ Reuben Cummings Robert Zaremba David C Ellis + cptpcrd + Felix C. Stegerman Jens-Uwe Mager Dan Stromberg Carl Meyer @@ -278,7 +282,6 @@ Thomas Hisch Barry Hart Tomasz Dziopa - cptpcrd Lutz Paelike Ignas Mikalajunas Martin Blais @@ -307,8 +310,9 @@ Miro Hrončok Antoine Dupre Bernd Schoeller - olliemath Catalin Fierut + nimaje + Pierre-Yves DAVID Gustavo Niemeyer Andrew Thompson Joshua Gilbert @@ -348,6 +352,7 @@ afteryu Andrew Stepanov Radu Ciorba + Ian Clester Carl Bordum Hansen Paul Ganssle Michal Kuffa @@ -366,6 +371,7 @@ Alex Orange alexprengere Dennis Sweeney + Kevin Lee Anna Ravencroft Dinu Gherman Michael Chermside @@ -469,6 +475,7 @@ Chris AtLee Christoph Reiter Chris Burr + Brad Kish Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden diff -Nru pypy-7.3.5+dfsg/pypy/conftest.py pypy-7.3.6+dfsg/pypy/conftest.py --- pypy-7.3.5+dfsg/pypy/conftest.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/conftest.py 2021-10-17 16:14:51.000000000 +0000 @@ -181,15 +181,17 @@ def pytest_runtest_setup(item): if isinstance(item, py.test.collect.Function): config = item.config + appdirect = (config.getoption('runappdirect') or + config.getoption('direct_apptest')) if (item.get_marker(name='pypy_only') and - not '__pypy__' in sys.builtin_module_names): + appdirect and not '__pypy__' in sys.builtin_module_names): pytest.skip('PyPy-specific test') appclass = item.getparent(py.test.Class) if appclass is not None: from pypy.tool.pytest.objspace import gettestobjspace # Make cls.space and cls.runappdirect available in tests. spaceconfig = getattr(appclass.obj, 'spaceconfig', {}) - if not (config.getoption('runappdirect') or config.getoption('direct_apptest')): + if not appdirect: spaceconfig.setdefault('objspace.std.reinterpretasserts', True) appclass.obj.space = gettestobjspace(**spaceconfig) appclass.obj.runappdirect = config.option.runappdirect diff -Nru pypy-7.3.5+dfsg/pypy/doc/conf.py pypy-7.3.6+dfsg/pypy/doc/conf.py --- pypy-7.3.5+dfsg/pypy/doc/conf.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/conf.py 2021-10-17 16:14:54.000000000 +0000 @@ -90,7 +90,7 @@ # The short X.Y version. version = '7.3' # The full version, including alpha/beta/rc tags. -release = '7.3.5' +release = '7.3.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -Nru pypy-7.3.5+dfsg/pypy/doc/contributing.rst pypy-7.3.6+dfsg/pypy/doc/contributing.rst --- pypy-7.3.5+dfsg/pypy/doc/contributing.rst 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/contributing.rst 2021-10-17 16:14:54.000000000 +0000 @@ -289,21 +289,15 @@ ------------------------- PyPy development always was and is still thoroughly test-driven. -We use the flexible `py.test testing tool`_ which you can `install independently -`_ and use for other projects. +There are two modes of tests: those that run on top of RPython before +translation (untranslated tests) and those that run on top of a translated +``pypy`` (app tests). Since RPython is a dialect of Python2, the untranslated +tests run with a python2 host. The PyPy source tree comes with an inlined version of ``py.test`` which you can invoke by typing:: - python pytest.py -h - -This is usually equivalent to using an installed version:: - - py.test -h - -If you encounter problems with the installed version -make sure you have the correct version installed which -you can find out with the ``--version`` switch. + python2 pytest.py -h You will need the `build requirements`_ to run tests successfully, since many of them compile little pieces of PyPy and then run the tests inside that minimal @@ -313,13 +307,10 @@ Now on to running some tests. PyPy has many different test directories and you can use shell completion to point at directories or files:: - py.test pypy/interpreter/test/test_pyframe.py + python2 pytest.py pypy/interpreter/test/test_pyframe.py # or for running tests of a whole subdirectory - py.test pypy/interpreter/ - -See `py.test usage and invocations`_ for some more generic info -on how you can run tests. + python2 pytest.py pypy/interpreter/ Beware trying to run "all" pypy tests by pointing to the root directory or even the top level subdirectory ``pypy``. It takes @@ -333,24 +324,23 @@ extract a minimal failing test of at most a few lines, and put it into one of our own tests in ``pypy/*/test/``. -.. _py.test testing tool: https://pytest.org -.. _py.test usage and invocations: https://pytest.org/latest/usage.html#usage .. _`build requirements`: build.html#install-build-time-dependencies -Testing After Translation -^^^^^^^^^^^^^^^^^^^^^^^^^ +App level testing +^^^^^^^^^^^^^^^^^ -While the usual invocation of `pytest` runs app-level tests on an untranslated -PyPy that runs on top of CPython, we have a test extension to run tests +While the usual invocation of `python2 pytest.py` runs app-level tests on an +untranslated PyPy that runs on top of CPython, we have a test extension to run tests directly on the host python. This is very convenient for modules such as `cpyext`, to compare and contrast test results between CPython and PyPy. -App-level tests run directly on the host interpreter when passing `-D` or +App-level tests (ones whose file name start with ``apptest_`` not ``test_``) +run directly on the host interpreter when passing `-D` or `--direct-apptest` to `pytest`:: pypy3 -m pytest -D pypy/interpreter/test/apptest_pyframe.py -Mixed-level tests are invoked by using the `-A` or `--runappdirect` option to +Mixed-level tests (the usual ones that start with ``test_``) are invoked by using the `-A` or `--runappdirect` option to `pytest`:: python2 pytest.py -A pypy/module/cpyext/test @@ -359,12 +349,22 @@ collection phase must be run with `python2` so untranslated tests are run with:: - cpython2 pytest.py -A pypy/module/cpyext/test --python=path/to/pypy3 + python2 pytest.py -A pypy/module/cpyext/test --python=path/to/pypy3 + + +Testing After Translation +^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you run translation, you will end up with a binary named ``pypy-c`` (or +``pypy3-c`` for the Python3 branches) in the directory where you ran the +translation. To run a test from the standard CPython regression test suite, use the regular -Python way, i.e. (replace "pypy" with the exact binary name, if needed):: +Python way, i.e. (use the exact binary name):: - pypy -m test.test_datetime + ./pypy3-c -m test.test_datetime + # or + ./pypy3-c lib-python/3/test/test_audit.py Tooling & Utilities diff -Nru pypy-7.3.5+dfsg/pypy/doc/contributor.rst pypy-7.3.6+dfsg/pypy/doc/contributor.rst --- pypy-7.3.5+dfsg/pypy/doc/contributor.rst 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/contributor.rst 2021-10-17 16:14:51.000000000 +0000 @@ -23,8 +23,8 @@ Christian Tismer Hakan Ardo Benjamin Peterson - Anders Chrigstrom Wim Lavrijsen + Anders Chrigstrom Eric van Riet Paap Dan Villiom Podlaski Christiansen Remi Meier @@ -51,27 +51,29 @@ Guido Wesdorp Lawrence Oluyede Bartosz Skowron - Daniel Roberts Stefano Rivera + Daniel Roberts Adrien Di Mascio Niko Matsakis Alexander Hesse Ludovic Aubry + Batuhan Taskaya stian Jacob Hallen Jason Creighton Mark Young Andrew Lawrence Alex Martelli + Ondrej Baranovič Spenser Bauman Michal Bendowski - Ondrej Baranovič Jan de Mooij Stefan Beyer Tyler Wade Vincent Legoll Michael Foord Stephan Diehl + muke101 Simon Cross Jean-Paul Calderone Stefan Schwarzer @@ -88,7 +90,6 @@ Edd Barrett Marius Gedminas Laurence Tratt - Batuhan Taskaya Alexandre Fayolle Nicolas Truessel Simon Burton @@ -102,10 +103,11 @@ Greg Price Ivan Sichmann Freitas Mark Pearse - Andreas Stührk Tobias Pape + Andreas Stührk Jean-Philippe St. Pierre Stian Andreassen + Yusuke Izawa Guido van Rossum Pavel Vinogradov William Leslie @@ -121,8 +123,8 @@ Joannah Nanjekye Georg Brandl quejebo - muke101 - Bert Freudenberg + Vanessa Freudenberg + Michał Górny Gerald Klix Wanja Saatkamp Mike Blume @@ -130,7 +132,6 @@ Rami Chowdhury Stefan H. Muller Dodan Mihai - Michał Górny Tim Felgentreff Eugene Oden Colin Valliant @@ -165,6 +166,7 @@ Lucian Branescu Mihaila anatoly techtonik Mariano Anaya + olliemath Olivier Dormond Jared Grubb Karl Bartel @@ -191,6 +193,7 @@ Berkin Ilbeyi Mihnea Saracin Matt Jackson + Ricky Zhou Jonathan David Riehl Anders Qvist Beatrice During @@ -200,7 +203,6 @@ Faye Zhao Pauli Virtanen Mike Pavone - Ricky Zhou Alan McIntyre Alexander Sedov Alex Perry @@ -211,6 +213,8 @@ Reuben Cummings Robert Zaremba David C Ellis + cptpcrd + Felix C. Stegerman Jens-Uwe Mager Dan Stromberg Carl Meyer @@ -244,7 +248,6 @@ Thomas Hisch Barry Hart Tomasz Dziopa - cptpcrd Lutz Paelike Ignas Mikalajunas Martin Blais @@ -273,8 +276,9 @@ Miro Hrončok Antoine Dupre Bernd Schoeller - olliemath Catalin Fierut + nimaje + Pierre-Yves DAVID Gustavo Niemeyer Andrew Thompson Joshua Gilbert @@ -314,6 +318,7 @@ afteryu Andrew Stepanov Radu Ciorba + Ian Clester Carl Bordum Hansen Paul Ganssle Michal Kuffa @@ -332,6 +337,7 @@ Alex Orange alexprengere Dennis Sweeney + Kevin Lee Anna Ravencroft Dinu Gherman Michael Chermside @@ -435,3 +441,4 @@ Chris AtLee Christoph Reiter Chris Burr + Brad Kish diff -Nru pypy-7.3.5+dfsg/pypy/doc/cpython_differences.rst pypy-7.3.6+dfsg/pypy/doc/cpython_differences.rst --- pypy-7.3.5+dfsg/pypy/doc/cpython_differences.rst 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/cpython_differences.rst 2021-10-17 16:14:51.000000000 +0000 @@ -23,11 +23,14 @@ OS's limit on the number of concurrently opened files. If you are debugging a case where a file in your program is not closed -properly, you can use the ``-X track-resources`` command line option. If it is -given, a ``ResourceWarning`` is produced for every file and socket that the -garbage collector closes. The warning will contain the stack trace of the -position where the file or socket was created, to make it easier to see which -parts of the program don't close files explicitly. +properly on PyPy2, you can use the ``-X track-resources`` command line +option. On Python3 (both CPython and PyPy), use the ``-Walways`` command line +option. In both cases, you may need to add a call to ``gc.collect()`` at the +end of the program. Then a ``ResourceWarning`` is produced for every file and +socket that the garbage collector closes. On PyPy, the warning will always +contain the stack trace of the position where the file or socket was created, +to make it easier to see which parts of the program don't close files +explicitly. Fixing this difference to CPython is essentially impossible without forcing a reference-counting approach to garbage collection. The effect that you diff -Nru pypy-7.3.5+dfsg/pypy/doc/faq.rst pypy-7.3.6+dfsg/pypy/doc/faq.rst --- pypy-7.3.5+dfsg/pypy/doc/faq.rst 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/faq.rst 2021-10-17 16:14:51.000000000 +0000 @@ -125,7 +125,7 @@ PyPy currently supports: * **x86** machines on most common operating systems - (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD), + (Linux 32/64 bits, Mac OS X 64 bits, Windows 32/64 bits, OpenBSD, FreeBSD), * 64-bit **AArch**, also known as ARM64, @@ -519,20 +519,19 @@ completely deleted.) -What is needed for Windows 64 support of PyPy? ------------------------------------------------ - -First, please note that the Windows 32 PyPy binary works just fine on Windows -64. The only problem is that it only supports up to 4GB of heap per process. - -As to real Windows 64 support: Currently we don't have an active PyPy developer -whose main development platform is Windows. So if you are interested in getting -Windows 64 support, we encourage you to volunteer `to make it happen`_! Another -option would be to pay some PyPy developers to implement Windows 64 support, -but so far there doesn't seem to be an overwhelming commercial interest in it. +What is needed for better Windows 64 support of PyPy? +----------------------------------------------------- -.. _`to make it happen`: windows.html#what-is-missing-for-a-full-64-bit-translation +As of PyPy 7.3.5, PyPy supports Windows 64-bits. Since only on that platform +``sizeof(long) != sizeof(void *)``, and the underlying data type for RPython is +``long``, this proved to be challenging. It seems we have crossed that bridge, +and welcome help in bringing the Windows version into parity with CPython. In +particular, we still do not support Windows-specific features like +``winconsoleio``, windows audit events, and the Windows ``faulthandler``. +Performance may lag behind Linux64, and the ``wininstaller`` branch is still +unfinished. +Help is welcome! How long will PyPy support Python2? ----------------------------------- diff -Nru pypy-7.3.5+dfsg/pypy/doc/how-to-release.rst pypy-7.3.6+dfsg/pypy/doc/how-to-release.rst --- pypy-7.3.5+dfsg/pypy/doc/how-to-release.rst 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/how-to-release.rst 2021-10-17 16:14:51.000000000 +0000 @@ -133,8 +133,11 @@ the ``versions.json`` in ``pypy/tools/release``, upload it, and run the ``check_versions.py`` file in that directory. This file is used by various downstream tools like "github actions" to find valid pypy downloads. It - takes an hour for - https://downloads.python.org/pypy/ to sync + takes an hour for https://downloads.python.org/pypy/ to sync. Note the + "latest_pypy" attribute: it is per-python-version. So if the new release + overrides a current latest_pypy (both are 2.7.18, for instance), you must + find the older version and set its "lastest_pypy" to "false" or + ``check_versions.py`` (and the various tools) will fail. * Send out a mailing list message asking for last-minute comments and testing @@ -153,6 +156,9 @@ * add a tag on the codespeed web site that corresponds to pypy release * revise versioning at https://readthedocs.org/projects/pypy * suggest updates to multibuild_ and cibuildwheel_ + * update conda forge's `pypy3.6-feedstock`_ and `pypy-meta-feedstock`_ .. _multibuild: https://github.com/matthew-brett/multibuild .. _cibuildwheel: https://github.com/joerick/cibuildwheel +.. _`pypy3.6-feedstock`: https://github.com/conda-forge/pypy3.6-feedstock +.. _`pypy-meta-feedstock`: https://github.com/conda-forge/pypy-meta-feedstock diff -Nru pypy-7.3.5+dfsg/pypy/doc/index-of-release-notes.rst pypy-7.3.6+dfsg/pypy/doc/index-of-release-notes.rst --- pypy-7.3.5+dfsg/pypy/doc/index-of-release-notes.rst 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/index-of-release-notes.rst 2021-10-17 16:14:54.000000000 +0000 @@ -6,6 +6,8 @@ .. toctree:: + release-v7.3.6.rst + release-v7.3.5.rst release-v7.3.4.rst release-v7.3.3.rst release-v7.3.2.rst diff -Nru pypy-7.3.5+dfsg/pypy/doc/index-of-whatsnew.rst pypy-7.3.6+dfsg/pypy/doc/index-of-whatsnew.rst --- pypy-7.3.5+dfsg/pypy/doc/index-of-whatsnew.rst 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/index-of-whatsnew.rst 2021-10-17 16:14:54.000000000 +0000 @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-pypy2-7.3.6.rst whatsnew-pypy2-7.3.4.rst whatsnew-pypy2-7.3.3.rst whatsnew-pypy2-7.3.2.rst diff -Nru pypy-7.3.5+dfsg/pypy/doc/release-v7.3.4.rst pypy-7.3.6+dfsg/pypy/doc/release-v7.3.4.rst --- pypy-7.3.5+dfsg/pypy/doc/release-v7.3.4.rst 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/release-v7.3.4.rst 2021-10-17 16:14:51.000000000 +0000 @@ -2,12 +2,6 @@ PyPy v7.3.4: release of 2.7 and 3.7 =================================== -.. note:: - This is a pre-release announcement. When the release actually happens, it - will be announced on the `PyPy blog`_ - -.. _`PyPy blog`: https://pypy.org/blog - .. Changelog up to commit 9c11d242d78c @@ -30,8 +24,8 @@ important to you, please reach out as we could offer sponsored longer term support. -The interpreters are based on much the same codebase, thus the multiple -release. This is a micro release, all APIs are compatible with the 7.3 +The two interpreters are based on much the same codebase, thus the multiple +release. This is a micro release, all APIs are compatible with the other 7.3 releases. Highlights of the release include binary **Windows 64** support, faster numerical instance fields, and a preliminary HPy backend. @@ -68,6 +62,9 @@ interpreters like GraalPython_ (written on top of the Java virtual machine), RustPython_, and PyPy. Thanks to Oracle and IBM for sponsoring work on HPy. +Support for the vmprof_ statistical profiler has been extended to ARM64 via a +built-in backend. + Several issues exposed in the 7.3.3 release were fixed. Many of them came from the great work ongoing to ship PyPy-compatible binary packages in `conda-forge`_. A big shout out to them for taking this on. @@ -124,6 +121,7 @@ .. _`GraalPython`: https://github.com/graalvm/graalpython .. _`RustPython`: https://github.com/RustPython/RustPython .. _`renovated blog site`: https://pypy.org/blog +.. _vmprof: https://vmprof.readthedocs.io/en/latest/ What is PyPy? diff -Nru pypy-7.3.5+dfsg/pypy/doc/release-v7.3.5.rst pypy-7.3.6+dfsg/pypy/doc/release-v7.3.5.rst --- pypy-7.3.5+dfsg/pypy/doc/release-v7.3.5.rst 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/release-v7.3.5.rst 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,112 @@ +=================================== +PyPy v7.3.5: release of 2.7 and 3.7 +=================================== + +We are releasing a PyPy 7.3.5 with bugfixes for PyPy 7.3.4, released April 4. +PyPy 7.3.4 was the first release that runs on windows 64-bit, so that support +is still "beta". We are releasing it in the hopes that we can garner momentum +for its continued support, but are already aware of some problems, for instance +it errors in the NumPy test suite (issue 3462_). Please help out with testing +the releae and reporting successes and failures, financially supporting our +ongoing work, and helping us find the source of these problems. + +- The new windows 64-bit builds improperly named c-extension modules + with the same extension as the 32-bit build (issue 3443_) +- Use the windows-specific ``PC/pyconfig.h`` rather than the posix one +- Fix the return type for ``_Py_HashDouble`` which impacts 64-bit windows +- A change to the python 3.7 ``sysconfig.get_config_var('LIBDIR')`` was wrong, + leading to problems finding `libpypy3-c.so` for embedded PyPy (issue 3442_). +- Instantiate ``distutils.command.install`` schema for PyPy-specific + ``implementation_lower`` +- Delay thread-checking logic in greenlets until the thread is actually started + (continuation of issue 3441_) +- Four upstream (CPython) security patches were applied: + + - `BPO 42988`_ to remove ``pydoc.getfile`` + - `BPO 43285`_ to not trust the ``PASV`` response in ``ftplib``. + - `BPO 43075`_ to remove a possible ReDoS in urllib AbstractBasicAuthHandler + - `BPO 43882`_ to sanitize urls containing ASCII newline and tabs in + ``urllib.parse`` + +- Fix for json-specialized dicts (issue 3460_) +- Specialize ``ByteBuffer.setslice`` which speeds up binary file reading by a + factor of 3 +- When assigning the full slice of a list, evaluate the rhs before clearing the + list (issue 3440_) +- On Python2, ``PyUnicode_Contains`` accepts bytes as well as unicode. +- Finish fixing ``_sqlite3`` - untested ``_reset()`` was missing an argument + (issue 3432_) +- Update the packaged sqlite3 to 3.35.5 on windows. While not a bugfix, this + seems like an easy win. + +We recommend updating. These fixes are the direct result of end-user bug +reports, so please continue reporting issues as they crop up. + +You can find links to download the v7.3.5 releases here: + + https://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. If PyPy is not quite good enough for your needs, we are available for +direct consulting work. If PyPy is helping you out, we would love to hear about +it and encourage submissions to our `renovated blog site`_ via a pull request +to https://github.com/pypy/pypy.org + +We would also like to thank our contributors and encourage new people to join +the project. PyPy has many layers and we need help with all of them: `PyPy`_ +and `RPython`_ documentation improvements, tweaking popular modules to run +on PyPy, or general `help`_ with making RPython's JIT even better. + +If you are a python library maintainer and use C-extensions, please consider +making a CFFI_ / cppyy_ version of your library that would be performant on PyPy. +In any case both `cibuildwheel`_ and the `multibuild system`_ support +building wheels for PyPy. + +.. _`PyPy`: index.html +.. _`RPython`: https://rpython.readthedocs.org +.. _`help`: project-ideas.html +.. _CFFI: https://cffi.readthedocs.io +.. _cppyy: https://cppyy.readthedocs.io +.. _`multibuild system`: https://github.com/matthew-brett/multibuild +.. _`cibuildwheel`: https://github.com/joerick/cibuildwheel +.. _`renovated blog site`: https://pypy.org/blog + + +What is PyPy? +============= + +PyPy is a Python interpreter, a drop-in replacement for CPython 2.7, 3.7, and +soon 3.8. It's fast (`PyPy and CPython 3.7.4`_ performance +comparison) due to its integrated tracing JIT compiler. + +We also welcome developers of other `dynamic languages`_ to see what RPython +can do for them. + +This PyPy release supports: + + * **x86** machines on most common operating systems + (Linux 32/64 bits, Mac OS X 64 bits, Windows 32/64 bits, OpenBSD, FreeBSD) + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + + * 64-bit **ARM** machines running Linux. + +PyPy does support ARM 32 bit processors, but does not release binaries. + +.. _`PyPy and CPython 3.7.4`: https://speed.pypy.org +.. _`dynamic languages`: https://rpython.readthedocs.io/en/latest/examples.html + +.. _3443: https://foss.heptapod.net/pypy/pypy/-/issues/3443 +.. _3442: https://foss.heptapod.net/pypy/pypy/-/issues/3442 +.. _3441: https://foss.heptapod.net/pypy/pypy/-/issues/3441 +.. _3440: https://foss.heptapod.net/pypy/pypy/-/issues/3440 +.. _3460: https://foss.heptapod.net/pypy/pypy/-/issues/3460 +.. _3462: https://foss.heptapod.net/pypy/pypy/-/issues/3462 +.. _3432: https://foss.heptapod.net/pypy/pypy/-/issues/3432 +.. _`BPO 42988`: https://bugs.python.org/issue42988 +.. _`BPO 43285`: https://bugs.python.org/issue43285 +.. _`BPO 43075`: https://bugs.python.org/issue43075 +.. _`BPO 43882`: https://bugs.python.org/issue43882 + diff -Nru pypy-7.3.5+dfsg/pypy/doc/release-v7.3.6.rst pypy-7.3.6+dfsg/pypy/doc/release-v7.3.6.rst --- pypy-7.3.5+dfsg/pypy/doc/release-v7.3.6.rst 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/release-v7.3.6.rst 2021-10-17 16:14:54.000000000 +0000 @@ -0,0 +1,248 @@ +===================================================== +PyPy v7.3.6: release of python 2.7, 3.7, and 3.8-beta +===================================================== + +.. + Changelog up to commit fae737d37616 + +.. note:: + This is a pre-release announcement. When the release actually happens, it + will be announced on the `PyPy blog`_ + +.. _`PyPy blog`: https://pypy.org/blog + +The PyPy team is proud to release version 7.3.6 of PyPy, which includes +three different interpreters: + + - PyPy2.7, which is an interpreter supporting the syntax and the features of + Python 2.7 including the stdlib for CPython 2.7.18+ (the ``+`` is for + backported security updates) + + - PyPy3.7, which is an interpreter supporting the syntax and the features of + Python 3.7, including the stdlib for CPython 3.7.12. + + - PyPy3.8, which is an interpreter supporting the syntax and the features of + Python 3.8, including the stdlib for CPython 3.8.12. Since this is our + first release of the interpreter, we relate to this as "beta" quality. We + welcome testing of this version, if you discover incompatibilites, please + report them so we can gain confidence in the version. + +The interpreters are based on much the same codebase, thus the multiple +release. This is a micro release, all APIs are compatible with the other 7.3 +releases. Highlights of the release, since the release of 7.3.5 in May 2021, +include: + + - We have merged a backend for HPy_, the better C-API interface. The backend + implements version 0.0.3. + - Translation of PyPy into a binary, known to be slow, is now about 40% + faster. On a modern machine, PyPy3.8 can translate in about 20 minutes. + - PyPy Windows 64 is now available on conda-forge_, along with over 600 + commonly used binary packages. This new offering joins the more than 1000 + conda packages for PyPy on Linux and macOS. Many thanks to the conda-forge + maintainers for pushing this forward over the past 18 months. + - Speed improvements were made to ``io``, ``sum``, ``_ssl`` and more. These + were done in response to user feedback. + - The 3.8 version of the release contains a beta-quality improvement to the + JIT to better support `compiling huge Python functions`_ by breaking them + up into smaller pieces. + - The release of Python3.8 required a concerted effort. We were greatly + helped by @isidentical (Batuhan Taskaya) and other new contributors. + - The 3.8 package now uses the same layout as CPython, and many of the + PyPy-specific changes to ``sysconfig``, ``distutils.sysconfig``, and + ``distutils.commands.install.py`` have been removed. The ``stdlib`` now + is located in ``/lib/pypy3.8`` on ``posix`` systems, and in + ``/Lib`` on Windows. The include files on windows remain the same, + on ``posix`` they are in ``/include/pypy3.8``. Note we still use the + ``pypy`` prefix to prevent mixing the files with CPython (which uses + ``python``. + +.. _`compiling huge Python functions`: https://www.pypy.org/posts/2021/09/jit-auto-generated-code.html + + +We recommend updating. You can find links to download the v7.3.6 releases here: + + https://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. If PyPy is not quite good enough for your needs, we are available for +direct consulting work. If PyPy is helping you out, we would love to hear about +it and encourage submissions to our blog_ via a pull request +to https://github.com/pypy/pypy.org + +We would also like to thank our contributors and encourage new people to join +the project. PyPy has many layers and we need help with all of them: `PyPy`_ +and `RPython`_ documentation improvements, tweaking popular modules to run +on PyPy, or general `help`_ with making RPython's JIT even better. Since the +previous release, we have accepted contributions from 7 new contributors, +thanks for pitching in, and welcome to the project! + +If you are a python library maintainer and use C-extensions, please consider +making a CFFI_ / cppyy_ version of your library that would be performant on PyPy. +In any case both `cibuildwheel`_ and the `multibuild system`_ support +building wheels for PyPy. + +.. _`PyPy`: index.html +.. _`RPython`: https://rpython.readthedocs.org +.. _`help`: project-ideas.html +.. _CFFI: https://cffi.readthedocs.io +.. _cppyy: https://cppyy.readthedocs.io +.. _`multibuild system`: https://github.com/matthew-brett/multibuild +.. _`cibuildwheel`: https://github.com/joerick/cibuildwheel +.. _blog: https://pypy.org/blog +.. _`conda-forge`: https://conda-forge.org/blog//2020/03/10/pypy +.. _HPy: https://hpyproject.org/ + + +What is PyPy? +============= + +PyPy is a Python interpreter, a drop-in replacement for CPython 2.7, 3.7, and +soon 3.8. It's fast (`PyPy and CPython 3.7.4`_ performance +comparison) due to its integrated tracing JIT compiler. + +We also welcome developers of other `dynamic languages`_ to see what RPython +can do for them. + +This PyPy release supports: + + * **x86** machines on most common operating systems + (Linux 32/64 bits, Mac OS X 64 bits, Windows 64 bits, OpenBSD, FreeBSD) + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + + * 64-bit **ARM** machines running Linux. + +PyPy does support Windows 32-bit and ARM 32 bit processors, but does not +release binaries. Please reach out to us if you wish to sponsor releases for +those platforms. + +.. _`PyPy and CPython 3.7.4`: https://speed.pypy.org +.. _`dynamic languages`: https://rpython.readthedocs.io/en/latest/examples.html + +Changelog +========= + +Bugfixes shared across versions +------------------------------- +- Backport fix for `bpo 44022`_ in ``httplib`` +- Make ``dotviewer`` Python3 compatible and add some features (like rudimentary + record support). +- Fix error reporting when the error position is the last character of a JSON + bytestring (issue 3514_) +- Set non-volatile xmm registers in the JIT for windows 64-bit calling + conventions. Fixes a bug where the JIT was not restoring registers when + returning from a call +- Support multiple tags in ``hg_archive``, fixes ``platform._sys_version()`` + which was reporting the first tag (i.e. rc1) when it should have reported + the last tag (i.e. final) +- Fix position bugs in the astcompiler stemming from the fact that + ``SyntaxErrors`` use 1-based column offsets + +Speedups and enhancements shared across versions +------------------------------------------------ +- Speed up RPython typing +- Speed up RPython graph cycle finding by removing leaves before checking + for cycles +- Speed up C compilation on GCC by using the pre-compiled header feature +- When switching from an unwrapped list strategy to the ``ObjectListStrategy``, + try to cache wrapped elements. This prevents the memory blowup on + code like ``l = [0] * N; l[0] = "abc"`` (issue 2881_). +- Specialize builtin ``sum`` for lists/tuples (issue 3492_). +- Update to cffi 1.14.6 +- Use ``libffi-7.dll`` on windows instead of an old vendored version of + ``libffi`` +- Fix for a corner case missing an optimization: ``interpindirect2app()`` on a + function with signature ``'self, space, __args__'`` was missing the + optimization for that signature, which works with ``interp2app()``. It's + used in ``_hpy_universal``. +- Add an option to the packaging script to force non-portable packaging (issue + 3538_) +- Switch to "powersort" merging strategy by Munro and Wild instead the timsort + algorithm (`bpo 34561`_) +- Check env keys for ``'='`` when calling ``os.execve`` +- Provide a PyPy-only scoped way to malloc buffers in cffi and use it in + ``ssl.read`` + +C-API (cpyext) and C-extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We are no longer backporting changes to the ``cpyext`` compatiblity layer to +PyPy2.7. + + +Python 3.7+ bugfixes +-------------------- +- Fix MemoryError on zip.read in shutil._unpack_zipfile for large files `bpo + 43650`_ +- Fix some issues around the ``obj`` field of ``memoryview``, and add missing + ``toreadonly``. +- Fix ``re.sub()`` with no match and with unusual types of arguments (issue + 3515_) +- Fix ``_socket.sethostname()`` failure when passed bytes +- Switch ``sys.implementation.version`` and ``sys.implementation.hexversion`` + to ``pypy_version_info`` (i.e. (7, 3. 6) not (3, 7. 10)) (issue 3129_) + +Python 3.7+ speedups and enhancements +------------------------------------- +- Speep up cached imports by re-implementing (a subset of) `bpo 22557`_. This + brings PyPy3.7 very close to the speed of PyPy2 (issue 3431_) +- Ignore finalizers on built-in ``io`` classes if we know the stream is closed. + Also find some other optimizations aroudn ``io`` operations. +- Add more fields to ``sysconfig.get_config_var`` via ``_sysconfigdata`` (issue + 3483_) +- Add a ``sys.implementation._multiarch`` field like CPython on linux and + darwin +- Add a ``lib_pypy\_sysconfigdata__*.py`` file like CPython on linux, darwin + during packaging via ``sysconfig._generate_posix_vars()`` (issue 3483_) +- Slightly adapt the packaging and cffi-module build scripts for compatibility + with conda-forge. +- Create ``pypy.exe``, ``pypyw.exe``, ``python.exe``, ``pythonw.exe`` when + packaging for windows +- Speed up ``_ssl`` error processing by moving the class out of + ``_PySSL_errno`` and creating a fast-path for instantiation (issue 3490_) +- Support HPy 0.0.2 +- Use CPython list of consts in ``os.{confstr,pathconf,sysconf}_names`` (issue + 3502_) +- Add ``_winapi.GetFileType`` and ``FILE_TYPE_*`` values (issue 3531_) +- Allow ``ctypes.POINTER()`` to cast `ctypes.array`` (issue 3546_) +- Update the stdlib to v3.7.12 + +Python 3.7 C-API +~~~~~~~~~~~~~~~~ +- Add PEP 495 c-api ``TimeAndFold`` datetime constructors (issue 2987_) +- Allow ``NULL`` in ``PyErr_WriteUnraisable`` (issue 3353_) +- Support ``*TimeZone*`` functions in datetime +- Add slot functions so ``int(x)`` and ``float(x)`` work properly where + ``x`` is a c-extension class +- When creating a ``PyUnicodeObject``, use the compact form to store the data + directly on the object and not via an additional buffer. This is used in + pythran via ``_PyUnicode_COMPACT_DATA`` even though it is a "private" + interface. +- Add ``PyGILState_Check``, ``PyContextVar_New``, ``PyContextVar_Get``, + ``PyContextVar_Set`` +- Add ``PyExc_WindowsError`` (issue 3472_) +- Add ``frame.f_back``, assuming the user is aware of the dangers of examinig + the stack +- Fix typo in ``import.h`` + +.. _2881: https://foss.heptapod.net/pypy/pypy/-/issues/2881 +.. _2987: https://foss.heptapod.net/pypy/pypy/-/issues/2987 +.. _3129: https://foss.heptapod.net/pypy/pypy/-/issues/3129 +.. _3353: https://foss.heptapod.net/pypy/pypy/-/issues/3353 +.. _3431: https://foss.heptapod.net/pypy/pypy/-/issues/3431 +.. _3402: https://foss.heptapod.net/pypy/pypy/-/issues/3402 +.. _3472: https://foss.heptapod.net/pypy/pypy/-/issues/3472 +.. _3483: https://foss.heptapod.net/pypy/pypy/-/issues/3483 +.. _3490: https://foss.heptapod.net/pypy/pypy/-/issues/3490 +.. _3492: https://foss.heptapod.net/pypy/pypy/-/issues/3492 +.. _3502: https://foss.heptapod.net/pypy/pypy/-/issues/3502 +.. _3514: https://foss.heptapod.net/pypy/pypy/-/issues/3514 +.. _3515: https://foss.heptapod.net/pypy/pypy/-/issues/3515 +.. _3531: https://foss.heptapod.net/pypy/pypy/-/issues/3531 +.. _3538: https://foss.heptapod.net/pypy/pypy/-/issues/3538 +.. _3546: https://foss.heptapod.net/pypy/pypy/-/issues/3546 +.. _`bpo 22557`: https://bugs.python.org/issue22557 +.. _`bpo 44022`: https://bugs.python.org/issue44022 +.. _`bpo 43650`: https://bugs.python.org/issue43650 +.. _`bpo 34561`: https://bugs.python.org/issue34561 diff -Nru pypy-7.3.5+dfsg/pypy/doc/tool/makecontributor.py pypy-7.3.6+dfsg/pypy/doc/tool/makecontributor.py --- pypy-7.3.5+dfsg/pypy/doc/tool/makecontributor.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/tool/makecontributor.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,3 +1,4 @@ +# encoding: utf-8 from __future__ import print_function # NOTE: run this script with LANG=en_US.UTF-8 # works with pip install mercurial==3.0 @@ -13,7 +14,7 @@ ROOT = py.path.local(__file__).join('..', '..', '..', '..') author_re = re.compile('(.*) <.*>') pair_programming_re = re.compile(r'^\((.*?)\)') -excluded = set(["pypy", "convert-repo"]) +excluded = set(["pypy", "convert-repo", "hgattic"]) alias = { 'Anders Chrigstrom': ['arre'], @@ -46,7 +47,7 @@ 'Eric van Riet Paap': ['ericvrp'], 'Jacob Hallen': ['jacob', 'jakob', 'jacob hallen'], 'Anders Lehmann': ['ale', 'anders'], - 'Bert Freudenberg': ['bert'], + 'Vanessa Freudenberg': ['bert'], 'Boris Feigin': ['boris', 'boria'], 'Valentino Volonghi': ['valentino', 'dialtone'], 'Aurelien Campeas': ['aurelien', 'aureliene'], @@ -94,6 +95,8 @@ 'Andrew Lawrence': ['andrew.lawrence@siemens.com', 'andrewjlawrence'], 'Batuhan Taskaya': ['isidentical'], 'Ondrej Baranovič': ['nulano'], + 'Brad Kish': ['rtkbkish'], + 'Michał Górny': ['mgorny'] } alias_map = {} @@ -152,9 +155,9 @@ ## items.sort(key=operator.itemgetter(1), reverse=True) ## for name, n in items: ## if show_numbers: - ## print '%5d %s' % (n, name) + ## print('%5d %s' % (n, name)) ## else: - ## print name + ## print(name) items = list(authors_count.items()) items.sort(key=operator.itemgetter(1), reverse=True) diff -Nru pypy-7.3.5+dfsg/pypy/doc/whatsnew-head.rst pypy-7.3.6+dfsg/pypy/doc/whatsnew-head.rst --- pypy-7.3.5+dfsg/pypy/doc/whatsnew-head.rst 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/whatsnew-head.rst 2021-10-17 16:14:54.000000000 +0000 @@ -1,8 +1,8 @@ ============================ -What's new in PyPy2.7 7.3.4+ +What's new in PyPy2.7 7.3.6+ ============================ -.. this is a revision shortly after release-pypy-7.3.4 -.. startrev: 9c11d242d78c +.. this is a revision shortly after release-pypy-7.3.6 +.. startrev: 0012ea4931c1 diff -Nru pypy-7.3.5+dfsg/pypy/doc/whatsnew-pypy2-7.3.6.rst pypy-7.3.6+dfsg/pypy/doc/whatsnew-pypy2-7.3.6.rst --- pypy-7.3.5+dfsg/pypy/doc/whatsnew-pypy2-7.3.6.rst 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/doc/whatsnew-pypy2-7.3.6.rst 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,64 @@ +=========================== +What's new in PyPy2.7 7.3.6 +=========================== + +.. this is a revision shortly after release-pypy-7.3.4 +.. startrev: 9c11d242d78c + + +.. branch: faster-rbigint-big-divmod + +Speed up ``divmod`` for very large numbers. This also speeds up string +formatting of big numbers. + +.. branch: jit-heapcache-interiorfields + +Optimize dictionary operations in the JIT a bit more, making it possible to +completely optimize away the creation of dictionaries in more situations (such +as calling the ``dict.update`` method on known dicts). + +.. branch: bpo-35714 + +Add special error messange for ``'\0'`` in ``rstruct.formatiterator`` +(bpo-35714) + +.. branch: gcc-precompiled-header + +Speed up GCC compilation by using a pre-compiled header. + +.. branch: set-vmprof_apple-only-on-darwin + +Only set VMPROF_APPLE on bsd-like when sys.platform is darwin + +.. minor branches not worth to document +.. branch: fix-checkmodule-2 +.. branch: tiny-traceviewer-fix + + +.. branch: dotviewer-python3 + +Make dotviewer python3 compatible and add some features (like rudimentary +record support). + +.. branch: specialize-sum + +Add specialization for sum(list) and sum(tuple) + +.. branch: win64-xmm-registers + +Set non-volatile xmm registers in the JIT for windows 64-bit calling +conventions. Fixes a bug where the JIT was not restoring registers when +returning from a call + +.. branch: no-make-portable + +Add an option to package pypy non-portably + +.. branch: win64-stat + +Add ``st_file_attributes`` and ``st_reparse_tag`` attributes to ``os.stat`` +on windows. Also follow the reparse logic of Python3.8. + +.. branch: scoped-cffi-malloc + +Adds a scoped way to malloc buffers to cffi and use it in ``ssl.read`` diff -Nru pypy-7.3.5+dfsg/pypy/goal/targetpypystandalone.py pypy-7.3.6+dfsg/pypy/goal/targetpypystandalone.py --- pypy-7.3.5+dfsg/pypy/goal/targetpypystandalone.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/goal/targetpypystandalone.py 2021-10-17 16:14:51.000000000 +0000 @@ -335,9 +335,13 @@ options = make_dict(config) wrapstr = 'space.wrap(%r)' % (options) # import time SysModule.interpleveldefs['pypy_translation_info'] = wrapstr - if config.objspace.usemodules._cffi_backend: + + if 'compile' in driver._disabled: + driver.default_goal = 'source' + elif config.objspace.usemodules._cffi_backend: self.hack_for_cffi_modules(driver) - + else: + driver.default_goal = 'compile' return self.get_entry_point(config) def hack_for_cffi_modules(self, driver): diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/app_main.py pypy-7.3.6+dfsg/pypy/interpreter/app_main.py --- pypy-7.3.5+dfsg/pypy/interpreter/app_main.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/app_main.py 2021-10-17 16:14:51.000000000 +0000 @@ -34,6 +34,7 @@ -X track-resources : track the creation of files and sockets and display a warning if they are not closed explicitly -X faulthandler : attempt to display tracebacks when PyPy crashes +-X jit-off : turn the JIT off, equivalent to --jit off """ # Missing vs CPython: PYTHONHOME, PYTHONCASEOK USAGE2 = """ @@ -278,9 +279,11 @@ sys.pypy_set_track_resources(True) elif Xparam == 'faulthandler': run_faulthandler() + elif Xparam == 'jit-off': + set_jit_option(options, 'off') else: print >> sys.stderr, 'usage: %s -X [options]' % (get_sys_executable(),) - print >> sys.stderr, '[options] can be: track-resources, faulthandler' + print >> sys.stderr, '[options] can be: track-resources, faulthandler, jit-off' raise SystemExit class CommandLineError(Exception): diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/astcompiler/codegen.py pypy-7.3.6+dfsg/pypy/interpreter/astcompiler/codegen.py --- pypy-7.3.5+dfsg/pypy/interpreter/astcompiler/codegen.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/astcompiler/codegen.py 2021-10-17 16:14:51.000000000 +0000 @@ -204,7 +204,8 @@ "mismatched frame blocks" def error(self, msg, node): - raise SyntaxError(msg, node.lineno, node.col_offset, + # NB: SyntaxError's offset is 1-based! + raise SyntaxError(msg, node.lineno, node.col_offset + 1, filename=self.compile_info.filename) def name_op(self, identifier, ctx): diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/gateway.py pypy-7.3.6+dfsg/pypy/interpreter/gateway.py --- pypy-7.3.5+dfsg/pypy/interpreter/gateway.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/gateway.py 2021-10-17 16:14:51.000000000 +0000 @@ -633,10 +633,14 @@ @not_rpython def __init__(self, func, unwrap_spec=None, self_type=None, descrmismatch=None, doc=None): + from rpython.rlib import rutf8 # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. Code.__init__(self, func.__name__) self.docstring = doc or func.__doc__ + if self.docstring: + # check that it's utf-8 + rutf8.check_utf8(self.docstring, False) self.identifier = "%s-%s-%s" % (func.__module__, func.__name__, getattr(self_type, '__name__', '*')) @@ -961,8 +965,9 @@ else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() - unwrap_spec['self'] = base_cls - return interp2app(globals()['unwrap_spec'](**unwrap_spec)(f)) + unwrap_spec['self'] = 'self' + return interp2app(globals()['unwrap_spec'](**unwrap_spec)(f), + self_type=base_cls) class interp2app(W_Root): """Build a gateway that calls 'f' at interp-level.""" @@ -973,11 +978,11 @@ @not_rpython def __new__(cls, f, app_name=None, unwrap_spec=None, descrmismatch=None, - as_classmethod=False, doc=None): + as_classmethod=False, doc=None, self_type=None): # f must be a function whose name does NOT start with 'app_' - self_type = None if hasattr(f, 'im_func'): + assert self_type in (None, f.im_class) self_type = f.im_class f = f.im_func if not isinstance(f, types.FunctionType): diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/pyparser/metaparser.py pypy-7.3.6+dfsg/pypy/interpreter/pyparser/metaparser.py --- pypy-7.3.5+dfsg/pypy/interpreter/pyparser/metaparser.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/pyparser/metaparser.py 2021-10-17 16:14:51.000000000 +0000 @@ -148,7 +148,7 @@ arcs.append((self.make_label(gram, label), dfa.index(next))) states.append((arcs, state.is_final)) symbol_id = gram.symbol_ids[name] - dfa = parser.DFA(symbol_id, states, self.make_first(gram, name)) + dfa = parser.DFA(gram, symbol_id, states, self.make_first(gram, name)) gram.dfas.append(dfa) assert len(gram.dfas) - 1 == symbol_id - 256 gram.start = gram.symbol_ids[self.start_symbol] diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/pyparser/parser.py pypy-7.3.6+dfsg/pypy/interpreter/pyparser/parser.py --- pypy-7.3.5+dfsg/pypy/interpreter/pyparser/parser.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/pyparser/parser.py 2021-10-17 16:14:51.000000000 +0000 @@ -57,7 +57,8 @@ return True class DFA(object): - def __init__(self, symbol_id, states, first): + def __init__(self, grammar, symbol_id, states, first): + self.grammar = grammar self.symbol_id = symbol_id self.states = states self.first = self._first_to_string(first) @@ -107,9 +108,12 @@ class Node(object): - __slots__ = ("type", ) + __slots__ = ("grammar", "type") - def __init__(self, type): + def __init__(self, grammar, type): + assert grammar is None or isinstance(grammar, Grammar) + assert isinstance(type, int) + self.grammar = grammar self.type = type def __eq__(self, other): @@ -139,19 +143,33 @@ def get_line(self): raise NotImplementedError("abstract base class") + def view(self): + from dotviewer import graphclient + import pytest + r = ["digraph G {"] + self._dot(r) + r.append("}") + p = pytest.ensuretemp("pyparser").join("temp.dot") + p.write("\n".join(r)) + graphclient.display_dot_file(str(p)) + + def _dot(self, result): + raise NotImplementedError("abstract base class") + class Terminal(Node): __slots__ = ("value", "lineno", "column", "line") - def __init__(self, type, value, lineno, column, line=None): - Node.__init__(self, type) + def __init__(self, grammar, type, value, lineno, column, line=None): + Node.__init__(self, grammar, type) self.value = value self.lineno = lineno self.column = column self.line = line @staticmethod - def fromtoken(token): + def fromtoken(grammar, token): return Terminal( + grammar, token.token_type, token.value, token.lineno, token.column, token.line) @@ -176,6 +194,10 @@ def get_line(self): return self.line + def _dot(self, result): + result.append('%s [label="%r", shape=box];' % (id(self), self.value)) + + class AbstractNonterminal(Node): __slots__ = () @@ -202,17 +224,27 @@ return False return True + def _dot(self, result): + for i in range(self.num_children()): + child = self.get_child(i) + result.append('%s [label=%s, shape=box]' % (id(self), self.grammar.symbol_names[self.type])) + result.append('%s -> %s [label="%s"]' % (id(self), id(child), i)) + child._dot(result) + class Nonterminal(AbstractNonterminal): __slots__ = ("_children", ) - def __init__(self, type, children=None): - Node.__init__(self, type) + def __init__(self, grammar, type, children=None): + Node.__init__(self, grammar, type) if children is None: children = [] self._children = children def __repr__(self): - return "Nonterminal(type=%s, children=%r)" % (self.type, self._children) + return "Nonterminal(type=%s, children=%r)" % ( + self.grammar.symbol_names[self.type] + if self.grammar is not None else self.type, + self._children) def get_child(self, i): assert self._children is not None @@ -227,12 +259,15 @@ class Nonterminal1(AbstractNonterminal): __slots__ = ("_child", ) - def __init__(self, type, child): - Node.__init__(self, type) + def __init__(self, grammar, type, child): + Node.__init__(self, grammar, type) self._child = child def __repr__(self): - return "Nonterminal(type=%s, children=[%r])" % (self.type, self._child) + return "Nonterminal(type=%s, children=[%r])" % ( + self.grammar.symbol_names[self.type] + if self.grammar is not None else self.type, + self._child) def get_child(self, i): assert i == 0 or i == -1 @@ -274,13 +309,33 @@ def node_append_child(self, child): node = self.node if node is None: - self.node = Nonterminal1(self.dfa.symbol_id, child) + self.node = Nonterminal1(self.dfa.grammar, self.dfa.symbol_id, child) elif isinstance(node, Nonterminal1): newnode = self.node = Nonterminal( + self.dfa.grammar, self.dfa.symbol_id, [node._child, child]) else: self.node.append_child(child) + def view(self): + from dotviewer import graphclient + import pytest + r = ["digraph G {"] + self._dot(r) + r.append("}") + p = pytest.ensuretemp("pyparser").join("temp.dot") + p.write("\n".join(r)) + graphclient.display_dot_file(str(p)) + + def _dot(self, result): + result.append('%s [label=%s, shape=box, color=white]' % (id(self), self.dfa.grammar.symbol_names[self.dfa.symbol_id])) + if self.next: + result.append('%s -> %s [label="next"]' % (id(self), id(self.next))) + self.next._dot(result) + if self.node: + result.append('%s -> %s [label="node"]' % (id(self), id(self.node))) + self.node._dot(result) + class Parser(object): @@ -351,7 +406,7 @@ def shift(self, next_state, token): """Shift a non-terminal and prepare for the next state.""" - new_node = Terminal.fromtoken(token) + new_node = Terminal.fromtoken(self.grammar, token) self.stack.node_append_child(new_node) self.stack.state = next_state diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/pyparser/pytokenizer.py pypy-7.3.6+dfsg/pypy/interpreter/pyparser/pytokenizer.py --- pypy-7.3.5+dfsg/pypy/interpreter/pyparser/pytokenizer.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/pyparser/pytokenizer.py 2021-10-17 16:14:51.000000000 +0000 @@ -77,8 +77,7 @@ lnum = continued = 0 namechars = NAMECHARS numchars = NUMCHARS - contstr, needcont = '', 0 - contline = None + contstrs, needcont = [], False indents = [0] last_comment = '' parenstack = [] @@ -95,7 +94,7 @@ line = universal_newline(line) pos, max = 0, len(line) - if contstr: + if contstrs: if not line: raise TokenError( "end of file (EOF) while scanning triple-quoted string literal", @@ -104,24 +103,23 @@ endmatch = endDFA.recognize(line) if endmatch >= 0: pos = end = endmatch - tok = Token(tokens.STRING, contstr + line[:end], strstart[0], + contstrs.append(line[:end]) + tok = Token(tokens.STRING, "".join(contstrs), strstart[0], strstart[1], line) token_list.append(tok) last_comment = '' - contstr, needcont = '', 0 - contline = None + contstrs, needcont = [], False elif (needcont and not line.endswith('\\\n') and not line.endswith('\\\r\n')): - tok = Token(tokens.ERRORTOKEN, contstr + line, strstart[0], + contstrs.append(line) + tok = Token(tokens.ERRORTOKEN, "".join(contstrs), strstart[0], strstart[1], line) token_list.append(tok) last_comment = '' - contstr = '' - contline = None + contstrs = [] continue else: - contstr = contstr + line - contline = contline + line + contstrs.append(line) continue elif not parenstack and not continued: # new statement @@ -199,8 +197,7 @@ last_comment = '' else: strstart = (lnum, start, line) - contstr = line[start:] - contline = line + contstrs = [line[start:]] break elif initial in single_quoted or \ token[:2] in single_quoted or \ @@ -209,8 +206,7 @@ strstart = (lnum, start, line) endDFA = (endDFAs[initial] or endDFAs[token[1]] or endDFAs[token[2]]) - contstr, needcont = line[start:], 1 - contline = line + contstrs, needcont = [line[start:]], True break else: # ordinary string tok = Token(tokens.STRING, token, lnum, start, line) diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/pyparser/test/test_parser.py pypy-7.3.6+dfsg/pypy/interpreter/pyparser/test/test_parser.py --- pypy-7.3.5+dfsg/pypy/interpreter/pyparser/test/test_parser.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/pyparser/test/test_parser.py 2021-10-17 16:14:51.000000000 +0000 @@ -9,7 +9,7 @@ def test_char_set(): first = {5: None, 9: None, 100: None, 255:None} - p = parser.DFA(None, None, first) + p = parser.DFA(None, None, None, first) for i in range(256): assert p.could_match_token(i) == (i in first) @@ -58,10 +58,10 @@ value = "\n" else: value = "" - n = parser.Terminal(tp, value, 0, 0) + n = parser.Terminal(None, tp, value, 0, 0) else: tp = gram.symbol_ids[data[0]] - n = parser.Nonterminal(tp) + n = parser.Nonterminal(None, tp) new_indent = count_indent(line) if new_indent >= last_indent: if new_indent == last_indent and node_stack: diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/test/test_app_main.py pypy-7.3.6+dfsg/pypy/interpreter/test/test_app_main.py --- pypy-7.3.5+dfsg/pypy/interpreter/test/test_app_main.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/test/test_app_main.py 2021-10-17 16:14:51.000000000 +0000 @@ -150,6 +150,8 @@ self.check(['-S', '-tOV'], {}, output_contains='Python') self.check(['--jit', 'off', '-S'], {}, sys_argv=[''], run_stdin=True, no_site=1) + self.check(['-X', 'jit-off', '-S'], {}, sys_argv=[''], + run_stdin=True, no_site=1) self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass') self.check(['-cpass'], {}, sys_argv=['-c'], run_command='pass') self.check(['-cpass','x'], {}, sys_argv=['-c','x'], run_command='pass') @@ -231,6 +233,15 @@ self.check(['-X', 'track-resources'], {}, sys_argv=[''], run_stdin=True) assert myflag[0] == True + def test_jit_off(self, monkeypatch): + options = [None] + def set_jit_option(_, option, *args): + options[0] = option + from pypy.interpreter import app_main + monkeypatch.setattr(app_main, 'set_jit_option', set_jit_option, raising=False) + self.check(['-X', 'jit-off'], {}, sys_argv=[''], run_stdin=True) + assert options == ["off"] + class TestInteraction: """ These tests require pexpect (UNIX-only). diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/test/test_argument.py pypy-7.3.6+dfsg/pypy/interpreter/test/test_argument.py --- pypy-7.3.5+dfsg/pypy/interpreter/test/test_argument.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/test/test_argument.py 2021-10-17 16:14:51.000000000 +0000 @@ -722,6 +722,7 @@ assert s == "got multiple values for keyword argument 'bla'" class AppTestArgument: + @pytest.mark.pypy_only def test_error_message(self): exc = raises(TypeError, (lambda a, b=2: 0), b=3) assert exc.value.message == "() takes at least 1 non-keyword argument (0 given)" diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/test/test_compiler.py pypy-7.3.6+dfsg/pypy/interpreter/test/test_compiler.py --- pypy-7.3.5+dfsg/pypy/interpreter/test/test_compiler.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/test/test_compiler.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,4 +1,5 @@ import __future__ +import pytest import py, sys from pypy.interpreter.pycompiler import PythonAstCompiler from pypy.interpreter.pycode import PyCode @@ -345,6 +346,16 @@ ex.normalize_exception(self.space) assert ex.match(self.space, self.space.w_SyntaxError) + def test_future_error_offset(self): + space = self.space + with pytest.raises(OperationError) as excinfo: + self.compiler.compile("from __future__ import bogus", "tmp", "exec", 0) + ex = excinfo.value + assert ex.match(space, space.w_SyntaxError) + ex.normalize_exception(space) + w_exc = ex.get_w_value(space) + assert space.int_w(w_exc.w_offset) == 1 + def test_globals_warnings(self): space = self.space w_mod = space.appexec((), '():\n import warnings\n return warnings\n') #sys.getmodule('warnings') diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/test/test_gateway.py pypy-7.3.6+dfsg/pypy/interpreter/test/test_gateway.py --- pypy-7.3.5+dfsg/pypy/interpreter/test/test_gateway.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/test/test_gateway.py 2021-10-17 16:14:51.000000000 +0000 @@ -159,6 +159,9 @@ def method_with_unwrap_spec(self, space, x): pass + def method_with_args(self, space, __args__): + pass + class A(BaseA): def method(self, space, x): return space.wrap(x + 2) @@ -169,6 +172,9 @@ def method_with_unwrap_spec(self, space, x): return space.wrap(x + 2) + def method_with_args(self, space, __args__): + return space.wrap(42) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) @@ -179,6 +185,9 @@ def method_with_unwrap_spec(self, space, x): return space.wrap(x + 1) + def method_with_args(self, space, __args__): + return space.wrap(43) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -212,6 +221,17 @@ w_e = space.wrap(meth_with_unwrap_spec) assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + meth_with_args = gateway.interpindirect2app( + BaseA.method_with_args) + w_f = space.wrap(meth_with_args) + assert space.int_w(space.call_function(w_f, w_a)) == 42 + assert space.int_w(space.call_function(w_f, w_b, + space.wrap("ignored"))) == 43 + # check that the optimization works even though we are using + # interpindirect2app: + assert isinstance(meth_with_args._code, + gateway.BuiltinCodePassThroughArguments1) + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap diff -Nru pypy-7.3.5+dfsg/pypy/interpreter/test/test_syntax.py pypy-7.3.6+dfsg/pypy/interpreter/test/test_syntax.py --- pypy-7.3.5+dfsg/pypy/interpreter/test/test_syntax.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/interpreter/test/test_syntax.py 2021-10-17 16:14:51.000000000 +0000 @@ -663,6 +663,14 @@ else: raise Exception("no SyntaxError??") + def test_codegen_error_location(self): + try: + exec("if 1:\n break") + except SyntaxError as e: + assert e.lineno == 2 + assert e.text == " break" + assert e.offset == 6 + def test_bad_encoding(self): program = """ # -*- coding: uft-8 -*- diff -Nru pypy-7.3.5+dfsg/pypy/module/__builtin__/app_functional.py pypy-7.3.6+dfsg/pypy/module/__builtin__/app_functional.py --- pypy-7.3.5+dfsg/pypy/module/__builtin__/app_functional.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/__builtin__/app_functional.py 2021-10-17 16:14:51.000000000 +0000 @@ -46,6 +46,19 @@ empty, returns start.""" if isinstance(start, basestring): raise TypeError("sum() can't sum strings") + + # Avoiding isinstance here, since subclasses can override `+` + if type(start) is list: + return _list_sum(sequence, start) + + if type(start) is tuple: + return _tuple_sum(sequence, start) + + return _regular_sum(sequence, start) + + +def _regular_sum(sequence, start): + # Default implementation for sum (no specialization) last = start for x in sequence: # Very intentionally *not* +=, that would have different semantics if @@ -54,6 +67,53 @@ return last +def _list_sum(sequence, start): + # Specialization avoiding quadratic complexity for lists + iterator = iter(sequence) + + try: + first = next(iterator) + except StopIteration: + return start + + if type(first) is not list: + return _regular_sum(iterator, start + first) + + last = start + first + for item in iterator: + if type(item) is list: + last += item + else: + # Non-trivial sum. Use _regular_sum. + return _regular_sum(iterator, last + item) + + return last + + +def _tuple_sum(sequence, start): + # Specialization avoiding quadratic complexity for tuples + iterator = iter(sequence) + + try: + first = next(iterator) + except StopIteration: + return start + + if type(first) is not tuple: + return _regular_sum(iterator, start + first) + + last = list(start) + last.extend(first) + for item in iterator: + if type(item) is tuple: + last.extend(item) + else: + # Non-trivial sum. Cast back to tuple and use regular_sum. + return _regular_sum(iterator, tuple(last) + item) + + return tuple(last) + + class _Cons(object): def __init__(self, prev, iter): self.prev = prev diff -Nru pypy-7.3.5+dfsg/pypy/module/__builtin__/test/test_builtin.py pypy-7.3.6+dfsg/pypy/module/__builtin__/test/test_builtin.py --- pypy-7.3.5+dfsg/pypy/module/__builtin__/test/test_builtin.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/__builtin__/test/test_builtin.py 2021-10-17 16:14:51.000000000 +0000 @@ -226,6 +226,86 @@ return 42 assert sum([Foo()], None) == 42 + def test_sum_fast_path(self): + # Fast paths for expected behaviour + start = [] + assert sum([[1, 2], [3]], start) == [1, 2, 3] + assert start == [] + + start = [1, 2] + assert sum([[3]], start) == [1, 2, 3] + assert start == [1, 2] + + assert sum([(1, 2), (3,)], ()) == (1, 2, 3) + assert sum([(3,)], (1, 2)) == (1, 2, 3) + assert sum(([x + 1] for x in range(3)), []) == [1, 2, 3] + + def test_sum_empty_edge_cases(self): + assert sum([], []) == [] + assert sum(iter([]), []) == [] + assert sum([], ()) == () + start = [] + assert sum([], start) is start + assert sum([[]], start) is not start + + def test_sum_type_errors(self): + with raises(TypeError): + sum([[]], ()) + with raises(TypeError): + sum([()], []) + with raises(TypeError): + sum([[], [], ()], []) + + def test_sum_strange_objects(self): + # All that follows should be rare, but needs care + class TupleTail(object): + def __radd__(self, other): + assert isinstance(other, tuple) + return other[1:] + + strange_seq = [(1, 2), (3, 4), TupleTail(), (5,)] + assert sum(strange_seq, (2, 3, 4, 5)) + assert sum(iter(strange_seq), (2, 3, 4, 5)) + + class NotAList(list): + def __add__(self, _): + return "!" + + def __radd__(self, _): + return "?" + + def __iadd__(self, _): + raise RuntimeError( + "Calling __iadd__ breaks CPython compatability" + ) + + assert sum([[1]], NotAList()) == "!" + assert sum([[1], NotAList()], []) == "?" + + def test_sum_first_object_edge_cases(self): + class X(list): + def __radd__(self, other): + return Y() + + class Y(object): + calls = [] + + def __add__(self, other): + Y.calls.append("add") + + def __iadd__(self, other): + Y.calls.append("iadd") + + assert sum([X(), []], []) is None + assert Y.calls == ["add"] + + class Z(tuple): + def __radd__(self, other): + return Y() + + assert sum([Z(), []], []) is None + assert Y.calls == ["add", "add"] + def test_type_selftest(self): assert type(type) is type diff -Nru pypy-7.3.5+dfsg/pypy/module/_cffi_backend/__init__.py pypy-7.3.6+dfsg/pypy/module/_cffi_backend/__init__.py --- pypy-7.3.5+dfsg/pypy/module/_cffi_backend/__init__.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_cffi_backend/__init__.py 2021-10-17 16:14:51.000000000 +0000 @@ -1 +1 @@ -VERSION = "1.14.5" +VERSION = "1.14.6" diff -Nru pypy-7.3.5+dfsg/pypy/module/_cffi_backend/test/_backend_test_c.py pypy-7.3.6+dfsg/pypy/module/_cffi_backend/test/_backend_test_c.py --- pypy-7.3.5+dfsg/pypy/module/_cffi_backend/test/_backend_test_c.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_cffi_backend/test/_backend_test_c.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.14.5", ("This test_c.py file is for testing a version" +assert __version__ == "1.14.6", ("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,): @@ -1350,6 +1350,8 @@ try: linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests sys.stderr = cStringIO.StringIO() + if hasattr(sys, '__unraisablehook__'): # work around pytest + sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons assert f(100) == 300 assert sys.stderr.getvalue() == '' assert f(10000) == -42 @@ -1436,6 +1438,8 @@ sys.stderr = cStringIO.StringIO() seen = "not a list" # this makes the oops() function crash assert ff(bigvalue) == -42 + # the $ after the AttributeError message are for the suggestions that + # will be added in Python 3.10 assert matches(sys.stderr.getvalue(), """\ From cffi callback : Trying to convert the result back to C: @@ -1446,7 +1450,7 @@ Traceback (most recent call last): File "$", line $, in oops $ -AttributeError: 'str' object has no attribute 'append' +AttributeError: 'str' object has no attribute 'append$ """, """\ Exception ignored from cffi callback , trying to convert the result back to C: Traceback (most recent call last): @@ -1457,7 +1461,7 @@ Traceback (most recent call last): File "$", line $, in oops $ -AttributeError: 'str' object has no attribute 'append' +AttributeError: 'str' object has no attribute 'append$ """) finally: sys.stderr = orig_stderr diff -Nru pypy-7.3.5+dfsg/pypy/module/_collections/interp_deque.py pypy-7.3.6+dfsg/pypy/module/_collections/interp_deque.py --- pypy-7.3.5+dfsg/pypy/module/_collections/interp_deque.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_collections/interp_deque.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,12 +1,14 @@ import sys + from rpython.rlib.objectmodel import specialize +from rpython.rlib import jit +from rpython.rlib.debug import check_nonneg from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.typedef import GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, oefmt -from rpython.rlib.debug import check_nonneg # A `dequeobject` is composed of a doubly-linked list of `block` nodes. @@ -50,6 +52,11 @@ class Lock(object): pass + +def get_printable_location(tp): + return "deque._find [%s]" % (tp.getname(tp.space), ) +find_jmp = jit.JitDriver(greens=['tp'], reds='auto', name='deque._find', get_printable_location=get_printable_location) + # ------------------------------------------------------------ class W_Deque(W_Root): @@ -243,25 +250,33 @@ self.modified() return w_obj - def remove(self, w_x): - "Remove first occurrence of value." + def _find(self, w_x): space = self.space block = self.leftblock index = self.leftindex lock = self.getlock() + tp = space.type(w_x) for i in range(self.len): + find_jmp.jit_merge_point(tp=tp) w_item = block.data[index] equal = space.eq_w(w_item, w_x) self.checklock(lock) if equal: - self.del_item(i) - return + return i # Advance the block/index pair index += 1 if index >= BLOCKLEN: block = block.rightlink index = 0 - raise oefmt(space.w_ValueError, "deque.remove(x): x not in deque") + return -1 + + def remove(self, w_x): + "Remove first occurrence of value." + i = self._find(w_x) + if i < 0: + raise oefmt(self.space.w_ValueError, + "deque.remove(x): x not in deque") + self.del_item(i) def reverse(self): "Reverse *IN PLACE*." diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/api.py pypy-7.3.6+dfsg/pypy/module/cpyext/api.py --- pypy-7.3.5+dfsg/pypy/module/cpyext/api.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/api.py 2021-10-17 16:14:51.000000000 +0000 @@ -31,7 +31,7 @@ from pypy.module.micronumpy.base import W_NDimArray from pypy.module.__pypy__.interp_buffer import W_Bufferable from rpython.rlib.entrypoint import entrypoint_lowlevel -from rpython.rlib.rposix import FdValidator +from rpython.rlib.rposix import SuppressIPH from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.objectmodel import specialize from pypy.module.exceptions import interp_exceptions @@ -100,27 +100,27 @@ def fclose(fp): try: - with FdValidator(c_fileno(fp)): + with SuppressIPH(): return c_fclose(fp) except IOError: return -1 def fwrite(buf, sz, n, fp): - with FdValidator(c_fileno(fp)): + with SuppressIPH(): return c_fwrite(buf, sz, n, fp) def fread(buf, sz, n, fp): - with FdValidator(c_fileno(fp)): + with SuppressIPH(): return c_fread(buf, sz, n, fp) _feof = rffi.llexternal('feof', [FILEP], rffi.INT) def feof(fp): - with FdValidator(c_fileno(fp)): + with SuppressIPH(): return _feof(fp) _ferror = rffi.llexternal('ferror', [FILEP], rffi.INT) def ferror(fp): - with FdValidator(c_fileno(fp)): + with SuppressIPH(): return _ferror(fp) pypy_decl = 'pypy_decl.h' @@ -136,6 +136,7 @@ Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_HAVE_NEWBUFFER Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES Py_MAX_NDIMS PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_READ PyBUF_WRITE +PY_SSIZE_T_MAX PY_SSIZE_T_MIN """.split() for name in ('INT', 'LONG', 'LIST', 'TUPLE', 'UNICODE', 'DICT', 'BASE_EXC', @@ -970,8 +971,9 @@ gil_release = (gil == "release" or gil == "around") pygilstate_ensure = (gil == "pygilstate_ensure") pygilstate_release = (gil == "pygilstate_release") + pygilstate_check = (gil == "pygilstate_check") assert (gil is None or gil_acquire or gil_release - or pygilstate_ensure or pygilstate_release) + or pygilstate_ensure or pygilstate_release or pygilstate_check) expected_nb_args = len(argtypesw) + pygilstate_ensure if isinstance(restype, lltype.Ptr) and error_value == 0: @@ -1010,6 +1012,9 @@ else: rgil.acquire() args += (pystate.PyGILState_UNLOCKED,) + elif pygilstate_check: + result = rgil.am_I_holding_the_GIL() + return rffi.cast(restype, result) else: if not rgil.am_I_holding_the_GIL(): no_gil_error(pname) diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/include/patchlevel.h pypy-7.3.6+dfsg/pypy/module/cpyext/include/patchlevel.h --- pypy-7.3.5+dfsg/pypy/module/cpyext/include/patchlevel.h 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/include/patchlevel.h 2021-10-17 16:14:54.000000000 +0000 @@ -32,8 +32,8 @@ * module/sys/version.py * doc/conf.py */ -#define PYPY_VERSION "7.3.5" -#define PYPY_VERSION_NUM 0x07030500 +#define PYPY_VERSION "7.3.6" +#define PYPY_VERSION_NUM 0x07030600 /* Defined to mean a PyPy where cpyext holds more regular references to PyObjects, e.g. staying alive as long as the internal PyPy object stays alive. */ diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/number.py pypy-7.3.6+dfsg/pypy/module/cpyext/number.py --- pypy-7.3.5+dfsg/pypy/module/cpyext/number.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/number.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,5 +1,7 @@ from pypy.interpreter.error import OperationError, oefmt -from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, Py_ssize_t +from pypy.module.cpyext.api import ( + cpython_api, CANNOT_FAIL, Py_ssize_t, PyVarObject, PY_SSIZE_T_MAX, + PY_SSIZE_T_MIN) from pypy.module.cpyext.pyobject import PyObject, PyObjectP, from_ref, make_ref from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import widen @@ -40,7 +42,22 @@ exception is cleared and the value is clipped to PY_SSIZE_T_MIN for a negative integer or PY_SSIZE_T_MAX for a positive integer. """ - return space.int_w(w_obj) #XXX: this is wrong on win64 + try: + return space.int_w(w_obj) #XXX: this is wrong on win64 + except OperationError as e: + if e.match(space, space.w_OverflowError): + if not w_exc: + # CPython does _PyLong_Sign(value) < 0 which is equivalent to + # Py_SIZE(value) < 0 which is value->ob_size + pyobj = make_ref(space, w_obj) + if rffi.cast(PyVarObject, pyobj).c_ob_size < 0: + return PY_SSIZE_T_MIN + else: + return PY_SSIZE_T_MAX + else: + raise oefmt(w_exc, "cannot fit '%T' into an index-sized integer", w_obj) + else: + raise @cpython_api([PyObject], PyObject) def PyNumber_Int(space, w_obj): diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/pystate.py pypy-7.3.6+dfsg/pypy/module/cpyext/pystate.py --- pypy-7.3.5+dfsg/pypy/module/cpyext/pystate.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/pystate.py 2021-10-17 16:14:51.000000000 +0000 @@ -248,6 +248,11 @@ space.threadlocals.get_ec = get_possibly_deleted_ec +@cpython_api([], rffi.INT_real, error=CANNOT_FAIL, gil="pygilstate_check") +def PyGILState_Check(space): + assert False, "the logic is completely inside wrapper_second_level" + + @cpython_api([], PyGILState_STATE, error=CANNOT_FAIL, gil="pygilstate_ensure") def PyGILState_Ensure(space, previous_state): # The argument 'previous_state' is not part of the API; it is inserted diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/test/test_number.py pypy-7.3.6+dfsg/pypy/module/cpyext/test/test_number.py --- pypy-7.3.5+dfsg/pypy/module/cpyext/test/test_number.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/test/test_number.py 2021-10-17 16:14:51.000000000 +0000 @@ -211,3 +211,32 @@ pass else: assert False, 'expected TypeError' + + def test_number_to_ssize_t(self): + import sys + mod = self.import_extension('foo', [ + ("to_ssize_t", "METH_VARARGS", + """ + PyObject *obj; + PyObject *exc = NULL; + long long value; + if (!PyArg_ParseTuple(args, "O|O:to_ssize_t", + &obj, &exc)) { + return NULL; + } + if (exc == NULL) { + printf("got no exc\\n"); + } else { + printf("got exc\\n"); + } + value = PyNumber_AsSsize_t(obj, exc); + if (PyErr_Occurred()) { + return NULL; + } + return PyLong_FromLongLong(value); + """)]) + assert mod.to_ssize_t(2 ** 68) == sys.maxsize + assert mod.to_ssize_t(12) == 12 + raises(TypeError, mod.to_ssize_t, 2 ** 68, TypeError) + + diff -Nru pypy-7.3.5+dfsg/pypy/module/cpyext/test/test_pystate.py pypy-7.3.6+dfsg/pypy/module/cpyext/test/test_pystate.py --- pypy-7.3.5+dfsg/pypy/module/cpyext/test/test_pystate.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/cpyext/test/test_pystate.py 2021-10-17 16:14:51.000000000 +0000 @@ -156,6 +156,8 @@ if (tstate == NULL) { return PyLong_FromLong(0); } + if (PyGILState_Check() != 0) + return PyLong_FromLong(-1); dict = PyThreadState_GetDict(); if (dict != NULL) { return PyLong_FromLong(1); @@ -165,12 +167,18 @@ if (dict == NULL) { return PyLong_FromLong(2); } + if (PyGILState_Check() != 1) + return PyLong_FromLong(-2); PyGILState_Release(gilstate); + if (PyGILState_Check() != 0) + return PyLong_FromLong(-3); PyEval_RestoreThread(tstate); if (PyThreadState_Get() != tstate) { return PyLong_FromLong(3); } + if (PyGILState_Check() != 1) + return PyLong_FromLong(-4); return PyLong_FromLong(4); """)]) diff -Nru pypy-7.3.5+dfsg/pypy/module/_multiprocessing/moduledef.py pypy-7.3.6+dfsg/pypy/module/_multiprocessing/moduledef.py --- pypy-7.3.5+dfsg/pypy/module/_multiprocessing/moduledef.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_multiprocessing/moduledef.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,5 +1,4 @@ import sys - from pypy.interpreter.mixedmodule import MixedModule class Module(MixedModule): @@ -19,7 +18,6 @@ 'interp_connection.W_PipeConnection' interpleveldefs['win32'] = 'interp_win32.win32_namespace(space)' - def init(self, space): - MixedModule.init(self, space) + def startup(self, space): from pypy.module._multiprocessing.interp_connection import State space.fromcache(State).init(space) diff -Nru pypy-7.3.5+dfsg/pypy/module/parser/pyparser.py pypy-7.3.6+dfsg/pypy/module/parser/pyparser.py --- pypy-7.3.5+dfsg/pypy/module/parser/pyparser.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/parser/pyparser.py 2021-10-17 16:14:51.000000000 +0000 @@ -143,7 +143,7 @@ def __init__(self): self.lineno = 0 -def build_node_tree(space, w_tuple): +def build_node_tree(space, parser, w_tuple): tup_w = space.unpackiterable(w_tuple) if len(tup_w) == 0: raise parser_error(space, w_tuple, "tuple too short") @@ -155,10 +155,10 @@ # Raise an exception now and be done with it. raise parser_error(space, w_tuple, "Illegal syntax-tree; cannot start with terminal symbol.") - return build_node_children(space, type, tup_w, node_state) + return build_node_children(space, parser, type, tup_w, node_state) -def build_node_children(space, type, tup_w, node_state): - node = pyparse.parser.Nonterminal(type) +def build_node_children(space, parser, type, tup_w, node_state): + node = pyparse.parser.Nonterminal(parser.grammar, type) for i in range(1, len(tup_w)): w_elem = tup_w[i] subtup_w = space.unpackiterable(w_elem) @@ -173,9 +173,9 @@ raise parse_error( space, "terminal nodes must have 2 or 3 entries") strn = space.text_w(w_obj) - child = pyparse.parser.Terminal(type, strn, node_state.lineno, 0) + child = pyparse.parser.Terminal(parser.grammar, type, strn, node_state.lineno, 0) else: - child = build_node_children(space, type, subtup_w, node_state) + child = build_node_children(space, parser, type, subtup_w, node_state) node.append_child(child) if type == pyparse.pygram.tokens.NEWLINE: node_state.lineno += 1 @@ -210,7 +210,7 @@ def tuple2st(space, w_sequence): # Convert the tree to the internal form before checking it - tree = build_node_tree(space, w_sequence) parser = pyparse.PythonParser(space) + tree = build_node_tree(space, parser, w_sequence) validate_node(space, tree, parser) return W_STType(tree, 'eval') diff -Nru pypy-7.3.5+dfsg/pypy/module/posix/app_posix.py pypy-7.3.6+dfsg/pypy/module/posix/app_posix.py --- pypy-7.3.5+dfsg/pypy/module/posix/app_posix.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/posix/app_posix.py 2021-10-17 16:14:51.000000000 +0000 @@ -78,6 +78,7 @@ f_favail = structseqfield(7) f_flag = structseqfield(8) f_namemax = structseqfield(9) + # f_fsid = structseqfield(10) # not python2 compatible # Capture file.fdopen at import time, as some code replaces # __builtins__.file with a custom function. diff -Nru pypy-7.3.5+dfsg/pypy/module/posix/interp_posix.py pypy-7.3.6+dfsg/pypy/module/posix/interp_posix.py --- pypy-7.3.5+dfsg/pypy/module/posix/interp_posix.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/posix/interp_posix.py 2021-10-17 16:14:51.000000000 +0000 @@ -253,7 +253,8 @@ vals_w = [None] * len(rposix_stat.STATVFS_FIELDS) for i, (name, _) in STATVFS_FIELDS: vals_w[i] = space.newint(getattr(st, name)) - w_tuple = space.newtuple(vals_w) + # f_fsid is not python2-compatible + w_tuple = space.newtuple(vals_w[:-1]) w_statvfs_result = space.getattr(space.getbuiltinmodule(os.name), space.newtext('statvfs_result')) return space.call_function(w_statvfs_result, w_tuple) @@ -534,27 +535,32 @@ @unwrap_spec(name='text0', value='text0') def putenv(space, name, value): """Change or add an environment variable.""" - # Search from index 1 because on Windows starting '=' is allowed for - # defining hidden environment variables. if _WIN32: + # Search from index 1 because on Windows starting '=' is allowed + # in general (see os.chdir which sets '=D:' for chdir(r'D:\temp') + # However it is a bit pointless here since the putenv system call + # hides the key/value. + # GetEnvironmentVariable/SetEnvironmentVariable will expose them, + # and as is mentioned in https://github.com/python/cpython/pull/2325#discussion_r674746677, + # someday the syscall may change to SetEnvironmentVariable here. if len(name) == 0 or '=' in name[1:]: raise oefmt(space.w_ValueError, "illegal environment variable name") + if len(name) > _MAX_ENV: + raise oefmt(space.w_ValueError, + "the environment variable is longer than %d bytes", + _MAX_ENV) + if not objectmodel.we_are_translated() and value == '': + # special case: on Windows, _putenv("NAME=") really means that + # we want to delete NAME. So that's what the os.environ[name]='' + # below will do after translation. But before translation, it + # will cache the environment value '' instead of and + # then return that. We need to avoid that. + del os.environ[name] + return else: if '=' in name: raise oefmt(space.w_ValueError, "illegal environment variable name") - if _WIN32 and len(name) > _MAX_ENV: - raise oefmt(space.w_ValueError, - "the environment variable is longer than %d bytes", - _MAX_ENV) - if _WIN32 and not objectmodel.we_are_translated() and value == '': - # special case: on Windows, _putenv("NAME=") really means that - # we want to delete NAME. So that's what the os.environ[name]='' - # below will do after translation. But before translation, it - # will cache the environment value '' instead of and - # then return that. We need to avoid that. - del os.environ[name] - return try: os.environ[name] = value except OSError as e: @@ -829,6 +835,22 @@ env[space.text0_w(w_key)] = space.text0_w(w_value) return env +def _env2interp(space, w_env): + env = {} + w_keys = space.call_method(w_env, 'keys') + for w_key in space.unpackiterable(w_keys): + w_value = space.getitem(w_env, w_key) + key = space.text0_w(w_key) + val = space.text0_w(w_value) + # Search from index 1 because on Windows starting '=' is allowed for + # defining hidden environment variables + if len(key) == 0 or '=' in key[1:]: + raise oefmt(space.w_ValueError, + "illegal environment variable name") + env[key] = val + return env + + @unwrap_spec(command='fsencode') def execve(space, command, w_args, w_env): """ execve(path, args, env) diff -Nru pypy-7.3.5+dfsg/pypy/module/posix/test/test_posix2.py pypy-7.3.6+dfsg/pypy/module/posix/test/test_posix2.py --- pypy-7.3.5+dfsg/pypy/module/posix/test/test_posix2.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/posix/test/test_posix2.py 2021-10-17 16:14:51.000000000 +0000 @@ -1218,7 +1218,7 @@ def test_putenv_invalid_name(self): import os, sys if sys.platform.startswith('win'): - os.putenv("=hidden", "foo") + raises(OSError, os.putenv, "=foo", "xxx") raises(ValueError, os.putenv, "foo=bar", "xxx") else: raises(ValueError, os.putenv, "=foo", "xxx") diff -Nru pypy-7.3.5+dfsg/pypy/module/pypyjit/test_pypy_c/test_call.py pypy-7.3.6+dfsg/pypy/module/pypyjit/test_pypy_c/test_call.py --- pypy-7.3.5+dfsg/pypy/module/pypyjit/test_pypy_c/test_call.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/pypyjit/test_pypy_c/test_call.py 2021-10-17 16:14:51.000000000 +0000 @@ -554,6 +554,26 @@ assert len(calls) == 0 assert len([op for op in allops if op.name.startswith('new')]) == 0 + def test_kwargs_update_virtual1(self): + log = self.run(""" + def f(**kwargs): + return len(kwargs) + def main(stop): + i = 0 + res = 0 + while i < stop: + d = {'a': 1, 'b': 2} + # used to force the dict! + res += f(c=2, **d) # ID: call + i += 1 + return res + """, [1000]) + loop, = log.loops_by_id('call') + ops = loop.ops_by_id('call') + assert log.opnames(ops) == ["guard_not_invalidated", "force_token", + "int_add_ovf", "guard_no_overflow"] + + def test_kwargs_non_virtual(self): log = self.run(""" def f(a, b, c): diff -Nru pypy-7.3.5+dfsg/pypy/module/pypyjit/test_pypy_c/test_instance.py pypy-7.3.6+dfsg/pypy/module/pypyjit/test_pypy_c/test_instance.py --- pypy-7.3.5+dfsg/pypy/module/pypyjit/test_pypy_c/test_instance.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/pypyjit/test_pypy_c/test_instance.py 2021-10-17 16:14:51.000000000 +0000 @@ -343,8 +343,10 @@ guard_value(p67, ConstPtr(ptr68), descr=...) # promote map guard_not_invalidated(descr=...) p69 = getfield_gc_r(p63, descr=...) # value0 - f71 = getarrayitem_gc_f(p69, 0, descr=...) # x - f73 = getarrayitem_gc_f(p69, 1, descr=...) # y + i71 = getarrayitem_gc_i(p69, 0, descr=...) # x + f71 = convert_longlong_bytes_to_float(i71) + i73 = getarrayitem_gc_i(p69, 1, descr=...) # y + f73 = convert_longlong_bytes_to_float(i73) f74 = float_add(f71, f73) # add them f75 = float_add(f57, f74) --TICK-- @@ -367,10 +369,12 @@ guard_value(p60, ConstPtr(ptr61), descr=...) guard_not_invalidated(descr=...) p62 = getfield_gc_r(p56, descr=...) # value - f64 = getarrayitem_gc_f(p62, 0, descr=...) # x + i64 = getarrayitem_gc_i(p62, 0, descr=...) # x + f64 = convert_longlong_bytes_to_float(i64) f66 = float_add(f64, 3.400000) + i66 = convert_float_bytes_to_longlong(f66) i68 = getfield_raw_i(..., descr=...) - setarrayitem_gc(p62, 0, f66, descr=...) # store x + setarrayitem_gc(p62, 0, i66, descr=...) # store x i71 = int_lt(i68, 0) guard_false(i71, descr=...) """) diff -Nru pypy-7.3.5+dfsg/pypy/module/_pypyjson/interp_decoder.py pypy-7.3.6+dfsg/pypy/module/_pypyjson/interp_decoder.py --- pypy-7.3.5+dfsg/pypy/module/_pypyjson/interp_decoder.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_pypyjson/interp_decoder.py 2021-10-17 16:14:51.000000000 +0000 @@ -498,7 +498,10 @@ # may be a surrogate pair return self.decode_escape_sequence_unicode(i, stringbuilder) else: - self._raise("Invalid \\escape: %s (char %d)", ch, i-1) + if ch <= ' ': + self._raise("Invalid \\escape: (char %d)", i-2) + else: + self._raise("Invalid \\escape: %s (char %d)", ch, i-2) return i def _get_int_val_from_hex4(self, i): diff -Nru pypy-7.3.5+dfsg/pypy/module/_pypyjson/test/test__pypyjson.py pypy-7.3.6+dfsg/pypy/module/_pypyjson/test/test__pypyjson.py --- pypy-7.3.5+dfsg/pypy/module/_pypyjson/test/test__pypyjson.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/_pypyjson/test/test__pypyjson.py 2021-10-17 16:14:51.000000000 +0000 @@ -525,6 +525,9 @@ ('["]', 'Unterminated string starting at char 1'), ('["spam":', "Unexpected ':' when decoding array (char 7)"), ('[{]', "Key name must be string at char 2"), + ('"\\X"', "Invalid \\escape: X (char 1)"), + ('"\\ "', "Invalid \\escape: (char 1)"), + ('"\\', "Invalid \\escape: (char 1)"), ] for inputtext, errmsg in test_cases: exc = raises(ValueError, _pypyjson.loads, inputtext) diff -Nru pypy-7.3.5+dfsg/pypy/module/struct/test/test_struct.py pypy-7.3.6+dfsg/pypy/module/struct/test/test_struct.py --- pypy-7.3.5+dfsg/pypy/module/struct/test/test_struct.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/struct/test/test_struct.py 2021-10-17 16:14:51.000000000 +0000 @@ -462,6 +462,12 @@ assert val == sys.maxint+1 assert type(val) is long + def test_bpo35714(self): + # why not "bad char in struct format"?? + for s in '\0', '2\0i', b'\0': + exc = raises(self.struct.error, self.struct.calcsize, s) + assert str(exc.value) == 'embedded null character' + class AppTestStructBuffer(object): spaceconfig = dict(usemodules=['struct', '__pypy__']) diff -Nru pypy-7.3.5+dfsg/pypy/module/sys/test/test_version.py pypy-7.3.6+dfsg/pypy/module/sys/test/test_version.py --- pypy-7.3.5+dfsg/pypy/module/sys/test/test_version.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/sys/test/test_version.py 2021-10-17 16:14:51.000000000 +0000 @@ -5,6 +5,14 @@ "GCC " in sys.version or "(untranslated)" in sys.version) + def test_version_info(self): + import sys + assert str(sys.version_info).startswith('sys.version_info') + + def test_pypy_version_info(self): + import sys + assert str(sys.pypy_version_info).startswith('sys.pypy_version_info') + def test_get_version(): from pypy.module.sys import version res = version._make_version_template(PYPY_VERSION=(2,5,0, "final", 1)) diff -Nru pypy-7.3.5+dfsg/pypy/module/sys/version.py pypy-7.3.6+dfsg/pypy/module/sys/version.py --- pypy-7.3.5+dfsg/pypy/module/sys/version.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/sys/version.py 2021-10-17 16:14:54.000000000 +0000 @@ -13,7 +13,7 @@ # make sure to keep PYPY_VERSION in sync with: # module/cpyext/include/patchlevel.h # doc/conf.py -PYPY_VERSION = (7, 3, 5, "final", 0) +PYPY_VERSION = (7, 3, 6, "final", 0) import pypy @@ -35,6 +35,20 @@ from _structseq import structseqtype, structseqfield class version_info: __metaclass__ = structseqtype + __module__ = 'sys' + name = 'sys.version_info' + + major = structseqfield(0, "Major release number") + minor = structseqfield(1, "Minor release number") + micro = structseqfield(2, "Patch release number") + releaselevel = structseqfield(3, + "'alpha', 'beta', 'candidate', or 'release'") + serial = structseqfield(4, "Serial release number") + +class pypy_version_info: + __metaclass__ = structseqtype + __module__ = 'sys' + name = 'sys.pypy_version_info' major = structseqfield(0, "Major release number") minor = structseqfield(1, "Minor release number") @@ -81,7 +95,7 @@ def get_pypy_version_info(space): ver = PYPY_VERSION - w_version_info = app.wget(space, "version_info") + w_version_info = app.wget(space, "pypy_version_info") # run at translation time return space.call_function(w_version_info, space.wrap(ver)) diff -Nru pypy-7.3.5+dfsg/pypy/module/test_lib_pypy/test_greenlet_thread.py pypy-7.3.6+dfsg/pypy/module/test_lib_pypy/test_greenlet_thread.py --- pypy-7.3.5+dfsg/pypy/module/test_lib_pypy/test_greenlet_thread.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/test_lib_pypy/test_greenlet_thread.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -import py -try: - import thread, time - from lib_pypy import greenlet - #import greenlet -except ImportError as e: - py.test.skip(e) - - -class TestThread: - - def test_cannot_switch_to_main_of_different_thread(self): - mains = [] - mains.append(greenlet.getcurrent()) - lock = thread.allocate_lock() - lock.acquire() - got_exception = [] - # - def run_thread(): - main = greenlet.getcurrent() - assert main not in mains - mains.append(main) - try: - mains[0].switch() - except Exception as e: - got_exception.append(e) - lock.release() - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - assert isinstance(got_exception[0], greenlet.error) - - def test_nonstarted_greenlet_is_still_attached_to_thread(self): - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g = greenlet.greenlet(lambda *args: None) - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - py.test.raises(greenlet.error, g.switch) - - def test_noninited_greenlet_is_still_attached_to_thread(self): - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g = greenlet.greenlet.__new__(greenlet.greenlet) - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - py.test.raises(greenlet.error, g.switch) - g.__init__(lambda *args: None) - py.test.raises(greenlet.error, g.switch) - - def test_noninited_greenlet_change_thread_via_parent(self): - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g = greenlet.greenlet.__new__(greenlet.greenlet) - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - g.__init__(lambda *args: 44) - g.parent = greenlet.getcurrent() - x = g.switch() - assert x == 44 - - def test_nonstarted_greenlet_change_thread_via_parent(self): - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g = greenlet.greenlet(lambda *args: 42) - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - g.parent = greenlet.getcurrent() - x = g.switch() - assert x == 42 - - def test_started_greenlet_cannot_change_thread_via_parent(self): - py.test.skip("not implemented on PyPy") - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g_parent = greenlet.getcurrent() - g = greenlet.greenlet(lambda *args: g_parent.switch(42)) - x = g.switch() - assert x == 42 - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - with py.test.raises(ValueError) as e: - g.parent = greenlet.getcurrent() - assert str(e.value) == "parent cannot be on a different thread" - - def test_finished_greenlet_cannot_change_thread_via_parent(self): - py.test.skip("not implemented on PyPy") - subs = [] - lock = thread.allocate_lock() - lock.acquire() - # - def run_thread(): - g = greenlet.greenlet(lambda *args: 42) - x = g.switch() - assert x == 42 - subs.append(g) - lock.release() - time.sleep(1) - # - thread.start_new_thread(run_thread, ()) - lock.acquire() - [g] = subs - with py.test.raises(ValueError) as e: - g.parent = greenlet.getcurrent() - assert str(e.value) == "parent cannot be on a different thread" diff -Nru pypy-7.3.5+dfsg/pypy/module/test_lib_pypy/test_greenlet_tracing.py pypy-7.3.6+dfsg/pypy/module/test_lib_pypy/test_greenlet_tracing.py --- pypy-7.3.5+dfsg/pypy/module/test_lib_pypy/test_greenlet_tracing.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/module/test_lib_pypy/test_greenlet_tracing.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -import py -try: - from lib_pypy import greenlet -except ImportError as e: - py.test.skip(e) - -class SomeError(Exception): - pass - -class TestTracing: - def test_greenlet_tracing(self): - main = greenlet.getcurrent() - actions = [] - def trace(*args): - actions.append(args) - def dummy(): - pass - def dummyexc(): - raise SomeError() - oldtrace = greenlet.settrace(trace) - try: - g1 = greenlet.greenlet(dummy) - g1.switch() - g2 = greenlet.greenlet(dummyexc) - py.test.raises(SomeError, g2.switch) - finally: - greenlet.settrace(oldtrace) - assert actions == [ - ('switch', (main, g1)), - ('switch', (g1, main)), - ('switch', (main, g2)), - ('throw', (g2, main)), - ] - - def test_exception_disables_tracing(self): - main = greenlet.getcurrent() - actions = [] - def trace(*args): - actions.append(args) - raise SomeError() - def dummy(): - main.switch() - g = greenlet.greenlet(dummy) - g.switch() - oldtrace = greenlet.settrace(trace) - try: - py.test.raises(SomeError, g.switch) - assert greenlet.gettrace() is None - finally: - greenlet.settrace(oldtrace) - assert actions == [ - ('switch', (main, g)), - ] diff -Nru pypy-7.3.5+dfsg/pypy/objspace/fake/checkmodule.py pypy-7.3.6+dfsg/pypy/objspace/fake/checkmodule.py --- pypy-7.3.5+dfsg/pypy/objspace/fake/checkmodule.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/fake/checkmodule.py 2021-10-17 16:14:51.000000000 +0000 @@ -16,7 +16,6 @@ # force computation and record what we wrap module = mod.Module(space, W_Root()) module.setup_after_space_initialization() - module.init(space) modules.append(module) for name in module.loaders: if name in ignore: diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/listobject.py pypy-7.3.6+dfsg/pypy/objspace/std/listobject.py --- pypy-7.3.5+dfsg/pypy/objspace/std/listobject.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/listobject.py 2021-10-17 16:14:51.000000000 +0000 @@ -3,7 +3,7 @@ Lists optimize their storage by holding certain primitive datatypes in unwrapped form. For more information: -http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html +https://www.pypy.org/posts/2011/10/more-compact-lists-with-list-strategies-8229304944653956829.html """ @@ -1354,6 +1354,10 @@ def unwrap(self, wrapped): raise NotImplementedError + def _quick_cmp(self, a, b): + """ do a quick comparison between two unwrapped elements. """ + raise NotImplementedError("abstract base class") + @staticmethod def unerase(storage): raise NotImplementedError("abstract base class") @@ -1418,15 +1422,29 @@ raise return self.wrap(r) - @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), - UNROLL_CUTOFF)) def getitems_copy(self, w_list): - return [self.wrap(item) for item in self.unerase(w_list.lstorage)] + storage = self.unerase(w_list.lstorage) + if len(storage) == 0: + return [] + res = [None] * len(storage) + prevvalue = storage[0] + w_item = self.wrap(prevvalue) + res[0] = w_item + for index in range(1, len(storage)): + item = storage[index] + if jit.we_are_jitted() or not self._quick_cmp(item, prevvalue): + prevvalue = item + w_item = self.wrap(item) + res[index] = w_item + return res + + getitems_unroll = jit.unroll_safe( + func_with_new_name(getitems_copy, "getitems_unroll")) + + getitems_copy = jit.look_inside_iff(lambda self, w_list: + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF))(getitems_copy) - @jit.unroll_safe - def getitems_unroll(self, w_list): - return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @jit.look_inside_iff(lambda self, w_list: jit.loop_unrolling_heuristic(w_list, w_list.length(), @@ -1655,10 +1673,25 @@ def wrap(self, item): return item + def _quick_cmp(self, a, b): + return a is b + erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) + @jit.look_inside_iff(lambda self, w_list: + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) + def getitems_copy(self, w_list): + storage = self.unerase(w_list.lstorage) + return storage[:] + + @jit.unroll_safe + def getitems_unroll(self, w_list): + storage = self.unerase(w_list.lstorage) + return storage[:] + def is_correct_type(self, w_obj): return True @@ -1692,6 +1725,9 @@ def unwrap(self, w_int): return self.space.int_w(w_int) + def _quick_cmp(self, a, b): + return a == b + erase, unerase = rerased.new_erasing_pair("integer") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -1792,6 +1828,9 @@ erase = staticmethod(erase) unerase = staticmethod(unerase) + def _quick_cmp(self, a, b): + return longlong2float.float2longlong(a) == longlong2float.float2longlong(b) + def is_correct_type(self, w_obj): return type(w_obj) is W_FloatObject @@ -1905,6 +1944,9 @@ floatval = self.space.float_w(w_int_or_float) return longlong2float.float2longlong(floatval) + def _quick_cmp(self, a, b): + return a == b + erase, unerase = rerased.new_erasing_pair("longlong") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -2005,6 +2047,9 @@ def unwrap(self, w_string): return self.space.bytes_w(w_string) + def _quick_cmp(self, a, b): + return a is b + erase, unerase = rerased.new_erasing_pair("bytes") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -2038,6 +2083,9 @@ def unwrap(self, w_string): return self.space.utf8_w(w_string) + def _quick_cmp(self, a, b): + return a is b + erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -2050,7 +2098,7 @@ def sort(self, w_list, reverse): l = self.unerase(w_list.lstorage) - sorter = UnicodeSort(l, len(l)) + sorter = StringSort(l, len(l)) sorter.sort() if reverse: l.reverse() @@ -2090,7 +2138,6 @@ IntBaseTimSort = make_timsort_class() FloatBaseTimSort = make_timsort_class() IntOrFloatBaseTimSort = make_timsort_class() -UnicodeBaseTimSort = make_timsort_class() class KeyContainer(W_Root): @@ -2126,11 +2173,6 @@ return fa < fb -class UnicodeSort(UnicodeBaseTimSort): - def lt(self, a, b): - return a < b - - class CustomCompareSort(SimpleSort): def lt(self, a, b): space = self.space diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/mapdict.py pypy-7.3.6+dfsg/pypy/objspace/std/mapdict.py --- pypy-7.3.5+dfsg/pypy/objspace/std/mapdict.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/mapdict.py 2021-10-17 16:14:51.000000000 +0000 @@ -505,16 +505,16 @@ space = self.space assert type(w_value) is self.typ if type(w_value) is space.IntObjectCls: - return longlong2float(space.int_w(w_value)) + return space.int_w(w_value) else: - return space.float_w(w_value) + return float2longlong(space.float_w(w_value)) def _box(self, val): space = self.space if self.typ is space.IntObjectCls: - return space.newint(float2longlong(val)) + return space.newint(val) else: - return space.newfloat(val) + return space.newfloat(longlong2float(val)) def _convert_to_boxed(self, obj): new_obj = obj._get_mapdict_map().copy(obj) diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/newformat.py pypy-7.3.6+dfsg/pypy/objspace/std/newformat.py --- pypy-7.3.5+dfsg/pypy/objspace/std/newformat.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/newformat.py 2021-10-17 16:14:51.000000000 +0000 @@ -594,7 +594,13 @@ if precision != -1 and length >= precision: assert precision >= 0 length = precision - string = string[:precision] + if for_unicode: + w_slice = space.newslice( + space.newint(0), space.newint(precision), space.w_None) + w_string = space.getitem(w_string, w_slice) + string = space.utf8_w(w_string) + else: + string = string[:precision] self._calc_padding(string, length) return self.wrap(self._pad(string)) diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/test/test_listobject.py pypy-7.3.6+dfsg/pypy/objspace/std/test/test_listobject.py --- pypy-7.3.5+dfsg/pypy/objspace/std/test/test_listobject.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/test/test_listobject.py 2021-10-17 16:14:51.000000000 +0000 @@ -2,7 +2,8 @@ import py import random from pypy.objspace.std.listobject import W_ListObject, SizeListStrategy,\ - IntegerListStrategy, ObjectListStrategy + IntegerListStrategy, BytesListStrategy, FloatListStrategy, \ + ObjectListStrategy, IntOrFloatListStrategy, AsciiListStrategy from pypy.interpreter.error import OperationError from rpython.rlib.rarithmetic import is_valid_int @@ -430,6 +431,57 @@ with py.test.raises(ValueError): intlist.find(w(4), 0, 2) + def test_intlist_to_object_too_much_wrapping(self): + w = self.space.wrap + w_list = W_ListObject(self.space, [w(1000000)] * 100) + assert isinstance(w_list.strategy, IntegerListStrategy) + w_list.setitem(0, w(1)) + w_list.setitem(0, self.space.w_None) + assert isinstance(w_list.strategy, ObjectListStrategy) + l = w_list.getitems() + assert len(set(l)) == 2 + + def test_floatlist_to_object_too_much_wrapping(self): + w = self.space.wrap + for value in [11233.12, float('NaN')]: + w_list = W_ListObject(self.space, [w(value)] * 100) + assert isinstance(w_list.strategy, FloatListStrategy) + w_list.setitem(0, self.space.w_None) + assert isinstance(w_list.strategy, ObjectListStrategy) + l = w_list.getitems() + for element in l[2:]: + assert element is l[1] + + def test_intorfloatlist_to_object_too_much_wrapping(self): + w = self.space.wrap + w_list = W_ListObject(self.space, [w(0)] * 100) + w_list.setitem(0, w(1.1)) + assert isinstance(w_list.strategy, IntOrFloatListStrategy) + w_list.setitem(0, self.space.w_None) + assert isinstance(w_list.strategy, ObjectListStrategy) + l = w_list.getitems() + assert len(set(l)) == 2 + + def test_byteslist_to_object_too_much_wrapping(self): + w = self.space.wrap + w_list = W_ListObject(self.space, [self.space.newbytes(b"abc")] * 100) + assert isinstance(w_list.strategy, BytesListStrategy) + w_list.setitem(0, self.space.w_None) + assert isinstance(w_list.strategy, ObjectListStrategy) + l = w_list.getitems() + for element in l[2:]: + assert element is l[1] + + def test_asciilist_to_object_too_much_wrapping(self): + w = self.space.wrap + w_list = W_ListObject(self.space, [self.space.newutf8(b"abc", 3)] * 100) + assert isinstance(w_list.strategy, AsciiListStrategy) + w_list.setitem(0, self.space.w_None) + assert isinstance(w_list.strategy, ObjectListStrategy) + l = w_list.getitems() + for element in l[2:]: + assert element is l[1] + class AppTestListObject(object): #spaceconfig = {"objspace.std.withliststrategies": True} # it's the default diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/test/test_mapdict.py pypy-7.3.6+dfsg/pypy/objspace/std/test/test_mapdict.py --- pypy-7.3.5+dfsg/pypy/objspace/std/test/test_mapdict.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/test/test_mapdict.py 2021-10-17 16:14:51.000000000 +0000 @@ -2,7 +2,6 @@ from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictObject from pypy.objspace.std.mapdict import * - skip_if_no_int_unboxing = pytest.mark.skipif(not ALLOW_UNBOXING_INTS, reason="int unboxing disabled on 32bit") class Config: @@ -571,34 +570,54 @@ int) assert aa.storage_needed() == 2 -@skip_if_no_int_unboxing -def test_unboxed_write_int(): +def unboxed_write_int(val1, val2): cls = Class(allow_unboxing=True) w_obj = cls.instantiate(space) - w_obj.setdictvalue(space, "a", 15) - w_obj.getdictvalue(space, "a") == 15 + w_obj.setdictvalue(space, "a", val1) + w_obj.getdictvalue(space, "a") == val1 assert isinstance(w_obj.map, UnboxedPlainAttribute) - w_obj.setdictvalue(space, "b", 20) - w_obj.getdictvalue(space, "b") == 20 - w_obj.getdictvalue(space, "a") == 15 + w_obj.setdictvalue(space, "b", val2) + w_obj.getdictvalue(space, "b") == val2 + w_obj.getdictvalue(space, "a") == val1 assert isinstance(w_obj.map, UnboxedPlainAttribute) assert isinstance(w_obj.map.back, UnboxedPlainAttribute) - assert unerase_unboxed(w_obj.storage[0]) == [longlong2float(15), longlong2float(20)] + assert unerase_unboxed(w_obj.storage[0]) == [val1, val2] -def test_unboxed_write_float(): +def unboxed_write_float(val1, val2): cls = Class(allow_unboxing=True) w_obj = cls.instantiate(space) - w_obj.setdictvalue(space, "a", 15.0) - w_obj.getdictvalue(space, "a") == 15.0 + w_obj.setdictvalue(space, "a", val1) + w_obj.getdictvalue(space, "a") == val1 assert isinstance(w_obj.map, UnboxedPlainAttribute) - w_obj.setdictvalue(space, "b", 20.0) - w_obj.getdictvalue(space, "b") == 20.0 - w_obj.getdictvalue(space, "a") == 15.0 + w_obj.setdictvalue(space, "b", val2) + w_obj.getdictvalue(space, "b") == val2 + w_obj.getdictvalue(space, "a") == val1 assert isinstance(w_obj.map, UnboxedPlainAttribute) assert isinstance(w_obj.map.back, UnboxedPlainAttribute) - assert unerase_unboxed(w_obj.storage[0]) == [15.0, 20.0] + assert unerase_unboxed(w_obj.storage[0]) == [ + float2longlong(val1), float2longlong(val2)] + +try: + from hypothesis import given, strategies +except ImportError: + @skip_if_no_int_unboxing + def test_unboxed_write_int(): + unboxed_write_int(15, 20) + def test_unboxed_write_float(): + unboxed_write_float(12.434, -1e17) +else: + @skip_if_no_int_unboxing + @given(strategies.integers(-sys.maxint-1, sys.maxint), + strategies.integers(-sys.maxint-1, sys.maxint)) + def test_unboxed_write_int(val1, val2): + unboxed_write_int(val1, val2) + + @given(strategies.floats(), strategies.floats()) + def test_unboxed_write_float(val1, val2): + unboxed_write_float(val1, val2) + @skip_if_no_int_unboxing def test_unboxed_write_mixed(): @@ -684,7 +703,7 @@ def _pure_unboxed_read(obj): indices.append(0) - return 10.12 + return float2longlong(10.12) obj.map.back._pure_unboxed_read = _pure_unboxed_read monkeypatch.setattr(jit, "isconstant", lambda c: True) diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/test/test_newformat.py pypy-7.3.6+dfsg/pypy/objspace/std/test/test_newformat.py --- pypy-7.3.5+dfsg/pypy/objspace/std/test/test_newformat.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/test/test_newformat.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,6 +1,5 @@ # -*- encoding: utf-8 -*- """Test unicode/str's format method""" -from __future__ import with_statement class BaseStringFormatTests: @@ -230,6 +229,10 @@ def test_padding_utf8_bug(self): assert format(unichr(228), "3") == unichr(228) + u" " + def test_precision_utf8_bug(self): + u = b'\xc3\xa4'.decode("utf-8") + assert u.__format__(".1") == u + class AppTestStringFormat(BaseStringFormatTests): def setup_class(cls): cls.w_s = cls.space.w_bytes diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/test/test_obj.py pypy-7.3.6+dfsg/pypy/objspace/std/test/test_obj.py --- pypy-7.3.5+dfsg/pypy/objspace/std/test/test_obj.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/test/test_obj.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,5 +1,5 @@ -from __future__ import with_statement from pypy.conftest import option +import pytest class AppTestObject: @@ -7,14 +7,8 @@ from pypy.interpreter import gateway import sys - cpython_behavior = (not option.runappdirect - or not hasattr(sys, 'pypy_translation_info')) - space = cls.space - cls.w_cpython_behavior = space.wrap(cpython_behavior) - cls.w_cpython_version = space.wrap(tuple(sys.version_info)) cls.w_appdirect = space.wrap(option.runappdirect) - cls.w_cpython_apptest = space.wrap(option.runappdirect and not hasattr(sys, 'pypy_translation_info')) def w_unwrap_wrap_unicode(space, w_obj): return space.newutf8(space.utf8_w(w_obj), w_obj._length) @@ -23,15 +17,6 @@ return space.wrap(space.str_w(w_obj)) cls.w_unwrap_wrap_str = space.wrap(gateway.interp2app(w_unwrap_wrap_str)) - def test_hash_builtin(self): - if not self.cpython_behavior: - skip("on pypy-c id == hash is not guaranteed") - if self.cpython_version >= (2, 7): - skip("on CPython >= 2.7, id != hash") - import sys - o = object() - assert (hash(o) & sys.maxint) == (id(o) & sys.maxint) - def test_hash_method(self): o = object() assert hash(o) == o.__hash__() @@ -49,8 +34,6 @@ class X(object): pass x = X() - if self.cpython_behavior and self.cpython_version < (2, 7): - assert (hash(x) & sys.maxint) == (id(x) & sys.maxint) assert hash(x) == object.__hash__(x) def test_reduce_recursion_bug(self): @@ -116,9 +99,8 @@ assert A().__str__() == 123456 + @pytest.mark.pypy_only def test_is_on_primitives(self): - if self.cpython_apptest: - skip("cpython behaves differently") assert 1 is 1 x = 1000000 assert x + 1 is int(str(x + 1)) @@ -147,12 +129,15 @@ s = "a" assert self.unwrap_wrap_str(s) is s + @pytest.mark.pypy_only + def test_is_by_value(self): + for typ in [int, long, float, complex]: + assert typ(42) is typ(42) + def test_is_on_subclasses(self): for typ in [int, long, float, complex, str, unicode]: class mytyp(typ): pass - if not self.cpython_apptest and typ not in (str, unicode): - assert typ(42) is typ(42) assert mytyp(42) is not mytyp(42) assert mytyp(42) is not typ(42) assert typ(42) is not mytyp(42) @@ -169,9 +154,8 @@ assert "43" is not x assert None is not x + @pytest.mark.pypy_only def test_id_on_primitives(self): - if self.cpython_apptest: - skip("cpython behaves differently") assert id(1) == (1 << 4) + 1 assert id(1l) == (1 << 4) + 3 class myint(int): diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/test/test_unicodeobject.py pypy-7.3.6+dfsg/pypy/objspace/std/test/test_unicodeobject.py --- pypy-7.3.5+dfsg/pypy/objspace/std/test/test_unicodeobject.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/test/test_unicodeobject.py 2021-10-17 16:14:51.000000000 +0000 @@ -217,12 +217,14 @@ uniupper, = unicodedb.toupper_full(ch) assert chr(uniupper) == chr(ch).upper() - def test_latin1_encode_shortcut_ascii(self, monkeypatch): + def test_latin1_ascii_encode_shortcut_ascii(self, monkeypatch): from rpython.rlib import rutf8 from pypy.objspace.std.unicodeobject import encode_object monkeypatch.setattr(rutf8, "check_ascii", None) w_b = encode_object(self.space, self.space.newutf8("abc", 3), "latin-1", "strict") assert self.space.bytes_w(w_b) == "abc" + w_b = encode_object(self.space, self.space.newutf8("abc", 3), "ascii", "strict") + assert self.space.bytes_w(w_b) == "abc" class AppTestUnicodeStringStdOnly: diff -Nru pypy-7.3.5+dfsg/pypy/objspace/std/unicodeobject.py pypy-7.3.6+dfsg/pypy/objspace/std/unicodeobject.py --- pypy-7.3.5+dfsg/pypy/objspace/std/unicodeobject.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/objspace/std/unicodeobject.py 2021-10-17 16:14:51.000000000 +0000 @@ -1197,7 +1197,8 @@ encoding == 'ascii'): s = space.utf8_w(w_obj) try: - rutf8.check_ascii(s) + if not (isinstance(w_obj, W_UnicodeObject) and w_obj.is_ascii()): + rutf8.check_ascii(s) except rutf8.CheckError as a: if space.isinstance_w(w_obj, space.w_unicode): eh = unicodehelper.encode_error_handler(space) diff -Nru pypy-7.3.5+dfsg/pypy/tool/pytest/appsupport.py pypy-7.3.6+dfsg/pypy/tool/pytest/appsupport.py --- pypy-7.3.5+dfsg/pypy/tool/pytest/appsupport.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/pytest/appsupport.py 2021-10-17 16:14:51.000000000 +0000 @@ -244,6 +244,7 @@ if not space.exception_match(w_exc_type, self.w_ExpectedException): self.report_error(space.text_w(space.repr(w_exc_type))) self.w_value = w_exc_value # for the 'value' app-level attribute + self.w_type = w_exc_type return space.w_True # suppress the exception def report_error(self, got): @@ -256,7 +257,8 @@ W_RaisesContextManager.typedef = typedef.TypeDef("RaisesContextManager", __enter__ = gateway.interp2app_temp(W_RaisesContextManager.enter), __exit__ = gateway.interp2app_temp(W_RaisesContextManager.exit), - value = typedef.interp_attrproperty_w('w_value', cls=W_RaisesContextManager) + value=typedef.interp_attrproperty_w('w_value', cls=W_RaisesContextManager), + type=typedef.interp_attrproperty_w('w_type', cls=W_RaisesContextManager) ) def pypyraises(space, w_ExpectedException, w_expr=None, __args__=None): diff -Nru pypy-7.3.5+dfsg/pypy/tool/pytest/fake_pytest/test/apptest_fake_pytest.py pypy-7.3.6+dfsg/pypy/tool/pytest/fake_pytest/test/apptest_fake_pytest.py --- pypy-7.3.5+dfsg/pypy/tool/pytest/fake_pytest/test/apptest_fake_pytest.py 1970-01-01 00:00:00.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/pytest/fake_pytest/test/apptest_fake_pytest.py 2021-10-17 16:14:51.000000000 +0000 @@ -0,0 +1,7 @@ +import pytest + +def test_with_raises_success(): + with pytest.raises(ValueError) as excinfo: + raise ValueError + assert isinstance(excinfo.value, ValueError) + assert excinfo.type is ValueError diff -Nru pypy-7.3.5+dfsg/pypy/tool/release/check_versions.py pypy-7.3.6+dfsg/pypy/tool/release/check_versions.py --- pypy-7.3.5+dfsg/pypy/tool/release/check_versions.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/release/check_versions.py 2021-10-17 16:14:54.000000000 +0000 @@ -6,9 +6,10 @@ - the other fields should have valid values - the pypy_version should be in the repo tags -Can be run as check_versions.py , by default will -download https://buildbot.pypy.org/pypy/versions.json and parse it - +By default will download https://buildbot.pypy.org/pypy/versions.json parse it, and +check against the files in https://downloads.python.org/pypy/ +Can be run as check_versions.py , in which case it will check the files in +https://buildbot.pypy.org/pypy/ """ import json @@ -32,6 +33,27 @@ pypy_versions = { + '7.3.6rc1': {'python_version': ['3.8.12', '3.7.12', '2.7.18'], + 'date': '2021-09-13', + }, + '7.3.5': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-05-23', + }, + '7.3.5rc3': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-05-19', + }, + '7.3.5rc2': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-05-05', + }, + '7.3.5rc1': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-05-02', + }, + '7.3.4': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-04-08', + }, + '7.3.4rc2': {'python_version': ['3.7.10', '2.7.18'], + 'date': '2021-04-04', + }, '7.3.4rc1': {'python_version': ['3.7.10', '2.7.18'], 'date': '2021-03-19', }, @@ -79,7 +101,7 @@ } -def check_versions(data): +def check_versions(data, url): for d in data: assert_in(d['pypy_version'], pypy_versions) v = pypy_versions[d['pypy_version']] @@ -100,9 +122,10 @@ if 'date' in d: assert_equal(d['date'], v['date']) for f in d['files']: + download_url = f['download_url'] if 'rc' not in d['pypy_version']: - assert_in(f['filename'], f['download_url']) - assert_in(d['pypy_version'], f['download_url']) + assert_in(f['filename'], download_url) + assert_in(d['pypy_version'], download_url) assert_in(f['arch'], arches) assert_in(f['platform'], platforms) arch_plat = arch_map[(f['arch'], f['platform'])] @@ -110,12 +133,14 @@ if arch_plat == 'linux32': # the nightly builds have a quirk in the linux32 file name arch_plat = 'linux' - assert_in(arch_plat, f['download_url']) + assert_in(arch_plat, download_url) else: - assert_in(arch_plat, f['download_url']) - assert_in('.'.join(d['python_version'].split('.')[:2]), f['download_url']) + assert_in(arch_plat, download_url) + assert_in('.'.join(d['python_version'].split('.')[:2]), download_url) + if url: + download_url = '/'.join((url, download_url.rsplit('/', 1)[1])) try: - r = request.urlopen(f['download_url']) + r = request.urlopen(download_url) except error.HTTPError as e: raise ValueError(f"could not open {f['download_url']}") from None assert_equal(r.getcode(), 200) @@ -125,9 +150,11 @@ print(f'checking local file "{sys.argv[1]}"') with open(sys.argv[1]) as fid: data = json.loads(fid.read()) + check_versions(data, 'https://buildbot.pypy.org/pypy') else: print('downloading versions.json') response = request.urlopen('https://buildbot.pypy.org/pypy/versions.json') assert_equal(response.getcode(), 200) data = json.loads(response.read()) - check_versions(data) + check_versions(data, None) + print('ok') diff -Nru pypy-7.3.5+dfsg/pypy/tool/release/package.py pypy-7.3.6+dfsg/pypy/tool/release/package.py --- pypy-7.3.5+dfsg/pypy/tool/release/package.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/release/package.py 2021-10-17 16:14:51.000000000 +0000 @@ -151,7 +151,9 @@ print("Picking %s" % str(pypyw)) # Can't rename a DLL win_extras = [('lib' + POSIX_EXE + '-c.dll', None), - ('sqlite3.dll', lib_pypy)] + ('sqlite3.dll', lib_pypy), + ('libffi-7.dll', None), + ] if not options.no__tkinter: tkinter_dir = lib_pypy.join('_tkinter') win_extras += [('tcl86t.dll', tkinter_dir), ('tk86t.dll', tkinter_dir)] @@ -351,7 +353,7 @@ default=(ARCH in ('darwin', 'aarch64', 'x86_64')), help='whether to embed dependencies in CFFI modules ' '(default on OS X)') - parser.add_argument('--make-portable', + parser.add_argument('--make-portable', '--no-make-portable', dest='make_portable', action=NegateAction, default=(ARCH in ('darwin',)), diff -Nru pypy-7.3.5+dfsg/pypy/tool/release/repackage.sh pypy-7.3.6+dfsg/pypy/tool/release/repackage.sh --- pypy-7.3.5+dfsg/pypy/tool/release/repackage.sh 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/release/repackage.sh 2021-10-17 16:14:54.000000000 +0000 @@ -1,11 +1,11 @@ #! /bin/bash # Edit these appropriately before running this script -pmaj=3 # python main version: 2 or 3 +pmaj=2 # python main version: 2 or 3 pmin=7 # python minor version maj=7 min=3 -rev=4 +rev=6 rc=rc1 # comment this line for actual release function maybe_exit { @@ -71,7 +71,12 @@ rm pypy-c-jit-latest-$plat.tar.bz2 # Check that this is the correct version - actual_ver=$(grep PYPY_VERSION pypy-c-jit-*-$plat/include/patchlevel.h |cut -f3 -d' ') + if [ "$pmin" == "7" ] # python2.7, 3.7 + then + actual_ver=$(grep PYPY_VERSION pypy-c-jit-*-$plat/include/patchlevel.h |cut -f3 -d' ') + else + actual_ver=$(grep PYPY_VERSION pypy-c-jit-*-$plat/include/pypy$pmaj.$pmin/patchlevel.h |cut -f3 -d' ') + fi if [ $actual_ver != "\"$maj.$min.$rev\"" ] then echo xxxxxxxxxxxxxxxxxxxxxx @@ -93,7 +98,7 @@ rm -rf $rel-$plat_final done # end of "for" loop - for plat in win64 win32 + for plat in win64 # win32 do if wget -q --show-progress http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.zip then diff -Nru pypy-7.3.5+dfsg/pypy/tool/release/versions.json pypy-7.3.6+dfsg/pypy/tool/release/versions.json --- pypy-7.3.5+dfsg/pypy/tool/release/versions.json 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/pypy/tool/release/versions.json 2021-10-17 16:14:54.000000000 +0000 @@ -1,5 +1,679 @@ [ { + "pypy_version": "7.3.6rc1", + "python_version": "3.8.12", + "stable": false, + "latest_pypy": false, + "date": "2021-09-13", + "files": [ + { + "filename": "pypy3.8-v7.3.6rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.6rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-linux32.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.6rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-linux64.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.6rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-osx64.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.6rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-win64.zip" + }, + { + "filename": "pypy3.8-v7.3.6rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.6rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.6rc1", + "python_version": "3.7.12", + "stable": false, + "latest_pypy": false, + "date": "2021-09-13", + "files": [ + { + "filename": "pypy3.7-v7.3.6rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.6rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.6rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.6rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.6rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.6rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.6rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.6rc1", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-09-13", + "files": [ + { + "filename": "pypy2.7-v7.3.6rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.6rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.6rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.6rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.6rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.6rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.6rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5", + "python_version": "3.7.10", + "stable": true, + "latest_pypy": true, + "date": "2021-05-23", + "files": [ + { + "filename": "pypy3.7-v7.3.5-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.5-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5", + "python_version": "2.7.18", + "stable": true, + "latest_pypy": true, + "date": "2021-05-23", + "files": [ + { + "filename": "pypy2.7-v7.3.5-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.5-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5-s390x.tar.bz2" + } + ] + }, { + "pypy_version": "7.3.5rc3", + "python_version": "3.7.10", + "stable": false, + "latest_pypy": false, + "date": "2021-05-19", + "files": [ + { + "filename": "pypy3.7-v7.3.5rc3-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc3-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc3-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc3-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc3-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.5rc3-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc3-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5rc3", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-05-19", + "files": [ + { + "filename": "pypy2.7-v7.3.5rc3-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc3-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc3-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc3-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc3-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.5rc3-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc3-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5rc2", + "python_version": "3.7.10", + "stable": false, + "latest_pypy": false, + "date": "2021-05-05", + "files": [ + { + "filename": "pypy3.7-v7.3.5rc2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc2-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.5rc2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5rc2", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-05-05", + "files": [ + { + "filename": "pypy2.7-v7.3.5rc2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc2-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.5rc2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5rc1", + "python_version": "3.7.10", + "stable": false, + "latest_pypy": false, + "date": "2021-05-02", + "files": [ + { + "filename": "pypy3.7-v7.3.5rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.5rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.5rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.5rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.5rc1", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-05-02", + "files": [ + { + "filename": "pypy2.7-v7.3.5rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.5rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.5rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.5rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.4", + "python_version": "3.7.10", + "stable": true, + "latest_pypy": false, + "date": "2021-04-08", + "files": [ + { + "filename": "pypy3.7-v7.3.4-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.4-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.4", + "python_version": "2.7.18", + "stable": true, + "latest_pypy": false, + "date": "2021-04-08", + "files": [ + { + "filename": "pypy2.7-v7.3.4-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.4-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.4rc2", + "python_version": "3.7.10", + "stable": false, + "latest_pypy": false, + "date": "2021-04-04", + "files": [ + { + "filename": "pypy3.7-v7.3.4rc2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4rc2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4rc2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4rc2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.4rc2-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-win64.zip" + }, + { + "filename": "pypy3.7-v7.3.4rc2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.4rc2", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-04-04", + "files": [ + { + "filename": "pypy2.7-v7.3.4rc2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc2-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-win64.zip" + }, + { + "filename": "pypy2.7-v7.3.4rc2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc2-s390x.tar.bz2" + } + ] + }, + { "pypy_version": "7.3.4rc1", "python_version": "3.7.10", "stable": false, @@ -216,7 +890,7 @@ "pypy_version": "7.3.3", "python_version": "2.7.18", "stable": true, - "latest_pypy": true, + "latest_pypy": false, "date": "2020-11-21", "files": [ { diff -Nru pypy-7.3.5+dfsg/rpython/annotator/model.py pypy-7.3.6+dfsg/rpython/annotator/model.py --- pypy-7.3.5+dfsg/rpython/annotator/model.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/annotator/model.py 2021-10-17 16:14:51.000000000 +0000 @@ -537,12 +537,20 @@ self.const = desc.pyobj elif len(descriptions) > 1: from rpython.annotator.classdesc import ClassDesc - if self.getKind() is ClassDesc: + from rpython.annotator.description import MethodOfFrozenDesc + kind = self.getKind() + if kind is ClassDesc: # a PBC of several classes: enforce them all to be # built, without support for specialization. See # rpython/test/test_rpbc.test_pbc_of_classes_not_all_used for desc in descriptions: desc.getuniqueclassdef() + elif kind is MethodOfFrozenDesc: + funcdescs = set(desc.funcdesc for desc in descriptions) + if len(funcdescs) > 1: + raise AnnotatorError( + "You can't mix a set of methods on a frozen PBC in " + "RPython that are different underlying functions") def any_description(self): return iter(self.descriptions).next() diff -Nru pypy-7.3.5+dfsg/rpython/annotator/test/test_annrpython.py pypy-7.3.6+dfsg/rpython/annotator/test/test_annrpython.py --- pypy-7.3.5+dfsg/rpython/annotator/test/test_annrpython.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/annotator/test/test_annrpython.py 2021-10-17 16:14:51.000000000 +0000 @@ -4665,6 +4665,33 @@ s = a.build_types(f, [int]) assert isinstance(listitem(s), annmodel.SomeChar) + def test_union_of_methods_of_frozen(self): + class A(Freezing): + def foo(self): + return 42 + def bar(self): + return 43 + class B(A): + def foo(self): + return 44 + + a = A() + b = B() + def f(n): + x = a if n > 0 else b + return x.foo() + def g(n): + x = a if n > 0 else b + return x.bar() + ann = self.RPythonAnnotator() + with py.test.raises(AnnotatorError): + # a.foo and b.foo are different functions -> BOOM + s = ann.build_types(f, [int]) + + # a.bar and b.bar are the same function -> OK + s = ann.build_types(g, [int]) + assert s.const == 43 + def g(n): return [0, 1, 2, n] diff -Nru pypy-7.3.5+dfsg/rpython/jit/backend/llsupport/test/test_codemap.py pypy-7.3.6+dfsg/rpython/jit/backend/llsupport/test/test_codemap.py --- pypy-7.3.5+dfsg/rpython/jit/backend/llsupport/test/test_codemap.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/backend/llsupport/test/test_codemap.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,4 +1,5 @@ - +import sys +import pytest from rpython.rtyper.lltypesystem import rffi, lltype from rpython.jit.backend.llsupport.codemap import CodemapStorage, \ CodemapBuilder, unpack_traceback, find_codemap_at_addr @@ -26,6 +27,7 @@ # codemap.free() +@pytest.mark.skipif(sys.platform=='win32', reason='codemap unused, and long/Signed confusion on win64') def test_free_with_alignment(): codemap = CodemapStorage() codemap.setup() diff -Nru pypy-7.3.5+dfsg/rpython/jit/backend/ppc/jump.py pypy-7.3.6+dfsg/rpython/jit/backend/ppc/jump.py --- pypy-7.3.5+dfsg/rpython/jit/backend/ppc/jump.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/backend/ppc/jump.py 2021-10-17 16:14:51.000000000 +0000 @@ -91,7 +91,9 @@ key = loc.as_key() if (key in dst_keys or (loc.width > WORD and (key + 1) in dst_keys)): - assembler.regalloc_push(loc, len(extrapushes)) + # don't call regalloc_push with already_pushed==0 here + # because it can conflict with the regalloc_push() above + assembler.regalloc_push(loc, len(extrapushes) + 1) extrapushes.append(dstloc) continue src_locations2red.append(loc) @@ -108,4 +110,4 @@ # finally, pop the extra fp stack locations while len(extrapushes) > 0: loc = extrapushes.pop() - assembler.regalloc_pop(loc, len(extrapushes)) + assembler.regalloc_pop(loc, len(extrapushes) + 1) diff -Nru pypy-7.3.5+dfsg/rpython/jit/backend/test/jitlog_test.py pypy-7.3.6+dfsg/rpython/jit/backend/test/jitlog_test.py --- pypy-7.3.5+dfsg/rpython/jit/backend/test/jitlog_test.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/backend/test/jitlog_test.py 2021-10-17 16:14:51.000000000 +0000 @@ -4,7 +4,7 @@ from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.rjitlog import rjitlog from rpython.rlib.rfile import create_file -from rpython.rlib.rposix import FdValidator +from rpython.rlib.rposix import SuppressIPH class LoggerTest(LLJitMixin): @@ -15,7 +15,7 @@ # visual2019 for instance rfile = create_file(file.strpath, 'wb') fileno = rfile.fileno() - with FdValidator(fileno): + with SuppressIPH(): enable_jitlog = lambda: rjitlog.enable_jitlog(fileno) f = self.run_sample_loop(enable_jitlog) self.meta_interp(f, [10, 0]) diff -Nru pypy-7.3.5+dfsg/rpython/jit/backend/x86/regalloc.py pypy-7.3.6+dfsg/rpython/jit/backend/x86/regalloc.py --- pypy-7.3.5+dfsg/rpython/jit/backend/x86/regalloc.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/backend/x86/regalloc.py 2021-10-17 16:14:51.000000000 +0000 @@ -125,6 +125,10 @@ all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs +class X86_64_WIN_XMMRegisterManager(X86_64_XMMRegisterManager): + # xmm15 reserved for scratch use + all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4] + class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) @@ -150,7 +154,10 @@ xmm_reg_mgr_cls = X86XMMRegisterManager elif WORD == 8: gpr_reg_mgr_cls = X86_64_RegisterManager - xmm_reg_mgr_cls = X86_64_XMMRegisterManager + if WIN64: + xmm_reg_mgr_cls = X86_64_WIN_XMMRegisterManager + else: + xmm_reg_mgr_cls = X86_64_XMMRegisterManager else: raise AssertionError("Word size should be 4 or 8") @@ -1319,7 +1326,11 @@ # Do we have a temp var? if IS_X86_64: tmpreg = X86_64_SCRATCH_REG - xmmtmp = X86_64_XMM_SCRATCH_REG + if WIN64: + # XXX perhaps use this for all_regs and do xmmtmp = None? + xmmtmp = xmm5 + else: + xmmtmp = X86_64_XMM_SCRATCH_REG else: tmpreg = None xmmtmp = None diff -Nru pypy-7.3.5+dfsg/rpython/jit/metainterp/optimizeopt/test/test_intbound.py pypy-7.3.6+dfsg/rpython/jit/metainterp/optimizeopt/test/test_intbound.py --- pypy-7.3.5+dfsg/rpython/jit/metainterp/optimizeopt/test/test_intbound.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/metainterp/optimizeopt/test/test_intbound.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,5 +1,5 @@ from rpython.jit.metainterp.optimizeopt.intutils import IntBound, IntUpperBound, \ - IntLowerBound, IntUnbounded, next_pow2_m1 + IntLowerBound, IntUnbounded, ConstIntBound, next_pow2_m1 from copy import copy import sys @@ -486,11 +486,12 @@ @given(bound_with_contained_number) @example((IntUpperBound(-100), -sys.maxint-1)) +@example((ConstIntBound(-sys.maxint - 1), -sys.maxint-1)) +@example((IntBound(-sys.maxint - 1, -sys.maxint+10), -sys.maxint-1)) def test_neg_bound_random(t1): b1, n1 = t1 b2 = b1.neg_bound() if n1 != -sys.maxint - 1: assert b2.contains(-n1) else: - assert not b1.has_lower assert not b2.has_upper diff -Nru pypy-7.3.5+dfsg/rpython/jit/metainterp/pyjitpl.py pypy-7.3.6+dfsg/rpython/jit/metainterp/pyjitpl.py --- pypy-7.3.5+dfsg/rpython/jit/metainterp/pyjitpl.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/metainterp/pyjitpl.py 2021-10-17 16:14:51.000000000 +0000 @@ -474,8 +474,8 @@ def opimpl_new_array_clear(self, lengthbox, itemsizedescr): return self.metainterp.execute_new_array_clear(itemsizedescr, lengthbox) - @specialize.arg(1) - def _do_getarrayitem_gc_any(self, op, arraybox, indexbox, arraydescr): + @specialize.arg(1, 5) + def _do_getarrayitem_gc_any(self, op, arraybox, indexbox, arraydescr, typ): tobox = self.metainterp.heapcache.getarrayitem( arraybox, indexbox, arraydescr) if tobox: @@ -484,12 +484,26 @@ self.metainterp.staticdata.profiler.count_ops(rop.GETARRAYITEM_GC_I, Counters.HEAPCACHED_OPS) resvalue = executor.execute(self.metainterp.cpu, self.metainterp, op, arraydescr, arraybox, indexbox) - if op == 'i': - assert resvalue == tobox.getint() - elif op == 'r': - assert resvalue == tobox.getref_base() - elif op == 'f': - assert resvalue == tobox.getfloat() + if typ == 'i': + if resvalue != tobox.getint(): + self.metainterp._record_helper_nonpure_varargs(rop.GETARRAYITEM_GC_I, resvalue, arraydescr, [arraybox, indexbox]) + self.metainterp.staticdata.logger_noopt.log_loop_from_trace(self.metainterp.history.trace, self.metainterp.box_names_memo) + print "assertion in GETARRAYITEM_GC_I failed", resvalue, tobox.getint() + assert 0 + elif typ == 'r': + if resvalue != tobox.getref_base(): + self.metainterp._record_helper_nonpure_varargs(rop.GETARRAYITEM_GC_R, resvalue, arraydescr, [arraybox, indexbox]) + self.metainterp.staticdata.logger_noopt.log_loop_from_trace(self.metainterp.history.trace, self.metainterp.box_names_memo) + print "assertion in GETARRAYITEM_GC_R failed", resvalue, tobox.getref_base() + assert 0 + elif typ == 'f': + if not ConstFloat(resvalue).same_constant(tobox.constbox()): + self.metainterp._record_helper_nonpure_varargs(rop.GETARRAYITEM_GC_F, resvalue, arraydescr, [arraybox, indexbox]) + self.metainterp.staticdata.logger_noopt.log_loop_from_trace(self.metainterp.history.trace, self.metainterp.box_names_memo) + print "assertion in GETARRAYITEM_GC_F failed", resvalue, tobox.getfloat() + assert 0 + else: + assert 0, "unreachable" return tobox resop = self.execute_with_descr(op, arraydescr, arraybox, indexbox) self.metainterp.heapcache.getarrayitem_now_known( @@ -499,17 +513,17 @@ @arguments("box", "box", "descr") def opimpl_getarrayitem_gc_i(self, arraybox, indexbox, arraydescr): return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_I, arraybox, - indexbox, arraydescr) + indexbox, arraydescr, 'i') @arguments("box", "box", "descr") def opimpl_getarrayitem_gc_r(self, arraybox, indexbox, arraydescr): return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_R, arraybox, - indexbox, arraydescr) + indexbox, arraydescr, 'r') @arguments("box", "box", "descr") def opimpl_getarrayitem_gc_f(self, arraybox, indexbox, arraydescr): return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_F, arraybox, - indexbox, arraydescr) + indexbox, arraydescr, 'f') @arguments("box", "box", "descr") def opimpl_getarrayitem_raw_i(self, arraybox, indexbox, arraydescr): @@ -531,7 +545,7 @@ arraybox, indexbox) return executor.wrap_constant(val) return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_I, - arraybox, indexbox, arraydescr) + arraybox, indexbox, arraydescr, 'i') @arguments("box", "box", "descr") def opimpl_getarrayitem_gc_f_pure(self, arraybox, indexbox, arraydescr): @@ -543,7 +557,7 @@ arraybox, indexbox) return executor.wrap_constant(resval) return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_F, - arraybox, indexbox, arraydescr) + arraybox, indexbox, arraydescr, 'f') @arguments("box", "box", "descr") def opimpl_getarrayitem_gc_r_pure(self, arraybox, indexbox, arraydescr): @@ -555,7 +569,7 @@ arraybox, indexbox) return executor.wrap_constant(val) return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_R, - arraybox, indexbox, arraydescr) + arraybox, indexbox, arraydescr, 'r') @arguments("box", "box", "box", "descr") def _opimpl_setarrayitem_gc_any(self, arraybox, indexbox, itembox, @@ -711,16 +725,43 @@ @arguments("box", "box", "descr") def opimpl_getinteriorfield_gc_i(self, array, index, descr): - return self.execute_with_descr(rop.GETINTERIORFIELD_GC_I, descr, - array, index) + return self._opimpl_getinteriorfield_gc_any( + rop.GETINTERIORFIELD_GC_I, array, + index, descr, 'i') @arguments("box", "box", "descr") def opimpl_getinteriorfield_gc_r(self, array, index, descr): - return self.execute_with_descr(rop.GETINTERIORFIELD_GC_R, descr, - array, index) + return self._opimpl_getinteriorfield_gc_any( + rop.GETINTERIORFIELD_GC_R, array, + index, descr, 'r') @arguments("box", "box", "descr") def opimpl_getinteriorfield_gc_f(self, array, index, descr): - return self.execute_with_descr(rop.GETINTERIORFIELD_GC_F, descr, - array, index) + return self._opimpl_getinteriorfield_gc_any( + rop.GETINTERIORFIELD_GC_F, array, + index, descr, 'f') + + @specialize.arg(1, 5) + def _opimpl_getinteriorfield_gc_any(self, opnum, arraybox, indexbox, descr, typ): + # use the getarrayitem heapcache methods, they work also for interior fields + tobox = self.metainterp.heapcache.getarrayitem( + arraybox, indexbox, descr) + if tobox: + # sanity check: see whether the current interior field value + # corresponds to what the cache thinks the value is + self.metainterp.staticdata.profiler.count_ops(opnum, Counters.HEAPCACHED_OPS) + resvalue = executor.execute(self.metainterp.cpu, self.metainterp, + opnum, descr, arraybox, indexbox) + if typ == 'i': + assert resvalue == tobox.getint() + elif typ == 'r': + assert resvalue == tobox.getref_base() + elif typ == 'f': + # need to be careful due to NaNs etc + assert ConstFloat(resvalue).same_constant(tobox.constbox()) + return tobox + resop = self.execute_with_descr(opnum, descr, arraybox, indexbox) + self.metainterp.heapcache.getarrayitem_now_known( + arraybox, indexbox, resop, descr) + return resop @specialize.arg(1, 4) def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr, type): @@ -2363,6 +2404,8 @@ def execute_setinteriorfield_gc(self, descr, array, index, value): self.execute_and_record(rop.SETINTERIORFIELD_GC, descr, array, index, value) + # use setarrayitem heapcache method, works for interior fields too + self.heapcache.setarrayitem(array, index, value, descr) def execute_raw_store(self, arraydescr, addrbox, offsetbox, valuebox): self.execute_and_record(rop.RAW_STORE, arraydescr, diff -Nru pypy-7.3.5+dfsg/rpython/jit/metainterp/test/test_dict.py pypy-7.3.6+dfsg/rpython/jit/metainterp/test/test_dict.py --- pypy-7.3.5+dfsg/rpython/jit/metainterp/test/test_dict.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/metainterp/test/test_dict.py 2021-10-17 16:14:51.000000000 +0000 @@ -381,6 +381,20 @@ self.meta_interp(f, [100]) self.check_simple_loop(call_may_force_i=0, call_i=0, new=0) + def test_loop_over_virtual_dict_gives_constants(self): + def fn(n): + d = self.newdict() + d[0] = n + d[1] = n + d2 = self.newdict() + d2[3] = n + 2 + for key, value in d2.iteritems(): + d[key] = value + return d[3] + res = self.interp_operations(fn, [0]) + assert res == 2 + self.check_operations_history(getinteriorfield_gc_i=0) + class TestLLtype(DictTests, LLJitMixin): pass diff -Nru pypy-7.3.5+dfsg/rpython/jit/metainterp/test/test_tracingopts.py pypy-7.3.6+dfsg/rpython/jit/metainterp/test/test_tracingopts.py --- pypy-7.3.5+dfsg/rpython/jit/metainterp/test/test_tracingopts.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/metainterp/test/test_tracingopts.py 2021-10-17 16:14:51.000000000 +0000 @@ -218,6 +218,42 @@ assert res == -7 * 2 self.check_operations_history(getarrayitem_gc_i=1) + def test_array_caching_float(self): + a1 = [0.0, 0.0] + a2 = [0.0, 0.0] + def fn(n): + if n > 0: + a = a1 + else: + a = a2 + a[0] = n + 0.01 + x1 = a[0] + a[n - n] = n + 0.1 + return a[0] + x1 + res = self.interp_operations(fn, [7]) + assert res == 7 + 7 + 0.01 + 0.1 + self.check_operations_history(getarrayitem_gc_f=1) + res = self.interp_operations(fn, [-7]) + assert res == -7 - 7 + 0.01 + 0.1 + self.check_operations_history(getarrayitem_gc_f=1) + + def fn(n, ca, cb): + a1[0] = n + 0.01 + a2[0] = n + 0.01 + a = a1 + if ca: + a = a2 + b = a1 + if cb: + b = a + return a[0] + b[0] + res = self.interp_operations(fn, [7, 0, 1]) + assert res == (7 + 0.01) * 2 + self.check_operations_history(getarrayitem_gc_f=1) + res = self.interp_operations(fn, [-7, 1, 1]) + assert res == (-7 + 0.01) * 2 + self.check_operations_history(getarrayitem_gc_f=1) + def test_array_caching_while_tracing_invalidation(self): a1 = [0, 0] a2 = [0, 0] @@ -859,3 +895,13 @@ res = self.interp_operations(g, [21]) assert res == g(21) self.check_operations_history(call_loopinvariant_r=2) + + def test_heapcache_interiorfields(self): + def fn(n): + d = {1: n, 2: n} + d[4] = n + 1 + return d[4] + res = self.interp_operations(fn, [0]) + assert res == 1 + self.check_operations_history(getinteriorfield_gc_i=0) + diff -Nru pypy-7.3.5+dfsg/rpython/jit/tool/test/test_traceviewer.py pypy-7.3.6+dfsg/rpython/jit/tool/test/test_traceviewer.py --- pypy-7.3.5+dfsg/rpython/jit/tool/test/test_traceviewer.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/tool/test/test_traceviewer.py 2021-10-17 16:14:51.000000000 +0000 @@ -105,6 +105,21 @@ main(str(fname), False, view=False) # assert did not explode + def test_non_contiguous_loops(self): + data = [preparse(""" + # Loop 1 : loop with 39 ops + debug_merge_point('', 0) + guard_class(p4, 141310752, descr=) [p0, p1] + p60 = getfield_gc(p4, descr=) + guard_nonnull(p60, descr=) [p0, p1] + """), preparse(""" + # Loop 4 : loop with 46 ops + p21 = getfield_gc(p4, descr=) + """)] + real_loops, all_loops = splitloops(data) + assert len(all_loops) == 2 + assert len(real_loops) == 5 + class TestMergPointStringExtraciton(object): def test_find_name_key(self): diff -Nru pypy-7.3.5+dfsg/rpython/jit/tool/traceviewer.py pypy-7.3.6+dfsg/rpython/jit/tool/traceviewer.py --- pypy-7.3.5+dfsg/rpython/jit/tool/traceviewer.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/jit/tool/traceviewer.py 2021-10-17 16:14:51.000000000 +0000 @@ -191,6 +191,13 @@ MAX_LOOPS = 300 LINE_CUTOFF = 300 +def fillappend(lst, elem, no): + there = len(lst) + assert there <= no + for _ in range(no - there): + lst.append(None) + lst.append(elem) + def splitloops(loops): real_loops = [] counter = 1 @@ -204,9 +211,9 @@ m = re.match('# Loop (\d+)', firstline) if m: no = int(m.group(1)) - assert len(real_loops) == no + assert len(real_loops) <= no _loop = FinalBlock(loop, None) - real_loops.append(_loop) + fillappend(real_loops, _loop, no) _loop.startlineno = counter _loop.loop_no = no allloops.append(_loop) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/clibffi.py pypy-7.3.6+dfsg/rpython/rlib/clibffi.py --- pypy-7.3.5+dfsg/rpython/rlib/clibffi.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/clibffi.py 2021-10-17 16:14:51.000000000 +0000 @@ -38,10 +38,7 @@ if _WIN32: from rpython.rlib import rwin32 - -if _WIN32: separate_module_sources = [''' - #include "src/precommondefs.h" #include #include @@ -107,22 +104,12 @@ ]) else: USE_C_LIBFFI_MSVC = True - libffidir = py.path.local(cdir).join('src', 'libffi_msvc') - if not _WIN64: - asm_ifc = 'win32.c' - else: - asm_ifc = 'win64.asm' + # libffidir = py.path.local(cdir).join('src', 'libffi_msvc') eci = ExternalCompilationInfo( includes = ['ffi.h', 'windows.h'], - libraries = ['kernel32'], - include_dirs = [libffidir, cdir], + libraries = ['kernel32', 'libffi-7'], separate_module_sources = separate_module_sources, post_include_bits = post_include_bits, - separate_module_files = [libffidir.join('ffi.c'), - libffidir.join('prep_cif.c'), - libffidir.join(asm_ifc), - libffidir.join('pypy_ffi.c'), - ], ) FFI_TYPE_P = lltype.Ptr(lltype.ForwardReference()) @@ -265,7 +252,7 @@ return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv='win') -if not _MSVC: +if 1 or not _MSVC: def check_fficall_result(result, flags): pass # No check else: @@ -329,7 +316,7 @@ c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, FFI_ABI, rffi.UINT, FFI_TYPE_P, FFI_TYPE_PP], rffi.INT) -if _MSVC: +if 0 and _MSVC: c_ffi_call_return_type = rffi.INT else: c_ffi_call_return_type = lltype.Void diff -Nru pypy-7.3.5+dfsg/rpython/rlib/listsort.py pypy-7.3.6+dfsg/rpython/rlib/listsort.py --- pypy-7.3.5+dfsg/rpython/rlib/listsort.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/listsort.py 2021-10-17 16:14:51.000000000 +0000 @@ -8,6 +8,49 @@ ## ------------------------------------------------------------------------ ## Adapted from CPython, original code and algorithms by Tim Peters + +def merge_compute_minrun(n): + # Compute a good value for the minimum run length; natural runs shorter + # than this are boosted artificially via binary insertion. + # + # If n < 64, return n (it's too small to bother with fancy stuff). + # Else if n is an exact power of 2, return 32. + # Else return an int k, 32 <= k <= 64, such that n/k is close to, but + # strictly less than, an exact power of 2. + # + # See listsort.txt for more info. + r = 0 # becomes 1 if any 1 bits are shifted off + while n >= 64: + r |= n & 1 + n >>= 1 + return n + r + +def powerloop(s1, n1, n2, n): + # Two adjacent runs begin at index s1. The first run has length n1, and + # the second run (starting at index s1+n1) has length n2. The list has total + # length n. + # Compute the "power" of the first run. See listsort.txt for details. + assert s1 >= 0 + assert n1 >= 1 and n2 >= 1 + assert s1 + n1 + n2 <= n + # a' = s1 + n1/2 + # b' = s1 + n1 + n2/2 = a' + (n1 + n2)/2 + a = 2 * s1 + n1 # 2 * a' + b = a + n1 + n2 # 2 * b' + result = 0 + while True: + result += 1 + if a >= n: + assert b >= a + a -= n + b -= n + elif b >= n: + break + assert a < b < n + a <<= 1 + b <<= 1 + return result + def make_timsort_class(getitem=None, setitem=None, length=None, getitem_slice=None, lt=None): @@ -491,60 +534,39 @@ else: self.merge_hi(a, b) - # Examine the stack of runs waiting to be merged, merging adjacent runs - # until the stack invariants are re-established: - # - # 1. len[-3] > len[-2] + len[-1] - # 2. len[-2] > len[-1] - # - # Note these invariants will not hold for the entire pending array even - # after this function completes. [1] This does not affect the - # correctness of the overall algorithm. - # - # [1] http://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/ - # - # See listsort.txt for more info. + def found_new_run(self, run): + """ + The next run has been identified. + If there's already a run on the stack, apply the "powersort" merge strategy: + compute the topmost run's "power" (depth in a conceptual binary merge tree) + and merge adjacent runs on the stack with greater power. See listsort.txt + for more info. + + It's the caller's responsibilty to push the new run on the stack when this + returns. + + See listsort.txt for more info. + """ - def merge_collapse(self): p = self.pending - while len(p) > 1: - if len(p) >= 3 and p[-3].len <= p[-2].len + p[-1].len: - if p[-3].len < p[-1].len: - self.merge_at(-3) - else: - self.merge_at(-2) - elif p[-2].len <= p[-1].len: + if p: + s1 = p[-1].base + n1 = p[-1].len + power = powerloop(s1, n1, run.len, self.listlength) + while len(p) > 1 and p[-2].power > power: self.merge_at(-2) - else: - break - - # Regardless of invariants, merge all runs on the stack until only one - # remains. This is used at the end of the mergesort. + assert len(p) < 2 or p[-2].power < power + p[-1].power = power; def merge_force_collapse(self): p = self.pending while len(p) > 1: + n = -2 if len(p) >= 3 and p[-3].len < p[-1].len: - self.merge_at(-3) - else: - self.merge_at(-2) - - # Compute a good value for the minimum run length; natural runs shorter - # than this are boosted artificially via binary insertion. - # - # If n < 64, return n (it's too small to bother with fancy stuff). - # Else if n is an exact power of 2, return 32. - # Else return an int k, 32 <= k <= 64, such that n/k is close to, but - # strictly less than, an exact power of 2. - # - # See listsort.txt for more info. + n = -3 + self.merge_at(n) - def merge_compute_minrun(self, n): - r = 0 # becomes 1 if any 1 bits are shifted off - while n >= 64: - r |= n & 1 - n >>= 1 - return n + r + merge_compute_minrun = staticmethod(merge_compute_minrun) # ____________________________________________________________ # Entry point. @@ -569,11 +591,12 @@ sorted = run.len run.len = min(minrun, remaining.len) self.binarysort(run, sorted) + # maybe merge (but never the newest) + self.found_new_run(run) + # Push run onto pending-runs stack + self.pending.append(run) # Advance remaining past this run. remaining.advance(run.len) - # Push run onto pending-runs stack, and maybe merge. - self.pending.append(run) - self.merge_collapse() assert remaining.base == self.listlength @@ -590,6 +613,10 @@ self.base = base self.len = len + def __repr__(self): + return "" % ( + self.base, self.len, self.list[self.base: self.base+self.len]) + def copyitems(self): "Make a copy of the slice of the original list." start = self.base diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rbigint.py pypy-7.3.6+dfsg/rpython/rlib/rbigint.py --- pypy-7.3.5+dfsg/rpython/rlib/rbigint.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rbigint.py 2021-10-17 16:14:51.000000000 +0000 @@ -143,6 +143,8 @@ hop.exception_cannot_occur() def intsign(i): + if i == 0: + return 0 return -1 if i < 0 else 1 class rbigint(object): @@ -213,6 +215,12 @@ def fromint(intval): # This function is marked as pure, so you must not call it and # then modify the result. + + # for hypothesis testing, we want to be able to set SHIFT to a small + # number to hit edge cases more easily. so use a slower path if SHIFT + # is a nonstandard value + if SHIFT != 63 and SHIFT != 31: + return rbigint.fromrarith_int(intval) check_regular_int(intval) if intval < 0: @@ -886,18 +894,7 @@ elif digit & (digit - 1) == 0: mod = self.int_and_(digit - 1) else: - # Perform - size = UDIGIT_TYPE(self.numdigits() - 1) - - if size > 0: - wrem = self.widedigit(size) - while size > 0: - size -= 1 - wrem = ((wrem << SHIFT) | self.digit(size)) % digit - rem = _store_digit(wrem) - else: - rem = _store_digit(self.digit(0) % digit) - + rem = _int_rem_core(self, digit) if rem == 0: return NULLRBIGINT mod = rbigint([rem], -1 if self.sign < 0 else 1, 1) @@ -907,6 +904,34 @@ return mod @jit.elidable + def int_mod_int_result(self, iother): + if iother == 0: + raise ZeroDivisionError("long division or modulo by zero") + if self.sign == 0: + return 0 + + elif not int_in_valid_range(iother): + # Fallback to long. + return self.mod(rbigint.fromint(iother)).toint() # cannot raise + + assert iother != -sys.maxint-1 # covered by int_in_valid_range above + digit = abs(iother) + if digit == 1: + return 0 + elif digit == 2: + modm = self.digit(0) & 1 + if modm: + return -1 if iother < 0 else 1 + return 0 + elif digit & (digit - 1) == 0: + mod = self.int_and_(digit - 1).toint() # XXX improve + else: + mod = _int_rem_core(self, digit) * self.sign + if intsign(mod) * intsign(iother) == -1: + mod = mod + iother + return mod + + @jit.elidable def divmod(self, other): """ The / and % operators are now defined in terms of divmod(). @@ -924,6 +949,17 @@ have different signs. We then subtract one from the 'div' part of the outcome to keep the invariant intact. """ + if self.numdigits() > 1.2 * other.numdigits() and \ + other.numdigits() > HOLDER.DIV_LIMIT * 2: # * 2 to offset setup cost + res = divmod_big(self, other) + # be paranoid: keep the assert here for a bit + div, mod = res + assert div.mul(other).add(mod).eq(self) + return res + + return self._divmod_small(other) + + def _divmod_small(self, other): div, mod = _divrem(self, other) if mod.sign * other.sign == -1: mod = mod.add(other) @@ -977,7 +1013,6 @@ raise TypeError( "pow() 2nd argument " "cannot be negative when 3rd argument specified") - # XXX failed to implement raise ValueError("bigint pow() too negative") size_b = UDIGIT_TYPE(other.numdigits()) @@ -986,9 +1021,6 @@ if modulus.sign == 0: raise ValueError("pow() 3rd argument cannot be 0") - # if modulus < 0: - # negativeOutput = True - # modulus = -modulus if modulus.sign < 0: negativeOutput = True modulus = modulus.neg() @@ -1115,7 +1147,6 @@ raise TypeError( "pow() 2nd argument " "cannot be negative when 3rd argument specified") - # XXX failed to implement raise ValueError("bigint pow() too negative") assert iother >= 0 @@ -1123,9 +1154,6 @@ if modulus.sign == 0: raise ValueError("pow() 3rd argument cannot be 0") - # if modulus < 0: - # negativeOutput = True - # modulus = -modulus if modulus.sign < 0: negativeOutput = True modulus = modulus.neg() @@ -1169,8 +1197,6 @@ z = ONERBIGINT - # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) - # into helper function result = _help_mult(x, y, modulus) # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf j = 1 << (LONG_BIT-2) @@ -1288,7 +1314,7 @@ z._normalize() return z rshift._always_inline_ = 'try' # It's so fast that it's always benefitial. - + @jit.elidable def rqshift(self, int_other): wordshift = int_other / SHIFT @@ -1449,14 +1475,7 @@ if i == 1 and self._digits[0] == NULLDIGIT: return 0 msd = self.digit(i - 1) - msd_bits = 0 - while msd >= 32: - msd_bits += 6 - msd >>= 6 - msd_bits += [ - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ][msd] + msd_bits = bits_in_digit(msd) # yes, this can overflow: a huge number which fits 3 gigabytes of # memory has around 24 gigabits! bits = ovfcheck((i-1) * SHIFT) + msd_bits @@ -1484,11 +1503,6 @@ (1 * SHIFT) % 5] -# if the bigint has more digits than this, it cannot fit into an int -# Also, if it has less digits than this, then it must be <=sys.maxint in -# absolute value and so it must fit an int. -MAX_DIGITS_THAT_CAN_FIT_IN_INT = rbigint.fromint(-sys.maxint - 1).numdigits() - #_________________________________________________________________ @@ -1880,13 +1894,6 @@ for i in range(t1.numdigits()): ret._digits[2*shift + i] = t1._digits[i] - # Zero-out the digits higher than the ah*bh copy. */ - ## ignored, assuming that we initialize to zero - ##i = ret->ob_size - 2*shift - t1->ob_size; - ##if (i) - ## memset(ret->ob_digit + 2*shift + t1->ob_size, 0, - ## i * sizeof(digit)); - # 3. t2 <- al*bl, and copy into the low digits. t2 = al.mul(bl) assert t2.sign >= 0 @@ -1894,12 +1901,6 @@ for i in range(t2.numdigits()): ret._digits[i] = t2._digits[i] - # Zero out remaining digits. - ## ignored, assuming that we initialize to zero - ##i = 2*shift - t2->ob_size; /* number of uninitialized digits */ - ##if (i) - ## memset(ret->ob_digit + t2->ob_size, 0, i * sizeof(digit)); - # 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first # because it's fresher in cache. i = ret.numdigits() - shift # # digits after shift @@ -1954,6 +1955,21 @@ z._normalize() return z, rem +def _int_rem_core(a, digit): + # digit must be positive + size = UDIGIT_TYPE(a.numdigits() - 1) + + if size > 0: + wrem = a.widedigit(size) + while size > 0: + size -= 1 + wrem = ((wrem << SHIFT) | a.digit(size)) % digit + rem = _store_digit(wrem) + else: + rem = _store_digit(a.digit(0) % digit) + + return rem + def _v_iadd(x, xofs, m, y, n): """ x and y are rbigints, m >= n required. x.digits[0:n] is modified in place, @@ -2186,6 +2202,198 @@ rem.sign = - rem.sign return z, rem + + +class DivLimitHolder: + pass + +HOLDER = DivLimitHolder() +HOLDER.DIV_LIMIT = 21 + + +def _extract_digits(a, startindex, numdigits): + assert startindex >= 0 + if startindex >= a.numdigits(): + return NULLRBIGINT + stop = min(startindex + numdigits, a.numdigits()) + assert stop >= 0 + digits = a._digits[startindex: stop] + if not digits: + return NULLRBIGINT + r = rbigint(digits, 1) + r._normalize() + return r + +def div2n1n(a_container, a_startindex, b, n_S): + """Divide a 2*n_S-digit nonnegative integer a by an n_S-digit positive integer + b, using a recursive divide-and-conquer algorithm. + + Inputs: + n_S is a positive integer + b is a positive rbigint with exactly n_S digits + a is a nonnegative integer such that a < 2**(n_S * SHIFT) * b + + Output: + (q, r) such that a = b*q+r and 0 <= r < b. + + a is represented as a slice of a bigger number a_container, 2 * n_S digits + wide, starting at a_startindex + """ + if n_S <= HOLDER.DIV_LIMIT: + a = _extract_digits(a_container, a_startindex, 2 * n_S) + if a.sign == 0: + return NULLRBIGINT, NULLRBIGINT + res = _divrem(a, b) + return res + assert n_S & 1 == 0 + half_n_S = n_S >> 1 + # school division: (diagram from Burnikel & Ziegler, p 3) + # + # size half_n_S size n_S + # | | + # v v + # +----+----+----+----+ +----+----+ +----+----+ +---------+ + # | a1 | a2 | a3 | a4 | / | b1 | b2 | = | q1 | q2 | = | q | + # +====+====+====+====+ +----+----+ +----+----+ +---------+ + # | q1 * b1 | + # +----+----+----+ < + # | q1 * b2 | subtracting < first call to div3n2n + # +---------+----+ < + # | r1 | a4 | + # +---------+----+ + # | q2 * b1 | + # +----+----+----+ < + # | q2 * b2 | subtracing < second call to div3n2n + # +---------+ < + # | r | + # +---------+ + + b1, b2 = _extract_digits(b, half_n_S, half_n_S), _extract_digits(b, 0, half_n_S) + q1, r1 = div3n2n(a_container, a_startindex + n_S, a_container, a_startindex + half_n_S, b, b1, b2, half_n_S) + q2, r = div3n2n(r1, 0, a_container, a_startindex, b, b1, b2, half_n_S) + return _full_digits_lshift_then_or(q1, half_n_S, q2), r + +def div3n2n(a12_container, a12_startindex, a3_container, a3_startindex, b, b1, b2, n_S): + """Helper function for div2n1n; not intended to be called directly.""" + q, r = div2n1n(a12_container, a12_startindex, b1, n_S) + # equivalent to r = _full_digits_lshift_then_or(r, n_S, _extract_digits(a_container, a3_startindex, n_S)) + if r.sign == 0: + r = _extract_digits(a3_container, a3_startindex, n_S) + else: + digits = [NULLDIGIT] * (n_S + r.numdigits()) + index = 0 + for i in range(a3_startindex, min(a3_startindex + n_S, a3_container.numdigits())): + digits[index] = a3_container._digits[i] + index += 1 + index = n_S + for i in range(r.numdigits()): + digits[index] = r._digits[i] + index += 1 + r = rbigint(digits, 1) + r._normalize() + if q.sign == 0: + return q, r + r = r.sub(q.mul(b2)) + + # loop runs at most twice + while r.sign < 0: + q = q.int_sub(1) + r = r.add(b) + return q, r + +def _full_digits_lshift_then_or(a, n, b): + """ equivalent to a.lshift(n * SHIFT).or_(b) + the size of b must be smaller than n + """ + if a.sign == 0: + return b + bdigits = b.numdigits() + assert bdigits <= n + # b._digits + [NULLDIGIT] * (n - bdigits) + a._digits + digits = [NULLDIGIT] * (a.numdigits() + n) + for i in range(b.numdigits()): + digit = b._digits[i] + digits[i] = digit + index = n + for i in range(a.numdigits()): + digits[index] = a._digits[i] + index += 1 + + return rbigint(digits, 1) + +def _divmod_fast_pos(a, b): + """Divide a positive integer a by a positive integer b, giving + quotient and remainder.""" + # Use grade-school algorithm in base 2**n, n = nbits(b) + n = b.bit_length() + m = a.bit_length() + if m < n: + return NULLRBIGINT, a + # make n of the form SHIFT * HOLDER.DIV_LIMIT * 2 ** x + new_n = SHIFT * HOLDER.DIV_LIMIT + while new_n < n: + new_n <<= 1 + rest_shift = new_n - n + if rest_shift: + a = a.lshift(rest_shift) + b = b.lshift(rest_shift) + assert b.bit_length() == new_n + n = new_n + + n_S = n // SHIFT + r = range(0, a.numdigits(), n_S) + a_digits_base_two_pow_n = [None] * len(r) + index = 0 + for i in r: + assert i >= 0 + stop = i + n_S + assert stop >= 0 + a_digits_base_two_pow_n[index] = rbigint(a._digits[i: stop], 1) + index += 1 + + a_digits_index = len(a_digits_base_two_pow_n) - 1 + if a_digits_base_two_pow_n[a_digits_index].ge(b): + r = NULLRBIGINT + else: + r = a_digits_base_two_pow_n[a_digits_index] + a_digits_index -= 1 + q_digits = None + q_index_start = a_digits_index * n_S + while a_digits_index >= 0: + arg1 = _full_digits_lshift_then_or(r, n_S, a_digits_base_two_pow_n[a_digits_index]) + q_digitbase_two_pow_n, r = div2n1n(arg1, 0, b, n_S) + if q_digits is None: + q_digits = [NULLDIGIT] * (a_digits_index * n_S + q_digitbase_two_pow_n.numdigits()) + for i in range(q_digitbase_two_pow_n.numdigits()): + q_digits[q_index_start + i] = q_digitbase_two_pow_n._digits[i] + q_index_start -= n_S + a_digits_index -= 1 + if rest_shift: + r = r.rshift(rest_shift) + if q_digits is None: + q = NULLRBIGINT + else: + q = rbigint(q_digits, 1) + q._normalize() + r._normalize() + return q, r + +def divmod_big(a, b): + # code from Mark Dickinson via https://bugs.python.org/file11060/fast_div.py + # follows cr.yp.to/bib/1998/burnikel.ps + if b.eq(NULLRBIGINT): + raise ZeroDivisionError + elif b.sign < 0: + q, r = divmod_big(a.neg(), b.neg()) + return q, r.neg() + elif a.sign < 0: + q, r = divmod_big(a.invert(), b) + return q.invert(), b.add(r.invert()) + elif a.eq(NULLRBIGINT): + return NULLRBIGINT, NULLRBIGINT + else: + return _divmod_fast_pos(a, b) + def _x_int_lt(a, b, eq=False): """ Compare bigint a with int b for less than or less than or equal """ osign = 1 @@ -3095,3 +3303,10 @@ a = a.mod(b) return rbigint.fromint(gcd_binary(b.toint(), a.toint())) + + +# if the bigint has more digits than this, it cannot fit into an int +# Also, if it has less digits than this, then it must be <=sys.maxint in +# absolute value and so it must fit an int. +MAX_DIGITS_THAT_CAN_FIT_IN_INT = rbigint.fromint(-sys.maxint - 1).numdigits() + diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rfile.py pypy-7.3.6+dfsg/rpython/rlib/rfile.py --- pypy-7.3.5+dfsg/rpython/rlib/rfile.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rfile.py 2021-10-17 16:14:54.000000000 +0000 @@ -192,7 +192,7 @@ newmode = _sanitize_mode(mode) ll_mode = rffi.str2charp(newmode) try: - with rposix.FdValidator(fd): + with rposix.SuppressIPH(): ll_file = c_fdopen(fd, ll_mode) if not ll_file: errno = rposix.get_saved_errno() diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rjitlog/test/test_jitlog.py pypy-7.3.6+dfsg/rpython/rlib/rjitlog/test/test_jitlog.py --- pypy-7.3.5+dfsg/rpython/rlib/rjitlog/test/test_jitlog.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rjitlog/test/test_jitlog.py 2021-10-17 16:14:51.000000000 +0000 @@ -6,7 +6,7 @@ from rpython.jit.metainterp.history import AbstractDescr from rpython.rlib.objectmodel import compute_unique_id from rpython.rlib.rfile import create_file -from rpython.rlib.rposix import FdValidator +from rpython.rlib.rposix import SuppressIPH class FakeCallAssemblerLoopToken(AbstractDescr): def __init__(self, target): @@ -57,7 +57,7 @@ # code may use different runtime libraries (win32 visual2008 vs. # visual2019 for instance rfile = create_file(str(file), 'wb') - with FdValidator(rfile.fileno()): + with SuppressIPH(): jl.jitlog_init(rfile.fileno()) logger.start_new_trace(metainterp_sd, jd_name='jdname') log_trace = logger.log_trace(jl.MARK_TRACE, None, None) @@ -131,7 +131,7 @@ # code may use different runtime libraries (win32 visual2008 vs. # visual2019 for instance rfile = create_file(str(file), 'wb') - with FdValidator(rfile.fileno()): + with SuppressIPH(): jl.jitlog_init(rfile.fileno()) logger.start_new_trace(metainterp_sd, jd_name='jdname') log_trace = logger.log_trace(jl.MARK_TRACE, None, None) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rmmap.py pypy-7.3.6+dfsg/rpython/rlib/rmmap.py --- pypy-7.3.5+dfsg/rpython/rlib/rmmap.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rmmap.py 2021-10-17 16:14:51.000000000 +0000 @@ -660,7 +660,7 @@ res = c_madvise_safe(rffi.cast(PTR, rffi.ptradd(self.data, + start)), rffi.cast(size_t, end), rffi.cast(rffi.INT, flags)) - if res == 0: + if rffi.cast(lltype.Signed, res) == 0: return errno = rposix.get_saved_errno() raise OSError(errno, os.strerror(errno)) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rposix.py pypy-7.3.6+dfsg/rpython/rlib/rposix.py --- pypy-7.3.5+dfsg/rpython/rlib/rposix.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rposix.py 2021-10-17 16:14:51.000000000 +0000 @@ -39,71 +39,9 @@ ll2ctypes.TLS.errno = value if os.name == 'nt': - if platform.name == 'msvc': - includes=['errno.h','stdio.h', 'stdlib.h'] - else: - includes=['errno.h','stdio.h', 'stdint.h'] + includes=['errno.h','stdio.h', 'stdlib.h'] separate_module_sources =[''' /* Lifted completely from CPython 3 Modules/posixmodule.c */ - #if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900 - #include /* for _msize */ - typedef struct { - intptr_t osfhnd; - char osfile; - } my_ioinfo; - extern __declspec(dllimport) char * __pioinfo[]; - #define IOINFO_L2E 5 - #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) - #define IOINFO_ARRAYS 64 - #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS) - #define FOPEN 0x01 - #define _NO_CONSOLE_FILENO (intptr_t)-2 - - /* This function emulates what the windows CRT - does to validate file handles */ - RPY_EXTERN int - _PyVerify_fd(int fd) - { - const int i1 = fd >> IOINFO_L2E; - const int i2 = fd & ((1 << IOINFO_L2E) - 1); - - static size_t sizeof_ioinfo = 0; - - /* Determine the actual size of the ioinfo structure, - * as used by the CRT loaded in memory - */ - if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) { - sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS; - } - if (sizeof_ioinfo == 0) { - /* This should not happen... */ - goto fail; - } - - /* See that it isn't a special CLEAR fileno */ - if (fd != _NO_CONSOLE_FILENO) { - /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead - * we check pointer validity and other info - */ - if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) { - /* finally, check that the file is open */ - my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo); - if (info->osfile & FOPEN) { - return 1; - } - } - } - fail: - errno = EBADF; - return 0; - } - RPY_EXTERN void* enter_suppress_iph(void) {return (void*)NULL;}; - RPY_EXTERN void exit_suppress_iph(void* handle) {}; - #elif defined _MSC_VER - RPY_EXTERN int _PyVerify_fd(int fd) - { - return 1; - } static void __cdecl _Py_silent_invalid_parameter_handler( wchar_t const* expression, wchar_t const* function, @@ -125,19 +63,37 @@ ret = _set_thread_local_invalid_parameter_handler(_handler); /*fprintf(stdout, "exiting, setting %p returning %p\\n", old_handler, ret);*/ } - - #else - RPY_EXTERN int _PyVerify_fd(int fd) + RPY_EXTERN size_t wrap_write(int fd, const void* data, size_t count) { - return 1; + _invalid_parameter_handler old = enter_suppress_iph(); + if (count > 32767 && _isatty(fd)) { + // CPython Issue #11395, PyPy Issue #2636: the Windows console + // returns an error (12: not enough space error) on writing into + // stdout if stdout mode is binary and the length is greater than + // 66,000 bytes (or less, depending on heap usage). Can't easily + // test that, because we need 'fd' to be non-redirected... + count = 32767; + } + else if (count > 0x7fffffff) + { + count = 0x7fffffff; + } + size_t ret = _write(fd, data, count); + exit_suppress_iph(old); + return ret; + } + RPY_EXTERN size_t wrap_read(int fd, const void* buffer, size_t buffer_size) + { + _invalid_parameter_handler old = enter_suppress_iph(); + size_t ret = _read(fd, buffer, buffer_size); + exit_suppress_iph(old); + return ret; } - RPY_EXTERN void* enter_suppress_iph(void) {return (void*)NULL;}; - RPY_EXTERN void exit_suppress_iph(void* handle) {}; - #endif ''',] - post_include_bits=['RPY_EXTERN int _PyVerify_fd(int);', - 'RPY_EXTERN void* enter_suppress_iph();', + post_include_bits=['RPY_EXTERN void* enter_suppress_iph();', 'RPY_EXTERN void exit_suppress_iph(void* handle);', + 'RPY_EXTERN size_t wrap_write(int, const void*, size_t);', + 'RPY_EXTERN size_t wrap_read(int, const void*, size_t);', ] else: separate_module_sources = [] @@ -270,10 +226,6 @@ if os.name == 'nt': # is_valid_fd is useful only on MSVC9, and should be deprecated. With it - # we can replace FdValidator with SuppressIPH - is_valid_fd = jit.dont_look_inside(external("_PyVerify_fd", [rffi.INT], - rffi.INT, compilation_info=errno_eci, - )) c_enter_suppress_iph = jit.dont_look_inside(external("enter_suppress_iph", [], rffi.VOIDP, compilation_info=errno_eci)) c_exit_suppress_iph = jit.dont_look_inside(external("exit_suppress_iph", @@ -286,24 +238,6 @@ [rffi.VOIDP], lltype.Void, releasegil=False, compilation_info=errno_eci)) - @enforceargs(int) - def _validate_fd(fd): - if not is_valid_fd(fd): - from errno import EBADF - raise OSError(EBADF, 'Bad file descriptor') - - class FdValidator(object): - - def __init__(self, fd): - _validate_fd(fd) - - def __enter__(self): - self.invalid_param_hndlr = c_enter_suppress_iph() - return self - - def __exit__(self, *args): - c_exit_suppress_iph(self.invalid_param_hndlr) - class SuppressIPH_del(object): def __init__(self): @@ -328,29 +262,7 @@ def __exit__(self, *args): c_exit_suppress_iph(self.invalid_param_hndlr) - def _bound_for_write(fd, count): - if count > 32767 and c_isatty(fd): - # CPython Issue #11395, PyPy Issue #2636: the Windows console - # returns an error (12: not enough space error) on writing into - # stdout if stdout mode is binary and the length is greater than - # 66,000 bytes (or less, depending on heap usage). Can't easily - # test that, because we need 'fd' to be non-redirected... - count = 32767 - elif count > 0x7fffffff: - count = 0x7fffffff - return count else: - class FdValidator(object): - - def __init__(self, fd): - pass - - def __enter__(self): - return self - - def __exit__(self, *args): - pass - class SuppressIPH(object): def __init__(self): @@ -364,14 +276,11 @@ SuppressIPH_del = SuppressIPH - def _bound_for_write(fd, count): - return count - def closerange(fd_low, fd_high): # this behaves like os.closerange() from Python 2.6. for fd in xrange(fd_low, fd_high): try: - with FdValidator(fd): + with SuppressIPH(): os.close(fd) except OSError: pass @@ -519,7 +428,7 @@ return result def _dup(fd, inheritable=True): - with FdValidator(fd): + with SuppressIPH(): if inheritable: res = c_dup(fd) else: @@ -533,7 +442,7 @@ @replace_os_function('dup2') def dup2(fd, newfd, inheritable=True): - with FdValidator(fd): + with SuppressIPH(): if inheritable: res = c_dup2(fd, newfd) else: @@ -552,10 +461,18 @@ fd = c_open(_as_bytes0(path), flags, mode) return handle_posix_error('open', fd) -c_read = external(UNDERSCORE_ON_WIN32 + 'read', +if os.name == 'nt': + c_read = external('wrap_read', + [rffi.INT, rffi.VOIDP, POSIX_SIZE_T], POSIX_SSIZE_T, + save_err=rffi.RFFI_SAVE_ERRNO, compilation_info=errno_eci) + c_write = external('wrap_write', + [rffi.INT, rffi.VOIDP, POSIX_SIZE_T], POSIX_SSIZE_T, + save_err=rffi.RFFI_SAVE_ERRNO, compilation_info=errno_eci) +else: + c_read = external('read', [rffi.INT, rffi.VOIDP, POSIX_SIZE_T], POSIX_SSIZE_T, save_err=rffi.RFFI_SAVE_ERRNO) -c_write = external(UNDERSCORE_ON_WIN32 + 'write', + c_write = external('write', [rffi.INT, rffi.VOIDP, POSIX_SIZE_T], POSIX_SSIZE_T, save_err=rffi.RFFI_SAVE_ERRNO) c_close = external(UNDERSCORE_ON_WIN32 + 'close', [rffi.INT], rffi.INT, @@ -566,26 +483,23 @@ def read(fd, count): if count < 0: raise OSError(errno.EINVAL, None) - with FdValidator(fd): - with rffi.scoped_alloc_buffer(count) as buf: - void_buf = rffi.cast(rffi.VOIDP, buf.raw) - got = handle_posix_error('read', c_read(fd, void_buf, count)) - return buf.str(got) + with rffi.scoped_alloc_buffer(count) as buf: + void_buf = rffi.cast(rffi.VOIDP, buf.raw) + got = handle_posix_error('read', c_read(fd, void_buf, count)) + return buf.str(got) @replace_os_function('write') @signature(types.int(), types.any(), returns=types.any()) def write(fd, data): count = len(data) - with FdValidator(fd): - count = _bound_for_write(fd, count) - with rffi.scoped_nonmovingbuffer(data) as buf: - ret = c_write(fd, buf, count) - return handle_posix_error('write', ret) + with rffi.scoped_nonmovingbuffer(data) as buf: + ret = c_write(fd, buf, count) + return handle_posix_error('write', ret) @replace_os_function('close') @signature(types.int(), returns=types.any()) def close(fd): - with FdValidator(fd): + with SuppressIPH(): handle_posix_error('close', c_close(fd)) c_lseek = external('_lseeki64' if _WIN32 else 'lseek', @@ -594,7 +508,7 @@ @replace_os_function('lseek') def lseek(fd, pos, how): - with FdValidator(fd): + with SuppressIPH(): if SEEK_SET is not None: if how == 0: how = SEEK_SET @@ -680,18 +594,17 @@ @replace_os_function('ftruncate') def ftruncate(fd, length): - with FdValidator(fd): + with SuppressIPH(): handle_posix_error('ftruncate', c_ftruncate(fd, length)) @replace_os_function('fsync') def fsync(fd): - with FdValidator(fd): + with SuppressIPH(): handle_posix_error('fsync', c_fsync(fd)) @replace_os_function('fdatasync') def fdatasync(fd): - with FdValidator(fd): - handle_posix_error('fdatasync', c_fdatasync(fd)) + handle_posix_error('fdatasync', c_fdatasync(fd)) def sync(): c_sync() @@ -758,8 +671,7 @@ @replace_os_function('fchdir') def fchdir(fd): - with FdValidator(fd): - handle_posix_error('fchdir', c_fchdir(fd)) + handle_posix_error('fchdir', c_fchdir(fd)) @replace_os_function('access') @specialize.argtype(0) @@ -1214,7 +1126,7 @@ @replace_os_function('isatty') def isatty(fd): - with FdValidator(fd): + with SuppressIPH(): return c_isatty(fd) != 0 return False diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rposix_stat.py pypy-7.3.6+dfsg/rpython/rlib/rposix_stat.py --- pypy-7.3.5+dfsg/rpython/rlib/rposix_stat.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rposix_stat.py 2021-10-17 16:14:51.000000000 +0000 @@ -4,6 +4,7 @@ """ import os, sys +import collections from rpython.flowspace.model import Constant from rpython.flowspace.operation import op @@ -20,7 +21,7 @@ from rpython.rlib.objectmodel import specialize, we_are_translated, not_rpython from rpython.rtyper.lltypesystem import lltype, rffi from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rlib.rarithmetic import intmask +from rpython.rlib.rarithmetic import widen from rpython.rlib.rposix import ( replace_os_function, handle_posix_error, _as_bytes0) from rpython.rlib import rposix @@ -66,6 +67,10 @@ ("nsec_mtime", lltype.Signed), # ("nsec_ctime", lltype.Signed), # ] +if sys.platform == 'win32': + ALL_STAT_FIELDS.append(("st_file_attributes", lltype.Signed)) + ALL_STAT_FIELDS.append(("st_reparse_tag", lltype.Signed)) + N_INDEXABLE_FIELDS = 10 # For OO backends, expose only the portable fields (the first 10). @@ -82,6 +87,7 @@ ("f_favail", lltype.Signed), ("f_flag", lltype.Signed), ("f_namemax", lltype.Signed), + ("f_fsid", lltype.Unsigned), ] @specialize.arg(1) @@ -144,27 +150,53 @@ TYPE = STAT_FIELD_TYPES[attrname] return lltype_to_annotation(TYPE) - def _get_rmarshall_support_(self): # for rlib.rmarshal - # reduce and recreate stat_result objects from 10-tuples - # (we ignore the extra values here for simplicity and portability) - def stat_result_reduce(st): - return (st[0], st[1], st[2], st[3], st[4], - st[5], st[6], st.st_atime, st.st_mtime, st.st_ctime) - - def stat_result_recreate(tup): - atime, mtime, ctime = tup[7:] - result = tup[:7] - result += (int(atime), int(mtime), int(ctime)) - result += extra_zeroes - result += (int((atime - result[7]) * 1e9), - int((mtime - result[8]) * 1e9), - int((ctime - result[9]) * 1e9)) - return make_stat_result(result) - s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE) - for name, TYPE in PORTABLE_STAT_FIELDS[:7]] + if sys.platform == 'win32': + def _get_rmarshall_support_(self): # for rlib.rmarshal + # reduce and recreate stat_result objects from 10-tuples + # (we ignore the extra values here for simplicity and portability) + def stat_result_reduce(st): + return (st[0], st[1], st[2], st[3], st[4], + st[5], st[6], st.st_atime, st.st_mtime, st.st_ctime, + st.st_file_attributes, st.st_reparse_tag) + + def stat_result_recreate(tup): + atime, mtime, ctime = tup[7:10] + result = tup[:7] + result += (int(atime), int(mtime), int(ctime)) + result += extra_zeroes + result += (int((atime - result[7]) * 1e9), + int((mtime - result[8]) * 1e9), + int((ctime - result[9]) * 1e9)) + result += tup[10:] + return make_stat_result(result) + s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE) + for name, TYPE in PORTABLE_STAT_FIELDS[:7]] + + 3 * [lltype_to_annotation(lltype.Float)] + + 2 * [lltype_to_annotation(lltype.Int)]) + extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS) - 3) + return s_reduced, stat_result_reduce, stat_result_recreate + else: + def _get_rmarshall_support_(self): # for rlib.rmarshal + # reduce and recreate stat_result objects from 10-tuples + # (we ignore the extra values here for simplicity and portability) + def stat_result_reduce(st): + return (st[0], st[1], st[2], st[3], st[4], + st[5], st[6], st.st_atime, st.st_mtime, st.st_ctime) + + def stat_result_recreate(tup): + atime, mtime, ctime = tup[7:] + result = tup[:7] + result += (int(atime), int(mtime), int(ctime)) + result += extra_zeroes + result += (int((atime - result[7]) * 1e9), + int((mtime - result[8]) * 1e9), + int((ctime - result[9]) * 1e9)) + return make_stat_result(result) + s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE) + for name, TYPE in PORTABLE_STAT_FIELDS[:7]] + 3 * [lltype_to_annotation(lltype.Float)]) - extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS) - 3) - return s_reduced, stat_result_reduce, stat_result_recreate + extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS) - 3) + return s_reduced, stat_result_reduce, stat_result_recreate class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)): @@ -253,9 +285,16 @@ value = lltype.cast_primitive(TYPE, tup[i]) positional.append(value) kwds = {} - kwds['st_atime'] = tup[7] + 1e-9 * tup[-3] - kwds['st_mtime'] = tup[8] + 1e-9 * tup[-2] - kwds['st_ctime'] = tup[9] + 1e-9 * tup[-1] + if sys.platform == 'win32': + kwds['st_atime'] = tup[7] + 1e-9 * tup[-5] + kwds['st_mtime'] = tup[8] + 1e-9 * tup[-4] + kwds['st_ctime'] = tup[9] + 1e-9 * tup[-3] + kwds['st_file_attributes'] = tup[-2] + kwds['st_reparse_tag'] = tup[-1] + else: + kwds['st_atime'] = tup[7] + 1e-9 * tup[-3] + kwds['st_mtime'] = tup[8] + 1e-9 * tup[-2] + kwds['st_ctime'] = tup[9] + 1e-9 * tup[-1] for value, (name, TYPE) in zip(tup, STAT_FIELDS)[N_INDEXABLE_FIELDS:]: if name.startswith('nsec_'): continue # ignore the nsec_Xtime here @@ -345,12 +384,12 @@ index = s_int.const return r_sta.redispatch_getfield(hop, index) - def make_statvfs_result(tup): args = tuple( lltype.cast_primitive(TYPE, value) for value, (name, TYPE) in zip(tup, STATVFS_FIELDS)) - return os.statvfs_result(args) + # only used untranslated + return statvfs_result(*args) class MakeStatvfsResultEntry(extregistry.ExtRegistryEntry): _about_ = make_statvfs_result @@ -450,7 +489,10 @@ posix_declaration(ALL_STAT_FIELDS[_i]) del _i -STAT_FIELDS += ALL_STAT_FIELDS[-3:] # nsec_Xtime +if sys.platform == 'win32': + STAT_FIELDS += ALL_STAT_FIELDS[-5:] # nsec_Xtime, st_file_attributes, st_reparse_tag +else: + STAT_FIELDS += ALL_STAT_FIELDS[-3:] # nsec_Xtime # these two global vars only list the fields defined in the underlying platform STAT_FIELD_TYPES = dict(STAT_FIELDS) # {'st_xxx': TYPE} @@ -459,7 +501,7 @@ STATVFS_FIELD_TYPES = dict(STATVFS_FIELDS) STATVFS_FIELD_NAMES = [name for name, tp in STATVFS_FIELDS] - +statvfs_result = collections.namedtuple('statvfs_result', STATVFS_FIELD_NAMES) def build_stat_result(st): # only for LL backends @@ -514,7 +556,8 @@ st.c_f_ffree, st.c_f_favail, st.c_f_flag, - st.c_f_namemax + st.c_f_namemax, + st.c_f_fsid, )) @@ -561,13 +604,13 @@ return make_stat_result((win32traits._S_IFCHR, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0)) + 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_PIPE: # socket or named pipe return make_stat_result((win32traits._S_IFIFO, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0)) + 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_UNKNOWN: error = rwin32.GetLastError_saved() if error != 0: @@ -575,16 +618,13 @@ # else: unknown but valid file # normal disk file (FILE_TYPE_DISK) - info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION, - flavor='raw', zero=True) - try: - res = win32traits.GetFileInformationByHandle(handle, info) + with lltype.scoped_alloc(win32traits.BY_HANDLE_FILE_INFORMATION, + zero=True) as fileInfo: + res = win32traits.GetFileInformationByHandle(handle, fileInfo) if res == 0: raise WindowsError(rwin32.GetLastError_saved(), "os_fstat failed") - return win32_by_handle_info_to_stat(win32traits, info) - finally: - lltype.free(info, flavor='raw') + return win32_by_handle_info_to_stat(win32traits, fileInfo, 0) @replace_os_function('stat') @specialize.argtype(0) @@ -597,7 +637,7 @@ else: traits = _preferred_traits(path) path = traits.as_str0(path) - return win32_xstat(traits, path, traverse=True) + return win32_xstat3(traits, path, traverse=True) @replace_os_function('lstat') @specialize.argtype(0) @@ -610,29 +650,29 @@ else: traits = _preferred_traits(path) path = traits.as_str0(path) - return win32_xstat(traits, path, traverse=False) + return win32_xstat3(traits, path, traverse=False) @specialize.argtype(0) def stat3(path): - # On Windows, the algorithm behind os.stat() changed a lot between - # Python 2 and Python 3. This is the Python 3 version. - if not _WIN32: - return stat(path) - else: + if _WIN32: + # On Windows, the algorithm behind os.stat() changed a lot between + # Python 2 and Python 3. This is the Python 3 version. traits = _preferred_traits(path) path = traits.as_str0(path) return win32_xstat3(traits, path, traverse=True) + else: + return stat(path) @specialize.argtype(0) def lstat3(path): - # On Windows, the algorithm behind os.lstat() changed a lot between - # Python 2 and Python 3. This is the Python 3 version. - if not _WIN32: - return lstat(path) - else: + if _WIN32: + # On Windows, the algorithm behind os.lstat() changed a lot between + # Python 2 and Python 3. This is the Python 3 version. traits = _preferred_traits(path) path = traits.as_str0(path) return win32_xstat3(traits, path, traverse=False) + else: + return lstat(path) if rposix.HAVE_FSTATAT: from rpython.rlib.rposix import AT_FDCWD, AT_SYMLINK_NOFOLLOW @@ -673,67 +713,149 @@ def make_longlong(high, low): return (rffi.r_longlong(high) << 32) + rffi.r_longlong(low) - @specialize.arg(0) - def win32_xstat(traits, path, traverse=False): - # XXX 'traverse' is ignored - win32traits = make_win32_traits(traits) - with lltype.scoped_alloc( - win32traits.WIN32_FILE_ATTRIBUTE_DATA) as data: - res = win32traits.GetFileAttributesEx( - path, win32traits.GetFileExInfoStandard, data) - if res == 0: - errcode = rwin32.GetLastError_saved() - if errcode == win32traits.ERROR_SHARING_VIOLATION: - res = win32_attributes_from_dir( - win32traits, path, data) - if res == 0: - errcode = rwin32.GetLastError_saved() - raise WindowsError(errcode, "os_stat failed") - return win32_attribute_data_to_stat(win32traits, data) + def IsReparseTagNameSurrogate(_tag): + return widen(_tag) & 0x20000000 @specialize.arg(0) - def win32_xstat3(traits, path, traverse=False): + def win32_xstat3(traits, path0, traverse=False): # This is the Python3 version of os.stat() or lstat(). - # XXX 'traverse' is ignored, and everything related to - # the "reparse points" is missing win32traits = make_win32_traits(traits) + path = traits.as_str0(path0) + + with lltype.scoped_alloc(win32traits.BY_HANDLE_FILE_INFORMATION, + zero=True) as fileInfo: + with lltype.scoped_alloc(win32traits.FILE_ATTRIBUTE_TAG_INFO, + zero=True) as tagInfo: + return win32_xstat_impl(win32traits, path, traverse, fileInfo, tagInfo) - hFile = win32traits.CreateFile(traits.as_str0(path), - win32traits.FILE_READ_ATTRIBUTES, - 0, + @specialize.arg(0) + def win32_xstat_impl(traits, path, traverse, fileInfo, tagInfo): + access = traits.FILE_READ_ATTRIBUTES + flags = traits.FILE_FLAG_BACKUP_SEMANTICS + isUnhandledTag = False + if not traverse: + flags |= traits.FILE_FLAG_OPEN_REPARSE_POINT + hFile = traits.CreateFile(path, access, 0, lltype.nullptr(rwin32.LPSECURITY_ATTRIBUTES.TO), - win32traits.OPEN_EXISTING, - win32traits.FILE_ATTRIBUTE_NORMAL | - win32traits.FILE_FLAG_BACKUP_SEMANTICS | - 0, # win32traits.FILE_FLAG_OPEN_REPARSE_POINT, + traits.OPEN_EXISTING, + flags, rwin32.NULL_HANDLE) if hFile == rwin32.INVALID_HANDLE_VALUE: + # Either the path doesn't exist, or the caller lacks access errcode = rwin32.GetLastError_saved() - if (errcode != win32traits.ERROR_ACCESS_DENIED and - errcode != win32traits.ERROR_SHARING_VIOLATION): - raise WindowsError(errcode, "os_stat failed") - - with lltype.scoped_alloc( - win32traits.WIN32_FILE_ATTRIBUTE_DATA) as data: - if win32_attributes_from_dir(win32traits, path, data) == 0: + if (errcode == traits.ERROR_ACCESS_DENIED or + errcode == traits.ERROR_SHARING_VIOLATION): + # Try reading the parent directory + if win32_attributes_from_dir(traits, path, fileInfo, tagInfo) == 0: raise WindowsError(rwin32.GetLastError_saved(), "win32_attributes_from_dir failed") - return win32_attribute_data_to_stat(win32traits, data) - - with lltype.scoped_alloc( - win32traits.BY_HANDLE_FILE_INFORMATION, zero=True) as data: - res = win32traits.GetFileInformationByHandle(hFile, data) - errcode = rwin32.GetLastError_saved() - rwin32.CloseHandle(hFile) - if res == 0: - raise WindowsError(errcode, "GetFileInformationByHandle failed") - return win32_by_handle_info_to_stat(win32traits, data) + if widen(fileInfo.c_dwFileAttributes) & traits.FILE_ATTRIBUTE_REPARSE_POINT: + if traverse or not IsReparseTagNameSurrogate(tagInfo.c_ReparseTag): + raise WindowsError(rwin32.GetLastError_saved(), + "win32_xstat failed") + elif errcode == traits.ERROR_INVALID_PARAMETER: + # \\.\con requires read or write access. + hFile = traits.CreateFile(path, + access | traits.GENERIC_READ, + traits.FILE_SHARE_READ | traits.FILE_SHARE_WRITE, + lltype.nullptr(rwin32.LPSECURITY_ATTRIBUTES.TO), + traits.OPEN_EXISTING, flags, + rwin32.NULL_HANDLE) + if hFile == rwin32.INVALID_HANDLE_VALUE: + raise WindowsError(rwin32.GetLastError_saved(), + "win32_xstat failed") + elif errcode == traits.ERROR_CANT_ACCESS_FILE: + # bpo37834: opne unhandled reparse points if traverse fails + if traverse: + traverse = False + isUnhandledTag = True + hFile = traits.CreateFile(path, access, 0, + lltype.nullptr(rwin32.LPSECURITY_ATTRIBUTES.TO), + traits.OPEN_EXISTING, + flags | traits.FILE_FLAG_OPEN_REPARSE_POINT, + rwin32.NULL_HANDLE) + if hFile == rwin32.INVALID_HANDLE_VALUE: + raise WindowsError(rwin32.GetLastError_saved(), + "win32_xstat failed") + else: + raise WindowsError(errcode, "os_stat failed") + + if hFile != rwin32.INVALID_HANDLE_VALUE: + # Handle types other than files on disk. + fileType = traits.GetFileType(hFile) + if fileType != traits.FILE_TYPE_DISK: + errcode = rwin32.GetLastError_saved() + if fileType == traits.FILE_TYPE_UNKNOWN and errcode != 0: + rwin32.CloseHandle(hFile) + raise WindowsError(errcode, "os_stat failed") + fileAttributes = widen(traits.GetFileAttributes(path)) + st_mode = 0 + if (fileAttributes != traits.INVALID_FILE_ATTRIBUTES and + fileAttributes & traits.FILE_ATTRIBUTE_DIRECTORY): + # \\.\pipe\ or \\.\mailslot\ + st_mode = traits._S_IFDIR + elif fileType == traits.FILE_TYPE_CHAR: + # \\.\nul + st_mode = traits._S_IFCHR + elif fileType == traits.FILE_TYPE_PIPE: + # \\.\pipe\spam + st_mode = traits._S_IFIFO + rwin32.CloseHandle(hFile) + result = (st_mode, + 0, 0, 0, 0, 0, + 0, + 0, 0, 0, + 0, 0, 0, + 0, 0) + # FILE_TYPE_UNKNOWN, e.g. \\.\mailslot\waitfor.exe\spam + return make_stat_result(result) + # Query the reparse tag, and traverse a non-link. + if not traverse: + if not traits.GetFileInformationByHandleEx(hFile, + traits.FileAttributeTagInfo, tagInfo, + traits.TagInfoSize): + errcode = rwin32.GetLastError_saved() + if errcode in (traits.ERROR_INVALID_PARAMETER, + traits.ERROR_INVALID_FUNCTION, + traits.ERROR_NOT_SUPPORTED): + tagInfo.c_FileAttributes = rffi.cast( + rwin32.DWORD, traits.FILE_ATTRIBUTE_NORMAL) + tagInfo.c_ReparseTag = rffi.cast(rwin32.DWORD, 0) + else: + rwin32.CloseHandle(hFile) + raise WindowsError(errcode, "os_stat failed") + elif widen(tagInfo.c_FileAttributes) & traits.FILE_ATTRIBUTE_REPARSE_POINT: + if IsReparseTagNameSurrogate(tagInfo.c_ReparseTag): + if isUnhandledTag: + # Traversing previously failed for either this + # link or its target. + rwin32.CloseHandle(hFile) + raise WindowsError( + traits.ERROR_CANT_ACCESS_FILE, + "os_stat failed") + # Traverse a non-link, but not if traversing already + # failed for an unhandled tag. + elif not isUnhandledTag: + rwin32.CloseHandle(hFile) + return win32_xstat_impl(traits, path, True, fileInfo, tagInfo) + + res = traits.GetFileInformationByHandle(hFile, fileInfo) + errcode = rwin32.GetLastError_saved() + rwin32.CloseHandle(hFile) + if res == 0: + raise WindowsError(errcode, "GetFileInformationByHandle failed") + result = win32_by_handle_info_to_stat(traits, fileInfo, tagInfo.c_ReparseTag) + + # TBD: adjust the file execute permissions by finding the file extension + # if fileExtension in ('exe', 'bat', 'cmd', 'com'): + # result.st_mode |= 0x0111 + return result @specialize.arg(0) def win32_attributes_to_mode(win32traits, attributes): m = 0 - attributes = intmask(attributes) + attributes = widen(attributes) if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY: m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other else: @@ -752,16 +874,23 @@ mtime, extra_mtime = FILE_TIME_to_time_t_nsec(info.c_ftLastWriteTime) atime, extra_atime = FILE_TIME_to_time_t_nsec(info.c_ftLastAccessTime) + st_ino = 0 + st_dev = 0 + st_nlink = 0 + st_file_attributes = info.c_dwFileAttributes + st_reparse_tag = 0 + result = (st_mode, - 0, 0, 0, 0, 0, + st_ino, st_dev, st_nlink, 0, 0, st_size, atime, mtime, ctime, - extra_atime, extra_mtime, extra_ctime) + extra_atime, extra_mtime, extra_ctime, + st_file_attributes, st_reparse_tag) return make_stat_result(result) @specialize.arg(0) - def win32_by_handle_info_to_stat(win32traits, info): + def win32_by_handle_info_to_stat(win32traits, info, reparse_tag): # similar to the one above st_mode = win32_attributes_to_mode(win32traits, info.c_dwFileAttributes) st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow) @@ -773,29 +902,37 @@ st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow) st_dev = info.c_dwVolumeSerialNumber st_nlink = info.c_nNumberOfLinks + st_file_attributes = info.c_dwFileAttributes + st_reparse_tag = reparse_tag result = (st_mode, st_ino, st_dev, st_nlink, 0, 0, st_size, atime, mtime, ctime, - extra_atime, extra_mtime, extra_ctime) + extra_atime, extra_mtime, extra_ctime, + st_file_attributes, st_reparse_tag) return make_stat_result(result) @specialize.arg(0) - def win32_attributes_from_dir(win32traits, path, data): - filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw') - try: - hFindFile = win32traits.FindFirstFile(path, filedata) + def win32_attributes_from_dir(traits, path, info, tagInfo): + with lltype.scoped_alloc(traits.WIN32_FIND_DATA) as filedata: + hFindFile = traits.FindFirstFile(path, filedata) if hFindFile == rwin32.INVALID_HANDLE_VALUE: return 0 - win32traits.FindClose(hFindFile) - data.c_dwFileAttributes = filedata.c_dwFileAttributes - rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime) - rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime) - rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime) - data.c_nFileSizeHigh = filedata.c_nFileSizeHigh - data.c_nFileSizeLow = filedata.c_nFileSizeLow + traits.FindClose(hFindFile) + tagInfo.c_ReparseTag = win32_find_data_to_file_info(traits, filedata, info) return 1 - finally: - lltype.free(filedata, flavor='raw') + + @specialize.arg(0) + def win32_find_data_to_file_info(traits, filedata, info): + info.c_dwFileAttributes = filedata.c_dwFileAttributes + rffi.structcopy(info.c_ftCreationTime, filedata.c_ftCreationTime) + rffi.structcopy(info.c_ftLastAccessTime, filedata.c_ftLastAccessTime) + rffi.structcopy(info.c_ftLastWriteTime, filedata.c_ftLastWriteTime) + info.c_nFileSizeHigh = filedata.c_nFileSizeHigh + info.c_nFileSizeLow = filedata.c_nFileSizeLow + attr = widen(filedata.c_dwFileAttributes) + if attr & traits.FILE_ATTRIBUTE_REPARSE_POINT: + return filedata.c_dwReserved0 + return 0 diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rsignal.py pypy-7.3.6+dfsg/rpython/rlib/rsignal.py --- pypy-7.3.5+dfsg/rpython/rlib/rsignal.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rsignal.py 2021-10-17 16:14:51.000000000 +0000 @@ -99,6 +99,7 @@ c_pause = external('pause', [], rffi.INT, releasegil=True) c_siginterrupt = external('siginterrupt', [rffi.INT, rffi.INT], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) +c_raise = external('raise', [rffi.INT], rffi.INT) if sys.platform != 'win32': itimervalP = rffi.CArrayPtr(itimerval) @@ -110,6 +111,32 @@ c_pthread_kill = external('pthread_kill', [lltype.Signed, rffi.INT], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) +HAVE_STRSIGNAL = rffi_platform.Has("strsignal") +if HAVE_STRSIGNAL: + c_strsignal = external('strsignal', [rffi.INT], rffi.CCHARP) + def strsignal(signum): + res = c_strsignal(signum) + if not res: + return None + return rffi.charp2str(res) +else: + def strsignal(signum): + # CPython does this too! + if signum == SIGINT: + return "Interrupt"; + elif signum == SIGILL: + return "Illegal instruction"; + elif signum == SIGABRT: + return "Aborted"; + elif signum == SIGFPE: + return "Floating point exception"; + elif signum == SIGSEGV: + return "Segmentation fault"; + elif signum == SIGTERM: + return "Terminated"; + return None + + if sys.platform != 'win32': c_sigset_t = rffi.COpaquePtr('sigset_t', compilation_info=eci) c_sigemptyset = external('sigemptyset', [c_sigset_t], rffi.INT) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/_rsocket_rffi.py pypy-7.3.6+dfsg/rpython/rlib/_rsocket_rffi.py --- pypy-7.3.5+dfsg/rpython/rlib/_rsocket_rffi.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/_rsocket_rffi.py 2021-10-17 16:14:51.000000000 +0000 @@ -65,7 +65,13 @@ header_lines.extend([ '#include ', # these types do not exist on microsoft compilers + '#ifdef _WIN64', + 'typedef long long ssize_t;', + 'typedef unsigned long long size_t;', + '#else', 'typedef int ssize_t;', + 'typedef unsigned int size_t;', + '#endif', 'typedef unsigned __int16 uint16_t;', 'typedef unsigned __int32 uint32_t;', ]) @@ -1242,8 +1248,12 @@ socketsetsockopt = external('setsockopt', [socketfd_type, rffi.INT, rffi.INT, rffi.VOIDP, socklen_t], rffi.INT, save_err=SAVE_ERR) -socketrecv = external('recv', [socketfd_type, rffi.VOIDP, rffi.INT, - rffi.INT], ssize_t, save_err=SAVE_ERR) +if WIN32: + socketrecv = external('recv', [socketfd_type, rffi.VOIDP, rffi.INT, + rffi.INT], rffi.INT, save_err=SAVE_ERR) +else: + socketrecv = external('recv', [socketfd_type, rffi.VOIDP, rffi.INT, + rffi.INT], ssize_t, save_err=SAVE_ERR) recvfrom = external('recvfrom', [socketfd_type, rffi.VOIDP, size_t, rffi.INT, sockaddr_ptr, socklen_t_ptr], rffi.INT, save_err=SAVE_ERR) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rstruct/formatiterator.py pypy-7.3.6+dfsg/rpython/rlib/rstruct/formatiterator.py --- pypy-7.3.5+dfsg/rpython/rlib/rstruct/formatiterator.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rstruct/formatiterator.py 2021-10-17 16:14:51.000000000 +0000 @@ -72,6 +72,8 @@ self.operate(fmtdesc, repetitions) break else: + if c == '\0': + raise StructError("embedded null character") raise StructError("bad char in struct format") if not self._operate_is_specialized_: if fmtdesc.alignment > 1: diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rstruct/test/test_runpack.py pypy-7.3.6+dfsg/rpython/rlib/rstruct/test/test_runpack.py --- pypy-7.3.5+dfsg/rpython/rlib/rstruct/test/test_runpack.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rstruct/test/test_runpack.py 2021-10-17 16:14:51.000000000 +0000 @@ -3,15 +3,16 @@ from rpython.rlib.rstruct.runpack import runpack from rpython.rlib.rstruct import standardfmttable from rpython.rlib.rstruct.error import StructError -from rpython.rlib.rarithmetic import LONG_BIT +from rpython.rlib.rarithmetic import LONG_BIT, long_typecode import struct class TestRStruct(BaseRtypingTest): def test_unpack(self): import sys pad = '\x00' * (LONG_BIT//8-1) # 3 or 7 null bytes + fmt = 's' + long_typecode + long_typecode def fn(): - return runpack('sll', 'a'+pad+'\x03'+pad+'\x04'+pad)[1] + return runpack(fmt, 'a'+pad+'\x03'+pad+'\x04'+pad)[1] result = 3 if sys.byteorder == 'little' else 3 << (LONG_BIT-8) assert fn() == result assert self.interpret(fn, []) == result diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rutf8.py pypy-7.3.6+dfsg/rpython/rlib/rutf8.py --- pypy-7.3.5+dfsg/rpython/rlib/rutf8.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rutf8.py 2021-10-17 16:14:51.000000000 +0000 @@ -638,7 +638,25 @@ return result -def make_utf8_escape_function(pass_printable=False, quotes=False, prefix=None): +TABLE = '0123456789abcdef' + +def char_escape_helper(result, char): + if char >= 0x10000 or char < 0: + result.append("\\U") + zeros = 8 + elif char >= 0x100: + result.append("\\u") + zeros = 4 + else: + result.append("\\x") + zeros = 2 + for i in range(zeros-1, -1, -1): + result.append(TABLE[(char >> (4 * i)) & 0x0f]) + +def make_utf8_escape_function(pass_printable=False, quotes=False, prefix=None, unicodedb=None): + if pass_printable: + assert unicodedb is not None, "need to give unicodedb explicitly!" + @jit.elidable def unicode_escape(s): size = len(s) @@ -717,21 +735,6 @@ result.append(chr(quote)) return result.build() - TABLE = '0123456789abcdef' - - def char_escape_helper(result, char): - if char >= 0x10000 or char < 0: - result.append("\\U") - zeros = 8 - elif char >= 0x100: - result.append("\\u") - zeros = 4 - else: - result.append("\\x") - zeros = 2 - for i in range(zeros-1, -1, -1): - result.append(TABLE[(char >> (4 * i)) & 0x0f]) - return unicode_escape #, char_escape_helper @finishsigs diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rvmprof/cintf.py pypy-7.3.6+dfsg/rpython/rlib/rvmprof/cintf.py --- pypy-7.3.5+dfsg/rpython/rlib/rvmprof/cintf.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rvmprof/cintf.py 2021-10-17 16:14:51.000000000 +0000 @@ -62,7 +62,8 @@ else: # Guessing a BSD-like Unix platform compile_extra += ['-DVMPROF_UNIX'] - compile_extra += ['-DVMPROF_APPLE'] + if sys.platform.startswith('darwin'): + compile_extra += ['-DVMPROF_APPLE'] if sys.platform.startswith('freebsd'): _libs = ['unwind'] else: diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rwin32file.py pypy-7.3.6+dfsg/rpython/rlib/rwin32file.py --- pypy-7.3.5+dfsg/rpython/rlib/rwin32file.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rwin32file.py 2021-10-17 16:14:51.000000000 +0000 @@ -31,8 +31,15 @@ 'INVALID_FILE_ATTRIBUTES') ERROR_SHARING_VIOLATION = platform.ConstantInteger( 'ERROR_SHARING_VIOLATION') - ERROR_ACCESS_DENIED = platform.ConstantInteger( - 'ERROR_ACCESS_DENIED') + ERROR_ACCESS_DENIED = platform.ConstantInteger('ERROR_ACCESS_DENIED') + ERROR_CANT_ACCESS_FILE = platform.ConstantInteger( + 'ERROR_CANT_ACCESS_FILE') + ERROR_INVALID_PARAMETER = platform.ConstantInteger( + 'ERROR_INVALID_PARAMETER') + ERROR_NOT_SUPPORTED = platform.ConstantInteger( + 'ERROR_NOT_SUPPORTED') + ERROR_INVALID_FUNCTION = platform.ConstantInteger( + 'ERROR_INVALID_FUNCTION') MOVEFILE_REPLACE_EXISTING = platform.ConstantInteger( 'MOVEFILE_REPLACE_EXISTING') _S_IFDIR = platform.ConstantInteger('_S_IFDIR') @@ -50,17 +57,23 @@ FILE_TYPE_UNKNOWN = platform.ConstantInteger('FILE_TYPE_UNKNOWN') FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR') FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE') - - FILE_READ_ATTRIBUTES = platform.ConstantInteger( - 'FILE_READ_ATTRIBUTES') + FILE_TYPE_DISK = platform.ConstantInteger('FILE_TYPE_DISK') + FILE_READ_ATTRIBUTES = platform.ConstantInteger('FILE_READ_ATTRIBUTES') FILE_WRITE_ATTRIBUTES = platform.ConstantInteger( 'FILE_WRITE_ATTRIBUTES') - OPEN_EXISTING = platform.ConstantInteger( - 'OPEN_EXISTING') + GENERIC_READ = platform.ConstantInteger('GENERIC_READ') + FILE_SHARE_READ = platform.ConstantInteger('FILE_SHARE_READ') + FILE_SHARE_WRITE = platform.ConstantInteger('FILE_SHARE_WRITE') + OPEN_EXISTING = platform.ConstantInteger('OPEN_EXISTING') FILE_ATTRIBUTE_NORMAL = platform.ConstantInteger( 'FILE_ATTRIBUTE_NORMAL') FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger( 'FILE_FLAG_BACKUP_SEMANTICS') + FILE_FLAG_OPEN_REPARSE_POINT = platform.ConstantInteger( + 'FILE_FLAG_OPEN_REPARSE_POINT') + FILE_ATTRIBUTE_REPARSE_POINT = platform.ConstantInteger( + 'FILE_ATTRIBUTE_REPARSE_POINT') + FileAttributeTagInfo = platform.ConstantInteger('FileAttributeTagInfo') VOLUME_NAME_DOS = platform.ConstantInteger('VOLUME_NAME_DOS') VOLUME_NAME_NT = platform.ConstantInteger('VOLUME_NAME_NT') @@ -86,6 +99,11 @@ ('nFileIndexHigh', rwin32.DWORD), ('nFileIndexLow', rwin32.DWORD)]) + FILE_ATTRIBUTE_TAG_INFO = platform.Struct( + 'FILE_ATTRIBUTE_TAG_INFO', + [('FileAttributes', rwin32.DWORD), + ('ReparseTag', rwin32.DWORD)]) + return CConfigGlobal config_global = None @@ -109,11 +127,13 @@ 'struct _WIN32_FIND_DATA' + suffix, # Only interesting fields [('dwFileAttributes', rwin32.DWORD), - ('nFileSizeHigh', rwin32.DWORD), - ('nFileSizeLow', rwin32.DWORD), ('ftCreationTime', rwin32.FILETIME), ('ftLastAccessTime', rwin32.FILETIME), ('ftLastWriteTime', rwin32.FILETIME), + ('nFileSizeHigh', rwin32.DWORD), + ('nFileSizeLow', rwin32.DWORD), + ('dwReserved0', rwin32.DWORD), + ('dwReserved1', rwin32.DWORD), ('cFileName', lltype.FixedSizeArray(traits.CHAR, 250))]) if config_global is None: @@ -129,18 +149,25 @@ class Win32Traits: apisuffix = suffix - for name in '''WIN32_FIND_DATA WIN32_FILE_ATTRIBUTE_DATA BY_HANDLE_FILE_INFORMATION + for name in '''WIN32_FIND_DATA WIN32_FILE_ATTRIBUTE_DATA + BY_HANDLE_FILE_INFORMATION + FILE_ATTRIBUTE_TAG_INFO GetFileExInfoStandard FILE_ATTRIBUTE_DIRECTORY FILE_ATTRIBUTE_READONLY INVALID_FILE_ATTRIBUTES _S_IFDIR _S_IFREG _S_IFCHR _S_IFIFO FILE_TYPE_UNKNOWN FILE_TYPE_CHAR FILE_TYPE_PIPE + ERROR_INVALID_PARAMETER FILE_TYPE_DISK GENERIC_READ + FILE_SHARE_READ FILE_SHARE_WRITE ERROR_NOT_SUPPORTED + FILE_FLAG_OPEN_REPARSE_POINT FileAttributeTagInfo FILE_READ_ATTRIBUTES FILE_ATTRIBUTE_NORMAL - FILE_WRITE_ATTRIBUTES OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS + FILE_WRITE_ATTRIBUTES OPEN_EXISTING VOLUME_NAME_DOS VOLUME_NAME_NT ERROR_FILE_NOT_FOUND ERROR_NO_MORE_FILES ERROR_SHARING_VIOLATION MOVEFILE_REPLACE_EXISTING - ERROR_ACCESS_DENIED + ERROR_ACCESS_DENIED ERROR_CANT_ACCESS_FILE + ERROR_INVALID_FUNCTION FILE_FLAG_BACKUP_SEMANTICS + FILE_ATTRIBUTE_REPARSE_POINT _O_RDONLY _O_WRONLY _O_BINARY '''.split(): locals()[name] = config[name] @@ -178,6 +205,12 @@ rwin32.BOOL, save_err=rffi.RFFI_SAVE_LASTERROR) + GetFileInformationByHandleEx = external( + 'GetFileInformationByHandleEx', + [rwin32.HANDLE, rffi.INT, rffi.VOIDP, rwin32.DWORD], + rwin32.BOOL, + save_err=rffi.RFFI_SAVE_LASTERROR) + GetFileInformationByHandle = external( 'GetFileInformationByHandle', [rwin32.HANDLE, lltype.Ptr(BY_HANDLE_FILE_INFORMATION)], @@ -249,6 +282,8 @@ rwin32.BOOL, save_err=rffi.RFFI_SAVE_LASTERROR) + TagInfoSize = 2 * rffi.sizeof(rwin32.DWORD) + return Win32Traits def make_longlong(high, low): diff -Nru pypy-7.3.5+dfsg/rpython/rlib/rwin32.py pypy-7.3.6+dfsg/rpython/rlib/rwin32.py --- pypy-7.3.5+dfsg/rpython/rlib/rwin32.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/rwin32.py 2021-10-17 16:14:54.000000000 +0000 @@ -251,8 +251,8 @@ _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], rffi.INTP) def get_osfhandle(fd): - from rpython.rlib.rposix import FdValidator - with FdValidator(fd): + from rpython.rlib.rposix import SuppressIPH + with SuppressIPH(): handle = rffi.cast(HANDLE, _get_osfhandle(fd)) if handle == INVALID_HANDLE_VALUE: raise WindowsError(ERROR_INVALID_HANDLE, "Invalid file handle") @@ -261,9 +261,9 @@ _open_osfhandle = rffi.llexternal('_open_osfhandle', [rffi.INTP, rffi.INT], rffi.INT) def open_osfhandle(handle, flags): - from rpython.rlib.rposix import FdValidator + from rpython.rlib.rposix import SuppressIPH fd = _open_osfhandle(handle, flags) - with FdValidator(fd): + with SuppressIPH(): return fd wcsncpy_s = rffi.llexternal('wcsncpy_s', diff -Nru pypy-7.3.5+dfsg/rpython/rlib/streamio.py pypy-7.3.6+dfsg/rpython/rlib/streamio.py --- pypy-7.3.5+dfsg/rpython/rlib/streamio.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/streamio.py 2021-10-17 16:14:51.000000000 +0000 @@ -202,7 +202,7 @@ def _setfd_binary(fd): # Allow this to succeed on invalid fd's - with rposix.FdValidator(fd): + with rposix.SuppressIPH(): _setmode(fd, os.O_BINARY) def ftruncate_win32(fd, size): @@ -660,10 +660,9 @@ def readall(self): pos = self.pos assert pos >= 0 + builder = StringBuilder() if self.buf: - chunks = [self.buf[pos:]] - else: - chunks = [] + builder.append_slice(self.buf, pos, len(self.buf)) self.buf = "" self.pos = 0 bufsize = self.bufsize @@ -673,14 +672,14 @@ except OSError as o: # like CPython < 3.4, partial results followed by an error # are returned as data - if not chunks: + if not builder.getlength(): raise break if not data: break - chunks.append(data) + builder.append(data) bufsize = min(bufsize*2, self.bigsize) - return "".join(chunks) + return builder.build() def read(self, n=-1): assert isinstance(n, int) @@ -696,7 +695,8 @@ self.pos += n return result else: - chunks = [self.buf[start:]] + builder = StringBuilder(n) + builder.append_slice(self.buf, start, len(self.buf)) while 1: self.buf = self.do_read(self.bufsize) if not self.buf: @@ -707,12 +707,12 @@ self.pos = len(self.buf) - (currentsize - n) stop = self.pos assert stop >= 0 - chunks.append(self.buf[:stop]) + builder.append_slice(self.buf, 0, stop) break buf = self.buf assert buf is not None - chunks.append(buf) - return ''.join(chunks) + builder.append(buf) + return builder.build() def readline(self): pos = self.pos @@ -738,7 +738,9 @@ self.pos = 0 return temp # need to keep getting data until we find a new line - chunks = [temp, self.buf] + builder = StringBuilder(len(temp) + len(self.buf)) # at least + builder.append(temp) + builder.append(self.buf) while 1: self.buf = self.do_read(self.bufsize) if not self.buf: @@ -747,11 +749,11 @@ i = self.buf.find("\n") if i >= 0: i += 1 - chunks.append(self.buf[:i]) + builder.append_slice(self.buf, 0, i) self.pos = i break - chunks.append(self.buf) - return "".join(chunks) + builder.append(self.buf) + return builder.build() def peek(self): return (self.pos, self.buf) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_listsort.py pypy-7.3.6+dfsg/rpython/rlib/test/test_listsort.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_listsort.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_listsort.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,16 +1,27 @@ import py -from rpython.rlib.listsort import TimSort +from rpython.rlib.listsort import TimSort, powerloop import random, os +from hypothesis import given, strategies as st, example + def makeset(lst): result = {} for a in lst: result.setdefault(id(a), []).append(True) return result +class TestTimSort(TimSort): + def merge_compute_minrun(self, n): + return 1 # that means we use the "timsorty" bits of the algorithm more + # than just mostly binary insertion sort + def sorttest(lst1): + _sorttest(TimSort, lst1) + _sorttest(TestTimSort, lst1) + +def _sorttest(cls, lst1): lst2 = lst1[:] - TimSort(lst2).sort() + cls(lst2).sort() assert len(lst1) == len(lst2) assert makeset(lst1) == makeset(lst2) position = {} @@ -34,8 +45,42 @@ lst1 = [C(random.randrange(0, up)) for i in range(v)] sorttest(lst1) +@given(st.lists(st.integers(), min_size=2)) +def test_hypothesis(l): + sorttest(l) + def test_file(): for fn in py.path.local(__file__).dirpath().listdir(): if fn.ext == '.py': lines1 = fn.readlines() sorttest(lines1) + + +def power(s1, n1, n2, n): + # from Tim's Python sketch code here: https://bugs.python.org/issue34561 + assert s1 >= 0 + assert n1 >= 1 and n2 >= 1 + assert s1 + n1 + n2 <= n + # a = s1 + n1/2 + # b = s1 + n1 + n2/2 = a + (n1 + n2)/2 + a = 2*s1 + n1 # 2*a + b = a + n1 + n2 # 2*b + # Array length has d bits. Max power is d: + # b/n - a/n = (b-a)/n = (n1 + n2)/2/n >= 2/2/n = 1/n > 1/2**d + # So at worst b/n and a/n differ in bit 1/2**d. + # a and b have <= d+1 bits. Shift left by d-1 and divide by 2n = + # shift left by d-2 and divide by n. Result is d - bit length of + # xor. After the shift, the numerator has at most d+1 + d-2 = 2*d-1 + # bits. Any value of d >= n.bit_length() can be used. + d = n.bit_length() # or larger; smaller can fail + a = (a << (d-2)) // n + b = (b << (d-2)) // n + return d - (a ^ b).bit_length() + + +@example(s1=0, n1=2, n2=2, moreitems=0) +@given(st.integers(min_value=0), st.integers(min_value=2), st.integers(min_value=2), st.integers(min_value=0)) +def test_powerloop_equal_power(s1, n1, n2, moreitems): + n = s1 + n1 + n2 + moreitems + assert powerloop(s1, n1, n2, n) == power(s1, n1, n2, n) + diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rbigint.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rbigint.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rbigint.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rbigint.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,17 +1,22 @@ from __future__ import division import operator -import sys +import sys, os import math from random import random, randint, sample -import pytest +try: + import pytest +except ImportError: + print 'cwd', os.getcwd() + print 'sys.path', sys.path + raise from rpython.rlib import rbigint as lobj from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask, LONG_BIT from rpython.rlib.rbigint import (rbigint, SHIFT, MASK, KARATSUBA_CUTOFF, _store_digit, _mask_digit, InvalidEndiannessError, InvalidSignednessError, - gcd_lehmer, lehmer_xgcd, gcd_binary) + gcd_lehmer, lehmer_xgcd, gcd_binary, divmod_big, ONERBIGINT) from rpython.rlib.rfloat import NAN from rpython.rtyper.test.test_llinterp import interpret from rpython.translator.c.test.test_standalone import StandaloneTests @@ -213,6 +218,18 @@ r2 = x % y assert r1.tolong() == r2 + def test_int_mod_int_result(self): + for x in gen_signs(long_vals): + op1 = rbigint.fromlong(x) + for y in signed_int_vals: + if not y: + with pytest.raises(ZeroDivisionError): + op1.int_mod_int_result(0) + continue + r1 = op1.int_mod_int_result(y) + r2 = x % y + assert r1 == r2 + def test_pow(self): for op1 in gen_signs(long_vals_not_too_big): rl_op1 = rbigint.fromlong(op1) @@ -279,6 +296,16 @@ assert not (a1 != a2) assert not (a1 == a3) + def test_divmod_big2(self): + def check(a, b): + fa = rbigint.fromlong(a) + fb = rbigint.fromlong(b) + div, mod = divmod_big(fa, fb) + return div.mul(fb).add(mod).eq(fa) + check(2, 3) + check(3, 2) + check((2 << 1000) - 1, (2 << (65 * 3 + 2)) - 1) + check((2 + 5 * 2 ** SHIFT) << (100 * SHIFT), 5 << (100 * SHIFT)) def bigint(lst, sign): @@ -1016,6 +1043,21 @@ assert div.tolong() == _div assert rem.tolong() == _rem + def test_divmod_big_bug(self): + a = -0x13131313131313131313cfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfd0 + b = -0x131313131313131313d0 + ra = rbigint.fromlong(a) + rb = rbigint.fromlong(b) + from rpython.rlib.rbigint import HOLDER + oldval = HOLDER.DIV_LIMIT + try: + HOLDER.DIV_LIMIT = 2 # set limit low to test divmod_big more + rdiv, rmod = divmod_big(ra, rb) + div, mod = divmod(a, b) + assert rdiv.tolong() == div + assert rmod.tolong() == mod + finally: + HOLDER.DIV_LIMIT = oldval def test_int_divmod(self): for x in long_vals: @@ -1101,6 +1143,10 @@ assert (rbigint.fromlong(-9**50).ulonglongmask() == r_ulonglong(-9**50)) + def test_toulonglong(self): + with pytest.raises(ValueError): + rbigint.fromlong(-1).toulonglong() + def test_fits_int(self): assert rbigint.fromlong(0).fits_int() assert rbigint.fromlong(42).fits_int() @@ -1110,6 +1156,7 @@ assert rbigint.fromlong(-sys.maxint - 1).fits_int() assert not rbigint.fromlong(-sys.maxint - 2).fits_int() assert not rbigint.fromlong(-73786976294838206459).fits_int() + assert not rbigint.fromlong(1 << 1000).fits_int() def test_parse_digit_string(self): from rpython.rlib.rbigint import parse_digit_string @@ -1287,6 +1334,58 @@ a, b = f1.divmod(f2) assert (a.tolong(), b.tolong()) == res + @given(biglongs, biglongs) + @example(510439143470502793407446782273075179618477362188870662225920, + 108089693021945158982483698831267549521) + def test_divmod_small(self, x, y): + if x < y: + x, y = y, x + + f1 = rbigint.fromlong(x) + f2 = rbigint.fromlong(y) + try: + res = divmod(x, y) + except Exception as e: + with pytest.raises(type(e)): + f1._divmod_small(f2) + else: + a, b = f1._divmod_small(f2) + assert (a.tolong(), b.tolong()) == res + + + @given(biglongs, biglongs) + @example(510439143470502793407446782273075179618477362188870662225920, + 108089693021945158982483698831267549521) + @example(51043991434705027934074467822730751796184773621888706622259209143470502793407446782273075179618477362188870662225920143470502793407446782273075179618477362188870662225920, + 10808) + @example(17, 257) + @example(510439143470502793407446782273075179618477362188870662225920L, 108089693021945158982483698831267549521L) + def test_divmod_big(self, x, y): + from rpython.rlib.rbigint import HOLDER + oldval = HOLDER.DIV_LIMIT + try: + HOLDER.DIV_LIMIT = 2 # set limit low to test divmod_big more + if x < y: + x, y = y, x + + # boost size + x *= 3 ** (HOLDER.DIV_LIMIT * SHIFT * 5) - 1 + y *= 2 ** (HOLDER.DIV_LIMIT * SHIFT * 5) - 1 + + f1 = rbigint.fromlong(x) + f2 = rbigint.fromlong(y) + try: + res = divmod(x, y) + except Exception as e: + with pytest.raises(type(e)): + divmod_big(f1, f2) + else: + print x, y + a, b = divmod_big(f1, f2) + assert (a.tolong(), b.tolong()) == res + finally: + HOLDER.DIV_LIMIT = oldval + @given(biglongs, ints) def test_int_divmod(self, x, iy): f1 = rbigint.fromlong(x) @@ -1328,7 +1427,7 @@ with pytest.raises(ZeroDivisionError): ra.truediv(rb) else: - assert ra.truediv(rb) == a / b + assert repr(ra.truediv(rb)) == repr(a / b) @given(longs, longs) def test_bitwise_and_mul(self, x, y): @@ -1395,6 +1494,7 @@ x, y, z = abs(x), abs(y), abs(z) def test(a, b, res): + print(rbigint.fromlong(a)) g = rbigint.fromlong(a).gcd(rbigint.fromlong(b)).tolong() assert g == res @@ -1411,3 +1511,106 @@ test(z, y * z, z) test(x, 0, x) test(0, x, x) + + @given(ints) + def test_longlong_roundtrip(self, x): + try: + rx = r_longlong(x) + except OverflowError: + pass + else: + assert rbigint.fromrarith_int(rx).tolonglong() == rx + + @given(longs) + def test_unsigned_roundtrip(self, x): + x = abs(x) + rx = r_uint(x) # will wrap on overflow + assert rbigint.fromrarith_int(rx).touint() == rx + rx = r_ulonglong(x) # will wrap on overflow + assert rbigint.fromrarith_int(rx).toulonglong() == rx + + @given(biglongs, biglongs) + def test_mod(self, x, y): + rx = rbigint.fromlong(x) + ry = rbigint.fromlong(y) + if not y: + with pytest.raises(ZeroDivisionError): + rx.mod(ry) + return + r1 = rx.mod(ry) + r2 = x % y + + assert r1.tolong() == r2 + + @given(biglongs, ints) + def test_int_mod(self, x, y): + rx = rbigint.fromlong(x) + if not y: + with pytest.raises(ZeroDivisionError): + rx.int_mod(0) + return + r1 = rx.int_mod(y) + r2 = x % y + assert r1.tolong() == r2 + + @given(biglongs, ints) + def test_int_mod_int_result(self, x, y): + rx = rbigint.fromlong(x) + if not y: + with pytest.raises(ZeroDivisionError): + rx.int_mod_int_result(0) + return + r1 = rx.int_mod_int_result(y) + r2 = x % y + assert r1 == r2 + +@pytest.mark.parametrize(['methname'], [(methodname, ) for methodname in dir(TestHypothesis) if methodname.startswith("test_")]) +def test_hypothesis_small_shift(methname): + # run the TestHypothesis in a subprocess with a smaller SHIFT value + # the idea is that this finds hopefully finds edge cases more easily + import subprocess, os + # The cwd on the buildbot is actually in rpython + # Add the pypy basedir so we get the local pytest + env = os.environ.copy() + parent = os.path.dirname + env['PYTHONPATH'] = parent(parent(parent(parent(__file__)))) + p = subprocess.Popen([sys.executable, os.path.abspath(__file__), methname], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=True, env=env) + stdout, stderr = p.communicate() + print stdout + print stderr + assert not p.returncode + +def _get_hacked_rbigint(shift): + testpath = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(os.path.dirname(testpath), "rbigint.py")) as f: + s = f.read() + s = s.replace("SHIFT = 63", "SHIFT = %s" % (shift, )) + s = s.replace("SHIFT = 31", "SHIFT = %s" % (shift, )) + with open(os.path.join(testpath, "_hacked_rbigint.py"), "w") as f: + f.write(s) + + from rpython.rlib.test import _hacked_rbigint + assert _hacked_rbigint.SHIFT == shift + return _hacked_rbigint + +def run(): + shift = 9 + print "USING SHIFT", shift + _hacked_rbigint = _get_hacked_rbigint(shift) + globals().update(_hacked_rbigint.__dict__) # emulate import * + assert SHIFT == shift + t = TestHypothesis() + try: + getattr(t, sys.argv[1])() + except: + if "--pdb" in sys.argv: + import traceback, pdb + info = sys.exc_info() + print(traceback.format_exc()) + pdb.post_mortem(info[2], pdb.Pdb) + + +if __name__ == '__main__': + run() diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rmmap.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rmmap.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rmmap.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rmmap.py 2021-10-17 16:14:51.000000000 +0000 @@ -456,6 +456,17 @@ compile(func, [int], gcpolicy='boehm') + @py.test.mark.skipif("not mmap.has_madvise") + def test_translated_madvise_bug(self): + from rpython.translator.c.test.test_genc import compile + + def func(): + m = mmap.mmap(-1, 8096) + m.madvise(mmap.MADV_NORMAL, 0, 8096) + m.close() + + compile(func, [], gcpolicy='boehm') + def test_windows_crasher_1(self): if sys.platform != "win32": py.test.skip("Windows-only test") diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rposix.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rposix.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rposix.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rposix.py 2021-10-17 16:14:51.000000000 +0000 @@ -149,7 +149,8 @@ arg = '%s -c "print 1+1" > %s' % (sys.executable, filename) data = rposix.system(arg) assert data == 0 - assert file(filename).read().strip() == '2' + with file(filename) as f: + assert f.read().strip() == '2' os.unlink(filename) diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rposix_stat.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rposix_stat.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rposix_stat.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rposix_stat.py 2021-10-17 16:14:51.000000000 +0000 @@ -77,10 +77,11 @@ assert st.st_dev == st.st_ino == 0 st = rposix_stat.stat3('C:\\') assert st.st_dev != 0 and st.st_ino != 0 + assert st.st_file_attributes & 0x16 # FILE_ATTRIBUTE_DIRECTORY + assert st.st_reparse_tag == 0 st2 = rposix_stat.lstat3('C:\\') assert (st2.st_dev, st2.st_ino) == (st.st_dev, st.st_ino) - @py.test.mark.skipif("not hasattr(rposix_stat, 'fstatat')") def test_fstatat(tmpdir): tmpdir.join('file').write('text') diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rsignal.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rsignal.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rsignal.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rsignal.py 2021-10-17 16:14:51.000000000 +0000 @@ -58,3 +58,26 @@ stderr = fn() assert stderr.endswith('Exception ignored when trying to write to the ' 'signal wakeup fd: Errno %d\n' % errno.EBADF) + + +def test_raise(): + import os + check(-1) + check(-1) + for i in range(3): + rsignal.pypysig_setflag(rsignal.SIGUSR1) + rsignal.c_raise(rsignal.SIGUSR1) + check(rsignal.SIGUSR1) + check(-1) + check(-1) + + rsignal.pypysig_ignore(rsignal.SIGUSR1) + rsignal.c_raise(rsignal.SIGUSR1) + check(-1) + check(-1) + + rsignal.pypysig_default(rsignal.SIGUSR1) + check(-1) + +def test_strsignal(): + assert rsignal.strsignal(rsignal.SIGSEGV) == "Segmentation fault" diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rsocket.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rsocket.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rsocket.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rsocket.py 2021-10-17 16:14:51.000000000 +0000 @@ -411,7 +411,8 @@ assert isinstance(lst, list) found = False for family, socktype, protocol, canonname, addr in lst: - if addr.get_host() in ('104.130.43.121', '23.253.135.79', '45.55.99.72'): + if addr.get_host() in ('138.197.63.241', '104.130.43.121', + '23.253.135.79', '45.55.99.72'): found = True elif family == AF_INET: print 'pydotorg changed to', addr.get_host() diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rutf8.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rutf8.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rutf8.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rutf8.py 2021-10-17 16:14:51.000000000 +0000 @@ -4,6 +4,7 @@ from hypothesis import given, strategies, settings, example from rpython.rlib import rutf8, runicode +from rpython.rlib.unicodedata import unicodedb_12_1_0 @given(strategies.characters(), strategies.booleans()) @@ -248,3 +249,12 @@ b = u.encode("utf-8") assert b.startswith(b"\xed") assert not rutf8.has_surrogates(b) + +printable_repr_func = rutf8.make_utf8_escape_function(pass_printable=True, + quotes=True, + unicodedb=unicodedb_12_1_0) + +def test_printable_repr_func(): + s = u'\U0001f42a'.encode("utf-8") + assert printable_repr_func(s) == "'" + s + "'" + diff -Nru pypy-7.3.5+dfsg/rpython/rlib/test/test_rwin32.py pypy-7.3.6+dfsg/rpython/rlib/test/test_rwin32.py --- pypy-7.3.5+dfsg/rpython/rlib/test/test_rwin32.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rlib/test/test_rwin32.py 2021-10-17 16:14:54.000000000 +0000 @@ -52,7 +52,7 @@ fd = fid.fileno() rwin32.get_osfhandle(fd) fid.close() - # Somehow the FdValidator's c_enter_suppress_iph, which resolves + # Somehow the SuppressIPH's c_enter_suppress_iph, which resolves # to calling _set_thread_local_invalid_parameter_handler, does not work # untranslated. After translation it does work. # py.test.raises(OSError, rwin32.get_osfhandle, fd) diff -Nru pypy-7.3.5+dfsg/rpython/rtyper/lltypesystem/rstr.py pypy-7.3.6+dfsg/rpython/rtyper/lltypesystem/rstr.py --- pypy-7.3.5+dfsg/rpython/rtyper/lltypesystem/rstr.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rtyper/lltypesystem/rstr.py 2021-10-17 16:14:51.000000000 +0000 @@ -1029,19 +1029,19 @@ strlen = len(chars) i = 0 #XXX: only space is allowed as white space for now - while i < strlen and chars[i] == ' ': + while i < strlen and ord(chars[i]) == ord(' '): i += 1 if not i < strlen: raise ValueError #check sign sign = 1 - if chars[i] == '-': + if ord(chars[i]) == ord('-'): sign = -1 i += 1 - elif chars[i] == '+': + elif ord(chars[i]) == ord('+'): i += 1 # skip whitespaces between sign and digits - while i < strlen and chars[i] == ' ': + while i < strlen and ord(chars[i]) == ord(' '): i += 1 #now get digits val = 0 @@ -1063,7 +1063,7 @@ if i == oldpos: raise ValueError # catch strings like '+' and '+ ' #skip trailing whitespace - while i < strlen and chars[i] == ' ': + while i < strlen and ord(chars[i]) == ord(' '): i += 1 if not i == strlen: raise ValueError diff -Nru pypy-7.3.5+dfsg/rpython/rtyper/rpbc.py pypy-7.3.6+dfsg/rpython/rtyper/rpbc.py --- pypy-7.3.5+dfsg/rpython/rtyper/rpbc.py 2021-05-23 11:36:29.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/rtyper/rpbc.py 2021-10-17 16:14:51.000000000 +0000 @@ -838,7 +838,9 @@ def __init__(self, rtyper, s_pbc): self.rtyper = rtyper - self.funcdesc = s_pbc.any_description().funcdesc + funcdescs = set([desc.funcdesc for desc in s_pbc.descriptions]) + assert len(funcdescs) == 1 + self.funcdesc = funcdescs.pop() # a hack to force the underlying function to show up in call_families # (generally not needed, as normalizecalls() should ensure this, @@ -851,14 +853,7 @@ raise TyperError("unsupported: variable of type " "method-of-frozen-PBC or None") - im_selves = [] - for desc in s_pbc.descriptions: - if desc.funcdesc is not self.funcdesc: - raise TyperError( - "You can't mix a set of methods on a frozen PBC in " - "RPython that are different underlying functions") - im_selves.append(desc.frozendesc) - + im_selves = [desc.frozendesc for desc in s_pbc.descriptions] self.s_im_self = annmodel.SomePBC(im_selves) self.r_im_self = rtyper.getrepr(self.s_im_self) self.lowleveltype = self.r_im_self.lowleveltype diff -Nru pypy-7.3.5+dfsg/rpython/tool/algo/graphlib.py pypy-7.3.6+dfsg/rpython/tool/algo/graphlib.py --- pypy-7.3.5+dfsg/rpython/tool/algo/graphlib.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/tool/algo/graphlib.py 2021-10-17 16:14:51.000000000 +0000 @@ -259,6 +259,64 @@ remaining_edges[max_edge.source] = lst assert is_acyclic(vertices, remaining_edges) +def compute_predecessors(vertices, edgedict): + result = {} + for node, edges in edgedict.iteritems(): + for edge in edges: + result.setdefault(edge.target, set()).add(edge.source) + return result + +def remove_leaves(vertices, edgedict): + """ recursively remove all leaves in the graph, ie nodes that have no + outgoing edges. """ + incoming = compute_predecessors(vertices, edgedict) + return remove_leaves_incoming(vertices, edgedict, incoming) + +def remove_leaves_incoming(vertices, edgedict, incoming, leaves=None): + """ helper function for remove_leaves, but useful on its own: incoming is + the result of compute_predecessors on the graph, can be re-used when + removing many leaves from the same graph, many times. when the optional + argument leaves is given, start removing things from those nodes. """ + if leaves is None: + leaves = {source for source, edges in edgedict.iteritems() + if len(edges) == 0} + for leave in leaves: + del edgedict[leave] + del vertices[leave] + while 1: + if not leaves: + break + + new_leaves = set() + to_update = set() + to_update.update(*[incoming.get(leave, set()) for leave in leaves]) + for vertex in to_update: + if vertex not in edgedict: + continue + edges = edgedict[vertex] + i = 0 + while i < len(edges): + edge = edges[i] + if edge.target in leaves: + del edges[i] + else: + i += 1 + if not edges: + new_leaves.add(vertex) + leaves = new_leaves + + for leave in leaves: + del edgedict[leave] + del vertices[leave] + + +def copy_edges(edges): + """ make a deep copy of edges """ + result = {} + for key, value in edges.items(): + result[key] = value[:] + return result + def break_cycles_v(vertices, edges): """Enumerates a reasonably minimal set of vertices that must be removed to @@ -278,6 +336,8 @@ # Ordering the cycles themselves nearest first maximizes the chances # that when breaking a nearby cycle - which must be broken in any # case - we remove a vertex and break some further cycles by chance. + edges = copy_edges(edges) # we mutate it + incoming = compute_predecessors(vertices, edges) v_depths = vertices progress = True @@ -288,10 +348,15 @@ v_depths = compute_depths(roots, vertices, edges) assert len(v_depths) == len(vertices) # ...so far. We remove # from v_depths the vertices at which we choose to break cycles + + # now that we computed the depths, we can remove all leaves, + # recursively. those won't contribute to cycles, but the all_cycles + # calls below otherwise try to walk into them repeatedly + remove_leaves_incoming(v_depths, edges, incoming) #print '%d inital roots' % (len(roots,)) progress = False for root in roots: - if root in roots_finished: + if root in roots_finished or root not in v_depths: continue cycles = all_cycles(root, v_depths, edges) log.dot() @@ -306,6 +371,7 @@ allcycles.append((cycledepth, cycle)) allcycles.sort() # consider all cycles starting from the ones with smallest depth + removed = set() for _, cycle in allcycles: try: choices = [(v_depths[edge.source], edge.source) @@ -316,9 +382,17 @@ # break this cycle by removing the furthest vertex max_depth, max_vertex = max(choices) del v_depths[max_vertex] + del edges[max_vertex] yield max_vertex + removed.add(max_vertex) progress = True - assert is_acyclic(v_depths, edges) + + # early exit when were done. it's quite fast if there are cycles + if is_acyclic(v_depths, edges): + return + # remove leaves, now that we have removed many cycles + # start removing leaves from the nodes that we just removed + remove_leaves_incoming(v_depths, edges, incoming, removed) def show_graph(vertices, edges): diff -Nru pypy-7.3.5+dfsg/rpython/tool/algo/test/test_graphlib.py pypy-7.3.6+dfsg/rpython/tool/algo/test/test_graphlib.py --- pypy-7.3.5+dfsg/rpython/tool/algo/test/test_graphlib.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/tool/algo/test/test_graphlib.py 2021-10-17 16:14:51.000000000 +0000 @@ -1,12 +1,6 @@ -import random +from hypothesis import given, example, assume, strategies as st from rpython.tool.algo.graphlib import * -def copy_edges(edges): - result = {} - for key, value in edges.items(): - result[key] = value[:] - return result - # ____________________________________________________________ class TestSimple: @@ -44,7 +38,7 @@ for comp in result: comp = list(comp) comp.sort() - result = [''.join(comp) for comp in result] + result = [''.join(sorted(comp)) for comp in result] result.sort() assert result == ['ABE', 'C', 'D', 'F', 'G'] @@ -96,6 +90,16 @@ roots.sort() assert ''.join(roots) == 'GR' + def test_remove_leaves(self): + edges = copy_edges(self.edges) + remove_leaves(dict.fromkeys(edges), edges) + assert "F" not in edges + assert "C" not in edges + assert len(edges["A"]) == 1 + assert edges["A"][0].target == "B" + assert len(edges["E"]) == 1 + assert edges["E"][0].target == "A" + class TestLoops: # a graph with 20 loops of length 10 each, plus an edge from each loop to @@ -151,6 +155,11 @@ roots = find_roots(self.vertices, edges) assert len(roots) == 1 + def test_remove_leaves(self): + edges = copy_edges(self.edges) + remove_leaves(dict.fromkeys(edges), edges) + assert edges == self.edges + class TestTree: edges = make_edge_dict([Edge(i//2, i) for i in range(1, 52)]) @@ -179,6 +188,10 @@ v = list(roots)[0] assert v == 0 + def test_remove_leaves(self): + edges = copy_edges(self.edges) + remove_leaves(dict.fromkeys(edges), edges) + assert not edges class TestChainAndLoop: edges = make_edge_dict([Edge(i,i+1) for i in range(100)] + [Edge(100,99)]) @@ -217,39 +230,66 @@ print len(result) assert result + def test_break_cycles_v(self): + result = list(break_cycles_v(self.edges, self.edges)) + assert len(set(result)) == self.NUM + assert len(result) == self.NUM + print len(result) + assert result + def test_find_roots(self): roots = find_roots(self.edges, self.edges) assert len(roots) == 1 assert list(roots)[0] in self.edges +@st.composite +def edges(draw): + max_vertex = draw(st.integers(min_value=1, max_value=200)) + num_edges = draw(st.integers(min_value=max_vertex, max_value=max_vertex * 5)) + return make_edge_dict([Edge(draw(st.integers(min_value=0, max_value=max_vertex)), + draw(st.integers(min_value=0, max_value=max_vertex))) for i in range(num_edges)]) class TestRandom: - edges = make_edge_dict([Edge(random.randrange(0,100), - random.randrange(0,100)) for i in range(150)]) - - def test_strong_components(self): - result = list(strong_components(self.edges, self.edges)) + @given(edges()) + def test_strong_components(self, edges): + result = list(strong_components(edges, edges)) vertices = [] for comp in result: vertices += comp vertices.sort() - expected = self.edges.keys() + expected = edges.keys() expected.sort() assert vertices == expected - def test_break_cycles(self): - list(break_cycles(self.edges, self.edges)) - # assert is_acyclic(): included in break_cycles() itself - - def test_break_cycles_v(self): - result = list(break_cycles_v(self.edges, self.edges)) + @given(edges()) + def test_break_cycles_v(self, edges): + # mostly a "does not crash" kind of test + result = list(break_cycles_v(edges, edges)) # assert is_acyclic(): included in break_cycles_v() itself print len(result), 'vertices removed' - def test_find_roots(self): - roots = find_roots(self.edges, self.edges) + @given(edges()) + def test_find_roots(self, edges): + roots = find_roots(edges, edges) reachable = set() for root in roots: - reachable |= set(vertices_reachable_from(root, self.edges, - self.edges)) - assert reachable == set(self.edges) + reachable |= set(vertices_reachable_from(root, edges, + edges)) + assert reachable == set(edges) + + @given(edges()) + def test_removing_leaves_doesnt_change_cycles(self, edges): + vertices = dict.fromkeys(edges) + assume(len(edges) > 0) + node = edges.keys()[0] + cycles = all_cycles(node, vertices, edges) + assume(len(cycles) > 0) + remove_leaves(vertices, edges) + assert all_cycles(node, vertices, edges) == cycles + + @given(edges()) + def test_removing_leaves_doesnt_change_cyclicness(self, edges): + vertices = dict.fromkeys(edges) + isacyc = is_acyclic(vertices, edges) + remove_leaves(vertices, edges) + assert isacyc == is_acyclic(vertices, edges) diff -Nru pypy-7.3.5+dfsg/rpython/tool/test/test_version.py pypy-7.3.6+dfsg/rpython/tool/test/test_version.py --- pypy-7.3.5+dfsg/rpython/tool/test/test_version.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/tool/test/test_version.py 2021-10-17 16:14:51.000000000 +0000 @@ -2,18 +2,21 @@ from rpython.tool.version import get_repo_version_info, _get_hg_archive_version def test_hg_archival_version(tmpdir): - def version_for(name, **kw): + def version_for(name, items): path = tmpdir.join(name) - path.write('\n'.join('%s: %s' % x for x in kw.items())) + path.write('\n'.join(('%s: %s' % (tag,value) for tag,value in items))) return _get_hg_archive_version(str(path)) assert version_for('release', - tag='release-123', - node='000', + (('tag', 'release-123'), + ('tag', 'ignore-me'), + ('node', '000'), + ), ) == ('release-123', '000') assert version_for('somebranch', - node='000', - branch='something', + (('node', '000'), + ('branch', 'something'), + ), ) == ('something', '000') diff -Nru pypy-7.3.5+dfsg/rpython/tool/version.py pypy-7.3.6+dfsg/rpython/tool/version.py --- pypy-7.3.5+dfsg/rpython/tool/version.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/tool/version.py 2021-10-17 16:14:51.000000000 +0000 @@ -84,11 +84,10 @@ def _get_hg_archive_version(path): - fp = open(path) - try: - data = dict(x.split(': ', 1) for x in fp.read().splitlines()) - finally: - fp.close() + with open(path) as fp: + # reverse the order since there may be more than one tag + # and the latest tag will be first, so make it last instead + data = dict(x.split(': ', 1) for x in fp.read().splitlines()[::-1]) if 'tag' in data: return data['tag'], data['node'] else: diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/genc.py pypy-7.3.6+dfsg/rpython/translator/c/genc.py --- pypy-7.3.5+dfsg/rpython/translator/c/genc.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/genc.py 2021-10-17 16:14:51.000000000 +0000 @@ -499,13 +499,13 @@ if self.translator.platform.name == 'msvc': mk.rule('lldebug0','', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -Od -DMAX_STACK_SIZE=8192000 -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'), wildcards = '..\*.obj ..\*.pdb ..\*.lib ..\*.dll ..\*.manifest ..\*.exp *.pch' - cmd = r'del /s %s $(DEFAULT_TARGET) $(TARGET) $(GCMAPFILES) $(ASMFILES)' % wildcards + cmd = r'del /s %s $(DEFAULT_TARGET) $(TARGET) $(ASMFILES)' % wildcards mk.rule('clean', '', cmd + ' *.gc?? ..\module_cache\*.gc??') mk.rule('clean_noprof', '', cmd) else: mk.rule('lldebug0','', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -O0 -DMAX_STACK_SIZE=8192000 -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'), - mk.rule('clean', '', 'rm -f $(OBJECTS) $(DEFAULT_TARGET) $(TARGET) $(GCMAPFILES) $(ASMFILES) *.gc?? ../module_cache/*.gc??') - mk.rule('clean_noprof', '', 'rm -f $(OBJECTS) $(DEFAULT_TARGET) $(TARGET) $(GCMAPFILES) $(ASMFILES)') + mk.rule('clean', '', 'rm -f $(OBJECTS) $(DEFAULT_TARGET) $(TARGET) $(ASMFILES) $(PRECOMPILEDHEADERS) *.gc?? ../module_cache/*.gc??') + mk.rule('clean_noprof', '', 'rm -f $(OBJECTS) $(DEFAULT_TARGET) $(TARGET) $(ASMFILES)') if self.config.translation.gcrootfinder == 'asmgcc': raise AssertionError("asmgcc not supported any more") @@ -704,11 +704,7 @@ print >> fc, '/***********************************************************/' print >> fc, '/*** Non-function Implementations ***/' print >> fc - print >> fc, '#include "common_header.h"' - print >> fc, '#include "structdef.h"' - print >> fc, '#include "forwarddecl.h"' - print >> fc, '#include "preimpl.h"' - print >> fc + print >> fc, '#include "singleheader.h"' print >> fc, '#include "src/g_include.h"' print >> fc print >> fc, MARKER @@ -727,10 +723,7 @@ print >> fc, '/***********************************************************/' print >> fc, '/*** Implementations ***/' print >> fc - print >> fc, '#include "common_header.h"' - print >> fc, '#include "structdef.h"' - print >> fc, '#include "forwarddecl.h"' - print >> fc, '#include "preimpl.h"' + print >> fc, '#include "singleheader.h"' print >> fc, '#define PYPY_FILE_NAME "%s"' % name print >> fc, '#include "src/g_include.h"' if self.database.reverse_debugger: @@ -913,4 +906,16 @@ eci = add_extra_files(database, eci) eci = eci.convert_sources_to_files() + + # create singleheader.h, which combines common_header.h, structdef.h, + # forwarddecl.h and preimpl.h + singleheader = targetdir.join('singleheader.h') + with singleheader.open("w") as fs: + for fn in "common_header structdef forwarddecl preimpl".split(): + fs.write("/*************** content of %s.h ***************/\n\n" % fn) + with targetdir.join(fn + ".h").open("r") as f: + fs.write(f.read()) + fs.write("\n\n") + headers_to_precompile.insert(0, singleheader) + return eci, filename, sg.getextrafiles(), headers_to_precompile diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/debug_traceback.c pypy-7.3.6+dfsg/rpython/translator/c/src/debug_traceback.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/debug_traceback.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/debug_traceback.c 2021-10-17 16:14:51.000000000 +0000 @@ -1,7 +1,4 @@ -#include "common_header.h" -#include "structdef.h" -#include "forwarddecl.h" -#include "preimpl.h" +#include "singleheader.h" #include "src/debug_traceback.h" #include #include diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/exception.c pypy-7.3.6+dfsg/rpython/translator/c/src/exception.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/exception.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/exception.c 2021-10-17 16:14:51.000000000 +0000 @@ -1,7 +1,4 @@ -#include "common_header.h" -#include "structdef.h" -#include "forwarddecl.h" -#include "preimpl.h" +#include "singleheader.h" #include "src/exception.h" #if defined(PYPY_CPYTHON_EXTENSION) diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/int.c pypy-7.3.6+dfsg/rpython/translator/c/src/int.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/int.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/int.c 2021-10-17 16:14:51.000000000 +0000 @@ -1,7 +1,4 @@ -#include "common_header.h" -#include "structdef.h" -#include "forwarddecl.h" -#include "preimpl.h" +#include "singleheader.h" #include #include #include diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi.c pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,496 +0,0 @@ -/* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. - Copyright (c) 2002 Ranjit Mathew - Copyright (c) 2002 Bo Thorsen - Copyright (c) 2002 Roger Sayle - - x86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include -#include - -#include - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -extern void ffi_fatalerror(char *msg); - -/*@-exportheader@*/ -void ffi_prep_args(char *stack, extended_cif *ecif) -/*@=exportheader@*/ -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - if (ecif->cif->flags == FFI_TYPE_STRUCT) - { - *(void **) argp = ecif->rvalue; - argp += sizeof(void *); - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0; - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(void *) - 1) & (size_t) argp) - argp = (char *) ALIGN(argp, sizeof(void *)); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(ffi_SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(ffi_UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(ffi_SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(ffi_UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(signed int *) argp = (signed int)*(ffi_SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned int *) argp = (unsigned int)*(ffi_UINT32 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - *(unsigned int *) argp = (unsigned int)*(ffi_UINT32 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } -#ifdef _WIN64 - else if (z != 1 && z != 2 && z != 4 && z != 8) - { - /* On Win64, if a single argument takes more than 8 bytes, - then it is always passed by reference. */ - *(void **)argp = *p_argv; - z = 8; - } -#endif - else - { - memcpy(argp, *p_argv, z); - } - p_argv++; - argp += z; - } - - if (argp - stack > (long)ecif->cif->bytes) - { - ffi_fatalerror("FFI BUG: not enough stack space for arguments"); - } - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif - cif->flags = (unsigned) cif->rtype->type; - break; - - case FFI_TYPE_STRUCT: - /* MSVC returns small structures in registers. Put in cif->flags - the value FFI_TYPE_STRUCT only if the structure is big enough; - otherwise, put the 4- or 8-bytes integer type. */ - if (cif->rtype->size == 1 || - cif->rtype->size == 2 || - cif->rtype->size == 4) - cif->flags = FFI_TYPE_INT; - else if (cif->rtype->size == 8) - cif->flags = FFI_TYPE_SINT64; - else - cif->flags = FFI_TYPE_STRUCT; - break; - - case FFI_TYPE_UINT64: -#ifdef _WIN64 - case FFI_TYPE_POINTER: -#endif - cif->flags = FFI_TYPE_SINT64; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - - return FFI_OK; -} - -#ifdef _WIN32 -extern int -ffi_call_x86(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -#ifdef _WIN64 -extern int -ffi_call_AMD64(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue) -{ - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) - { - /*@-sysunrecog@*/ - ecif.rvalue = alloca(cif->rtype->size); - /*@=sysunrecog@*/ - } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) - { -#if !defined(_WIN64) - case FFI_SYSV: - case FFI_STDCALL: - return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - break; -#else - case FFI_SYSV: - /*@-usedef@*/ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - /*@=usedef@*/ - break; -#endif - - default: - FFI_ASSERT(0); - break; - } - return -1; /* theller: Hrm. */ -} - - -/** private members **/ - -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); -/* This function is jumped to by the trampoline */ - -#ifdef _WIN64 -void * -#else -static void __fastcall -#endif -ffi_closure_SYSV (ffi_closure *closure, char *argp) -{ - // this is our return value storage - long double res; - - // our various things... - ffi_cif *cif; - void **arg_area; - unsigned short rtype; - void *resp = (void*)&res; - void *args = argp + sizeof(void *); - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); - - (closure->fun) (cif, resp, arg_area, closure->user_data); - - rtype = cif->flags; - -#if defined(_WIN32) && !defined(_WIN64) -#ifdef _MSC_VER - /* now, do a generic return based on the value of rtype */ - if (rtype == FFI_TYPE_INT) - { - _asm mov eax, resp ; - _asm mov eax, [eax] ; - } - else if (rtype == FFI_TYPE_FLOAT) - { - _asm mov eax, resp ; - _asm fld DWORD PTR [eax] ; -// asm ("flds (%0)" : : "r" (resp) : "st" ); - } - else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) - { - _asm mov eax, resp ; - _asm fld QWORD PTR [eax] ; -// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); - } - else if (rtype == FFI_TYPE_SINT64) - { - _asm mov edx, resp ; - _asm mov eax, [edx] ; - _asm mov edx, [edx + 4] ; -// asm ("movl 0(%0),%%eax;" -// "movl 4(%0),%%edx" -// : : "r"(resp) -// : "eax", "edx"); - } - else if (rtype == FFI_TYPE_STRUCT) - { - _asm mov eax, resp ; - } -#else - /* now, do a generic return based on the value of rtype */ - if (rtype == FFI_TYPE_INT) - { - asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); - } - else if (rtype == FFI_TYPE_FLOAT) - { - asm ("flds (%0)" : : "r" (resp) : "st" ); - } - else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) - { - asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); - } - else if (rtype == FFI_TYPE_SINT64) - { - asm ("movl 0(%0),%%eax;" - "movl 4(%0),%%edx" - : : "r"(resp) - : "eax", "edx"); - } - else if (rtype == FFI_TYPE_STRUCT) - { - asm ("movl %0,%%eax" : : "r" (resp) : "eax"); - } -#endif -#endif - -#ifdef _WIN64 - /* The result is returned in rax. This does the right thing for - result types except for floats; we have to 'mov xmm0, rax' in the - caller to correct this. - */ - if (rtype == FFI_TYPE_STRUCT) - return resp; - return *(void **)resp; -#endif -} - -/*@-exportheader@*/ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, - void **avalue, ffi_cif *cif) -/*@=exportheader@*/ -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(char *) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(char*)); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - -#ifdef _WIN64 - if (z != 1 && z != 2 && z != 4 && z != 8) - { - /* On Win64, if a single argument takes more than 8 bytes, - then it is always passed by reference. */ - *p_argv = *((void**) argp); - z = 8; - } - else -#endif - *p_argv = (void*) argp; - - p_argv++; - argp += z; - } - - return; -} - -/* the cif must already be prep'ed */ -extern void ffi_closure_OUTER(); - -ffi_status -ffi_prep_closure (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data) -{ - short bytes; - char *tramp; -#ifdef _WIN64 - int mask = 0; -#endif - FFI_ASSERT (cif->abi == FFI_SYSV); - - if (cif->abi == FFI_SYSV) - bytes = 0; -#if !defined(_WIN64) - else if (cif->abi == FFI_STDCALL) - bytes = cif->bytes; -#endif - else - return FFI_BAD_ABI; - - tramp = &closure->tramp[0]; - -#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1 -#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*) -#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short) -#define INT(x) *(int*)tramp = x, tramp += sizeof(int) - -#ifdef _WIN64 - if (cif->nargs >= 1 && - (cif->arg_types[0]->type == FFI_TYPE_FLOAT - || cif->arg_types[0]->type == FFI_TYPE_DOUBLE)) - mask |= 1; - if (cif->nargs >= 2 && - (cif->arg_types[1]->type == FFI_TYPE_FLOAT - || cif->arg_types[1]->type == FFI_TYPE_DOUBLE)) - mask |= 2; - if (cif->nargs >= 3 && - (cif->arg_types[2]->type == FFI_TYPE_FLOAT - || cif->arg_types[2]->type == FFI_TYPE_DOUBLE)) - mask |= 4; - if (cif->nargs >= 4 && - (cif->arg_types[3]->type == FFI_TYPE_FLOAT - || cif->arg_types[3]->type == FFI_TYPE_DOUBLE)) - mask |= 8; - - /* if we return a non-small struct, then the first argument is a pointer - * to the return area, and all real arguments are shifted by one */ - if (cif->flags == FFI_TYPE_STRUCT) - mask = (mask & ~8) << 1; - - /* 41 BB ---- mov r11d,mask */ - BYTES("\x41\xBB"); INT(mask); - - /* 48 B8 -------- mov rax, closure */ - BYTES("\x48\xB8"); POINTER(closure); - - /* 49 BA -------- mov r10, ffi_closure_OUTER */ - BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER); - - /* 41 FF E2 jmp r10 */ - BYTES("\x41\xFF\xE2"); - -#else - - /* mov ecx, closure */ - BYTES("\xb9"); POINTER(closure); - - /* mov edx, esp */ - BYTES("\x8b\xd4"); - - /* call ffi_closure_SYSV */ - BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4)); - - /* ret bytes */ - BYTES("\xc2"); - SHORT(bytes); - -#endif - - if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE) - ffi_fatalerror("FFI_TRAMPOLINE_SIZE too small in " __FILE__); - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - return FFI_OK; -} diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi_common.h pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi_common.h --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi_common.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/* ----------------------------------------------------------------------- - ffi_common.h - Copyright (c) 1996 Red Hat, Inc. - - Common internal definitions and macros. Only necessary for building - libffi. - ----------------------------------------------------------------------- */ - -#ifndef FFI_COMMON_H -#define FFI_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* Check for the existence of memcpy. */ -#if STDC_HEADERS -# include -#else -# ifndef HAVE_MEMCPY -# define memcpy(d, s, n) bcopy ((s), (d), (n)) -# endif -#endif - -#if defined(FFI_DEBUG) -#include -#endif - -#ifdef FFI_DEBUG -/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); -void ffi_stop_here(void); -void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); - -#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) -#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) -#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) -#else -#define FFI_ASSERT(x) -#define FFI_ASSERT_AT(x, f, l) -#define FFI_ASSERT_VALID_TYPE(x) -#endif - -#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif); - -/* Extended cif, used in callback from assembly routine */ -typedef struct -{ - /*@dependent@*/ ffi_cif *cif; - /*@dependent@*/ void *rvalue; - /*@dependent@*/ void **avalue; -} extended_cif; - -/* Terse sized type definitions. */ -/* Fix for PyPy: these names are fine, but are bound to conflict with - * some other name from somewhere else :-( Added a 'ffi_' prefix. */ -typedef unsigned int ffi_UINT8 __attribute__((__mode__(__QI__))); -typedef signed int ffi_SINT8 __attribute__((__mode__(__QI__))); -typedef unsigned int ffi_UINT16 __attribute__((__mode__(__HI__))); -typedef signed int ffi_SINT16 __attribute__((__mode__(__HI__))); -typedef unsigned int ffi_UINT32 __attribute__((__mode__(__SI__))); -typedef signed int ffi_SINT32 __attribute__((__mode__(__SI__))); -typedef unsigned int ffi_UINT64 __attribute__((__mode__(__DI__))); -typedef signed int ffi_SINT64 __attribute__((__mode__(__DI__))); - -typedef float ffi_FLOAT32; - - -#ifdef __cplusplus -} -#endif - -#endif - - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/fficonfig.h pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/fficonfig.h --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/fficonfig.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/fficonfig.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ - -/* fficonfig.h. Generated automatically by configure. */ -/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ - -/* Define this for MSVC, but not for mingw32! */ -#ifdef _MSC_VER -#define __attribute__(x) /* */ -#endif -#define alloca _alloca - -/*----------------------------------------------------------------*/ - -/* Define if using alloca.c. */ -/* #undef C_ALLOCA */ - -/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. - This function is required for alloca.c support on those systems. */ -/* #undef CRAY_STACKSEG_END */ - -/* Define if you have alloca, as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define if you have and it should be used (not on Ultrix). */ -/* #define HAVE_ALLOCA_H 1 */ - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown - */ -/* #undef STACK_DIRECTION */ - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you have the memcpy function. */ -#define HAVE_MEMCPY 1 - -/* Define if read-only mmap of a plain file works. */ -//#define HAVE_MMAP_FILE 1 - -/* Define if mmap of /dev/zero works. */ -//#define HAVE_MMAP_DEV_ZERO 1 - -/* Define if mmap with MAP_ANON(YMOUS) works. */ -//#define HAVE_MMAP_ANON 1 - -/* The number of bytes in type double */ -#define SIZEOF_DOUBLE 8 - -/* The number of bytes in type long double */ -#define SIZEOF_LONG_DOUBLE 12 - -/* Define if you have the long double type and it is bigger than a double */ -#define HAVE_LONG_DOUBLE 1 - -/* whether byteorder is bigendian */ -/* #undef WORDS_BIGENDIAN */ - -/* Define if the host machine stores words of multi-word integers in - big-endian order. */ -/* #undef HOST_WORDS_BIG_ENDIAN */ - -/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ -#define BYTEORDER 1234 - -/* Define if your assembler and linker support unaligned PC relative relocs. */ -/* #undef HAVE_AS_SPARC_UA_PCREL */ - -/* Define if your assembler supports .register. */ -/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ - -/* Define if .eh_frame sections should be read-only. */ -/* #undef HAVE_RO_EH_FRAME */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define this if you want extra debugging. */ -/* #undef FFI_DEBUG */ - -/* Define this is you do not want support for aggregate types. */ -/* #undef FFI_NO_STRUCTS */ - -/* Define this is you do not want support for the raw API. */ -/* #undef FFI_NO_RAW_API */ - -/* Define this if you are using Purify and want to suppress spurious messages. */ -/* #undef USING_PURIFY */ - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi.h pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi.h --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffi.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,319 +0,0 @@ -/* -----------------------------------------------------------------*-C-*- - libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure API can be found in: - - http://gcc.gnu.org/ml/java/1999-q3/msg00138.html - - and - - http://gcc.gnu.org/ml/java/1999-q3/msg00174.html - -------------------------------------------------------------------- */ - -#ifndef LIBFFI_H -#define LIBFFI_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Specify which architecture libffi is configured for. */ -//XXX #define X86 - -/* ---- System configuration information --------------------------------- */ - -#include /* for RPY_EXTERN */ -#include - -#ifndef LIBFFI_ASM - -#include -#include - -/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). - But we can find it either under the correct ANSI name, or under GNU - C's internal name. */ -#ifdef LONG_LONG_MAX -# define FFI_LONG_LONG_MAX LONG_LONG_MAX -#else -# ifdef LLONG_MAX -# define FFI_LONG_LONG_MAX LLONG_MAX -# else -# ifdef __GNUC__ -# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ -# endif -# ifdef _MSC_VER -# define FFI_LONG_LONG_MAX _I64_MAX -# endif -# endif -#endif - -#if SCHAR_MAX == 127 -# define ffi_type_uchar ffi_type_uint8 -# define ffi_type_schar ffi_type_sint8 -#else - #error "char size not supported" -#endif - -#if SHRT_MAX == 32767 -# define ffi_type_ushort ffi_type_uint16 -# define ffi_type_sshort ffi_type_sint16 -#elif SHRT_MAX == 2147483647 -# define ffi_type_ushort ffi_type_uint32 -# define ffi_type_sshort ffi_type_sint32 -#else - #error "short size not supported" -#endif - -#if INT_MAX == 32767 -# define ffi_type_uint ffi_type_uint16 -# define ffi_type_sint ffi_type_sint16 -#elif INT_MAX == 2147483647 -# define ffi_type_uint ffi_type_uint32 -# define ffi_type_sint ffi_type_sint32 -#elif INT_MAX == 9223372036854775807 -# define ffi_type_uint ffi_type_uint64 -# define ffi_type_sint ffi_type_sint64 -#else - #error "int size not supported" -#endif - -#define ffi_type_ulong ffi_type_uint64 -#define ffi_type_slong ffi_type_sint64 -#if LONG_MAX == 2147483647 -# if FFI_LONG_LONG_MAX != 9223372036854775807 - #error "no 64-bit data type supported" -# endif -#elif LONG_MAX != 9223372036854775807 - #error "long size not supported" -#endif - -/* The closure code assumes that this works on pointers, i.e. a size_t */ -/* can hold a pointer. */ - -typedef struct _ffi_type -{ - size_t size; - unsigned short alignment; - unsigned short type; - /*@null@*/ struct _ffi_type **elements; -} ffi_type; - -/* These are defined in types.c */ -extern ffi_type ffi_type_void; -extern ffi_type ffi_type_uint8; -extern ffi_type ffi_type_sint8; -extern ffi_type ffi_type_uint16; -extern ffi_type ffi_type_sint16; -extern ffi_type ffi_type_uint32; -extern ffi_type ffi_type_sint32; -extern ffi_type ffi_type_uint64; -extern ffi_type ffi_type_sint64; -extern ffi_type ffi_type_float; -extern ffi_type ffi_type_double; -extern ffi_type ffi_type_longdouble; -extern ffi_type ffi_type_pointer; - - -typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI -} ffi_status; - -typedef unsigned FFI_TYPE; - -typedef struct { - ffi_abi abi; - unsigned nargs; - /*@dependent@*/ ffi_type **arg_types; - /*@dependent@*/ ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif -} ffi_cif; - -/* ---- Definitions for the raw API -------------------------------------- */ - -#ifdef _WIN64 -#define FFI_SIZEOF_ARG 8 -#else -#define FFI_SIZEOF_ARG 4 -#endif - -typedef union { - ffi_sarg sint; - ffi_arg uint; - float flt; - char data[FFI_SIZEOF_ARG]; - void* ptr; -} ffi_raw; - -void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_raw_size (ffi_cif *cif); - -/* This is analogous to the raw API, except it uses Java parameter */ -/* packing, even on 64-bit machines. I.e. on 64-bit machines */ -/* longs and doubles are followed by an empty 64-bit word. */ - -void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_java_raw_size (ffi_cif *cif); - -/* ---- Definitions for closures ----------------------------------------- */ - -#if FFI_CLOSURES - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; -} ffi_closure; - -RPY_EXTERN -ffi_status -ffi_prep_closure (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data); - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_raw*,void*); - void *user_data; - -} ffi_raw_closure; - -ffi_status -ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -ffi_status -ffi_prep_java_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -#endif /* FFI_CLOSURES */ - -/* ---- Public interface definition -------------------------------------- */ - -RPY_EXTERN -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes); - -RPY_EXTERN -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue); - -/* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((void (*)())f) - -/* ---- Definitions shared with assembly code ---------------------------- */ - -#endif - -/* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#ifndef _WIN64 -#define FFI_TYPE_LONGDOUBLE 4 -#else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 - -/* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffitarget.h pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffitarget.h --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/ffitarget.h 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/ffitarget.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. - Target configuration macros for x86 and x86-64. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -#ifndef LIBFFI_TARGET_H -#define LIBFFI_TARGET_H - -/* ---- System specific configurations ----------------------------------- */ - -#if defined (X86_64) && defined (__i386__) -#undef X86_64 -#define X86 -#endif - -/* ---- Generic type definitions ----------------------------------------- */ - -#ifndef LIBFFI_ASM -#ifndef _WIN64 -typedef unsigned long ffi_arg; -#else -typedef unsigned __int64 ffi_arg; -#endif -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - - /* ---- Intel x86 Win32 ---------- */ - FFI_SYSV, -#ifndef _WIN64 - FFI_STDCALL, -#endif - /* TODO: Add fastcall support for the sake of completeness */ - FFI_DEFAULT_ABI = FFI_SYSV, - - /* ---- Intel x86 and AMD x86-64 - */ -/* #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) */ -/* FFI_SYSV, */ -/* FFI_UNIX64,*/ /* Unix variants all use the same ABI for x86-64 */ -/* #ifdef __i386__ */ -/* FFI_DEFAULT_ABI = FFI_SYSV, */ -/* #else */ -/* FFI_DEFAULT_ABI = FFI_UNIX64, */ -/* #endif */ -/* #endif */ - - FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 - -#ifdef _WIN64 -#define FFI_TRAMPOLINE_SIZE 29 -#define FFI_NATIVE_RAW_API 0 -#else -#define FFI_TRAMPOLINE_SIZE 15 -#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ -#endif - -#endif - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/prep_cif.c pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/prep_cif.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/prep_cif.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/prep_cif.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -/* ----------------------------------------------------------------------- - prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include -#include -#include - - -/* Round up to FFI_SIZEOF_ARG. */ - -#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) - -/* Perform machine independent initialization of aggregate type - specifications. */ - -static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) -{ - ffi_type **ptr; - - FFI_ASSERT(arg != NULL); - - /*@-usedef@*/ - - FFI_ASSERT(arg->elements != NULL); - FFI_ASSERT(arg->size == 0); - FFI_ASSERT(arg->alignment == 0); - - ptr = &(arg->elements[0]); - - while ((*ptr) != NULL) - { - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type */ - FFI_ASSERT_VALID_TYPE(*ptr); - - arg->size = ALIGN(arg->size, (*ptr)->alignment); - arg->size += (*ptr)->size; - - arg->alignment = (arg->alignment > (*ptr)->alignment) ? - arg->alignment : (*ptr)->alignment; - - ptr++; - } - - /* Structure size includes tail padding. This is important for - structures that fit in one register on ABIs like the PowerPC64 - Linux ABI that right justify small structs in a register. - It's also needed for nested structure layout, for example - struct A { long a; char b; }; struct B { struct A x; char y; }; - should find y at an offset of 2*sizeof(long) and result in a - total size of 3*sizeof(long). */ - arg->size = ALIGN (arg->size, arg->alignment); - - if (arg->size == 0) - return FFI_BAD_TYPEDEF; - else - return FFI_OK; - - /*@=usedef@*/ -} - -/* Perform machine independent ffi_cif preparation, then call - machine dependent routine. */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes) -{ - unsigned bytes = 0; - unsigned int i; - ffi_type **ptr; - - FFI_ASSERT(cif != NULL); - FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); - - cif->abi = abi; - cif->arg_types = atypes; - cif->nargs = nargs; - cif->rtype = rtype; - - cif->flags = 0; - - /* Initialize the return type if necessary */ - /*@-usedef@*/ - if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) - return FFI_BAD_TYPEDEF; - /*@=usedef@*/ - - /* Perform a sanity check on the return type */ - FFI_ASSERT_VALID_TYPE(cif->rtype); - - /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ -#if !defined M68K && !defined __x86_64__ && !defined S390 - /* Make space for the return structure pointer */ - if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef _WIN32 - && (cif->rtype->size != 1) /* MSVC returns small structs in registers */ - && (cif->rtype->size != 2) - && (cif->rtype->size != 4) - && (cif->rtype->size != 8) -#endif -#ifdef SPARC - && (cif->abi != FFI_V9 || cif->rtype->size > 32) -#endif - ) - bytes = STACK_ARG_SIZE(sizeof(void*)); -#endif - - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - - /* Initialize any uninitialized aggregate type definitions */ - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type, do this - check after the initialization. */ - FFI_ASSERT_VALID_TYPE(*ptr); - -#if !defined __x86_64__ && !defined S390 -#ifdef SPARC - if (((*ptr)->type == FFI_TYPE_STRUCT - && ((*ptr)->size > 16 || cif->abi != FFI_V9)) - || ((*ptr)->type == FFI_TYPE_LONGDOUBLE - && cif->abi != FFI_V9)) - bytes += sizeof(void*); - else -#elif defined (_WIN64) - if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) - bytes += sizeof(void*); - else -#endif - { -#if !defined(_MSC_VER) && !defined(__MINGW32__) - /* Don't know if this is a libffi bug or not. At least on - Windows with MSVC, function call parameters are *not* - aligned in the same way as structure fields are, they are - only aligned in integer boundaries. - - This doesn't do any harm for cdecl functions and closures, - since the caller cleans up the stack, but it is wrong for - stdcall functions where the callee cleans. - */ - - /* Add any padding if necessary */ - if (((*ptr)->alignment - 1) & bytes) - bytes = ALIGN(bytes, (*ptr)->alignment); - -#endif - bytes += STACK_ARG_SIZE((*ptr)->size); - } -#endif - } - -#ifdef _WIN64 - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - if (bytes < 40) - bytes = 40; -#endif - - cif->bytes = bytes; - - /* Perform machine dependent cif processing */ - return ffi_prep_cif_machdep(cif); -} diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/pypy_ffi.c pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/pypy_ffi.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/pypy_ffi.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/pypy_ffi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* This file contains definition from symbols not defined - * in the libffi_msvc directory of CPython. - * most definitions wer copied from the ctypes.c file. - */ - -#include "ffi.h" -#include -#include - -typedef struct { char c; long long x; } s_long_long; -typedef struct { char c; float x; } s_float; -typedef struct { char c; double x; } s_double; -typedef struct { char c; long double x; } s_long_double; -typedef struct { char c; void *x; } s_void_p; -#define FLOAT_ALIGN (sizeof(s_float) - sizeof(float)) -#define DOUBLE_ALIGN (sizeof(s_double) - sizeof(double)) -#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(long long)) -#define VOID_P_ALIGN (sizeof(s_void_p) - sizeof(void*)) -#define LONGDOUBLE_ALIGN (sizeof(s_long_double) - sizeof(long double)) - -/* align and size are bogus for void, but they must not be zero */ -ffi_type ffi_type_void = { 1, 1, FFI_TYPE_VOID }; - -ffi_type ffi_type_uint8 = { 1, 1, FFI_TYPE_UINT8 }; -ffi_type ffi_type_sint8 = { 1, 1, FFI_TYPE_SINT8 }; - -ffi_type ffi_type_uint16 = { 2, 2, FFI_TYPE_UINT16 }; -ffi_type ffi_type_sint16 = { 2, 2, FFI_TYPE_SINT16 }; - -ffi_type ffi_type_uint32 = { 4, 4, FFI_TYPE_UINT32 }; -ffi_type ffi_type_sint32 = { 4, 4, FFI_TYPE_SINT32 }; - -ffi_type ffi_type_uint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_UINT64 }; -ffi_type ffi_type_sint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_SINT64 }; - -ffi_type ffi_type_float = { sizeof(float), FLOAT_ALIGN, FFI_TYPE_FLOAT }; -ffi_type ffi_type_double = { sizeof(double), DOUBLE_ALIGN, FFI_TYPE_DOUBLE }; -ffi_type ffi_type_longdouble = { sizeof(long double), LONGDOUBLE_ALIGN, FFI_TYPE_LONGDOUBLE }; - -ffi_type ffi_type_pointer = { sizeof(void *), VOID_P_ALIGN, FFI_TYPE_POINTER }; - -void ffi_fatalerror(const char* msg) { - fprintf(stderr, "%s\\n", msg); - abort(); -} - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/README.pypy pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/README.pypy --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/README.pypy 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/README.pypy 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -This directory contains the libffi package, copied from the -Modules/_ctypes/libffi_msvc directory of the CPython distribution, -as of relase 2.6a3. - -It was slightly modify to suit pypy needs: -- Py_FatalError was renamed to libffi_fatalerror, in ffi.c -- The file pypy_ffi.c was added, to resolve undefined externals. - Its contents is inspired from the `ctypes.c` file of the CPython module. diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/types.c pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/types.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/types.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/types.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/* ----------------------------------------------------------------------- - types.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Predefined ffi_types needed by libffi. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#include -#include - -/* Type definitions */ - -#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } -#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } - -/* Size and alignment are fake here. They must not be 0. */ -FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); - -FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); -FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); -FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); -FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); -FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); -FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); -FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); - -#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 || defined _WIN64 - -FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); - -#else - -FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); - -#endif - -#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined SH - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#else - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); - -#endif - - -#if defined X86 || defined X86_WIN32 || defined M68K - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined SPARC - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -#ifdef SPARC64 -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); -#else -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); -#endif - -#elif defined X86_64 - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); - -#else - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); - -#endif - diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/win32.c pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/win32.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/win32.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/win32.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -/* ----------------------------------------------------------------------- - win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. - Copyright (c) 2001 John Beniton - Copyright (c) 2002 Ranjit Mathew - - - X86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* theller: almost verbatim translation from gas syntax to MSVC inline - assembler code. */ - -/* theller: ffi_call_x86 now returns an integer - the difference of the stack - pointer before and after the function call. If everything is ok, zero is - returned. If stdcall functions are passed the wrong number of arguments, - the difference will be nonzero. */ - -#include -#include - -__declspec(naked) int -ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */ - extended_cif *ecif, /* 12 */ - unsigned bytes, /* 16 */ - unsigned flags, /* 20 */ - unsigned *rvalue, /* 24 */ - void (*fn)()) /* 28 */ -{ - _asm { - push ebp - mov ebp, esp - - push esi // NEW: this register must be preserved across function calls -// XXX SAVE ESP NOW! - mov esi, esp // save stack pointer before the call - -// Make room for all of the new args. - mov ecx, [ebp+16] - sub esp, ecx // sub esp, bytes - - mov eax, esp - -// Place all of the ffi_prep_args in position - push [ebp + 12] // ecif - push eax - call [ebp + 8] // prepfunc - -// Return stack to previous state and call the function - add esp, 8 -// FIXME: Align the stack to a 128-bit boundary to avoid -// potential performance hits. - call [ebp + 28] - -// Load ecif->cif->abi - mov ecx, [ebp + 12] - mov ecx, [ecx]ecif.cif - mov ecx, [ecx]ecif.cif.abi - - cmp ecx, FFI_STDCALL - je noclean -// STDCALL: Remove the space we pushed for the args - mov ecx, [ebp + 16] - add esp, ecx -// CDECL: Caller has already cleaned the stack -noclean: -// Check that esp has the same value as before! - sub esi, esp - -// Load %ecx with the return type code - mov ecx, [ebp + 20] - -// If the return value pointer is NULL, assume no return value. -/* - Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, - otherwise only one BYTE will be compared (instead of a DWORD)! - */ - cmp DWORD PTR [ebp + 24], 0 - jne sc_retint - -// Even if there is no space for the return value, we are -// obliged to handle floating-point values. - cmp ecx, FFI_TYPE_FLOAT - jne sc_noretval -// fstp %st(0) - fstp st(0) - - jmp sc_epilogue - -sc_retint: - cmp ecx, FFI_TYPE_INT - jne sc_retfloat -// # Load %ecx with the pointer to storage for the return value - mov ecx, [ebp + 24] - mov [ecx + 0], eax - jmp sc_epilogue - -sc_retfloat: - cmp ecx, FFI_TYPE_FLOAT - jne sc_retdouble -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstps (%ecx) - fstp DWORD PTR [ecx] - jmp sc_epilogue - -sc_retdouble: - cmp ecx, FFI_TYPE_DOUBLE - jne sc_retlongdouble -// movl 24(%ebp),%ecx - mov ecx, [ebp+24] - fstp QWORD PTR [ecx] - jmp sc_epilogue - - jmp sc_retlongdouble // avoid warning about unused label -sc_retlongdouble: - cmp ecx, FFI_TYPE_LONGDOUBLE - jne sc_retint64 -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstpt (%ecx) - fstp QWORD PTR [ecx] /* XXX ??? */ - jmp sc_epilogue - -sc_retint64: - cmp ecx, FFI_TYPE_SINT64 - jne sc_retstruct -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] - mov [ecx+0], eax - mov [ecx+4], edx - -sc_retstruct: -// Nothing to do! - -sc_noretval: -sc_epilogue: - mov eax, esi - pop esi // NEW restore: must be preserved across function calls - mov esp, ebp - pop ebp - ret - } -} diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/win64.asm pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/win64.asm --- pypy-7.3.5+dfsg/rpython/translator/c/src/libffi_msvc/win64.asm 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/libffi_msvc/win64.asm 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -PUBLIC ffi_call_AMD64 - -EXTRN __chkstk:NEAR -EXTRN ffi_closure_SYSV:NEAR - -_TEXT SEGMENT - -;;; ffi_closure_OUTER will be called with these registers set: -;;; rax points to 'closure' -;;; r11 contains a bit mask that specifies which of the -;;; first four parameters are float or double -;;; -;;; It must move the parameters passed in registers to their stack location, -;;; call ffi_closure_SYSV for the actual work, then return the result. -;;; -ffi_closure_OUTER PROC FRAME - ;; save actual arguments to their stack space. - test r11, 1 - jne first_is_float - mov QWORD PTR [rsp+8], rcx - jmp second -first_is_float: - movlpd QWORD PTR [rsp+8], xmm0 - -second: - test r11, 2 - jne second_is_float - mov QWORD PTR [rsp+16], rdx - jmp third -second_is_float: - movlpd QWORD PTR [rsp+16], xmm1 - -third: - test r11, 4 - jne third_is_float - mov QWORD PTR [rsp+24], r8 - jmp forth -third_is_float: - movlpd QWORD PTR [rsp+24], xmm2 - -forth: - test r11, 8 - jne forth_is_float - mov QWORD PTR [rsp+32], r9 - jmp done -forth_is_float: - movlpd QWORD PTR [rsp+32], xmm3 - -done: -.ALLOCSTACK 40 - sub rsp, 40 -.ENDPROLOG - mov rcx, rax ; context is first parameter - mov rdx, rsp ; stack is second parameter - add rdx, 40 ; correct our own area - mov rax, ffi_closure_SYSV - call rax ; call the real closure function - ;; Here, code is missing that handles float return values - add rsp, 40 - movd xmm0, rax ; In case the closure returned a float. - ret 0 -ffi_closure_OUTER ENDP - - -;;; ffi_call_AMD64 - -stack$ = 0 -prepfunc$ = 32 -ecif$ = 40 -bytes$ = 48 -flags$ = 56 -rvalue$ = 64 -fn$ = 72 - -ffi_call_AMD64 PROC FRAME - - mov QWORD PTR [rsp+32], r9 - mov QWORD PTR [rsp+24], r8 - mov QWORD PTR [rsp+16], rdx - mov QWORD PTR [rsp+8], rcx -.PUSHREG rbp - push rbp -.ALLOCSTACK 48 - sub rsp, 48 ; 00000030H -.SETFRAME rbp, 32 - lea rbp, QWORD PTR [rsp+32] -.ENDPROLOG - - mov eax, DWORD PTR bytes$[rbp] - add rax, 15 - and rax, -16 - call __chkstk - sub rsp, rax - lea rax, QWORD PTR [rsp+32] - mov QWORD PTR stack$[rbp], rax - - mov rdx, QWORD PTR ecif$[rbp] - mov rcx, QWORD PTR stack$[rbp] - call QWORD PTR prepfunc$[rbp] - - mov rsp, QWORD PTR stack$[rbp] - - movlpd xmm3, QWORD PTR [rsp+24] - movd r9, xmm3 - - movlpd xmm2, QWORD PTR [rsp+16] - movd r8, xmm2 - - movlpd xmm1, QWORD PTR [rsp+8] - movd rdx, xmm1 - - movlpd xmm0, QWORD PTR [rsp] - movd rcx, xmm0 - - call QWORD PTR fn$[rbp] -ret_int$: - cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT - jne ret_float$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov DWORD PTR [rcx], eax - jmp SHORT ret_nothing$ - -ret_float$: - cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT - jne SHORT ret_double$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_double$: - cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE - jne SHORT ret_int64$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_int64$: - cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64 - jne ret_nothing$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_nothing$ - -ret_nothing$: - xor eax, eax - - lea rsp, QWORD PTR [rbp+16] - pop rbp - ret 0 -ffi_call_AMD64 ENDP -_TEXT ENDS -END diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/src/rtyper.c pypy-7.3.6+dfsg/rpython/translator/c/src/rtyper.c --- pypy-7.3.5+dfsg/rpython/translator/c/src/rtyper.c 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/src/rtyper.c 2021-10-17 16:14:51.000000000 +0000 @@ -1,9 +1,6 @@ /************************************************************/ /*** C header subsection: tools for RTyper-aware code ***/ -#include "common_header.h" -#include "structdef.h" -#include "forwarddecl.h" -#include "preimpl.h" +#include "singleheader.h" #include #include diff -Nru pypy-7.3.5+dfsg/rpython/translator/c/test/test_standalone.py pypy-7.3.6+dfsg/rpython/translator/c/test/test_standalone.py --- pypy-7.3.5+dfsg/rpython/translator/c/test/test_standalone.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/c/test/test_standalone.py 2021-10-17 16:14:51.000000000 +0000 @@ -1180,6 +1180,26 @@ out2 = cbuilder.cmdexec(args=['f', arg2, '64']) assert out1 != out2 + def test_gcc_precompiled_header(self): + if sys.platform == 'win32': + py.test.skip("no win") + def entry_point(argv): + os.write(1, "hello world\n") + argv = argv[1:] + os.write(1, "argument count: " + str(len(argv)) + "\n") + for s in argv: + os.write(1, " '" + str(s) + "'\n") + return 0 + + t, cbuilder = self.compile(entry_point) + if "gcc" not in t.platform.cc: + py.test.skip("gcc only") + data = cbuilder.cmdexec('hi there') + assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + + # check that the precompiled header was generated + assert cbuilder.targetdir.join("singleheader.h.gch").check() + class TestThread(object): gcrootfinder = 'shadowstack' diff -Nru pypy-7.3.5+dfsg/rpython/translator/driver.py pypy-7.3.6+dfsg/rpython/translator/driver.py --- pypy-7.3.5+dfsg/rpython/translator/driver.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/driver.py 2021-10-17 16:14:51.000000000 +0000 @@ -507,6 +507,11 @@ newname = newexename.new(basename=soname.basename) shutil.copyfile(str(name), str(newname.new(ext=ext))) self.log.info("copied: %s" % (newname,)) + # HACK: copy libcffi-7.dll which is required for venvs + # At some point, we should stop doing this, and instead + # use the artifact from packaging the build instead + libffi = py.path.local.sysfind('libffi-7.dll') + shutil.copyfile(str(libffi), os.getcwd() + r'\libffi-7.dll') self.c_entryp = newexename self.log.info("created: %s" % (self.c_entryp,)) diff -Nru pypy-7.3.5+dfsg/rpython/translator/platform/posix.py pypy-7.3.6+dfsg/rpython/translator/platform/posix.py --- pypy-7.3.5+dfsg/rpython/translator/platform/posix.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/platform/posix.py 2021-10-17 16:14:54.000000000 +0000 @@ -191,7 +191,6 @@ ('LINKFILES', eci.link_files), ('RPATH_FLAGS', self.get_rpath_flags(rel_libdirs)), ] - if profopt==True and shared==True: definitions.append(('PROFOPT_TARGET', exe_name.basename)) @@ -206,13 +205,23 @@ if detect_pax(): postcompile_rule[2].append('attr -q -s pax.flags -V m $(BIN)') + if "gcc" in self.cc and headers_to_precompile: + precompiled_header = headers_to_precompile[0].basename + pch = "%s.gch" % precompiled_header + extra_rules = [(pch, str(precompiled_header), '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)')] + m.definition('PRECOMPILEDHEADERS', [pch]) + o_dependency = '%.c ' + pch + else: + pch = "" + extra_rules = [] + o_dependency = '%.c' rules = [ ('all', '$(DEFAULT_TARGET)', []), ('$(TARGET)', '$(OBJECTS)', ['$(CC_LINK) $(LDFLAGSEXTRA) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) $(LINKFILES) $(LDFLAGS)', '$(MAKE) postcompile BIN=$(TARGET)']), - ('%.o', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), + ('%.o', o_dependency, '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), ('%.o', '%.s', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), ('%.o', '%.cxx', '$(CXX) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'), - ] + ] + extra_rules for rule in rules: m.rule(*rule) diff -Nru pypy-7.3.5+dfsg/rpython/translator/simplify.py pypy-7.3.6+dfsg/rpython/translator/simplify.py --- pypy-7.3.5+dfsg/rpython/translator/simplify.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/simplify.py 2021-10-17 16:14:51.000000000 +0000 @@ -419,19 +419,18 @@ hasattr: True, } -def find_start_blocks(graphs): - start_blocks = set() - for graph in graphs: - start_blocks.add(graph.startblock) - return start_blocks - def transform_dead_op_vars_in_blocks(blocks, graphs, translator=None): """Remove dead operations and variables that are passed over a link but not used in the target block. Input is a set of blocks""" read_vars = set() # set of variables really used dependencies = defaultdict(set) # map {Var: list-of-Vars-it-depends-on} set_of_blocks = set(blocks) - start_blocks = find_start_blocks(graphs) + if len(graphs) == 1: + start_blocks = {graphs[0].startblock} + else: + assert translator + start_blocks = {translator.annotator.annotated[block].startblock + for block in blocks} def canremove(op, block): return op.opname in CanRemove and op is not block.raising_op diff -Nru pypy-7.3.5+dfsg/rpython/translator/transform.py pypy-7.3.6+dfsg/rpython/translator/transform.py --- pypy-7.3.5+dfsg/rpython/translator/transform.py 2021-05-23 11:36:26.000000000 +0000 +++ pypy-7.3.6+dfsg/rpython/translator/transform.py 2021-10-17 16:14:51.000000000 +0000 @@ -134,12 +134,13 @@ s_dict.dictdef.generalize_key(self.binding(op.args[1])) -def transform_dead_op_vars(self, block_subset): +def transform_dead_op_vars(ann, block_subset): # we redo the same simplification from simplify.py, # to kill dead (never-followed) links, # which can possibly remove more variables. from rpython.translator.simplify import transform_dead_op_vars_in_blocks - transform_dead_op_vars_in_blocks(block_subset, self.translator.graphs) + transform_dead_op_vars_in_blocks(block_subset, ann.translator.graphs, + ann.translator) def transform_dead_code(self, block_subset): """Remove dead code: these are the blocks that are not annotated at all