* Wed Jan 5 2011 David Malcolm <dmalcolm@redhat.com> - 1.4.1-4

- rebuild pypy using itself, for speed, with a boolean to break this cycle in
the build-requirement graph (falling back to using "python-devel" aka CPython)
- add work-in-progress patch to try to make generated c more readable
(rhbz#666963)
- capture the RPython source code files from the build within the debuginfo
package (rhbz#666975)
This commit is contained in:
David Malcolm 2011-01-06 17:09:03 -05:00
parent f756cfcb34
commit 00e57e74f8
2 changed files with 773 additions and 3 deletions

View File

@ -0,0 +1,695 @@
diff -r cd083843b67a pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/interpreter/pycode.py Wed Jan 05 16:14:35 2011 -0500
@@ -14,6 +14,7 @@
from pypy.interpreter.astcompiler.consts import (CO_OPTIMIZED,
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
CO_GENERATOR, CO_CONTAINSGLOBALS)
+from pypy.interpreter.pytraceback import offset2lineno
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib import jit
@@ -81,6 +82,7 @@
self.hidden_applevel = hidden_applevel
self.magic = magic
self._signature = cpython_code_signature(self)
+ self._cached_source = None
self._initialize()
def _initialize(self):
@@ -403,3 +405,25 @@
def repr(self, space):
return space.wrap(self.get_repr())
repr.unwrap_spec = ['self', ObjSpace]
+
+ def get_linenum_for_offset(self, offset):
+ # Given a bytecode offset, return a 1-based index into the lines of the
+ # source code
+ return offset2lineno(self, offset)
+
+ def _ensure_source(self):
+ # Lazily grab the source lines into self._cached_source (or raise
+ # an IOError)
+ if not self._cached_source:
+ f = open(self.co_filename, 'r')
+ source = [line.rstrip() for line in f.readlines()]
+ f.close()
+ self._cached_source = source
+
+ def get_source_text(self, linenum):
+ # Given a 1-based index, get the corresponding line of source code (or
+ # raise an IOError)
+ self._ensure_source()
+ return self._cached_source[linenum - 1]
+
+
diff -r cd083843b67a pypy/objspace/flow/model.py
--- a/pypy/objspace/flow/model.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/objspace/flow/model.py Wed Jan 05 16:14:35 2011 -0500
@@ -31,6 +31,120 @@
__metaclass__ = type
+class SourceLoc(object):
+ # A srcloc is a specific location within the RPython source code,
+ # intended for human display
+ __slots__ = ('code', # code object
+ 'linenum' # 1-based index, as displayed to a user
+ )
+ def __init__(self, code, linenum):
+ self.code = code
+ self.linenum = linenum
+
+ def get_text(self):
+ # Get the actual source text of this line
+ return self.code.get_source_text(self.linenum)
+
+ def __eq__(self, other):
+ return self.code == other.code and self.linenum == other.linenum
+
+ def __ne__(self, other):
+ if other:
+ return self.code != other.code or self.linenum != other.linenum
+ else:
+ return True
+
+class CodeLoc(object):
+ # A codeloc is a specific location within the RPython bytecode
+ __slots__ = ('code', # code object
+ 'offset' # int index into bytecode, or -1
+ )
+
+ def __init__(self, code, offset):
+ self.code = code
+ self.offset = offset
+
+ def __str__(self):
+ if self.offset >= 0:
+ return "%s@%d" % (self.code.co_name, self.offset)
+ else:
+ return ""
+
+ def __ne__(self, other):
+ if other:
+ return self.code != other.code or self.offset != other.offset
+ else:
+ return True
+
+ def __cmp__(self, other):
+ # Partial ordering, for those locations that have an offset:
+ if other:
+ if self.offset >= 0 and other.offset >= 0:
+ return self.offset - other.offset
+ return 0
+
+ def get_source_loc(self):
+ # Convert to a SourceLoc:
+ return SourceLoc(self.code, self.code.get_linenum_for_offset(self.offset))
+
+class OperationLoc(object):
+ # An oploc is the location within the RPython source code of a given
+ # operation
+ #
+ # This is a list consisting of CodeLoc instances, some of which may be None
+ #
+ # For the simple case, this is list of length 1 with a single CodeLoc
+ #
+ # For an operation inside an inlined callsite, we have a list of length 2:
+ # [codeloc of callsite,
+ # codeloc of operation within inlined body]
+ #
+ # For more interesting inlined cases, we have a chain of source locations:
+ # [codeloc of callsite,
+ # codeloc of inner callsite,
+ # ... ,
+ # codeloc of innermost inlined callsite,
+ # codeloc of operation within inlined body]
+ #
+
+ __slots__ = ('codelocs', )
+
+ def __init__(self, codelocs):
+ self.codelocs = codelocs
+
+ def __str__(self):
+ return '[' + ' > '.join(str(codeloc) for codeloc in self.codelocs) + ']'
+
+ def __cmp__(self, other):
+ return cmp(self.codelocs, other.codelocs)
+
+def block_comparator(blk0, blk1):
+ '''
+ Sort function for blocks, putting them in an ordering that attempts to
+ maximize readability of the generated C code
+ '''
+ # print 'comparing %r and %r' % (blk0, blk1)
+ # Put the start/end block at the top/bottom:
+ if blk0.isstartblock:
+ return -1
+
+ if blk1.isstartblock:
+ return 1
+
+ # Order blocks by the offset, where present:
+ if blk0.operations:
+ if blk1.operations:
+ return cmp(blk0.operations[0].oploc, blk1.operations[0].oploc)
+ else:
+ return -1
+ else:
+ if blk1.operations:
+ return 1
+ else:
+ return 0
+
+def edge_comparator(edge0, edge1):
+ return block_comparator(edge0.target, edge1.target)
class FunctionGraph(object):
__slots__ = ['startblock', 'returnblock', 'exceptblock', '__dict__']
@@ -94,6 +208,21 @@
seen[block] = True
stack += block.exits[::-1]
+ def iterblocks_by_source(self):
+ # Try to preserve logical source ordering in the blocks
+ block = self.startblock
+ yield block
+ seen = {block: True}
+ stack = list(block.exits[::-1])
+ stack.sort(edge_comparator)
+ while stack:
+ block = stack.pop().target
+ if block not in seen:
+ yield block
+ seen[block] = True
+ stack += block.exits[::-1]
+ stack.sort(edge_comparator)
+
def iterlinks(self):
block = self.startblock
seen = {block: True}
@@ -183,14 +312,14 @@
self.exits = [] # list of Link(s)
def at(self):
- if self.operations and self.operations[0].offset >= 0:
- return "@%d" % self.operations[0].offset
+ if self.operations:
+ return str(self.operations[0].oploc)
else:
return ""
def __str__(self):
if self.operations:
- txt = "block@%d" % self.operations[0].offset
+ txt = "block%s" % self.operations[0].oploc
else:
if (not self.exits) and len(self.inputargs) == 1:
txt = "return block"
@@ -245,6 +374,21 @@
from pypy.translator.tool.graphpage import try_show
try_show(self)
+ def isreturnblock(self):
+ return (not self.operations) and (not self.exits) and len(self.inputargs) == 1
+
+ def get_base_label(self, blocknum):
+ # Generate a more friendly C label for this block
+ if self.operations:
+ txt = "block"
+ elif (not self.exits) and len(self.inputargs) == 1:
+ txt = "return_block"
+ elif (not self.exits) and len(self.inputargs) == 2:
+ txt = "raise_block"
+ else:
+ txt = "codeless_block"
+ return '%s%d' % (txt, blocknum)
+
class Variable(object):
__slots__ = ["_name", "_nr", "concretetype"]
@@ -331,13 +475,15 @@
class SpaceOperation(object):
- __slots__ = "opname args result offset".split()
+ __slots__ = "opname args result oploc".split()
- def __init__(self, opname, args, result, offset=-1):
+ def __init__(self, opname, args, result, oploc=None):
self.opname = intern(opname) # operation name
self.args = list(args) # mixed list of var/const
self.result = result # either Variable or Constant instance
- self.offset = offset # offset in code string
+ if oploc is None:
+ oploc = OperationLoc([None])
+ self.oploc = oploc
def __eq__(self, other):
return (self.__class__ is other.__class__ and
@@ -352,8 +498,9 @@
return hash((self.opname,tuple(self.args),self.result))
def __repr__(self):
- return "%r = %s(%s)" % (self.result, self.opname,
- ", ".join(map(repr, self.args)))
+ return "%r = %s(%s) (%s)" % (self.result, self.opname,
+ ", ".join(map(repr, self.args)),
+ self.oploc)
class Atom(object):
def __init__(self, name):
@@ -448,8 +595,7 @@
for op in oplist:
copyop = SpaceOperation(op.opname,
[copyvar(v) for v in op.args],
- copyvar(op.result), op.offset)
- #copyop.offset = op.offset
+ copyvar(op.result), op.oploc)
result.append(copyop)
return result
newblock.operations = copyoplist(block.operations)
diff -r cd083843b67a pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/objspace/flow/objspace.py Wed Jan 05 16:14:35 2011 -0500
@@ -310,7 +310,9 @@
def do_operation(self, name, *args_w):
spaceop = SpaceOperation(name, args_w, Variable())
if hasattr(self, 'executioncontext'): # not here during bootstrapping
- spaceop.offset = self.executioncontext.crnt_offset
+ codeloc = CodeLoc(self.executioncontext.code,
+ self.executioncontext.crnt_offset)
+ spaceop.oploc = OperationLoc([codeloc])
self.executioncontext.recorder.append(spaceop)
return spaceop.result
diff -r cd083843b67a pypy/objspace/flow/test/test_model.py
--- a/pypy/objspace/flow/test/test_model.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/objspace/flow/test/test_model.py Wed Jan 05 16:14:35 2011 -0500
@@ -132,3 +132,25 @@
assert v2.renamed
assert v2.name.startswith("foobar_") and v2.name != v.name
assert v2.name.split('_', 1)[1].isdigit()
+
+def test_source_locations():
+ # Invent some random offsets into the code:
+ co = sample_function.__code__
+ codelocA = CodeLoc(co, 42)
+ codelocB = CodeLoc(co, 87)
+
+ assert str(codelocA) == 'sample_function@42'
+ assert str(codelocB) == 'sample_function@87'
+
+ assert cmp(codelocA, codelocB) < 0
+ assert cmp(codelocB, codelocA) > 0
+
+ oplocA = OperationLoc([codelocA])
+ oplocB = OperationLoc([codelocB])
+
+ assert str(oplocA) == '[sample_function@42]'
+ assert str(oplocB) == '[sample_function@87]'
+
+ assert cmp(oplocA, oplocB) < 0
+ assert cmp(oplocB, oplocA) > 0
+
diff -r cd083843b67a pypy/rpython/rtyper.py
--- a/pypy/rpython/rtyper.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/rpython/rtyper.py Wed Jan 05 16:14:35 2011 -0500
@@ -800,7 +800,7 @@
return vars
def genop(self, opname, args_v, resulttype=None):
- return self.llops.genop(opname, args_v, resulttype)
+ return self.llops.genop(opname, args_v, resulttype, self.spaceop.oploc)
def gendirectcall(self, ll_function, *args_v):
return self.llops.gendirectcall(ll_function, *args_v)
@@ -935,7 +935,7 @@
v.concretetype))
return v
- def genop(self, opname, args_v, resulttype=None):
+ def genop(self, opname, args_v, resulttype=None, oploc=None):
try:
for v in args_v:
v.concretetype
@@ -944,7 +944,7 @@
" and pass its result to genop(),"
" never hop.args_v directly.")
vresult = Variable()
- self.append(SpaceOperation(opname, args_v, vresult))
+ self.append(SpaceOperation(opname, args_v, vresult, oploc))
if resulttype is None:
vresult.concretetype = Void
return None
diff -r cd083843b67a pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/backendopt/inline.py Wed Jan 05 16:14:35 2011 -0500
@@ -4,6 +4,7 @@
from pypy.translator.unsimplify import copyvar
from pypy.objspace.flow.model import Variable, Constant, Block, Link
from pypy.objspace.flow.model import SpaceOperation, c_last_exception
+from pypy.objspace.flow.model import OperationLoc
from pypy.objspace.flow.model import FunctionGraph
from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph
from pypy.annotation import model as annmodel
@@ -231,6 +232,7 @@
self.varmap = {}
self._copied_blocks = {}
self.op = block.operations[index_operation]
+ self.callsite_oploc = self.op.oploc
self.graph_to_inline = self.get_graph_from_op(self.op)
self.exception_guarded = False
if (block.exitswitch == c_last_exception and
@@ -297,7 +299,9 @@
def copy_operation(self, op):
args = [self.get_new_name(arg) for arg in op.args]
- result = SpaceOperation(op.opname, args, self.get_new_name(op.result))
+ new_oploc = OperationLoc(self.callsite_oploc.codelocs[:] + op.oploc.codelocs[:])
+ result = SpaceOperation(op.opname, args, self.get_new_name(op.result),
+ new_oploc)
return result
def copy_block(self, block):
diff -r cd083843b67a pypy/translator/c/funcgen.py
--- a/pypy/translator/c/funcgen.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/c/funcgen.py Wed Jan 05 16:14:35 2011 -0500
@@ -1,4 +1,6 @@
import sys
+import inspect
+import dis
from pypy.translator.c.support import USESLOTS # set to False if necessary while refactoring
from pypy.translator.c.support import cdecl
from pypy.translator.c.support import llvalue_from_constant, gen_assignments
@@ -22,6 +24,38 @@
KEEP_INLINED_GRAPHS = False
+def block_comparator(blk0, blk1):
+ '''
+ Sort function for blocks, putting them in an ordering that attempts to
+ maximize readability of the generated C code
+ '''
+ # print 'comparing %r and %r' % (blk0, blk1)
+ # Put the start/end block at the top/bottom:
+ if blk0.isstartblock:
+ return -1
+
+ if blk1.isstartblock:
+ return 1
+
+ # Order blocks by the offset, where present:
+ if blk0.operations:
+ if blk1.operations:
+ return cmp(blk0.operations[0].oploc, blk1.operations[0].oploc)
+ else:
+ return -1
+ else:
+ if blk1.operations:
+ return 1
+ else:
+ return 0
+
+def escape_c_comments(py_src):
+ # Escape C comments within RPython source, to avoid generating bogus
+ # comments in our generated C source:
+ py_src = py_src.replace('/*', '')
+ py_src = py_src.replace('*/', '')
+ return py_src
+
class FunctionCodeGenerator(object):
"""
Collects information about a function which we have to generate
@@ -210,14 +244,57 @@
def cfunction_body(self):
graph = self.graph
- yield 'goto block0;' # to avoid a warning "this label is not used"
+ # Try to print python source code:
+ if hasattr(graph, 'func'):
+ filename = inspect.getfile(graph.func)
+ #yield '/* name: %r */' % filename
+ try:
+ src, startline = inspect.getsourcelines(graph.func)
+ except IOError:
+ pass # No source found
+ except IndexError:
+ pass # Bulletproofing
+ else:
+ yield '/* Python source %r' % filename
+ for i, line in enumerate(src):
+ line = line.rstrip()
+ line = escape_c_comments(line)
+ # FuncNode.funcgen_implementation treats lines ending in ':'
+ # as C blocks, which messes up the formatting.
+ # Work around this:
+ if line.endswith(':'):
+ line += ' '
+ yield ' * %4d : %s' % (startline + i, line)
+ yield ' */'
+
+ label = graph.startblock.get_base_label(self.blocknum[graph.startblock])
+ yield 'goto %s;' % label # to avoid a warning "this label is not used"
+
+ # Sort the blocks into a (hopefully) readable order:
+ blocks = list(graph.iterblocks_by_source())
+ blocks.sort(block_comparator)
# generate the body of each block
- for block in graph.iterblocks():
+ for block in blocks:
+ cursrcloc = None
myblocknum = self.blocknum[block]
yield ''
- yield 'block%d:' % myblocknum
+ yield '%s:' % block.get_base_label(myblocknum)
+ #yield "/* repr(block): %r */" % (block, )
+ #yield "/* type(block): %r */" % (type(block), )
for i, op in enumerate(block.operations):
+ #yield "/* type(op): %r */" % (type(op), )
+ #yield "/* op.oploc: %s */" % (op.oploc, )
+ codeloc = op.oploc.codelocs[-1]
+ if codeloc:
+ srcloc = codeloc.get_source_loc()
+ if srcloc != cursrcloc:
+ try:
+ yield "/* %s:%d : %s */" % (codeloc.code.co_name, srcloc.linenum, escape_c_comments(srcloc.get_text()))
+ cursrcloc = srcloc
+ except IOError:
+ pass
+
for line in self.gen_op(op):
yield line
if len(block.exits) == 0:
@@ -310,7 +387,7 @@
assignments.append((a2typename, dest, src))
for line in gen_assignments(assignments):
yield line
- label = 'block%d' % self.blocknum[link.target]
+ label = link.target.get_base_label(self.blocknum[link.target])
if link.target in self.innerloops:
loop = self.innerloops[link.target]
if link is loop.links[-1]: # link that ends a loop
diff -r cd083843b67a pypy/translator/c/test/test_genc.py
--- a/pypy/translator/c/test/test_genc.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/c/test/test_genc.py Wed Jan 05 16:14:35 2011 -0500
@@ -1,4 +1,5 @@
import autopath, sys, os, py
+import re
from pypy.rpython.lltypesystem.lltype import *
from pypy.annotation import model as annmodel
from pypy.translator.translator import TranslationContext
@@ -498,3 +499,130 @@
else:
assert 0, "the call was not found in the C source"
assert 'PYPY_INHIBIT_TAIL_CALL();' in lines[i+1]
+
+def get_generated_c_source(fn, types):
+ # Return a (optimized fn, c source code, c source filename) 3-tuple
+ t = Translation(fn)
+ t.annotate(types)
+ c_filename_path = t.source_c()
+ h = c_filename_path.open()
+ src = h.read()
+ h.close()
+ c_fn = t.compile_c()
+ return (c_fn, src, c_filename_path)
+
+def extract_c_function(c_src, fname):
+ # Extract the source for a given C function out of a the given src string
+ # Makes assumptions about the layout of the source
+ pattern = '^(.+) \**%s\(.*\) {$' % fname
+ within_fn = False
+ result = ''
+ for line in c_src.splitlines():
+ if within_fn:
+ result += line + '\n'
+ if line.startswith('}'):
+ return result
+ else:
+ m = re.match(pattern, line)
+ if m:
+ within_fn = True
+ result += line + '\n'
+ return result
+
+
+
+def test_generated_c_source():
+ # Verify that generate C source "looks good"
+ # We'll use is_perfect_number, as it contains a loop and a conditional
+
+ # Generate C source code
+ from pypy.translator.test.snippet import is_perfect_number
+ c_fn, c_src, c_filename_path = get_generated_c_source(is_perfect_number,
+ [int])
+
+ # Locate the C source for the type-specialized function:
+ c_fn_src = extract_c_function(c_src, 'pypy_g_is_perfect_number')
+
+ # Verify that the C source contains embedded comments containing the lines
+ # of the python source:
+ expected_comment_lines = [
+ '/* is_perfect_number:31 : while div < n: */',
+ '/* is_perfect_number:32 : if n % div == 0: */',
+ '/* is_perfect_number:33 : sum += div */',
+ '/* is_perfect_number:34 : div += 1 */',
+ '/* is_perfect_number:35 : return n == sum */']
+ for exp_line in expected_comment_lines:
+ assert exp_line in c_fn_src
+
+ # Verify that the lines occur in the correct order
+ # ...we do this by filtering the function's generated C source to just
+ # those lines containing our comments (and dropping whitespace):
+ lines = c_fn_src.splitlines()
+ lines = [line.strip()
+ for line in lines
+ if '/* is_perfect_number:' in line]
+
+ # ...we should now have exact equality: the ordering should be as expected,
+ # and each comment should appear exactly once:
+ assert lines == expected_comment_lines
+
+ # Ensure that the generated C function does the right thing:
+ assert c_fn(5) == False
+ assert c_fn(6) == True
+ assert c_fn(7) == False
+
+ assert c_fn(5.0) == False
+ assert c_fn(6.0) == True
+ assert c_fn(7.0) == False
+
+ assert c_fn(5L) == False
+ assert c_fn(6L) == True
+ assert c_fn(7L) == False
+
+ try:
+ c_fn('hello world')
+ except:
+ pass
+ else:
+ raise 'Was expected exception'
+
+def test_escaping_c_comments():
+ # Ensure that c comments within RPython code get escaped when we generate
+ # our .c code (to avoid generating bogus C)
+ # See e.g. pypy.module.cpyext.dictobject's PyDict_Next, which has a
+ # docstring embedding a C comment
+ def c_style_comment(a, b):
+ '''Here is a C-style comment within an RPython docstring:
+ /* hello world */
+ '''
+ # and here's one in a string literal:
+ return '/* hello world a:%s b:%s */' % (a, b)
+
+ def cplusplus_style_comment(a, b):
+ '''Here is a C++-style comment within an RPython docstring:
+ // hello world
+ '''
+ # and here are some in string literals, and one as the floor division
+ # operator:
+ return '// hello world: a // b = %s' % (a // b)
+
+ for fn_name, exp_output in [('c_style_comment',
+ '/* hello world a:6 b:3 */'),
+ ('cplusplus_style_comment',
+ '// hello world: a // b = 2')]:
+ fn = locals()[fn_name]
+
+ c_fn, c_src, c_filename_path = get_generated_c_source(fn, [int, int])
+ # If the above survived, then the C compiler managed to handle
+ # the generated C code
+
+ # Verify that the generated code works (i.e. that we didn't
+ # accidentally change the meaning):
+ assert c_fn(6, 3) == exp_output
+
+ # Ensure that at least part of the docstrings made it into the C
+ # code:
+ c_fn_src = extract_c_function(c_src, 'pypy_g_' + fn_name)
+ assert 'Here is a ' in c_fn_src
+ assert 'style comment within an RPython docstring' in c_fn_src
+
diff -r cd083843b67a pypy/translator/driver.py
--- a/pypy/translator/driver.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/driver.py Wed Jan 05 16:14:35 2011 -0500
@@ -539,6 +539,7 @@
dstname = self.compute_exe_name() + '.staticdata.info'
shutil.copy(str(fname), str(dstname))
self.log.info('Static data info written to %s' % dstname)
+ return c_source_filename
#
task_source_c = taskdef(task_source_c, ['database_c'], "Generating c source")
diff -r cd083843b67a pypy/translator/gensupp.py
--- a/pypy/translator/gensupp.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/gensupp.py Wed Jan 05 16:14:35 2011 -0500
@@ -16,8 +16,8 @@
def visit(block):
if isinstance(block, Block):
# first we order by offset in the code string
- if block.operations:
- ofs = block.operations[0].offset
+ if block.operations and block.operations[0].oploc.codelocs[0]:
+ ofs = block.operations[0].oploc.codelocs[0].offset
else:
ofs = sys.maxint
# then we order by input variable name or value
diff -r cd083843b67a pypy/translator/interactive.py
--- a/pypy/translator/interactive.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/interactive.py Wed Jan 05 16:14:35 2011 -0500
@@ -138,7 +138,7 @@
def source_c(self, argtypes=None, **kwds):
self.update_options(argtypes, kwds)
self.ensure_backend('c')
- self.driver.source_c()
+ return self.driver.source_c()
def source_cl(self, argtypes=None, **kwds):
self.update_options(argtypes, kwds)
diff -r cd083843b67a pypy/translator/llsupport/wrapper.py
--- a/pypy/translator/llsupport/wrapper.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/llsupport/wrapper.py Wed Jan 05 16:14:35 2011 -0500
@@ -59,6 +59,8 @@
# "return result"
block = Block(wrapper_inputargs)
wgraph = FunctionGraph('pyfn_' + (newname or func.func_name), block)
+ if hasattr(graph, 'func'):
+ wgraph.func = graph.func
translator.update_call_graph(wgraph, graph, object())
translator.graphs.append(wgraph)
block.operations[:] = newops
diff -r cd083843b67a pypy/translator/simplify.py
--- a/pypy/translator/simplify.py Mon Dec 20 17:17:45 2010 +0100
+++ b/pypy/translator/simplify.py Wed Jan 05 16:14:35 2011 -0500
@@ -294,7 +294,7 @@
return renaming.get(v, v)
def rename_op(op):
args = [rename(a) for a in op.args]
- op = SpaceOperation(op.opname, args, rename(op.result), op.offset)
+ op = SpaceOperation(op.opname, args, rename(op.result), op.oploc)
# special case...
if op.opname == 'indirect_call':
if isinstance(op.args[0], Constant):

View File

@ -1,6 +1,6 @@
Name: pypy
Version: 1.4.1
Release: 3%{?dist}
Release: 4%{?dist}
Summary: Python implementation with a Just-In-Time compiler
Group: Development/Languages
@ -136,9 +136,33 @@ Patch2: fix-test_commands-expected-ls-output-issue7108.patch
# https://codespeak.net/issue/pypy-dev/issue614
Patch3: pypy-1.4.1-add-LIBRARY_INSTALLATION_PATH.patch
# Try to improve the readability of the generated .c code, by adding in the
# RPython source as comments where possible.
# A version of this was sent upstream as:
# http://codespeak.net/pipermail/pypy-dev/2010q4/006532.html
# TODO: get this into the upstream bug tracker, and finish inlining
# support (rhbz#666963)
Patch4: pypy-1.4.1-more-readable-c-code.patch
# Build-time requirements:
BuildRequires: python-devel
# pypy's can be rebuilt using itself, rather than with CPython; doing so
# halves the build time.
#
# Turn it off with this boolean, to revert back to rebuilding using CPython
# and avoid a cycle in the build-time dependency graph:
#
%global use_self_when_building 1
%if 0%{use_self_when_building}
BuildRequires: pypy
%global bootstrap_python_interp pypy
%else
BuildRequires: python-devel
%global bootstrap_python_interp python
%endif
# FIXME: I'm seeing errors like this in the logs:
# [translation:WARNING] The module '_rawffi' is disabled
@ -215,6 +239,8 @@ sed -i \
-e 's|LIBRARY_INSTALLATION_PATH|"%{pypyprefix}"|' \
pypy/translator/goal/app_main.py
%patch4 -p1 -b .more-readable-c-code
# Replace /usr/local/bin/python shebangs with /usr/bin/python:
find -name "*.py" -exec \
@ -304,6 +330,7 @@ BuildPyPy() {
# doesn't interract well with the results of using our standard build flags.
# For now, filter our CFLAGS of everything that could be conflicting with
# pypy. Need to check these and reenable ones that are okay later.
# Filed as https://bugzilla.redhat.com/show_bug.cgi?id=666966
export CFLAGS=$(echo "$RPM_OPT_FLAGS" | sed -e 's/-Wp,-D_FORTIFY_SOURCE=2//' -e 's/-fexceptions//' -e 's/-fstack-protector//' -e 's/--param=ssp-buffer-size=4//' -e 's/-O2//' -e 's/-fasynchronous-unwind-tables//' -e 's/-march=i686//' -e 's/-mtune=atom//')
# If we're already built the JIT-enabled "pypy", then use it for subsequent
@ -311,7 +338,10 @@ BuildPyPy() {
if test -x './pypy' ; then
INTERP='./pypy'
else
INTERP='python'
# First pypy build within this rpm build?
# Fall back to using the bootstrap python interpreter, which might be a
# system copy of pypy from an earlier rpm, or be cpython's /usr/bin/python:
INTERP='%{bootstrap_python_interp}'
fi
# Here's where we actually invoke the build:
@ -484,6 +514,34 @@ mkdir -p %{buildroot}/%{pypyprefix}/site-packages
%{buildroot}/%{_bindir}/pypy \
0
# Capture the RPython source code files from the build within the debuginfo
# package (rhbz#666975)
%global pypy_debuginfo_dir /usr/src/debug/pypy-%{version}-src
mkdir -p %{buildroot}%{pypy_debuginfo_dir}
# copy over everything:
cp -a pypy %{buildroot}%{pypy_debuginfo_dir}
# ...then delete files that aren't .py files:
find \
%{buildroot}%{pypy_debuginfo_dir} \
\( -type f \
-a \
\! -name "*.py" \
\) \
-delete
# We don't need bytecode for these files; they are being included for reference
# purposes.
# There are some rpmlint warnings from these files:
# non-executable-script
# wrong-script-interpreter
# zero-length
# script-without-shebang
# dangling-symlink
# but given that the objective is to preserve a copy of the source code, those
# are acceptable.
%check
topdir=$(pwd)
@ -511,6 +569,7 @@ CheckPyPy() {
# Gather a list of tests to skip, due to known failures
# TODO: report these failures to pypy upstream
# See also rhbz#666967 and rhbz#666969
TESTS_TO_SKIP=""
# Test failures relating to missing codecs
@ -622,6 +681,14 @@ CheckPyPy() {
# AssertionError: ValueError not raised
SkipTest test_zlib
%if 0%{use_self_when_building}
# Patch 3 prioritizes the installed copy of pypy's libraries over the
# build copy.
# This leads to test failures of test_pep263 and test_tarfile
# For now, suppress these when building using pypy itself:
SkipTest test_pep263 # on-disk encoding issues
SkipTest test_tarfile # permissions issues
%endif
# Run the built binary through the selftests:
time ./$ExeName -m test.regrtest -x $TESTS_TO_SKIP
@ -696,6 +763,14 @@ rm -rf $RPM_BUILD_ROOT
%changelog
* Wed Jan 5 2011 David Malcolm <dmalcolm@redhat.com> - 1.4.1-4
- rebuild pypy using itself, for speed, with a boolean to break this cycle in
the build-requirement graph (falling back to using "python-devel" aka CPython)
- add work-in-progress patch to try to make generated c more readable
(rhbz#666963)
- capture the RPython source code files from the build within the debuginfo
package (rhbz#666975)
* Wed Dec 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.4.1-3
- try to respect the FHS by installing libraries below libdir, rather than
datadir; patch app_main.py to look in this installation location first when