[pypy-commit] pypy numpy-complex: merged default
alex_gaynor
noreply at buildbot.pypy.org
Fri Oct 28 17:44:43 CEST 2011
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: numpy-complex
Changeset: r48568:8f899b94cb87
Date: 2011-10-28 00:11 -0400
http://bitbucket.org/pypy/pypy/changeset/8f899b94cb87/
Log: merged default
diff too long, truncating to 10000 out of 10937 lines
diff --git a/lib-python/modified-2.7/heapq.py b/lib-python/modified-2.7/heapq.py
new file mode 100644
--- /dev/null
+++ b/lib-python/modified-2.7/heapq.py
@@ -0,0 +1,442 @@
+# -*- coding: latin-1 -*-
+
+"""Heap queue algorithm (a.k.a. priority queue).
+
+Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
+all k, counting elements from 0. For the sake of comparison,
+non-existing elements are considered to be infinite. The interesting
+property of a heap is that a[0] is always its smallest element.
+
+Usage:
+
+heap = [] # creates an empty heap
+heappush(heap, item) # pushes a new item on the heap
+item = heappop(heap) # pops the smallest item from the heap
+item = heap[0] # smallest item on the heap without popping it
+heapify(x) # transforms list into a heap, in-place, in linear time
+item = heapreplace(heap, item) # pops and returns smallest item, and adds
+ # new item; the heap size is unchanged
+
+Our API differs from textbook heap algorithms as follows:
+
+- We use 0-based indexing. This makes the relationship between the
+ index for a node and the indexes for its children slightly less
+ obvious, but is more suitable since Python uses 0-based indexing.
+
+- Our heappop() method returns the smallest item, not the largest.
+
+These two make it possible to view the heap as a regular Python list
+without surprises: heap[0] is the smallest item, and heap.sort()
+maintains the heap invariant!
+"""
+
+# Original code by Kevin O'Connor, augmented by Tim Peters and Raymond Hettinger
+
+__about__ = """Heap queues
+
+[explanation by Fran�ois Pinard]
+
+Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
+all k, counting elements from 0. For the sake of comparison,
+non-existing elements are considered to be infinite. The interesting
+property of a heap is that a[0] is always its smallest element.
+
+The strange invariant above is meant to be an efficient memory
+representation for a tournament. The numbers below are `k', not a[k]:
+
+ 0
+
+ 1 2
+
+ 3 4 5 6
+
+ 7 8 9 10 11 12 13 14
+
+ 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+
+
+In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In
+an usual binary tournament we see in sports, each cell is the winner
+over the two cells it tops, and we can trace the winner down the tree
+to see all opponents s/he had. However, in many computer applications
+of such tournaments, we do not need to trace the history of a winner.
+To be more memory efficient, when a winner is promoted, we try to
+replace it by something else at a lower level, and the rule becomes
+that a cell and the two cells it tops contain three different items,
+but the top cell "wins" over the two topped cells.
+
+If this heap invariant is protected at all time, index 0 is clearly
+the overall winner. The simplest algorithmic way to remove it and
+find the "next" winner is to move some loser (let's say cell 30 in the
+diagram above) into the 0 position, and then percolate this new 0 down
+the tree, exchanging values, until the invariant is re-established.
+This is clearly logarithmic on the total number of items in the tree.
+By iterating over all items, you get an O(n ln n) sort.
+
+A nice feature of this sort is that you can efficiently insert new
+items while the sort is going on, provided that the inserted items are
+not "better" than the last 0'th element you extracted. This is
+especially useful in simulation contexts, where the tree holds all
+incoming events, and the "win" condition means the smallest scheduled
+time. When an event schedule other events for execution, they are
+scheduled into the future, so they can easily go into the heap. So, a
+heap is a good structure for implementing schedulers (this is what I
+used for my MIDI sequencer :-).
+
+Various structures for implementing schedulers have been extensively
+studied, and heaps are good for this, as they are reasonably speedy,
+the speed is almost constant, and the worst case is not much different
+than the average case. However, there are other representations which
+are more efficient overall, yet the worst cases might be terrible.
+
+Heaps are also very useful in big disk sorts. You most probably all
+know that a big sort implies producing "runs" (which are pre-sorted
+sequences, which size is usually related to the amount of CPU memory),
+followed by a merging passes for these runs, which merging is often
+very cleverly organised[1]. It is very important that the initial
+sort produces the longest runs possible. Tournaments are a good way
+to that. If, using all the memory available to hold a tournament, you
+replace and percolate items that happen to fit the current run, you'll
+produce runs which are twice the size of the memory for random input,
+and much better for input fuzzily ordered.
+
+Moreover, if you output the 0'th item on disk and get an input which
+may not fit in the current tournament (because the value "wins" over
+the last output value), it cannot fit in the heap, so the size of the
+heap decreases. The freed memory could be cleverly reused immediately
+for progressively building a second heap, which grows at exactly the
+same rate the first heap is melting. When the first heap completely
+vanishes, you switch heaps and start a new run. Clever and quite
+effective!
+
+In a word, heaps are useful memory structures to know. I use them in
+a few applications, and I think it is good to keep a `heap' module
+around. :-)
+
+--------------------
+[1] The disk balancing algorithms which are current, nowadays, are
+more annoying than clever, and this is a consequence of the seeking
+capabilities of the disks. On devices which cannot seek, like big
+tape drives, the story was quite different, and one had to be very
+clever to ensure (far in advance) that each tape movement will be the
+most effective possible (that is, will best participate at
+"progressing" the merge). Some tapes were even able to read
+backwards, and this was also used to avoid the rewinding time.
+Believe me, real good tape sorts were quite spectacular to watch!
+From all times, sorting has always been a Great Art! :-)
+"""
+
+__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge',
+ 'nlargest', 'nsmallest', 'heappushpop']
+
+from itertools import islice, repeat, count, imap, izip, tee, chain
+from operator import itemgetter
+import bisect
+
+def heappush(heap, item):
+ """Push item onto heap, maintaining the heap invariant."""
+ heap.append(item)
+ _siftdown(heap, 0, len(heap)-1)
+
+def heappop(heap):
+ """Pop the smallest item off the heap, maintaining the heap invariant."""
+ lastelt = heap.pop() # raises appropriate IndexError if heap is empty
+ if heap:
+ returnitem = heap[0]
+ heap[0] = lastelt
+ _siftup(heap, 0)
+ else:
+ returnitem = lastelt
+ return returnitem
+
+def heapreplace(heap, item):
+ """Pop and return the current smallest value, and add the new item.
+
+ This is more efficient than heappop() followed by heappush(), and can be
+ more appropriate when using a fixed-size heap. Note that the value
+ returned may be larger than item! That constrains reasonable uses of
+ this routine unless written as part of a conditional replacement:
+
+ if item > heap[0]:
+ item = heapreplace(heap, item)
+ """
+ returnitem = heap[0] # raises appropriate IndexError if heap is empty
+ heap[0] = item
+ _siftup(heap, 0)
+ return returnitem
+
+def heappushpop(heap, item):
+ """Fast version of a heappush followed by a heappop."""
+ if heap and heap[0] < item:
+ item, heap[0] = heap[0], item
+ _siftup(heap, 0)
+ return item
+
+def heapify(x):
+ """Transform list into a heap, in-place, in O(len(heap)) time."""
+ n = len(x)
+ # Transform bottom-up. The largest index there's any point to looking at
+ # is the largest with a child index in-range, so must have 2*i + 1 < n,
+ # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so
+ # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is
+ # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.
+ for i in reversed(xrange(n//2)):
+ _siftup(x, i)
+
+def nlargest(n, iterable):
+ """Find the n largest elements in a dataset.
+
+ Equivalent to: sorted(iterable, reverse=True)[:n]
+ """
+ if n < 0: # for consistency with the c impl
+ return []
+ it = iter(iterable)
+ result = list(islice(it, n))
+ if not result:
+ return result
+ heapify(result)
+ _heappushpop = heappushpop
+ for elem in it:
+ _heappushpop(result, elem)
+ result.sort(reverse=True)
+ return result
+
+def nsmallest(n, iterable):
+ """Find the n smallest elements in a dataset.
+
+ Equivalent to: sorted(iterable)[:n]
+ """
+ if n < 0: # for consistency with the c impl
+ return []
+ if hasattr(iterable, '__len__') and n * 10 <= len(iterable):
+ # For smaller values of n, the bisect method is faster than a minheap.
+ # It is also memory efficient, consuming only n elements of space.
+ it = iter(iterable)
+ result = sorted(islice(it, 0, n))
+ if not result:
+ return result
+ insort = bisect.insort
+ pop = result.pop
+ los = result[-1] # los --> Largest of the nsmallest
+ for elem in it:
+ if los <= elem:
+ continue
+ insort(result, elem)
+ pop()
+ los = result[-1]
+ return result
+ # An alternative approach manifests the whole iterable in memory but
+ # saves comparisons by heapifying all at once. Also, saves time
+ # over bisect.insort() which has O(n) data movement time for every
+ # insertion. Finding the n smallest of an m length iterable requires
+ # O(m) + O(n log m) comparisons.
+ h = list(iterable)
+ heapify(h)
+ return map(heappop, repeat(h, min(n, len(h))))
+
+# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
+# is the index of a leaf with a possibly out-of-order value. Restore the
+# heap invariant.
+def _siftdown(heap, startpos, pos):
+ newitem = heap[pos]
+ # Follow the path to the root, moving parents down until finding a place
+ # newitem fits.
+ while pos > startpos:
+ parentpos = (pos - 1) >> 1
+ parent = heap[parentpos]
+ if newitem < parent:
+ heap[pos] = parent
+ pos = parentpos
+ continue
+ break
+ heap[pos] = newitem
+
+# The child indices of heap index pos are already heaps, and we want to make
+# a heap at index pos too. We do this by bubbling the smaller child of
+# pos up (and so on with that child's children, etc) until hitting a leaf,
+# then using _siftdown to move the oddball originally at index pos into place.
+#
+# We *could* break out of the loop as soon as we find a pos where newitem <=
+# both its children, but turns out that's not a good idea, and despite that
+# many books write the algorithm that way. During a heap pop, the last array
+# element is sifted in, and that tends to be large, so that comparing it
+# against values starting from the root usually doesn't pay (= usually doesn't
+# get us out of the loop early). See Knuth, Volume 3, where this is
+# explained and quantified in an exercise.
+#
+# Cutting the # of comparisons is important, since these routines have no
+# way to extract "the priority" from an array element, so that intelligence
+# is likely to be hiding in custom __cmp__ methods, or in array elements
+# storing (priority, record) tuples. Comparisons are thus potentially
+# expensive.
+#
+# On random arrays of length 1000, making this change cut the number of
+# comparisons made by heapify() a little, and those made by exhaustive
+# heappop() a lot, in accord with theory. Here are typical results from 3
+# runs (3 just to demonstrate how small the variance is):
+#
+# Compares needed by heapify Compares needed by 1000 heappops
+# -------------------------- --------------------------------
+# 1837 cut to 1663 14996 cut to 8680
+# 1855 cut to 1659 14966 cut to 8678
+# 1847 cut to 1660 15024 cut to 8703
+#
+# Building the heap by using heappush() 1000 times instead required
+# 2198, 2148, and 2219 compares: heapify() is more efficient, when
+# you can use it.
+#
+# The total compares needed by list.sort() on the same lists were 8627,
+# 8627, and 8632 (this should be compared to the sum of heapify() and
+# heappop() compares): list.sort() is (unsurprisingly!) more efficient
+# for sorting.
+
+def _siftup(heap, pos):
+ endpos = len(heap)
+ startpos = pos
+ newitem = heap[pos]
+ # Bubble up the smaller child until hitting a leaf.
+ childpos = 2*pos + 1 # leftmost child position
+ while childpos < endpos:
+ # Set childpos to index of smaller child.
+ rightpos = childpos + 1
+ if rightpos < endpos and not heap[childpos] < heap[rightpos]:
+ childpos = rightpos
+ # Move the smaller child up.
+ heap[pos] = heap[childpos]
+ pos = childpos
+ childpos = 2*pos + 1
+ # The leaf at pos is empty now. Put newitem there, and bubble it up
+ # to its final resting place (by sifting its parents down).
+ heap[pos] = newitem
+ _siftdown(heap, startpos, pos)
+
+# If available, use C implementation
+try:
+ from _heapq import *
+except ImportError:
+ pass
+
+def merge(*iterables):
+ '''Merge multiple sorted inputs into a single sorted output.
+
+ Similar to sorted(itertools.chain(*iterables)) but returns a generator,
+ does not pull the data into memory all at once, and assumes that each of
+ the input streams is already sorted (smallest to largest).
+
+ >>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
+ [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
+
+ '''
+ _heappop, _heapreplace, _StopIteration = heappop, heapreplace, StopIteration
+
+ h = []
+ h_append = h.append
+ for itnum, it in enumerate(map(iter, iterables)):
+ try:
+ next = it.next
+ h_append([next(), itnum, next])
+ except _StopIteration:
+ pass
+ heapify(h)
+
+ while 1:
+ try:
+ while 1:
+ v, itnum, next = s = h[0] # raises IndexError when h is empty
+ yield v
+ s[0] = next() # raises StopIteration when exhausted
+ _heapreplace(h, s) # restore heap condition
+ except _StopIteration:
+ _heappop(h) # remove empty iterator
+ except IndexError:
+ return
+
+# Extend the implementations of nsmallest and nlargest to use a key= argument
+_nsmallest = nsmallest
+def nsmallest(n, iterable, key=None):
+ """Find the n smallest elements in a dataset.
+
+ Equivalent to: sorted(iterable, key=key)[:n]
+ """
+ # Short-cut for n==1 is to use min() when len(iterable)>0
+ if n == 1:
+ it = iter(iterable)
+ head = list(islice(it, 1))
+ if not head:
+ return []
+ if key is None:
+ return [min(chain(head, it))]
+ return [min(chain(head, it), key=key)]
+
+ # When n>=size, it's faster to use sort()
+ try:
+ size = len(iterable)
+ except (TypeError, AttributeError):
+ pass
+ else:
+ if n >= size:
+ return sorted(iterable, key=key)[:n]
+
+ # When key is none, use simpler decoration
+ if key is None:
+ it = izip(iterable, count()) # decorate
+ result = _nsmallest(n, it)
+ return map(itemgetter(0), result) # undecorate
+
+ # General case, slowest method
+ in1, in2 = tee(iterable)
+ it = izip(imap(key, in1), count(), in2) # decorate
+ result = _nsmallest(n, it)
+ return map(itemgetter(2), result) # undecorate
+
+_nlargest = nlargest
+def nlargest(n, iterable, key=None):
+ """Find the n largest elements in a dataset.
+
+ Equivalent to: sorted(iterable, key=key, reverse=True)[:n]
+ """
+
+ # Short-cut for n==1 is to use max() when len(iterable)>0
+ if n == 1:
+ it = iter(iterable)
+ head = list(islice(it, 1))
+ if not head:
+ return []
+ if key is None:
+ return [max(chain(head, it))]
+ return [max(chain(head, it), key=key)]
+
+ # When n>=size, it's faster to use sort()
+ try:
+ size = len(iterable)
+ except (TypeError, AttributeError):
+ pass
+ else:
+ if n >= size:
+ return sorted(iterable, key=key, reverse=True)[:n]
+
+ # When key is none, use simpler decoration
+ if key is None:
+ it = izip(iterable, count(0,-1)) # decorate
+ result = _nlargest(n, it)
+ return map(itemgetter(0), result) # undecorate
+
+ # General case, slowest method
+ in1, in2 = tee(iterable)
+ it = izip(imap(key, in1), count(0,-1), in2) # decorate
+ result = _nlargest(n, it)
+ return map(itemgetter(2), result) # undecorate
+
+if __name__ == "__main__":
+ # Simple sanity test
+ heap = []
+ data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+ for item in data:
+ heappush(heap, item)
+ sort = []
+ while heap:
+ sort.append(heappop(heap))
+ print sort
+
+ import doctest
+ doctest.testmod()
diff --git a/lib-python/modified-2.7/json/encoder.py b/lib-python/modified-2.7/json/encoder.py
--- a/lib-python/modified-2.7/json/encoder.py
+++ b/lib-python/modified-2.7/json/encoder.py
@@ -2,14 +2,7 @@
"""
import re
-try:
- from _json import encode_basestring_ascii as c_encode_basestring_ascii
-except ImportError:
- c_encode_basestring_ascii = None
-try:
- from _json import make_encoder as c_make_encoder
-except ImportError:
- c_make_encoder = None
+from __pypy__.builders import StringBuilder, UnicodeBuilder
ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
@@ -24,8 +17,7 @@
'\t': '\\t',
}
for i in range(0x20):
- ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
- #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
+ ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
# Assume this produces an infinity on all machines (probably not guaranteed)
INFINITY = float('1e66666')
@@ -37,10 +29,9 @@
"""
def replace(match):
return ESCAPE_DCT[match.group(0)]
- return '"' + ESCAPE.sub(replace, s) + '"'
+ return ESCAPE.sub(replace, s)
-
-def py_encode_basestring_ascii(s):
+def encode_basestring_ascii(s):
"""Return an ASCII-only JSON representation of a Python string
"""
@@ -53,20 +44,18 @@
except KeyError:
n = ord(s)
if n < 0x10000:
- return '\\u{0:04x}'.format(n)
- #return '\\u%04x' % (n,)
+ return '\\u%04x' % (n,)
else:
# surrogate pair
n -= 0x10000
s1 = 0xd800 | ((n >> 10) & 0x3ff)
s2 = 0xdc00 | (n & 0x3ff)
- return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
- #return '\\u%04x\\u%04x' % (s1, s2)
- return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
-
-
-encode_basestring_ascii = (
- c_encode_basestring_ascii or py_encode_basestring_ascii)
+ return '\\u%04x\\u%04x' % (s1, s2)
+ if ESCAPE_ASCII.search(s):
+ return str(ESCAPE_ASCII.sub(replace, s))
+ return s
+py_encode_basestring_ascii = lambda s: '"' + encode_basestring_ascii(s) + '"'
+c_encode_basestring_ascii = None
class JSONEncoder(object):
"""Extensible JSON <http://json.org> encoder for Python data structures.
@@ -147,6 +136,17 @@
self.skipkeys = skipkeys
self.ensure_ascii = ensure_ascii
+ if ensure_ascii:
+ self.encoder = encode_basestring_ascii
+ else:
+ self.encoder = encode_basestring
+ if encoding != 'utf-8':
+ orig_encoder = self.encoder
+ def encoder(o):
+ if isinstance(o, str):
+ o = o.decode(encoding)
+ return orig_encoder(o)
+ self.encoder = encoder
self.check_circular = check_circular
self.allow_nan = allow_nan
self.sort_keys = sort_keys
@@ -184,24 +184,126 @@
'{"foo": ["bar", "baz"]}'
"""
- # This is for extremely simple cases and benchmarks.
+ if self.check_circular:
+ markers = {}
+ else:
+ markers = None
+ if self.ensure_ascii:
+ builder = StringBuilder()
+ else:
+ builder = UnicodeBuilder()
+ self._encode(o, markers, builder, 0)
+ return builder.build()
+
+ def _emit_indent(self, builder, _current_indent_level):
+ if self.indent is not None:
+ _current_indent_level += 1
+ newline_indent = '\n' + (' ' * (self.indent *
+ _current_indent_level))
+ separator = self.item_separator + newline_indent
+ builder.append(newline_indent)
+ else:
+ separator = self.item_separator
+ return separator, _current_indent_level
+
+ def _emit_unindent(self, builder, _current_indent_level):
+ if self.indent is not None:
+ builder.append('\n')
+ builder.append(' ' * (self.indent * (_current_indent_level - 1)))
+
+ def _encode(self, o, markers, builder, _current_indent_level):
if isinstance(o, basestring):
- if isinstance(o, str):
- _encoding = self.encoding
- if (_encoding is not None
- and not (_encoding == 'utf-8')):
- o = o.decode(_encoding)
- if self.ensure_ascii:
- return encode_basestring_ascii(o)
+ builder.append('"')
+ builder.append(self.encoder(o))
+ builder.append('"')
+ elif o is None:
+ builder.append('null')
+ elif o is True:
+ builder.append('true')
+ elif o is False:
+ builder.append('false')
+ elif isinstance(o, (int, long)):
+ builder.append(str(o))
+ elif isinstance(o, float):
+ builder.append(self._floatstr(o))
+ elif isinstance(o, (list, tuple)):
+ if not o:
+ builder.append('[]')
+ return
+ self._encode_list(o, markers, builder, _current_indent_level)
+ elif isinstance(o, dict):
+ if not o:
+ builder.append('{}')
+ return
+ self._encode_dict(o, markers, builder, _current_indent_level)
+ else:
+ self._mark_markers(markers, o)
+ res = self.default(o)
+ self._encode(res, markers, builder, _current_indent_level)
+ self._remove_markers(markers, o)
+ return res
+
+ def _encode_list(self, l, markers, builder, _current_indent_level):
+ self._mark_markers(markers, l)
+ builder.append('[')
+ first = True
+ separator, _current_indent_level = self._emit_indent(builder,
+ _current_indent_level)
+ for elem in l:
+ if first:
+ first = False
else:
- return encode_basestring(o)
- # This doesn't pass the iterator directly to ''.join() because the
- # exceptions aren't as detailed. The list call should be roughly
- # equivalent to the PySequence_Fast that ''.join() would do.
- chunks = self.iterencode(o, _one_shot=True)
- if not isinstance(chunks, (list, tuple)):
- chunks = list(chunks)
- return ''.join(chunks)
+ builder.append(separator)
+ self._encode(elem, markers, builder, _current_indent_level)
+ del elem # XXX grumble
+ self._emit_unindent(builder, _current_indent_level)
+ builder.append(']')
+ self._remove_markers(markers, l)
+
+ def _encode_dict(self, d, markers, builder, _current_indent_level):
+ self._mark_markers(markers, d)
+ first = True
+ builder.append('{')
+ separator, _current_indent_level = self._emit_indent(builder,
+ _current_indent_level)
+ if self.sort_keys:
+ items = sorted(d.items(), key=lambda kv: kv[0])
+ else:
+ items = d.iteritems()
+
+ for key, v in items:
+ if first:
+ first = False
+ else:
+ builder.append(separator)
+ if isinstance(key, basestring):
+ pass
+ # JavaScript is weakly typed for these, so it makes sense to
+ # also allow them. Many encoders seem to do something like this.
+ elif isinstance(key, float):
+ key = self._floatstr(key)
+ elif key is True:
+ key = 'true'
+ elif key is False:
+ key = 'false'
+ elif key is None:
+ key = 'null'
+ elif isinstance(key, (int, long)):
+ key = str(key)
+ elif self.skipkeys:
+ continue
+ else:
+ raise TypeError("key " + repr(key) + " is not a string")
+ builder.append('"')
+ builder.append(self.encoder(key))
+ builder.append('"')
+ builder.append(self.key_separator)
+ self._encode(v, markers, builder, _current_indent_level)
+ del key
+ del v # XXX grumble
+ self._emit_unindent(builder, _current_indent_level)
+ builder.append('}')
+ self._remove_markers(markers, d)
def iterencode(self, o, _one_shot=False):
"""Encode the given object and yield each string
@@ -217,86 +319,54 @@
markers = {}
else:
markers = None
- if self.ensure_ascii:
- _encoder = encode_basestring_ascii
+ return self._iterencode(o, markers, 0)
+
+ def _floatstr(self, o):
+ # Check for specials. Note that this type of test is processor
+ # and/or platform-specific, so do tests which don't depend on the
+ # internals.
+
+ if o != o:
+ text = 'NaN'
+ elif o == INFINITY:
+ text = 'Infinity'
+ elif o == -INFINITY:
+ text = '-Infinity'
else:
- _encoder = encode_basestring
- if self.encoding != 'utf-8':
- def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
- if isinstance(o, str):
- o = o.decode(_encoding)
- return _orig_encoder(o)
+ return FLOAT_REPR(o)
- def floatstr(o, allow_nan=self.allow_nan,
- _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
- # Check for specials. Note that this type of test is processor
- # and/or platform-specific, so do tests which don't depend on the
- # internals.
+ if not self.allow_nan:
+ raise ValueError(
+ "Out of range float values are not JSON compliant: " +
+ repr(o))
- if o != o:
- text = 'NaN'
- elif o == _inf:
- text = 'Infinity'
- elif o == _neginf:
- text = '-Infinity'
- else:
- return _repr(o)
+ return text
- if not allow_nan:
- raise ValueError(
- "Out of range float values are not JSON compliant: " +
- repr(o))
+ def _mark_markers(self, markers, o):
+ if markers is not None:
+ if id(o) in markers:
+ raise ValueError("Circular reference detected")
+ markers[id(o)] = None
- return text
+ def _remove_markers(self, markers, o):
+ if markers is not None:
+ del markers[id(o)]
-
- if (_one_shot and c_make_encoder is not None
- and not self.indent and not self.sort_keys):
- _iterencode = c_make_encoder(
- markers, self.default, _encoder, self.indent,
- self.key_separator, self.item_separator, self.sort_keys,
- self.skipkeys, self.allow_nan)
- else:
- _iterencode = _make_iterencode(
- markers, self.default, _encoder, self.indent, floatstr,
- self.key_separator, self.item_separator, self.sort_keys,
- self.skipkeys, _one_shot)
- return _iterencode(o, 0)
-
-def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
- _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
- ## HACK: hand-optimized bytecode; turn globals into locals
- ValueError=ValueError,
- basestring=basestring,
- dict=dict,
- float=float,
- id=id,
- int=int,
- isinstance=isinstance,
- list=list,
- long=long,
- str=str,
- tuple=tuple,
- ):
-
- def _iterencode_list(lst, _current_indent_level):
+ def _iterencode_list(self, lst, markers, _current_indent_level):
if not lst:
yield '[]'
return
- if markers is not None:
- markerid = id(lst)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = lst
+ self._mark_markers(markers, lst)
buf = '['
- if _indent is not None:
+ if self.indent is not None:
_current_indent_level += 1
- newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
- separator = _item_separator + newline_indent
+ newline_indent = '\n' + (' ' * (self.indent *
+ _current_indent_level))
+ separator = self.item_separator + newline_indent
buf += newline_indent
else:
newline_indent = None
- separator = _item_separator
+ separator = self.item_separator
first = True
for value in lst:
if first:
@@ -304,7 +374,7 @@
else:
buf = separator
if isinstance(value, basestring):
- yield buf + _encoder(value)
+ yield buf + '"' + self.encoder(value) + '"'
elif value is None:
yield buf + 'null'
elif value is True:
@@ -314,44 +384,43 @@
elif isinstance(value, (int, long)):
yield buf + str(value)
elif isinstance(value, float):
- yield buf + _floatstr(value)
+ yield buf + self._floatstr(value)
else:
yield buf
if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
+ chunks = self._iterencode_list(value, markers,
+ _current_indent_level)
elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
+ chunks = self._iterencode_dict(value, markers,
+ _current_indent_level)
else:
- chunks = _iterencode(value, _current_indent_level)
+ chunks = self._iterencode(value, markers,
+ _current_indent_level)
for chunk in chunks:
yield chunk
if newline_indent is not None:
_current_indent_level -= 1
- yield '\n' + (' ' * (_indent * _current_indent_level))
+ yield '\n' + (' ' * (self.indent * _current_indent_level))
yield ']'
- if markers is not None:
- del markers[markerid]
+ self._remove_markers(markers, lst)
- def _iterencode_dict(dct, _current_indent_level):
+ def _iterencode_dict(self, dct, markers, _current_indent_level):
if not dct:
yield '{}'
return
- if markers is not None:
- markerid = id(dct)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = dct
+ self._mark_markers(markers, dct)
yield '{'
- if _indent is not None:
+ if self.indent is not None:
_current_indent_level += 1
- newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
- item_separator = _item_separator + newline_indent
+ newline_indent = '\n' + (' ' * (self.indent *
+ _current_indent_level))
+ item_separator = self.item_separator + newline_indent
yield newline_indent
else:
newline_indent = None
- item_separator = _item_separator
+ item_separator = self.item_separator
first = True
- if _sort_keys:
+ if self.sort_keys:
items = sorted(dct.items(), key=lambda kv: kv[0])
else:
items = dct.iteritems()
@@ -361,7 +430,7 @@
# JavaScript is weakly typed for these, so it makes sense to
# also allow them. Many encoders seem to do something like this.
elif isinstance(key, float):
- key = _floatstr(key)
+ key = self._floatstr(key)
elif key is True:
key = 'true'
elif key is False:
@@ -370,7 +439,7 @@
key = 'null'
elif isinstance(key, (int, long)):
key = str(key)
- elif _skipkeys:
+ elif self.skipkeys:
continue
else:
raise TypeError("key " + repr(key) + " is not a string")
@@ -378,10 +447,10 @@
first = False
else:
yield item_separator
- yield _encoder(key)
- yield _key_separator
+ yield '"' + self.encoder(key) + '"'
+ yield self.key_separator
if isinstance(value, basestring):
- yield _encoder(value)
+ yield '"' + self.encoder(value) + '"'
elif value is None:
yield 'null'
elif value is True:
@@ -391,26 +460,28 @@
elif isinstance(value, (int, long)):
yield str(value)
elif isinstance(value, float):
- yield _floatstr(value)
+ yield self._floatstr(value)
else:
if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
+ chunks = self._iterencode_list(value, markers,
+ _current_indent_level)
elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
+ chunks = self._iterencode_dict(value, markers,
+ _current_indent_level)
else:
- chunks = _iterencode(value, _current_indent_level)
+ chunks = self._iterencode(value, markers,
+ _current_indent_level)
for chunk in chunks:
yield chunk
if newline_indent is not None:
_current_indent_level -= 1
- yield '\n' + (' ' * (_indent * _current_indent_level))
+ yield '\n' + (' ' * (self.indent * _current_indent_level))
yield '}'
- if markers is not None:
- del markers[markerid]
+ self._remove_markers(markers, dct)
- def _iterencode(o, _current_indent_level):
+ def _iterencode(self, o, markers, _current_indent_level):
if isinstance(o, basestring):
- yield _encoder(o)
+ yield '"' + self.encoder(o) + '"'
elif o is None:
yield 'null'
elif o is True:
@@ -420,23 +491,19 @@
elif isinstance(o, (int, long)):
yield str(o)
elif isinstance(o, float):
- yield _floatstr(o)
+ yield self._floatstr(o)
elif isinstance(o, (list, tuple)):
- for chunk in _iterencode_list(o, _current_indent_level):
+ for chunk in self._iterencode_list(o, markers,
+ _current_indent_level):
yield chunk
elif isinstance(o, dict):
- for chunk in _iterencode_dict(o, _current_indent_level):
+ for chunk in self._iterencode_dict(o, markers,
+ _current_indent_level):
yield chunk
else:
- if markers is not None:
- markerid = id(o)
- if markerid in markers:
- raise ValueError("Circular reference detected")
- markers[markerid] = o
- o = _default(o)
- for chunk in _iterencode(o, _current_indent_level):
+ self._mark_markers(markers, o)
+ obj = self.default(o)
+ for chunk in self._iterencode(obj, markers,
+ _current_indent_level):
yield chunk
- if markers is not None:
- del markers[markerid]
-
- return _iterencode
+ self._remove_markers(markers, o)
diff --git a/lib-python/modified-2.7/json/tests/test_unicode.py b/lib-python/modified-2.7/json/tests/test_unicode.py
--- a/lib-python/modified-2.7/json/tests/test_unicode.py
+++ b/lib-python/modified-2.7/json/tests/test_unicode.py
@@ -80,3 +80,9 @@
self.assertEqual(type(json.loads(u'["a"]')[0]), unicode)
# Issue 10038.
self.assertEqual(type(json.loads('"foo"')), unicode)
+
+ def test_encode_not_utf_8(self):
+ self.assertEqual(json.dumps('\xb1\xe6', encoding='iso8859-2'),
+ '"\\u0105\\u0107"')
+ self.assertEqual(json.dumps(['\xb1\xe6'], encoding='iso8859-2'),
+ '["\\u0105\\u0107"]')
diff --git a/lib-python/modified-2.7/test/test_heapq.py b/lib-python/modified-2.7/test/test_heapq.py
--- a/lib-python/modified-2.7/test/test_heapq.py
+++ b/lib-python/modified-2.7/test/test_heapq.py
@@ -186,6 +186,11 @@
self.assertFalse(sys.modules['heapq'] is self.module)
self.assertTrue(hasattr(self.module.heapify, 'func_code'))
+ def test_islice_protection(self):
+ m = self.module
+ self.assertFalse(m.nsmallest(-1, [1]))
+ self.assertFalse(m.nlargest(-1, [1]))
+
class TestHeapC(TestHeap):
module = c_heapq
diff --git a/lib-python/modified-2.7/urllib2.py b/lib-python/modified-2.7/urllib2.py
--- a/lib-python/modified-2.7/urllib2.py
+++ b/lib-python/modified-2.7/urllib2.py
@@ -395,11 +395,7 @@
meth_name = protocol+"_response"
for processor in self.process_response.get(protocol, []):
meth = getattr(processor, meth_name)
- try:
- response = meth(req, response)
- except:
- response.close()
- raise
+ response = meth(req, response)
return response
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -395,9 +395,21 @@
_wrapper.f_in = f_in
_wrapper.f_out = f_out
- if hasattr(sys, '__raw_input__'): # PyPy
- _old_raw_input = sys.__raw_input__
+ if '__pypy__' in sys.builtin_module_names: # PyPy
+
+ def _old_raw_input(prompt=''):
+ # sys.__raw_input__() is only called when stdin and stdout are
+ # as expected and are ttys. If it is the case, then get_reader()
+ # should not really fail in _wrapper.raw_input(). If it still
+ # does, then we will just cancel the redirection and call again
+ # the built-in raw_input().
+ try:
+ del sys.__raw_input__
+ except AttributeError:
+ pass
+ return raw_input(prompt)
sys.__raw_input__ = _wrapper.raw_input
+
else:
# this is not really what readline.c does. Better than nothing I guess
import __builtin__
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -72,6 +72,7 @@
del working_modules['fcntl'] # LOCK_NB not defined
del working_modules["_minimal_curses"]
del working_modules["termios"]
+ del working_modules["_multiprocessing"] # depends on rctime
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -17,6 +17,12 @@
projects, or anything else in PyPy, pop up on IRC or write to us on the
`mailing list`_.
+Make big integers faster
+-------------------------
+
+PyPy's implementation of the Python ``long`` type is slower than CPython's.
+Find out why and optimize them.
+
Numpy improvements
------------------
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -2,7 +2,7 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter import typedef
from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.rlib.unroll import unrolling_iterable
from pypy.tool.pairtype import extendabletype
from pypy.tool.sourcetools import func_with_new_name
@@ -2925,14 +2925,13 @@
def Module_get_body(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -2968,14 +2967,13 @@
def Interactive_get_body(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3015,8 +3013,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
return space.wrap(w_self.body)
def Expression_set_body(space, w_self, w_new_value):
@@ -3057,14 +3054,13 @@
def Suite_get_body(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3104,8 +3100,7 @@
return w_obj
if not w_self.initialization_state & w_self._lineno_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
return space.wrap(w_self.lineno)
def stmt_set_lineno(space, w_self, w_new_value):
@@ -3126,8 +3121,7 @@
return w_obj
if not w_self.initialization_state & w_self._col_offset_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
return space.wrap(w_self.col_offset)
def stmt_set_col_offset(space, w_self, w_new_value):
@@ -3157,8 +3151,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
return space.wrap(w_self.name)
def FunctionDef_set_name(space, w_self, w_new_value):
@@ -3179,8 +3172,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
return space.wrap(w_self.args)
def FunctionDef_set_args(space, w_self, w_new_value):
@@ -3197,14 +3189,13 @@
def FunctionDef_get_body(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3215,14 +3206,13 @@
def FunctionDef_get_decorator_list(space, w_self):
if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'decorator_list'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list')
if w_self.w_decorator_list is None:
if w_self.decorator_list is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.decorator_list]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_decorator_list = w_list
return w_self.w_decorator_list
@@ -3266,8 +3256,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
return space.wrap(w_self.name)
def ClassDef_set_name(space, w_self, w_new_value):
@@ -3284,14 +3273,13 @@
def ClassDef_get_bases(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'bases'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'bases')
if w_self.w_bases is None:
if w_self.bases is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.bases]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_bases = w_list
return w_self.w_bases
@@ -3302,14 +3290,13 @@
def ClassDef_get_body(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3320,14 +3307,13 @@
def ClassDef_get_decorator_list(space, w_self):
if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'decorator_list'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list')
if w_self.w_decorator_list is None:
if w_self.decorator_list is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.decorator_list]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_decorator_list = w_list
return w_self.w_decorator_list
@@ -3372,8 +3358,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Return_set_value(space, w_self, w_new_value):
@@ -3414,14 +3399,13 @@
def Delete_get_targets(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'targets'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets')
if w_self.w_targets is None:
if w_self.targets is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.targets]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_targets = w_list
return w_self.w_targets
@@ -3457,14 +3441,13 @@
def Assign_get_targets(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'targets'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets')
if w_self.w_targets is None:
if w_self.targets is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.targets]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_targets = w_list
return w_self.w_targets
@@ -3479,8 +3462,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Assign_set_value(space, w_self, w_new_value):
@@ -3527,8 +3509,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
return space.wrap(w_self.target)
def AugAssign_set_target(space, w_self, w_new_value):
@@ -3549,8 +3530,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
return operator_to_class[w_self.op - 1]()
def AugAssign_set_op(space, w_self, w_new_value):
@@ -3573,8 +3553,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def AugAssign_set_value(space, w_self, w_new_value):
@@ -3621,8 +3600,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'dest'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dest')
return space.wrap(w_self.dest)
def Print_set_dest(space, w_self, w_new_value):
@@ -3639,14 +3617,13 @@
def Print_get_values(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
if w_self.w_values is None:
if w_self.values is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.values]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_values = w_list
return w_self.w_values
@@ -3661,8 +3638,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'nl'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'nl')
return space.wrap(w_self.nl)
def Print_set_nl(space, w_self, w_new_value):
@@ -3710,8 +3686,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
return space.wrap(w_self.target)
def For_set_target(space, w_self, w_new_value):
@@ -3732,8 +3707,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'iter'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter')
return space.wrap(w_self.iter)
def For_set_iter(space, w_self, w_new_value):
@@ -3750,14 +3724,13 @@
def For_get_body(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3768,14 +3741,13 @@
def For_get_orelse(space, w_self):
if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
if w_self.w_orelse is None:
if w_self.orelse is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.orelse]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_orelse = w_list
return w_self.w_orelse
@@ -3819,8 +3791,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
return space.wrap(w_self.test)
def While_set_test(space, w_self, w_new_value):
@@ -3837,14 +3808,13 @@
def While_get_body(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3855,14 +3825,13 @@
def While_get_orelse(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
if w_self.w_orelse is None:
if w_self.orelse is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.orelse]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_orelse = w_list
return w_self.w_orelse
@@ -3905,8 +3874,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
return space.wrap(w_self.test)
def If_set_test(space, w_self, w_new_value):
@@ -3923,14 +3891,13 @@
def If_get_body(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -3941,14 +3908,13 @@
def If_get_orelse(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
if w_self.w_orelse is None:
if w_self.orelse is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.orelse]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_orelse = w_list
return w_self.w_orelse
@@ -3991,8 +3957,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'context_expr'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'context_expr')
return space.wrap(w_self.context_expr)
def With_set_context_expr(space, w_self, w_new_value):
@@ -4013,8 +3978,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'optional_vars'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'optional_vars')
return space.wrap(w_self.optional_vars)
def With_set_optional_vars(space, w_self, w_new_value):
@@ -4031,14 +3995,13 @@
def With_get_body(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -4080,8 +4043,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'type'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type')
return space.wrap(w_self.type)
def Raise_set_type(space, w_self, w_new_value):
@@ -4102,8 +4064,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'inst'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'inst')
return space.wrap(w_self.inst)
def Raise_set_inst(space, w_self, w_new_value):
@@ -4124,8 +4085,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'tback'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'tback')
return space.wrap(w_self.tback)
def Raise_set_tback(space, w_self, w_new_value):
@@ -4168,14 +4128,13 @@
def TryExcept_get_body(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -4186,14 +4145,13 @@
def TryExcept_get_handlers(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'handlers'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'handlers')
if w_self.w_handlers is None:
if w_self.handlers is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.handlers]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_handlers = w_list
return w_self.w_handlers
@@ -4204,14 +4162,13 @@
def TryExcept_get_orelse(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
if w_self.w_orelse is None:
if w_self.orelse is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.orelse]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_orelse = w_list
return w_self.w_orelse
@@ -4251,14 +4208,13 @@
def TryFinally_get_body(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -4269,14 +4225,13 @@
def TryFinally_get_finalbody(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'finalbody'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'finalbody')
if w_self.w_finalbody is None:
if w_self.finalbody is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.finalbody]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_finalbody = w_list
return w_self.w_finalbody
@@ -4318,8 +4273,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
return space.wrap(w_self.test)
def Assert_set_test(space, w_self, w_new_value):
@@ -4340,8 +4294,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'msg'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'msg')
return space.wrap(w_self.msg)
def Assert_set_msg(space, w_self, w_new_value):
@@ -4383,14 +4336,13 @@
def Import_get_names(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
if w_self.w_names is None:
if w_self.names is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.names]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_names = w_list
return w_self.w_names
@@ -4430,8 +4382,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'module'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'module')
return space.wrap(w_self.module)
def ImportFrom_set_module(space, w_self, w_new_value):
@@ -4451,14 +4402,13 @@
def ImportFrom_get_names(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
if w_self.w_names is None:
if w_self.names is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.names]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_names = w_list
return w_self.w_names
@@ -4473,8 +4423,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'level'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'level')
return space.wrap(w_self.level)
def ImportFrom_set_level(space, w_self, w_new_value):
@@ -4522,8 +4471,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
return space.wrap(w_self.body)
def Exec_set_body(space, w_self, w_new_value):
@@ -4544,8 +4492,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'globals'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'globals')
return space.wrap(w_self.globals)
def Exec_set_globals(space, w_self, w_new_value):
@@ -4566,8 +4513,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'locals'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'locals')
return space.wrap(w_self.locals)
def Exec_set_locals(space, w_self, w_new_value):
@@ -4610,14 +4556,13 @@
def Global_get_names(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
if w_self.w_names is None:
if w_self.names is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.names]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_names = w_list
return w_self.w_names
@@ -4657,8 +4602,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Expr_set_value(space, w_self, w_new_value):
@@ -4754,8 +4698,7 @@
return w_obj
if not w_self.initialization_state & w_self._lineno_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
return space.wrap(w_self.lineno)
def expr_set_lineno(space, w_self, w_new_value):
@@ -4776,8 +4719,7 @@
return w_obj
if not w_self.initialization_state & w_self._col_offset_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
return space.wrap(w_self.col_offset)
def expr_set_col_offset(space, w_self, w_new_value):
@@ -4807,8 +4749,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
return boolop_to_class[w_self.op - 1]()
def BoolOp_set_op(space, w_self, w_new_value):
@@ -4827,14 +4768,13 @@
def BoolOp_get_values(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
if w_self.w_values is None:
if w_self.values is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.values]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_values = w_list
return w_self.w_values
@@ -4875,8 +4815,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'left'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left')
return space.wrap(w_self.left)
def BinOp_set_left(space, w_self, w_new_value):
@@ -4897,8 +4836,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
return operator_to_class[w_self.op - 1]()
def BinOp_set_op(space, w_self, w_new_value):
@@ -4921,8 +4859,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'right'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'right')
return space.wrap(w_self.right)
def BinOp_set_right(space, w_self, w_new_value):
@@ -4969,8 +4906,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
return unaryop_to_class[w_self.op - 1]()
def UnaryOp_set_op(space, w_self, w_new_value):
@@ -4993,8 +4929,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'operand'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'operand')
return space.wrap(w_self.operand)
def UnaryOp_set_operand(space, w_self, w_new_value):
@@ -5040,8 +4975,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
return space.wrap(w_self.args)
def Lambda_set_args(space, w_self, w_new_value):
@@ -5062,8 +4996,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
return space.wrap(w_self.body)
def Lambda_set_body(space, w_self, w_new_value):
@@ -5109,8 +5042,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
return space.wrap(w_self.test)
def IfExp_set_test(space, w_self, w_new_value):
@@ -5131,8 +5063,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
return space.wrap(w_self.body)
def IfExp_set_body(space, w_self, w_new_value):
@@ -5153,8 +5084,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
return space.wrap(w_self.orelse)
def IfExp_set_orelse(space, w_self, w_new_value):
@@ -5197,14 +5127,13 @@
def Dict_get_keys(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'keys'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keys')
if w_self.w_keys is None:
if w_self.keys is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.keys]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_keys = w_list
return w_self.w_keys
@@ -5215,14 +5144,13 @@
def Dict_get_values(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
if w_self.w_values is None:
if w_self.values is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.values]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_values = w_list
return w_self.w_values
@@ -5260,14 +5188,13 @@
def Set_get_elts(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
if w_self.w_elts is None:
if w_self.elts is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.elts]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_elts = w_list
return w_self.w_elts
@@ -5307,8 +5234,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
return space.wrap(w_self.elt)
def ListComp_set_elt(space, w_self, w_new_value):
@@ -5325,14 +5251,13 @@
def ListComp_get_generators(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
if w_self.w_generators is None:
if w_self.generators is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.generators]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_generators = w_list
return w_self.w_generators
@@ -5373,8 +5298,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
return space.wrap(w_self.elt)
def SetComp_set_elt(space, w_self, w_new_value):
@@ -5391,14 +5315,13 @@
def SetComp_get_generators(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
if w_self.w_generators is None:
if w_self.generators is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.generators]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_generators = w_list
return w_self.w_generators
@@ -5439,8 +5362,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'key'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'key')
return space.wrap(w_self.key)
def DictComp_set_key(space, w_self, w_new_value):
@@ -5461,8 +5383,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def DictComp_set_value(space, w_self, w_new_value):
@@ -5479,14 +5400,13 @@
def DictComp_get_generators(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
if w_self.w_generators is None:
if w_self.generators is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.generators]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_generators = w_list
return w_self.w_generators
@@ -5528,8 +5448,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
return space.wrap(w_self.elt)
def GeneratorExp_set_elt(space, w_self, w_new_value):
@@ -5546,14 +5465,13 @@
def GeneratorExp_get_generators(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
if w_self.w_generators is None:
if w_self.generators is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.generators]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_generators = w_list
return w_self.w_generators
@@ -5594,8 +5512,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Yield_set_value(space, w_self, w_new_value):
@@ -5640,8 +5557,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'left'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left')
return space.wrap(w_self.left)
def Compare_set_left(space, w_self, w_new_value):
@@ -5658,14 +5574,13 @@
def Compare_get_ops(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ops'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ops')
if w_self.w_ops is None:
if w_self.ops is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [cmpop_to_class[node - 1]() for node in w_self.ops]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_ops = w_list
return w_self.w_ops
@@ -5676,14 +5591,13 @@
def Compare_get_comparators(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'comparators'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'comparators')
if w_self.w_comparators is None:
if w_self.comparators is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.comparators]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_comparators = w_list
return w_self.w_comparators
@@ -5726,8 +5640,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'func'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'func')
return space.wrap(w_self.func)
def Call_set_func(space, w_self, w_new_value):
@@ -5744,14 +5657,13 @@
def Call_get_args(space, w_self):
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
if w_self.w_args is None:
if w_self.args is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.args]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_args = w_list
return w_self.w_args
@@ -5762,14 +5674,13 @@
def Call_get_keywords(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'keywords'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords')
if w_self.w_keywords is None:
if w_self.keywords is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.keywords]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_keywords = w_list
return w_self.w_keywords
@@ -5784,8 +5695,7 @@
return w_obj
if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'starargs'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs')
return space.wrap(w_self.starargs)
def Call_set_starargs(space, w_self, w_new_value):
@@ -5806,8 +5716,7 @@
return w_obj
if not w_self.initialization_state & 16:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'kwargs'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs')
return space.wrap(w_self.kwargs)
def Call_set_kwargs(space, w_self, w_new_value):
@@ -5858,8 +5767,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Repr_set_value(space, w_self, w_new_value):
@@ -5904,8 +5812,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'n'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'n')
return w_self.n
def Num_set_n(space, w_self, w_new_value):
@@ -5950,8 +5857,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 's'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's')
return w_self.s
def Str_set_s(space, w_self, w_new_value):
@@ -5996,8 +5902,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Attribute_set_value(space, w_self, w_new_value):
@@ -6018,8 +5923,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'attr'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'attr')
return space.wrap(w_self.attr)
def Attribute_set_attr(space, w_self, w_new_value):
@@ -6040,8 +5944,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
return expr_context_to_class[w_self.ctx - 1]()
def Attribute_set_ctx(space, w_self, w_new_value):
@@ -6090,8 +5993,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Subscript_set_value(space, w_self, w_new_value):
@@ -6112,8 +6014,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'slice'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'slice')
return space.wrap(w_self.slice)
def Subscript_set_slice(space, w_self, w_new_value):
@@ -6134,8 +6035,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
return expr_context_to_class[w_self.ctx - 1]()
def Subscript_set_ctx(space, w_self, w_new_value):
@@ -6184,8 +6084,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'id'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'id')
return space.wrap(w_self.id)
def Name_set_id(space, w_self, w_new_value):
@@ -6206,8 +6105,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
return expr_context_to_class[w_self.ctx - 1]()
def Name_set_ctx(space, w_self, w_new_value):
@@ -6251,14 +6149,13 @@
def List_get_elts(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
if w_self.w_elts is None:
if w_self.elts is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.elts]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_elts = w_list
return w_self.w_elts
@@ -6273,8 +6170,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
return expr_context_to_class[w_self.ctx - 1]()
def List_set_ctx(space, w_self, w_new_value):
@@ -6319,14 +6215,13 @@
def Tuple_get_elts(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
if w_self.w_elts is None:
if w_self.elts is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.elts]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_elts = w_list
return w_self.w_elts
@@ -6341,8 +6236,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
return expr_context_to_class[w_self.ctx - 1]()
def Tuple_set_ctx(space, w_self, w_new_value):
@@ -6391,8 +6285,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return w_self.value
def Const_set_value(space, w_self, w_new_value):
@@ -6510,8 +6403,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'lower'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lower')
return space.wrap(w_self.lower)
def Slice_set_lower(space, w_self, w_new_value):
@@ -6532,8 +6424,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'upper'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'upper')
return space.wrap(w_self.upper)
def Slice_set_upper(space, w_self, w_new_value):
@@ -6554,8 +6445,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'step'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'step')
return space.wrap(w_self.step)
def Slice_set_step(space, w_self, w_new_value):
@@ -6598,14 +6488,13 @@
def ExtSlice_get_dims(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'dims'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dims')
if w_self.w_dims is None:
if w_self.dims is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.dims]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_dims = w_list
return w_self.w_dims
@@ -6645,8 +6534,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def Index_set_value(space, w_self, w_new_value):
@@ -6915,8 +6803,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
return space.wrap(w_self.target)
def comprehension_set_target(space, w_self, w_new_value):
@@ -6937,8 +6824,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'iter'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter')
return space.wrap(w_self.iter)
def comprehension_set_iter(space, w_self, w_new_value):
@@ -6955,14 +6841,13 @@
def comprehension_get_ifs(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'ifs'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ifs')
if w_self.w_ifs is None:
if w_self.ifs is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.ifs]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_ifs = w_list
return w_self.w_ifs
@@ -7004,8 +6889,7 @@
return w_obj
if not w_self.initialization_state & w_self._lineno_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
return space.wrap(w_self.lineno)
def excepthandler_set_lineno(space, w_self, w_new_value):
@@ -7026,8 +6910,7 @@
return w_obj
if not w_self.initialization_state & w_self._col_offset_mask:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
return space.wrap(w_self.col_offset)
def excepthandler_set_col_offset(space, w_self, w_new_value):
@@ -7057,8 +6940,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'type'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type')
return space.wrap(w_self.type)
def ExceptHandler_set_type(space, w_self, w_new_value):
@@ -7079,8 +6961,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
return space.wrap(w_self.name)
def ExceptHandler_set_name(space, w_self, w_new_value):
@@ -7097,14 +6978,13 @@
def ExceptHandler_get_body(space, w_self):
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
if w_self.w_body is None:
if w_self.body is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.body]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_body = w_list
return w_self.w_body
@@ -7142,14 +7022,13 @@
def arguments_get_args(space, w_self):
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
if w_self.w_args is None:
if w_self.args is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.args]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_args = w_list
return w_self.w_args
@@ -7164,8 +7043,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'vararg'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'vararg')
return space.wrap(w_self.vararg)
def arguments_set_vararg(space, w_self, w_new_value):
@@ -7189,8 +7067,7 @@
return w_obj
if not w_self.initialization_state & 4:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'kwarg'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg')
return space.wrap(w_self.kwarg)
def arguments_set_kwarg(space, w_self, w_new_value):
@@ -7210,14 +7087,13 @@
def arguments_get_defaults(space, w_self):
if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'defaults'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults')
if w_self.w_defaults is None:
if w_self.defaults is None:
- w_list = space.newlist([])
+ list_w = []
else:
list_w = [space.wrap(node) for node in w_self.defaults]
- w_list = space.newlist(list_w)
+ w_list = space.newlist(list_w)
w_self.w_defaults = w_list
return w_self.w_defaults
@@ -7261,8 +7137,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'arg'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg')
return space.wrap(w_self.arg)
def keyword_set_arg(space, w_self, w_new_value):
@@ -7283,8 +7158,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
return space.wrap(w_self.value)
def keyword_set_value(space, w_self, w_new_value):
@@ -7330,8 +7204,7 @@
return w_obj
if not w_self.initialization_state & 1:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
return space.wrap(w_self.name)
def alias_set_name(space, w_self, w_new_value):
@@ -7352,8 +7225,7 @@
return w_obj
if not w_self.initialization_state & 2:
typename = space.type(w_self).getname(space)
- w_err = space.wrap("'%s' object has no attribute 'asname'" % typename)
- raise OperationError(space.w_AttributeError, w_err)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'asname')
return space.wrap(w_self.asname)
def alias_set_asname(space, w_self, w_new_value):
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -414,13 +414,12 @@
self.emit(" return w_obj", 1)
self.emit("if not w_self.initialization_state & %s:" % (flag,), 1)
self.emit("typename = space.type(w_self).getname(space)", 2)
- self.emit("w_err = space.wrap(\"'%%s' object has no attribute '%s'\" %% typename)" %
+ self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%s' object has no attribute '%%s'\", typename, '%s')" %
(field.name,), 2)
- self.emit("raise OperationError(space.w_AttributeError, w_err)", 2)
if field.seq:
self.emit("if w_self.w_%s is None:" % (field.name,), 1)
self.emit("if w_self.%s is None:" % (field.name,), 2)
- self.emit("w_list = space.newlist([])", 3)
+ self.emit("list_w = []", 3)
self.emit("else:", 2)
if field.type.value in self.data.simple_types:
wrapper = "%s_to_class[node - 1]()" % (field.type,)
@@ -428,7 +427,7 @@
wrapper = "space.wrap(node)"
self.emit("list_w = [%s for node in w_self.%s]" %
(wrapper, field.name), 3)
- self.emit("w_list = space.newlist(list_w)", 3)
+ self.emit("w_list = space.newlist(list_w)", 2)
self.emit("w_self.w_%s = w_list" % (field.name,), 2)
self.emit("return w_self.w_%s" % (field.name,), 1)
elif field.type.value in self.data.simple_types:
@@ -540,7 +539,7 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter import typedef
from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.rlib.unroll import unrolling_iterable
from pypy.tool.pairtype import extendabletype
from pypy.tool.sourcetools import func_with_new_name
@@ -639,9 +638,7 @@
missing = required[i]
if missing is not None:
err = "required field \\"%s\\" missing from %s"
- err = err % (missing, host)
- w_err = space.wrap(err)
- raise OperationError(space.w_TypeError, w_err)
+ raise operationerrfmt(space.w_TypeError, err, missing, host)
raise AssertionError("should not reach here")
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -391,8 +391,11 @@
def decrement_ticker(self, by):
value = self._ticker
if self.has_bytecode_counter: # this 'if' is constant-folded
- value -= by
- self._ticker = value
+ if jit.isconstant(by) and by == 0:
+ pass # normally constant-folded too
+ else:
+ value -= by
+ self._ticker = value
return value
diff --git a/pypy/interpreter/pyparser/pytokenizer.py b/pypy/interpreter/pyparser/pytokenizer.py
--- a/pypy/interpreter/pyparser/pytokenizer.py
+++ b/pypy/interpreter/pyparser/pytokenizer.py
@@ -226,7 +226,7 @@
parenlev = parenlev - 1
if parenlev < 0:
raise TokenError("unmatched '%s'" % initial, line,
- lnum-1, 0, token_list)
+ lnum, start + 1, token_list)
if token in python_opmap:
punct = python_opmap[token]
else:
diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py
--- a/pypy/interpreter/pyparser/test/test_pyparse.py
+++ b/pypy/interpreter/pyparser/test/test_pyparse.py
@@ -87,6 +87,10 @@
assert exc.lineno == 1
assert exc.offset == 5
assert exc.lastlineno == 5
+ exc = py.test.raises(SyntaxError, parse, "abc)").value
+ assert exc.msg == "unmatched ')'"
+ assert exc.lineno == 1
+ assert exc.offset == 4
def test_is(self):
self.parse("x is y")
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -7,9 +7,7 @@
import weakref
from pypy.objspace.flow.model import Variable, Constant
from pypy.annotation import model as annmodel
-from pypy.jit.metainterp.history import (ConstInt, ConstPtr,
- BoxInt, BoxPtr, BoxObj, BoxFloat,
- REF, INT, FLOAT)
+from pypy.jit.metainterp.history import REF, INT, FLOAT
from pypy.jit.codewriter import heaptracker
from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rffi
from pypy.rpython.ootypesystem import ootype
@@ -17,7 +15,7 @@
from pypy.rpython.llinterp import LLException
from pypy.rpython.extregistry import ExtRegistryEntry
-from pypy.jit.metainterp import resoperation, executor
+from pypy.jit.metainterp import resoperation
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend.llgraph import symbolic
from pypy.jit.codewriter import longlong
@@ -165,6 +163,7 @@
'unicodegetitem' : (('ref', 'int'), 'int'),
'unicodesetitem' : (('ref', 'int', 'int'), 'int'),
'cast_ptr_to_int' : (('ref',), 'int'),
+ 'cast_int_to_ptr' : (('int',), 'ref'),
'debug_merge_point': (('ref', 'int'), None),
'force_token' : ((), 'int'),
'call_may_force' : (('int', 'varargs'), 'intorptr'),
@@ -333,6 +332,13 @@
assert isinstance(type, str) and len(type) == 1
op.descr = Descr(ofs, type, arg_types=arg_types)
+def compile_add_descr_arg(loop, ofs, type, arg_types):
+ from pypy.jit.backend.llgraph.runner import Descr
+ loop = _from_opaque(loop)
+ op = loop.operations[-1]
+ assert isinstance(type, str) and len(type) == 1
+ op.args.append(Descr(ofs, type, arg_types=arg_types))
+
def compile_add_loop_token(loop, descr):
if we_are_translated():
raise ValueError("CALL_ASSEMBLER not supported")
@@ -437,8 +443,11 @@
self._may_force = -1
def getenv(self, v):
+ from pypy.jit.backend.llgraph.runner import Descr
if isinstance(v, Constant):
return v.value
+ elif isinstance(v, Descr):
+ return v
else:
return self.env[v]
@@ -806,6 +815,29 @@
else:
raise NotImplementedError
+ def op_getinteriorfield_gc(self, descr, array, index):
+ if descr.typeinfo == REF:
+ return do_getinteriorfield_gc_ptr(array, index, descr.ofs)
+ elif descr.typeinfo == INT:
+ return do_getinteriorfield_gc_int(array, index, descr.ofs)
+ elif descr.typeinfo == FLOAT:
+ return do_getinteriorfield_gc_float(array, index, descr.ofs)
+ else:
+ raise NotImplementedError
+
+ def op_setinteriorfield_gc(self, descr, array, index, newvalue):
+ if descr.typeinfo == REF:
+ return do_setinteriorfield_gc_ptr(array, index, descr.ofs,
+ newvalue)
+ elif descr.typeinfo == INT:
+ return do_setinteriorfield_gc_int(array, index, descr.ofs,
+ newvalue)
+ elif descr.typeinfo == FLOAT:
+ return do_setinteriorfield_gc_float(array, index, descr.ofs,
+ newvalue)
+ else:
+ raise NotImplementedError
+
def op_setfield_gc(self, fielddescr, struct, newvalue):
if fielddescr.typeinfo == REF:
do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue)
@@ -875,9 +907,6 @@
def op_new_array(self, arraydescr, count):
return do_new_array(arraydescr.ofs, count)
- def op_cast_ptr_to_int(self, descr, ptr):
- return cast_to_int(ptr)
-
def op_force_token(self, descr):
opaque_frame = _to_opaque(self)
return llmemory.cast_ptr_to_adr(opaque_frame)
@@ -1356,6 +1385,22 @@
def do_getfield_gc_ptr(struct, fieldnum):
return cast_to_ptr(_getfield_gc(struct, fieldnum))
+def _getinteriorfield_gc(struct, fieldnum):
+ STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+ return getattr(struct, fieldname)
+
+def do_getinteriorfield_gc_int(array, index, fieldnum):
+ struct = array._obj.container.getitem(index)
+ return cast_to_int(_getinteriorfield_gc(struct, fieldnum))
+
+def do_getinteriorfield_gc_float(array, index, fieldnum):
+ struct = array._obj.container.getitem(index)
+ return cast_to_floatstorage(_getinteriorfield_gc(struct, fieldnum))
+
+def do_getinteriorfield_gc_ptr(array, index, fieldnum):
+ struct = array._obj.container.getitem(index)
+ return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
+
def _getfield_raw(struct, fieldnum):
STRUCT, fieldname = symbolic.TokenToField[fieldnum]
ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
@@ -1411,26 +1456,28 @@
newvalue = cast_from_ptr(ITEMTYPE, newvalue)
array.setitem(index, newvalue)
-def do_setfield_gc_int(struct, fieldnum, newvalue):
- STRUCT, fieldname = symbolic.TokenToField[fieldnum]
- ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
- FIELDTYPE = getattr(STRUCT, fieldname)
- newvalue = cast_from_int(FIELDTYPE, newvalue)
- setattr(ptr, fieldname, newvalue)
+def new_setfield_gc(cast_func):
+ def do_setfield_gc(struct, fieldnum, newvalue):
+ STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+ ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
+ FIELDTYPE = getattr(STRUCT, fieldname)
+ newvalue = cast_func(FIELDTYPE, newvalue)
+ setattr(ptr, fieldname, newvalue)
+ return do_setfield_gc
+do_setfield_gc_int = new_setfield_gc(cast_from_int)
+do_setfield_gc_float = new_setfield_gc(cast_from_floatstorage)
+do_setfield_gc_ptr = new_setfield_gc(cast_from_ptr)
-def do_setfield_gc_float(struct, fieldnum, newvalue):
- STRUCT, fieldname = symbolic.TokenToField[fieldnum]
- ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
- FIELDTYPE = getattr(STRUCT, fieldname)
- newvalue = cast_from_floatstorage(FIELDTYPE, newvalue)
- setattr(ptr, fieldname, newvalue)
-
-def do_setfield_gc_ptr(struct, fieldnum, newvalue):
- STRUCT, fieldname = symbolic.TokenToField[fieldnum]
- ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
- FIELDTYPE = getattr(STRUCT, fieldname)
- newvalue = cast_from_ptr(FIELDTYPE, newvalue)
- setattr(ptr, fieldname, newvalue)
+def new_setinteriorfield_gc(cast_func):
+ def do_setinteriorfield_gc(array, index, fieldnum, newvalue):
+ STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+ struct = array._obj.container.getitem(index)
+ FIELDTYPE = getattr(STRUCT, fieldname)
+ setattr(struct, fieldname, cast_func(FIELDTYPE, newvalue))
+ return do_setinteriorfield_gc
+do_setinteriorfield_gc_int = new_setinteriorfield_gc(cast_from_int)
+do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
+do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
def do_setfield_raw_int(struct, fieldnum, newvalue):
STRUCT, fieldname = symbolic.TokenToField[fieldnum]
@@ -1696,6 +1743,7 @@
setannotation(compile_start_float_var, annmodel.SomeInteger())
setannotation(compile_add, annmodel.s_None)
setannotation(compile_add_descr, annmodel.s_None)
+setannotation(compile_add_descr_arg, annmodel.s_None)
setannotation(compile_add_var, annmodel.s_None)
setannotation(compile_add_int_const, annmodel.s_None)
setannotation(compile_add_ref_const, annmodel.s_None)
@@ -1743,6 +1791,9 @@
setannotation(do_getfield_raw_int, annmodel.SomeInteger())
setannotation(do_getfield_raw_ptr, annmodel.SomePtr(llmemory.GCREF))
setannotation(do_getfield_raw_float, s_FloatStorage)
+setannotation(do_getinteriorfield_gc_int, annmodel.SomeInteger())
+setannotation(do_getinteriorfield_gc_ptr, annmodel.SomePtr(llmemory.GCREF))
+setannotation(do_getinteriorfield_gc_float, s_FloatStorage)
setannotation(do_new, annmodel.SomePtr(llmemory.GCREF))
setannotation(do_new_array, annmodel.SomePtr(llmemory.GCREF))
setannotation(do_setarrayitem_gc_int, annmodel.s_None)
@@ -1756,6 +1807,9 @@
setannotation(do_setfield_raw_int, annmodel.s_None)
setannotation(do_setfield_raw_ptr, annmodel.s_None)
setannotation(do_setfield_raw_float, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_int, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_ptr, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_float, annmodel.s_None)
setannotation(do_newstr, annmodel.SomePtr(llmemory.GCREF))
setannotation(do_strsetitem, annmodel.s_None)
setannotation(do_newunicode, annmodel.SomePtr(llmemory.GCREF))
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -2,21 +2,19 @@
Minimal-API wrapper around the llinterpreter to run operations.
"""
-import sys
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import we_are_translated
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.llinterp import LLInterpreter
from pypy.jit.metainterp import history
-from pypy.jit.metainterp.history import REF, INT, FLOAT
+from pypy.jit.metainterp.history import REF, INT, FLOAT, STRUCT
from pypy.jit.metainterp.warmstate import unwrap
-from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend import model
from pypy.jit.backend.llgraph import llimpl, symbolic
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.jit.codewriter import heaptracker, longlong
-from pypy.rlib import rgc
class MiniStats:
pass
@@ -62,6 +60,9 @@
def is_array_of_floats(self):
return self.typeinfo == FLOAT
+ def is_array_of_structs(self):
+ return self.typeinfo == STRUCT
+
def as_vtable_size_descr(self):
return self
@@ -177,8 +178,10 @@
llimpl.compile_add(c, op.getopnum())
descr = op.getdescr()
if isinstance(descr, Descr):
- llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo, descr.arg_types)
- if isinstance(descr, history.LoopToken) and op.getopnum() != rop.JUMP:
+ llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo,
+ descr.arg_types)
+ if (isinstance(descr, history.LoopToken) and
+ op.getopnum() != rop.JUMP):
llimpl.compile_add_loop_token(c, descr)
if self.is_oo and isinstance(descr, (OODescr, MethDescr)):
# hack hack, not rpython
@@ -193,6 +196,9 @@
llimpl.compile_add_ref_const(c, x.value, self.ts.BASETYPE)
elif isinstance(x, history.ConstFloat):
llimpl.compile_add_float_const(c, x.value)
+ elif isinstance(x, Descr):
+ llimpl.compile_add_descr_arg(c, x.ofs, x.typeinfo,
+ x.arg_types)
else:
raise Exception("'%s' args contain: %r" % (op.getopname(),
x))
@@ -316,6 +322,13 @@
token = history.getkind(getattr(S, fieldname))
return self.getdescr(ofs, token[0], name=fieldname)
+ def interiorfielddescrof(self, A, fieldname):
+ S = A.OF
+ ofs2 = symbolic.get_size(A)
+ ofs, size = symbolic.get_field_token(S, fieldname)
+ token = history.getkind(getattr(S, fieldname))
+ return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2)
+
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
arg_types = []
for ARG in ARGS:
@@ -353,8 +366,13 @@
def arraydescrof(self, A):
assert A.OF != lltype.Void
size = symbolic.get_size(A)
- token = history.getkind(A.OF)
- return self.getdescr(size, token[0])
+ if isinstance(A.OF, lltype.Ptr) or isinstance(A.OF, lltype.Primitive):
+ token = history.getkind(A.OF)[0]
+ elif isinstance(A.OF, lltype.Struct):
+ token = 's'
+ else:
+ token = '?'
+ return self.getdescr(size, token)
# ---------- the backend-dependent operations ----------
@@ -406,6 +424,29 @@
assert isinstance(fielddescr, Descr)
return llimpl.do_getfield_raw_float(struct, fielddescr.ofs)
+ def bh_getinteriorfield_gc_i(self, array, index, descr):
+ assert isinstance(descr, Descr)
+ return llimpl.do_getinteriorfield_gc_int(array, index, descr.ofs)
+ def bh_getinteriorfield_gc_r(self, array, index, descr):
+ assert isinstance(descr, Descr)
+ return llimpl.do_getinteriorfield_gc_ptr(array, index, descr.ofs)
+ def bh_getinteriorfield_gc_f(self, array, index, descr):
+ assert isinstance(descr, Descr)
+ return llimpl.do_getinteriorfield_gc_float(array, index, descr.ofs)
+
+ def bh_setinteriorfield_gc_i(self, array, index, descr, value):
+ assert isinstance(descr, Descr)
+ return llimpl.do_setinteriorfield_gc_int(array, index, descr.ofs,
+ value)
+ def bh_setinteriorfield_gc_r(self, array, index, descr, value):
+ assert isinstance(descr, Descr)
+ return llimpl.do_setinteriorfield_gc_ptr(array, index, descr.ofs,
+ value)
+ def bh_setinteriorfield_gc_f(self, array, index, descr, value):
+ assert isinstance(descr, Descr)
+ return llimpl.do_setinteriorfield_gc_float(array, index, descr.ofs,
+ value)
+
def bh_new(self, sizedescr):
assert isinstance(sizedescr, Descr)
return llimpl.do_new(sizedescr.ofs)
@@ -418,7 +459,6 @@
def bh_classof(self, struct):
struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
- result = struct.typeptr
result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
return heaptracker.adr2int(result_adr)
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -1,13 +1,10 @@
import py
-from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass
+from pypy.rpython.lltypesystem import lltype, rffi, llmemory
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.jit.backend.llsupport import symbolic, support
-from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr
-from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat
+from pypy.jit.metainterp.history import AbstractDescr, getkind
from pypy.jit.metainterp import history
-from pypy.jit.metainterp.resoperation import ResOperation, rop
from pypy.jit.codewriter import heaptracker, longlong
-from pypy.rlib.rarithmetic import r_longlong, r_ulonglong
# The point of the class organization in this file is to make instances
# as compact as possible. This is done by not storing the field size or
@@ -23,6 +20,7 @@
self._cache_field = {}
self._cache_array = {}
self._cache_call = {}
+ self._cache_interiorfield = {}
def init_size_descr(self, STRUCT, sizedescr):
assert isinstance(STRUCT, lltype.GcStruct)
@@ -142,7 +140,6 @@
cachedict[fieldname] = fielddescr
return fielddescr
-
# ____________________________________________________________
# ArrayDescrs
@@ -167,6 +164,7 @@
_is_array_of_pointers = False # unless overridden by GcPtrArrayDescr
_is_array_of_floats = False # unless overridden by FloatArrayDescr
+ _is_array_of_structs = False # unless overridden by StructArrayDescr
_is_item_signed = False # unless overridden by XxxArrayDescr
def is_array_of_pointers(self):
@@ -175,6 +173,9 @@
def is_array_of_floats(self):
return self._is_array_of_floats
+ def is_array_of_structs(self):
+ return self._is_array_of_structs
+
def is_item_signed(self):
return self._is_item_signed
@@ -199,6 +200,10 @@
def get_item_size(self, translate_support_code):
return symbolic.get_size(lltype.Float, translate_support_code)
+class StructArrayDescr(BaseArrayDescr):
+ _clsname = 'StructArrayDescr'
+ _is_array_of_structs = True
+
class BaseArrayNoLengthDescr(BaseArrayDescr):
def get_base_size(self, translate_support_code):
return 0
@@ -218,6 +223,13 @@
def getArrayDescrClass(ARRAY):
if ARRAY.OF is lltype.Float:
return FloatArrayDescr
+ elif isinstance(ARRAY.OF, lltype.Struct):
+ class Descr(StructArrayDescr):
+ _clsname = '%sArrayDescr' % ARRAY.OF._name
+ def get_item_size(self, translate_support_code):
+ return symbolic.get_size(ARRAY.OF, translate_support_code)
+ Descr.__name__ = Descr._clsname
+ return Descr
return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
NonGcPtrArrayDescr, 'Array', 'get_item_size',
'_is_array_of_floats', '_is_item_signed')
@@ -252,6 +264,39 @@
cache[ARRAY] = arraydescr
return arraydescr
+# ____________________________________________________________
+# InteriorFieldDescr
+
+class InteriorFieldDescr(AbstractDescr):
+ arraydescr = BaseArrayDescr() # workaround for the annotator
+ fielddescr = BaseFieldDescr('', 0)
+
+ def __init__(self, arraydescr, fielddescr):
+ self.arraydescr = arraydescr
+ self.fielddescr = fielddescr
+
+ def is_pointer_field(self):
+ return self.fielddescr.is_pointer_field()
+
+ def is_float_field(self):
+ return self.fielddescr.is_float_field()
+
+ def sort_key(self):
+ return self.fielddescr.sort_key()
+
+ def repr_of_descr(self):
+ return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_descr()
+
+def get_interiorfield_descr(gc_ll_descr, ARRAY, FIELDTP, name):
+ cache = gc_ll_descr._cache_interiorfield
+ try:
+ return cache[(ARRAY, FIELDTP, name)]
+ except KeyError:
+ arraydescr = get_array_descr(gc_ll_descr, ARRAY)
+ fielddescr = get_field_descr(gc_ll_descr, FIELDTP, name)
+ descr = InteriorFieldDescr(arraydescr, fielddescr)
+ cache[(ARRAY, FIELDTP, name)] = descr
+ return descr
# ____________________________________________________________
# CallDescrs
@@ -525,7 +570,8 @@
#
if TYPE is lltype.Float or is_longlong(TYPE):
setattr(Descr, floatattrname, True)
- elif TYPE is not lltype.Bool and rffi.cast(TYPE, -1) == -1:
+ elif (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
+ rffi.cast(TYPE, -1) == -1):
setattr(Descr, signedattrname, True)
#
_cache[nameprefix, TYPE] = Descr
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -45,6 +45,14 @@
def freeing_block(self, start, stop):
pass
+ def get_funcptr_for_newarray(self):
+ return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
+ def get_funcptr_for_newstr(self):
+ return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
+ def get_funcptr_for_newunicode(self):
+ return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
+
+
def record_constptrs(self, op, gcrefs_output_list):
for i in range(op.numargs()):
v = op.getarg(i)
@@ -96,6 +104,39 @@
malloc_fn_ptr = self.configure_boehm_once()
self.funcptr_for_new = malloc_fn_ptr
+ def malloc_array(basesize, itemsize, ofs_length, num_elem):
+ try:
+ size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+ except OverflowError:
+ return lltype.nullptr(llmemory.GCREF.TO)
+ res = self.funcptr_for_new(size)
+ if not res:
+ return res
+ rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
+ return res
+ self.malloc_array = malloc_array
+ self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType(
+ [lltype.Signed] * 4, llmemory.GCREF))
+
+
+ (str_basesize, str_itemsize, str_ofs_length
+ ) = symbolic.get_array_token(rstr.STR, self.translate_support_code)
+ (unicode_basesize, unicode_itemsize, unicode_ofs_length
+ ) = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code)
+ def malloc_str(length):
+ return self.malloc_array(
+ str_basesize, str_itemsize, str_ofs_length, length
+ )
+ def malloc_unicode(length):
+ return self.malloc_array(
+ unicode_basesize, unicode_itemsize, unicode_ofs_length, length
+ )
+ self.malloc_str = malloc_str
+ self.malloc_unicode = malloc_unicode
+ self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType(
+ [lltype.Signed], llmemory.GCREF))
+
+
# on some platform GC_init is required before any other
# GC_* functions, call it here for the benefit of tests
# XXX move this to tests
@@ -116,39 +157,27 @@
ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
basesize = arraydescr.get_base_size(self.translate_support_code)
itemsize = arraydescr.get_item_size(self.translate_support_code)
- size = basesize + itemsize * num_elem
- res = self.funcptr_for_new(size)
- rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
- return res
+ return self.malloc_array(basesize, itemsize, ofs_length, num_elem)
def gc_malloc_str(self, num_elem):
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
- self.translate_support_code)
- assert itemsize == 1
- size = basesize + num_elem
- res = self.funcptr_for_new(size)
- rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
- return res
+ return self.malloc_str(num_elem)
def gc_malloc_unicode(self, num_elem):
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
- self.translate_support_code)
- size = basesize + num_elem * itemsize
- res = self.funcptr_for_new(size)
- rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
- return res
+ return self.malloc_unicode(num_elem)
def args_for_new(self, sizedescr):
assert isinstance(sizedescr, BaseSizeDescr)
return [sizedescr.size]
+ def args_for_new_array(self, arraydescr):
+ ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
+ basesize = arraydescr.get_base_size(self.translate_support_code)
+ itemsize = arraydescr.get_item_size(self.translate_support_code)
+ return [basesize, itemsize, ofs_length]
+
def get_funcptr_for_new(self):
return self.funcptr_for_new
- get_funcptr_for_newarray = None
- get_funcptr_for_newstr = None
- get_funcptr_for_newunicode = None
-
def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
# record all GCREFs too, because Boehm cannot see them and keep them
# alive if they end up as constants in the assembler
@@ -620,10 +649,13 @@
def malloc_basic(size, tid):
type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
has_finalizer = bool(tid & (1<<llgroup.HALFSHIFT))
+ has_light_finalizer = bool(tid & (1<<(llgroup.HALFSHIFT + 1)))
check_typeid(type_id)
res = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
type_id, size,
- has_finalizer, False)
+ has_finalizer,
+ has_light_finalizer,
+ False)
# In case the operation above failed, we are returning NULL
# from this function to assembler. There is also an RPython
# exception set, typically MemoryError; but it's easier and
@@ -694,7 +726,7 @@
# also use it to allocate varsized objects. The tid
# and possibly the length are both set afterward.
gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
- 0, size, False, False)
+ 0, size, False, False, False)
return rffi.cast(lltype.Signed, gcref)
self.malloc_slowpath = malloc_slowpath
self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed], lltype.Signed)
@@ -718,7 +750,9 @@
type_id = self.layoutbuilder.get_type_id(S)
assert not self.layoutbuilder.is_weakref_type(S)
has_finalizer = bool(self.layoutbuilder.has_finalizer(S))
- flags = int(has_finalizer) << llgroup.HALFSHIFT
+ has_light_finalizer = bool(self.layoutbuilder.has_light_finalizer(S))
+ flags = (int(has_finalizer) << llgroup.HALFSHIFT |
+ int(has_light_finalizer) << (llgroup.HALFSHIFT + 1))
descr.tid = llop.combine_ushort(lltype.Signed, type_id, flags)
def init_array_descr(self, A, descr):
@@ -752,15 +786,6 @@
def get_funcptr_for_new(self):
return llhelper(self.GC_MALLOC_BASIC, self.malloc_basic)
- def get_funcptr_for_newarray(self):
- return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
-
- def get_funcptr_for_newstr(self):
- return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
-
- def get_funcptr_for_newunicode(self):
- return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
-
def do_write_barrier(self, gcref_struct, gcref_newptr):
hdr_addr = llmemory.cast_ptr_to_adr(gcref_struct)
hdr_addr -= self.gcheaderbuilder.size_gc_header
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -1,24 +1,18 @@
-import sys
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.llinterp import LLInterpreter, LLException
+from pypy.rpython.llinterp import LLInterpreter
from pypy.rpython.annlowlevel import llhelper
from pypy.rlib.objectmodel import we_are_translated, specialize
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, set_future_values,\
- BoxFloat
from pypy.jit.metainterp import history
from pypy.jit.codewriter import heaptracker, longlong
from pypy.jit.backend.model import AbstractCPU
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
-from pypy.jit.backend.llsupport.descr import get_size_descr, BaseSizeDescr
-from pypy.jit.backend.llsupport.descr import get_field_descr, BaseFieldDescr
-from pypy.jit.backend.llsupport.descr import get_array_descr, BaseArrayDescr
-from pypy.jit.backend.llsupport.descr import get_call_descr
-from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
-from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr
+from pypy.jit.backend.llsupport.descr import (get_size_descr,
+ get_field_descr, BaseFieldDescr, get_array_descr, BaseArrayDescr,
+ get_call_descr, BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr,
+ VoidCallDescr, InteriorFieldDescr, get_interiorfield_descr)
from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
-from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
class AbstractLLCPU(AbstractCPU):
@@ -241,6 +235,9 @@
def arraydescrof(self, A):
return get_array_descr(self.gc_ll_descr, A)
+ def interiorfielddescrof(self, A, fieldname):
+ return get_interiorfield_descr(self.gc_ll_descr, A, A.OF, fieldname)
+
def unpack_arraydescr(self, arraydescr):
assert isinstance(arraydescr, BaseArrayDescr)
return arraydescr.get_base_size(self.translate_support_code)
@@ -358,6 +355,100 @@
bh_getarrayitem_raw_i = bh_getarrayitem_gc_i
bh_getarrayitem_raw_f = bh_getarrayitem_gc_f
+ def bh_getinteriorfield_gc_i(self, gcref, itemindex, descr):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+ sign = descr.fielddescr.is_field_signed()
+ fullofs = itemindex * size + ofs
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), fullofs)
+ for STYPE, UTYPE, itemsize in unroll_basic_sizes:
+ if fieldsize == itemsize:
+ if sign:
+ item = rffi.cast(rffi.CArrayPtr(STYPE), items)
+ val = item[0]
+ val = rffi.cast(lltype.Signed, val)
+ else:
+ item = rffi.cast(rffi.CArrayPtr(UTYPE), items)
+ val = item[0]
+ val = rffi.cast(lltype.Signed, val)
+ # --- end of GC unsafe code ---
+ return val
+ else:
+ raise NotImplementedError("size = %d" % fieldsize)
+
+ def bh_getinteriorfield_gc_r(self, gcref, itemindex, descr):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs +
+ size * itemindex)
+ items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items)
+ pval = self._cast_int_to_gcref(items[0])
+ # --- end of GC unsafe code ---
+ return pval
+
+ def bh_getinteriorfield_gc_f(self, gcref, itemindex, descr):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs +
+ size * itemindex)
+ items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items)
+ fval = items[0]
+ # --- end of GC unsafe code ---
+ return fval
+
+ def bh_setinteriorfield_gc_i(self, gcref, itemindex, descr, value):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+ ofs = itemindex * size + ofs
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
+ for TYPE, _, itemsize in unroll_basic_sizes:
+ if fieldsize == itemsize:
+ items = rffi.cast(rffi.CArrayPtr(TYPE), items)
+ items[0] = rffi.cast(TYPE, value)
+ # --- end of GC unsafe code ---
+ return
+ else:
+ raise NotImplementedError("size = %d" % fieldsize)
+
+ def bh_setinteriorfield_gc_r(self, gcref, itemindex, descr, newvalue):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ self.gc_ll_descr.do_write_barrier(gcref, newvalue)
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref),
+ ofs + size * itemindex)
+ items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items)
+ items[0] = self.cast_gcref_to_int(newvalue)
+ # --- end of GC unsafe code ---
+
+ def bh_setinteriorfield_gc_f(self, gcref, itemindex, descr, newvalue):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+ ofs += descr.fielddescr.offset
+ # --- start of GC unsafe code (no GC operation!) ---
+ items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref),
+ ofs + size * itemindex)
+ items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items)
+ items[0] = newvalue
+ # --- end of GC unsafe code ---
+
def bh_strlen(self, string):
s = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string)
return len(s.chars)
@@ -475,7 +566,6 @@
def bh_classof(self, struct):
struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
- result = struct.typeptr
result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
return heaptracker.adr2int(result_adr)
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -287,7 +287,6 @@
self.reg_bindings[to_v] = reg
def _move_variable_away(self, v, prev_loc):
- reg = None
if self.free_regs:
loc = self.free_regs.pop()
self.reg_bindings[v] = loc
diff --git a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
--- a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
+++ b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
@@ -211,14 +211,14 @@
debug._log = debug.DebugLog()
try:
mc._dump(addr, 'test-logname-section')
- log = list(debug._log)
+ log = list(debug._log)
finally:
debug._log = None
encoded = ''.join(writtencode).encode('hex').upper()
ataddr = '@%x' % addr
assert log == [('test-logname-section',
[('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
- #
+
lltype.free(p, flavor='raw')
def test_blockbuildermixin2():
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -3,7 +3,6 @@
from pypy.jit.backend.llsupport import symbolic
from pypy.rlib.objectmodel import Symbolic
from pypy.rpython.annlowlevel import llhelper
-from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
from pypy.jit.metainterp import history
from pypy.jit.codewriter import longlong
import sys, struct, py
@@ -149,7 +148,9 @@
A2 = lltype.GcArray(lltype.Ptr(T))
A3 = lltype.GcArray(lltype.Ptr(U))
A4 = lltype.GcArray(lltype.Float)
- A5 = lltype.GcArray(lltype.SingleFloat)
+ A5 = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed),
+ ('k', lltype.Signed)))
+ A6 = lltype.GcArray(lltype.SingleFloat)
assert getArrayDescrClass(A2) is GcPtrArrayDescr
assert getArrayDescrClass(A3) is NonGcPtrArrayDescr
cls = getArrayDescrClass(A1)
@@ -158,7 +159,7 @@
clsf = getArrayDescrClass(A4)
assert clsf != cls
assert clsf == getArrayDescrClass(lltype.GcArray(lltype.Float))
- clss = getArrayDescrClass(A5)
+ clss = getArrayDescrClass(A6)
assert clss not in (clsf, cls)
assert clss == getArrayDescrClass(lltype.GcArray(rffi.UINT))
#
@@ -168,11 +169,12 @@
descr3 = get_array_descr(c0, A3)
descr4 = get_array_descr(c0, A4)
descr5 = get_array_descr(c0, A5)
+ descr6 = get_array_descr(c0, A6)
assert descr1.__class__ is cls
assert descr2.__class__ is GcPtrArrayDescr
assert descr3.__class__ is NonGcPtrArrayDescr
assert descr4.__class__ is clsf
- assert descr5.__class__ is clss
+ assert descr6.__class__ is clss
assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char))
assert not descr1.is_array_of_pointers()
assert descr2.is_array_of_pointers()
@@ -202,7 +204,8 @@
assert descr2.get_item_size(False) == rffi.sizeof(lltype.Ptr(T))
assert descr3.get_item_size(False) == rffi.sizeof(lltype.Ptr(U))
assert descr4.get_item_size(False) == rffi.sizeof(lltype.Float)
- assert descr5.get_item_size(False) == rffi.sizeof(lltype.SingleFloat)
+ assert descr5.get_item_size(False) == rffi.sizeof(lltype.Signed) * 2
+ assert descr6.get_item_size(False) == rffi.sizeof(lltype.SingleFloat)
#
assert isinstance(descr1.get_base_size(True), Symbolic)
assert isinstance(descr2.get_base_size(True), Symbolic)
@@ -348,7 +351,6 @@
(rffi.SHORT, True), (rffi.USHORT, False),
(rffi.INT, True), (rffi.UINT, False),
(rffi.LONG, True), (rffi.ULONG, False)]:
- A = lltype.GcArray(RESTYPE)
for tsc in [False, True]:
c2 = GcCache(tsc)
descr1 = get_call_descr(c2, [], RESTYPE)
@@ -379,7 +381,6 @@
descr3i = get_array_descr(c0, lltype.GcArray(lltype.Char))
assert descr3i.repr_of_descr() == '<CharArrayDescr>'
#
- cache = {}
descr4 = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Ptr(S))
assert 'GcPtrCallDescr' in descr4.repr_of_descr()
#
@@ -412,10 +413,10 @@
ARGS = [lltype.Float, lltype.Ptr(ARRAY)]
RES = lltype.Float
- def f(a, b):
+ def f2(a, b):
return float(b[0]) + a
- fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f)
+ fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f2)
descr2 = get_call_descr(c0, ARGS, RES)
a = lltype.malloc(ARRAY, 3)
opaquea = lltype.cast_opaque_ptr(llmemory.GCREF, a)
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -247,12 +247,14 @@
self.record = []
def do_malloc_fixedsize_clear(self, RESTYPE, type_id, size,
- has_finalizer, contains_weakptr):
+ has_finalizer, has_light_finalizer,
+ contains_weakptr):
assert not contains_weakptr
+ assert not has_finalizer # in these tests
+ assert not has_light_finalizer # in these tests
p = llmemory.raw_malloc(size)
p = llmemory.cast_adr_to_ptr(p, RESTYPE)
- flags = int(has_finalizer) << 16
- tid = llop.combine_ushort(lltype.Signed, type_id, flags)
+ tid = llop.combine_ushort(lltype.Signed, type_id, 0)
self.record.append(("fixedsize", repr(size), tid, p))
return p
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -1,5 +1,5 @@
from pypy.rlib.debug import debug_start, debug_print, debug_stop
-from pypy.jit.metainterp import history, compile
+from pypy.jit.metainterp import history
class AbstractCPU(object):
@@ -213,6 +213,10 @@
def typedescrof(TYPE):
raise NotImplementedError
+ @staticmethod
+ def interiorfielddescrof(A, fieldname):
+ raise NotImplementedError
+
# ---------- the backend-dependent operations ----------
# lltype specific operations
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -5,7 +5,7 @@
BoxInt, Box, BoxPtr,
LoopToken,
ConstInt, ConstPtr,
- BoxObj, Const,
+ BoxObj,
ConstObj, BoxFloat, ConstFloat)
from pypy.jit.metainterp.resoperation import ResOperation, rop
from pypy.jit.metainterp.typesystem import deref
@@ -111,7 +111,7 @@
self.cpu.set_future_value_int(0, 2)
fail = self.cpu.execute_token(looptoken)
res = self.cpu.get_latest_value_int(0)
- assert res == 3
+ assert res == 3
assert fail.identifier == 1
def test_compile_loop(self):
@@ -127,7 +127,7 @@
]
inputargs = [i0]
operations[2].setfailargs([i1])
-
+
self.cpu.compile_loop(inputargs, operations, looptoken)
self.cpu.set_future_value_int(0, 2)
fail = self.cpu.execute_token(looptoken)
@@ -148,7 +148,7 @@
]
inputargs = [i0]
operations[2].setfailargs([None, None, i1, None])
-
+
self.cpu.compile_loop(inputargs, operations, looptoken)
self.cpu.set_future_value_int(0, 2)
fail = self.cpu.execute_token(looptoken)
@@ -372,7 +372,7 @@
for opnum, boxargs, retvalue in get_int_tests():
res = self.execute_operation(opnum, boxargs, 'int')
assert res.value == retvalue
-
+
def test_float_operations(self):
from pypy.jit.metainterp.test.test_executor import get_float_tests
for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu):
@@ -438,7 +438,7 @@
def test_ovf_operations_reversed(self):
self.test_ovf_operations(reversed=True)
-
+
def test_bh_call(self):
cpu = self.cpu
#
@@ -503,7 +503,7 @@
[funcbox, BoxInt(num), BoxInt(num)],
'int', descr=dyn_calldescr)
assert res.value == 2 * num
-
+
if cpu.supports_floats:
def func(f0, f1, f2, f3, f4, f5, f6, i0, i1, f7, f8, f9):
@@ -543,7 +543,7 @@
funcbox = self.get_funcbox(self.cpu, func_ptr)
res = self.execute_operation(rop.CALL, [funcbox] + map(BoxInt, args), 'int', descr=calldescr)
assert res.value == func(*args)
-
+
def test_call_stack_alignment(self):
# test stack alignment issues, notably for Mac OS/X.
# also test the ordering of the arguments.
@@ -615,7 +615,7 @@
res = self.execute_operation(rop.GETFIELD_GC, [t_box],
'int', descr=shortdescr)
assert res.value == 1331
-
+
#
u_box, U_box = self.alloc_instance(self.U)
fielddescr2 = self.cpu.fielddescrof(self.S, 'next')
@@ -695,7 +695,7 @@
def test_failing_guard_class(self):
t_box, T_box = self.alloc_instance(self.T)
- u_box, U_box = self.alloc_instance(self.U)
+ u_box, U_box = self.alloc_instance(self.U)
null_box = self.null_instance()
for opname, args in [(rop.GUARD_CLASS, [t_box, U_box]),
(rop.GUARD_CLASS, [u_box, T_box]),
@@ -787,7 +787,7 @@
r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(3)],
'int', descr=arraydescr)
assert r.value == 160
-
+
#
if isinstance(A, lltype.GcArray):
A = lltype.Ptr(A)
@@ -880,6 +880,73 @@
'int', descr=arraydescr)
assert r.value == 7441
+ def test_array_of_structs(self):
+ TP = lltype.GcStruct('x')
+ ITEM = lltype.Struct('x',
+ ('vs', lltype.Signed),
+ ('vu', lltype.Unsigned),
+ ('vsc', rffi.SIGNEDCHAR),
+ ('vuc', rffi.UCHAR),
+ ('vss', rffi.SHORT),
+ ('vus', rffi.USHORT),
+ ('vsi', rffi.INT),
+ ('vui', rffi.UINT),
+ ('k', lltype.Float),
+ ('p', lltype.Ptr(TP)))
+ a_box, A = self.alloc_array_of(ITEM, 15)
+ s_box, S = self.alloc_instance(TP)
+ kdescr = self.cpu.interiorfielddescrof(A, 'k')
+ pdescr = self.cpu.interiorfielddescrof(A, 'p')
+ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3),
+ boxfloat(1.5)],
+ 'void', descr=kdescr)
+ f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr)
+ assert longlong.getrealfloat(f) == 1.5
+ self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, kdescr, longlong.getfloatstorage(2.5))
+ r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)],
+ 'float', descr=kdescr)
+ assert r.getfloat() == 2.5
+ #
+ NUMBER_FIELDS = [('vs', lltype.Signed),
+ ('vu', lltype.Unsigned),
+ ('vsc', rffi.SIGNEDCHAR),
+ ('vuc', rffi.UCHAR),
+ ('vss', rffi.SHORT),
+ ('vus', rffi.USHORT),
+ ('vsi', rffi.INT),
+ ('vui', rffi.UINT)]
+ for name, TYPE in NUMBER_FIELDS[::-1]:
+ vdescr = self.cpu.interiorfielddescrof(A, name)
+ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3),
+ BoxInt(-15)],
+ 'void', descr=vdescr)
+ for name, TYPE in NUMBER_FIELDS:
+ vdescr = self.cpu.interiorfielddescrof(A, name)
+ i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3,
+ vdescr)
+ assert i == rffi.cast(lltype.Signed, rffi.cast(TYPE, -15))
+ for name, TYPE in NUMBER_FIELDS[::-1]:
+ vdescr = self.cpu.interiorfielddescrof(A, name)
+ self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3,
+ vdescr, -25)
+ for name, TYPE in NUMBER_FIELDS:
+ vdescr = self.cpu.interiorfielddescrof(A, name)
+ r = self.execute_operation(rop.GETINTERIORFIELD_GC,
+ [a_box, BoxInt(3)],
+ 'int', descr=vdescr)
+ assert r.getint() == rffi.cast(lltype.Signed, rffi.cast(TYPE, -25))
+ #
+ self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(4),
+ s_box],
+ 'void', descr=pdescr)
+ r = self.cpu.bh_getinteriorfield_gc_r(a_box.getref_base(), 4, pdescr)
+ assert r == s_box.getref_base()
+ self.cpu.bh_setinteriorfield_gc_r(a_box.getref_base(), 3, pdescr,
+ s_box.getref_base())
+ r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)],
+ 'ref', descr=pdescr)
+ assert r.getref_base() == s_box.getref_base()
+
def test_string_basic(self):
s_box = self.alloc_string("hello\xfe")
r = self.execute_operation(rop.STRLEN, [s_box], 'int')
@@ -1402,7 +1469,7 @@
addr = llmemory.cast_ptr_to_adr(func_ptr)
return ConstInt(heaptracker.adr2int(addr))
-
+
MY_VTABLE = rclass.OBJECT_VTABLE # for tests only
S = lltype.GcForwardReference()
@@ -1439,7 +1506,6 @@
return BoxPtr(lltype.nullptr(llmemory.GCREF.TO))
def alloc_array_of(self, ITEM, length):
- cpu = self.cpu
A = lltype.GcArray(ITEM)
a = lltype.malloc(A, length)
a_box = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a))
@@ -1468,20 +1534,16 @@
return u''.join(u.chars)
- def test_casts(self):
- py.test.skip("xxx fix or kill")
- from pypy.rpython.lltypesystem import lltype, llmemory
- TP = lltype.GcStruct('x')
- x = lltype.malloc(TP)
- x = lltype.cast_opaque_ptr(llmemory.GCREF, x)
+ def test_cast_int_to_ptr(self):
+ res = self.execute_operation(rop.CAST_INT_TO_PTR,
+ [BoxInt(-17)], 'ref').value
+ assert lltype.cast_ptr_to_int(res) == -17
+
+ def test_cast_ptr_to_int(self):
+ x = lltype.cast_int_to_ptr(llmemory.GCREF, -19)
res = self.execute_operation(rop.CAST_PTR_TO_INT,
- [BoxPtr(x)], 'int').value
- expected = self.cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(x))
- assert rffi.get_real_int(res) == rffi.get_real_int(expected)
- res = self.execute_operation(rop.CAST_PTR_TO_INT,
- [ConstPtr(x)], 'int').value
- expected = self.cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(x))
- assert rffi.get_real_int(res) == rffi.get_real_int(expected)
+ [BoxPtr(x)], 'int').value
+ assert res == -19
def test_ooops_non_gc(self):
x = lltype.malloc(lltype.Struct('x'), flavor='raw')
@@ -2299,13 +2361,6 @@
#
cpu.bh_strsetitem(x, 4, ord('/'))
assert str.chars[4] == '/'
- #
-## x = cpu.bh_newstr(5)
-## y = cpu.bh_cast_ptr_to_int(x)
-## z = cpu.bh_cast_ptr_to_int(x)
-## y = rffi.get_real_int(y)
-## z = rffi.get_real_int(z)
-## assert type(y) == type(z) == int and y == z
def test_sorting_of_fields(self):
S = self.S
@@ -2329,7 +2384,7 @@
for opname, arg, res in ops:
self.execute_operation(opname, [arg], 'void')
assert self.guard_failed == res
-
+
lltype.free(x, flavor='raw')
def test_assembler_call(self):
@@ -2409,7 +2464,7 @@
FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
EffectInfo.MOST_GENERAL)
-
+
ops = '''
[f0, f1]
f2 = float_add(f0, f1)
@@ -2500,7 +2555,7 @@
FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
EffectInfo.MOST_GENERAL)
-
+
ops = '''
[f0, f1]
f2 = float_add(f0, f1)
@@ -2951,4 +3006,4 @@
def alloc_unicode(self, unicode):
py.test.skip("implement me")
-
+
diff --git a/pypy/jit/backend/test/test_ll_random.py b/pypy/jit/backend/test/test_ll_random.py
--- a/pypy/jit/backend/test/test_ll_random.py
+++ b/pypy/jit/backend/test/test_ll_random.py
@@ -28,16 +28,27 @@
fork.structure_types_and_vtables = self.structure_types_and_vtables
return fork
- def get_structptr_var(self, r, must_have_vtable=False, type=lltype.Struct):
+ def _choose_ptr_vars(self, from_, type, array_of_structs):
+ ptrvars = []
+ for i in range(len(from_)):
+ v, S = from_[i][:2]
+ if not isinstance(S, type):
+ continue
+ if ((isinstance(S, lltype.Array) and
+ isinstance(S.OF, lltype.Struct)) == array_of_structs):
+ ptrvars.append((v, S))
+ return ptrvars
+
+ def get_structptr_var(self, r, must_have_vtable=False, type=lltype.Struct,
+ array_of_structs=False):
while True:
- ptrvars = [(v, S) for (v, S) in self.ptrvars
- if isinstance(S, type)]
+ ptrvars = self._choose_ptr_vars(self.ptrvars, type,
+ array_of_structs)
if ptrvars and r.random() < 0.8:
v, S = r.choice(ptrvars)
else:
- prebuilt_ptr_consts = [(v, S)
- for (v, S, _) in self.prebuilt_ptr_consts
- if isinstance(S, type)]
+ prebuilt_ptr_consts = self._choose_ptr_vars(
+ self.prebuilt_ptr_consts, type, array_of_structs)
if prebuilt_ptr_consts and r.random() < 0.7:
v, S = r.choice(prebuilt_ptr_consts)
else:
@@ -48,7 +59,8 @@
has_vtable=must_have_vtable)
else:
# create a new constant array
- p = self.get_random_array(r)
+ p = self.get_random_array(r,
+ must_be_array_of_structs=array_of_structs)
S = lltype.typeOf(p).TO
v = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, p))
self.prebuilt_ptr_consts.append((v, S,
@@ -74,7 +86,8 @@
TYPE = lltype.Signed
return TYPE
- def get_random_structure_type(self, r, with_vtable=None, cache=True):
+ def get_random_structure_type(self, r, with_vtable=None, cache=True,
+ type=lltype.GcStruct):
if cache and self.structure_types and r.random() < 0.5:
return r.choice(self.structure_types)
fields = []
@@ -85,7 +98,7 @@
for i in range(r.randrange(1, 5)):
TYPE = self.get_random_primitive_type(r)
fields.append(('f%d' % i, TYPE))
- S = lltype.GcStruct('S%d' % self.counter, *fields, **kwds)
+ S = type('S%d' % self.counter, *fields, **kwds)
self.counter += 1
if cache:
self.structure_types.append(S)
@@ -125,17 +138,29 @@
setattr(p, fieldname, rffi.cast(TYPE, r.random_integer()))
return p
- def get_random_array_type(self, r):
- TYPE = self.get_random_primitive_type(r)
+ def get_random_array_type(self, r, can_be_array_of_struct=False,
+ must_be_array_of_structs=False):
+ if ((can_be_array_of_struct and r.random() < 0.1) or
+ must_be_array_of_structs):
+ TYPE = self.get_random_structure_type(r, cache=False,
+ type=lltype.Struct)
+ else:
+ TYPE = self.get_random_primitive_type(r)
return lltype.GcArray(TYPE)
- def get_random_array(self, r):
- A = self.get_random_array_type(r)
+ def get_random_array(self, r, must_be_array_of_structs=False):
+ A = self.get_random_array_type(r,
+ must_be_array_of_structs=must_be_array_of_structs)
length = (r.random_integer() // 15) % 300 # length: between 0 and 299
# likely to be small
p = lltype.malloc(A, length)
- for i in range(length):
- p[i] = rffi.cast(A.OF, r.random_integer())
+ if isinstance(A.OF, lltype.Primitive):
+ for i in range(length):
+ p[i] = rffi.cast(A.OF, r.random_integer())
+ else:
+ for i in range(length):
+ for fname, TP in A.OF._flds.iteritems():
+ setattr(p[i], fname, rffi.cast(TP, r.random_integer()))
return p
def get_index(self, length, r):
@@ -155,8 +180,16 @@
dic[fieldname] = getattr(p, fieldname)
else:
assert isinstance(S, lltype.Array)
- for i in range(len(p)):
- dic[i] = p[i]
+ if isinstance(S.OF, lltype.Struct):
+ for i in range(len(p)):
+ item = p[i]
+ s1 = {}
+ for fieldname in S.OF._names:
+ s1[fieldname] = getattr(item, fieldname)
+ dic[i] = s1
+ else:
+ for i in range(len(p)):
+ dic[i] = p[i]
return dic
def print_loop_prebuilt(self, names, writevar, s):
@@ -220,7 +253,7 @@
class GetFieldOperation(test_random.AbstractOperation):
def field_descr(self, builder, r):
- v, S = builder.get_structptr_var(r)
+ v, S = builder.get_structptr_var(r, )
names = S._names
if names[0] == 'parent':
names = names[1:]
@@ -239,6 +272,28 @@
continue
break
+class GetInteriorFieldOperation(test_random.AbstractOperation):
+ def field_descr(self, builder, r):
+ v, A = builder.get_structptr_var(r, type=lltype.Array,
+ array_of_structs=True)
+ array = v.getref(lltype.Ptr(A))
+ v_index = builder.get_index(len(array), r)
+ name = r.choice(A.OF._names)
+ descr = builder.cpu.interiorfielddescrof(A, name)
+ descr._random_info = 'cpu.interiorfielddescrof(%s, %r)' % (A.OF._name,
+ name)
+ TYPE = getattr(A.OF, name)
+ return v, v_index, descr, TYPE
+
+ def produce_into(self, builder, r):
+ while True:
+ try:
+ v, v_index, descr, _ = self.field_descr(builder, r)
+ self.put(builder, [v, v_index], descr)
+ except lltype.UninitializedMemoryAccess:
+ continue
+ break
+
class SetFieldOperation(GetFieldOperation):
def produce_into(self, builder, r):
v, descr, TYPE = self.field_descr(builder, r)
@@ -251,6 +306,18 @@
break
builder.do(self.opnum, [v, w], descr)
+class SetInteriorFieldOperation(GetInteriorFieldOperation):
+ def produce_into(self, builder, r):
+ v, v_index, descr, TYPE = self.field_descr(builder, r)
+ while True:
+ if r.random() < 0.3:
+ w = ConstInt(r.random_integer())
+ else:
+ w = r.choice(builder.intvars)
+ if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value:
+ break
+ builder.do(self.opnum, [v, v_index, w], descr)
+
class NewOperation(test_random.AbstractOperation):
def size_descr(self, builder, S):
descr = builder.cpu.sizeof(S)
@@ -306,7 +373,7 @@
class NewArrayOperation(ArrayOperation):
def produce_into(self, builder, r):
- A = builder.get_random_array_type(r)
+ A = builder.get_random_array_type(r, can_be_array_of_struct=True)
v_size = builder.get_index(300, r)
v_ptr = builder.do(self.opnum, [v_size], self.array_descr(builder, A))
builder.ptrvars.append((v_ptr, A))
@@ -586,7 +653,9 @@
for i in range(4): # make more common
OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC))
OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC))
+ OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC))
OPERATIONS.append(SetFieldOperation(rop.SETFIELD_GC))
+ OPERATIONS.append(SetInteriorFieldOperation(rop.SETINTERIORFIELD_GC))
OPERATIONS.append(NewOperation(rop.NEW))
OPERATIONS.append(NewOperation(rop.NEW_WITH_VTABLE))
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -595,6 +595,10 @@
for name, value in fields.items():
if isinstance(name, str):
setattr(container, name, value)
+ elif isinstance(value, dict):
+ item = container.getitem(name)
+ for key1, value1 in value.items():
+ setattr(item, key1, value1)
else:
container.setitem(name, value)
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -1,7 +1,7 @@
import sys, os
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
-from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
+from pypy.jit.metainterp.history import Const, Box, BoxInt, ConstInt
from pypy.jit.metainterp.history import (AbstractFailDescr, INT, REF, FLOAT,
LoopToken)
from pypy.rpython.lltypesystem import lltype, rffi, rstr, llmemory
@@ -36,7 +36,6 @@
from pypy.rlib import rgc
from pypy.rlib.clibffi import FFI_DEFAULT_ABI
from pypy.jit.backend.x86.jump import remap_frame_layout
-from pypy.jit.metainterp.history import ConstInt, BoxInt
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter import longlong
@@ -729,8 +728,8 @@
# Also, make sure this is consistent with FRAME_FIXED_SIZE.
self.mc.PUSH_r(ebp.value)
self.mc.MOV_rr(ebp.value, esp.value)
- for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
- self.mc.PUSH_r(regloc.value)
+ for loc in self.cpu.CALLEE_SAVE_REGISTERS:
+ self.mc.PUSH_r(loc.value)
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap and gcrootmap.is_shadow_stack:
@@ -994,7 +993,7 @@
effectinfo = op.getdescr().get_extra_info()
oopspecindex = effectinfo.oopspecindex
genop_llong_list[oopspecindex](self, op, arglocs, resloc)
-
+
def regalloc_perform_math(self, op, arglocs, resloc):
effectinfo = op.getdescr().get_extra_info()
oopspecindex = effectinfo.oopspecindex
@@ -1277,8 +1276,8 @@
genop_int_ne = _cmpop("NE", "NE")
genop_int_gt = _cmpop("G", "L")
genop_int_ge = _cmpop("GE", "LE")
- genop_ptr_eq = genop_int_eq
- genop_ptr_ne = genop_int_ne
+ genop_ptr_eq = genop_instance_ptr_eq = genop_int_eq
+ genop_ptr_ne = genop_instance_ptr_ne = genop_int_ne
genop_float_lt = _cmpop_float('B', 'A')
genop_float_le = _cmpop_float('BE', 'AE')
@@ -1298,8 +1297,8 @@
genop_guard_int_ne = _cmpop_guard("NE", "NE", "E", "E")
genop_guard_int_gt = _cmpop_guard("G", "L", "LE", "GE")
genop_guard_int_ge = _cmpop_guard("GE", "LE", "L", "G")
- genop_guard_ptr_eq = genop_guard_int_eq
- genop_guard_ptr_ne = genop_guard_int_ne
+ genop_guard_ptr_eq = genop_guard_instance_ptr_eq = genop_guard_int_eq
+ genop_guard_ptr_ne = genop_guard_instance_ptr_ne = genop_guard_int_ne
genop_guard_uint_gt = _cmpop_guard("A", "B", "BE", "AE")
genop_guard_uint_lt = _cmpop_guard("B", "A", "AE", "BE")
@@ -1311,7 +1310,7 @@
genop_guard_float_eq = _cmpop_guard_float("E", "E", "NE","NE")
genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE")
genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A")
-
+
def genop_math_sqrt(self, op, arglocs, resloc):
self.mc.SQRTSD(arglocs[0], resloc)
@@ -1387,7 +1386,8 @@
def genop_same_as(self, op, arglocs, resloc):
self.mov(arglocs[0], resloc)
- #genop_cast_ptr_to_int = genop_same_as
+ genop_cast_ptr_to_int = genop_same_as
+ genop_cast_int_to_ptr = genop_same_as
def genop_int_mod(self, op, arglocs, resloc):
if IS_X86_32:
@@ -1596,12 +1596,43 @@
genop_getarrayitem_gc_pure = genop_getarrayitem_gc
genop_getarrayitem_raw = genop_getarrayitem_gc
+ def _get_interiorfield_addr(self, temp_loc, index_loc, itemsize_loc,
+ base_loc, ofs_loc):
+ assert isinstance(itemsize_loc, ImmedLoc)
+ if isinstance(index_loc, ImmedLoc):
+ temp_loc = imm(index_loc.value * itemsize_loc.value)
+ else:
+ # XXX should not use IMUL in most cases
+ assert isinstance(temp_loc, RegLoc)
+ assert isinstance(index_loc, RegLoc)
+ self.mc.IMUL_rri(temp_loc.value, index_loc.value,
+ itemsize_loc.value)
+ assert isinstance(ofs_loc, ImmedLoc)
+ return AddressLoc(base_loc, temp_loc, 0, ofs_loc.value)
+
+ def genop_getinteriorfield_gc(self, op, arglocs, resloc):
+ (base_loc, ofs_loc, itemsize_loc, fieldsize_loc,
+ index_loc, sign_loc) = arglocs
+ src_addr = self._get_interiorfield_addr(resloc, index_loc,
+ itemsize_loc, base_loc,
+ ofs_loc)
+ self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
+
+
def genop_discard_setfield_gc(self, op, arglocs):
base_loc, ofs_loc, size_loc, value_loc = arglocs
assert isinstance(size_loc, ImmedLoc)
dest_addr = AddressLoc(base_loc, ofs_loc)
self.save_into_mem(dest_addr, value_loc, size_loc)
+ def genop_discard_setinteriorfield_gc(self, op, arglocs):
+ (base_loc, ofs_loc, itemsize_loc, fieldsize_loc,
+ index_loc, temp_loc, value_loc) = arglocs
+ dest_addr = self._get_interiorfield_addr(temp_loc, index_loc,
+ itemsize_loc, base_loc,
+ ofs_loc)
+ self.save_into_mem(dest_addr, value_loc, fieldsize_loc)
+
def genop_discard_setarrayitem_gc(self, op, arglocs):
base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs
assert isinstance(baseofs, ImmedLoc)
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -7,7 +7,7 @@
ResOperation, BoxPtr, ConstFloat,
BoxFloat, LoopToken, INT, REF, FLOAT)
from pypy.jit.backend.x86.regloc import *
-from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
+from pypy.rpython.lltypesystem import lltype, rffi, rstr
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib import rgc
from pypy.jit.backend.llsupport import symbolic
@@ -17,11 +17,12 @@
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr
from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
+from pypy.jit.backend.llsupport.descr import InteriorFieldDescr
from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
TempBox
from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS
-from pypy.rlib.rarithmetic import r_longlong, r_uint
+from pypy.rlib.rarithmetic import r_longlong
class X86RegisterManager(RegisterManager):
@@ -433,7 +434,7 @@
if self.can_merge_with_next_guard(op, i, operations):
oplist_with_guard[op.getopnum()](self, op, operations[i + 1])
i += 1
- elif not we_are_translated() and op.getopnum() == -124:
+ elif not we_are_translated() and op.getopnum() == -124:
self._consider_force_spill(op)
else:
oplist[op.getopnum()](self, op)
@@ -650,8 +651,8 @@
consider_uint_lt = _consider_compop
consider_uint_le = _consider_compop
consider_uint_ge = _consider_compop
- consider_ptr_eq = _consider_compop
- consider_ptr_ne = _consider_compop
+ consider_ptr_eq = consider_instance_ptr_eq = _consider_compop
+ consider_ptr_ne = consider_instance_ptr_ne = _consider_compop
def _consider_float_op(self, op):
loc1 = self.xrm.loc(op.getarg(1))
@@ -815,7 +816,7 @@
save_all_regs = guard_not_forced_op is not None
self.xrm.before_call(force_store, save_all_regs=save_all_regs)
if not save_all_regs:
- gcrootmap = gc_ll_descr = self.assembler.cpu.gc_ll_descr.gcrootmap
+ gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
if gcrootmap and gcrootmap.is_shadow_stack:
save_all_regs = 2
self.rm.before_call(force_store, save_all_regs=save_all_regs)
@@ -972,74 +973,27 @@
return self._call(op, arglocs)
def consider_newstr(self, op):
- gc_ll_descr = self.assembler.cpu.gc_ll_descr
- if gc_ll_descr.get_funcptr_for_newstr is not None:
- # framework GC
- loc = self.loc(op.getarg(0))
- return self._call(op, [loc])
- # boehm GC (XXX kill the following code at some point)
- ofs_items, itemsize, ofs = symbolic.get_array_token(rstr.STR, self.translate_support_code)
- assert itemsize == 1
- return self._malloc_varsize(ofs_items, ofs, 0, op.getarg(0),
- op.result)
+ loc = self.loc(op.getarg(0))
+ return self._call(op, [loc])
def consider_newunicode(self, op):
- gc_ll_descr = self.assembler.cpu.gc_ll_descr
- if gc_ll_descr.get_funcptr_for_newunicode is not None:
- # framework GC
- loc = self.loc(op.getarg(0))
- return self._call(op, [loc])
- # boehm GC (XXX kill the following code at some point)
- ofs_items, _, ofs = symbolic.get_array_token(rstr.UNICODE,
- self.translate_support_code)
- scale = self._get_unicode_item_scale()
- return self._malloc_varsize(ofs_items, ofs, scale, op.getarg(0),
- op.result)
-
- def _malloc_varsize(self, ofs_items, ofs_length, scale, v, res_v):
- # XXX kill this function at some point
- if isinstance(v, Box):
- loc = self.rm.make_sure_var_in_reg(v, [v])
- tempbox = TempBox()
- other_loc = self.rm.force_allocate_reg(tempbox, [v])
- self.assembler.load_effective_addr(loc, ofs_items,scale, other_loc)
- else:
- tempbox = None
- other_loc = imm(ofs_items + (v.getint() << scale))
- self._call(ResOperation(rop.NEW, [], res_v),
- [other_loc], [v])
- loc = self.rm.make_sure_var_in_reg(v, [res_v])
- assert self.loc(res_v) == eax
- # now we have to reload length to some reasonable place
- self.rm.possibly_free_var(v)
- if tempbox is not None:
- self.rm.possibly_free_var(tempbox)
- self.PerformDiscard(ResOperation(rop.SETFIELD_GC, [None, None], None),
- [eax, imm(ofs_length), imm(WORD), loc])
+ loc = self.loc(op.getarg(0))
+ return self._call(op, [loc])
def consider_new_array(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
- if gc_ll_descr.get_funcptr_for_newarray is not None:
- # framework GC
- box_num_elem = op.getarg(0)
- if isinstance(box_num_elem, ConstInt):
- num_elem = box_num_elem.value
- if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
- num_elem):
- self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
- return
- args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
- op.getdescr())
- arglocs = [imm(x) for x in args]
- arglocs.append(self.loc(box_num_elem))
- self._call(op, arglocs)
- return
- # boehm GC (XXX kill the following code at some point)
- itemsize, basesize, ofs_length, _, _ = (
- self._unpack_arraydescr(op.getdescr()))
- scale_of_field = _get_scale(itemsize)
- self._malloc_varsize(basesize, ofs_length, scale_of_field,
- op.getarg(0), op.result)
+ box_num_elem = op.getarg(0)
+ if isinstance(box_num_elem, ConstInt):
+ num_elem = box_num_elem.value
+ if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
+ num_elem):
+ self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
+ return
+ args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
+ op.getdescr())
+ arglocs = [imm(x) for x in args]
+ arglocs.append(self.loc(box_num_elem))
+ self._call(op, arglocs)
def _unpack_arraydescr(self, arraydescr):
assert isinstance(arraydescr, BaseArrayDescr)
@@ -1058,6 +1012,16 @@
sign = fielddescr.is_field_signed()
return imm(ofs), imm(size), ptr, sign
+ def _unpack_interiorfielddescr(self, descr):
+ assert isinstance(descr, InteriorFieldDescr)
+ arraydescr = descr.arraydescr
+ ofs = arraydescr.get_base_size(self.translate_support_code)
+ itemsize = arraydescr.get_item_size(self.translate_support_code)
+ fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+ sign = descr.fielddescr.is_field_signed()
+ ofs += descr.fielddescr.offset
+ return imm(ofs), imm(itemsize), imm(fieldsize), sign
+
def consider_setfield_gc(self, op):
ofs_loc, size_loc, _, _ = self._unpack_fielddescr(op.getdescr())
assert isinstance(size_loc, ImmedLoc)
@@ -1074,6 +1038,35 @@
consider_setfield_raw = consider_setfield_gc
+ def consider_setinteriorfield_gc(self, op):
+ t = self._unpack_interiorfielddescr(op.getdescr())
+ ofs, itemsize, fieldsize, _ = t
+ args = op.getarglist()
+ if fieldsize.value == 1:
+ need_lower_byte = True
+ else:
+ need_lower_byte = False
+ box_base, box_index, box_value = args
+ base_loc = self.rm.make_sure_var_in_reg(box_base, args)
+ index_loc = self.rm.make_sure_var_in_reg(box_index, args)
+ value_loc = self.make_sure_var_in_reg(box_value, args,
+ need_lower_byte=need_lower_byte)
+ # If 'index_loc' is not an immediate, then we need a 'temp_loc' that
+ # is a register whose value will be destroyed. It's fine to destroy
+ # the same register as 'index_loc', but not the other ones.
+ self.rm.possibly_free_var(box_index)
+ if not isinstance(index_loc, ImmedLoc):
+ tempvar = TempBox()
+ temp_loc = self.rm.force_allocate_reg(tempvar, [box_base,
+ box_value])
+ self.rm.possibly_free_var(tempvar)
+ else:
+ temp_loc = None
+ self.rm.possibly_free_var(box_base)
+ self.possibly_free_var(box_value)
+ self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize,
+ index_loc, temp_loc, value_loc])
+
def consider_strsetitem(self, op):
args = op.getarglist()
base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
@@ -1135,6 +1128,25 @@
consider_getarrayitem_raw = consider_getarrayitem_gc
consider_getarrayitem_gc_pure = consider_getarrayitem_gc
+ def consider_getinteriorfield_gc(self, op):
+ t = self._unpack_interiorfielddescr(op.getdescr())
+ ofs, itemsize, fieldsize, sign = t
+ if sign:
+ sign_loc = imm1
+ else:
+ sign_loc = imm0
+ args = op.getarglist()
+ base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
+ index_loc = self.rm.make_sure_var_in_reg(op.getarg(1), args)
+ # 'base' and 'index' are put in two registers (or one if 'index'
+ # is an immediate). 'result' can be in the same register as
+ # 'index' but must be in a different register than 'base'.
+ self.rm.possibly_free_var(op.getarg(1))
+ result_loc = self.force_allocate_reg(op.result, [op.getarg(0)])
+ self.rm.possibly_free_var(op.getarg(0))
+ self.Perform(op, [base_loc, ofs, itemsize, fieldsize,
+ index_loc, sign_loc], result_loc)
+
def consider_int_is_true(self, op, guard_op):
# doesn't need arg to be in a register
argloc = self.loc(op.getarg(0))
@@ -1152,7 +1164,8 @@
self.possibly_free_var(op.getarg(0))
resloc = self.force_allocate_reg(op.result)
self.Perform(op, [argloc], resloc)
- #consider_cast_ptr_to_int = consider_same_as
+ consider_cast_ptr_to_int = consider_same_as
+ consider_cast_int_to_ptr = consider_same_as
def consider_strlen(self, op):
args = op.getarglist()
@@ -1240,7 +1253,6 @@
self.rm.possibly_free_var(srcaddr_box)
def _gen_address_inside_string(self, baseloc, ofsloc, resloc, is_unicode):
- cpu = self.assembler.cpu
if is_unicode:
ofs_items, _, _ = symbolic.get_array_token(rstr.UNICODE,
self.translate_support_code)
@@ -1299,7 +1311,7 @@
tmpreg = X86RegisterManager.all_regs[0]
tmploc = self.rm.force_allocate_reg(box, selected_reg=tmpreg)
xmmtmp = X86XMMRegisterManager.all_regs[0]
- xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
+ self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
# Part about non-floats
# XXX we don't need a copy, we only just the original list
src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
@@ -1379,7 +1391,7 @@
return lambda self, op: fn(self, op, None)
def is_comparison_or_ovf_op(opnum):
- from pypy.jit.metainterp.resoperation import opclasses, AbstractResOp
+ from pypy.jit.metainterp.resoperation import opclasses
cls = opclasses[opnum]
# hack hack: in theory they are instance method, but they don't use
# any instance field, we can use a fake object
diff --git a/pypy/jit/backend/x86/test/test_del.py b/pypy/jit/backend/x86/test/test_del.py
--- a/pypy/jit/backend/x86/test/test_del.py
+++ b/pypy/jit/backend/x86/test/test_del.py
@@ -1,5 +1,4 @@
-import py
from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
from pypy.jit.metainterp.test.test_del import DelTests
diff --git a/pypy/jit/backend/x86/test/test_dict.py b/pypy/jit/backend/x86/test/test_dict.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/x86/test/test_dict.py
@@ -0,0 +1,9 @@
+
+from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
+from pypy.jit.metainterp.test.test_dict import DictTests
+
+
+class TestDict(Jit386Mixin, DictTests):
+ # for the individual tests see
+ # ====> ../../../metainterp/test/test_dict.py
+ pass
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -31,7 +31,7 @@
# for the individual tests see
# ====> ../../test/runner_test.py
-
+
def setup_method(self, meth):
self.cpu = CPU(rtyper=None, stats=FakeStats())
self.cpu.setup_once()
@@ -69,22 +69,16 @@
def test_allocations(self):
from pypy.rpython.lltypesystem import rstr
-
+
allocs = [None]
all = []
+ orig_new = self.cpu.gc_ll_descr.funcptr_for_new
def f(size):
allocs.insert(0, size)
- buf = ctypes.create_string_buffer(size)
- all.append(buf)
- return ctypes.cast(buf, ctypes.c_void_p).value
- func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f)
- addr = ctypes.cast(func, ctypes.c_void_p).value
- # ctypes produces an unsigned value. We need it to be signed for, eg,
- # relative addressing to work properly.
- addr = rffi.cast(lltype.Signed, addr)
-
+ return orig_new(size)
+
self.cpu.assembler.setup_once()
- self.cpu.assembler.malloc_func_addr = addr
+ self.cpu.gc_ll_descr.funcptr_for_new = f
ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
res = self.execute_operation(rop.NEWSTR, [ConstInt(7)], 'ref')
@@ -108,7 +102,7 @@
res = self.execute_operation(rop.NEW_ARRAY, [ConstInt(10)],
'ref', descr)
assert allocs[0] == 10*WORD + ofs + WORD
- resbuf = self._resbuf(res)
+ resbuf = self._resbuf(res)
assert resbuf[ofs/WORD] == 10
# ------------------------------------------------------------
@@ -116,7 +110,7 @@
res = self.execute_operation(rop.NEW_ARRAY, [BoxInt(10)],
'ref', descr)
assert allocs[0] == 10*WORD + ofs + WORD
- resbuf = self._resbuf(res)
+ resbuf = self._resbuf(res)
assert resbuf[ofs/WORD] == 10
def test_stringitems(self):
@@ -146,7 +140,7 @@
ConstInt(2), BoxInt(38)],
'void', descr)
assert resbuf[itemsofs/WORD + 2] == 38
-
+
self.execute_operation(rop.SETARRAYITEM_GC, [res,
BoxInt(3), BoxInt(42)],
'void', descr)
@@ -167,7 +161,7 @@
BoxInt(2)],
'int', descr)
assert r.value == 38
-
+
r = self.execute_operation(rop.GETARRAYITEM_GC, [res, BoxInt(3)],
'int', descr)
assert r.value == 42
@@ -226,7 +220,7 @@
self.execute_operation(rop.SETFIELD_GC, [res, BoxInt(1234)], 'void', ofs_i)
i = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_i)
assert i.value == 1234
-
+
#u = self.execute_operation(rop.GETFIELD_GC, [res, ofs_u], 'int')
#assert u.value == 5
self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(1)], 'void',
@@ -299,7 +293,7 @@
else:
assert result != execute(self.cpu, None,
op, None, b).value
-
+
def test_stuff_followed_by_guard(self):
boxes = [(BoxInt(1), BoxInt(0)),
@@ -523,7 +517,7 @@
def test_debugger_on(self):
from pypy.tool.logparser import parse_log_file, extract_category
from pypy.rlib import debug
-
+
loop = """
[i0]
debug_merge_point('xyz', 0)
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -52,9 +52,11 @@
newoperations = []
#
def do_rename(var, var_or_const):
+ if var.concretetype is lltype.Void:
+ renamings[var] = Constant(None, lltype.Void)
+ return
renamings[var] = var_or_const
- if (isinstance(var_or_const, Constant)
- and var.concretetype != lltype.Void):
+ if isinstance(var_or_const, Constant):
value = var_or_const.value
value = lltype._cast_whatever(var.concretetype, value)
renamings_constants[var] = Constant(value, var.concretetype)
@@ -441,6 +443,8 @@
rewrite_op_gc_identityhash = _do_builtin_call
rewrite_op_gc_id = _do_builtin_call
rewrite_op_uint_mod = _do_builtin_call
+ rewrite_op_cast_float_to_uint = _do_builtin_call
+ rewrite_op_cast_uint_to_float = _do_builtin_call
# ----------
# getfield/setfield/mallocs etc.
@@ -735,29 +739,54 @@
return SpaceOperation(opname, [op.args[0]], op.result)
def rewrite_op_getinteriorfield(self, op):
- # only supports strings and unicodes
assert len(op.args) == 3
- assert op.args[1].value == 'chars'
optype = op.args[0].concretetype
if optype == lltype.Ptr(rstr.STR):
opname = "strgetitem"
+ return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
+ elif optype == lltype.Ptr(rstr.UNICODE):
+ opname = "unicodegetitem"
+ return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
else:
- assert optype == lltype.Ptr(rstr.UNICODE)
- opname = "unicodegetitem"
- return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
+ v_inst, v_index, c_field = op.args
+ if op.result.concretetype is lltype.Void:
+ return
+ # only GcArray of Struct supported
+ assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
+ STRUCT = v_inst.concretetype.TO.OF
+ assert isinstance(STRUCT, lltype.Struct)
+ descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
+ c_field.value)
+ args = [v_inst, v_index, descr]
+ kind = getkind(op.result.concretetype)[0]
+ return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
+ op.result)
def rewrite_op_setinteriorfield(self, op):
- # only supports strings and unicodes
assert len(op.args) == 4
- assert op.args[1].value == 'chars'
optype = op.args[0].concretetype
if optype == lltype.Ptr(rstr.STR):
opname = "strsetitem"
+ return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
+ op.result)
+ elif optype == lltype.Ptr(rstr.UNICODE):
+ opname = "unicodesetitem"
+ return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
+ op.result)
else:
- assert optype == lltype.Ptr(rstr.UNICODE)
- opname = "unicodesetitem"
- return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
- op.result)
+ v_inst, v_index, c_field, v_value = op.args
+ if v_value.concretetype is lltype.Void:
+ return
+ # only GcArray of Struct supported
+ assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
+ STRUCT = v_inst.concretetype.TO.OF
+ assert isinstance(STRUCT, lltype.Struct)
+ descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
+ c_field.value)
+ kind = getkind(v_value.concretetype)[0]
+ args = [v_inst, v_index, v_value, descr]
+ return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
+ op.result)
def _rewrite_equality(self, op, opname):
arg0, arg1 = op.args
@@ -771,6 +800,9 @@
def _is_gc(self, v):
return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
+ def _is_rclass_instance(self, v):
+ return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
+
def _rewrite_cmp_ptrs(self, op):
if self._is_gc(op.args[0]):
return op
@@ -788,11 +820,21 @@
return self._rewrite_equality(op, 'int_is_true')
def rewrite_op_ptr_eq(self, op):
- op1 = self._rewrite_equality(op, 'ptr_iszero')
+ prefix = ''
+ if self._is_rclass_instance(op.args[0]):
+ assert self._is_rclass_instance(op.args[1])
+ op = SpaceOperation('instance_ptr_eq', op.args, op.result)
+ prefix = 'instance_'
+ op1 = self._rewrite_equality(op, prefix + 'ptr_iszero')
return self._rewrite_cmp_ptrs(op1)
def rewrite_op_ptr_ne(self, op):
- op1 = self._rewrite_equality(op, 'ptr_nonzero')
+ prefix = ''
+ if self._is_rclass_instance(op.args[0]):
+ assert self._is_rclass_instance(op.args[1])
+ op = SpaceOperation('instance_ptr_ne', op.args, op.result)
+ prefix = 'instance_'
+ op1 = self._rewrite_equality(op, prefix + 'ptr_nonzero')
return self._rewrite_cmp_ptrs(op1)
rewrite_op_ptr_iszero = _rewrite_cmp_ptrs
@@ -800,8 +842,11 @@
def rewrite_op_cast_ptr_to_int(self, op):
if self._is_gc(op.args[0]):
- #return op
- raise NotImplementedError("cast_ptr_to_int")
+ return op
+
+ def rewrite_op_cast_opaque_ptr(self, op):
+ # None causes the result of this op to get aliased to op.args[0]
+ return [SpaceOperation('mark_opaque_ptr', op.args, None), None]
def rewrite_op_force_cast(self, op):
v_arg = op.args[0]
@@ -822,26 +867,44 @@
elif not float_arg and float_res:
# some int -> some float
ops = []
- v1 = varoftype(lltype.Signed)
- oplist = self.rewrite_operation(
- SpaceOperation('force_cast', [v_arg], v1)
- )
- if oplist:
- ops.extend(oplist)
+ v2 = varoftype(lltype.Float)
+ sizesign = rffi.size_and_sign(v_arg.concretetype)
+ if sizesign <= rffi.size_and_sign(lltype.Signed):
+ # cast from a type that fits in an int: either the size is
+ # smaller, or it is equal and it is not unsigned
+ v1 = varoftype(lltype.Signed)
+ oplist = self.rewrite_operation(
+ SpaceOperation('force_cast', [v_arg], v1)
+ )
+ if oplist:
+ ops.extend(oplist)
+ else:
+ v1 = v_arg
+ op = self.rewrite_operation(
+ SpaceOperation('cast_int_to_float', [v1], v2)
+ )
+ ops.append(op)
else:
- v1 = v_arg
- v2 = varoftype(lltype.Float)
- op = self.rewrite_operation(
- SpaceOperation('cast_int_to_float', [v1], v2)
- )
- ops.append(op)
+ if sizesign == rffi.size_and_sign(lltype.Unsigned):
+ opname = 'cast_uint_to_float'
+ elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
+ opname = 'cast_longlong_to_float'
+ elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
+ opname = 'cast_ulonglong_to_float'
+ else:
+ raise AssertionError('cast_x_to_float: %r' % (sizesign,))
+ ops1 = self.rewrite_operation(
+ SpaceOperation(opname, [v_arg], v2)
+ )
+ if not isinstance(ops1, list): ops1 = [ops1]
+ ops.extend(ops1)
op2 = self.rewrite_operation(
SpaceOperation('force_cast', [v2], v_result)
)
if op2:
ops.append(op2)
else:
- op.result = v_result
+ ops[-1].result = v_result
return ops
elif float_arg and not float_res:
# some float -> some int
@@ -854,18 +917,36 @@
ops.append(op1)
else:
v1 = v_arg
- v2 = varoftype(lltype.Signed)
- op = self.rewrite_operation(
- SpaceOperation('cast_float_to_int', [v1], v2)
- )
- ops.append(op)
- oplist = self.rewrite_operation(
- SpaceOperation('force_cast', [v2], v_result)
- )
- if oplist:
- ops.extend(oplist)
+ sizesign = rffi.size_and_sign(v_result.concretetype)
+ if sizesign <= rffi.size_and_sign(lltype.Signed):
+ # cast to a type that fits in an int: either the size is
+ # smaller, or it is equal and it is not unsigned
+ v2 = varoftype(lltype.Signed)
+ op = self.rewrite_operation(
+ SpaceOperation('cast_float_to_int', [v1], v2)
+ )
+ ops.append(op)
+ oplist = self.rewrite_operation(
+ SpaceOperation('force_cast', [v2], v_result)
+ )
+ if oplist:
+ ops.extend(oplist)
+ else:
+ op.result = v_result
else:
- op.result = v_result
+ if sizesign == rffi.size_and_sign(lltype.Unsigned):
+ opname = 'cast_float_to_uint'
+ elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
+ opname = 'cast_float_to_longlong'
+ elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
+ opname = 'cast_float_to_ulonglong'
+ else:
+ raise AssertionError('cast_float_to_x: %r' % (sizesign,))
+ ops1 = self.rewrite_operation(
+ SpaceOperation(opname, [v1], v_result)
+ )
+ if not isinstance(ops1, list): ops1 = [ops1]
+ ops.extend(ops1)
return ops
else:
assert False
@@ -1071,8 +1152,6 @@
# The new operation is optionally further processed by rewrite_operation().
for _old, _new in [('bool_not', 'int_is_zero'),
('cast_bool_to_float', 'cast_int_to_float'),
- ('cast_uint_to_float', 'cast_int_to_float'),
- ('cast_float_to_uint', 'cast_float_to_int'),
('int_add_nonneg_ovf', 'int_add_ovf'),
('keepalive', '-live-'),
@@ -1543,6 +1622,10 @@
def rewrite_op_jit_force_virtual(self, op):
return self._do_builtin_call(op)
+ def rewrite_op_jit_is_virtual(self, op):
+ raise Exception, (
+ "'vref.virtual' should not be used from jit-visible code")
+
def rewrite_op_jit_force_virtualizable(self, op):
# this one is for virtualizables
vinfo = self.get_vinfo(op.args[0])
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -13,7 +13,6 @@
from pypy.translator.simplify import get_funcobj
from pypy.translator.unsimplify import split_block
from pypy.objspace.flow.model import Constant
-from pypy import conftest
from pypy.translator.translator import TranslationContext
from pypy.annotation.policy import AnnotatorPolicy
from pypy.annotation import model as annmodel
@@ -48,15 +47,13 @@
a.build_types(func, argtypes, main_entry_point=True)
rtyper = t.buildrtyper(type_system = type_system)
rtyper.specialize()
- if inline:
- auto_inlining(t, threshold=inline)
+ #if inline:
+ # auto_inlining(t, threshold=inline)
if backendoptimize:
from pypy.translator.backendopt.all import backend_optimizations
backend_optimizations(t, inline_threshold=inline or 0,
remove_asserts=True, really_remove_asserts=True)
- #if conftest.option.view:
- # t.view()
return rtyper
def getgraph(func, values):
@@ -232,6 +229,17 @@
else:
return x
+def _ll_1_cast_uint_to_float(x):
+ # XXX on 32-bit platforms, this should be done using cast_longlong_to_float
+ # (which is a residual call right now in the x86 backend)
+ return llop.cast_uint_to_float(lltype.Float, x)
+
+def _ll_1_cast_float_to_uint(x):
+ # XXX on 32-bit platforms, this should be done using cast_float_to_longlong
+ # (which is a residual call right now in the x86 backend)
+ return llop.cast_float_to_uint(lltype.Unsigned, x)
+
+
# math support
# ------------
@@ -456,6 +464,8 @@
return LLtypeHelpers._dictnext_items(lltype.Ptr(RES), iter)
_ll_1_dictiter_nextitems.need_result_type = True
+ _ll_1_dict_resize = ll_rdict.ll_dict_resize
+
# ---------- strings and unicode ----------
_ll_1_str_str2unicode = ll_rstr.LLHelpers.ll_str2unicode
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -8,7 +8,7 @@
from pypy.rpython.lltypesystem import lltype, rclass, rstr
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
from pypy.translator.unsimplify import varoftype
-from pypy.rlib.rarithmetic import ovfcheck, r_uint
+from pypy.rlib.rarithmetic import ovfcheck, r_uint, r_longlong, r_ulonglong
from pypy.rlib.jit import dont_look_inside, _we_are_jitted, JitDriver
from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rlib import jit
@@ -70,7 +70,8 @@
return 'residual'
def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
try:
- if 'cannot_raise' in op.args[0].value._obj.graph.name:
+ name = op.args[0].value._obj._name
+ if 'cannot_raise' in name or name.startswith('cast_'):
return self._descr_cannot_raise
except AttributeError:
pass
@@ -900,6 +901,67 @@
int_return %i4
""", transform=True)
+ def f(dbl):
+ return rffi.cast(rffi.UCHAR, dbl)
+ self.encoding_test(f, [12.456], """
+ cast_float_to_int %f0 -> %i0
+ int_and %i0, $255 -> %i1
+ int_return %i1
+ """, transform=True)
+
+ def f(dbl):
+ return rffi.cast(lltype.Unsigned, dbl)
+ self.encoding_test(f, [12.456], """
+ residual_call_irf_i $<* fn cast_float_to_uint>, <Descr>, I[], R[], F[%f0] -> %i0
+ int_return %i0
+ """, transform=True)
+
+ def f(i):
+ return rffi.cast(lltype.Float, chr(i)) # "char -> float"
+ self.encoding_test(f, [12], """
+ cast_int_to_float %i0 -> %f0
+ float_return %f0
+ """, transform=True)
+
+ def f(i):
+ return rffi.cast(lltype.Float, r_uint(i)) # "uint -> float"
+ self.encoding_test(f, [12], """
+ residual_call_irf_f $<* fn cast_uint_to_float>, <Descr>, I[%i0], R[], F[] -> %f0
+ float_return %f0
+ """, transform=True)
+
+ if not longlong.is_64_bit:
+ def f(dbl):
+ return rffi.cast(lltype.SignedLongLong, dbl)
+ self.encoding_test(f, [12.3], """
+ residual_call_irf_f $<* fn llong_from_float>, <Descr>, I[], R[], F[%f0] -> %f1
+ float_return %f1
+ """, transform=True)
+
+ def f(dbl):
+ return rffi.cast(lltype.UnsignedLongLong, dbl)
+ self.encoding_test(f, [12.3], """
+ residual_call_irf_f $<* fn ullong_from_float>, <Descr>, I[], R[], F[%f0] -> %f1
+ float_return %f1
+ """, transform=True)
+
+ def f(x):
+ ll = r_longlong(x)
+ return rffi.cast(lltype.Float, ll)
+ self.encoding_test(f, [12], """
+ residual_call_irf_f $<* fn llong_from_int>, <Descr>, I[%i0], R[], F[] -> %f0
+ residual_call_irf_f $<* fn llong_to_float>, <Descr>, I[], R[], F[%f0] -> %f1
+ float_return %f1
+ """, transform=True)
+
+ def f(x):
+ ll = r_ulonglong(x)
+ return rffi.cast(lltype.Float, ll)
+ self.encoding_test(f, [12], """
+ residual_call_irf_f $<* fn ullong_from_int>, <Descr>, I[%i0], R[], F[] -> %f0
+ residual_call_irf_f $<* fn ullong_u_to_float>, <Descr>, I[], R[], F[%f0] -> %f1
+ float_return %f1
+ """, transform=True)
def test_direct_ptradd(self):
from pypy.rpython.lltypesystem import rffi
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -1,4 +1,3 @@
-import py
import random
try:
from itertools import product
@@ -16,13 +15,13 @@
from pypy.objspace.flow.model import FunctionGraph, Block, Link
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
-from pypy.jit.codewriter.jtransform import Transformer
-from pypy.jit.metainterp.history import getkind
-from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rlist
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
from pypy.rpython.lltypesystem.module import ll_math
from pypy.translator.unsimplify import varoftype
from pypy.jit.codewriter import heaptracker, effectinfo
from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.jtransform import Transformer
+from pypy.jit.metainterp.history import getkind
def const(x):
return Constant(x, lltype.typeOf(x))
@@ -37,6 +36,8 @@
return ('calldescr', FUNC, ARGS, RESULT)
def fielddescrof(self, STRUCT, name):
return ('fielddescr', STRUCT, name)
+ def interiorfielddescrof(self, ARRAY, name):
+ return ('interiorfielddescr', ARRAY, name)
def arraydescrof(self, ARRAY):
return FakeDescr(('arraydescr', ARRAY))
def sizeof(self, STRUCT):
@@ -539,7 +540,7 @@
def test_rename_on_links():
v1 = Variable()
- v2 = Variable()
+ v2 = Variable(); v2.concretetype = llmemory.Address
v3 = Variable()
block = Block([v1])
block.operations = [SpaceOperation('cast_pointer', [v1], v2)]
@@ -575,10 +576,10 @@
assert op1.args == [v2]
def test_ptr_eq():
- v1 = varoftype(rclass.OBJECTPTR)
- v2 = varoftype(rclass.OBJECTPTR)
+ v1 = varoftype(lltype.Ptr(rstr.STR))
+ v2 = varoftype(lltype.Ptr(rstr.STR))
v3 = varoftype(lltype.Bool)
- c0 = const(lltype.nullptr(rclass.OBJECT))
+ c0 = const(lltype.nullptr(rstr.STR))
#
for opname, reducedname in [('ptr_eq', 'ptr_iszero'),
('ptr_ne', 'ptr_nonzero')]:
@@ -597,6 +598,31 @@
assert op1.opname == reducedname
assert op1.args == [v2]
+def test_instance_ptr_eq():
+ v1 = varoftype(rclass.OBJECTPTR)
+ v2 = varoftype(rclass.OBJECTPTR)
+ v3 = varoftype(lltype.Bool)
+ c0 = const(lltype.nullptr(rclass.OBJECT))
+
+ for opname, newopname, reducedname in [
+ ('ptr_eq', 'instance_ptr_eq', 'instance_ptr_iszero'),
+ ('ptr_ne', 'instance_ptr_ne', 'instance_ptr_nonzero')
+ ]:
+ op = SpaceOperation(opname, [v1, v2], v3)
+ op1 = Transformer().rewrite_operation(op)
+ assert op1.opname == newopname
+ assert op1.args == [v1, v2]
+
+ op = SpaceOperation(opname, [v1, c0], v3)
+ op1 = Transformer().rewrite_operation(op)
+ assert op1.opname == reducedname
+ assert op1.args == [v1]
+
+ op = SpaceOperation(opname, [c0, v1], v3)
+ op1 = Transformer().rewrite_operation(op)
+ assert op1.opname == reducedname
+ assert op1.args == [v1]
+
def test_nongc_ptr_eq():
v1 = varoftype(rclass.NONGCOBJECTPTR)
v2 = varoftype(rclass.NONGCOBJECTPTR)
@@ -676,6 +702,22 @@
assert op1.args == [v, v_index]
assert op1.result == v_result
+def test_dict_getinteriorfield():
+ DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
+ ('k', lltype.Signed)))
+ v = varoftype(lltype.Ptr(DICT))
+ i = varoftype(lltype.Signed)
+ v_result = varoftype(lltype.Signed)
+ op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
+ v_result)
+ op1 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'getinteriorfield_gc_i'
+ assert op1.args == [v, i, ('interiorfielddescr', DICT, 'v')]
+ op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
+ Constant(None, lltype.Void))
+ op1 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1 is None
+
def test_str_setinteriorfield():
v = varoftype(lltype.Ptr(rstr.STR))
v_index = varoftype(lltype.Signed)
@@ -702,6 +744,23 @@
assert op1.args == [v, v_index, v_newchr]
assert op1.result == v_void
+def test_dict_setinteriorfield():
+ DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
+ ('k', lltype.Signed)))
+ v = varoftype(lltype.Ptr(DICT))
+ i = varoftype(lltype.Signed)
+ v_void = varoftype(lltype.Void)
+ op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
+ i],
+ v_void)
+ op1 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert op1.opname == 'setinteriorfield_gc_i'
+ assert op1.args == [v, i, i, ('interiorfielddescr', DICT, 'v')]
+ op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
+ v_void], v_void)
+ op1 = Transformer(FakeCPU()).rewrite_operation(op)
+ assert not op1
+
def test_promote_1():
v1 = varoftype(lltype.Signed)
v2 = varoftype(lltype.Signed)
@@ -1069,3 +1128,16 @@
varoftype(lltype.Signed))
tr = Transformer(None, None)
raises(NotImplementedError, tr.rewrite_operation, op)
+
+def test_cast_opaque_ptr():
+ S = lltype.GcStruct("S", ("x", lltype.Signed))
+ v1 = varoftype(lltype.Ptr(S))
+ v2 = varoftype(lltype.Ptr(rclass.OBJECT))
+
+ op = SpaceOperation('cast_opaque_ptr', [v1], v2)
+ tr = Transformer()
+ [op1, op2] = tr.rewrite_operation(op)
+ assert op1.opname == 'mark_opaque_ptr'
+ assert op1.args == [v1]
+ assert op1.result is None
+ assert op2 is None
\ No newline at end of file
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -2,11 +2,10 @@
from pypy.rlib.rtimer import read_timestamp
from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import debug_start, debug_stop
+from pypy.rlib.debug import debug_start, debug_stop, ll_assert
from pypy.rlib.debug import make_sure_not_resized
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.llinterp import LLException
from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
from pypy.jit.codewriter import heaptracker, longlong
from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
@@ -500,9 +499,25 @@
@arguments("r", returns="i")
def bhimpl_ptr_nonzero(a):
return bool(a)
- @arguments("r", returns="r")
- def bhimpl_cast_opaque_ptr(a):
- return a
+ @arguments("r", "r", returns="i")
+ def bhimpl_instance_ptr_eq(a, b):
+ return a == b
+ @arguments("r", "r", returns="i")
+ def bhimpl_instance_ptr_ne(a, b):
+ return a != b
+ @arguments("r", returns="i")
+ def bhimpl_cast_ptr_to_int(a):
+ i = lltype.cast_ptr_to_int(a)
+ ll_assert((i & 1) == 1, "bhimpl_cast_ptr_to_int: not an odd int")
+ return i
+ @arguments("i", returns="r")
+ def bhimpl_cast_int_to_ptr(i):
+ ll_assert((i & 1) == 1, "bhimpl_cast_int_to_ptr: not an odd int")
+ return lltype.cast_int_to_ptr(llmemory.GCREF, i)
+
+ @arguments("r")
+ def bhimpl_mark_opaque_ptr(a):
+ pass
@arguments("i", returns="i")
def bhimpl_int_copy(a):
@@ -622,6 +637,9 @@
a = longlong.getrealfloat(a)
# note: we need to call int() twice to care for the fact that
# int(-2147483648.0) returns a long :-(
+ # we could also call intmask() instead of the outermost int(), but
+ # it's probably better to explicitly crash (by getting a long) if a
+ # non-translated version tries to cast a too large float to an int.
return int(int(a))
@arguments("i", returns="f")
@@ -1145,6 +1163,26 @@
array = cpu.bh_getfield_gc_r(vable, fdescr)
return cpu.bh_arraylen_gc(adescr, array)
+ @arguments("cpu", "r", "i", "d", returns="i")
+ def bhimpl_getinteriorfield_gc_i(cpu, array, index, descr):
+ return cpu.bh_getinteriorfield_gc_i(array, index, descr)
+ @arguments("cpu", "r", "i", "d", returns="r")
+ def bhimpl_getinteriorfield_gc_r(cpu, array, index, descr):
+ return cpu.bh_getinteriorfield_gc_r(array, index, descr)
+ @arguments("cpu", "r", "i", "d", returns="f")
+ def bhimpl_getinteriorfield_gc_f(cpu, array, index, descr):
+ return cpu.bh_getinteriorfield_gc_f(array, index, descr)
+
+ @arguments("cpu", "r", "i", "d", "i")
+ def bhimpl_setinteriorfield_gc_i(cpu, array, index, descr, value):
+ cpu.bh_setinteriorfield_gc_i(array, index, descr, value)
+ @arguments("cpu", "r", "i", "d", "r")
+ def bhimpl_setinteriorfield_gc_r(cpu, array, index, descr, value):
+ cpu.bh_setinteriorfield_gc_r(array, index, descr, value)
+ @arguments("cpu", "r", "i", "d", "f")
+ def bhimpl_setinteriorfield_gc_f(cpu, array, index, descr, value):
+ cpu.bh_setinteriorfield_gc_f(array, index, descr, value)
+
@arguments("cpu", "r", "d", returns="i")
def bhimpl_getfield_gc_i(cpu, struct, fielddescr):
return cpu.bh_getfield_gc_i(struct, fielddescr)
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -1,11 +1,8 @@
"""This implements pyjitpl's execution of operations.
"""
-import py
-from pypy.rpython.lltypesystem import lltype, llmemory, rstr
-from pypy.rpython.ootypesystem import ootype
-from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask, r_longlong
+from pypy.rpython.lltypesystem import lltype, rstr
+from pypy.rlib.rarithmetic import ovfcheck, r_longlong
from pypy.rlib.rtimer import read_timestamp
from pypy.rlib.unroll import unrolling_iterable
from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr
@@ -123,6 +120,29 @@
else:
cpu.bh_setarrayitem_raw_i(arraydescr, array, index, itembox.getint())
+def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, descr):
+ array = arraybox.getref_base()
+ index = indexbox.getint()
+ if descr.is_pointer_field():
+ return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, descr))
+ elif descr.is_float_field():
+ return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, descr))
+ else:
+ return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))
+
+def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr):
+ array = arraybox.getref_base()
+ index = indexbox.getint()
+ if descr.is_pointer_field():
+ cpu.bh_setinteriorfield_gc_r(array, index, descr,
+ valuebox.getref_base())
+ elif descr.is_float_field():
+ cpu.bh_setinteriorfield_gc_f(array, index, descr,
+ valuebox.getfloatstorage())
+ else:
+ cpu.bh_setinteriorfield_gc_i(array, index, descr,
+ valuebox.getint())
+
def do_getfield_gc(cpu, _, structbox, fielddescr):
struct = structbox.getref_base()
if fielddescr.is_pointer_field():
diff --git a/pypy/jit/metainterp/graphpage.py b/pypy/jit/metainterp/graphpage.py
--- a/pypy/jit/metainterp/graphpage.py
+++ b/pypy/jit/metainterp/graphpage.py
@@ -12,8 +12,8 @@
def get_display_text(self):
return None
-def display_loops(loops, errmsg=None, highlight_loops=()):
- graphs = [(loop, loop in highlight_loops) for loop in loops]
+def display_loops(loops, errmsg=None, highlight_loops={}):
+ graphs = [(loop, highlight_loops.get(loop, 0)) for loop in loops]
for graph, highlight in graphs:
for op in graph.get_operations():
if is_interesting_guard(op):
@@ -65,8 +65,7 @@
def add_graph(self, graph, highlight=False):
graphindex = len(self.graphs)
self.graphs.append(graph)
- if highlight:
- self.highlight_graphs[graph] = True
+ self.highlight_graphs[graph] = highlight
for i, op in enumerate(graph.get_operations()):
self.all_operations[op] = graphindex, i
@@ -126,10 +125,13 @@
self.dotgen.emit('subgraph cluster%d {' % graphindex)
label = graph.get_display_text()
if label is not None:
- if self.highlight_graphs.get(graph):
- fillcolor = '#f084c2'
+ colorindex = self.highlight_graphs.get(graph, 0)
+ if colorindex == 1:
+ fillcolor = '#f084c2' # highlighted graph
+ elif colorindex == 2:
+ fillcolor = '#808080' # invalidated graph
else:
- fillcolor = '#84f0c2'
+ fillcolor = '#84f0c2' # normal color
self.dotgen.emit_node(graphname, shape="octagon",
label=label, fillcolor=fillcolor)
self.pendingedges.append((graphname,
diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py
--- a/pypy/jit/metainterp/heapcache.py
+++ b/pypy/jit/metainterp/heapcache.py
@@ -34,7 +34,6 @@
self.clear_caches(opnum, descr, argboxes)
def mark_escaped(self, opnum, argboxes):
- idx = 0
if opnum == rop.SETFIELD_GC:
assert len(argboxes) == 2
box, valuebox = argboxes
@@ -42,8 +41,20 @@
self.dependencies.setdefault(box, []).append(valuebox)
else:
self._escape(valuebox)
- # GETFIELD_GC doesn't escape it's argument
- elif opnum != rop.GETFIELD_GC:
+ elif opnum == rop.SETARRAYITEM_GC:
+ assert len(argboxes) == 3
+ box, indexbox, valuebox = argboxes
+ if self.is_unescaped(box) and self.is_unescaped(valuebox):
+ self.dependencies.setdefault(box, []).append(valuebox)
+ else:
+ self._escape(valuebox)
+ # GETFIELD_GC, MARK_OPAQUE_PTR, PTR_EQ, and PTR_NE don't escape their
+ # arguments
+ elif (opnum != rop.GETFIELD_GC and
+ opnum != rop.MARK_OPAQUE_PTR and
+ opnum != rop.PTR_EQ and
+ opnum != rop.PTR_NE):
+ idx = 0
for box in argboxes:
# setarrayitem_gc don't escape its first argument
if not (idx == 0 and opnum in [rop.SETARRAYITEM_GC]):
@@ -60,13 +71,13 @@
self._escape(dep)
def clear_caches(self, opnum, descr, argboxes):
- if opnum == rop.SETFIELD_GC:
- return
- if opnum == rop.SETARRAYITEM_GC:
- return
- if opnum == rop.SETFIELD_RAW:
- return
- if opnum == rop.SETARRAYITEM_RAW:
+ if (opnum == rop.SETFIELD_GC or
+ opnum == rop.SETARRAYITEM_GC or
+ opnum == rop.SETFIELD_RAW or
+ opnum == rop.SETARRAYITEM_RAW or
+ opnum == rop.SETINTERIORFIELD_GC or
+ opnum == rop.COPYSTRCONTENT or
+ opnum == rop.COPYUNICODECONTENT):
return
if rop._OVF_FIRST <= opnum <= rop._OVF_LAST:
return
@@ -75,9 +86,9 @@
if opnum == rop.CALL or opnum == rop.CALL_LOOPINVARIANT:
effectinfo = descr.get_extra_info()
ef = effectinfo.extraeffect
- if ef == effectinfo.EF_LOOPINVARIANT or \
- ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \
- ef == effectinfo.EF_ELIDABLE_CAN_RAISE:
+ if (ef == effectinfo.EF_LOOPINVARIANT or
+ ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or
+ ef == effectinfo.EF_ELIDABLE_CAN_RAISE):
return
# A special case for ll_arraycopy, because it is so common, and its
# effects are so well defined.
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -16,6 +16,7 @@
INT = 'i'
REF = 'r'
FLOAT = 'f'
+STRUCT = 's'
HOLE = '_'
VOID = 'v'
@@ -172,6 +173,11 @@
"""
raise NotImplementedError
+ def is_array_of_structs(self):
+ """ Implement for array descr
+ """
+ raise NotImplementedError
+
def is_pointer_field(self):
""" Implement for field descr
"""
@@ -732,6 +738,7 @@
failed_states = None
retraced_count = 0
terminating = False # see TerminatingLoopToken in compile.py
+ invalidated = False
outermost_jitdriver_sd = None
# and more data specified by the backend when the loop is compiled
number = -1
@@ -934,6 +941,7 @@
self.loops = []
self.locations = []
self.aborted_keys = []
+ self.invalidated_token_numbers = set()
def set_history(self, history):
self.operations = history.operations
@@ -1012,7 +1020,12 @@
if loop in loops:
loops.remove(loop)
loops.append(loop)
- display_loops(loops, errmsg, extraloops)
+ highlight_loops = dict.fromkeys(extraloops, 1)
+ for loop in loops:
+ if hasattr(loop, '_looptoken_number') and (
+ loop._looptoken_number in self.invalidated_token_numbers):
+ highlight_loops.setdefault(loop, 2)
+ display_loops(loops, errmsg, highlight_loops)
# ----------------------------------------------------------------
diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -68,7 +68,8 @@
debug_print("Loop tokens before:", oldtotal)
max_generation = self.current_generation - (self.max_age-1)
for looptoken in self.alive_loops.keys():
- if 0 <= looptoken.generation < max_generation:
+ if (0 <= looptoken.generation < max_generation or
+ looptoken.invalidated):
del self.alive_loops[looptoken]
newtotal = len(self.alive_loops)
debug_print("Loop tokens freed: ", oldtotal - newtotal)
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -209,13 +209,19 @@
def setfield(self, ofs, value):
raise NotImplementedError
+ def getlength(self):
+ raise NotImplementedError
+
def getitem(self, index):
raise NotImplementedError
- def getlength(self):
+ def setitem(self, index, value):
raise NotImplementedError
- def setitem(self, index, value):
+ def getinteriorfield(self, index, ofs, default):
+ raise NotImplementedError
+
+ def setinteriorfield(self, index, ofs, value):
raise NotImplementedError
@@ -283,11 +289,11 @@
return self.optimizer.optpure.has_pure_result(opnum, args, descr)
return False
- def get_pure_result(self, key):
+ def get_pure_result(self, key):
if self.optimizer.optpure:
return self.optimizer.optpure.get_pure_result(key)
return None
-
+
def setup(self):
pass
@@ -524,7 +530,7 @@
def replace_op(self, old_op, new_op):
# XXX: Do we want to cache indexes to prevent search?
- i = len(self._newoperations)
+ i = len(self._newoperations)
while i > 0:
i -= 1
if self._newoperations[i] is old_op:
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -106,10 +106,9 @@
self.make_equal_to(op.result, v1)
else:
self.emit_operation(op)
-
- # Synthesize the reverse ops for optimize_default to reuse
- self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
- self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
+ # Synthesize the reverse ops for optimize_default to reuse
+ self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
+ self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
def optimize_INT_ADD(self, op):
v1 = self.getvalue(op.getarg(0))
@@ -122,10 +121,9 @@
self.make_equal_to(op.result, v1)
else:
self.emit_operation(op)
-
- # Synthesize the reverse op for optimize_default to reuse
- self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
- self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
+ # Synthesize the reverse op for optimize_default to reuse
+ self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
+ self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
def optimize_INT_MUL(self, op):
v1 = self.getvalue(op.getarg(0))
@@ -141,13 +139,13 @@
self.make_constant_int(op.result, 0)
else:
for lhs, rhs in [(v1, v2), (v2, v1)]:
- # x & (x -1) == 0 is a quick test for power of 2
- if (lhs.is_constant() and
- (lhs.box.getint() & (lhs.box.getint() - 1)) == 0):
- new_rhs = ConstInt(highest_bit(lhs.box.getint()))
- op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs])
- break
-
+ if lhs.is_constant():
+ x = lhs.box.getint()
+ # x & (x - 1) == 0 is a quick test for power of 2
+ if x & (x - 1) == 0:
+ new_rhs = ConstInt(highest_bit(lhs.box.getint()))
+ op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs])
+ break
self.emit_operation(op)
def optimize_UINT_FLOORDIV(self, op):
@@ -339,7 +337,7 @@
def optimize_INT_IS_ZERO(self, op):
self._optimize_nullness(op, op.getarg(0), False)
- def _optimize_oois_ooisnot(self, op, expect_isnot):
+ def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
value0 = self.getvalue(op.getarg(0))
value1 = self.getvalue(op.getarg(1))
if value0.is_virtual():
@@ -357,21 +355,28 @@
elif value0 is value1:
self.make_constant_int(op.result, not expect_isnot)
else:
- cls0 = value0.get_constant_class(self.optimizer.cpu)
- if cls0 is not None:
- cls1 = value1.get_constant_class(self.optimizer.cpu)
- if cls1 is not None and not cls0.same_constant(cls1):
- # cannot be the same object, as we know that their
- # class is different
- self.make_constant_int(op.result, expect_isnot)
- return
+ if instance:
+ cls0 = value0.get_constant_class(self.optimizer.cpu)
+ if cls0 is not None:
+ cls1 = value1.get_constant_class(self.optimizer.cpu)
+ if cls1 is not None and not cls0.same_constant(cls1):
+ # cannot be the same object, as we know that their
+ # class is different
+ self.make_constant_int(op.result, expect_isnot)
+ return
self.emit_operation(op)
+ def optimize_PTR_EQ(self, op):
+ self._optimize_oois_ooisnot(op, False, False)
+
def optimize_PTR_NE(self, op):
- self._optimize_oois_ooisnot(op, True)
+ self._optimize_oois_ooisnot(op, True, False)
- def optimize_PTR_EQ(self, op):
- self._optimize_oois_ooisnot(op, False)
+ def optimize_INSTANCE_PTR_EQ(self, op):
+ self._optimize_oois_ooisnot(op, False, True)
+
+ def optimize_INSTANCE_PTR_NE(self, op):
+ self._optimize_oois_ooisnot(op, True, True)
## def optimize_INSTANCEOF(self, op):
## value = self.getvalue(op.args[0])
@@ -450,6 +455,9 @@
if v2.is_constant() and v2.box.getint() == 1:
self.make_equal_to(op.result, v1)
return
+ elif v1.is_constant() and v1.box.getint() == 0:
+ self.make_constant_int(op.result, 0)
+ return
if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant():
val = v2.box.getint()
if val & (val - 1) == 0 and val > 0: # val == 2**shift
@@ -457,10 +465,17 @@
args = [op.getarg(0), ConstInt(highest_bit(val))])
self.emit_operation(op)
- def optimize_CAST_OPAQUE_PTR(self, op):
+ def optimize_MARK_OPAQUE_PTR(self, op):
value = self.getvalue(op.getarg(0))
self.optimizer.opaque_pointers[value] = True
- self.make_equal_to(op.result, value)
+
+ def optimize_CAST_PTR_TO_INT(self, op):
+ self.pure(rop.CAST_INT_TO_PTR, [op.result], op.getarg(0))
+ self.emit_operation(op)
+
+ def optimize_CAST_INT_TO_PTR(self, op):
+ self.pure(rop.CAST_PTR_TO_INT, [op.result], op.getarg(0))
+ self.emit_operation(op)
dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
default=OptRewrite.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -25,7 +25,8 @@
# but it's a bit hard to implement robustly if heap.py is also run
pass
- optimize_CAST_OPAQUE_PTR = optimize_VIRTUAL_REF
+ def optimize_MARK_OPAQUE_PTR(self, op):
+ pass
dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -508,13 +508,13 @@
ops = """
[p0]
guard_class(p0, ConstClass(node_vtable)) []
- i0 = ptr_ne(p0, NULL)
+ i0 = instance_ptr_ne(p0, NULL)
guard_true(i0) []
- i1 = ptr_eq(p0, NULL)
+ i1 = instance_ptr_eq(p0, NULL)
guard_false(i1) []
- i2 = ptr_ne(NULL, p0)
+ i2 = instance_ptr_ne(NULL, p0)
guard_true(i0) []
- i3 = ptr_eq(NULL, p0)
+ i3 = instance_ptr_eq(NULL, p0)
guard_false(i1) []
jump(p0)
"""
@@ -935,7 +935,6 @@
"""
self.optimize_loop(ops, expected)
-
def test_virtual_constant_isnonnull(self):
ops = """
[i0]
@@ -951,6 +950,32 @@
"""
self.optimize_loop(ops, expected)
+ def test_virtual_array_of_struct(self):
+ ops = """
+ [f0, f1, f2, f3]
+ p0 = new_array(2, descr=complexarraydescr)
+ setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
+ setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
+ setinteriorfield_gc(p0, 1, f2, descr=complexrealdescr)
+ setinteriorfield_gc(p0, 1, f3, descr=compleximagdescr)
+ f4 = getinteriorfield_gc(p0, 0, descr=complexrealdescr)
+ f5 = getinteriorfield_gc(p0, 1, descr=complexrealdescr)
+ f6 = float_mul(f4, f5)
+ f7 = getinteriorfield_gc(p0, 0, descr=compleximagdescr)
+ f8 = getinteriorfield_gc(p0, 1, descr=compleximagdescr)
+ f9 = float_mul(f7, f8)
+ f10 = float_add(f6, f9)
+ finish(f10)
+ """
+ expected = """
+ [f0, f1, f2, f3]
+ f4 = float_mul(f0, f2)
+ f5 = float_mul(f1, f3)
+ f6 = float_add(f4, f5)
+ finish(f6)
+ """
+ self.optimize_loop(ops, expected)
+
def test_nonvirtual_1(self):
ops = """
[i]
@@ -2026,7 +2051,7 @@
ops = """
[p1]
guard_class(p1, ConstClass(node_vtable2)) []
- i = ptr_ne(ConstPtr(myptr), p1)
+ i = instance_ptr_ne(ConstPtr(myptr), p1)
guard_true(i) []
jump(p1)
"""
@@ -2181,6 +2206,17 @@
"""
self.optimize_loop(ops, expected)
+ ops = """
+ [i0]
+ i1 = int_floordiv(0, i0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_fold_partially_constant_ops_ovf(self):
ops = """
[i0]
@@ -4170,10 +4206,12 @@
class FakeCallInfoCollection:
def callinfo_for_oopspec(self, oopspecindex):
calldescrtype = type(LLtypeMixin.strequaldescr)
+ effectinfotype = type(LLtypeMixin.strequaldescr.get_extra_info())
for value in LLtypeMixin.__dict__.values():
if isinstance(value, calldescrtype):
extra = value.get_extra_info()
- if extra and extra.oopspecindex == oopspecindex:
+ if (extra and isinstance(extra, effectinfotype) and
+ extra.oopspecindex == oopspecindex):
# returns 0 for 'func' in this test
return value, 0
raise AssertionError("not found: oopspecindex=%d" %
@@ -4789,6 +4827,18 @@
"""
self.optimize_strunicode_loop(ops, expected)
+ def test_ptr_eq_str_constant(self):
+ ops = """
+ []
+ i0 = ptr_eq(s"abc", s"\x00")
+ finish(i0)
+ """
+ expected = """
+ []
+ finish(0)
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -234,6 +234,30 @@
""" % expected_value
self.optimize_loop(ops, expected)
+ def test_reverse_of_cast(self):
+ ops = """
+ [i0]
+ p0 = cast_int_to_ptr(i0)
+ i1 = cast_ptr_to_int(p0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+ ops = """
+ [p0]
+ i1 = cast_ptr_to_int(p0)
+ p1 = cast_int_to_ptr(i1)
+ jump(p1)
+ """
+ expected = """
+ [p0]
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
# ----------
def test_remove_guard_class_1(self):
@@ -2659,7 +2683,7 @@
ops = """
[p1]
guard_class(p1, ConstClass(node_vtable2)) []
- i = ptr_ne(ConstPtr(myptr), p1)
+ i = instance_ptr_ne(ConstPtr(myptr), p1)
guard_true(i) []
jump(p1)
"""
@@ -3307,7 +3331,7 @@
jump(p1, i1, i2, i6)
'''
self.optimize_loop(ops, expected, preamble)
-
+
# ----------
@@ -5776,10 +5800,12 @@
class FakeCallInfoCollection:
def callinfo_for_oopspec(self, oopspecindex):
calldescrtype = type(LLtypeMixin.strequaldescr)
+ effectinfotype = type(LLtypeMixin.strequaldescr.get_extra_info())
for value in LLtypeMixin.__dict__.values():
if isinstance(value, calldescrtype):
extra = value.get_extra_info()
- if extra and extra.oopspecindex == oopspecindex:
+ if (extra and isinstance(extra, effectinfotype) and
+ extra.oopspecindex == oopspecindex):
# returns 0 for 'func' in this test
return value, 0
raise AssertionError("not found: oopspecindex=%d" %
@@ -7256,7 +7282,7 @@
ops = """
[p1, p2]
setarrayitem_gc(p1, 2, 10, descr=arraydescr)
- setarrayitem_gc(p2, 3, 13, descr=arraydescr)
+ setarrayitem_gc(p2, 3, 13, descr=arraydescr)
call(0, p1, p2, 0, 0, 10, descr=arraycopydescr)
jump(p1, p2)
"""
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -185,6 +185,18 @@
EffectInfo([], [arraydescr], [], [arraydescr],
oopspecindex=EffectInfo.OS_ARRAYCOPY))
+
+ # array of structs (complex data)
+ complexarray = lltype.GcArray(
+ lltype.Struct("complex",
+ ("real", lltype.Float),
+ ("imag", lltype.Float),
+ )
+ )
+ complexarraydescr = cpu.arraydescrof(complexarray)
+ complexrealdescr = cpu.interiorfielddescrof(complexarray, "real")
+ compleximagdescr = cpu.interiorfielddescrof(complexarray, "imag")
+
for _name, _os in [
('strconcatdescr', 'OS_STR_CONCAT'),
('strslicedescr', 'OS_STR_SLICE'),
@@ -240,7 +252,7 @@
## def get_class_of_box(self, box):
## root = box.getref(ootype.ROOT)
## return ootype.classof(root)
-
+
## cpu = runner.OOtypeCPU(None)
## NODE = ootype.Instance('NODE', ootype.ROOT, {})
## NODE._add_fields({'value': ootype.Signed,
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -59,7 +59,7 @@
def import_from(self, other, optimizer):
raise NotImplementedError("should not be called at this level")
-
+
def get_fielddescrlist_cache(cpu):
if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
result = descrlist_dict()
@@ -113,7 +113,7 @@
#
if not we_are_translated():
op.name = 'FORCE ' + self.source_op.name
-
+
if self._is_immutable_and_filled_with_constants(optforce):
box = optforce.optimizer.constant_fold(op)
self.make_constant(box)
@@ -239,12 +239,12 @@
for index in range(len(self._items)):
self._items[index] = self._items[index].force_at_end_of_preamble(already_forced, optforce)
return self
-
+
def _really_force(self, optforce):
assert self.source_op is not None
if not we_are_translated():
self.source_op.name = 'FORCE ' + self.source_op.name
- optforce.emit_operation(self.source_op)
+ optforce.emit_operation(self.source_op)
self.box = box = self.source_op.result
for index in range(len(self._items)):
subvalue = self._items[index]
@@ -271,20 +271,86 @@
def _make_virtual(self, modifier):
return modifier.make_varray(self.arraydescr)
+class VArrayStructValue(AbstractVirtualValue):
+ def __init__(self, arraydescr, size, keybox, source_op=None):
+ AbstractVirtualValue.__init__(self, keybox, source_op)
+ self.arraydescr = arraydescr
+ self._items = [{} for _ in xrange(size)]
+
+ def getlength(self):
+ return len(self._items)
+
+ def getinteriorfield(self, index, ofs, default):
+ return self._items[index].get(ofs, default)
+
+ def setinteriorfield(self, index, ofs, itemvalue):
+ assert isinstance(itemvalue, optimizer.OptValue)
+ self._items[index][ofs] = itemvalue
+
+ def _really_force(self, optforce):
+ assert self.source_op is not None
+ if not we_are_translated():
+ self.source_op.name = 'FORCE ' + self.source_op.name
+ optforce.emit_operation(self.source_op)
+ self.box = box = self.source_op.result
+ for index in range(len(self._items)):
+ for descr, value in self._items[index].iteritems():
+ subbox = value.force_box(optforce)
+ op = ResOperation(rop.SETINTERIORFIELD_GC,
+ [box, ConstInt(index), subbox], None, descr=descr
+ )
+ optforce.emit_operation(op)
+
+ def _get_list_of_descrs(self):
+ descrs = []
+ for item in self._items:
+ item_descrs = item.keys()
+ sort_descrs(item_descrs)
+ descrs.append(item_descrs)
+ return descrs
+
+ def get_args_for_fail(self, modifier):
+ if self.box is None and not modifier.already_seen_virtual(self.keybox):
+ itemdescrs = self._get_list_of_descrs()
+ itemboxes = []
+ for i in range(len(self._items)):
+ for descr in itemdescrs[i]:
+ itemboxes.append(self._items[i][descr].get_key_box())
+ modifier.register_virtual_fields(self.keybox, itemboxes)
+ for i in range(len(self._items)):
+ for descr in itemdescrs[i]:
+ self._items[i][descr].get_args_for_fail(modifier)
+
+ def force_at_end_of_preamble(self, already_forced, optforce):
+ if self in already_forced:
+ return self
+ already_forced[self] = self
+ for index in range(len(self._items)):
+ for descr in self._items[index].keys():
+ self._items[index][descr] = self._items[index][descr].force_at_end_of_preamble(already_forced, optforce)
+ return self
+
+ def _make_virtual(self, modifier):
+ return modifier.make_varraystruct(self.arraydescr, self._get_list_of_descrs())
+
+
class OptVirtualize(optimizer.Optimization):
"Virtualize objects until they escape."
def new(self):
return OptVirtualize()
-
+
def make_virtual(self, known_class, box, source_op=None):
vvalue = VirtualValue(self.optimizer.cpu, known_class, box, source_op)
self.make_equal_to(box, vvalue)
return vvalue
def make_varray(self, arraydescr, size, box, source_op=None):
- constvalue = self.new_const_item(arraydescr)
- vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op)
+ if arraydescr.is_array_of_structs():
+ vvalue = VArrayStructValue(arraydescr, size, box, source_op)
+ else:
+ constvalue = self.new_const_item(arraydescr)
+ vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op)
self.make_equal_to(box, vvalue)
return vvalue
@@ -431,6 +497,34 @@
value.ensure_nonnull()
self.emit_operation(op)
+ def optimize_GETINTERIORFIELD_GC(self, op):
+ value = self.getvalue(op.getarg(0))
+ if value.is_virtual():
+ indexbox = self.get_constant_box(op.getarg(1))
+ if indexbox is not None:
+ descr = op.getdescr()
+ fieldvalue = value.getinteriorfield(
+ indexbox.getint(), descr, None
+ )
+ if fieldvalue is None:
+ fieldvalue = self.new_const(descr)
+ self.make_equal_to(op.result, fieldvalue)
+ return
+ value.ensure_nonnull()
+ self.emit_operation(op)
+
+ def optimize_SETINTERIORFIELD_GC(self, op):
+ value = self.getvalue(op.getarg(0))
+ if value.is_virtual():
+ indexbox = self.get_constant_box(op.getarg(1))
+ if indexbox is not None:
+ value.setinteriorfield(
+ indexbox.getint(), op.getdescr(), self.getvalue(op.getarg(2))
+ )
+ return
+ value.ensure_nonnull()
+ self.emit_operation(op)
+
dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_',
default=OptVirtualize.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -16,7 +16,7 @@
class AbstractVirtualStateInfo(resume.AbstractVirtualInfo):
position = -1
-
+
def generalization_of(self, other, renum, bad):
raise NotImplementedError
@@ -54,7 +54,7 @@
s.debug_print(indent + " ", seen, bad)
else:
debug_print(indent + " ...")
-
+
def debug_header(self, indent):
raise NotImplementedError
@@ -77,13 +77,15 @@
bad[self] = True
bad[other] = True
return False
+
+ assert isinstance(other, AbstractVirtualStructStateInfo)
assert len(self.fielddescrs) == len(self.fieldstate)
assert len(other.fielddescrs) == len(other.fieldstate)
if len(self.fielddescrs) != len(other.fielddescrs):
bad[self] = True
bad[other] = True
return False
-
+
for i in range(len(self.fielddescrs)):
if other.fielddescrs[i] is not self.fielddescrs[i]:
bad[self] = True
@@ -112,8 +114,8 @@
def _enum(self, virtual_state):
for s in self.fieldstate:
s.enum(virtual_state)
-
-
+
+
class VirtualStateInfo(AbstractVirtualStructStateInfo):
def __init__(self, known_class, fielddescrs):
AbstractVirtualStructStateInfo.__init__(self, fielddescrs)
@@ -128,13 +130,13 @@
def debug_header(self, indent):
debug_print(indent + 'VirtualStateInfo(%d):' % self.position)
-
+
class VStructStateInfo(AbstractVirtualStructStateInfo):
def __init__(self, typedescr, fielddescrs):
AbstractVirtualStructStateInfo.__init__(self, fielddescrs)
self.typedescr = typedescr
- def _generalization_of(self, other):
+ def _generalization_of(self, other):
if not isinstance(other, VStructStateInfo):
return False
if self.typedescr is not other.typedescr:
@@ -143,7 +145,7 @@
def debug_header(self, indent):
debug_print(indent + 'VStructStateInfo(%d):' % self.position)
-
+
class VArrayStateInfo(AbstractVirtualStateInfo):
def __init__(self, arraydescr):
self.arraydescr = arraydescr
@@ -157,11 +159,7 @@
bad[other] = True
return False
renum[self.position] = other.position
- if not isinstance(other, VArrayStateInfo):
- bad[self] = True
- bad[other] = True
- return False
- if self.arraydescr is not other.arraydescr:
+ if not self._generalization_of(other):
bad[self] = True
bad[other] = True
return False
@@ -177,6 +175,10 @@
return False
return True
+ def _generalization_of(self, other):
+ return (isinstance(other, VArrayStateInfo) and
+ self.arraydescr is other.arraydescr)
+
def enum_forced_boxes(self, boxes, value, optimizer):
assert isinstance(value, virtualize.VArrayValue)
assert value.is_virtual()
@@ -192,8 +194,75 @@
def debug_header(self, indent):
debug_print(indent + 'VArrayStateInfo(%d):' % self.position)
-
-
+
+class VArrayStructStateInfo(AbstractVirtualStateInfo):
+ def __init__(self, arraydescr, fielddescrs):
+ self.arraydescr = arraydescr
+ self.fielddescrs = fielddescrs
+
+ def generalization_of(self, other, renum, bad):
+ assert self.position != -1
+ if self.position in renum:
+ if renum[self.position] == other.position:
+ return True
+ bad[self] = True
+ bad[other] = True
+ return False
+ renum[self.position] = other.position
+ if not self._generalization_of(other):
+ bad[self] = True
+ bad[other] = True
+ return False
+
+ assert isinstance(other, VArrayStructStateInfo)
+ if len(self.fielddescrs) != len(other.fielddescrs):
+ bad[self] = True
+ bad[other] = True
+ return False
+
+ p = 0
+ for i in range(len(self.fielddescrs)):
+ if len(self.fielddescrs[i]) != len(other.fielddescrs[i]):
+ bad[self] = True
+ bad[other] = True
+ return False
+ for j in range(len(self.fielddescrs[i])):
+ if self.fielddescrs[i][j] is not other.fielddescrs[i][j]:
+ bad[self] = True
+ bad[other] = True
+ return False
+ if not self.fieldstate[p].generalization_of(other.fieldstate[p],
+ renum, bad):
+ bad[self] = True
+ bad[other] = True
+ return False
+ p += 1
+ return True
+
+ def _generalization_of(self, other):
+ return (isinstance(other, VArrayStructStateInfo) and
+ self.arraydescr is other.arraydescr)
+
+ def _enum(self, virtual_state):
+ for s in self.fieldstate:
+ s.enum(virtual_state)
+
+ def enum_forced_boxes(self, boxes, value, optimizer):
+ assert isinstance(value, virtualize.VArrayStructValue)
+ assert value.is_virtual()
+ p = 0
+ for i in range(len(self.fielddescrs)):
+ for j in range(len(self.fielddescrs[i])):
+ v = value._items[i][self.fielddescrs[i][j]]
+ s = self.fieldstate[p]
+ if s.position > self.position:
+ s.enum_forced_boxes(boxes, v, optimizer)
+ p += 1
+
+ def debug_header(self, indent):
+ debug_print(indent + 'VArrayStructStateInfo(%d):' % self.position)
+
+
class NotVirtualStateInfo(AbstractVirtualStateInfo):
def __init__(self, value):
self.known_class = value.known_class
@@ -277,7 +346,7 @@
op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None)
extra_guards.append(op)
return
-
+
if self.level == LEVEL_NONNULL and \
other.level == LEVEL_UNKNOWN and \
isinstance(box, BoxPtr) and \
@@ -285,7 +354,7 @@
op = ResOperation(rop.GUARD_NONNULL, [box], None)
extra_guards.append(op)
return
-
+
if self.level == LEVEL_UNKNOWN and \
other.level == LEVEL_UNKNOWN and \
isinstance(box, BoxInt) and \
@@ -309,7 +378,7 @@
op = ResOperation(rop.GUARD_TRUE, [res], None)
extra_guards.append(op)
return
-
+
# Remaining cases are probably not interesting
raise InvalidLoop
if self.level == LEVEL_CONSTANT:
@@ -319,7 +388,7 @@
def enum_forced_boxes(self, boxes, value, optimizer):
if self.level == LEVEL_CONSTANT:
return
- assert 0 <= self.position_in_notvirtuals
+ assert 0 <= self.position_in_notvirtuals
boxes[self.position_in_notvirtuals] = value.force_box(optimizer)
def _enum(self, virtual_state):
@@ -348,7 +417,7 @@
lb = ''
if self.lenbound:
lb = ', ' + self.lenbound.bound.__repr__()
-
+
debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position +
', ' + l + ', ' + self.intbound.__repr__() + lb + ')')
@@ -370,7 +439,7 @@
return False
return True
- def generate_guards(self, other, args, cpu, extra_guards):
+ def generate_guards(self, other, args, cpu, extra_guards):
assert len(self.state) == len(other.state) == len(args)
renum = {}
for i in range(len(self.state)):
@@ -393,7 +462,7 @@
inputargs.append(box)
assert None not in inputargs
-
+
return inputargs
def debug_print(self, hdr='', bad=None):
@@ -412,7 +481,7 @@
def register_virtual_fields(self, keybox, fieldboxes):
self.fieldboxes[keybox] = fieldboxes
-
+
def already_seen_virtual(self, keybox):
return keybox in self.fieldboxes
@@ -463,6 +532,9 @@
def make_varray(self, arraydescr):
return VArrayStateInfo(arraydescr)
+ def make_varraystruct(self, arraydescr, fielddescrs):
+ return VArrayStructStateInfo(arraydescr, fielddescrs)
+
class BoxNotProducable(Exception):
pass
@@ -501,12 +573,12 @@
else: # Low priority
lo -= 1
return alts
-
+
def renamed(self, box):
if box in self.rename:
return self.rename[box]
return box
-
+
def add_to_short(self, box, op):
if op:
op = op.clone()
@@ -528,12 +600,12 @@
self.optimizer.make_equal_to(newbox, value)
else:
self.short_boxes[box] = op
-
+
def produce_short_preamble_box(self, box):
if box in self.short_boxes:
- return
+ return
if isinstance(box, Const):
- return
+ return
if box in self.potential_ops:
ops = self.prioritized_alternatives(box)
produced_one = False
@@ -570,7 +642,7 @@
else:
debug_print(logops.repr_of_arg(box) + ': None')
debug_stop('jit-short-boxes')
-
+
def operations(self):
if not we_are_translated(): # For tests
ops = self.short_boxes.values()
@@ -588,7 +660,7 @@
if not isinstance(oldbox, Const) and newbox not in self.short_boxes:
self.short_boxes[newbox] = self.short_boxes[oldbox]
self.aliases[newbox] = oldbox
-
+
def original(self, box):
while box in self.aliases:
box = self.aliases[box]
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -163,17 +163,6 @@
for value in self._chars:
value.get_args_for_fail(modifier)
- def FIXME_enum_forced_boxes(self, boxes, already_seen):
- key = self.get_key_box()
- if key in already_seen:
- return
- already_seen[key] = None
- if self.box is None:
- for box in self._chars:
- box.enum_forced_boxes(boxes, already_seen)
- else:
- boxes.append(self.box)
-
def _make_virtual(self, modifier):
return modifier.make_vstrplain(self.mode is mode_unicode)
@@ -226,18 +215,6 @@
self.left.get_args_for_fail(modifier)
self.right.get_args_for_fail(modifier)
- def FIXME_enum_forced_boxes(self, boxes, already_seen):
- key = self.get_key_box()
- if key in already_seen:
- return
- already_seen[key] = None
- if self.box is None:
- self.left.enum_forced_boxes(boxes, already_seen)
- self.right.enum_forced_boxes(boxes, already_seen)
- self.lengthbox = None
- else:
- boxes.append(self.box)
-
def _make_virtual(self, modifier):
return modifier.make_vstrconcat(self.mode is mode_unicode)
@@ -284,18 +261,6 @@
self.vstart.get_args_for_fail(modifier)
self.vlength.get_args_for_fail(modifier)
- def FIXME_enum_forced_boxes(self, boxes, already_seen):
- key = self.get_key_box()
- if key in already_seen:
- return
- already_seen[key] = None
- if self.box is None:
- self.vstr.enum_forced_boxes(boxes, already_seen)
- self.vstart.enum_forced_boxes(boxes, already_seen)
- self.vlength.enum_forced_boxes(boxes, already_seen)
- else:
- boxes.append(self.box)
-
def _make_virtual(self, modifier):
return modifier.make_vstrslice(self.mode is mode_unicode)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -36,6 +36,7 @@
class MIFrame(object):
+ debug = False
def __init__(self, metainterp):
self.metainterp = metainterp
@@ -164,7 +165,7 @@
if not we_are_translated():
for b in registers[count:]:
assert not oldbox.same_box(b)
-
+
def make_result_of_lastop(self, resultbox):
got_type = resultbox.type
@@ -198,7 +199,7 @@
'float_add', 'float_sub', 'float_mul', 'float_truediv',
'float_lt', 'float_le', 'float_eq',
'float_ne', 'float_gt', 'float_ge',
- 'ptr_eq', 'ptr_ne',
+ 'ptr_eq', 'ptr_ne', 'instance_ptr_eq', 'instance_ptr_ne',
]:
exec py.code.Source('''
@arguments("box", "box")
@@ -222,6 +223,7 @@
'cast_float_to_int', 'cast_int_to_float',
'cast_float_to_singlefloat', 'cast_singlefloat_to_float',
'float_neg', 'float_abs',
+ 'cast_ptr_to_int', 'cast_int_to_ptr',
]:
exec py.code.Source('''
@arguments("box")
@@ -238,8 +240,8 @@
return self.execute(rop.PTR_EQ, box, history.CONST_NULL)
@arguments("box")
- def opimpl_cast_opaque_ptr(self, box):
- return self.execute(rop.CAST_OPAQUE_PTR, box)
+ def opimpl_mark_opaque_ptr(self, box):
+ return self.execute(rop.MARK_OPAQUE_PTR, box)
@arguments("box")
def _opimpl_any_return(self, box):
@@ -547,6 +549,14 @@
opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
+ @arguments("box", "box", "descr")
+ def _opimpl_getinteriorfield_gc_any(self, array, index, descr):
+ return self.execute_with_descr(rop.GETINTERIORFIELD_GC, descr,
+ array, index)
+ opimpl_getinteriorfield_gc_i = _opimpl_getinteriorfield_gc_any
+ opimpl_getinteriorfield_gc_f = _opimpl_getinteriorfield_gc_any
+ opimpl_getinteriorfield_gc_r = _opimpl_getinteriorfield_gc_any
+
@specialize.arg(1)
def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr):
tobox = self.metainterp.heapcache.getfield(box, fielddescr)
@@ -587,6 +597,15 @@
opimpl_setfield_gc_r = _opimpl_setfield_gc_any
opimpl_setfield_gc_f = _opimpl_setfield_gc_any
+ @arguments("box", "box", "box", "descr")
+ def _opimpl_setinteriorfield_gc_any(self, array, index, value, descr):
+ self.execute_with_descr(rop.SETINTERIORFIELD_GC, descr,
+ array, index, value)
+ opimpl_setinteriorfield_gc_i = _opimpl_setinteriorfield_gc_any
+ opimpl_setinteriorfield_gc_f = _opimpl_setinteriorfield_gc_any
+ opimpl_setinteriorfield_gc_r = _opimpl_setinteriorfield_gc_any
+
+
@arguments("box", "descr")
def _opimpl_getfield_raw_any(self, box, fielddescr):
return self.execute_with_descr(rop.GETFIELD_RAW, fielddescr, box)
@@ -2587,17 +2606,21 @@
self.pc = position
#
if not we_are_translated():
- print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
+ if self.debug:
+ print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
try:
resultbox = unboundmethod(self, *args)
except Exception, e:
- print '-> %s!' % e.__class__.__name__
+ if self.debug:
+ print '-> %s!' % e.__class__.__name__
raise
if num_return_args == 0:
- print
+ if self.debug:
+ print
assert resultbox is None
else:
- print '-> %r' % (resultbox,)
+ if self.debug:
+ print '-> %r' % (resultbox,)
assert argcodes[next_argcode] == '>'
result_argcode = argcodes[next_argcode + 1]
assert resultbox.type == {'i': history.INT,
diff --git a/pypy/jit/metainterp/quasiimmut.py b/pypy/jit/metainterp/quasiimmut.py
--- a/pypy/jit/metainterp/quasiimmut.py
+++ b/pypy/jit/metainterp/quasiimmut.py
@@ -2,6 +2,7 @@
from pypy.rpython.lltypesystem import lltype, rclass
from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
from pypy.jit.metainterp.history import AbstractDescr
+from pypy.rlib.objectmodel import we_are_translated
def get_mutate_field_name(fieldname):
@@ -50,13 +51,13 @@
class QuasiImmut(object):
llopaque = True
+ compress_limit = 30
def __init__(self, cpu):
self.cpu = cpu
# list of weakrefs to the LoopTokens that must be invalidated if
# this value ever changes
self.looptokens_wrefs = []
- self.compress_limit = 30
def hide(self):
qmut_ptr = self.cpu.ts.cast_instance_to_base_ref(self)
@@ -75,6 +76,8 @@
def compress_looptokens_list(self):
self.looptokens_wrefs = [wref for wref in self.looptokens_wrefs
if wref() is not None]
+ # NB. we must keep around the looptoken_wrefs that are
+ # already invalidated; see below
self.compress_limit = (len(self.looptokens_wrefs) + 15) * 2
def invalidate(self):
@@ -86,7 +89,16 @@
for wref in wrefs:
looptoken = wref()
if looptoken is not None:
+ looptoken.invalidated = True
self.cpu.invalidate_loop(looptoken)
+ # NB. we must call cpu.invalidate_loop() even if
+ # looptoken.invalidated was already set to True.
+ # It's possible to invalidate several times the
+ # same looptoken; see comments in jit.backend.model
+ # in invalidate_loop().
+ if not we_are_translated():
+ self.cpu.stats.invalidated_token_numbers.add(
+ looptoken.number)
class QuasiImmutDescr(AbstractDescr):
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -1,5 +1,4 @@
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import make_sure_not_resized
def ResOperation(opnum, args, result, descr=None):
cls = opclasses[opnum]
@@ -405,8 +404,8 @@
'FLOAT_TRUEDIV/2',
'FLOAT_NEG/1',
'FLOAT_ABS/1',
- 'CAST_FLOAT_TO_INT/1',
- 'CAST_INT_TO_FLOAT/1',
+ 'CAST_FLOAT_TO_INT/1', # don't use for unsigned ints; we would
+ 'CAST_INT_TO_FLOAT/1', # need some messy code in the backend
'CAST_FLOAT_TO_SINGLEFLOAT/1',
'CAST_SINGLEFLOAT_TO_FLOAT/1',
#
@@ -433,10 +432,13 @@
'INT_INVERT/1',
#
'SAME_AS/1', # gets a Const or a Box, turns it into another Box
+ 'CAST_PTR_TO_INT/1',
+ 'CAST_INT_TO_PTR/1',
#
'PTR_EQ/2b',
'PTR_NE/2b',
- 'CAST_OPAQUE_PTR/1b',
+ 'INSTANCE_PTR_EQ/2b',
+ 'INSTANCE_PTR_NE/2b',
#
'ARRAYLEN_GC/1d',
'STRLEN/1',
@@ -455,6 +457,7 @@
'GETARRAYITEM_GC/2d',
'GETARRAYITEM_RAW/2d',
+ 'GETINTERIORFIELD_GC/2d',
'GETFIELD_GC/1d',
'GETFIELD_RAW/1d',
'_MALLOC_FIRST',
@@ -467,10 +470,12 @@
'FORCE_TOKEN/0',
'VIRTUAL_REF/2', # removed before it's passed to the backend
'READ_TIMESTAMP/0',
+ 'MARK_OPAQUE_PTR/1b',
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
'SETARRAYITEM_GC/3d',
'SETARRAYITEM_RAW/3d',
+ 'SETINTERIORFIELD_GC/3d',
'SETFIELD_GC/2d',
'SETFIELD_RAW/2d',
'STRSETITEM/3',
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -139,7 +139,7 @@
self.numberings = {}
self.cached_boxes = {}
self.cached_virtuals = {}
-
+
self.nvirtuals = 0
self.nvholes = 0
self.nvreused = 0
@@ -273,6 +273,9 @@
def make_varray(self, arraydescr):
return VArrayInfo(arraydescr)
+ def make_varraystruct(self, arraydescr, fielddescrs):
+ return VArrayStructInfo(arraydescr, fielddescrs)
+
def make_vstrplain(self, is_unicode=False):
if is_unicode:
return VUniPlainInfo()
@@ -402,7 +405,7 @@
virtuals[num] = vinfo
if self._invalidation_needed(len(liveboxes), nholes):
- memo.clear_box_virtual_numbers()
+ memo.clear_box_virtual_numbers()
def _invalidation_needed(self, nliveboxes, nholes):
memo = self.memo
@@ -455,7 +458,7 @@
def debug_prints(self):
raise NotImplementedError
-
+
class AbstractVirtualStructInfo(AbstractVirtualInfo):
def __init__(self, fielddescrs):
self.fielddescrs = fielddescrs
@@ -537,6 +540,29 @@
for i in self.fieldnums:
debug_print("\t\t", str(untag(i)))
+
+class VArrayStructInfo(AbstractVirtualInfo):
+ def __init__(self, arraydescr, fielddescrs):
+ self.arraydescr = arraydescr
+ self.fielddescrs = fielddescrs
+
+ def debug_prints(self):
+ debug_print("\tvarraystructinfo", self.arraydescr)
+ for i in self.fieldnums:
+ debug_print("\t\t", str(untag(i)))
+
+ @specialize.argtype(1)
+ def allocate(self, decoder, index):
+ array = decoder.allocate_array(self.arraydescr, len(self.fielddescrs))
+ decoder.virtuals_cache[index] = array
+ p = 0
+ for i in range(len(self.fielddescrs)):
+ for j in range(len(self.fielddescrs[i])):
+ decoder.setinteriorfield(i, self.fielddescrs[i][j], array, self.fieldnums[p])
+ p += 1
+ return array
+
+
class VStrPlainInfo(AbstractVirtualInfo):
"""Stands for the string made out of the characters of all fieldnums."""
@@ -884,6 +910,17 @@
self.metainterp.execute_and_record(rop.SETFIELD_GC, descr,
structbox, fieldbox)
+ def setinteriorfield(self, index, descr, array, fieldnum):
+ if descr.is_pointer_field():
+ kind = REF
+ elif descr.is_float_field():
+ kind = FLOAT
+ else:
+ kind = INT
+ fieldbox = self.decode_box(fieldnum, kind)
+ self.metainterp.execute_and_record(rop.SETINTERIORFIELD_GC, descr,
+ array, ConstInt(index), fieldbox)
+
def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum):
self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT)
@@ -1164,6 +1201,17 @@
newvalue = self.decode_int(fieldnum)
self.cpu.bh_setfield_gc_i(struct, descr, newvalue)
+ def setinteriorfield(self, index, descr, array, fieldnum):
+ if descr.is_pointer_field():
+ newvalue = self.decode_ref(fieldnum)
+ self.cpu.bh_setinteriorfield_gc_r(array, index, descr, newvalue)
+ elif descr.is_float_field():
+ newvalue = self.decode_float(fieldnum)
+ self.cpu.bh_setinteriorfield_gc_f(array, index, descr, newvalue)
+ else:
+ newvalue = self.decode_int(fieldnum)
+ self.cpu.bh_setinteriorfield_gc_i(array, index, descr, newvalue)
+
def setarrayitem_int(self, arraydescr, array, index, fieldnum):
newvalue = self.decode_int(fieldnum)
self.cpu.bh_setarrayitem_gc_i(arraydescr, array, index, newvalue)
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -10,6 +10,7 @@
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
from pypy.jit.metainterp.warmspot import get_stats
from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.rlib import rerased
from pypy.rlib.jit import (JitDriver, we_are_jitted, hint, dont_look_inside,
loop_invariant, elidable, promote, jit_debug, assert_green,
AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
@@ -3435,12 +3436,133 @@
return sa
res = self.meta_interp(f, [16])
assert res == f(16)
-
+
+ def test_ptr_eq(self):
+ myjitdriver = JitDriver(greens = [], reds = ["n", "x"])
+ class A(object):
+ def __init__(self, v):
+ self.v = v
+ def f(n, x):
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, x=x)
+ z = 0 / x
+ a1 = A("key")
+ a2 = A("\x00")
+ n -= [a1, a2][z].v is not a2.v
+ return n
+ res = self.meta_interp(f, [10, 1])
+ assert res == 0
+
+ def test_instance_ptr_eq(self):
+ myjitdriver = JitDriver(greens = [], reds = ["n", "i", "a1", "a2"])
+ class A(object):
+ pass
+ def f(n):
+ a1 = A()
+ a2 = A()
+ i = 0
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, i=i, a1=a1, a2=a2)
+ if n % 2:
+ a = a2
+ else:
+ a = a1
+ i += a is a1
+ n -= 1
+ return i
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+ def f(n):
+ a1 = A()
+ a2 = A()
+ i = 0
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, i=i, a1=a1, a2=a2)
+ if n % 2:
+ a = a2
+ else:
+ a = a1
+ if a is a2:
+ i += 1
+ n -= 1
+ return i
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+
+ def test_virtual_array_of_structs(self):
+ myjitdriver = JitDriver(greens = [], reds=["n", "d"])
+ def f(n):
+ d = None
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, d=d)
+ d = {"q": 1}
+ if n % 2:
+ d["k"] = n
+ else:
+ d["z"] = n
+ n -= len(d) - d["q"]
+ return n
+ res = self.meta_interp(f, [10])
+ assert res == 0
+
+ def test_virtual_dict_constant_keys(self):
+ myjitdriver = JitDriver(greens = [], reds = ["n"])
+ def g(d):
+ return d["key"] - 1
+
+ def f(n):
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n)
+ n = g({"key": n})
+ return n
+
+ res = self.meta_interp(f, [10])
+ assert res == 0
+ self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
+ def test_virtual_opaque_ptr(self):
+ myjitdriver = JitDriver(greens = [], reds = ["n"])
+ erase, unerase = rerased.new_erasing_pair("x")
+ @look_inside_iff(lambda x: isvirtual(x))
+ def g(x):
+ return x[0]
+ def f(n):
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n)
+ x = []
+ y = erase(x)
+ z = unerase(y)
+ z.append(1)
+ n -= g(z)
+ return n
+ res = self.meta_interp(f, [10])
+ assert res == 0
+ self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
+ def test_virtual_opaque_dict(self):
+ myjitdriver = JitDriver(greens = [], reds = ["n"])
+ erase, unerase = rerased.new_erasing_pair("x")
+ @look_inside_iff(lambda x: isvirtual(x))
+ def g(x):
+ return x[0]["key"] - 1
+ def f(n):
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n)
+ x = [{}]
+ x[0]["key"] = n
+ x[0]["other key"] = n
+ y = erase(x)
+ z = unerase(y)
+ n = g(x)
+ return n
+ res = self.meta_interp(f, [10])
+ assert res == 0
+ self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
- py.test.skip("implement me")
from pypy.rlib.objectmodel import UnboxedValue
class Base(object):
__slots__ = ()
@@ -3492,3 +3614,34 @@
pc += 1
return pc
res = self.meta_interp(main, [False, 100, True], taggedpointers=True)
+
+ def test_rerased(self):
+ eraseX, uneraseX = rerased.new_erasing_pair("X")
+ #
+ class X:
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+ #
+ def f(i, j):
+ # 'j' should be 0 or 1, not other values
+ if j > 0:
+ e = eraseX(X(i, j))
+ else:
+ try:
+ e = rerased.erase_int(i)
+ except OverflowError:
+ return -42
+ if j & 1:
+ x = uneraseX(e)
+ return x.a - x.b
+ else:
+ return rerased.unerase_int(e)
+ #
+ x = self.interp_operations(f, [-128, 0], taggedpointers=True)
+ assert x == -128
+ bigint = sys.maxint//2 + 1
+ x = self.interp_operations(f, [bigint, 0], taggedpointers=True)
+ assert x == -42
+ x = self.interp_operations(f, [1000, 1], taggedpointers=True)
+ assert x == 999
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -91,7 +91,7 @@
res1 = f(100)
res2 = self.meta_interp(f, [100], listops=True)
assert res1 == res2
- self.check_loops(int_mod=1) # the hash was traced
+ self.check_loops(int_mod=1) # the hash was traced and eq, but cached
def test_dict_setdefault(self):
myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -128,7 +128,7 @@
assert f(100) == 50
res = self.meta_interp(f, [100], listops=True)
assert res == 50
- self.check_loops(int_mod=1)
+ self.check_loops(int_mod=1) # key + eq, but cached
def test_repeated_lookup(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'd'])
@@ -153,10 +153,12 @@
res = self.meta_interp(f, [100], listops=True)
assert res == f(50)
- self.check_loops({"call": 7, "guard_false": 1, "guard_no_exception": 6,
+ self.check_loops({"call": 5, "getfield_gc": 1, "getinteriorfield_gc": 1,
+ "guard_false": 1, "guard_no_exception": 4,
"guard_true": 1, "int_and": 1, "int_gt": 1,
"int_is_true": 1, "int_sub": 1, "jump": 1,
- "new_with_vtable": 1, "setfield_gc": 1})
+ "new_with_vtable": 1, "new": 1, "new_array": 1,
+ "setfield_gc": 3, })
class TestOOtype(DictTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_float.py b/pypy/jit/metainterp/test/test_float.py
--- a/pypy/jit/metainterp/test/test_float.py
+++ b/pypy/jit/metainterp/test/test_float.py
@@ -1,5 +1,6 @@
-import math
+import math, sys
from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.rlib.rarithmetic import intmask, r_uint
class FloatTests:
@@ -45,6 +46,34 @@
res = self.interp_operations(f, [-2.0])
assert res == -8.5
+ def test_cast_float_to_int(self):
+ def g(f):
+ return int(f)
+ res = self.interp_operations(g, [-12345.9])
+ assert res == -12345
+
+ def test_cast_float_to_uint(self):
+ def g(f):
+ return intmask(r_uint(f))
+ res = self.interp_operations(g, [sys.maxint*2.0])
+ assert res == intmask(long(sys.maxint*2.0))
+ res = self.interp_operations(g, [-12345.9])
+ assert res == -12345
+
+ def test_cast_int_to_float(self):
+ def g(i):
+ return float(i)
+ res = self.interp_operations(g, [-12345])
+ assert type(res) is float and res == -12345.0
+
+ def test_cast_uint_to_float(self):
+ def g(i):
+ return float(r_uint(i))
+ res = self.interp_operations(g, [intmask(sys.maxint*2)])
+ assert type(res) is float and res == float(sys.maxint*2)
+ res = self.interp_operations(g, [-12345])
+ assert type(res) is float and res == float(long(r_uint(-12345)))
+
class TestOOtype(FloatTests, OOJitMixin):
pass
diff --git a/pypy/jit/metainterp/test/test_heapcache.py b/pypy/jit/metainterp/test/test_heapcache.py
--- a/pypy/jit/metainterp/test/test_heapcache.py
+++ b/pypy/jit/metainterp/test/test_heapcache.py
@@ -371,3 +371,17 @@
assert h.is_unescaped(box1)
h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box2, index1, box1])
assert not h.is_unescaped(box1)
+
+ h = HeapCache()
+ h.new_array(box1, lengthbox1)
+ h.new(box2)
+ assert h.is_unescaped(box1)
+ assert h.is_unescaped(box2)
+ h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box1, lengthbox2, box2])
+ assert h.is_unescaped(box1)
+ assert h.is_unescaped(box2)
+ h.invalidate_caches(
+ rop.CALL, FakeCallDescr(FakeEffektinfo.EF_RANDOM_EFFECTS), [box1]
+ )
+ assert not h.is_unescaped(box1)
+ assert not h.is_unescaped(box2)
diff --git a/pypy/jit/metainterp/test/test_memmgr.py b/pypy/jit/metainterp/test/test_memmgr.py
--- a/pypy/jit/metainterp/test/test_memmgr.py
+++ b/pypy/jit/metainterp/test/test_memmgr.py
@@ -18,6 +18,7 @@
class FakeLoopToken:
generation = 0
+ invalidated = False
class _TestMemoryManager:
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -48,6 +48,13 @@
class QuasiImmutTests(object):
+ def setup_method(self, meth):
+ self.prev_compress_limit = QuasiImmut.compress_limit
+ QuasiImmut.compress_limit = 1
+
+ def teardown_method(self, meth):
+ QuasiImmut.compress_limit = self.prev_compress_limit
+
def test_simple_1(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
class Foo:
@@ -289,7 +296,7 @@
return total
res = self.meta_interp(main, [])
- self.check_loop_count(9)
+ self.check_tree_loop_count(6)
assert res == main()
def test_change_during_running(self):
@@ -317,7 +324,7 @@
assert f(100, 15) == 3009
res = self.meta_interp(f, [100, 15])
assert res == 3009
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
+ self.check_loops(guard_not_invalidated=4, getfield_gc=0,
call_may_force=0, guard_not_forced=0)
def test_list_simple_1(self):
@@ -453,10 +460,30 @@
assert f(100, 15) == 3009
res = self.meta_interp(f, [100, 15])
assert res == 3009
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
+ self.check_loops(guard_not_invalidated=4, getfield_gc=0,
getarrayitem_gc=0, getarrayitem_gc_pure=0,
call_may_force=0, guard_not_forced=0)
+ def test_invalidated_loop_is_not_used_any_more_as_target(self):
+ myjitdriver = JitDriver(greens=['foo'], reds=['x'])
+ class Foo:
+ _immutable_fields_ = ['step?']
+ @dont_look_inside
+ def residual(x, foo):
+ if x == 20:
+ foo.step = 1
+ def f(x):
+ foo = Foo()
+ foo.step = 2
+ while x > 0:
+ myjitdriver.jit_merge_point(foo=foo, x=x)
+ residual(x, foo)
+ x -= foo.step
+ return foo.step
+ res = self.meta_interp(f, [60])
+ assert res == 1
+ self.check_tree_loop_count(4) # at least not 2 like before
+
class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
import py
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
--- a/pypy/jit/metainterp/test/test_tracingopts.py
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -3,6 +3,7 @@
from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.rlib import jit
from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rstring import StringBuilder
import py
@@ -590,4 +591,14 @@
assert res == 4
self.check_operations_history(int_add_ovf=0)
res = self.interp_operations(fn, [sys.maxint])
- assert res == 12
\ No newline at end of file
+ assert res == 12
+
+ def test_copy_str_content(self):
+ def fn(n):
+ a = StringBuilder()
+ x = [1]
+ a.append("hello world")
+ return x[0]
+ res = self.interp_operations(fn, [0])
+ assert res == 1
+ self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0 )
\ No newline at end of file
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -3,6 +3,7 @@
from pypy.rpython.llinterp import LLException
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef
+from pypy.rlib.jit import non_virtual_ref
from pypy.rlib.objectmodel import compute_unique_id
from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes
from pypy.jit.metainterp.resoperation import rop
@@ -595,6 +596,65 @@
res = self.meta_interp(fn, [10])
assert res == 6
+ def test_is_virtual(self):
+ myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+ class X:
+ pass
+ @dont_look_inside
+ def residual(vref):
+ return vref.virtual
+ #
+ def f(n):
+ res1 = -42
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, res1=res1)
+ x = X()
+ vref = virtual_ref(x)
+ res1 = residual(vref)
+ virtual_ref_finish(vref, x)
+ n -= 1
+ return res1
+ #
+ res = self.meta_interp(f, [10])
+ assert res == 1
+
+ def test_is_not_virtual_none(self):
+ myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+ @dont_look_inside
+ def residual(vref):
+ return vref.virtual
+ #
+ def f(n):
+ res1 = -42
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, res1=res1)
+ res1 = residual(vref_None)
+ n -= 1
+ return res1
+ #
+ res = self.meta_interp(f, [10])
+ assert res == 0
+
+ def test_is_not_virtual_non_none(self):
+ myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+ class X:
+ pass
+ @dont_look_inside
+ def residual(vref):
+ return vref.virtual
+ #
+ def f(n):
+ res1 = -42
+ while n > 0:
+ myjitdriver.jit_merge_point(n=n, res1=res1)
+ x = X()
+ res1 = residual(non_virtual_ref(x))
+ n -= 1
+ return res1
+ #
+ res = self.meta_interp(f, [10])
+ assert res == 0
+
class TestLLtype(VRefTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -39,6 +39,7 @@
def replace_force_virtual_with_call(self, graphs):
# similar to rvirtualizable2.replace_force_virtualizable_with_call().
c_force_virtual_ptr = None
+ c_is_virtual_ptr = None
force_virtual_count = 0
for graph in graphs:
for block in graph.iterblocks():
@@ -52,6 +53,13 @@
op.opname = 'direct_call'
op.args = [c_force_virtual_ptr, op.args[0]]
force_virtual_count += 1
+ #
+ if op.opname == 'jit_is_virtual':
+ if c_is_virtual_ptr is None:
+ c_is_virtual_ptr = self.get_is_virtual_fnptr()
+ #
+ op.opname = 'direct_call'
+ op.args = [c_is_virtual_ptr, op.args[0]]
#
if c_force_virtual_ptr is not None:
log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count,
@@ -129,6 +137,17 @@
force_virtual_if_necessary)
return inputconst(lltype.typeOf(funcptr), funcptr)
+ def get_is_virtual_fnptr(self):
+ #
+ def is_virtual(inst):
+ if not inst:
+ return False
+ return inst.typeptr == self.jit_virtual_ref_vtable
+ #
+ FUNC = lltype.FuncType([rclass.OBJECTPTR], lltype.Bool)
+ funcptr = self.warmrunnerdesc.helper_func(lltype.Ptr(FUNC), is_virtual)
+ return inputconst(lltype.typeOf(funcptr), funcptr)
+
def force_virtual(self, inst):
vref = lltype.cast_pointer(lltype.Ptr(self.JIT_VIRTUAL_REF), inst)
token = vref.virtual_token
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -206,7 +206,7 @@
self.make_enter_functions()
self.rewrite_jit_merge_points(policy)
- verbose = not self.cpu.translate_support_code
+ verbose = False # not self.cpu.translate_support_code
self.codewriter.make_jitcodes(verbose=verbose)
self.rewrite_can_enter_jits()
self.rewrite_set_param()
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -178,7 +178,7 @@
if self.compiled_merge_points_wref is not None:
for wref in self.compiled_merge_points_wref:
looptoken = wref()
- if looptoken is not None:
+ if looptoken is not None and not looptoken.invalidated:
result.append(looptoken)
return result
diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py
--- a/pypy/module/__builtin__/__init__.py
+++ b/pypy/module/__builtin__/__init__.py
@@ -23,6 +23,7 @@
'map' : 'app_functional.map',
'reduce' : 'app_functional.reduce',
'filter' : 'app_functional.filter',
+ 'zip' : 'app_functional.zip',
'vars' : 'app_inspect.vars',
'dir' : 'app_inspect.dir',
@@ -89,7 +90,6 @@
'enumerate' : 'functional.W_Enumerate',
'min' : 'functional.min',
'max' : 'functional.max',
- 'zip' : 'functional.zip',
'reversed' : 'functional.reversed',
'super' : 'descriptor.W_Super',
'staticmethod' : 'descriptor.StaticMethod',
@@ -119,7 +119,7 @@
builtin = space.interpclass_w(w_builtin)
if isinstance(builtin, module.Module):
return builtin
- # no builtin! make a default one. Given them None, at least.
+ # no builtin! make a default one. Give them None, at least.
builtin = module.Module(space, None)
space.setitem(builtin.w_dict, space.wrap('None'), space.w_None)
return builtin
diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py
--- a/pypy/module/__builtin__/app_functional.py
+++ b/pypy/module/__builtin__/app_functional.py
@@ -162,4 +162,21 @@
item = seq[i]
if func(item):
result.append(item)
- return tuple(result)
\ No newline at end of file
+ return tuple(result)
+
+def zip(*sequences):
+ """zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
+
+Return a list of tuples, where each tuple contains the i-th element
+from each of the argument sequences. The returned list is truncated
+in length to the length of the shortest argument sequence."""
+ if not sequences:
+ return []
+ result = []
+ iterators = [iter(seq) for seq in sequences]
+ while True:
+ try:
+ items = [next(it) for it in iterators]
+ except StopIteration:
+ return result
+ result.append(tuple(items))
diff --git a/pypy/module/__builtin__/app_io.py b/pypy/module/__builtin__/app_io.py
--- a/pypy/module/__builtin__/app_io.py
+++ b/pypy/module/__builtin__/app_io.py
@@ -27,7 +27,20 @@
co = compile(source.rstrip()+"\n", filename, 'exec')
exec co in glob, loc
-def raw_input(prompt=None):
+def _write_prompt(stdout, prompt):
+ print >> stdout, prompt,
+ try:
+ flush = stdout.flush
+ except AttributeError:
+ pass
+ else:
+ flush()
+ try:
+ stdout.softspace = 0
+ except (AttributeError, TypeError):
+ pass
+
+def raw_input(prompt=''):
"""raw_input([prompt]) -> string
Read a string from standard input. The trailing newline is stripped.
@@ -47,18 +60,10 @@
if (hasattr(sys, '__raw_input__') and
isinstance(stdin, file) and stdin.fileno() == 0 and stdin.isatty() and
isinstance(stdout, file) and stdout.fileno() == 1):
- if prompt is None:
- prompt = ''
- return sys.__raw_input__(prompt)
+ _write_prompt(stdout, '')
+ return sys.__raw_input__(str(prompt))
- if prompt is not None:
- stdout.write(prompt)
- try:
- flush = stdout.flush
- except AttributeError:
- pass
- else:
- flush()
+ _write_prompt(stdout, prompt)
line = stdin.readline()
if not line: # inputting an empty line gives line == '\n'
raise EOFError
@@ -66,7 +71,7 @@
return line[:-1]
return line
-def input(prompt=None):
+def input(prompt=''):
"""Equivalent to eval(raw_input(prompt))."""
return eval(raw_input(prompt))
diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py
--- a/pypy/module/__builtin__/compiling.py
+++ b/pypy/module/__builtin__/compiling.py
@@ -84,8 +84,8 @@
raise OperationError(space.w_TypeError,
w('eval() arg 1 must be a string or code object'))
- caller = space.getexecutioncontext().gettopframe_nohidden()
if space.is_w(w_globals, space.w_None):
+ caller = space.getexecutioncontext().gettopframe_nohidden()
if caller is None:
w_globals = space.newdict()
if space.is_w(w_locals, space.w_None):
@@ -97,13 +97,9 @@
elif space.is_w(w_locals, space.w_None):
w_locals = w_globals
- try:
- space.getitem(w_globals, space.wrap('__builtins__'))
- except OperationError, e:
- if not e.match(space, space.w_KeyError):
- raise
- if caller is not None:
- w_builtin = space.builtin.pick_builtin(caller.w_globals)
- space.setitem(w_globals, space.wrap('__builtins__'), w_builtin)
+ # xxx removed: adding '__builtins__' to the w_globals dict, if there
+ # is none. This logic was removed as costly (it requires to get at
+ # the gettopframe_nohidden()). I bet no test fails, and it's a really
+ # obscure case.
return codeobj.exec_code(space, w_globals, w_locals)
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -201,27 +201,6 @@
"""
return min_max(space, __args__, "min")
- at unwrap_spec(sequences_w="args_w")
-def zip(space, sequences_w):
- """Return a list of tuples, where the nth tuple contains every nth item of
- each collection.
-
- If the collections have different lengths, zip returns a list as long as the
- shortest collection, ignoring the trailing items in the other collections.
- """
- if not sequences_w:
- return space.newlist([])
- result_w = []
- iterators_w = [space.iter(w_seq) for w_seq in sequences_w]
- while True:
- try:
- items_w = [space.next(w_it) for w_it in iterators_w]
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- return space.newlist(result_w)
- result_w.append(space.newtuple(items_w))
-
class W_Enumerate(Wrappable):
def __init__(self, w_iter, w_start):
diff --git a/pypy/module/__builtin__/test/test_rawinput.py b/pypy/module/__builtin__/test/test_rawinput.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__builtin__/test/test_rawinput.py
@@ -0,0 +1,80 @@
+import autopath
+
+
+class AppTestRawInput():
+
+ def test_input_and_raw_input(self):
+ import sys, StringIO
+ for prompt, expected in [("def:", "abc/ def:/ghi\n"),
+ ("", "abc/ /ghi\n"),
+ (42, "abc/ 42/ghi\n"),
+ (None, "abc/ None/ghi\n"),
+ (Ellipsis, "abc/ /ghi\n")]:
+ for inputfn, inputtext, gottext in [
+ (raw_input, "foo\nbar\n", "foo"),
+ (input, "40+2\n", 42)]:
+ save = sys.stdin, sys.stdout
+ try:
+ sys.stdin = StringIO.StringIO(inputtext)
+ out = sys.stdout = StringIO.StringIO()
+ print "abc", # softspace = 1
+ out.write('/')
+ if prompt is Ellipsis:
+ got = inputfn()
+ else:
+ got = inputfn(prompt)
+ out.write('/')
+ print "ghi"
+ finally:
+ sys.stdin, sys.stdout = save
+ assert out.getvalue() == expected
+ assert got == gottext
+
+ def test_softspace(self):
+ import sys
+ import StringIO
+ fin = StringIO.StringIO()
+ fout = StringIO.StringIO()
+
+ fin.write("Coconuts\n")
+ fin.seek(0)
+
+ sys_stdin_orig = sys.stdin
+ sys_stdout_orig = sys.stdout
+
+ sys.stdin = fin
+ sys.stdout = fout
+
+ print "test",
+ raw_input("test")
+
+ sys.stdin = sys_stdin_orig
+ sys.stdout = sys_stdout_orig
+
+ fout.seek(0)
+ assert fout.read() == "test test"
+
+ def test_softspace_carryover(self):
+ import sys
+ import StringIO
+ fin = StringIO.StringIO()
+ fout = StringIO.StringIO()
+
+ fin.write("Coconuts\n")
+ fin.seek(0)
+
+ sys_stdin_orig = sys.stdin
+ sys_stdout_orig = sys.stdout
+
+ sys.stdin = fin
+ sys.stdout = fout
+
+ print "test",
+ raw_input("test")
+ print "test",
+
+ sys.stdin = sys_stdin_orig
+ sys.stdout = sys_stdout_orig
+
+ fout.seek(0)
+ assert fout.read() == "test testtest"
diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -19,6 +19,11 @@
# - normal: self.sthread != None, not is_empty_handle(self.h)
# - finished: self.sthread != None, is_empty_handle(self.h)
+ def __del__(self):
+ sthread = self.sthread
+ if sthread is not None and not sthread.is_empty_handle(self.h):
+ sthread.destroy(self.h)
+
def check_sthread(self):
ec = self.space.getexecutioncontext()
if ec.stacklet_thread is not self.sthread:
@@ -28,6 +33,8 @@
def descr_init(self, w_callable, __args__):
if self.sthread is not None:
raise geterror(self.space, "continulet already __init__ialized")
+ sthread = build_sthread(self.space)
+ workaround_disable_jit(sthread)
#
# hackish: build the frame "by hand", passing it the correct arguments
space = self.space
@@ -41,7 +48,6 @@
self.bottomframe = bottomframe
#
global_state.origin = self
- sthread = build_sthread(self.space)
self.sthread = sthread
h = sthread.new(new_stacklet_callback)
post_switch(sthread, h)
@@ -71,6 +77,7 @@
global_state.clear()
raise geterror(self.space, "continulet already finished")
self.check_sthread()
+ workaround_disable_jit(self.sthread)
#
global_state.origin = self
if to is None:
@@ -259,6 +266,16 @@
sthread = ec.stacklet_thread = SThread(space, ec)
return sthread
+def workaround_disable_jit(sthread):
+ # A bad workaround to kill the JIT anywhere in this thread.
+ # This forces all the frames. It's a bad workaround because
+ # it takes O(depth) time, and it will cause some "abort:
+ # vable escape" in the JIT. The goal is to prevent any frame
+ # from being still virtuals, because the JIT generates code
+ # to un-virtualizable them "on demand" by loading values based
+ # on FORCE_TOKEN, which is an address in the stack.
+ sthread.ec.force_all_frames()
+
# ____________________________________________________________
def permute(space, args_w):
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -19,7 +19,7 @@
class W_RSocket(Wrappable, RSocket):
def __del__(self):
self.clear_all_weakrefs()
- self.close()
+ RSocket.__del__(self)
def accept_w(self, space):
"""accept() -> (socket object, address info)
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -211,7 +211,9 @@
return result
def __del__(self):
- self.clear_all_weakrefs()
+ # note that we don't call clear_all_weakrefs here because
+ # an array with freed buffer is ok to see - it's just empty with 0
+ # length
self.setlen(0)
def setlen(self, size):
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -824,6 +824,22 @@
r = weakref.ref(a)
assert r() is a
+ def test_subclass_del(self):
+ import array, gc, weakref
+ l = []
+
+ class A(array.array):
+ pass
+
+ a = A('d')
+ a.append(3.0)
+ r = weakref.ref(a, lambda a: l.append(a()))
+ del a
+ gc.collect()
+ assert l
+ assert l[0] is None or len(l[0]) == 0
+
+
class TestCPythonsOwnArray(BaseArrayTests):
def setup_class(cls):
@@ -844,11 +860,7 @@
cls.w_tempfile = cls.space.wrap(
str(py.test.ensuretemp('array').join('tmpfile')))
cls.w_maxint = cls.space.wrap(sys.maxint)
-
-
-
-
-
+
def test_buffer_info(self):
a = self.array('c', 'Hi!')
bi = a.buffer_info()
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -116,6 +116,12 @@
def setitem_w(self, space, storage, i, w_item):
self.setitem(storage, i, self.unwrap(space, w_item))
+ def fill(self, storage, item, start, stop):
+ storage = self.unerase(storage)
+ item = self.unbox(item)
+ for i in xrange(start, stop):
+ storage[i] = item
+
if "adapt_val" not in exclude_methods:
@specialize.argtype(1)
def adapt_val(self, val):
@@ -182,9 +188,6 @@
@binop
def mul(self, v1, v2):
return v1 * v2
- @binop
- def div(self, v1, v2):
- return v1 / v2
@unaryop
def pos(self, v):
@@ -238,6 +241,14 @@
return float2string(self.for_computation(self.unbox(item)), 'g', rfloat.DTSF_STR_PRECISION)
@binop
+ def div(self, v1, v2):
+ try:
+ return v1 / v2
+ except ZeroDivisionError:
+ if v1 == v2 == 0.0:
+ return rfloat.NAN
+ return rfloat.copysign(rfloat.INFINITY, v1 * v2)
+ @binop
def mod(self, v1, v2):
return math.fmod(v1, v2)
@binop
@@ -316,6 +327,11 @@
return str(widen(self.unbox(item)))
@binop
+ def div(self, v1, v2):
+ if v2 == 0:
+ return 0
+ return v1 / v2
+ @binop
def mod(self, v1, v2):
return v1 % v2
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -563,8 +563,7 @@
arr = SingleDimArray(size, dtype=dtype)
one = dtype.adapt_val(1)
- for i in xrange(size):
- arr.dtype.setitem(arr.storage, i, one)
+ arr.dtype.fill(arr.storage, one, 0, size)
return space.wrap(arr)
BaseArray.typedef = TypeDef(
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -285,7 +285,9 @@
assert b[i] == i * 5
def test_div(self):
- from numpy import array, dtype
+ from math import isnan
+ from numpy import array, dtype, inf
+
a = array(range(1, 6))
b = a / a
for i in range(5):
@@ -297,6 +299,24 @@
for i in range(5):
assert b[i] == 1
+ a = array([-1, 0, 1])
+ b = array([0, 0, 0])
+ c = a / b
+ assert (c == [0, 0, 0]).all()
+
+ a = array([-1.0, 0.0, 1.0])
+ b = array([0.0, 0.0, 0.0])
+ c = a / b
+ assert c[0] == -inf
+ assert isnan(c[1])
+ assert c[2] == inf
+
+ b = array([-0.0, -0.0, -0.0])
+ c = a / b
+ assert c[0] == inf
+ assert isnan(c[1])
+ assert c[2] == -inf
+
def test_div_other(self):
from numpy import array
a = array(range(5))
diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py
--- a/pypy/module/pyexpat/__init__.py
+++ b/pypy/module/pyexpat/__init__.py
@@ -4,12 +4,8 @@
class ErrorsModule(MixedModule):
"Definition of pyexpat.errors module."
-
- appleveldefs = {
- }
-
- interpleveldefs = {
- }
+ appleveldefs = {}
+ interpleveldefs = {}
def setup_after_space_initialization(self):
from pypy.module.pyexpat import interp_pyexpat
@@ -18,6 +14,18 @@
interp_pyexpat.ErrorString(self.space,
getattr(interp_pyexpat, name)))
+class ModelModule(MixedModule):
+ "Definition of pyexpat.model module."
+ appleveldefs = {}
+ interpleveldefs = {}
+
+ def setup_after_space_initialization(self):
+ from pypy.module.pyexpat import interp_pyexpat
+ space = self.space
+ for name in interp_pyexpat.xml_model_list:
+ value = getattr(interp_pyexpat, name)
+ space.setattr(self, space.wrap(name), space.wrap(value))
+
class Module(MixedModule):
"Python wrapper for Expat parser."
@@ -39,6 +47,7 @@
submodules = {
'errors': ErrorsModule,
+ 'model': ModelModule,
}
for name in ['XML_PARAM_ENTITY_PARSING_NEVER',
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -76,6 +76,18 @@
"XML_ERROR_FINISHED",
"XML_ERROR_SUSPEND_PE",
]
+xml_model_list = [
+ "XML_CTYPE_EMPTY",
+ "XML_CTYPE_ANY",
+ "XML_CTYPE_MIXED",
+ "XML_CTYPE_NAME",
+ "XML_CTYPE_CHOICE",
+ "XML_CTYPE_SEQ",
+ "XML_CQUANT_NONE",
+ "XML_CQUANT_OPT",
+ "XML_CQUANT_REP",
+ "XML_CQUANT_PLUS",
+ ]
class CConfigure:
_compilation_info_ = eci
@@ -104,6 +116,8 @@
for name in xml_error_list:
locals()[name] = rffi_platform.ConstantInteger(name)
+ for name in xml_model_list:
+ locals()[name] = rffi_platform.ConstantInteger(name)
for k, v in rffi_platform.configure(CConfigure).items():
globals()[k] = v
diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py
--- a/pypy/module/pyexpat/test/test_parser.py
+++ b/pypy/module/pyexpat/test/test_parser.py
@@ -131,3 +131,7 @@
'encoding specified in XML declaration is incorrect')
assert (pyexpat.errors.XML_ERROR_XML_DECL ==
'XML declaration not well-formed')
+
+ def test_model(self):
+ import pyexpat
+ assert isinstance(pyexpat.model.XML_CTYPE_EMPTY, int)
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -137,20 +137,15 @@
def jump_absolute(self, jumpto, _, ec=None):
if we_are_jitted():
- # Normally, the tick counter is decremented by 100 for every
- # Python opcode. Here, to better support JIT compilation of
- # small loops, we decrement it by a possibly smaller constant.
- # We get the maximum 100 when the (unoptimized) trace length
- # is at least 3200 (a bit randomly).
- trace_length = r_uint(current_trace_length())
- decr_by = trace_length // 32
- if decr_by < 1:
- decr_by = 1
- elif decr_by > 100: # also if current_trace_length() returned -1
- decr_by = 100
+ #
+ # assume that only threads are using the bytecode counter
+ decr_by = 0
+ if self.space.actionflag.has_bytecode_counter: # constant-folded
+ if self.space.threadlocals.gil_ready: # quasi-immutable field
+ decr_by = _get_adapted_tick_counter()
#
self.last_instr = intmask(jumpto)
- ec.bytecode_trace(self, intmask(decr_by))
+ ec.bytecode_trace(self, decr_by)
jumpto = r_uint(self.last_instr)
#
pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto,
@@ -158,6 +153,20 @@
is_being_profiled=self.is_being_profiled)
return jumpto
+def _get_adapted_tick_counter():
+ # Normally, the tick counter is decremented by 100 for every
+ # Python opcode. Here, to better support JIT compilation of
+ # small loops, we decrement it by a possibly smaller constant.
+ # We get the maximum 100 when the (unoptimized) trace length
+ # is at least 3200 (a bit randomly).
+ trace_length = r_uint(current_trace_length())
+ decr_by = trace_length // 32
+ if decr_by < 1:
+ decr_by = 1
+ elif decr_by > 100: # also if current_trace_length() returned -1
+ decr_by = 100
+ return intmask(decr_by)
+
PyCode__initialize = PyCode._initialize
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -16,7 +16,8 @@
if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
'imp', 'sys', 'array', '_ffi', 'itertools', 'operator',
'posix', '_socket', '_sre', '_lsprof', '_weakref',
- '__pypy__', 'cStringIO', '_collections', 'struct']:
+ '__pypy__', 'cStringIO', '_collections', 'struct',
+ 'mmap']:
return True
return False
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -225,6 +225,8 @@
# strip comment
if '#' in line:
line = line[:line.index('#')]
+ if line.strip() == 'guard_not_invalidated?':
+ return 'guard_not_invalidated', None, [], '...', False
# find the resvar, if any
if ' = ' in line:
resvar, _, line = line.partition(' = ')
@@ -249,7 +251,7 @@
descr = descr[len('descr='):]
else:
descr = None
- return opname, resvar, args, descr
+ return opname, resvar, args, descr, True
@classmethod
def preprocess_expected_src(cls, src):
@@ -258,13 +260,23 @@
# replaced with the corresponding operations, so that tests don't have
# to repeat it every time
ticker_check = """
+ guard_not_invalidated?
+ ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+ ticker_cond0 = int_lt(ticker0, 0)
+ guard_false(ticker_cond0, descr=...)
+ """
+ src = src.replace('--TICK--', ticker_check)
+ #
+ # this is the ticker check generated if we have threads
+ thread_ticker_check = """
+ guard_not_invalidated?
ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
ticker1 = int_sub(ticker0, 1)
setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
ticker_cond0 = int_lt(ticker1, 0)
guard_false(ticker_cond0, descr=...)
"""
- src = src.replace('--TICK--', ticker_check)
+ src = src.replace('--THREAD-TICK--', thread_ticker_check)
#
# this is the ticker check generated in PyFrame.handle_operation_error
exc_ticker_check = """
@@ -298,7 +310,7 @@
if not cond:
raise InvalidMatch(message, frame=sys._getframe(1))
- def match_op(self, op, (exp_opname, exp_res, exp_args, exp_descr)):
+ def match_op(self, op, (exp_opname, exp_res, exp_args, exp_descr, _)):
self._assert(op.name == exp_opname, "operation mismatch")
self.match_var(op.res, exp_res)
if exp_args != ['...']:
@@ -341,7 +353,7 @@
what is after the '...'
"""
iter_exp_ops = iter(expected_ops)
- iter_ops = iter(self.ops)
+ iter_ops = RevertableIterator(self.ops)
for opindex, exp_op in enumerate(iter_exp_ops):
try:
if exp_op == '...':
@@ -360,6 +372,9 @@
break
self.match_op(op, exp_op)
except InvalidMatch, e:
+ if exp_op[4] is False: # optional operation
+ iter_ops.revert_one()
+ continue # try to match with the next exp_op
e.opindex = opindex
raise
#
@@ -372,8 +387,8 @@
return ''
text = str(py.code.Source(src).deindent().indent())
lines = text.splitlines(True)
- if opindex is not None and 0 <= opindex < len(lines):
- lines[opindex] = lines[opindex].rstrip() + '\t<=====\n'
+ if opindex is not None and 0 <= opindex <= len(lines):
+ lines.insert(opindex, '\n\t===== HERE =====\n')
return ''.join(lines)
#
expected_src = self.preprocess_expected_src(expected_src)
@@ -398,3 +413,18 @@
else:
return True
+
+class RevertableIterator(object):
+ def __init__(self, sequence):
+ self.sequence = sequence
+ self.index = 0
+ def __iter__(self):
+ return self
+ def next(self):
+ index = self.index
+ if index == len(self.sequence):
+ raise StopIteration
+ self.index = index + 1
+ return self.sequence[index]
+ def revert_one(self):
+ self.index -= 1
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -145,15 +145,17 @@
def test_parse_op(self):
res = OpMatcher.parse_op(" a = int_add( b, 3 ) # foo")
- assert res == ("int_add", "a", ["b", "3"], None)
+ assert res == ("int_add", "a", ["b", "3"], None, True)
res = OpMatcher.parse_op("guard_true(a)")
- assert res == ("guard_true", None, ["a"], None)
+ assert res == ("guard_true", None, ["a"], None, True)
res = OpMatcher.parse_op("setfield_gc(p0, i0, descr=<foobar>)")
- assert res == ("setfield_gc", None, ["p0", "i0"], "<foobar>")
+ assert res == ("setfield_gc", None, ["p0", "i0"], "<foobar>", True)
res = OpMatcher.parse_op("i1 = getfield_gc(p0, descr=<foobar>)")
- assert res == ("getfield_gc", "i1", ["p0"], "<foobar>")
+ assert res == ("getfield_gc", "i1", ["p0"], "<foobar>", True)
res = OpMatcher.parse_op("p0 = force_token()")
- assert res == ("force_token", "p0", [], None)
+ assert res == ("force_token", "p0", [], None, True)
+ res = OpMatcher.parse_op("guard_not_invalidated?")
+ assert res == ("guard_not_invalidated", None, [], '...', False)
def test_exact_match(self):
loop = """
@@ -341,7 +343,7 @@
# this is the actual loop
'int_lt', 'guard_true', 'int_add',
# this is the signal checking stuff
- 'getfield_raw', 'int_sub', 'setfield_raw', 'int_lt', 'guard_false',
+ 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false',
'jump'
]
@@ -407,7 +409,7 @@
# this is the actual loop
'int_lt', 'guard_true', 'force_token', 'int_add',
# this is the signal checking stuff
- 'getfield_raw', 'int_sub', 'setfield_raw', 'int_lt', 'guard_false',
+ 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false',
'jump'
]
@@ -425,10 +427,9 @@
guard_true(i6, descr=...)
i8 = int_add(i4, 1)
# signal checking stuff
+ guard_not_invalidated(descr=...)
i10 = getfield_raw(37212896, descr=<.* pypysig_long_struct.c_value .*>)
- i12 = int_sub(i10, 1)
- setfield_raw(37212896, i12, descr=<.* pypysig_long_struct.c_value .*>)
- i14 = int_lt(i12, 0)
+ i14 = int_lt(i10, 0)
guard_false(i14, descr=...)
jump(p0, p1, p2, p3, i8, descr=...)
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -465,3 +465,25 @@
setfield_gc(p4, p22, descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
jump(p0, p1, p2, p3, p4, p7, p22, p7, descr=<Loop0>)
""")
+
+ def test_kwargs_virtual(self):
+ def main(n):
+ def g(**kwargs):
+ return kwargs["x"] + 1
+
+ i = 0
+ while i < n:
+ i = g(x=i)
+ return i
+
+ log = self.run(main, [500])
+ assert log.result == 500
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i2 = int_lt(i0, i1)
+ guard_true(i2, descr=...)
+ i3 = force_token()
+ i4 = int_add(i0, 1)
+ --TICK--
+ jump(..., descr=...)
+ """)
\ No newline at end of file
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -44,9 +44,9 @@
# gc_id call is hoisted out of the loop, the id of a value obviously
# can't change ;)
assert loop.match_by_id("getitem", """
- i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...)
+ i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
...
- p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...)
+ p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
...
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -329,4 +329,20 @@
guard_false(i28, descr=...)
i30 = int_lshift(i20, 24)
i31 = int_or(i26, i30)
- """ % {"32_bit_only": extra})
\ No newline at end of file
+ """ % {"32_bit_only": extra})
+
+ def test_eval(self):
+ def main():
+ i = 1
+ a = compile('x+x+x+x+x+x', 'eval', 'eval')
+ b = {'x': 7}
+ while i < 1000:
+ y = eval(a,b,b) # ID: eval
+ i += 1
+ return y
+
+ log = self.run(main)
+ assert log.result == 42
+ # the following assertion fails if the loop was cancelled due
+ # to "abort: vable escape"
+ assert len(log.loops_by_id("eval")) == 1
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -41,7 +41,7 @@
guard_true(i32, descr=...)
i34 = int_add(i6, 1)
--TICK--
- jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=<Loop4>)
+ jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=...)
""")
def test_long(self):
@@ -93,7 +93,8 @@
i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
guard_false(i46, descr=...)
p51 = new_with_vtable(21136408)
- setfield_gc(p51, _, descr=...) # 6 setfields, but the order is dict-order-dependent
+ setfield_gc(p51, _, descr=...) # 7 setfields, but the order is dict-order-dependent
+ setfield_gc(p51, _, descr=...)
setfield_gc(p51, _, descr=...)
setfield_gc(p51, _, descr=...)
setfield_gc(p51, _, descr=...)
@@ -106,7 +107,7 @@
i58 = int_add_ovf(i6, i57)
guard_no_overflow(descr=...)
--TICK--
- jump(p0, p1, p2, p3, p4, p5, i58, i7, descr=<Loop4>)
+ jump(p0, p1, p2, p3, p4, p5, i58, i7, descr=...)
""")
def test_str_mod(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -0,0 +1,28 @@
+from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
+
+class TestThread(BaseTestPyPyC):
+ def test_simple(self):
+ def main(n):
+ import thread
+ def f():
+ i = 0
+ while i < n:
+ i += 1
+ done.release()
+
+ done = thread.allocate_lock()
+ done.acquire()
+ thread.start_new_thread(f, ())
+ done.acquire()
+ return 0
+ log = self.run(main, [500])
+ assert round(log.result, 6) == round(main(500), 6)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i2 = int_lt(i0, i1)
+ guard_true(i2, descr=...)
+ i3 = int_add(i0, 1)
+ --THREAD-TICK--
+ jump(..., descr=<Loop0>)
+ """)
diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py
--- a/pypy/module/rctime/interp_time.py
+++ b/pypy/module/rctime/interp_time.py
@@ -245,6 +245,9 @@
if sys.platform != 'win32':
@unwrap_spec(secs=float)
def sleep(space, secs):
+ if secs < 0:
+ raise OperationError(space.w_IOError,
+ space.wrap("Invalid argument: negative time in sleep"))
pytime.sleep(secs)
else:
from pypy.rlib import rwin32
@@ -265,6 +268,9 @@
OSError(EINTR, "sleep() interrupted"))
@unwrap_spec(secs=float)
def sleep(space, secs):
+ if secs < 0:
+ raise OperationError(space.w_IOError,
+ space.wrap("Invalid argument: negative time in sleep"))
# as decreed by Guido, only the main thread can be
# interrupted.
main_thread = space.fromcache(State).main_thread
diff --git a/pypy/module/rctime/test/test_rctime.py b/pypy/module/rctime/test/test_rctime.py
--- a/pypy/module/rctime/test/test_rctime.py
+++ b/pypy/module/rctime/test/test_rctime.py
@@ -20,8 +20,9 @@
import sys
import os
raises(TypeError, rctime.sleep, "foo")
- rctime.sleep(1.2345)
-
+ rctime.sleep(0.12345)
+ raises(IOError, rctime.sleep, -1.0)
+
def test_clock(self):
import time as rctime
rctime.clock()
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -109,8 +109,11 @@
p = pypysig_getaddr_occurred()
value = p.c_value
if self.has_bytecode_counter: # this 'if' is constant-folded
- value -= by
- p.c_value = value
+ if jit.isconstant(by) and by == 0:
+ pass # normally constant-folded too
+ else:
+ value -= by
+ p.c_value = value
return value
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -47,7 +47,7 @@
'pypy_initial_path' : 'state.pypy_initial_path',
'_getframe' : 'vm._getframe',
- '_current_frames' : 'vm._current_frames',
+ '_current_frames' : 'currentframes._current_frames',
'setrecursionlimit' : 'vm.setrecursionlimit',
'getrecursionlimit' : 'vm.getrecursionlimit',
'setcheckinterval' : 'vm.setcheckinterval',
diff --git a/pypy/module/sys/currentframes.py b/pypy/module/sys/currentframes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/sys/currentframes.py
@@ -0,0 +1,78 @@
+"""
+Implementation of the 'sys._current_frames()' routine.
+"""
+from pypy.interpreter import gateway
+
+app = gateway.applevel('''
+"NOT_RPYTHON"
+import __builtin__
+
+class fake_code(object):
+ co_name = "?"
+ co_filename = "?"
+ co_firstlineno = 0
+
+class fake_frame(object):
+ f_back = None
+ f_builtins = __builtin__.__dict__
+ f_code = fake_code()
+ f_exc_traceback = None
+ f_exc_type = None
+ f_exc_value = None
+ f_globals = {}
+ f_lasti = -1
+ f_lineno = 0
+ f_locals = {}
+ f_restricted = False
+ f_trace = None
+
+ def __init__(self, f):
+ if f is not None:
+ for name in ["f_builtins", "f_code", "f_globals", "f_lasti",
+ "f_lineno"]:
+ setattr(self, name, getattr(f, name))
+''')
+
+def _current_frames(space):
+ """_current_frames() -> dictionary
+
+ Return a dictionary mapping each current thread T's thread id to T's
+ current stack "frame". Functions in the traceback module can build the
+ call stack given such a frame.
+
+ Note that in PyPy this returns fake frame objects, to avoid a runtime
+ penalty everywhere with the JIT. (So far these fake frames can be
+ completely uninformative depending on the JIT state; we could return
+ more with more efforts.)
+
+ This function should be used for specialized purposes only."""
+ w_result = space.newdict()
+ w_fake_frame = app.wget(space, "fake_frame")
+ w_fake_code = app.wget(space, "fake_code")
+ ecs = space.threadlocals.getallvalues()
+ for thread_ident, ec in ecs.items():
+ vref = ec.topframeref
+ frames = []
+ while not vref.virtual:
+ f = vref()
+ if f is None:
+ break
+ frames.append(f)
+ vref = f.f_backref
+ else:
+ frames.append(None)
+ #
+ w_topframe = space.wrap(None)
+ w_prevframe = None
+ for f in frames:
+ w_nextframe = space.call_function(w_fake_frame, space.wrap(f))
+ if w_prevframe is None:
+ w_topframe = w_nextframe
+ else:
+ space.setattr(w_prevframe, space.wrap('f_back'), w_nextframe)
+ w_prevframe = w_nextframe
+ #
+ space.setitem(w_result,
+ space.wrap(thread_ident),
+ w_topframe)
+ return w_result
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -556,7 +556,7 @@
return sys._current_frames()
frames = f()
assert frames.keys() == [0]
- assert frames[0].f_code.co_name == 'f'
+ assert frames[0].f_code.co_name in ('f', '?')
class AppTestCurrentFramesWithThread(AppTestCurrentFrames):
def setup_class(cls):
@@ -568,23 +568,25 @@
import thread
thread_id = thread.get_ident()
- self.ready = False
def other_thread():
- self.ready = True
print "thread started"
- time.sleep(5)
+ lock2.release()
+ lock1.acquire()
+ lock1 = thread.allocate_lock()
+ lock2 = thread.allocate_lock()
+ lock1.acquire()
+ lock2.acquire()
thread.start_new_thread(other_thread, ())
def f():
- for i in range(100):
- if self.ready: break
- time.sleep(0.1)
+ lock2.acquire()
return sys._current_frames()
frames = f()
+ lock1.release()
thisframe = frames.pop(thread_id)
- assert thisframe.f_code.co_name == 'f'
+ assert thisframe.f_code.co_name in ('f', '?')
assert len(frames) == 1
_, other_frame = frames.popitem()
- assert other_frame.f_code.co_name == 'other_thread'
+ assert other_frame.f_code.co_name in ('other_thread', '?')
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -45,25 +45,6 @@
f.mark_as_escaped()
return space.wrap(f)
-def _current_frames(space):
- """_current_frames() -> dictionary
-
- Return a dictionary mapping each current thread T's thread id to T's
- current stack frame.
-
- This function should be used for specialized purposes only."""
- raise OperationError(space.w_NotImplementedError,
- space.wrap("XXX sys._current_frames() incompatible with the JIT"))
- w_result = space.newdict()
- ecs = space.threadlocals.getallvalues()
- for thread_ident, ec in ecs.items():
- f = ec.gettopframe_nohidden()
- f.mark_as_escaped()
- space.setitem(w_result,
- space.wrap(thread_ident),
- space.wrap(f))
- return w_result
-
def setrecursionlimit(space, w_new_limit):
"""setrecursionlimit() sets the maximum number of nested calls that
can occur before a RuntimeError is raised. On PyPy the limit is
diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -17,6 +17,7 @@
class GILThreadLocals(OSThreadLocals):
"""A version of OSThreadLocals that enforces a GIL."""
gil_ready = False
+ _immutable_fields_ = ['gil_ready?']
def initialize(self, space):
# add the GIL-releasing callback as an action on the space
diff --git a/pypy/module/thread/threadlocals.py b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -8,9 +8,14 @@
def __init__(self):
self._valuedict = {} # {thread_ident: ExecutionContext()}
+ self._freeze_()
+
+ def _freeze_(self):
+ self._valuedict.clear()
self._mainthreadident = 0
self._mostrecentkey = 0 # fast minicaching for the common case
self._mostrecentvalue = None # fast minicaching for the common case
+ return False
def getvalue(self):
ident = thread.get_ident()
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -120,6 +120,8 @@
out.append_slice(s, last_literal, end)
return out.build()
+ # This is only ever called if we're already unrolling _do_build_string
+ @jit.unroll_safe
def _parse_field(self, start, end):
s = self.template
# Find ":" or "!"
@@ -149,6 +151,7 @@
i += 1
return s[start:end], None, end
+ @jit.unroll_safe
def _get_argument(self, name):
# First, find the argument.
space = self.space
@@ -207,6 +210,7 @@
raise OperationError(space.w_IndexError, w_msg)
return self._resolve_lookups(w_arg, name, i, end)
+ @jit.unroll_safe
def _resolve_lookups(self, w_obj, name, start, end):
# Resolve attribute and item lookups.
space = self.space
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -83,11 +83,12 @@
if self.config.objspace.std.withtproxy:
transparent.setup(self)
+ interplevel_classes = {}
for type, classes in self.model.typeorder.iteritems():
- if len(classes) >= 3:
+ if len(classes) >= 3: # XXX what does this 3 mean??!
# W_Root, AnyXxx and actual object
- self.gettypefor(type).interplevel_cls = classes[0][0]
-
+ interplevel_classes[self.gettypefor(type)] = classes[0][0]
+ self._interplevel_classes = interplevel_classes
def get_builtin_types(self):
return self.builtin_types
@@ -579,7 +580,7 @@
raise OperationError(self.w_TypeError,
self.wrap("need type object"))
if is_annotation_constant(w_type):
- cls = w_type.interplevel_cls
+ cls = self._get_interplevel_cls(w_type)
if cls is not None:
assert w_inst is not None
if isinstance(w_inst, cls):
@@ -589,3 +590,9 @@
@specialize.arg_or_var(2)
def isinstance_w(space, w_inst, w_type):
return space._type_isinstance(w_inst, w_type)
+
+ @specialize.memo()
+ def _get_interplevel_cls(self, w_type):
+ if not hasattr(self, "_interplevel_classes"):
+ return None # before running initialize
+ return self._interplevel_classes.get(w_type, None)
diff --git a/pypy/objspace/std/smallintobject.py b/pypy/objspace/std/smallintobject.py
--- a/pypy/objspace/std/smallintobject.py
+++ b/pypy/objspace/std/smallintobject.py
@@ -12,6 +12,7 @@
from pypy.rlib.rbigint import rbigint
from pypy.rlib.rarithmetic import r_uint
from pypy.tool.sourcetools import func_with_new_name
+from pypy.objspace.std.inttype import wrapint
class W_SmallIntObject(W_Object, UnboxedValue):
__slots__ = 'intval'
@@ -48,14 +49,36 @@
def delegate_SmallInt2Complex(space, w_small):
return space.newcomplex(float(w_small.intval), 0.0)
+def add__SmallInt_SmallInt(space, w_a, w_b):
+ return wrapint(space, w_a.intval + w_b.intval) # cannot overflow
+
+def sub__SmallInt_SmallInt(space, w_a, w_b):
+ return wrapint(space, w_a.intval - w_b.intval) # cannot overflow
+
+def floordiv__SmallInt_SmallInt(space, w_a, w_b):
+ return wrapint(space, w_a.intval // w_b.intval) # cannot overflow
+
+div__SmallInt_SmallInt = floordiv__SmallInt_SmallInt
+
+def mod__SmallInt_SmallInt(space, w_a, w_b):
+ return wrapint(space, w_a.intval % w_b.intval) # cannot overflow
+
+def divmod__SmallInt_SmallInt(space, w_a, w_b):
+ w = wrapint(space, w_a.intval // w_b.intval) # cannot overflow
+ z = wrapint(space, w_a.intval % w_b.intval)
+ return space.newtuple([w, z])
+
def copy_multimethods(ns):
"""Copy integer multimethods for small int."""
for name, func in intobject.__dict__.iteritems():
if "__Int" in name:
new_name = name.replace("Int", "SmallInt")
- # Copy the function, so the annotator specializes it for
- # W_SmallIntObject.
- ns[new_name] = func_with_new_name(func, new_name)
+ if new_name not in ns:
+ # Copy the function, so the annotator specializes it for
+ # W_SmallIntObject.
+ ns[new_name] = func = func_with_new_name(func, new_name, globals=ns)
+ else:
+ ns[name] = func
ns["get_integer"] = ns["pos__SmallInt"] = ns["int__SmallInt"]
ns["get_negint"] = ns["neg__SmallInt"]
diff --git a/pypy/objspace/std/strutil.py b/pypy/objspace/std/strutil.py
--- a/pypy/objspace/std/strutil.py
+++ b/pypy/objspace/std/strutil.py
@@ -35,7 +35,7 @@
def error(self):
raise ParseStringError("invalid literal for %s() with base %d: '%s'" %
- (self.fname, self.base, self.literal))
+ (self.fname, self.original_base, self.literal))
def __init__(self, s, literal, base, fname):
self.literal = literal
@@ -47,7 +47,8 @@
elif s.startswith('+'):
s = strip_spaces(s[1:])
self.sign = sign
-
+ self.original_base = base
+
if base == 0:
if s.startswith('0x') or s.startswith('0X'):
base = 16
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -102,3 +102,11 @@
def __repr__(self):
return 123456
assert A().__str__() == 123456
+
+def test_isinstance_shortcut():
+ from pypy.objspace.std import objspace
+ space = objspace.StdObjSpace()
+ w_a = space.wrap("a")
+ space.type = None
+ space.isinstance_w(w_a, space.w_str) # does not crash
+
diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -14,11 +14,11 @@
def test_int_w_non_int(self):
raises(OperationError,self.space.int_w,self.space.wrap(None))
- raises(OperationError,self.space.int_w,self.space.wrap(""))
+ raises(OperationError,self.space.int_w,self.space.wrap(""))
def test_uint_w_non_int(self):
raises(OperationError,self.space.uint_w,self.space.wrap(None))
- raises(OperationError,self.space.uint_w,self.space.wrap(""))
+ raises(OperationError,self.space.uint_w,self.space.wrap(""))
def test_multimethods_defined_on(self):
from pypy.objspace.std.stdtypedef import multimethods_defined_on
@@ -49,14 +49,14 @@
def test_fastpath_isinstance(self):
from pypy.objspace.std.stringobject import W_StringObject
from pypy.objspace.std.intobject import W_IntObject
-
+
space = self.space
- assert space.w_str.interplevel_cls is W_StringObject
- assert space.w_int.interplevel_cls is W_IntObject
+ assert space._get_interplevel_cls(space.w_str) is W_StringObject
+ assert space._get_interplevel_cls(space.w_int) is W_IntObject
class X(W_StringObject):
def __init__(self):
pass
-
+
typedef = None
assert space.isinstance_w(X(), space.w_str)
diff --git a/pypy/objspace/std/test/test_strutil.py b/pypy/objspace/std/test/test_strutil.py
--- a/pypy/objspace/std/test/test_strutil.py
+++ b/pypy/objspace/std/test/test_strutil.py
@@ -89,6 +89,8 @@
exc = raises(ParseStringError, string_to_int, '')
assert exc.value.msg == "invalid literal for int() with base 10: ''"
+ exc = raises(ParseStringError, string_to_int, '', 0)
+ assert exc.value.msg == "invalid literal for int() with base 0: ''"
def test_string_to_int_overflow(self):
import sys
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -102,7 +102,6 @@
'instancetypedef',
'terminator',
'_version_tag?',
- 'interplevel_cls',
]
# for config.objspace.std.getattributeshortcut
@@ -117,9 +116,6 @@
# of the __new__ is an instance of the type
w_bltin_new = None
- interplevel_cls = None # not None for prebuilt instances of
- # interpreter-level types
-
@dont_look_inside
def __init__(w_self, space, name, bases_w, dict_w,
overridetypedef=None):
diff --git a/pypy/pytest.ini b/pypy/pytest.ini
--- a/pypy/pytest.ini
+++ b/pypy/pytest.ini
@@ -1,2 +1,2 @@
[pytest]
-addopts = --assertmode=old
\ No newline at end of file
+addopts = --assertmode=old -rf
diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py
--- a/pypy/rlib/_jit_vref.py
+++ b/pypy/rlib/_jit_vref.py
@@ -25,6 +25,10 @@
def simple_call(self):
return self.s_instance
+ def getattr(self, s_attr):
+ assert s_attr.const == 'virtual'
+ return annmodel.s_Bool
+
def rtyper_makerepr(self, rtyper):
if rtyper.type_system.name == 'lltypesystem':
return vrefrepr
@@ -61,6 +65,13 @@
" prebuilt virtual_ref")
return lltype.nullptr(OBJECTPTR.TO)
+ def rtype_getattr(self, hop):
+ s_attr = hop.args_s[1]
+ assert s_attr.const == 'virtual'
+ v = hop.inputarg(self, arg=0)
+ hop.exception_cannot_occur()
+ return hop.genop('jit_is_virtual', [v], resulttype = lltype.Bool)
+
from pypy.rpython.ootypesystem.rclass import OBJECT
class OOVRefRepr(VRefRepr):
diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py
--- a/pypy/rlib/_rsocket_rffi.py
+++ b/pypy/rlib/_rsocket_rffi.py
@@ -16,6 +16,7 @@
_MINGW = target_platform.name == "mingw32"
_SOLARIS = sys.platform == "sunos5"
_MACOSX = sys.platform == "darwin"
+_HAS_AF_PACKET = sys.platform.startswith('linux') # only Linux for now
if _POSIX:
includes = ('sys/types.h',
@@ -34,11 +35,12 @@
'stdint.h',
'errno.h',
)
+ if _HAS_AF_PACKET:
+ includes += ('netpacket/packet.h',
+ 'sys/ioctl.h',
+ 'net/if.h')
- cond_includes = [('AF_NETLINK', 'linux/netlink.h'),
- ('AF_PACKET', 'netpacket/packet.h'),
- ('AF_PACKET', 'sys/ioctl.h'),
- ('AF_PACKET', 'net/if.h')]
+ cond_includes = [('AF_NETLINK', 'linux/netlink.h')]
libraries = ()
calling_conv = 'c'
@@ -320,18 +322,18 @@
('events', rffi.SHORT),
('revents', rffi.SHORT)])
- CConfig.sockaddr_ll = platform.Struct('struct sockaddr_ll',
+ if _HAS_AF_PACKET:
+ CConfig.sockaddr_ll = platform.Struct('struct sockaddr_ll',
[('sll_ifindex', rffi.INT),
('sll_protocol', rffi.INT),
('sll_pkttype', rffi.INT),
('sll_hatype', rffi.INT),
('sll_addr', rffi.CFixedArray(rffi.CHAR, 8)),
- ('sll_halen', rffi.INT)],
- ifdef='AF_PACKET')
+ ('sll_halen', rffi.INT)])
- CConfig.ifreq = platform.Struct('struct ifreq', [('ifr_ifindex', rffi.INT),
- ('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))],
- ifdef='AF_PACKET')
+ CConfig.ifreq = platform.Struct('struct ifreq',
+ [('ifr_ifindex', rffi.INT),
+ ('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))])
if _WIN32:
CConfig.WSAEVENT = platform.SimpleType('WSAEVENT', rffi.VOIDP)
@@ -386,6 +388,8 @@
constants[name] = value
else:
constants[name] = default
+if not _HAS_AF_PACKET and 'AF_PACKET' in constants:
+ del constants['AF_PACKET']
constants['has_ipv6'] = True # This is a configuration option in CPython
for name, value in constants.items():
@@ -439,21 +443,14 @@
if _POSIX:
nfds_t = cConfig.nfds_t
pollfd = cConfig.pollfd
- if cConfig.sockaddr_ll is not None:
+ if _HAS_AF_PACKET:
sockaddr_ll = cConfig.sockaddr_ll
- ifreq = cConfig.ifreq
+ ifreq = cConfig.ifreq
if WIN32:
WSAEVENT = cConfig.WSAEVENT
WSANETWORKEVENTS = cConfig.WSANETWORKEVENTS
timeval = cConfig.timeval
-#if _POSIX:
-# includes = list(includes)
-# for _name, _header in cond_includes:
-# if getattr(cConfig, _name) is not None:
-# includes.append(_header)
-# eci = ExternalCompilationInfo(includes=includes, libraries=libraries,
-# separate_module_sources=sources)
def external(name, args, result, **kwds):
return rffi.llexternal(name, args, result, compilation_info=eci,
@@ -544,7 +541,7 @@
socketpair_t = rffi.CArray(socketfd_type)
socketpair = external('socketpair', [rffi.INT, rffi.INT, rffi.INT,
lltype.Ptr(socketpair_t)], rffi.INT)
- if ifreq is not None:
+ if _HAS_AF_PACKET:
ioctl = external('ioctl', [socketfd_type, rffi.INT, lltype.Ptr(ifreq)],
rffi.INT)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -8,6 +8,8 @@
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.tool.sourcetools import func_with_new_name
+DEBUG_ELIDABLE_FUNCTIONS = False
+
def elidable(func):
""" Decorate a function as "trace-elidable". This means precisely that:
@@ -24,6 +26,18 @@
If a particular call to this function ends up raising an exception, then it
is handled like a normal function call (this decorator is ignored).
"""
+ if DEBUG_ELIDABLE_FUNCTIONS:
+ cache = {}
+ oldfunc = func
+ def func(*args):
+ result = oldfunc(*args) # if it raises, no caching
+ try:
+ oldresult = cache.setdefault(args, result)
+ except TypeError:
+ pass # unhashable args
+ else:
+ assert oldresult == result
+ return result
func._elidable_function_ = True
return func
@@ -317,6 +331,12 @@
raise InvalidVirtualRef
return self._x
+ @property
+ def virtual(self):
+ """A property that is True if the vref contains a virtual that would
+ be forced by the '()' operator."""
+ return self._state == 'non-forced'
+
def _finish(self):
if self._state == 'non-forced':
self._state = 'invalid'
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -135,6 +135,8 @@
_about_ = erase_int
def compute_result_annotation(self, s_obj):
+ config = self.bookkeeper.annotator.translator.config
+ assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
assert annmodel.SomeInteger().contains(s_obj)
return SomeErased()
@@ -218,18 +220,18 @@
[v_value] = hop.inputargs(lltype.Signed)
c_one = hop.inputconst(lltype.Signed, 1)
hop.exception_is_here()
- v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+ v2 = hop.genop('int_add_ovf', [v_value, v_value],
resulttype = lltype.Signed)
v2p1 = hop.genop('int_add', [v2, c_one],
resulttype = lltype.Signed)
v_instance = hop.genop('cast_int_to_ptr', [v2p1],
resulttype=self.lowleveltype)
- v = hop.genop('cast_opaque_ptr', [v_instance],
- resulttype=self.lowleveltype)
- return v
+ return v_instance
def convert_const(self, value):
if value._identity is _identity_for_ints:
+ config = self.rtyper.annotator.translator.config
+ assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
return lltype.cast_int_to_ptr(self.lowleveltype, value._x * 2 + 1)
bk = self.rtyper.annotator.bookkeeper
s_obj = value._identity.get_input_annotation(bk)
@@ -266,10 +268,10 @@
return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed)
def rtype_erase_int(self, hop):
- hop.exception_is_here()
[v_value] = hop.inputargs(lltype.Signed)
c_one = hop.inputconst(lltype.Signed, 1)
- v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+ hop.exception_is_here()
+ v2 = hop.genop('int_add_ovf', [v_value, v_value],
resulttype = lltype.Signed)
v2p1 = hop.genop('int_add', [v2, c_one],
resulttype = lltype.Signed)
diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py
--- a/pypy/rlib/rgc.py
+++ b/pypy/rlib/rgc.py
@@ -214,6 +214,10 @@
func._gc_no_collect_ = True
return func
+def is_light_finalizer(func):
+ func._is_light_finalizer_ = True
+ return func
+
# ____________________________________________________________
def get_rpy_roots():
diff --git a/pypy/rlib/rmmap.py b/pypy/rlib/rmmap.py
--- a/pypy/rlib/rmmap.py
+++ b/pypy/rlib/rmmap.py
@@ -292,6 +292,9 @@
elif _POSIX:
self.closed = True
if self.fd != -1:
+ # XXX this is buggy - raising in an RPython del is not a good
+ # idea, we should swallow the exception or ignore the
+ # underlaying close error code
os.close(self.fd)
self.fd = -1
if self.size > 0:
diff --git a/pypy/rlib/rsocket.py b/pypy/rlib/rsocket.py
--- a/pypy/rlib/rsocket.py
+++ b/pypy/rlib/rsocket.py
@@ -8,6 +8,7 @@
# Known missing features:
#
# - address families other than AF_INET, AF_INET6, AF_UNIX, AF_PACKET
+# - AF_PACKET is only supported on Linux
# - methods makefile(),
# - SSL
#
@@ -55,6 +56,7 @@
_FAMILIES = {}
+
class Address(object):
"""The base class for RPython-level objects representing addresses.
Fields: addr - a _c.sockaddr_ptr (memory owned by the Address instance)
@@ -76,9 +78,8 @@
self.addrlen = addrlen
def __del__(self):
- addr = self.addr_p
- if addr:
- lltype.free(addr, flavor='raw')
+ if self.addr_p:
+ lltype.free(self.addr_p, flavor='raw')
def setdata(self, addr, addrlen):
# initialize self.addr and self.addrlen. 'addr' can be a different
@@ -612,7 +613,10 @@
self.timeout = defaults.timeout
def __del__(self):
- self.close()
+ fd = self.fd
+ if fd != _c.INVALID_SOCKET:
+ self.fd = _c.INVALID_SOCKET
+ _c.socketclose(fd)
if hasattr(_c, 'fcntl'):
def _setblocking(self, block):
diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py
--- a/pypy/rlib/test/test__jit_vref.py
+++ b/pypy/rlib/test/test__jit_vref.py
@@ -27,10 +27,13 @@
x1 = X()
vref = virtual_ref(x1)
assert vref._state == 'non-forced'
+ assert vref.virtual is True
assert vref() is x1
assert vref._state == 'forced'
+ assert vref.virtual is False
virtual_ref_finish(vref, x1)
assert vref._state == 'forced'
+ assert vref.virtual is False
assert vref() is x1
def test_direct_invalid():
@@ -135,6 +138,13 @@
x = self.interpret(f, [])
assert x == 42
+ def test_rtype_virtualattr(self):
+ def f():
+ vref = virtual_ref(X())
+ return vref.virtual
+ x = self.interpret(f, [])
+ assert x is False
+
class TestLLtype(BaseTestVRef, LLRtypeMixin):
OBJECTTYPE = OBJECTPTR
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -139,12 +139,11 @@
def test_isconstant(self):
def f(n):
- assert n >= 0
assert isconstant(n) is False
l = []
l.append(n)
return len(l)
- res = self.interpret(f, [234])
+ res = self.interpret(f, [-234])
assert res == 1
diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py
--- a/pypy/rlib/test/test_rerased.py
+++ b/pypy/rlib/test/test_rerased.py
@@ -10,6 +10,13 @@
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
+def make_annotator():
+ a = RPythonAnnotator()
+ a.translator.config.translation.taggedpointers = True
+ return a
+
+
+
class X(object):
pass
@@ -55,7 +62,7 @@
def test_annotate_1():
def f():
return eraseX(X())
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [])
assert isinstance(s, SomeErased)
@@ -66,7 +73,7 @@
#assert not is_integer(e)
x2 = uneraseX(e)
return x2
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [])
assert isinstance(s, annmodel.SomeInstance)
assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
@@ -77,7 +84,7 @@
#assert is_integer(e)
x2 = unerase_int(e)
return x2
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [])
assert isinstance(s, annmodel.SomeInteger)
@@ -105,7 +112,7 @@
x = make(n)
return check(x, n)
#
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [int])
assert isinstance(s, annmodel.SomeInteger)
@@ -135,7 +142,7 @@
else:
return inst
#
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [])
assert isinstance(s, annmodel.SomeInstance)
assert s.classdef == a.bookkeeper.getuniqueclassdef(A)
@@ -155,7 +162,7 @@
e = e2
return unerase(e)
#
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [int])
assert isinstance(s, annmodel.SomeInstance)
assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
@@ -165,11 +172,14 @@
e1 = erase_int(42)
def f(i):
return unerase_int(e1)
- a = RPythonAnnotator()
+ a = make_annotator()
s = a.build_types(f, [int])
assert isinstance(s, annmodel.SomeInteger)
class BaseTestRErased(BaseRtypingTest):
+ def interpret(self, *args, **kwargs):
+ kwargs["taggedpointers"] = True
+ return BaseRtypingTest.interpret(self, *args, **kwargs)
def test_rtype_1(self):
def f():
return eraseX(X())
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -1095,13 +1095,6 @@
assert y >= 0
return self.op_int_add_ovf(x, y)
- def op_cast_float_to_int(self, f):
- assert type(f) is float
- try:
- return ovfcheck(int(f))
- except OverflowError:
- self.make_llexception()
-
def op_int_is_true(self, x):
# special case
if type(x) is CDefinedIntSymbolic:
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -15,12 +15,11 @@
load_library_kwargs = {}
import os
-from pypy import conftest
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.extfunc import ExtRegistryEntry
from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
from pypy.tool.uid import fixid
-from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, base_int, intmask
+from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat, base_int, intmask
from pypy.annotation import model as annmodel
from pypy.rpython.llinterp import LLInterpreter, LLException
from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -531,6 +530,10 @@
def __str__(self):
return repr(self)
+ def _setparentstructure(self, parent, parentindex):
+ super(_parentable_mixin, self)._setparentstructure(parent, parentindex)
+ self._keepparent = parent # always keep a strong ref
+
class _struct_mixin(_parentable_mixin):
"""Mixin added to _struct containers when they become ctypes-based."""
__slots__ = ()
@@ -566,7 +569,10 @@
return 0, sys.maxint
def getitem(self, index, uninitialized_ok=False):
- return self._storage.contents._getitem(index, boundscheck=False)
+ res = self._storage.contents._getitem(index, boundscheck=False)
+ if isinstance(self._TYPE.OF, lltype.ContainerType):
+ res._obj._setparentstructure(self, index)
+ return res
def setitem(self, index, value):
self._storage.contents._setitem(index, value, boundscheck=False)
@@ -658,6 +664,8 @@
if T == llmemory.GCREF:
if isinstance(llobj._obj, _llgcopaque):
return ctypes.c_void_p(llobj._obj.intval)
+ if isinstance(llobj._obj, int): # tagged pointer
+ return ctypes.c_void_p(llobj._obj)
container = llobj._obj.container
T = lltype.Ptr(lltype.typeOf(container))
# otherwise it came from integer and we want a c_void_p with
@@ -1268,6 +1276,7 @@
class _llgcopaque(lltype._container):
_TYPE = llmemory.GCREF.TO
_name = "_llgcopaque"
+ _read_directly_intval = True # for _ptr._cast_to_int()
def __init__(self, void_p):
if isinstance(void_p, (int, long)):
@@ -1276,6 +1285,8 @@
self.intval = intmask(void_p.value)
def __eq__(self, other):
+ if not other:
+ return self.intval == 0
if isinstance(other, _llgcopaque):
return self.intval == other.intval
storage = object()
@@ -1299,11 +1310,6 @@
return _opaque_objs[self.intval // 2]
return force_cast(PTRTYPE, self.intval)
-## def _cast_to_int(self):
-## return self.intval
-
-## def _cast_to_adr(self):
-## return _lladdress(self.intval)
def cast_adr_to_int(addr):
if isinstance(addr, llmemory.fakeaddress):
diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -498,6 +498,8 @@
def _cast_to_int(self, symbolic=False):
if self:
+ if isinstance(self.ptr._obj0, int): # tagged integer
+ return self.ptr._obj0
if symbolic:
return AddressAsInt(self)
else:
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -343,8 +343,8 @@
'cast_uint_to_float': LLOp(canfold=True),
'cast_longlong_to_float' :LLOp(canfold=True),
'cast_ulonglong_to_float':LLOp(canfold=True),
- 'cast_float_to_int': LLOp(canraise=(OverflowError,), tryfold=True),
- 'cast_float_to_uint': LLOp(canfold=True), # XXX need OverflowError?
+ 'cast_float_to_int': LLOp(canfold=True),
+ 'cast_float_to_uint': LLOp(canfold=True),
'cast_float_to_longlong' :LLOp(canfold=True),
'cast_float_to_ulonglong':LLOp(canfold=True),
'truncate_longlong_to_int':LLOp(canfold=True),
@@ -428,6 +428,7 @@
'jit_marker': LLOp(),
'jit_force_virtualizable':LLOp(canrun=True),
'jit_force_virtual': LLOp(canrun=True),
+ 'jit_is_virtual': LLOp(canrun=True),
'jit_force_quasi_immutable': LLOp(canrun=True),
'get_exception_addr': LLOp(),
'get_exc_value_addr': LLOp(),
diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -1360,6 +1360,8 @@
obj = normalizeptr(self, check)._getobj(check)
if isinstance(obj, int):
return obj # special case for cast_int_to_ptr() results put into opaques
+ if getattr(obj, '_read_directly_intval', False):
+ return obj.intval # special case for _llgcopaque
result = intmask(obj._getid())
# assume that id() returns an addressish value which is
# not zero and aligned to at least a multiple of 4
@@ -1520,7 +1522,7 @@
and parentindex in (self._parent_type._names[0], 0)
and self._TYPE._gckind == typeOf(parent)._gckind):
# keep strong reference to parent, we share the same allocation
- self._keepparent = parent
+ self._keepparent = parent
def _parentstructure(self, check=True):
if self._wrparent is not None:
@@ -1711,6 +1713,7 @@
return v
def setitem(self, index, value):
+ assert typeOf(value) == self._TYPE.OF
self.items[index] = value
assert not '__dict__' in dir(_array)
@@ -1728,7 +1731,8 @@
# Keep the parent array alive, we share the same allocation.
# Don't do it if we are inside a GC object, though -- it's someone
# else's job to keep the GC object alive
- if typeOf(top_container(parent))._gckind == 'raw':
+ if (typeOf(top_container(parent))._gckind == 'raw' or
+ hasattr(top_container(parent)._storage, 'contents')): # ll2ctypes
self._keepparent = parent
def __str__(self):
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -355,6 +355,10 @@
assert type(b) is bool
return float(b)
+def op_cast_float_to_int(f):
+ assert type(f) is float
+ return intmask(int(f))
+
def op_cast_float_to_uint(f):
assert type(f) is float
return r_uint(long(f))
@@ -538,6 +542,9 @@
def op_jit_force_virtual(x):
return x
+def op_jit_is_virtual(x):
+ return False
+
def op_jit_force_quasi_immutable(*args):
pass
diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py
--- a/pypy/rpython/lltypesystem/rbuilder.py
+++ b/pypy/rpython/lltypesystem/rbuilder.py
@@ -29,7 +29,7 @@
except OverflowError:
raise MemoryError
newbuf = mallocfn(new_allocated)
- copycontentsfn(ll_builder.buf, newbuf, 0, 0, ll_builder.allocated)
+ copycontentsfn(ll_builder.buf, newbuf, 0, 0, ll_builder.used)
ll_builder.buf = newbuf
ll_builder.allocated = new_allocated
return func_with_new_name(stringbuilder_grow, name)
@@ -56,7 +56,7 @@
class BaseStringBuilderRepr(AbstractStringBuilderRepr):
def empty(self):
return nullptr(self.lowleveltype.TO)
-
+
@classmethod
def ll_new(cls, init_size):
if init_size < 0 or init_size > MAX:
diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py
--- a/pypy/rpython/lltypesystem/rdict.py
+++ b/pypy/rpython/lltypesystem/rdict.py
@@ -1,16 +1,14 @@
from pypy.tool.pairtype import pairtype
-from pypy.annotation import model as annmodel
from pypy.objspace.flow.model import Constant
-from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
- rtype_newdict
+from pypy.rpython.rdict import (AbstractDictRepr, AbstractDictIteratorRepr,
+ rtype_newdict)
from pypy.rpython.lltypesystem import lltype
+from pypy.rlib import objectmodel, jit
from pypy.rlib.rarithmetic import r_uint, intmask, LONG_BIT
-from pypy.rlib.objectmodel import hlinvoke
-from pypy.rpython import robject
-from pypy.rlib import objectmodel, jit
from pypy.rpython import rmodel
from pypy.rpython.error import TyperError
+
HIGHEST_BIT = intmask(1 << (LONG_BIT - 1))
MASK = intmask(HIGHEST_BIT - 1)
@@ -417,17 +415,16 @@
ENTRIES = lltype.typeOf(entries).TO
return ENTRIES.fasthashfn(entries[i].key)
- at jit.dont_look_inside
def ll_get_value(d, i):
return d.entries[i].value
def ll_keyhash_custom(d, key):
DICT = lltype.typeOf(d).TO
- return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
+ return objectmodel.hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
def ll_keyeq_custom(d, key1, key2):
DICT = lltype.typeOf(d).TO
- return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2)
+ return objectmodel.hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2)
def ll_dict_len(d):
return d.num_items
@@ -448,7 +445,9 @@
i = ll_dict_lookup(d, key, hash)
return _ll_dict_setitem_lookup_done(d, key, value, hash, i)
- at jit.dont_look_inside
+# It may be safe to look inside always, it has a few branches though, and their
+# frequencies needs to be investigated.
+ at jit.look_inside_iff(lambda d, key, value, hash, i: jit.isvirtual(d) and jit.isconstant(key))
def _ll_dict_setitem_lookup_done(d, key, value, hash, i):
valid = (i & HIGHEST_BIT) == 0
i = i & MASK
@@ -492,6 +491,8 @@
raise KeyError
_ll_dict_del(d, i)
+# XXX: Move the size checking and resize into a single call which is opauqe to
+# the JIT to avoid extra branches.
@jit.dont_look_inside
def _ll_dict_del(d, i):
d.entries.mark_deleted(i)
@@ -532,6 +533,7 @@
# ------- a port of CPython's dictobject.c's lookdict implementation -------
PERTURB_SHIFT = 5
+ at jit.look_inside_iff(lambda d, key, hash: jit.isvirtual(d) and jit.isconstant(key))
def ll_dict_lookup(d, key, hash):
entries = d.entries
ENTRIES = lltype.typeOf(entries).TO
@@ -621,7 +623,6 @@
d.num_items = 0
d.resize_counter = DICT_INITSIZE * 2
return d
-ll_newdict.oopspec = 'newdict()'
def ll_newdict_size(DICT, length_estimate):
length_estimate = (length_estimate // 2) * 3
@@ -633,7 +634,6 @@
d.num_items = 0
d.resize_counter = n * 2
return d
-ll_newdict_size.oopspec = 'newdict()'
# pypy.rpython.memory.lldict uses a dict based on Struct and Array
# instead of GcStruct and GcArray, which is done by using different
@@ -866,7 +866,6 @@
global_popitem_index.nextindex = base + counter
return i
- at jit.dont_look_inside
def ll_popitem(ELEM, dic):
i = _ll_getnextitem(dic)
entry = dic.entries[i]
diff --git a/pypy/rpython/lltypesystem/rtagged.py b/pypy/rpython/lltypesystem/rtagged.py
--- a/pypy/rpython/lltypesystem/rtagged.py
+++ b/pypy/rpython/lltypesystem/rtagged.py
@@ -43,7 +43,7 @@
v_value = hop.inputarg(lltype.Signed, arg=1)
c_one = hop.inputconst(lltype.Signed, 1)
hop.exception_is_here()
- v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+ v2 = hop.genop('int_add_ovf', [v_value, v_value],
resulttype = lltype.Signed)
v2p1 = hop.genop('int_add', [v2, c_one],
resulttype = lltype.Signed)
diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -8,6 +8,7 @@
from pypy.rpython.lltypesystem.ll2ctypes import uninitialized2ctypes
from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED, force_cast
from pypy.rpython.lltypesystem.ll2ctypes import cast_adr_to_int, get_ctypes_type
+from pypy.rpython.lltypesystem.ll2ctypes import _llgcopaque
from pypy.rpython.annlowlevel import llhelper
from pypy.rlib import rposix
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -1123,6 +1124,9 @@
#assert lltype.cast_ptr_to_int(ref1) == intval
+ x = rffi.cast(llmemory.GCREF, -17)
+ assert lltype.cast_ptr_to_int(x) == -17
+
def test_ptr_truth(self):
abc = rffi.cast(lltype.Ptr(lltype.FuncType([], lltype.Void)), 0)
assert not abc
@@ -1346,6 +1350,11 @@
round = ctypes2lltype(llmemory.GCREF, lltype2ctypes(opaque.hide()))
assert Opaque.show(round) is opaque
+ def test_array_of_structs(self):
+ A = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed)))
+ a = lltype.malloc(A, 5)
+ a2 = ctypes2lltype(lltype.Ptr(A), lltype2ctypes(a))
+ assert a2._obj.getitem(0)._obj._parentstructure() is a2._obj
class TestPlatform(object):
def test_lib_on_libpaths(self):
@@ -1387,3 +1396,7 @@
f = rffi.llexternal('f', [rffi.INT, rffi.INT], rffi.INT,
compilation_info=eci)
assert f(3, 4) == 7
+
+ def test_llgcopaque_eq(self):
+ assert _llgcopaque(1) != None
+ assert _llgcopaque(0) == None
diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py
--- a/pypy/rpython/memory/gc/base.py
+++ b/pypy/rpython/memory/gc/base.py
@@ -1,4 +1,5 @@
-from pypy.rpython.lltypesystem import lltype, llmemory, llarena
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi
+from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.debug import ll_assert
from pypy.rpython.memory.gcheader import GCHeaderBuilder
from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
@@ -62,6 +63,7 @@
def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
is_gcarrayofgcptr,
getfinalizer,
+ getlightfinalizer,
offsets_to_gc_pointers,
fixed_size, varsize_item_sizes,
varsize_offset_to_variable_part,
@@ -74,6 +76,7 @@
get_custom_trace,
fast_path_tracing):
self.getfinalizer = getfinalizer
+ self.getlightfinalizer = getlightfinalizer
self.is_varsize = is_varsize
self.has_gcptr_in_varsize = has_gcptr_in_varsize
self.is_gcarrayofgcptr = is_gcarrayofgcptr
@@ -139,6 +142,7 @@
size = self.fixed_size(typeid)
needs_finalizer = bool(self.getfinalizer(typeid))
+ finalizer_is_light = bool(self.getlightfinalizer(typeid))
contains_weakptr = self.weakpointer_offset(typeid) >= 0
assert not (needs_finalizer and contains_weakptr)
if self.is_varsize(typeid):
@@ -158,6 +162,7 @@
else:
malloc_fixedsize = self.malloc_fixedsize
ref = malloc_fixedsize(typeid, size, needs_finalizer,
+ finalizer_is_light,
contains_weakptr)
# lots of cast and reverse-cast around...
return llmemory.cast_ptr_to_adr(ref)
diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py
--- a/pypy/rpython/memory/gc/generation.py
+++ b/pypy/rpython/memory/gc/generation.py
@@ -167,7 +167,9 @@
return self.nursery <= addr < self.nursery_top
def malloc_fixedsize_clear(self, typeid, size,
- has_finalizer=False, contains_weakptr=False):
+ has_finalizer=False,
+ is_finalizer_light=False,
+ contains_weakptr=False):
if (has_finalizer or
(raw_malloc_usage(size) > self.lb_young_fixedsize and
raw_malloc_usage(size) > self.largest_young_fixedsize)):
@@ -179,6 +181,7 @@
# "non-simple" case or object too big: don't use the nursery
return SemiSpaceGC.malloc_fixedsize_clear(self, typeid, size,
has_finalizer,
+ is_finalizer_light,
contains_weakptr)
size_gc_header = self.gcheaderbuilder.size_gc_header
totalsize = size_gc_header + size
diff --git a/pypy/rpython/memory/gc/marksweep.py b/pypy/rpython/memory/gc/marksweep.py
--- a/pypy/rpython/memory/gc/marksweep.py
+++ b/pypy/rpython/memory/gc/marksweep.py
@@ -93,7 +93,8 @@
pass
def malloc_fixedsize(self, typeid16, size,
- has_finalizer=False, contains_weakptr=False):
+ has_finalizer=False, is_finalizer_light=False,
+ contains_weakptr=False):
self.maybe_collect()
size_gc_header = self.gcheaderbuilder.size_gc_header
try:
@@ -128,7 +129,9 @@
malloc_fixedsize._dont_inline_ = True
def malloc_fixedsize_clear(self, typeid16, size,
- has_finalizer=False, contains_weakptr=False):
+ has_finalizer=False,
+ is_finalizer_light=False,
+ contains_weakptr=False):
self.maybe_collect()
size_gc_header = self.gcheaderbuilder.size_gc_header
try:
diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -290,6 +290,8 @@
#
# A list of all objects with finalizers (these are never young).
self.objects_with_finalizers = self.AddressDeque()
+ self.young_objects_with_light_finalizers = self.AddressStack()
+ self.old_objects_with_light_finalizers = self.AddressStack()
#
# Two lists of the objects with weakrefs. No weakref can be an
# old object weakly pointing to a young object: indeed, weakrefs
@@ -457,14 +459,16 @@
def malloc_fixedsize_clear(self, typeid, size,
- needs_finalizer=False, contains_weakptr=False):
+ needs_finalizer=False,
+ is_finalizer_light=False,
+ contains_weakptr=False):
size_gc_header = self.gcheaderbuilder.size_gc_header
totalsize = size_gc_header + size
rawtotalsize = raw_malloc_usage(totalsize)
#
# If the object needs a finalizer, ask for a rawmalloc.
# The following check should be constant-folded.
- if needs_finalizer:
+ if needs_finalizer and not is_finalizer_light:
ll_assert(not contains_weakptr,
"'needs_finalizer' and 'contains_weakptr' both specified")
obj = self.external_malloc(typeid, 0, can_make_young=False)
@@ -494,13 +498,14 @@
#
# Build the object.
llarena.arena_reserve(result, totalsize)
+ obj = result + size_gc_header
+ if is_finalizer_light:
+ self.young_objects_with_light_finalizers.append(obj)
self.init_gc_object(result, typeid, flags=0)
#
# If it is a weakref, record it (check constant-folded).
if contains_weakptr:
- self.young_objects_with_weakrefs.append(result+size_gc_header)
- #
- obj = result + size_gc_header
+ self.young_objects_with_weakrefs.append(obj)
#
return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
@@ -1264,6 +1269,8 @@
# weakrefs' targets.
if self.young_objects_with_weakrefs.non_empty():
self.invalidate_young_weakrefs()
+ if self.young_objects_with_light_finalizers.non_empty():
+ self.deal_with_young_objects_with_finalizers()
#
# Clear this mapping.
if self.nursery_objects_shadows.length() > 0:
@@ -1292,10 +1299,12 @@
# if a prebuilt GcStruct contains a pointer to a young object,
# then the write_barrier must have ensured that the prebuilt
# GcStruct is in the list self.old_objects_pointing_to_young.
+ debug_start("gc-minor-walkroots")
self.root_walker.walk_roots(
MiniMarkGC._trace_drag_out1, # stack roots
MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc
None) # static in prebuilt gc
+ debug_stop("gc-minor-walkroots")
def collect_cardrefs_to_nursery(self):
size_gc_header = self.gcheaderbuilder.size_gc_header
@@ -1582,6 +1591,9 @@
# Weakref support: clear the weak pointers to dying objects
if self.old_objects_with_weakrefs.non_empty():
self.invalidate_old_weakrefs()
+ if self.old_objects_with_light_finalizers.non_empty():
+ self.deal_with_old_objects_with_finalizers()
+
#
# Walk all rawmalloced objects and free the ones that don't
# have the GCFLAG_VISITED flag.
@@ -1647,8 +1659,7 @@
if self.header(obj).tid & GCFLAG_VISITED:
self.header(obj).tid &= ~GCFLAG_VISITED
return False # survives
- else:
- return True # dies
+ return True # dies
def _reset_gcflag_visited(self, obj, ignored):
self.header(obj).tid &= ~GCFLAG_VISITED
@@ -1827,6 +1838,39 @@
# ----------
# Finalizers
+ def deal_with_young_objects_with_finalizers(self):
+ """ This is a much simpler version of dealing with finalizers
+ and an optimization - we can reasonably assume that those finalizers
+ don't do anything fancy and *just* call them. Among other things
+ they won't resurrect objects
+ """
+ while self.young_objects_with_light_finalizers.non_empty():
+ obj = self.young_objects_with_light_finalizers.pop()
+ if not self.is_forwarded(obj):
+ finalizer = self.getlightfinalizer(self.get_type_id(obj))
+ ll_assert(bool(finalizer), "no light finalizer found")
+ finalizer(obj, llmemory.NULL)
+
+ def deal_with_old_objects_with_finalizers(self):
+ """ This is a much simpler version of dealing with finalizers
+ and an optimization - we can reasonably assume that those finalizers
+ don't do anything fancy and *just* call them. Among other things
+ they won't resurrect objects
+ """
+ new_objects = self.AddressStack()
+ while self.old_objects_with_light_finalizers.non_empty():
+ obj = self.old_objects_with_light_finalizers.pop()
+ if self.header(obj).tid & GCFLAG_VISITED:
+ # surviving
+ new_objects.append(obj)
+ else:
+ # dying
+ finalizer = self.getlightfinalizer(self.get_type_id(obj))
+ ll_assert(bool(finalizer), "no light finalizer found")
+ finalizer(obj, llmemory.NULL)
+ self.old_objects_with_light_finalizers.delete()
+ self.old_objects_with_light_finalizers = new_objects
+
def deal_with_objects_with_finalizers(self):
# Walk over list of objects with finalizers.
# If it is not surviving, add it to the list of to-be-called
@@ -1957,7 +2001,6 @@
#
self.old_objects_with_weakrefs.append(obj)
-
def invalidate_old_weakrefs(self):
"""Called during a major collection."""
# walk over list of objects that contain weakrefs
diff --git a/pypy/rpython/memory/gc/semispace.py b/pypy/rpython/memory/gc/semispace.py
--- a/pypy/rpython/memory/gc/semispace.py
+++ b/pypy/rpython/memory/gc/semispace.py
@@ -82,6 +82,7 @@
self.free = self.tospace
MovingGCBase.setup(self)
self.objects_with_finalizers = self.AddressDeque()
+ self.objects_with_light_finalizers = self.AddressStack()
self.objects_with_weakrefs = self.AddressStack()
def _teardown(self):
@@ -93,7 +94,9 @@
# because the spaces are filled with zeroes in advance.
def malloc_fixedsize_clear(self, typeid16, size,
- has_finalizer=False, contains_weakptr=False):
+ has_finalizer=False,
+ is_finalizer_light=False,
+ contains_weakptr=False):
size_gc_header = self.gcheaderbuilder.size_gc_header
totalsize = size_gc_header + size
result = self.free
@@ -102,7 +105,9 @@
llarena.arena_reserve(result, totalsize)
self.init_gc_object(result, typeid16)
self.free = result + totalsize
- if has_finalizer:
+ if is_finalizer_light:
+ self.objects_with_light_finalizers.append(result + size_gc_header)
+ elif has_finalizer:
self.objects_with_finalizers.append(result + size_gc_header)
if contains_weakptr:
self.objects_with_weakrefs.append(result + size_gc_header)
@@ -263,6 +268,8 @@
if self.run_finalizers.non_empty():
self.update_run_finalizers()
scan = self.scan_copied(scan)
+ if self.objects_with_light_finalizers.non_empty():
+ self.deal_with_objects_with_light_finalizers()
if self.objects_with_finalizers.non_empty():
scan = self.deal_with_objects_with_finalizers(scan)
if self.objects_with_weakrefs.non_empty():
@@ -471,6 +478,23 @@
# immortal objects always have GCFLAG_FORWARDED set;
# see get_forwarding_address().
+ def deal_with_objects_with_light_finalizers(self):
+ """ This is a much simpler version of dealing with finalizers
+ and an optimization - we can reasonably assume that those finalizers
+ don't do anything fancy and *just* call them. Among other things
+ they won't resurrect objects
+ """
+ new_objects = self.AddressStack()
+ while self.objects_with_light_finalizers.non_empty():
+ obj = self.objects_with_light_finalizers.pop()
+ if self.surviving(obj):
+ new_objects.append(self.get_forwarding_address(obj))
+ else:
+ finalizer = self.getfinalizer(self.get_type_id(obj))
+ finalizer(obj, llmemory.NULL)
+ self.objects_with_light_finalizers.delete()
+ self.objects_with_light_finalizers = new_objects
+
def deal_with_objects_with_finalizers(self, scan):
# walk over list of objects with finalizers
# if it is not copied, add it to the list of to-be-called finalizers
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -12,6 +12,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.translator.backendopt import graphanalyze
from pypy.translator.backendopt.support import var_needsgc
+from pypy.translator.backendopt.finalizer import FinalizerAnalyzer
from pypy.annotation import model as annmodel
from pypy.rpython import annlowlevel
from pypy.rpython.rbuiltin import gen_cast
@@ -258,6 +259,7 @@
[s_gc, s_typeid16,
annmodel.SomeInteger(nonneg=True),
annmodel.SomeBool(),
+ annmodel.SomeBool(),
annmodel.SomeBool()], s_gcref,
inline = False)
if hasattr(GCClass, 'malloc_fixedsize'):
@@ -267,6 +269,7 @@
[s_gc, s_typeid16,
annmodel.SomeInteger(nonneg=True),
annmodel.SomeBool(),
+ annmodel.SomeBool(),
annmodel.SomeBool()], s_gcref,
inline = False)
else:
@@ -319,7 +322,7 @@
raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality")
# in some GCs we can inline the common case of
- # malloc_fixedsize(typeid, size, True, False, False)
+ # malloc_fixedsize(typeid, size, False, False, False)
if getattr(GCClass, 'inline_simple_malloc', False):
# make a copy of this function so that it gets annotated
# independently and the constants are folded inside
@@ -337,7 +340,7 @@
malloc_fast,
[s_gc, s_typeid16,
annmodel.SomeInteger(nonneg=True),
- s_False, s_False], s_gcref,
+ s_False, s_False, s_False], s_gcref,
inline = True)
else:
self.malloc_fast_ptr = None
@@ -668,7 +671,13 @@
kind_and_fptr = self.special_funcptr_for_type(TYPE)
has_finalizer = (kind_and_fptr is not None and
kind_and_fptr[0] == "finalizer")
+ has_light_finalizer = (kind_and_fptr is not None and
+ kind_and_fptr[0] == "light_finalizer")
+ if has_light_finalizer:
+ has_finalizer = True
c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer)
+ c_has_light_finalizer = rmodel.inputconst(lltype.Bool,
+ has_light_finalizer)
if not op.opname.endswith('_varsize') and not flags.get('varsize'):
#malloc_ptr = self.malloc_fixedsize_ptr
@@ -682,7 +691,8 @@
else:
malloc_ptr = self.malloc_fixedsize_ptr
args = [self.c_const_gc, c_type_id, c_size,
- c_has_finalizer, rmodel.inputconst(lltype.Bool, False)]
+ c_has_finalizer, c_has_light_finalizer,
+ rmodel.inputconst(lltype.Bool, False)]
else:
assert not c_has_finalizer.value
info_varsize = self.layoutbuilder.get_info_varsize(type_id)
@@ -847,12 +857,13 @@
# used by the JIT (see pypy.jit.backend.llsupport.gc)
op = hop.spaceop
[v_typeid, v_size,
- v_has_finalizer, v_contains_weakptr] = op.args
+ v_has_finalizer, v_has_light_finalizer, v_contains_weakptr] = op.args
livevars = self.push_roots(hop)
hop.genop("direct_call",
[self.malloc_fixedsize_clear_ptr, self.c_const_gc,
v_typeid, v_size,
- v_has_finalizer, v_contains_weakptr],
+ v_has_finalizer, v_has_light_finalizer,
+ v_contains_weakptr],
resultvar=op.result)
self.pop_roots(hop, livevars)
@@ -912,10 +923,10 @@
info = self.layoutbuilder.get_info(type_id)
c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
malloc_ptr = self.malloc_fixedsize_ptr
- c_has_finalizer = rmodel.inputconst(lltype.Bool, False)
+ c_false = rmodel.inputconst(lltype.Bool, False)
c_has_weakptr = rmodel.inputconst(lltype.Bool, True)
args = [self.c_const_gc, c_type_id, c_size,
- c_has_finalizer, c_has_weakptr]
+ c_false, c_false, c_has_weakptr]
# push and pop the current live variables *including* the argument
# to the weakref_create operation, which must be kept alive and
@@ -1250,6 +1261,7 @@
lltype2vtable = translator.rtyper.lltype2vtable
More information about the pypy-commit
mailing list