[pypy-svn] pypy new-dict-proxy: merge default
cfbolz
commits-noreply at bitbucket.org
Mon Apr 18 14:11:12 CEST 2011
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: new-dict-proxy
Changeset: r43448:f0418b95a2b0
Date: 2011-04-18 14:09 +0200
http://bitbucket.org/pypy/pypy/changeset/f0418b95a2b0/
Log: merge default
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -854,6 +854,9 @@
def op_gc_adr_of_nursery_free(self):
raise NotImplementedError
+ def op_gc_adr_of_root_stack_top(self):
+ raise NotImplementedError
+
def op_gc_call_rtti_destructor(self, rtti, addr):
if hasattr(rtti._obj, 'destructor_funcptr'):
d = rtti._obj.destructor_funcptr
diff --git a/pypy/rlib/test/test_runicode.py b/pypy/rlib/test/test_runicode.py
--- a/pypy/rlib/test/test_runicode.py
+++ b/pypy/rlib/test/test_runicode.py
@@ -31,22 +31,28 @@
def checkdecode(self, s, encoding):
decoder = self.getdecoder(encoding)
- if isinstance(s, str):
- trueresult = s.decode(encoding)
- else:
- trueresult = s
- s = s.encode(encoding)
+ try:
+ if isinstance(s, str):
+ trueresult = s.decode(encoding)
+ else:
+ trueresult = s
+ s = s.encode(encoding)
+ except LookupError, e:
+ py.test.skip(e)
result, consumed = decoder(s, len(s), True)
assert consumed == len(s)
self.typeequals(trueresult, result)
def checkencode(self, s, encoding):
encoder = self.getencoder(encoding)
- if isinstance(s, unicode):
- trueresult = s.encode(encoding)
- else:
- trueresult = s
- s = s.decode(encoding)
+ try:
+ if isinstance(s, unicode):
+ trueresult = s.encode(encoding)
+ else:
+ trueresult = s
+ s = s.decode(encoding)
+ except LookupError, e:
+ py.test.skip(e)
result = encoder(s, len(s), True)
self.typeequals(trueresult, result)
@@ -66,9 +72,10 @@
assert called[0]
assert "42424242" in result
- def checkdecodeerror(self, s, encoding, start, stop, addstuff=True):
+ def checkdecodeerror(self, s, encoding, start, stop,
+ addstuff=True, msg=None):
called = [0]
- def errorhandler(errors, enc, msg, t, startingpos,
+ def errorhandler(errors, enc, errmsg, t, startingpos,
endingpos):
called[0] += 1
if called[0] == 1:
@@ -77,6 +84,8 @@
assert t is s
assert start == startingpos
assert stop == endingpos
+ if msg is not None:
+ assert errmsg == msg
return u"42424242", stop
return u"", endingpos
decoder = self.getdecoder(encoding)
@@ -90,7 +99,7 @@
class TestDecoding(UnicodeTests):
-
+
# XXX test bom recognition in utf-16
# XXX test proper error handling
@@ -131,6 +140,96 @@
"utf-32 utf-32-be utf-32-le").split():
self.checkdecode(uni, encoding)
+ def test_ascii_error(self):
+ self.checkdecodeerror("abc\xFF\xFF\xFFcde", "ascii", 3, 4)
+
+ def test_utf16_errors(self):
+ # trunkated BOM
+ for s in ["\xff", "\xfe"]:
+ self.checkdecodeerror(s, "utf-16", 0, len(s), addstuff=False)
+
+ for s in [
+ # unexpected end of data ascii
+ "\xff\xfeF",
+ # unexpected end of data
+ '\xff\xfe\xc0\xdb\x00', '\xff\xfe\xc0\xdb', '\xff\xfe\xc0',
+ ]:
+ self.checkdecodeerror(s, "utf-16", 2, len(s), addstuff=False)
+ for s in [
+ # illegal surrogate
+ "\xff\xfe\xff\xdb\xff\xff",
+ ]:
+ self.checkdecodeerror(s, "utf-16", 2, 4, addstuff=False)
+
+ def test_utf16_bugs(self):
+ s = '\x80-\xe9\xdeL\xa3\x9b'
+ py.test.raises(UnicodeDecodeError, runicode.str_decode_utf_16_le,
+ s, len(s), True)
+
+ def test_utf7_bugs(self):
+ u = u'A\u2262\u0391.'
+ assert runicode.unicode_encode_utf_7(u, len(u), None) == 'A+ImIDkQ.'
+
+ def test_utf7_tofrom_utf8_bug(self):
+ def _assert_decu7(input, expected):
+ assert runicode.str_decode_utf_7(input, len(input), None) == (expected, len(input))
+
+ _assert_decu7('+-', u'+')
+ _assert_decu7('+-+-', u'++')
+ _assert_decu7('+-+AOQ-', u'+\xe4')
+ _assert_decu7('+AOQ-', u'\xe4')
+ _assert_decu7('+AOQ-', u'\xe4')
+ _assert_decu7('+AOQ- ', u'\xe4 ')
+ _assert_decu7(' +AOQ-', u' \xe4')
+ _assert_decu7(' +AOQ- ', u' \xe4 ')
+ _assert_decu7('+AOQ-+AOQ-', u'\xe4\xe4')
+
+ s_utf7 = 'Die M+AOQ-nner +AOQ-rgen sich!'
+ s_utf8 = u'Die Männer ärgen sich!'
+ s_utf8_esc = u'Die M\xe4nner \xe4rgen sich!'
+
+ _assert_decu7(s_utf7, s_utf8_esc)
+ _assert_decu7(s_utf7, s_utf8)
+
+ assert runicode.unicode_encode_utf_7(s_utf8_esc, len(s_utf8_esc), None) == s_utf7
+ assert runicode.unicode_encode_utf_7(s_utf8, len(s_utf8_esc), None) == s_utf7
+
+ def test_utf7_partial(self):
+ s = u"a+-b".encode('utf-7')
+ assert s == "a+--b"
+ decode = self.getdecoder('utf-7')
+ assert decode(s, 1, None) == (u'a', 1)
+ assert decode(s, 2, None) == (u'a', 1)
+ assert decode(s, 3, None) == (u'a+', 3)
+ assert decode(s, 4, None) == (u'a+-', 4)
+ assert decode(s, 5, None) == (u'a+-b', 5)
+
+ def test_utf7_surrogates(self):
+ encode = self.getencoder('utf-7')
+ u = u'\U000abcde'
+ assert encode(u, len(u), None) == '+2m/c3g-'
+ decode = self.getdecoder('utf-7')
+ s = '+3ADYAA-'
+ raises(UnicodeError, decode, s, len(s), None)
+ def replace_handler(errors, codec, message, input, start, end):
+ return u'?', end
+ assert decode(s, len(s), None, final=True,
+ errorhandler = replace_handler) == (u'??', len(s))
+
+
+class TestUTF8Decoding(UnicodeTests):
+ def __init__(self):
+ self.decoder = self.getdecoder('utf-8')
+
+ def replace_handler(self, errors, codec, message, input, start, end):
+ return u'\ufffd', end
+
+ def ignore_handler(self, errors, codec, message, input, start, end):
+ return u'', end
+
+ def to_bytestring(self, bytes):
+ return ''.join(chr(int(c, 16)) for c in bytes.split())
+
def test_single_chars_utf8(self):
for s in ["\xd7\x90", "\xd6\x96", "\xeb\x96\x95", "\xf0\x90\x91\x93"]:
self.checkdecode(s, "utf-8")
@@ -140,30 +239,297 @@
# This test will raise an error with python 3.x
self.checkdecode(u"\ud800", "utf-8")
+ def test_invalid_start_byte(self):
+ """
+ Test that an 'invalid start byte' error is raised when the first byte
+ is not in the ASCII range or is not a valid start byte of a 2-, 3-, or
+ 4-bytes sequence. The invalid start byte is replaced with a single
+ U+FFFD when errors='replace'.
+ E.g. <80> is a continuation byte and can appear only after a start byte.
+ """
+ FFFD = u'\ufffd'
+ for byte in '\x80\xA0\x9F\xBF\xC0\xC1\xF5\xFF':
+ raises(UnicodeDecodeError, self.decoder, byte, 1, None, final=True)
+ self.checkdecodeerror(byte, 'utf-8', 0, 1, addstuff=False,
+ msg='invalid start byte')
+ assert self.decoder(byte, 1, None, final=True,
+ errorhandler=self.replace_handler) == (FFFD, 1)
+ assert (self.decoder('aaaa' + byte + 'bbbb', 9, None,
+ final=True, errorhandler=self.replace_handler) ==
+ (u'aaaa'+ FFFD + u'bbbb', 9))
+ assert self.decoder(byte, 1, None, final=True,
+ errorhandler=self.ignore_handler) == (u'', 1)
+ assert (self.decoder('aaaa' + byte + 'bbbb', 9, None,
+ final=True, errorhandler=self.ignore_handler) ==
+ (u'aaaabbbb', 9))
+
+ def test_unexpected_end_of_data(self):
+ """
+ Test that an 'unexpected end of data' error is raised when the string
+ ends after a start byte of a 2-, 3-, or 4-bytes sequence without having
+ enough continuation bytes. The incomplete sequence is replaced with a
+ single U+FFFD when errors='replace'.
+ E.g. in the sequence <F3 80 80>, F3 is the start byte of a 4-bytes
+ sequence, but it's followed by only 2 valid continuation bytes and the
+ last continuation bytes is missing.
+ Note: the continuation bytes must be all valid, if one of them is
+ invalid another error will be raised.
+ """
+ sequences = [
+ 'C2', 'DF',
+ 'E0 A0', 'E0 BF', 'E1 80', 'E1 BF', 'EC 80', 'EC BF',
+ 'ED 80', 'ED 9F', 'EE 80', 'EE BF', 'EF 80', 'EF BF',
+ 'F0 90', 'F0 BF', 'F0 90 80', 'F0 90 BF', 'F0 BF 80', 'F0 BF BF',
+ 'F1 80', 'F1 BF', 'F1 80 80', 'F1 80 BF', 'F1 BF 80', 'F1 BF BF',
+ 'F3 80', 'F3 BF', 'F3 80 80', 'F3 80 BF', 'F3 BF 80', 'F3 BF BF',
+ 'F4 80', 'F4 8F', 'F4 80 80', 'F4 80 BF', 'F4 8F 80', 'F4 8F BF'
+ ]
+ FFFD = u'\ufffd'
+ for seq in sequences:
+ seq = self.to_bytestring(seq)
+ raises(UnicodeDecodeError, self.decoder, seq, len(seq),
+ None, final=True)
+ self.checkdecodeerror(seq, 'utf-8', 0, len(seq), addstuff=False,
+ msg='unexpected end of data')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.replace_handler) == (FFFD, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.replace_handler) ==
+ (u'aaaa'+ FFFD + u'bbbb', len(seq) + 8))
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.ignore_handler) == (u'', len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.ignore_handler) ==
+ (u'aaaabbbb', len(seq) + 8))
+
+ def test_invalid_cb_for_2bytes_seq(self):
+ """
+ Test that an 'invalid continuation byte' error is raised when the
+ continuation byte of a 2-bytes sequence is invalid. The start byte
+ is replaced by a single U+FFFD and the second byte is handled
+ separately when errors='replace'.
+ E.g. in the sequence <C2 41>, C2 is the start byte of a 2-bytes
+ sequence, but 41 is not a valid continuation byte because it's the
+ ASCII letter 'A'.
+ """
+ FFFD = u'\ufffd'
+ FFFDx2 = FFFD * 2
+ sequences = [
+ ('C2 00', FFFD+u'\x00'), ('C2 7F', FFFD+u'\x7f'),
+ ('C2 C0', FFFDx2), ('C2 FF', FFFDx2),
+ ('DF 00', FFFD+u'\x00'), ('DF 7F', FFFD+u'\x7f'),
+ ('DF C0', FFFDx2), ('DF FF', FFFDx2),
+ ]
+ for seq, res in sequences:
+ seq = self.to_bytestring(seq)
+ raises(UnicodeDecodeError, self.decoder, seq, len(seq),
+ None, final=True)
+ self.checkdecodeerror(seq, 'utf-8', 0, 1, addstuff=False,
+ msg='invalid continuation byte')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.replace_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.replace_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+ res = res.replace(FFFD, u'')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.ignore_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.ignore_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+
+ def test_invalid_cb_for_3bytes_seq(self):
+ """
+ Test that an 'invalid continuation byte' error is raised when the
+ continuation byte(s) of a 3-bytes sequence are invalid. When
+ errors='replace', if the first continuation byte is valid, the first
+ two bytes (start byte + 1st cb) are replaced by a single U+FFFD and the
+ third byte is handled separately, otherwise only the start byte is
+ replaced with a U+FFFD and the other continuation bytes are handled
+ separately.
+ E.g. in the sequence <E1 80 41>, E1 is the start byte of a 3-bytes
+ sequence, 80 is a valid continuation byte, but 41 is not a valid cb
+ because it's the ASCII letter 'A'.
+ Note: when the start byte is E0 or ED, the valid ranges for the first
+ continuation byte are limited to A0..BF and 80..9F respectively.
+ However, when the start byte is ED, Python 2 considers all the bytes
+ in range 80..BF valid. This is fixed in Python 3.
+ """
+ FFFD = u'\ufffd'
+ FFFDx2 = FFFD * 2
+ sequences = [
+ ('E0 00', FFFD+u'\x00'), ('E0 7F', FFFD+u'\x7f'), ('E0 80', FFFDx2),
+ ('E0 9F', FFFDx2), ('E0 C0', FFFDx2), ('E0 FF', FFFDx2),
+ ('E0 A0 00', FFFD+u'\x00'), ('E0 A0 7F', FFFD+u'\x7f'),
+ ('E0 A0 C0', FFFDx2), ('E0 A0 FF', FFFDx2),
+ ('E0 BF 00', FFFD+u'\x00'), ('E0 BF 7F', FFFD+u'\x7f'),
+ ('E0 BF C0', FFFDx2), ('E0 BF FF', FFFDx2), ('E1 00', FFFD+u'\x00'),
+ ('E1 7F', FFFD+u'\x7f'), ('E1 C0', FFFDx2), ('E1 FF', FFFDx2),
+ ('E1 80 00', FFFD+u'\x00'), ('E1 80 7F', FFFD+u'\x7f'),
+ ('E1 80 C0', FFFDx2), ('E1 80 FF', FFFDx2),
+ ('E1 BF 00', FFFD+u'\x00'), ('E1 BF 7F', FFFD+u'\x7f'),
+ ('E1 BF C0', FFFDx2), ('E1 BF FF', FFFDx2), ('EC 00', FFFD+u'\x00'),
+ ('EC 7F', FFFD+u'\x7f'), ('EC C0', FFFDx2), ('EC FF', FFFDx2),
+ ('EC 80 00', FFFD+u'\x00'), ('EC 80 7F', FFFD+u'\x7f'),
+ ('EC 80 C0', FFFDx2), ('EC 80 FF', FFFDx2),
+ ('EC BF 00', FFFD+u'\x00'), ('EC BF 7F', FFFD+u'\x7f'),
+ ('EC BF C0', FFFDx2), ('EC BF FF', FFFDx2), ('ED 00', FFFD+u'\x00'),
+ ('ED 7F', FFFD+u'\x7f'),
+ # ('ED A0', FFFDx2), ('ED BF', FFFDx2), # see note ^
+ ('ED C0', FFFDx2), ('ED FF', FFFDx2), ('ED 80 00', FFFD+u'\x00'),
+ ('ED 80 7F', FFFD+u'\x7f'), ('ED 80 C0', FFFDx2),
+ ('ED 80 FF', FFFDx2), ('ED 9F 00', FFFD+u'\x00'),
+ ('ED 9F 7F', FFFD+u'\x7f'), ('ED 9F C0', FFFDx2),
+ ('ED 9F FF', FFFDx2), ('EE 00', FFFD+u'\x00'),
+ ('EE 7F', FFFD+u'\x7f'), ('EE C0', FFFDx2), ('EE FF', FFFDx2),
+ ('EE 80 00', FFFD+u'\x00'), ('EE 80 7F', FFFD+u'\x7f'),
+ ('EE 80 C0', FFFDx2), ('EE 80 FF', FFFDx2),
+ ('EE BF 00', FFFD+u'\x00'), ('EE BF 7F', FFFD+u'\x7f'),
+ ('EE BF C0', FFFDx2), ('EE BF FF', FFFDx2), ('EF 00', FFFD+u'\x00'),
+ ('EF 7F', FFFD+u'\x7f'), ('EF C0', FFFDx2), ('EF FF', FFFDx2),
+ ('EF 80 00', FFFD+u'\x00'), ('EF 80 7F', FFFD+u'\x7f'),
+ ('EF 80 C0', FFFDx2), ('EF 80 FF', FFFDx2),
+ ('EF BF 00', FFFD+u'\x00'), ('EF BF 7F', FFFD+u'\x7f'),
+ ('EF BF C0', FFFDx2), ('EF BF FF', FFFDx2),
+ ]
+ for seq, res in sequences:
+ seq = self.to_bytestring(seq)
+ raises(UnicodeDecodeError, self.decoder, seq, len(seq),
+ None, final=True)
+ self.checkdecodeerror(seq, 'utf-8', 0, len(seq)-1, addstuff=False,
+ msg='invalid continuation byte')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.replace_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.replace_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+ res = res.replace(FFFD, u'')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.ignore_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.ignore_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+
+ def test_invalid_cb_for_4bytes_seq(self):
+ """
+ Test that an 'invalid continuation byte' error is raised when the
+ continuation byte(s) of a 4-bytes sequence are invalid. When
+ errors='replace',the start byte and all the following valid
+ continuation bytes are replaced with a single U+FFFD, and all the bytes
+ starting from the first invalid continuation bytes (included) are
+ handled separately.
+ E.g. in the sequence <E1 80 41>, E1 is the start byte of a 3-bytes
+ sequence, 80 is a valid continuation byte, but 41 is not a valid cb
+ because it's the ASCII letter 'A'.
+ Note: when the start byte is E0 or ED, the valid ranges for the first
+ continuation byte are limited to A0..BF and 80..9F respectively.
+ However, when the start byte is ED, Python 2 considers all the bytes
+ in range 80..BF valid. This is fixed in Python 3.
+ """
+ FFFD = u'\ufffd'
+ FFFDx2 = FFFD * 2
+ sequences = [
+ ('F0 00', FFFD+u'\x00'), ('F0 7F', FFFD+u'\x7f'), ('F0 80', FFFDx2),
+ ('F0 8F', FFFDx2), ('F0 C0', FFFDx2), ('F0 FF', FFFDx2),
+ ('F0 90 00', FFFD+u'\x00'), ('F0 90 7F', FFFD+u'\x7f'),
+ ('F0 90 C0', FFFDx2), ('F0 90 FF', FFFDx2),
+ ('F0 BF 00', FFFD+u'\x00'), ('F0 BF 7F', FFFD+u'\x7f'),
+ ('F0 BF C0', FFFDx2), ('F0 BF FF', FFFDx2),
+ ('F0 90 80 00', FFFD+u'\x00'), ('F0 90 80 7F', FFFD+u'\x7f'),
+ ('F0 90 80 C0', FFFDx2), ('F0 90 80 FF', FFFDx2),
+ ('F0 90 BF 00', FFFD+u'\x00'), ('F0 90 BF 7F', FFFD+u'\x7f'),
+ ('F0 90 BF C0', FFFDx2), ('F0 90 BF FF', FFFDx2),
+ ('F0 BF 80 00', FFFD+u'\x00'), ('F0 BF 80 7F', FFFD+u'\x7f'),
+ ('F0 BF 80 C0', FFFDx2), ('F0 BF 80 FF', FFFDx2),
+ ('F0 BF BF 00', FFFD+u'\x00'), ('F0 BF BF 7F', FFFD+u'\x7f'),
+ ('F0 BF BF C0', FFFDx2), ('F0 BF BF FF', FFFDx2),
+ ('F1 00', FFFD+u'\x00'), ('F1 7F', FFFD+u'\x7f'), ('F1 C0', FFFDx2),
+ ('F1 FF', FFFDx2), ('F1 80 00', FFFD+u'\x00'),
+ ('F1 80 7F', FFFD+u'\x7f'), ('F1 80 C0', FFFDx2),
+ ('F1 80 FF', FFFDx2), ('F1 BF 00', FFFD+u'\x00'),
+ ('F1 BF 7F', FFFD+u'\x7f'), ('F1 BF C0', FFFDx2),
+ ('F1 BF FF', FFFDx2), ('F1 80 80 00', FFFD+u'\x00'),
+ ('F1 80 80 7F', FFFD+u'\x7f'), ('F1 80 80 C0', FFFDx2),
+ ('F1 80 80 FF', FFFDx2), ('F1 80 BF 00', FFFD+u'\x00'),
+ ('F1 80 BF 7F', FFFD+u'\x7f'), ('F1 80 BF C0', FFFDx2),
+ ('F1 80 BF FF', FFFDx2), ('F1 BF 80 00', FFFD+u'\x00'),
+ ('F1 BF 80 7F', FFFD+u'\x7f'), ('F1 BF 80 C0', FFFDx2),
+ ('F1 BF 80 FF', FFFDx2), ('F1 BF BF 00', FFFD+u'\x00'),
+ ('F1 BF BF 7F', FFFD+u'\x7f'), ('F1 BF BF C0', FFFDx2),
+ ('F1 BF BF FF', FFFDx2), ('F3 00', FFFD+u'\x00'),
+ ('F3 7F', FFFD+u'\x7f'), ('F3 C0', FFFDx2), ('F3 FF', FFFDx2),
+ ('F3 80 00', FFFD+u'\x00'), ('F3 80 7F', FFFD+u'\x7f'),
+ ('F3 80 C0', FFFDx2), ('F3 80 FF', FFFDx2),
+ ('F3 BF 00', FFFD+u'\x00'), ('F3 BF 7F', FFFD+u'\x7f'),
+ ('F3 BF C0', FFFDx2), ('F3 BF FF', FFFDx2),
+ ('F3 80 80 00', FFFD+u'\x00'), ('F3 80 80 7F', FFFD+u'\x7f'),
+ ('F3 80 80 C0', FFFDx2), ('F3 80 80 FF', FFFDx2),
+ ('F3 80 BF 00', FFFD+u'\x00'), ('F3 80 BF 7F', FFFD+u'\x7f'),
+ ('F3 80 BF C0', FFFDx2), ('F3 80 BF FF', FFFDx2),
+ ('F3 BF 80 00', FFFD+u'\x00'), ('F3 BF 80 7F', FFFD+u'\x7f'),
+ ('F3 BF 80 C0', FFFDx2), ('F3 BF 80 FF', FFFDx2),
+ ('F3 BF BF 00', FFFD+u'\x00'), ('F3 BF BF 7F', FFFD+u'\x7f'),
+ ('F3 BF BF C0', FFFDx2), ('F3 BF BF FF', FFFDx2),
+ ('F4 00', FFFD+u'\x00'), ('F4 7F', FFFD+u'\x7f'), ('F4 90', FFFDx2),
+ ('F4 BF', FFFDx2), ('F4 C0', FFFDx2), ('F4 FF', FFFDx2),
+ ('F4 80 00', FFFD+u'\x00'), ('F4 80 7F', FFFD+u'\x7f'),
+ ('F4 80 C0', FFFDx2), ('F4 80 FF', FFFDx2),
+ ('F4 8F 00', FFFD+u'\x00'), ('F4 8F 7F', FFFD+u'\x7f'),
+ ('F4 8F C0', FFFDx2), ('F4 8F FF', FFFDx2),
+ ('F4 80 80 00', FFFD+u'\x00'), ('F4 80 80 7F', FFFD+u'\x7f'),
+ ('F4 80 80 C0', FFFDx2), ('F4 80 80 FF', FFFDx2),
+ ('F4 80 BF 00', FFFD+u'\x00'), ('F4 80 BF 7F', FFFD+u'\x7f'),
+ ('F4 80 BF C0', FFFDx2), ('F4 80 BF FF', FFFDx2),
+ ('F4 8F 80 00', FFFD+u'\x00'), ('F4 8F 80 7F', FFFD+u'\x7f'),
+ ('F4 8F 80 C0', FFFDx2), ('F4 8F 80 FF', FFFDx2),
+ ('F4 8F BF 00', FFFD+u'\x00'), ('F4 8F BF 7F', FFFD+u'\x7f'),
+ ('F4 8F BF C0', FFFDx2), ('F4 8F BF FF', FFFDx2)
+ ]
+ for seq, res in sequences:
+ seq = self.to_bytestring(seq)
+ raises(UnicodeDecodeError, self.decoder, seq, len(seq),
+ None, final=True)
+ self.checkdecodeerror(seq, 'utf-8', 0, len(seq)-1, addstuff=False,
+ msg='invalid continuation byte')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.replace_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.replace_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+ res = res.replace(FFFD, u'')
+ assert self.decoder(seq, len(seq), None, final=True,
+ errorhandler=self.ignore_handler) == (res, len(seq))
+ assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, None,
+ final=True, errorhandler=self.ignore_handler) ==
+ (u'aaaa' + res + u'bbbb', len(seq) + 8))
+
def test_utf8_errors(self):
- for s in [# unexpected end of data
- "\xd7", "\xd6", "\xeb\x96", "\xf0\x90\x91"]:
- self.checkdecodeerror(s, "utf-8", 0, len(s), addstuff=False)
-
- # unexpected code byte
- for s in ["\x81", "\xbf"]:
- self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True)
+ # unexpected end of data
+ for s in ['\xd7', '\xd6', '\xeb\x96', '\xf0\x90\x91', '\xc2', '\xdf']:
+ self.checkdecodeerror(s, 'utf-8', 0, len(s), addstuff=False,
+ msg='unexpected end of data')
# invalid data 2 byte
for s in ["\xd7\x50", "\xd6\x06", "\xd6\xD6"]:
- self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True,
+ msg='invalid continuation byte')
# invalid data 3 byte
for s in ["\xeb\x56\x95", "\xeb\x06\x95", "\xeb\xD6\x95"]:
- self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True,
+ msg='invalid continuation byte')
for s in ["\xeb\x96\x55", "\xeb\x96\x05", "\xeb\x96\xD5"]:
- self.checkdecodeerror(s, "utf-8", 0, 2, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 2, addstuff=True,
+ msg='invalid continuation byte')
# invalid data 4 byte
for s in ["\xf0\x50\x91\x93", "\xf0\x00\x91\x93", "\xf0\xd0\x91\x93"]:
- self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 1, addstuff=True,
+ msg='invalid continuation byte')
for s in ["\xf0\x90\x51\x93", "\xf0\x90\x01\x93", "\xf0\x90\xd1\x93"]:
- self.checkdecodeerror(s, "utf-8", 0, 2, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 2, addstuff=True,
+ msg='invalid continuation byte')
for s in ["\xf0\x90\x91\x53", "\xf0\x90\x91\x03", "\xf0\x90\x91\xd3"]:
- self.checkdecodeerror(s, "utf-8", 0, 3, addstuff=True)
+ self.checkdecodeerror(s, "utf-8", 0, 3, addstuff=True,
+ msg='invalid continuation byte')
def test_issue8271(self):
@@ -249,97 +615,18 @@
('\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64',
u'\x61\uFFFD\uFFFD\uFFFD\x62\uFFFD\x63\uFFFD\uFFFD\x64'),
]
- def replace_handler(errors, codec, message, input, start, end):
- return FFFD, end
- def ignore_handler(errors, codec, message, input, start, end):
- return u'', end
+
for n, (seq, res) in enumerate(sequences):
decoder = self.getdecoder('utf-8')
raises(UnicodeDecodeError, decoder, seq, len(seq), None, final=True)
assert decoder(seq, len(seq), None, final=True,
- errorhandler=replace_handler) == (res, len(seq))
+ errorhandler=self.replace_handler) == (res, len(seq))
assert decoder(seq + 'b', len(seq) + 1, None, final=True,
- errorhandler=replace_handler) == (res + u'b',
- len(seq) + 1)
+ errorhandler=self.replace_handler) == (res + u'b',
+ len(seq) + 1)
res = res.replace(FFFD, u'')
assert decoder(seq, len(seq), None, final=True,
- errorhandler=ignore_handler) == (res, len(seq))
-
- def test_ascii_error(self):
- self.checkdecodeerror("abc\xFF\xFF\xFFcde", "ascii", 3, 4)
-
- def test_utf16_errors(self):
- # trunkated BOM
- for s in ["\xff", "\xfe"]:
- self.checkdecodeerror(s, "utf-16", 0, len(s), addstuff=False)
-
- for s in [
- # unexpected end of data ascii
- "\xff\xfeF",
- # unexpected end of data
- '\xff\xfe\xc0\xdb\x00', '\xff\xfe\xc0\xdb', '\xff\xfe\xc0',
- ]:
- self.checkdecodeerror(s, "utf-16", 2, len(s), addstuff=False)
- for s in [
- # illegal surrogate
- "\xff\xfe\xff\xdb\xff\xff",
- ]:
- self.checkdecodeerror(s, "utf-16", 2, 4, addstuff=False)
-
- def test_utf16_bugs(self):
- s = '\x80-\xe9\xdeL\xa3\x9b'
- py.test.raises(UnicodeDecodeError, runicode.str_decode_utf_16_le,
- s, len(s), True)
-
- def test_utf7_bugs(self):
- u = u'A\u2262\u0391.'
- assert runicode.unicode_encode_utf_7(u, len(u), None) == 'A+ImIDkQ.'
-
- def test_utf7_tofrom_utf8_bug(self):
- def _assert_decu7(input, expected):
- assert runicode.str_decode_utf_7(input, len(input), None) == (expected, len(input))
-
- _assert_decu7('+-', u'+')
- _assert_decu7('+-+-', u'++')
- _assert_decu7('+-+AOQ-', u'+\xe4')
- _assert_decu7('+AOQ-', u'\xe4')
- _assert_decu7('+AOQ-', u'\xe4')
- _assert_decu7('+AOQ- ', u'\xe4 ')
- _assert_decu7(' +AOQ-', u' \xe4')
- _assert_decu7(' +AOQ- ', u' \xe4 ')
- _assert_decu7('+AOQ-+AOQ-', u'\xe4\xe4')
-
- s_utf7 = 'Die M+AOQ-nner +AOQ-rgen sich!'
- s_utf8 = u'Die Männer ärgen sich!'
- s_utf8_esc = u'Die M\xe4nner \xe4rgen sich!'
-
- _assert_decu7(s_utf7, s_utf8_esc)
- _assert_decu7(s_utf7, s_utf8)
-
- assert runicode.unicode_encode_utf_7(s_utf8_esc, len(s_utf8_esc), None) == s_utf7
- assert runicode.unicode_encode_utf_7(s_utf8, len(s_utf8_esc), None) == s_utf7
-
- def test_utf7_partial(self):
- s = u"a+-b".encode('utf-7')
- assert s == "a+--b"
- decode = self.getdecoder('utf-7')
- assert decode(s, 1, None) == (u'a', 1)
- assert decode(s, 2, None) == (u'a', 1)
- assert decode(s, 3, None) == (u'a+', 3)
- assert decode(s, 4, None) == (u'a+-', 4)
- assert decode(s, 5, None) == (u'a+-b', 5)
-
- def test_utf7_surrogates(self):
- encode = self.getencoder('utf-7')
- u = u'\U000abcde'
- assert encode(u, len(u), None) == '+2m/c3g-'
- decode = self.getdecoder('utf-7')
- s = '+3ADYAA-'
- raises(UnicodeError, decode, s, len(s), None)
- def replace_handler(errors, codec, message, input, start, end):
- return u'?', end
- assert decode(s, len(s), None, final=True,
- errorhandler = replace_handler) == (u'??', len(s))
+ errorhandler=self.ignore_handler) == (res, len(seq))
class TestEncoding(UnicodeTests):
@@ -376,7 +663,7 @@
self.checkencode(uni, "utf-7")
for encoding in ("utf-8 utf-16 utf-16-be utf-16-le "
"utf-32 utf-32-be utf-32-le").split():
- self.checkencode(uni, encoding)
+ self.checkencode(uni, encoding)
def test_maxunicode(self):
uni = unichr(sys.maxunicode)
@@ -384,7 +671,7 @@
self.checkencode(uni, "utf-7")
for encoding in ("utf-8 utf-16 utf-16-be utf-16-le "
"utf-32 utf-32-be utf-32-le").split():
- self.checkencode(uni, encoding)
+ self.checkencode(uni, encoding)
def test_single_chars_utf8(self):
# check every number of bytes per char
@@ -394,7 +681,7 @@
def test_utf8_surrogates(self):
# check replacing of two surrogates by single char while encoding
# make sure that the string itself is not marshalled
- u = u"\ud800"
+ u = u"\ud800"
for i in range(4):
u += u"\udc00"
self.checkencode(u, "utf-8")
@@ -422,7 +709,7 @@
def test_utf8(self):
from pypy.rpython.test.test_llinterp import interpret
def f(x):
-
+
s1 = "".join(["\xd7\x90\xd6\x96\xeb\x96\x95\xf0\x90\x91\x93"] * x)
u, consumed = runicode.str_decode_utf_8(s1, len(s1), True)
s2 = runicode.unicode_encode_utf_8(u, len(u), True)
@@ -438,6 +725,6 @@
u = runicode.UNICHR(x)
t = runicode.ORD(u)
return t
-
+
res = interpret(f, [0x10140])
assert res == 0x10140
diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py
--- a/pypy/interpreter/test/test_eval.py
+++ b/pypy/interpreter/test/test_eval.py
@@ -13,7 +13,8 @@
def __init__(self, space, code, numlocals):
self.code = code
- Frame.__init__(self, space, numlocals=numlocals)
+ Frame.__init__(self, space)
+ self.numlocals = numlocals
self.fastlocals_w = [None] * self.numlocals
def getcode(self):
@@ -24,7 +25,10 @@
def getfastscope(self):
return self.fastlocals_w
-
+
+ def getfastscopelength(self):
+ return self.numlocals
+
self.f = ConcreteFastscopeFrame(self.space, code, numlocals=5)
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
@@ -179,6 +179,9 @@
"""
raise NotImplementedError
+ def count_fields_if_immutable(self):
+ return -1
+
def _clone_if_mutable(self):
return self
def clone_if_mutable(self):
diff --git a/pypy/translator/backendopt/constfold.py b/pypy/translator/backendopt/constfold.py
--- a/pypy/translator/backendopt/constfold.py
+++ b/pypy/translator/backendopt/constfold.py
@@ -1,19 +1,16 @@
from pypy.objspace.flow.model import Constant, Variable, SpaceOperation
from pypy.objspace.flow.model import c_last_exception
from pypy.objspace.flow.model import mkentrymap
-from pypy.translator.backendopt.support import split_block_with_keepalive
from pypy.translator.backendopt.support import log
from pypy.translator.simplify import eliminate_empty_blocks
-from pypy.translator.unsimplify import insert_empty_block
+from pypy.translator.unsimplify import insert_empty_block, split_block
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.lltypesystem import lltype
def fold_op_list(operations, constants, exit_early=False, exc_catch=False):
newops = []
- keepalives = []
folded_count = 0
- first_sideeffect_index = None
for spaceop in operations:
vargsmodif = False
vargs = []
@@ -29,10 +26,9 @@
try:
op = getattr(llop, spaceop.opname)
except AttributeError:
- sideeffects = True
+ pass
else:
- sideeffects = op.sideeffects
- if not sideeffects and len(args) == len(vargs):
+ if not op.sideeffects and len(args) == len(vargs):
RESTYPE = spaceop.result.concretetype
try:
result = op(RESTYPE, *args)
@@ -53,10 +49,6 @@
# failed to fold an operation, exit early if requested
if exit_early:
return folded_count
- if spaceop.opname == 'keepalive' and first_sideeffect_index is None:
- if vargsmodif:
- continue # keepalive(constant) is not useful
- keepalives.append(spaceop)
else:
if vargsmodif:
if (spaceop.opname == 'indirect_call'
@@ -66,20 +58,11 @@
else:
spaceop = SpaceOperation(spaceop.opname, vargs,
spaceop.result)
- if sideeffects and first_sideeffect_index is None:
- first_sideeffect_index = len(newops)
newops.append(spaceop)
# end
if exit_early:
return folded_count
else:
- # move the keepalives to the end of the block, which makes the life
- # of prepare_constant_fold_link() easier. Don't put them past the
- # exception-raising operation, though. There is also no point in
- # moving them past the first sideeffect-ing operation.
- if first_sideeffect_index is None:
- first_sideeffect_index = len(newops) - exc_catch
- newops[first_sideeffect_index:first_sideeffect_index] = keepalives
return newops
def constant_fold_block(block):
@@ -177,33 +160,23 @@
if block.exitswitch == c_last_exception:
n -= 1
# is the next, non-folded operation an indirect_call?
- m = folded_count
- while m < n and block.operations[m].opname == 'keepalive':
- m += 1
- if m < n:
- nextop = block.operations[m]
+ if folded_count < n:
+ nextop = block.operations[folded_count]
if nextop.opname == 'indirect_call' and nextop.args[0] in constants:
# indirect_call -> direct_call
callargs = [constants[nextop.args[0]]]
constants1 = constants.copy()
complete_constants(link, constants1)
- newkeepalives = []
- for i in range(folded_count, m):
- [v] = block.operations[i].args
- v = constants1.get(v, v)
- v_void = Variable()
- v_void.concretetype = lltype.Void
- newkeepalives.append(SpaceOperation('keepalive', [v], v_void))
for v in nextop.args[1:-1]:
callargs.append(constants1.get(v, v))
v_result = Variable(nextop.result)
v_result.concretetype = nextop.result.concretetype
constants[nextop.result] = v_result
callop = SpaceOperation('direct_call', callargs, v_result)
- newblock = insert_empty_block(None, link, newkeepalives + [callop])
+ newblock = insert_empty_block(None, link, [callop])
[link] = newblock.exits
assert link.target is block
- folded_count = m+1
+ folded_count += 1
if folded_count > 0:
splits = splitblocks.setdefault(block, [])
@@ -226,7 +199,7 @@
splitlink = block.exits[0]
else:
# split the block at the given position
- splitlink = split_block_with_keepalive(block, position)
+ splitlink = split_block(None, block, position)
assert list(block.exits) == [splitlink]
assert link.target is block
assert splitlink.prevblock is block
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -119,13 +119,16 @@
Impara, Germany
Change Maker, Sweden
+The PyPy Logo as used by http://speed.pypy.org and others was created
+by Samuel Reis and is distributed on terms of Creative Commons Share Alike
+License.
-License for 'lib-python/2.5.2' and 'lib-python/2.5.2-modified'
+License for 'lib-python/2.7.0' and 'lib-python/2.7.0-modified'
==============================================================
Except when otherwise stated (look for LICENSE files or
copyright/license information at the beginning of each file) the files
-in the 'lib-python/2.5.2' and 'lib-python/2.5.2-modified' directories
+in the 'lib-python/2.7.0' and 'lib-python/2.7.0-modified' directories
are all copyrighted by the Python Software Foundation and licensed under
the Python Software License of which you can find a copy here:
http://www.python.org/doc/Copyright.html
@@ -158,21 +161,12 @@
======================================
The following files are from the website of The Unicode Consortium
-at http://www.unicode.org/. For the terms of use of these files, see
-http://www.unicode.org/terms_of_use.html
+at http://www.unicode.org/. For the terms of use of these files, see
+http://www.unicode.org/terms_of_use.html . Or they are derived from
+files from the above website, and the same terms of use apply.
- CompositionExclusions-3.2.0.txt
- CompositionExclusions-4.1.0.txt
- CompositionExclusions-5.0.0.txt
- EastAsianWidth-3.2.0.txt
- EastAsianWidth-4.1.0.txt
- EastAsianWidth-5.0.0.txt
- UnicodeData-3.2.0.txt
- UnicodeData-4.1.0.txt
- UnicodeData-5.0.0.txt
-
-The following files are derived from files from the above website. The same
-terms of use apply.
- UnihanNumeric-3.2.0.txt
- UnihanNumeric-4.1.0.txt
- UnihanNumeric-5.0.0.txt
+ CompositionExclusions-*.txt
+ EastAsianWidth-*.txt
+ LineBreak-*.txt
+ UnicodeData-*.txt
+ UnihanNumeric-*.txt
diff --git a/pypy/translator/c/test/test_lltyped.py b/pypy/translator/c/test/test_lltyped.py
--- a/pypy/translator/c/test/test_lltyped.py
+++ b/pypy/translator/c/test/test_lltyped.py
@@ -895,3 +895,10 @@
fn = self.getcompiled(llf)
assert fn() == 45
+ def test_rstring_to_float(self):
+ from pypy.rlib.rfloat import rstring_to_float
+ def llf(i):
+ s = ['42.3', '123.4'][i]
+ return rstring_to_float(s)
+ fn = self.getcompiled(llf, [int])
+ assert fn(0) == 42.3
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
@@ -9,7 +9,6 @@
from pypy.jit.tool.oparser import parse
from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
-from pypy.rpython.memory.gctransform import asmgcroot
def test_boehm():
gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -75,8 +74,8 @@
num2a = ((-num2|3) >> 7) | 128
num2b = (-num2|3) & 127
shape = gcrootmap.get_basic_shape()
- gcrootmap.add_ebp_offset(shape, num1)
- gcrootmap.add_ebp_offset(shape, num2)
+ gcrootmap.add_frame_offset(shape, num1)
+ gcrootmap.add_frame_offset(shape, num2)
assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
gcrootmap.add_callee_save_reg(shape, 1)
assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
@@ -228,6 +227,33 @@
gc.asmgcroot = saved
+class TestGcRootMapShadowStack:
+ class FakeGcDescr:
+ force_index_ofs = 92
+
+ def test_make_shapes(self):
+ gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+ shape = gcrootmap.get_basic_shape()
+ gcrootmap.add_frame_offset(shape, 16)
+ gcrootmap.add_frame_offset(shape, -24)
+ assert shape == [16, -24]
+
+ def test_compress_callshape(self):
+ class FakeDataBlockWrapper:
+ def malloc_aligned(self, size, alignment):
+ assert alignment == 4 # even on 64-bits
+ assert size == 12 # 4*3, even on 64-bits
+ return rffi.cast(lltype.Signed, p)
+ datablockwrapper = FakeDataBlockWrapper()
+ p = lltype.malloc(rffi.CArray(rffi.INT), 3, immortal=True)
+ gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+ shape = [16, -24]
+ gcrootmap.compress_callshape(shape, datablockwrapper)
+ assert rffi.cast(lltype.Signed, p[0]) == 16
+ assert rffi.cast(lltype.Signed, p[1]) == -24
+ assert rffi.cast(lltype.Signed, p[2]) == 0
+
+
class FakeLLOp(object):
def __init__(self):
self.record = []
diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py
--- a/pypy/module/sys/interp_encoding.py
+++ b/pypy/module/sys/interp_encoding.py
@@ -37,6 +37,10 @@
base_encoding = None
def _getfilesystemencoding(space):
+ if (space.config.translation.type_system == 'ootype'):
+ # XXX: fix this for ootype
+ return base_encoding
+ #
encoding = base_encoding
if rlocale.HAVE_LANGINFO and rlocale.CODESET:
oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None)
diff --git a/lib-python/TODO b/lib-python/TODO
--- a/lib-python/TODO
+++ b/lib-python/TODO
@@ -2,7 +2,7 @@
===================
You can find the results of the most recent buildbot run at:
-http://buildbot.pypy.org/summary?branch=fast-forward
+http://buildbot.pypy.org/
Probably easy tasks
@@ -39,18 +39,8 @@
Medium tasks
------------
-- Ast objects should be picklable, see in pypy/module/_ast/test/test_ast.py:
- test_pickle()
-
- socket module has a couple of changes (including AF_TIPC packet range)
-- (test_lib2to3) When a "for" loop runs a generator function, if the loop is
- exited before the end, the "finally" clause of the generator is not called
- until the next gc collection. In our case, in lib2to3/pytree.py,
- WildcardPattern.match_seq() does not exhaust the generate_matches() generator,
- and stderr is not restored.
-
-
Longer tasks
------------
diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py
--- a/pypy/jit/metainterp/test/test_send.py
+++ b/pypy/jit/metainterp/test/test_send.py
@@ -1,7 +1,7 @@
import py
from pypy.rlib.jit import JitDriver, hint, purefunction
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class SendTests(object):
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -457,6 +457,12 @@
args_s.append(s_arg)
bk.emulate_pbc_call(uniquekey, s_func, args_s)
+ def get_getfield_op(self, rtyper):
+ if rtyper.type_system.name == 'ootypesystem':
+ return 'oogetfield'
+ else:
+ return 'getfield'
+
def specialize_call(self, hop, **kwds_i):
# XXX to be complete, this could also check that the concretetype
# of the variables are the same for each of the calls.
@@ -471,8 +477,8 @@
r_green = hop.args_r[i]
v_green = hop.inputarg(r_green, arg=i)
else:
- if hop.rtyper.type_system.name == 'ootypesystem':
- py.test.skip("lltype only")
+ #if hop.rtyper.type_system.name == 'ootypesystem':
+ #py.test.skip("lltype only")
objname, fieldname = name.split('.') # see test_green_field
assert objname in driver.reds
i = kwds_i['i_' + objname]
@@ -488,7 +494,10 @@
"field %r not found in %r" % (name,
r_red.lowleveltype.TO))
r_red = r_red.rbase
- GTYPE = r_red.lowleveltype.TO
+ if hop.rtyper.type_system.name == 'ootypesystem':
+ GTYPE = r_red.lowleveltype
+ else:
+ GTYPE = r_red.lowleveltype.TO
assert GTYPE._immutable_field(mangled_name), (
"field %r must be declared as immutable" % name)
if not hasattr(driver, 'll_greenfields'):
@@ -497,7 +506,8 @@
#
v_red = hop.inputarg(r_red, arg=i)
c_llname = hop.inputconst(lltype.Void, mangled_name)
- v_green = hop.genop('getfield', [v_red, c_llname],
+ getfield_op = self.get_getfield_op(hop.rtyper)
+ v_green = hop.genop(getfield_op, [v_red, c_llname],
resulttype = r_field)
s_green = s_red.classdef.about_attribute(fieldname)
assert s_green is not None
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
@@ -1,5 +1,5 @@
import py
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
from pypy.rlib import objectmodel
diff --git a/pypy/rpython/memory/test/test_transformed_gc.py b/pypy/rpython/memory/test/test_transformed_gc.py
--- a/pypy/rpython/memory/test/test_transformed_gc.py
+++ b/pypy/rpython/memory/test/test_transformed_gc.py
@@ -13,7 +13,6 @@
from pypy.rlib import rgc
from pypy import conftest
from pypy.rlib.rstring import StringBuilder
-from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rlib.rarithmetic import LONG_BIT
WORD = LONG_BIT // 8
diff --git a/pypy/translator/backendopt/test/test_support.py b/pypy/translator/backendopt/test/test_support.py
--- a/pypy/translator/backendopt/test/test_support.py
+++ b/pypy/translator/backendopt/test/test_support.py
@@ -1,94 +1,7 @@
-from pypy.translator.unsimplify import varoftype
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator.backendopt.support import \
- needs_conservative_livevar_calculation, split_block_with_keepalive, \
find_loop_blocks, find_backedges, compute_reachability
-from pypy.rpython.rtyper import LowLevelOpList
-from pypy.rpython.lltypesystem import lltype
-from pypy.objspace.flow import model
-
-NonGcB = lltype.Struct("B", ('x', lltype.Signed))
-GcA = lltype.GcStruct("A", ('b', NonGcB), ('c', lltype.Ptr(lltype.FuncType([], lltype.Void))))
-
-def test_nclc_should_be_true():
- # this is testing a block like:
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getsubstruct pointer_to_gc 'b'
- # +--- exitargs: v0 (i.e. pointer to non-gc)
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([v_res], None))
- assert needs_conservative_livevar_calculation(block)
-
-def test_nclc_nongc_not_passed_on():
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getsubstruct pointer_to_gc 'b'
- # +--- exitargs: pointer_to_gc (i.e. the pointer to non-gc doesn't leave the block)
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([ptr_a], None))
- assert not needs_conservative_livevar_calculation(block)
-
-def test_nclc_ignore_functype():
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getfield pointer_to_gc 'c'
- # +--- exitargs: v0 (i.e. a pointer to function)
- # pointers to functions are 'not gc' but functions are also
- # immortal so you don't need to muck around inserting keepalives
- # so *they* don't die!
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('c', lltype.Void)],
- resulttype=GcA.c)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([v_res], None))
- assert not needs_conservative_livevar_calculation(block)
-
-def test_sbwk_should_insert_keepalives():
- # this is testing something like:
- # v0 <- op_producing_non_gc
- # v1 <- op_using_v0 <- split here
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res],
- resulttype=lltype.Void)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([], None))
- link = split_block_with_keepalive(block, 1)
- assert 'keepalive' in [op.opname for op in link.target.operations]
-
-def test_sbwk_should_insert_keepalives_2():
- # this is testing something like:
- # v0 <- op_producing_non_gc
- # v1 <- op_not_using_v0 <- split here
- # v2 <- op_using_v0
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- llops.genop("direct_call", [model.Constant(None, lltype.Void)],
- resulttype=lltype.Void)
- llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res],
- resulttype=lltype.Void)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([], None))
- link = split_block_with_keepalive(block, 1)
- assert 'keepalive' in [op.opname for op in link.target.operations]
-
#__________________________________________________________
# test compute_reachability
diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py
--- a/pypy/jit/metainterp/test/test_optimizeutil.py
+++ b/pypy/jit/metainterp/test/test_optimizeutil.py
@@ -68,6 +68,16 @@
nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj)
refdescr = cpu.fielddescrof(NODEOBJ, 'ref')
+ INTOBJ_NOIMMUT = lltype.GcStruct('INTOBJ_NOIMMUT', ('parent', OBJECT),
+ ('intval', lltype.Signed))
+ INTOBJ_IMMUT = lltype.GcStruct('INTOBJ_IMMUT', ('parent', OBJECT),
+ ('intval', lltype.Signed),
+ hints={'immutable': True})
+ intobj_noimmut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ intobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval')
+ immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval')
+
arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
@@ -155,6 +165,8 @@
register_known_gctype(cpu, node_vtable2, NODE2)
register_known_gctype(cpu, u_vtable, U)
register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF)
+ register_known_gctype(cpu, intobj_noimmut_vtable, INTOBJ_NOIMMUT)
+ register_known_gctype(cpu, intobj_immut_vtable, INTOBJ_IMMUT)
namespace = locals()
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
@@ -1,6 +1,8 @@
+import os
from pypy.rlib import rgc
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import fatalerror
+from pypy.rlib.rarithmetic import ovfcheck
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
from pypy.rpython.lltypesystem import llgroup
from pypy.rpython.lltypesystem.lloperation import llop
@@ -21,6 +23,8 @@
class GcLLDescription(GcCache):
minimal_size_in_nursery = 0
+ get_malloc_slowpath_addr = None
+
def __init__(self, gcdescr, translator=None, rtyper=None):
GcCache.__init__(self, translator is not None, rtyper)
self.gcdescr = gcdescr
@@ -34,6 +38,8 @@
pass
def can_inline_malloc(self, descr):
return False
+ def can_inline_malloc_varsize(self, descr, num_elem):
+ return False
def has_write_barrier_class(self):
return None
def freeing_block(self, start, stop):
@@ -212,10 +218,12 @@
return addr_ref
-class GcRootMap_asmgcc:
+class GcRootMap_asmgcc(object):
"""Handles locating the stack roots in the assembler.
This is the class supporting --gcrootfinder=asmgcc.
"""
+ is_shadow_stack = False
+
LOC_REG = 0
LOC_ESP_PLUS = 1
LOC_EBP_PLUS = 2
@@ -224,7 +232,7 @@
GCMAP_ARRAY = rffi.CArray(lltype.Signed)
CALLSHAPE_ARRAY_PTR = rffi.CArrayPtr(rffi.UCHAR)
- def __init__(self):
+ def __init__(self, gcdescr=None):
# '_gcmap' is an array of length '_gcmap_maxlength' of addresses.
# '_gcmap_curlength' tells how full the array really is.
# The addresses are actually grouped in pairs:
@@ -237,6 +245,13 @@
self._gcmap_deadentries = 0
self._gcmap_sorted = True
+ def add_jit2gc_hooks(self, jit2gc):
+ jit2gc.update({
+ 'gcmapstart': lambda: self.gcmapstart(),
+ 'gcmapend': lambda: self.gcmapend(),
+ 'gcmarksorted': lambda: self.gcmarksorted(),
+ })
+
def initialize(self):
# hack hack hack. Remove these lines and see MissingRTypeAttribute
# when the rtyper tries to annotate these methods only when GC-ing...
@@ -365,7 +380,7 @@
number >>= 7
shape.append(chr(number | flag))
- def add_ebp_offset(self, shape, offset):
+ def add_frame_offset(self, shape, offset):
assert (offset & 3) == 0
if offset >= 0:
num = self.LOC_EBP_PLUS | offset
@@ -388,6 +403,126 @@
return rawaddr
+class GcRootMap_shadowstack(object):
+ """Handles locating the stack roots in the assembler.
+ This is the class supporting --gcrootfinder=shadowstack.
+ """
+ is_shadow_stack = True
+ MARKER = 8
+
+ # The "shadowstack" is a portable way in which the GC finds the
+ # roots that live in the stack. Normally it is just a list of
+ # pointers to GC objects. The pointers may be moved around by a GC
+ # collection. But with the JIT, an entry can also be MARKER, in
+ # which case the next entry points to an assembler stack frame.
+ # During a residual CALL from the assembler (which may indirectly
+ # call the GC), we use the force_index stored in the assembler
+ # stack frame to identify the call: we can go from the force_index
+ # to a list of where the GC pointers are in the frame (this is the
+ # purpose of the present class).
+ #
+ # Note that across CALL_MAY_FORCE or CALL_ASSEMBLER, we can also go
+ # from the force_index to a ResumeGuardForcedDescr instance, which
+ # is used if the virtualizable or the virtualrefs need to be forced
+ # (see pypy.jit.backend.model). The force_index number in the stack
+ # frame is initially set to a non-negative value x, but it is
+ # occasionally turned into (~x) in case of forcing.
+
+ INTARRAYPTR = rffi.CArrayPtr(rffi.INT)
+ CALLSHAPES_ARRAY = rffi.CArray(INTARRAYPTR)
+
+ def __init__(self, gcdescr):
+ self._callshapes = lltype.nullptr(self.CALLSHAPES_ARRAY)
+ self._callshapes_maxlength = 0
+ self.force_index_ofs = gcdescr.force_index_ofs
+
+ def add_jit2gc_hooks(self, jit2gc):
+ #
+ def collect_jit_stack_root(callback, gc, addr):
+ if addr.signed[0] != GcRootMap_shadowstack.MARKER:
+ # common case
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ return WORD
+ else:
+ # case of a MARKER followed by an assembler stack frame
+ follow_stack_frame_of_assembler(callback, gc, addr)
+ return 2 * WORD
+ #
+ def follow_stack_frame_of_assembler(callback, gc, addr):
+ frame_addr = addr.signed[1]
+ addr = llmemory.cast_int_to_adr(frame_addr + self.force_index_ofs)
+ force_index = addr.signed[0]
+ if force_index < 0:
+ force_index = ~force_index
+ callshape = self._callshapes[force_index]
+ n = 0
+ while True:
+ offset = rffi.cast(lltype.Signed, callshape[n])
+ if offset == 0:
+ break
+ addr = llmemory.cast_int_to_adr(frame_addr + offset)
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ n += 1
+ #
+ jit2gc.update({
+ 'rootstackhook': collect_jit_stack_root,
+ })
+
+ def initialize(self):
+ pass
+
+ def get_basic_shape(self, is_64_bit=False):
+ return []
+
+ def add_frame_offset(self, shape, offset):
+ assert offset != 0
+ shape.append(offset)
+
+ def add_callee_save_reg(self, shape, register):
+ msg = "GC pointer in %s was not spilled" % register
+ os.write(2, '[llsupport/gc] %s\n' % msg)
+ raise AssertionError(msg)
+
+ def compress_callshape(self, shape, datablockwrapper):
+ length = len(shape)
+ SZINT = rffi.sizeof(rffi.INT)
+ rawaddr = datablockwrapper.malloc_aligned((length + 1) * SZINT, SZINT)
+ p = rffi.cast(self.INTARRAYPTR, rawaddr)
+ for i in range(length):
+ p[i] = rffi.cast(rffi.INT, shape[i])
+ p[length] = rffi.cast(rffi.INT, 0)
+ return p
+
+ def write_callshape(self, p, force_index):
+ if force_index >= self._callshapes_maxlength:
+ self._enlarge_callshape_list(force_index + 1)
+ self._callshapes[force_index] = p
+
+ def _enlarge_callshape_list(self, minsize):
+ newlength = 250 + (self._callshapes_maxlength // 3) * 4
+ if newlength < minsize:
+ newlength = minsize
+ newarray = lltype.malloc(self.CALLSHAPES_ARRAY, newlength,
+ flavor='raw', track_allocation=False)
+ if self._callshapes:
+ i = self._callshapes_maxlength - 1
+ while i >= 0:
+ newarray[i] = self._callshapes[i]
+ i -= 1
+ lltype.free(self._callshapes, flavor='raw', track_allocation=False)
+ self._callshapes = newarray
+ self._callshapes_maxlength = newlength
+
+ def freeing_block(self, start, stop):
+ pass # nothing needed here
+
+ def get_root_stack_top_addr(self):
+ rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address)
+ return rffi.cast(lltype.Signed, rst_addr)
+
+
class WriteBarrierDescr(AbstractDescr):
def __init__(self, gc_ll_descr):
self.llop1 = gc_ll_descr.llop1
@@ -437,7 +572,7 @@
except KeyError:
raise NotImplementedError("--gcrootfinder=%s not implemented"
" with the JIT" % (name,))
- gcrootmap = cls()
+ gcrootmap = cls(gcdescr)
self.gcrootmap = gcrootmap
self.gcrefs = GcRefList()
self.single_gcref_descr = GcPtrFieldDescr('', 0)
@@ -446,12 +581,9 @@
# where it can be fished and reused by the FrameworkGCTransformer
self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
self.layoutbuilder.delay_encoding()
- self.translator._jit2gc = {
- 'layoutbuilder': self.layoutbuilder,
- 'gcmapstart': lambda: gcrootmap.gcmapstart(),
- 'gcmapend': lambda: gcrootmap.gcmapend(),
- 'gcmarksorted': lambda: gcrootmap.gcmarksorted(),
- }
+ self.translator._jit2gc = {'layoutbuilder': self.layoutbuilder}
+ gcrootmap.add_jit2gc_hooks(self.translator._jit2gc)
+
self.GCClass = self.layoutbuilder.GCClass
self.moving_gc = self.GCClass.moving_gc
self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
@@ -461,6 +593,10 @@
self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
+ # for the fast path of mallocs, the following must be true, at least
+ assert self.GCClass.inline_simple_malloc
+ assert self.GCClass.inline_simple_malloc_varsize
+
# make a malloc function, with three arguments
def malloc_basic(size, tid):
type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
@@ -539,20 +675,23 @@
x3 = x0 * 0.3
for_test_only.x = x0 + x1 + x2 + x3
#
- def malloc_fixedsize_slowpath(size):
+ def malloc_slowpath(size):
if self.DEBUG:
random_usage_of_xmm_registers()
assert size >= self.minimal_size_in_nursery
try:
+ # NB. although we call do_malloc_fixedsize_clear() here,
+ # it's a bit of a hack because we set tid to 0 and may
+ # 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, True, False, False)
except MemoryError:
fatalerror("out of memory (from JITted code)")
return 0
return rffi.cast(lltype.Signed, gcref)
- self.malloc_fixedsize_slowpath = malloc_fixedsize_slowpath
- self.MALLOC_FIXEDSIZE_SLOWPATH = lltype.FuncType([lltype.Signed],
- lltype.Signed)
+ self.malloc_slowpath = malloc_slowpath
+ self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed], lltype.Signed)
def get_nursery_free_addr(self):
nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
@@ -562,9 +701,8 @@
nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
return rffi.cast(lltype.Signed, nurs_top_addr)
- def get_malloc_fixedsize_slowpath_addr(self):
- fptr = llhelper(lltype.Ptr(self.MALLOC_FIXEDSIZE_SLOWPATH),
- self.malloc_fixedsize_slowpath)
+ def get_malloc_slowpath_addr(self):
+ fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
return rffi.cast(lltype.Signed, fptr)
def initialize(self):
@@ -710,6 +848,16 @@
return True
return False
+ def can_inline_malloc_varsize(self, arraydescr, num_elem):
+ assert isinstance(arraydescr, BaseArrayDescr)
+ basesize = arraydescr.get_base_size(self.translate_support_code)
+ itemsize = arraydescr.get_item_size(self.translate_support_code)
+ try:
+ size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+ return size < self.max_size_of_young_obj
+ except OverflowError:
+ return False
+
def has_write_barrier_class(self):
return WriteBarrierDescr
diff --git a/pypy/translator/backendopt/malloc.py b/pypy/translator/backendopt/malloc.py
--- a/pypy/translator/backendopt/malloc.py
+++ b/pypy/translator/backendopt/malloc.py
@@ -1,5 +1,5 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
-from pypy.objspace.flow.model import SpaceOperation, traverse
+from pypy.objspace.flow.model import SpaceOperation
from pypy.tool.algo.unionfind import UnionFind
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
@@ -67,7 +67,6 @@
# in this 'block', follow where the 'var' goes to and replace
# it by a flattened-out family of variables. This family is given
# by newvarsmap, whose keys are the 'flatnames'.
- self.last_removed_access = None
def list_newvars():
return [newvarsmap[key] for key in self.flatnames]
@@ -115,7 +114,6 @@
newargs.append(arg)
link.args[:] = newargs
- self.insert_keepalives(list_newvars())
block.operations[:] = self.newops
def compute_lifetimes(self, graph):
@@ -149,8 +147,7 @@
set_use_point(graph.exceptblock, graph.exceptblock.inputargs[0], "except")
set_use_point(graph.exceptblock, graph.exceptblock.inputargs[1], "except")
- def visit(node):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname in self.IDENTITY_OPS:
# special-case these operations to identify their input
@@ -167,7 +164,7 @@
if isinstance(node.exitswitch, Variable):
set_use_point(node, node.exitswitch, "exitswitch", node)
- if isinstance(node, Link):
+ for node in graph.iterlinks():
if isinstance(node.last_exception, Variable):
set_creation_point(node.prevblock, node.last_exception,
"last_exception")
@@ -187,7 +184,6 @@
else:
d[arg] = True
- traverse(visit, graph)
return lifetimes.infos()
def _try_inline_malloc(self, info):
@@ -213,7 +209,7 @@
STRUCT = self.get_STRUCT(lltypes.keys()[0])
# must be only ever accessed via getfield/setfield/getsubstruct/
- # direct_fieldptr, or touched by keepalive or ptr_iszero/ptr_nonzero.
+ # direct_fieldptr, or touched by ptr_iszero/ptr_nonzero.
# Note that same_as and cast_pointer are not recorded in usepoints.
self.accessed_substructs = {}
@@ -333,7 +329,6 @@
MALLOC_OP = "malloc"
FIELD_ACCESS = dict.fromkeys(["getfield",
"setfield",
- "keepalive",
"ptr_iszero",
"ptr_nonzero",
"getarrayitem",
@@ -484,7 +479,6 @@
[newvarsmap[key]],
op.result)
self.newops.append(newop)
- self.last_removed_access = len(self.newops)
elif op.opname in ("setfield", "setarrayitem"):
S = op.args[0].concretetype.TO
fldname = op.args[1].value
@@ -500,15 +494,12 @@
self.newops.append(newop)
else:
newvarsmap[key] = op.args[2]
- self.last_removed_access = len(self.newops)
elif op.opname in ("same_as", "cast_pointer"):
vars[op.result] = True
# Consider the two pointers (input and result) as
# equivalent. We can, and indeed must, use the same
# flattened list of variables for both, as a "setfield"
# via one pointer must be reflected in the other.
- elif op.opname == 'keepalive':
- self.last_removed_access = len(self.newops)
elif op.opname in ("getsubstruct", "getarraysubstruct",
"direct_fieldptr"):
S = op.args[0].concretetype.TO
@@ -546,18 +537,6 @@
else:
raise AssertionError, op.opname
-
- def insert_keepalives(self, newvars):
- if self.last_removed_access is not None:
- keepalives = []
- for v in newvars:
- T = v.concretetype
- if isinstance(T, lltype.Ptr) and T._needsgc():
- v0 = Variable()
- v0.concretetype = lltype.Void
- newop = SpaceOperation('keepalive', [v], v0)
- keepalives.append(newop)
- self.newops[self.last_removed_access:self.last_removed_access] = keepalives
class OOTypeMallocRemover(BaseMallocRemover):
@@ -616,14 +595,12 @@
[newvarsmap[key]],
op.result)
self.newops.append(newop)
- last_removed_access = len(self.newops)
elif op.opname == "oosetfield":
S = op.args[0].concretetype
fldname = op.args[1].value
key = self.key_for_field_access(S, fldname)
assert key in newvarsmap
newvarsmap[key] = op.args[2]
- last_removed_access = len(self.newops)
elif op.opname in ("same_as", "oodowncast", "ooupcast"):
vars[op.result] = True
# Consider the two pointers (input and result) as
@@ -639,8 +616,6 @@
else:
raise AssertionError, op.opname
- def insert_keepalives(self, newvars):
- pass
def remove_simple_mallocs(graph, type_system='lltypesystem', verbose=True):
if type_system == 'lltypesystem':
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -79,7 +79,8 @@
possibly replacing ``--opt=jit`` with another `optimization level`_
of your choice like ``--opt=2`` if you do not want the included JIT
- compiler. As of March 2011, Intel **32-bit** environment needs ``4GB``.
+ compiler. As of March 2011, Intel 32-bit environment needs **at
+ least** 2GB, and 64-bit needs 4GB.
.. _`optimization level`: config/opt.html
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -880,6 +880,11 @@
except AttributeError:
return False
+ def warn_missing_attribute(self, attr):
+ # only warn for missing attribute names whose name doesn't start
+ # with '$', to silence the warnings about '$memofield_xxx'.
+ return not self.has_attribute(attr) and not attr.startswith('$')
+
def read_attribute(self, attr):
try:
return self.attrcache[attr]
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
@@ -12,7 +12,7 @@
import py
from pypy.jit.metainterp.memmgr import MemoryManager
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.rlib.jit import JitDriver, dont_look_inside
diff --git a/pypy/translator/backendopt/test/test_constfold.py b/pypy/translator/backendopt/test/test_constfold.py
--- a/pypy/translator/backendopt/test/test_constfold.py
+++ b/pypy/translator/backendopt/test/test_constfold.py
@@ -185,27 +185,6 @@
check_graph(graph, [0], 61, t)
-def test_keepalive_const_substruct():
- py.test.skip("do we want partial folding of getinteriorfield?")
- S2 = lltype.Struct('S2', ('x', lltype.Signed))
- S1 = lltype.GcStruct('S1', ('sub', S2))
- s1 = lltype.malloc(S1)
- s1.sub.x = 1234
- def fn():
- return s1.sub.x
- graph, t = get_graph(fn, [])
- assert summary(graph) == {'getinteriorfield': 1}
- constant_fold_graph(graph)
-
- # kill all references to 's1'
- s1 = fn = None
- del graph.func
- import gc; gc.collect()
-
- assert summary(graph) == {'getfield': 1}
- check_graph(graph, [], 1234, t)
-
-
def test_keepalive_const_fieldptr():
S1 = lltype.GcStruct('S1', ('x', lltype.Signed))
s1 = lltype.malloc(S1)
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class ListTests:
diff --git a/_pytest/resultlog.py b/_pytest/resultlog.py
--- a/_pytest/resultlog.py
+++ b/_pytest/resultlog.py
@@ -74,7 +74,7 @@
elif report.failed:
longrepr = str(report.longrepr)
elif report.skipped:
- longrepr = str(report.longrepr[2])
+ longrepr = str(report.longrepr)
self.log_outcome(report, code, longrepr)
def pytest_collectreport(self, report):
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
@@ -717,6 +717,7 @@
def test_random_function(BuilderClass=OperationBuilder):
r = Random()
cpu = get_cpu()
+ cpu.setup_once()
if pytest.config.option.repeat == -1:
while 1:
check_random_function(cpu, BuilderClass, r)
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -5,8 +5,8 @@
soon as possible (at least in a simple case).
"""
-import weakref, random
-import py
+import weakref
+import py, os
from pypy.annotation import policy as annpolicy
from pypy.rlib import rgc
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -72,6 +72,20 @@
return entrypoint
+def get_functions_to_patch():
+ from pypy.jit.backend.llsupport import gc
+ #
+ can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc
+ def can_inline_malloc2(*args):
+ try:
+ if os.environ['PYPY_NO_INLINE_MALLOC']:
+ return False
+ except KeyError:
+ pass
+ return can_inline_malloc1(*args)
+ #
+ return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2}
+
def compile(f, gc, **kwds):
from pypy.annotation.listdef import s_list_of_strings
from pypy.translator.translator import TranslationContext
@@ -87,8 +101,21 @@
ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy())
ann.build_types(f, [s_list_of_strings], main_entry_point=True)
t.buildrtyper().specialize()
+
if kwds['jit']:
- apply_jit(t, enable_opts='')
+ patch = get_functions_to_patch()
+ old_value = {}
+ try:
+ for (obj, attr), value in patch.items():
+ old_value[obj, attr] = getattr(obj, attr)
+ setattr(obj, attr, value)
+ #
+ apply_jit(t, enable_opts='')
+ #
+ finally:
+ for (obj, attr), oldvalue in old_value.items():
+ setattr(obj, attr, oldvalue)
+
cbuilder = genc.CStandaloneBuilder(t, f, t.config)
cbuilder.generate_source()
cbuilder.compile()
@@ -127,7 +154,7 @@
# ______________________________________________________________________
-class TestCompileFramework(object):
+class CompileFrameworkTests(object):
# Test suite using (so far) the minimark GC.
def setup_class(cls):
funcs = []
@@ -178,15 +205,21 @@
try:
GcLLDescr_framework.DEBUG = True
cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC,
- gcrootfinder="asmgcc", jit=True)
+ gcrootfinder=cls.gcrootfinder, jit=True)
finally:
GcLLDescr_framework.DEBUG = OLD_DEBUG
+ def _run(self, name, n, env):
+ res = self.cbuilder.cmdexec("%s %d" %(name, n), env=env)
+ assert int(res) == 20
+
def run(self, name, n=2000):
pypylog = udir.join('TestCompileFramework.log')
- res = self.cbuilder.cmdexec("%s %d" %(name, n),
- env={'PYPYLOG': ':%s' % pypylog})
- assert int(res) == 20
+ env = {'PYPYLOG': ':%s' % pypylog,
+ 'PYPY_NO_INLINE_MALLOC': '1'}
+ self._run(name, n, env)
+ env['PYPY_NO_INLINE_MALLOC'] = ''
+ self._run(name, n, env)
def run_orig(self, name, n, x):
self.main_allfuncs(name, n, x)
@@ -576,3 +609,10 @@
def test_compile_framework_minimal_size_in_nursery(self):
self.run('compile_framework_minimal_size_in_nursery')
+
+
+class TestShadowStack(CompileFrameworkTests):
+ gcrootfinder = "shadowstack"
+
+class TestAsmGcc(CompileFrameworkTests):
+ gcrootfinder = "asmgcc"
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -105,13 +105,6 @@
return parser
def handle_config(self, config, translateconfig):
- if config.translation.type_system == 'ootype':
- print
- print 'Translation to cli and jvm is known to be broken at the moment'
- print 'Please try the "cli-jit" branch at:'
- print 'http://codespeak.net/svn/pypy/branch/cli-jit/'
- sys.exit(1)
-
self.translateconfig = translateconfig
# set up the objspace optimizations based on the --opt argument
from pypy.config.pypyoption import set_pypy_opt_level
@@ -159,8 +152,8 @@
from pypy.config.pypyoption import enable_translationmodules
enable_translationmodules(config)
- if config.translation.type_system == 'ootype':
- config.objspace.usemodules.suggest(rbench=True)
+ ## if config.translation.type_system == 'ootype':
+ ## config.objspace.usemodules.suggest(rbench=True)
if config.translation.thread:
config.objspace.usemodules.thread = True
diff --git a/pypy/jit/metainterp/test/test_del.py b/pypy/jit/metainterp/test/test_del.py
--- a/pypy/jit/metainterp/test/test_del.py
+++ b/pypy/jit/metainterp/test/test_del.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class DelTests:
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -17,8 +17,8 @@
'_count': 'os_thread._count',
'allocate_lock': 'os_lock.allocate_lock',
'allocate': 'os_lock.allocate_lock', # obsolete synonym
- 'LockType': 'os_lock.getlocktype(space)',
- '_local': 'os_local.getlocaltype(space)',
+ 'LockType': 'os_lock.Lock',
+ '_local': 'os_local.Local',
'error': 'space.fromcache(error.Cache).w_error',
}
diff --git a/lib_pypy/_pypy_wait.py b/lib_pypy/_pypy_wait.py
--- a/lib_pypy/_pypy_wait.py
+++ b/lib_pypy/_pypy_wait.py
@@ -2,34 +2,50 @@
from ctypes.util import find_library
from resource import _struct_rusage, struct_rusage
+__all__ = ["wait3", "wait4"]
+
libc = CDLL(find_library("c"))
c_wait3 = libc.wait3
c_wait3.argtypes = [POINTER(c_int), c_int, POINTER(_struct_rusage)]
+c_wait4 = libc.wait4
+
+c_wait4.argtypes = [c_int, POINTER(c_int), c_int, POINTER(_struct_rusage)]
+
+def create_struct_rusage(c_struct):
+ return struct_rusage((
+ float(c_struct.ru_utime),
+ float(c_struct.ru_stime),
+ c_struct.ru_maxrss,
+ c_struct.ru_ixrss,
+ c_struct.ru_idrss,
+ c_struct.ru_isrss,
+ c_struct.ru_minflt,
+ c_struct.ru_majflt,
+ c_struct.ru_nswap,
+ c_struct.ru_inblock,
+ c_struct.ru_oublock,
+ c_struct.ru_msgsnd,
+ c_struct.ru_msgrcv,
+ c_struct.ru_nsignals,
+ c_struct.ru_nvcsw,
+ c_struct.ru_nivcsw))
+
def wait3(options):
status = c_int()
_rusage = _struct_rusage()
pid = c_wait3(byref(status), c_int(options), byref(_rusage))
- rusage = struct_rusage((
- float(_rusage.ru_utime),
- float(_rusage.ru_stime),
- _rusage.ru_maxrss,
- _rusage.ru_ixrss,
- _rusage.ru_idrss,
- _rusage.ru_isrss,
- _rusage.ru_minflt,
- _rusage.ru_majflt,
- _rusage.ru_nswap,
- _rusage.ru_inblock,
- _rusage.ru_oublock,
- _rusage.ru_msgsnd,
- _rusage.ru_msgrcv,
- _rusage.ru_nsignals,
- _rusage.ru_nvcsw,
- _rusage.ru_nivcsw))
+ rusage = create_struct_rusage(_rusage)
return pid, status.value, rusage
-__all__ = ["wait3"]
+def wait4(pid, options):
+ status = c_int()
+ _rusage = _struct_rusage()
+ pid = c_wait4(c_int(pid), byref(status), c_int(options), byref(_rusage))
+
+ rusage = create_struct_rusage(_rusage)
+
+ return pid, status.value, rusage
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -174,6 +174,17 @@
assert api.PyObject_Compare(space.wrap(72), space.wrap(42)) == 1
assert api.PyObject_Compare(space.wrap("a"), space.wrap("a")) == 0
+ def test_cmp(self, space, api):
+ w = space.wrap
+ with lltype.scoped_alloc(rffi.INTP.TO, 1) as ptr:
+ assert api.PyObject_Cmp(w(42), w(72), ptr) == 0
+ assert ptr[0] == -1
+ assert api.PyObject_Cmp(w("a"), w("a"), ptr) == 0
+ assert ptr[0] == 0
+ assert api.PyObject_Cmp(w(u"\xe9"), w("\xe9"), ptr) < 0
+ assert api.PyErr_Occurred()
+ api.PyErr_Clear()
+
def test_unicode(self, space, api):
assert space.unwrap(api.PyObject_Unicode(space.wrap([]))) == u"[]"
assert space.unwrap(api.PyObject_Unicode(space.wrap("e"))) == u"e"
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -3,7 +3,8 @@
from pypy.rlib.rarithmetic import most_neg_value_of_same_type
from pypy.rlib.rfloat import isinf, isnan
from pypy.rlib.debug import make_sure_not_resized, check_regular_int
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, specialize
+from pypy.rlib import jit
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rpython import extregistry
@@ -122,7 +123,11 @@
def numdigits(self):
return len(self._digits)
+ @staticmethod
+ @jit.purefunction
def fromint(intval):
+ # This function is marked as pure, so you must not call it and
+ # then modify the result.
check_regular_int(intval)
if intval < 0:
sign = -1
@@ -149,20 +154,25 @@
t >>= SHIFT
p += 1
return v
- fromint = staticmethod(fromint)
+ @staticmethod
+ @jit.purefunction
def frombool(b):
+ # This function is marked as pure, so you must not call it and
+ # then modify the result.
if b:
return rbigint([ONEDIGIT], 1)
return rbigint()
- frombool = staticmethod(frombool)
+ @staticmethod
def fromlong(l):
+ "NOT_RPYTHON"
return rbigint(*args_from_long(l))
- fromlong = staticmethod(fromlong)
+ @staticmethod
def fromfloat(dval):
""" Create a new bigint object from a float """
+ # This function is not marked as pure because it can raise
sign = 1
if isinf(dval) or isnan(dval):
raise OverflowError
@@ -183,16 +193,21 @@
frac -= float(bits)
frac = math.ldexp(frac, SHIFT)
return v
- fromfloat = staticmethod(fromfloat)
+ @staticmethod
+ @jit.purefunction
+ @specialize.argtype(0)
def fromrarith_int(i):
+ # This function is marked as pure, so you must not call it and
+ # then modify the result.
return rbigint(*args_from_rarith_int(i))
- fromrarith_int._annspecialcase_ = "specialize:argtype(0)"
- fromrarith_int = staticmethod(fromrarith_int)
+ @staticmethod
+ @jit.purefunction
def fromdecimalstr(s):
+ # This function is marked as pure, so you must not call it and
+ # then modify the result.
return _decimalstr_to_bigint(s)
- fromdecimalstr = staticmethod(fromdecimalstr)
def toint(self):
"""
@@ -1841,7 +1856,7 @@
elif s[p] == '+':
p += 1
- a = rbigint.fromint(0)
+ a = rbigint()
tens = 1
dig = 0
ord0 = ord('0')
@@ -1859,7 +1874,7 @@
def parse_digit_string(parser):
# helper for objspace.std.strutil
- a = rbigint.fromint(0)
+ a = rbigint()
base = parser.base
digitmax = BASE_MAX[base]
tens, dig = 1, 0
diff --git a/pypy/translator/jvm/database.py b/pypy/translator/jvm/database.py
--- a/pypy/translator/jvm/database.py
+++ b/pypy/translator/jvm/database.py
@@ -4,7 +4,7 @@
"""
from cStringIO import StringIO
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rpython.ootypesystem import ootype, rclass
from pypy.rpython.ootypesystem.module import ll_os
from pypy.translator.jvm import node, methods
@@ -229,9 +229,15 @@
if not ootype.isSubclass(OOTYPE, SELF): continue
mobj = self._function_for_graph(
clsobj, mname, False, mimpl.graph)
- graphs = OOTYPE._lookup_graphs(mname)
- if len(graphs) == 1:
- mobj.is_final = True
+ # XXX: this logic is broken: it might happen that there are
+ # ootype.Instance which contains a meth whose graph is exactly
+ # the same as the meth in the superclass: in this case,
+ # len(graphs) == 1 but we cannot just mark the method as final
+ # (or we can, but we should avoid to emit the method in the
+ # subclass, then)
+ ## graphs = OOTYPE._lookup_graphs(mname)
+ ## if len(graphs) == 1:
+ ## mobj.is_final = True
clsobj.add_method(mobj)
# currently, we always include a special "dump" method for debugging
@@ -359,6 +365,7 @@
ootype.UniChar:jvm.PYPYESCAPEDUNICHAR,
ootype.String:jvm.PYPYESCAPEDSTRING,
ootype.Unicode:jvm.PYPYESCAPEDUNICODE,
+ rffi.SHORT:jvm.SHORTTOSTRINGS,
}
def toString_method_for_ootype(self, OOTYPE):
@@ -406,6 +413,7 @@
ootype.UniChar: jvm.jChar,
ootype.Class: jvm.jClass,
ootype.ROOT: jvm.jObject, # treat like a scalar
+ rffi.SHORT: jvm.jShort,
}
# Dictionary for non-scalar types; in this case, if we see the key, we
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -278,6 +278,22 @@
rex_mem_reg_plus_scaled_reg_plus_const)
# ____________________________________________________________
+# Emit a mod/rm referencing an immediate address that fits in 32-bit
+# (the immediate address itself must be explicitely encoded as well,
+# with immediate(argnum)).
+
+def encode_abs(mc, _1, _2, orbyte):
+ # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit
+ if mc.WORD == 8:
+ mc.writechar(chr(0x04 | orbyte))
+ mc.writechar(chr(0x25))
+ else:
+ mc.writechar(chr(0x05 | orbyte))
+ return 0
+
+abs_ = encode_abs, 0, None, None
+
+# ____________________________________________________________
# For 64-bits mode: the REX.W, REX.R, REX.X, REG.B prefixes
REX_W = 8
@@ -348,7 +364,9 @@
INSN_br = insn(rex_w, chr(base+1), register(2,8), stack_bp(1))
INSN_rb = insn(rex_w, chr(base+3), register(1,8), stack_bp(2))
INSN_rm = insn(rex_w, chr(base+3), register(1,8), mem_reg_plus_const(2))
- INSN_rj = insn(rex_w, chr(base+3), register(1,8), '\x05', immediate(2))
+ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2))
+ INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1),
+ immediate(2,'b'))
INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b'))
INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2))
@@ -366,7 +384,8 @@
INSN_bi32(mc, offset, immed)
INSN_bi._always_inline_ = True # try to constant-fold single_byte()
- return INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj
+ return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj,
+ INSN_ji8)
def select_8_or_32_bit_immed(insn_8, insn_32):
def INSN(*args):
@@ -444,23 +463,25 @@
# ------------------------------ Arithmetic ------------------------------
- ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj = common_modes(0)
- OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj = common_modes(1)
- AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj = common_modes(4)
- SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj = common_modes(5)
- SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj = common_modes(3)
- XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj = common_modes(6)
- CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj = common_modes(7)
+ ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0)
+ OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1)
+ AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4)
+ SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5)
+ SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3)
+ XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6)
+ CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7)
CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b'))
CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
CMP_mi = select_8_or_32_bit_immed(CMP_mi8, CMP_mi32)
CMP_mr = insn(rex_w, '\x39', register(2, 8), mem_reg_plus_const(1))
- CMP_ji8 = insn(rex_w, '\x83', '\x3D', immediate(1), immediate(2, 'b'))
- CMP_ji32 = insn(rex_w, '\x81', '\x3D', immediate(1), immediate(2))
+ CMP_ji8 = insn(rex_w, '\x83', orbyte(7<<3), abs_,
+ immediate(1), immediate(2, 'b'))
+ CMP_ji32 = insn(rex_w, '\x81', orbyte(7<<3), abs_,
+ immediate(1), immediate(2))
CMP_ji = select_8_or_32_bit_immed(CMP_ji8, CMP_ji32)
- CMP_jr = insn(rex_w, '\x39', register(2, 8), '\x05', immediate(1))
+ CMP_jr = insn(rex_w, '\x39', register(2, 8), abs_, immediate(1))
CMP32_mi = insn(rex_nw, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
@@ -508,7 +529,7 @@
LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True))
LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2))
LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2))
- LEA_rj = insn(rex_w, '\x8D', register(1, 8), '\x05', immediate(2))
+ LEA_rj = insn(rex_w, '\x8D', register(1, 8), abs_, immediate(2))
CALL_l = insn('\xE8', relative(1))
CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3)))
@@ -534,12 +555,15 @@
CDQ = insn(rex_nw, '\x99')
TEST8_mi = insn(rex_nw, '\xF6', orbyte(0<<3), mem_reg_plus_const(1), immediate(2, 'b'))
- TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), '\x05', immediate(1), immediate(2, 'b'))
+ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b'))
TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0')
# x87 instructions
FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1))
+ # reserved as an illegal instruction
+ UD2 = insn('\x0F\x0B')
+
# ------------------------------ SSE2 ------------------------------
# Conversion
@@ -639,7 +663,7 @@
add_insn('s', stack_sp(modrm_argnum))
add_insn('m', mem_reg_plus_const(modrm_argnum))
add_insn('a', mem_reg_plus_scaled_reg_plus_const(modrm_argnum))
- add_insn('j', '\x05', immediate(modrm_argnum))
+ add_insn('j', abs_, immediate(modrm_argnum))
# Define a regular MOV, and a variant MOV32 that only uses the low 4 bytes of a
# register
@@ -680,7 +704,7 @@
#
assert insnname_template.count('*') == 1
add_insn('x', register(2), '\xC0')
- add_insn('j', '\x05', immediate(2))
+ add_insn('j', abs_, immediate(2))
define_pxmm_insn('PADDQ_x*', '\xD4')
define_pxmm_insn('PSUBQ_x*', '\xFB')
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -519,7 +519,7 @@
return
code = frame.pycode
if frame.instr_lb <= frame.last_instr < frame.instr_ub:
- if frame.last_instr <= frame.instr_prev:
+ if frame.last_instr < frame.instr_prev_plus_one:
# We jumped backwards in the same line.
executioncontext._trace(frame, 'line', self.space.w_None)
else:
@@ -557,5 +557,5 @@
frame.f_lineno = line
executioncontext._trace(frame, 'line', self.space.w_None)
- frame.instr_prev = frame.last_instr
+ frame.instr_prev_plus_one = frame.last_instr + 1
self.space.frame_trace_action.fire() # continue tracing
diff --git a/pypy/translator/backendopt/test/test_merge_if_blocks.py b/pypy/translator/backendopt/test/test_merge_if_blocks.py
--- a/pypy/translator/backendopt/test/test_merge_if_blocks.py
+++ b/pypy/translator/backendopt/test/test_merge_if_blocks.py
@@ -2,7 +2,7 @@
from pypy.translator.backendopt.merge_if_blocks import merge_if_blocks
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof as tgraphof
-from pypy.objspace.flow.model import flatten, Block
+from pypy.objspace.flow.model import Block
from pypy.translator.backendopt.removenoops import remove_same_as
from pypy.rpython.llinterp import LLInterpreter
from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, r_int
diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class ImmutableFieldsTests:
diff --git a/pypy/translator/test/test_simplify.py b/pypy/translator/test/test_simplify.py
--- a/pypy/translator/test/test_simplify.py
+++ b/pypy/translator/test/test_simplify.py
@@ -3,7 +3,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.simplify import (get_graph, transform_dead_op_vars,
desugar_isinstance)
-from pypy.objspace.flow.model import traverse, Block, Constant, summary
+from pypy.objspace.flow.model import Block, Constant, summary
from pypy import conftest
def translate(func, argtypes, backend_optimize=True):
@@ -156,36 +156,6 @@
assert graph.startblock.operations[-1].opname == 'direct_call'
-def test_remove_pointless_keepalive():
- from pypy.rlib import objectmodel
- class C:
- y = None
- z1 = None
- z2 = None
-
- def g():
- return C()
-
- def f(i):
- c = g()
- c.y
- if i:
- n = c.z1
- else:
- n = c.z2
- objectmodel.keepalive_until_here(c, n)
-
- graph, t = translate(f, [bool])
-
- #t.view()
-
- for block in graph.iterblocks():
- for op in block.operations:
- assert op.opname != 'getfield'
- if op.opname == 'keepalive':
- assert op.args[0] in graph.getargs()
-
-
def test_remove_identical_variables():
def g(code):
pc = 0
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -191,6 +191,10 @@
f = _io.BufferedReader(raw)
assert repr(f) == '<_io.BufferedReader name=%r>' % (self.tmpfile,)
+class AppTestBufferedReaderWithThreads(AppTestBufferedReader):
+ spaceconfig = dict(usemodules=['_io', 'thread'])
+
+
class AppTestBufferedWriter:
def setup_class(cls):
cls.space = gettestobjspace(usemodules=['_io'])
diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py
--- a/pypy/tool/jitlogparser/parser.py
+++ b/pypy/tool/jitlogparser/parser.py
@@ -107,7 +107,8 @@
self.bytecode_no = int(bytecode_no)
self.operations = operations
self.storage = storage
- self.code = storage.disassemble_code(self.filename, self.startlineno)
+ self.code = storage.disassemble_code(self.filename, self.startlineno,
+ self.name)
def repr(self):
if self.filename is None:
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -641,6 +641,8 @@
except TypeError:
s = None # unhashable T, e.g. a Ptr(GcForwardReference())
if s is None:
+ if isinstance(T, lltype.Typedef):
+ return lltype_to_annotation(T.OF)
if isinstance(T, lltype.Number):
return SomeInteger(knowntype=T._type)
if isinstance(T, (ootype.Instance, ootype.BuiltinType)):
diff --git a/lib_pypy/pypy_test/test_os_wait.py b/lib_pypy/pypy_test/test_os_wait.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/pypy_test/test_os_wait.py
@@ -0,0 +1,44 @@
+# Generates the resource cache
+from __future__ import absolute_import
+from lib_pypy.ctypes_config_cache import rebuild
+rebuild.rebuild_one('resource.ctc.py')
+
+import os
+
+from lib_pypy._pypy_wait import wait3, wait4
+
+if hasattr(os, 'wait3'):
+ def test_os_wait3():
+ exit_status = 0x33
+
+ if not hasattr(os, "fork"):
+ skip("Need fork() to test wait3()")
+
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait3(0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
+
+if hasattr(os, 'wait4'):
+ def test_os_wait4():
+ exit_status = 0x33
+
+ if not hasattr(os, "fork"):
+ skip("Need fork() to test wait4()")
+
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait4(child, 0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py
--- a/pypy/jit/metainterp/test/test_jitprof.py
+++ b/pypy/jit/metainterp/test/test_jitprof.py
@@ -1,7 +1,7 @@
from pypy.jit.metainterp.warmspot import ll_meta_interp
from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.jit.metainterp import pyjitpl
from pypy.jit.metainterp.jitprof import *
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,5 @@
import math
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class FloatTests:
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -382,7 +382,7 @@
send_bridge_to_backend(metainterp.staticdata, self, inputargs,
new_loop.operations, new_loop.token)
- def copy_all_attrbutes_into(self, res):
+ def copy_all_attributes_into(self, res):
# XXX a bit ugly to have to list them all here
res.rd_snapshot = self.rd_snapshot
res.rd_frame_info_list = self.rd_frame_info_list
@@ -393,13 +393,13 @@
def _clone_if_mutable(self):
res = ResumeGuardDescr()
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
class ResumeAtPositionDescr(ResumeGuardDescr):
def _clone_if_mutable(self):
res = ResumeAtPositionDescr()
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
class ResumeGuardForcedDescr(ResumeGuardDescr):
@@ -473,7 +473,7 @@
def _clone_if_mutable(self):
res = ResumeGuardForcedDescr(self.metainterp_sd,
self.jitdriver_sd)
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -42,3 +42,13 @@
assert arr[1:].tolist() == [2,3,4]
assert arr[:2].tolist() == [1,2]
assert arr[1:3].tolist() == [2,3]
+
+ def test_buffer(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3,4])
+ # XXX big-endian
+ assert str(buffer(arr)) == ('\x01\0\0\0'
+ '\x02\0\0\0'
+ '\x03\0\0\0'
+ '\x04\0\0\0')
+
diff --git a/pypy/rpython/lltypesystem/module/test/test_ll_math.py b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
--- a/pypy/rpython/lltypesystem/module/test/test_ll_math.py
+++ b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
@@ -3,6 +3,7 @@
from pypy.rpython.lltypesystem.module import ll_math
from pypy.module.math.test.test_direct import MathTests, get_tester
+from pypy.translator.c.test.test_genc import compile
class TestMath(MathTests):
@@ -11,6 +12,7 @@
nan = inf / inf
assert not ll_math.ll_math_isinf(0)
assert ll_math.ll_math_isinf(inf)
+ assert ll_math.ll_math_isinf(-inf)
assert not ll_math.ll_math_isinf(nan)
def test_isnan(self):
@@ -20,6 +22,13 @@
assert ll_math.ll_math_isnan(nan)
assert not ll_math.ll_math_isnan(inf)
+ def test_compiled_isinf(self):
+ def f(x):
+ return ll_math.ll_math_isinf(1. / x)
+ f = compile(f, [float], backendopt=False)
+ assert f(5.5e-309)
+
+
def make_test_case((fnname, args, expected), dict):
#
def test_func(self):
diff --git a/pypy/translator/c/src/ll_math.h b/pypy/translator/c/src/ll_math.h
--- a/pypy/translator/c/src/ll_math.h
+++ b/pypy/translator/c/src/ll_math.h
@@ -1,9 +1,6 @@
/* Definitions of some C99 math library functions, for those platforms
that don't implement these functions already. */
-int _pypy_math_isinf(double x);
-int _pypy_math_isnan(double x);
-
double _pypy_math_acosh(double x);
double _pypy_math_asinh(double x);
double _pypy_math_atanh(double x);
diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py
--- a/pypy/rpython/ootypesystem/rdict.py
+++ b/pypy/rpython/ootypesystem/rdict.py
@@ -153,6 +153,13 @@
hop.exception_cannot_occur()
return self.send_message(hop, 'll_clear')
+ def rtype_method_popitem(self, hop):
+ v_dict, = hop.inputargs(self)
+ r_tuple = hop.r_result
+ cTUPLE = hop.inputconst(ootype.Void, r_tuple.lowleveltype)
+ hop.exception_is_here()
+ return hop.gendirectcall(ll_popitem, cTUPLE, v_dict)
+
def __get_func(self, interp, r_func, fn, TYPE):
if isinstance(r_func, MethodOfFrozenPBCRepr):
obj = r_func.r_im_self.convert_const(fn.im_self)
@@ -353,6 +360,16 @@
ll_dict_values = _make_ll_keys_values_items('values')
ll_dict_items = _make_ll_keys_values_items('items')
+def ll_popitem(ELEM, d):
+ it = d.ll_get_items_iterator()
+ if it.ll_go_next():
+ res = ootype.new(ELEM)
+ key = res.item0 = it.ll_current_key()
+ res.item1 = it.ll_current_value()
+ d.ll_remove(key)
+ return res
+ raise KeyError
+
# ____________________________________________________________
#
# Iteration.
diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py
--- a/pypy/translator/cli/opcodes.py
+++ b/pypy/translator/cli/opcodes.py
@@ -71,6 +71,8 @@
'hint': [PushArg(0), StoreResult],
'direct_call': [Call],
'indirect_call': [IndirectCall],
+ 'int_between': [PushAllArgs, 'call bool [pypylib]pypy.runtime.Utils::IntBetween(int32, int32, int32)'],
+
'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF],
'gc__collect': 'call void class [mscorlib]System.GC::Collect()',
@@ -147,7 +149,10 @@
'cast_float_to_uint': 'conv.u4',
'cast_longlong_to_float': 'conv.r8',
'cast_float_to_longlong': 'conv.i8',
+ 'cast_ulonglong_to_float': 'conv.r8',
+ 'cast_float_to_ulonglong': 'conv.u8',
'cast_primitive': [PushAllArgs, CastPrimitive],
+ 'force_cast': [PushAllArgs, CastPrimitive],
'truncate_longlong_to_int': 'conv.i4',
}
@@ -266,6 +271,8 @@
'ullong_ge': _not('clt.un'),
'ullong_lshift': [PushAllArgs, 'conv.u4', 'shl'],
'ullong_rshift': [PushAllArgs, 'conv.i4', 'shr'],
+ 'ullong_and': 'and',
+ 'ullong_or': 'or',
'oois': 'ceq',
'ooisnot': _not('ceq'),
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -201,6 +201,23 @@
assert cmpr == 3
assert cmpr != 42
+ def test_richcompare(self):
+ module = self.import_module("comparisons")
+ cmpr = module.CmpType()
+
+ # should not crash
+ cmpr < 4
+ cmpr <= 4
+ cmpr > 4
+ cmpr >= 4
+
+ assert cmpr.__le__(4) is NotImplemented
+
+ def test_tpcompare(self):
+ module = self.import_module("comparisons")
+ cmpr = module.OldCmpType()
+ assert cmpr < cmpr
+
def test_hash(self):
module = self.import_module("comparisons")
cmpr = module.CmpType()
diff --git a/pypy/translator/jvm/metavm.py b/pypy/translator/jvm/metavm.py
--- a/pypy/translator/jvm/metavm.py
+++ b/pypy/translator/jvm/metavm.py
@@ -1,4 +1,5 @@
from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.lltypesystem import rffi
from pypy.translator.oosupport.metavm import MicroInstruction
from pypy.translator.jvm.typesystem import JvmScalarType, JvmClassType
import pypy.translator.jvm.typesystem as jvm
@@ -94,14 +95,20 @@
(ootype.SignedLongLong, ootype.Signed): jvm.L2I,
(ootype.UnsignedLongLong, ootype.Unsigned): jvm.L2I,
(ootype.UnsignedLongLong, ootype.Signed): jvm.L2I,
+ (ootype.Signed, rffi.SHORT): jvm.I2S,
+ (ootype.Unsigned, ootype.SignedLongLong): jvm.PYPYUINTTOLONG,
(ootype.UnsignedLongLong, ootype.SignedLongLong): None,
(ootype.SignedLongLong, ootype.UnsignedLongLong): None,
+ (ootype.Signed, ootype.Unsigned): None,
+ (ootype.Unsigned, ootype.Signed): None,
}
class _CastPrimitive(MicroInstruction):
def render(self, generator, op):
FROM = op.args[0].concretetype
TO = op.result.concretetype
+ if TO == FROM:
+ return
opcode = CASTS[(FROM, TO)]
if opcode:
generator.emit(opcode)
diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -56,13 +56,10 @@
"""A frame is an environment supporting the execution of a code object.
Abstract base class."""
- def __init__(self, space, w_globals=None, numlocals=-1):
+ def __init__(self, space, w_globals=None):
self.space = space
self.w_globals = w_globals # wrapped dict of globals
self.w_locals = None # wrapped dict of locals
- if numlocals < 0: # compute the minimal size based on arguments
- numlocals = len(self.getcode().getvarnames())
- self.numlocals = numlocals
def run(self):
"Abstract method to override. Runs the frame"
@@ -96,6 +93,10 @@
where the order is according to self.getcode().signature()."""
raise TypeError, "abstract"
+ def getfastscopelength(self):
+ "Abstract. Get the expected number of locals."
+ raise TypeError, "abstract"
+
def fast2locals(self):
# Copy values from self.fastlocals_w to self.w_locals
if self.w_locals is None:
@@ -113,10 +114,11 @@
# Copy values from self.w_locals to self.fastlocals_w
assert self.w_locals is not None
varnames = self.getcode().getvarnames()
+ numlocals = self.getfastscopelength()
- new_fastlocals_w = [None]*self.numlocals
-
- for i in range(min(len(varnames), self.numlocals)):
+ new_fastlocals_w = [None] * numlocals
+
+ for i in range(min(len(varnames), numlocals)):
w_name = self.space.wrap(varnames[i])
try:
w_value = self.space.getitem(self.w_locals, w_name)
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -5,6 +5,8 @@
syntax: regexp
^testresult$
^site-packages$
+^site-packages/.*$
+^site-packages/.*$
^bin$
^pypy/bin/pypy-c
^pypy/module/cpyext/src/.+\.o$
@@ -37,8 +39,6 @@
^pypy/translator/goal/.+\.dll$
^pypy/translator/goal/target.+-c$
^pypy/_cache$
-^site-packages/.+\.egg$
-^site-packages/.+\.pth$
^pypy/doc/statistic/.+\.html$
^pypy/doc/statistic/.+\.eps$
^pypy/doc/statistic/.+\.pdf$
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
@@ -8,6 +8,8 @@
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.error import TyperError
+from pypy.rpython.ootypesystem import ootype
+
class SomeVRef(annmodel.SomeObject):
@@ -24,7 +26,10 @@
return self.s_instance
def rtyper_makerepr(self, rtyper):
- return vrefrepr
+ if rtyper.type_system.name == 'lltypesystem':
+ return vrefrepr
+ elif rtyper.type_system.name == 'ootypesystem':
+ return oovrefrepr
def rtyper_makekey(self):
return self.__class__,
@@ -54,4 +59,20 @@
" prebuilt virtual_ref")
return lltype.nullptr(OBJECTPTR.TO)
+from pypy.rpython.ootypesystem.rclass import OBJECT
+
+class OOVRefRepr(VRefRepr):
+ lowleveltype = OBJECT
+ def rtype_simple_call(self, hop):
+ [v] = hop.inputargs(self)
+ v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT)
+ return hop.genop('oodowncast', [v], resulttype = hop.r_result)
+
+ def convert_const(self, value):
+ if value() is not None:
+ raise TypeError("only supports virtual_ref_None as a"
+ " prebuilt virtual_ref")
+ return ootype.ROOT._null
+
vrefrepr = VRefRepr()
+oovrefrepr = OOVRefRepr()
diff --git a/pypy/translator/cli/test/test_class.py b/pypy/translator/cli/test/test_class.py
--- a/pypy/translator/cli/test/test_class.py
+++ b/pypy/translator/cli/test/test_class.py
@@ -1,11 +1,8 @@
import py
from pypy.translator.cli.test.runtest import CliTest
-from pypy.translator.oosupport.test_template.class_ import BaseTestClass, BaseTestSpecialcase
+from pypy.translator.oosupport.test_template.class_ import BaseTestClass
# ====> ../../oosupport/test_template/class_.py
class TestCliClass(CliTest, BaseTestClass):
pass
-
-class TestCliSpecialCase(CliTest, BaseTestSpecialcase):
- pass
diff --git a/pypy/jit/metainterp/test/test_exception.py b/pypy/jit/metainterp/test/test_exception.py
--- a/pypy/jit/metainterp/test/test_exception.py
+++ b/pypy/jit/metainterp/test/test_exception.py
@@ -1,5 +1,5 @@
import py, sys
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver, dont_look_inside
from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
from pypy.jit.codewriter.policy import StopAtXPolicy
diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py
--- a/pypy/jit/backend/x86/arch.py
+++ b/pypy/jit/backend/x86/arch.py
@@ -1,17 +1,29 @@
# Constants that depend on whether we are on 32-bit or 64-bit
+# The frame size gives the standard fixed part at the start of
+# every assembler frame: the saved value of some registers,
+# one word for the force_index, and some extra space used only
+# during a malloc that needs to go via its slow path.
+
import sys
if sys.maxint == (2**31 - 1):
WORD = 4
- # ebp + ebx + esi + edi + force_index = 5 words
- FRAME_FIXED_SIZE = 5
+ # ebp + ebx + esi + edi + 4 extra words + force_index = 9 words
+ FRAME_FIXED_SIZE = 9
+ FORCE_INDEX_OFS = -8*WORD
+ MY_COPY_OF_REGS = -7*WORD
IS_X86_32 = True
IS_X86_64 = False
else:
WORD = 8
- # rbp + rbx + r12 + r13 + r14 + r15 + force_index = 7 words
- FRAME_FIXED_SIZE = 7
+ # rbp + rbx + r12 + r13 + r14 + r15 + 11 extra words + force_index = 18
+ FRAME_FIXED_SIZE = 18
+ FORCE_INDEX_OFS = -17*WORD
+ MY_COPY_OF_REGS = -16*WORD
IS_X86_32 = False
IS_X86_64 = True
-FORCE_INDEX_OFS = -(FRAME_FIXED_SIZE-1)*WORD
+# The extra space has room for almost all registers, apart from eax and edx
+# which are used in the malloc itself. They are:
+# ecx, ebx, esi, edi [32 and 64 bits]
+# r8, r9, r10, r12, r13, r14, r15 [64 bits only]
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -343,7 +343,11 @@
}
def final_check_config(config):
- pass
+ # XXX: this should be a real config option, but it is hard to refactor it;
+ # instead, we "just" patch it from here
+ from pypy.rlib import rfloat
+ if config.translation.type_system == 'ootype':
+ rfloat.USE_SHORT_FLOAT_REPR = False
def set_opt_level(config, level):
"""Apply optimization suggestions on the 'config'.
diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -486,6 +486,7 @@
class W_IMap(Wrappable):
_error_name = "imap"
+ _immutable_fields_ = ["w_fun", "iterators_w"]
def __init__(self, space, w_fun, args_w):
self.space = space
diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -4,6 +4,8 @@
from pypy.rpython.tool import rffi_platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rlib import objectmodel
+from pypy.rpython.extfunc import register_external
+from pypy.annotation.model import SomeString
USE_SHORT_FLOAT_REPR = True # XXX make it a translation option?
@@ -24,16 +26,28 @@
globals().update(rffi_platform.configure(CConfig))
def rstring_to_float(s):
+ return rstring_to_float_impl(s)
+
+def rstring_to_float_impl(s):
if USE_SHORT_FLOAT_REPR:
from pypy.rlib.rdtoa import strtod
return strtod(s)
-
sign, before_point, after_point, exponent = break_up_float(s)
-
if not before_point and not after_point:
raise ValueError
+ return parts_to_float(sign, before_point, after_point, exponent)
- return parts_to_float(sign, before_point, after_point, exponent)
+def oo_rstring_to_float(s):
+ from pypy.rpython.annlowlevel import oostr
+ from pypy.rpython.ootypesystem import ootype
+ lls = oostr(s)
+ return ootype.ooparse_float(lls)
+
+register_external(rstring_to_float, [SomeString(can_be_None=False)], float,
+ llimpl=rstring_to_float_impl,
+ ooimpl=oo_rstring_to_float,
+ sandboxsafe=True)
+
# float as string -> sign, beforept, afterpt, exponent
def break_up_float(s):
@@ -153,128 +167,132 @@
result = formatd(value, tp, precision, flags)
return result, special
-if USE_SHORT_FLOAT_REPR:
- def round_double(value, ndigits):
- # The basic idea is very simple: convert and round the double to
- # a decimal string using _Py_dg_dtoa, then convert that decimal
- # string back to a double with _Py_dg_strtod. There's one minor
- # difficulty: Python 2.x expects round to do
- # round-half-away-from-zero, while _Py_dg_dtoa does
- # round-half-to-even. So we need some way to detect and correct
- # the halfway cases.
+def round_double(value, ndigits):
+ if USE_SHORT_FLOAT_REPR:
+ return round_double_short_repr(value, ndigits)
+ else:
+ return round_double_fallback_repr(value, ndigits)
- # a halfway value has the form k * 0.5 * 10**-ndigits for some
- # odd integer k. Or in other words, a rational number x is
- # exactly halfway between two multiples of 10**-ndigits if its
- # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
- # least -ndigits. For ndigits >= 0 the latter condition is
- # automatically satisfied for a binary float x, since any such
- # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
- # needs to be an integral multiple of 5**-ndigits; we can check
- # this using fmod. For -22 > ndigits, there are no halfway
- # cases: 5**23 takes 54 bits to represent exactly, so any odd
- # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
- # precision to represent exactly.
+def round_double_short_repr(value, ndigits):
+ # The basic idea is very simple: convert and round the double to
+ # a decimal string using _Py_dg_dtoa, then convert that decimal
+ # string back to a double with _Py_dg_strtod. There's one minor
+ # difficulty: Python 2.x expects round to do
+ # round-half-away-from-zero, while _Py_dg_dtoa does
+ # round-half-to-even. So we need some way to detect and correct
+ # the halfway cases.
- sign = copysign(1.0, value)
- value = abs(value)
+ # a halfway value has the form k * 0.5 * 10**-ndigits for some
+ # odd integer k. Or in other words, a rational number x is
+ # exactly halfway between two multiples of 10**-ndigits if its
+ # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
+ # least -ndigits. For ndigits >= 0 the latter condition is
+ # automatically satisfied for a binary float x, since any such
+ # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
+ # needs to be an integral multiple of 5**-ndigits; we can check
+ # this using fmod. For -22 > ndigits, there are no halfway
+ # cases: 5**23 takes 54 bits to represent exactly, so any odd
+ # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
+ # precision to represent exactly.
- # find 2-valuation value
- m, expo = math.frexp(value)
- while m != math.floor(m):
- m *= 2.0
- expo -= 1
+ sign = copysign(1.0, value)
+ value = abs(value)
- # determine whether this is a halfway case.
- halfway_case = 0
- if expo == -ndigits - 1:
- if ndigits >= 0:
+ # find 2-valuation value
+ m, expo = math.frexp(value)
+ while m != math.floor(m):
+ m *= 2.0
+ expo -= 1
+
+ # determine whether this is a halfway case.
+ halfway_case = 0
+ if expo == -ndigits - 1:
+ if ndigits >= 0:
+ halfway_case = 1
+ elif ndigits >= -22:
+ # 22 is the largest k such that 5**k is exactly
+ # representable as a double
+ five_pow = 1.0
+ for i in range(-ndigits):
+ five_pow *= 5.0
+ if math.fmod(value, five_pow) == 0.0:
halfway_case = 1
- elif ndigits >= -22:
- # 22 is the largest k such that 5**k is exactly
- # representable as a double
- five_pow = 1.0
- for i in range(-ndigits):
- five_pow *= 5.0
- if math.fmod(value, five_pow) == 0.0:
- halfway_case = 1
- # round to a decimal string; use an extra place for halfway case
- strvalue = formatd(value, 'f', ndigits + halfway_case)
+ # round to a decimal string; use an extra place for halfway case
+ strvalue = formatd(value, 'f', ndigits + halfway_case)
- if halfway_case:
- buf = [c for c in strvalue]
- if ndigits >= 0:
- endpos = len(buf) - 1
- else:
- endpos = len(buf) + ndigits
- # Sanity checks: there should be exactly ndigits+1 places
- # following the decimal point, and the last digit in the
- # buffer should be a '5'
- if not objectmodel.we_are_translated():
- assert buf[endpos] == '5'
- if '.' in buf:
- assert endpos == len(buf) - 1
- assert buf.index('.') == len(buf) - ndigits - 2
+ if halfway_case:
+ buf = [c for c in strvalue]
+ if ndigits >= 0:
+ endpos = len(buf) - 1
+ else:
+ endpos = len(buf) + ndigits
+ # Sanity checks: there should be exactly ndigits+1 places
+ # following the decimal point, and the last digit in the
+ # buffer should be a '5'
+ if not objectmodel.we_are_translated():
+ assert buf[endpos] == '5'
+ if '.' in buf:
+ assert endpos == len(buf) - 1
+ assert buf.index('.') == len(buf) - ndigits - 2
- # increment and shift right at the same time
- i = endpos - 1
- carry = 1
- while i >= 0:
+ # increment and shift right at the same time
+ i = endpos - 1
+ carry = 1
+ while i >= 0:
+ digit = ord(buf[i])
+ if digit == ord('.'):
+ buf[i+1] = chr(digit)
+ i -= 1
digit = ord(buf[i])
- if digit == ord('.'):
- buf[i+1] = chr(digit)
- i -= 1
- digit = ord(buf[i])
- carry += digit - ord('0')
- buf[i+1] = chr(carry % 10 + ord('0'))
- carry /= 10
- i -= 1
- buf[0] = chr(carry + ord('0'))
- if ndigits < 0:
- buf.append('0')
+ carry += digit - ord('0')
+ buf[i+1] = chr(carry % 10 + ord('0'))
+ carry /= 10
+ i -= 1
+ buf[0] = chr(carry + ord('0'))
+ if ndigits < 0:
+ buf.append('0')
- strvalue = ''.join(buf)
+ strvalue = ''.join(buf)
- return sign * rstring_to_float(strvalue)
+ return sign * rstring_to_float(strvalue)
-else:
- # fallback version, to be used when correctly rounded
- # binary<->decimal conversions aren't available
- def round_double(value, ndigits):
- if ndigits >= 0:
- if ndigits > 22:
- # pow1 and pow2 are each safe from overflow, but
- # pow1*pow2 ~= pow(10.0, ndigits) might overflow
- pow1 = math.pow(10.0, ndigits - 22)
- pow2 = 1e22
- else:
- pow1 = math.pow(10.0, ndigits)
- pow2 = 1.0
+# fallback version, to be used when correctly rounded
+# binary<->decimal conversions aren't available
+def round_double_fallback_repr(value, ndigits):
+ if ndigits >= 0:
+ if ndigits > 22:
+ # pow1 and pow2 are each safe from overflow, but
+ # pow1*pow2 ~= pow(10.0, ndigits) might overflow
+ pow1 = math.pow(10.0, ndigits - 22)
+ pow2 = 1e22
+ else:
+ pow1 = math.pow(10.0, ndigits)
+ pow2 = 1.0
- y = (value * pow1) * pow2
- # if y overflows, then rounded value is exactly x
- if isinf(y):
- return value
+ y = (value * pow1) * pow2
+ # if y overflows, then rounded value is exactly x
+ if isinf(y):
+ return value
- else:
- pow1 = math.pow(10.0, -ndigits);
- pow2 = 1.0 # unused; for translation
- y = value / pow1
+ else:
+ pow1 = math.pow(10.0, -ndigits);
+ pow2 = 1.0 # unused; for translation
+ y = value / pow1
- if y >= 0.0:
- z = math.floor(y + 0.5)
- else:
- z = math.ceil(y - 0.5)
- if math.fabs(y-z) == 1.0: # obscure case, see the test
- z = y
+ if y >= 0.0:
+ z = math.floor(y + 0.5)
+ else:
+ z = math.ceil(y - 0.5)
+ if math.fabs(y-z) == 1.0: # obscure case, see the test
+ z = y
- if ndigits >= 0:
- z = (z / pow2) / pow1
- else:
- z *= pow1
- return z
+ if ndigits >= 0:
+ z = (z / pow2) / pow1
+ else:
+ z *= pow1
+ return z
INFINITY = 1e200 * 1e200
NAN = INFINITY / INFINITY
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -133,6 +133,8 @@
class AppTest_DictObject:
+ def setup_class(cls):
+ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names)
def test_equality(self):
d = {1:2}
@@ -252,10 +254,17 @@
k = Key()
d = {}
d.setdefault(k, [])
- assert k.calls == 1
+ if self.on_pypy:
+ assert k.calls == 1
d.setdefault(k, 1)
- assert k.calls == 2
+ if self.on_pypy:
+ assert k.calls == 2
+
+ k = Key()
+ d.setdefault(k, 42)
+ if self.on_pypy:
+ assert k.calls == 1
def test_update(self):
d = {1:2, 3:4}
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_ajit.py
copy from pypy/jit/metainterp/test/test_basic.py
copy to pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -4,269 +4,17 @@
from pypy.rlib.jit import loop_invariant
from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
from pypy.rlib.jit import unroll_safe, current_trace_length
-from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp import pyjitpl, history
from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.jit.metainterp.warmspot import get_stats
from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
-from pypy.jit.codewriter import longlong
from pypy import conftest
from pypy.rlib.rarithmetic import ovfcheck
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
-
-def _get_jitcodes(testself, CPUClass, func, values, type_system,
- supports_longlong=False, **kwds):
- from pypy.jit.codewriter import support, codewriter
-
- class FakeJitCell:
- __compiled_merge_points = []
- def get_compiled_merge_points(self):
- return self.__compiled_merge_points[:]
- def set_compiled_merge_points(self, lst):
- self.__compiled_merge_points = lst
-
- class FakeWarmRunnerState:
- def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
- pass
-
- def jit_cell_at_key(self, greenkey):
- assert greenkey == []
- return self._cell
- _cell = FakeJitCell()
-
- trace_limit = sys.maxint
- enable_opts = ALL_OPTS_DICT
-
- func._jit_unroll_safe_ = True
- rtyper = support.annotate(func, values, type_system=type_system)
- graphs = rtyper.annotator.translator.graphs
- result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
-
- class FakeJitDriverSD:
- num_green_args = 0
- portal_graph = graphs[0]
- virtualizable_info = None
- greenfield_info = None
- result_type = result_kind
- portal_runner_ptr = "???"
-
- stats = history.Stats()
- cpu = CPUClass(rtyper, stats, None, False)
- cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
- testself.cw = cw
- policy = JitPolicy()
- policy.set_supports_longlong(supports_longlong)
- cw.find_all_graphs(policy)
- #
- testself.warmrunnerstate = FakeWarmRunnerState()
- testself.warmrunnerstate.cpu = cpu
- FakeJitDriverSD.warmstate = testself.warmrunnerstate
- if hasattr(testself, 'finish_setup_for_interp_operations'):
- testself.finish_setup_for_interp_operations()
- #
- cw.make_jitcodes(verbose=True)
-
-def _run_with_blackhole(testself, args):
- from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
- cw = testself.cw
- blackholeinterpbuilder = BlackholeInterpBuilder(cw)
- blackholeinterp = blackholeinterpbuilder.acquire_interp()
- count_i = count_r = count_f = 0
- for value in args:
- T = lltype.typeOf(value)
- if T == lltype.Signed:
- blackholeinterp.setarg_i(count_i, value)
- count_i += 1
- elif T == llmemory.GCREF:
- blackholeinterp.setarg_r(count_r, value)
- count_r += 1
- elif T == lltype.Float:
- value = longlong.getfloatstorage(value)
- blackholeinterp.setarg_f(count_f, value)
- count_f += 1
- else:
- raise TypeError(T)
- [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
- blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
- blackholeinterp.run()
- return blackholeinterp._final_result_anytype()
-
-def _run_with_pyjitpl(testself, args):
-
- class DoneWithThisFrame(Exception):
- pass
-
- class DoneWithThisFrameRef(DoneWithThisFrame):
- def __init__(self, cpu, *args):
- DoneWithThisFrame.__init__(self, *args)
-
- cw = testself.cw
- opt = history.Options(listops=True)
- metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
- metainterp_sd.finish_setup(cw)
- [jitdriver_sd] = metainterp_sd.jitdrivers_sd
- metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
- metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
- metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
- metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
- testself.metainterp = metainterp
- try:
- metainterp.compile_and_run_once(jitdriver_sd, *args)
- except DoneWithThisFrame, e:
- #if conftest.option.view:
- # metainterp.stats.view()
- return e.args[0]
- else:
- raise Exception("FAILED")
-
-def _run_with_machine_code(testself, args):
- metainterp = testself.metainterp
- num_green_args = metainterp.jitdriver_sd.num_green_args
- loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
- if len(loop_tokens) != 1:
- return NotImplemented
- # a loop was successfully created by _run_with_pyjitpl(); call it
- cpu = metainterp.cpu
- for i in range(len(args) - num_green_args):
- x = args[num_green_args + i]
- typecode = history.getkind(lltype.typeOf(x))
- set_future_value(cpu, i, x, typecode)
- faildescr = cpu.execute_token(loop_tokens[0])
- assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
- if metainterp.jitdriver_sd.result_type == history.INT:
- return cpu.get_latest_value_int(0)
- elif metainterp.jitdriver_sd.result_type == history.REF:
- return cpu.get_latest_value_ref(0)
- elif metainterp.jitdriver_sd.result_type == history.FLOAT:
- return cpu.get_latest_value_float(0)
- else:
- return None
-
-
-class JitMixin:
- basic = True
- def check_loops(self, expected=None, everywhere=False, **check):
- get_stats().check_loops(expected=expected, everywhere=everywhere,
- **check)
- def check_loop_count(self, count):
- """NB. This is a hack; use check_tree_loop_count() or
- check_enter_count() for the real thing.
- This counts as 1 every bridge in addition to every loop; and it does
- not count at all the entry bridges from interpreter, although they
- are TreeLoops as well."""
- assert get_stats().compiled_count == count
- def check_tree_loop_count(self, count):
- assert len(get_stats().loops) == count
- def check_loop_count_at_most(self, count):
- assert get_stats().compiled_count <= count
- def check_enter_count(self, count):
- assert get_stats().enter_count == count
- def check_enter_count_at_most(self, count):
- assert get_stats().enter_count <= count
- def check_jumps(self, maxcount):
- assert get_stats().exec_jumps <= maxcount
- def check_aborted_count(self, count):
- assert get_stats().aborted_count == count
- def check_aborted_count_at_least(self, count):
- assert get_stats().aborted_count >= count
-
- def meta_interp(self, *args, **kwds):
- kwds['CPUClass'] = self.CPUClass
- kwds['type_system'] = self.type_system
- if "backendopt" not in kwds:
- kwds["backendopt"] = False
- return ll_meta_interp(*args, **kwds)
-
- def interp_operations(self, f, args, **kwds):
- # get the JitCodes for the function f
- _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
- # try to run it with blackhole.py
- result1 = _run_with_blackhole(self, args)
- # try to run it with pyjitpl.py
- result2 = _run_with_pyjitpl(self, args)
- assert result1 == result2
- # try to run it by running the code compiled just before
- result3 = _run_with_machine_code(self, args)
- assert result1 == result3 or result3 == NotImplemented
- #
- if (longlong.supports_longlong and
- isinstance(result1, longlong.r_float_storage)):
- result1 = longlong.getrealfloat(result1)
- return result1
-
- def check_history(self, expected=None, **isns):
- # this can be used after calling meta_interp
- get_stats().check_history(expected, **isns)
-
- def check_operations_history(self, expected=None, **isns):
- # this can be used after interp_operations
- if expected is not None:
- expected = dict(expected)
- expected['jump'] = 1
- self.metainterp.staticdata.stats.check_history(expected, **isns)
-
-
-class LLJitMixin(JitMixin):
- type_system = 'lltype'
- CPUClass = runner.LLtypeCPU
-
- @staticmethod
- def Ptr(T):
- return lltype.Ptr(T)
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- S = lltype.GcStruct(name, *fields, **kwds)
- return S
-
- malloc = staticmethod(lltype.malloc)
- nullptr = staticmethod(lltype.nullptr)
-
- @staticmethod
- def malloc_immortal(T):
- return lltype.malloc(T, immortal=True)
-
- def _get_NODE(self):
- NODE = lltype.GcForwardReference()
- NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
- ('next', lltype.Ptr(NODE))))
- return NODE
-
-class OOJitMixin(JitMixin):
- type_system = 'ootype'
- #CPUClass = runner.OOtypeCPU
-
- def setup_class(cls):
- py.test.skip("ootype tests skipped for now")
-
- @staticmethod
- def Ptr(T):
- return T
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- if 'hints' in kwds:
- kwds['_hints'] = kwds['hints']
- del kwds['hints']
- I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
- return I
-
- malloc = staticmethod(ootype.new)
- nullptr = staticmethod(ootype.null)
-
- @staticmethod
- def malloc_immortal(T):
- return ootype.new(T)
-
- def _get_NODE(self):
- NODE = ootype.Instance('NODE', ootype.ROOT, {})
- NODE._add_fields({'value': ootype.Signed,
- 'next': NODE})
- return NODE
-
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class BasicTests:
diff --git a/pypy/translator/backendopt/test/test_mallocprediction.py b/pypy/translator/backendopt/test/test_mallocprediction.py
--- a/pypy/translator/backendopt/test/test_mallocprediction.py
+++ b/pypy/translator/backendopt/test/test_mallocprediction.py
@@ -4,7 +4,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.llinterp import LLInterpreter
-from pypy.objspace.flow.model import checkgraph, flatten, Block
+from pypy.objspace.flow.model import checkgraph, Block
from pypy.conftest import option
import sys
diff --git a/pypy/translator/backendopt/merge_if_blocks.py b/pypy/translator/backendopt/merge_if_blocks.py
--- a/pypy/translator/backendopt/merge_if_blocks.py
+++ b/pypy/translator/backendopt/merge_if_blocks.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import Block, Constant, Variable, flatten
+from pypy.objspace.flow.model import Block, Constant, Variable
from pypy.objspace.flow.model import checkgraph, mkentrymap
from pypy.translator.backendopt.support import log
@@ -75,14 +75,19 @@
# False link
checkvar = [var for var in current.operations[-1].args
if isinstance(var, Variable)][0]
+ resvar = current.operations[-1].result
case = [var for var in current.operations[-1].args
if isinstance(var, Constant)][0]
- chain.append((current, case))
checkvars.append(checkvar)
falseexit = current.exits[0]
assert not falseexit.exitcase
trueexit = current.exits[1]
targetblock = falseexit.target
+ # if the result of the check is also passed through the link, we
+ # cannot construct the chain
+ if resvar in falseexit.args or resvar in trueexit.args:
+ break
+ chain.append((current, case))
if len(entrymap[targetblock]) != 1:
break
if checkvar not in falseexit.args:
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -6,7 +6,7 @@
from pypy.jit.codewriter import heaptracker
from pypy.rlib.jit import JitDriver, hint, dont_look_inside
from pypy.rlib.rarithmetic import intmask
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rpython.rclass import FieldListAccessor
from pypy.jit.metainterp.warmspot import get_stats, get_translator
from pypy.jit.metainterp import history
diff --git a/pypy/module/__builtin__/app_inspect.py b/pypy/module/__builtin__/app_inspect.py
--- a/pypy/module/__builtin__/app_inspect.py
+++ b/pypy/module/__builtin__/app_inspect.py
@@ -76,8 +76,8 @@
result.sort()
return result
- elif hasattr(obj, '__dir__'):
- result = obj.__dir__()
+ elif hasattr(type(obj), '__dir__'):
+ result = type(obj).__dir__(obj)
if not isinstance(result, list):
raise TypeError("__dir__() must return a list, not %r" % (
type(result),))
@@ -87,11 +87,14 @@
else: #(regular item)
Dict = {}
try:
- Dict.update(obj.__dict__)
- except AttributeError: pass
+ if isinstance(obj.__dict__, dict):
+ Dict.update(obj.__dict__)
+ except AttributeError:
+ pass
try:
Dict.update(_classdir(obj.__class__))
- except AttributeError: pass
+ except AttributeError:
+ pass
## Comment from object.c:
## /* Merge in __members__ and __methods__ (if any).
@@ -99,10 +102,14 @@
## XXX needed to get at im_self etc of method objects. */
for attr in ['__members__','__methods__']:
try:
- for item in getattr(obj, attr):
+ l = getattr(obj, attr)
+ if not isinstance(l, list):
+ continue
+ for item in l:
if isinstance(item, types.StringTypes):
Dict[item] = None
- except (AttributeError, TypeError): pass
+ except (AttributeError, TypeError):
+ pass
result = Dict.keys()
result.sort()
diff --git a/pypy/rpython/lltypesystem/test/test_rffi.py b/pypy/rpython/lltypesystem/test/test_rffi.py
--- a/pypy/rpython/lltypesystem/test/test_rffi.py
+++ b/pypy/rpython/lltypesystem/test/test_rffi.py
@@ -728,6 +728,7 @@
for ll, ctp in cache.items():
assert sizeof(ll) == ctypes.sizeof(ctp)
+ assert sizeof(lltype.Typedef(ll, 'test')) == sizeof(ll)
assert not size_and_sign(lltype.Signed)[1]
assert not size_and_sign(lltype.Char)[1]
assert not size_and_sign(lltype.UniChar)[1]
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -135,7 +135,7 @@
return type(self) is type(other) # xxx obscure
def clone_if_mutable(self):
res = Storage(self.metainterp_sd, self.original_greenkey)
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
def _sortboxes(boxes):
@@ -2757,7 +2757,7 @@
"""
self.optimize_loop(ops, expected)
- def test_fold_partially_constant_ops(self):
+ def test_fold_partially_constant_add_sub(self):
ops = """
[i0]
i1 = int_sub(i0, 0)
@@ -2791,7 +2791,7 @@
"""
self.optimize_loop(ops, expected)
- def test_fold_partially_constant_ops_ovf(self):
+ def test_fold_partially_constant_add_sub_ovf(self):
ops = """
[i0]
i1 = int_sub_ovf(i0, 0)
@@ -2828,6 +2828,21 @@
"""
self.optimize_loop(ops, expected)
+ def test_fold_partially_constant_shift(self):
+ ops = """
+ [i0]
+ i1 = int_lshift(i0, 0)
+ i2 = int_rshift(i1, 0)
+ i3 = int_eq(i2, i0)
+ guard_true(i3) []
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
# ----------
class TestLLtype(OptimizeOptTest, LLtypeMixin):
@@ -4960,6 +4975,58 @@
p2 = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p2, i1, descr=nextdescr)
"""
+ py.test.skip("no test here")
+
+ def test_immutable_not(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_noimmut_vtable))
+ setfield_gc(p0, 42, descr=noimmut_intval)
+ escape(p0)
+ jump()
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_variable(self):
+ ops = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ setfield_gc(p0, i0, descr=immut_intval)
+ escape(p0)
+ jump(i0)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_incomplete(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ escape(p0)
+ jump()
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_constantfold(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ setfield_gc(p0, 1242, descr=immut_intval)
+ escape(p0)
+ jump()
+ """
+ from pypy.rpython.lltypesystem import lltype, llmemory
+ class IntObj1242(object):
+ _TYPE = llmemory.GCREF.TO
+ def __eq__(self, other):
+ return other.container.intval == 1242
+ self.namespace['intobj1242'] = lltype._ptr(llmemory.GCREF,
+ IntObj1242())
+ expected = """
+ []
+ escape(ConstPtr(intobj1242))
+ jump()
+ """
+ self.optimize_loop(ops, expected)
# ----------
def optimize_strunicode_loop(self, ops, optops, preamble=None):
diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py
--- a/pypy/rpython/test/test_rfloat.py
+++ b/pypy/rpython/test/test_rfloat.py
@@ -156,6 +156,37 @@
return x
self.interpret(fn, [1.0, 2.0, 3.0])
+ def test_copysign(self):
+ import math
+ def fn(x, y):
+ return math.copysign(x, y)
+ assert self.interpret(fn, [42, -1]) == -42
+ assert self.interpret(fn, [42, -0.0]) == -42
+ assert self.interpret(fn, [42, 0.0]) == 42
+
+ def test_rstring_to_float(self):
+ from pypy.rlib.rfloat import rstring_to_float
+ def fn(i):
+ s = ['42.3', '123.4'][i]
+ return rstring_to_float(s)
+ assert self.interpret(fn, [0]) == 42.3
+
+ def test_isnan(self):
+ import math
+ def fn(x):
+ inf = x * x
+ nan = inf / inf
+ return math.isnan(nan)
+ assert self.interpret(fn, [1e200])
+
+ def test_isinf(self):
+ import math
+ def fn(x):
+ inf = x * x
+ return math.isinf(inf)
+ assert self.interpret(fn, [1e200])
+
+
class TestLLtype(BaseTestRfloat, LLRtypeMixin):
def test_hash(self):
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
@@ -514,12 +514,10 @@
break
else:
# all constant arguments: constant-fold away
- argboxes = [self.get_constant_box(op.getarg(i))
- for i in range(op.numargs())]
- resbox = execute_nonspec(self.cpu, None,
- op.getopnum(), argboxes, op.getdescr())
- # FIXME: Don't we need to check for an overflow here?
- self.make_constant(op.result, resbox.constbox())
+ resbox = self.constant_fold(op)
+ # note that INT_xxx_OVF is not done from here, and the
+ # overflows in the INT_xxx operations are ignored
+ self.make_constant(op.result, resbox)
return
# did we do the exact same operation already?
@@ -538,6 +536,13 @@
if nextop:
self.emit_operation(nextop)
+ def constant_fold(self, op):
+ argboxes = [self.get_constant_box(op.getarg(i))
+ for i in range(op.numargs())]
+ resbox = execute_nonspec(self.cpu, None,
+ op.getopnum(), argboxes, op.getdescr())
+ return resbox.constbox()
+
#def optimize_GUARD_NO_OVERFLOW(self, op):
# # otherwise the default optimizer will clear fields, which is unwanted
# # in this case
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -1,6 +1,6 @@
"""Tests for multiple JitDrivers."""
from pypy.rlib.jit import JitDriver, unroll_safe
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.warmspot import get_stats
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_basic.py
+++ /dev/null
@@ -1,2411 +0,0 @@
-import py
-import sys
-from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
-from pypy.rlib.jit import loop_invariant
-from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
-from pypy.rlib.jit import unroll_safe, current_trace_length
-from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.backend.llgraph import runner
-from pypy.jit.metainterp import pyjitpl, history
-from pypy.jit.metainterp.warmstate import set_future_value
-from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
-from pypy.jit.codewriter import longlong
-from pypy import conftest
-from pypy.rlib.rarithmetic import ovfcheck
-from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
-from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.ootypesystem import ootype
-from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
-
-def _get_jitcodes(testself, CPUClass, func, values, type_system,
- supports_longlong=False, **kwds):
- from pypy.jit.codewriter import support, codewriter
-
- class FakeJitCell:
- __compiled_merge_points = []
- def get_compiled_merge_points(self):
- return self.__compiled_merge_points[:]
- def set_compiled_merge_points(self, lst):
- self.__compiled_merge_points = lst
-
- class FakeWarmRunnerState:
- def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
- pass
-
- def jit_cell_at_key(self, greenkey):
- assert greenkey == []
- return self._cell
- _cell = FakeJitCell()
-
- trace_limit = sys.maxint
- enable_opts = ALL_OPTS_DICT
-
- func._jit_unroll_safe_ = True
- rtyper = support.annotate(func, values, type_system=type_system)
- graphs = rtyper.annotator.translator.graphs
- result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
-
- class FakeJitDriverSD:
- num_green_args = 0
- portal_graph = graphs[0]
- virtualizable_info = None
- greenfield_info = None
- result_type = result_kind
- portal_runner_ptr = "???"
-
- stats = history.Stats()
- cpu = CPUClass(rtyper, stats, None, False)
- cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
- testself.cw = cw
- policy = JitPolicy()
- policy.set_supports_longlong(supports_longlong)
- cw.find_all_graphs(policy)
- #
- testself.warmrunnerstate = FakeWarmRunnerState()
- testself.warmrunnerstate.cpu = cpu
- FakeJitDriverSD.warmstate = testself.warmrunnerstate
- if hasattr(testself, 'finish_setup_for_interp_operations'):
- testself.finish_setup_for_interp_operations()
- #
- cw.make_jitcodes(verbose=True)
-
-def _run_with_blackhole(testself, args):
- from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
- cw = testself.cw
- blackholeinterpbuilder = BlackholeInterpBuilder(cw)
- blackholeinterp = blackholeinterpbuilder.acquire_interp()
- count_i = count_r = count_f = 0
- for value in args:
- T = lltype.typeOf(value)
- if T == lltype.Signed:
- blackholeinterp.setarg_i(count_i, value)
- count_i += 1
- elif T == llmemory.GCREF:
- blackholeinterp.setarg_r(count_r, value)
- count_r += 1
- elif T == lltype.Float:
- value = longlong.getfloatstorage(value)
- blackholeinterp.setarg_f(count_f, value)
- count_f += 1
- else:
- raise TypeError(T)
- [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
- blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
- blackholeinterp.run()
- return blackholeinterp._final_result_anytype()
-
-def _run_with_pyjitpl(testself, args):
-
- class DoneWithThisFrame(Exception):
- pass
-
- class DoneWithThisFrameRef(DoneWithThisFrame):
- def __init__(self, cpu, *args):
- DoneWithThisFrame.__init__(self, *args)
-
- cw = testself.cw
- opt = history.Options(listops=True)
- metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
- metainterp_sd.finish_setup(cw)
- [jitdriver_sd] = metainterp_sd.jitdrivers_sd
- metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
- metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
- metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
- metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
- testself.metainterp = metainterp
- try:
- metainterp.compile_and_run_once(jitdriver_sd, *args)
- except DoneWithThisFrame, e:
- #if conftest.option.view:
- # metainterp.stats.view()
- return e.args[0]
- else:
- raise Exception("FAILED")
-
-def _run_with_machine_code(testself, args):
- metainterp = testself.metainterp
- num_green_args = metainterp.jitdriver_sd.num_green_args
- loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
- if len(loop_tokens) != 1:
- return NotImplemented
- # a loop was successfully created by _run_with_pyjitpl(); call it
- cpu = metainterp.cpu
- for i in range(len(args) - num_green_args):
- x = args[num_green_args + i]
- typecode = history.getkind(lltype.typeOf(x))
- set_future_value(cpu, i, x, typecode)
- faildescr = cpu.execute_token(loop_tokens[0])
- assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
- if metainterp.jitdriver_sd.result_type == history.INT:
- return cpu.get_latest_value_int(0)
- elif metainterp.jitdriver_sd.result_type == history.REF:
- return cpu.get_latest_value_ref(0)
- elif metainterp.jitdriver_sd.result_type == history.FLOAT:
- return cpu.get_latest_value_float(0)
- else:
- return None
-
-
-class JitMixin:
- basic = True
- def check_loops(self, expected=None, everywhere=False, **check):
- get_stats().check_loops(expected=expected, everywhere=everywhere,
- **check)
- def check_loop_count(self, count):
- """NB. This is a hack; use check_tree_loop_count() or
- check_enter_count() for the real thing.
- This counts as 1 every bridge in addition to every loop; and it does
- not count at all the entry bridges from interpreter, although they
- are TreeLoops as well."""
- assert get_stats().compiled_count == count
- def check_tree_loop_count(self, count):
- assert len(get_stats().loops) == count
- def check_loop_count_at_most(self, count):
- assert get_stats().compiled_count <= count
- def check_enter_count(self, count):
- assert get_stats().enter_count == count
- def check_enter_count_at_most(self, count):
- assert get_stats().enter_count <= count
- def check_jumps(self, maxcount):
- assert get_stats().exec_jumps <= maxcount
- def check_aborted_count(self, count):
- assert get_stats().aborted_count == count
- def check_aborted_count_at_least(self, count):
- assert get_stats().aborted_count >= count
-
- def meta_interp(self, *args, **kwds):
- kwds['CPUClass'] = self.CPUClass
- kwds['type_system'] = self.type_system
- if "backendopt" not in kwds:
- kwds["backendopt"] = False
- return ll_meta_interp(*args, **kwds)
-
- def interp_operations(self, f, args, **kwds):
- # get the JitCodes for the function f
- _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
- # try to run it with blackhole.py
- result1 = _run_with_blackhole(self, args)
- # try to run it with pyjitpl.py
- result2 = _run_with_pyjitpl(self, args)
- assert result1 == result2
- # try to run it by running the code compiled just before
- result3 = _run_with_machine_code(self, args)
- assert result1 == result3 or result3 == NotImplemented
- #
- if (longlong.supports_longlong and
- isinstance(result1, longlong.r_float_storage)):
- result1 = longlong.getrealfloat(result1)
- return result1
-
- def check_history(self, expected=None, **isns):
- # this can be used after calling meta_interp
- get_stats().check_history(expected, **isns)
-
- def check_operations_history(self, expected=None, **isns):
- # this can be used after interp_operations
- if expected is not None:
- expected = dict(expected)
- expected['jump'] = 1
- self.metainterp.staticdata.stats.check_history(expected, **isns)
-
-
-class LLJitMixin(JitMixin):
- type_system = 'lltype'
- CPUClass = runner.LLtypeCPU
-
- @staticmethod
- def Ptr(T):
- return lltype.Ptr(T)
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- S = lltype.GcStruct(name, *fields, **kwds)
- return S
-
- malloc = staticmethod(lltype.malloc)
- nullptr = staticmethod(lltype.nullptr)
-
- @staticmethod
- def malloc_immortal(T):
- return lltype.malloc(T, immortal=True)
-
- def _get_NODE(self):
- NODE = lltype.GcForwardReference()
- NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
- ('next', lltype.Ptr(NODE))))
- return NODE
-
-class OOJitMixin(JitMixin):
- type_system = 'ootype'
- #CPUClass = runner.OOtypeCPU
-
- def setup_class(cls):
- py.test.skip("ootype tests skipped for now")
-
- @staticmethod
- def Ptr(T):
- return T
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- if 'hints' in kwds:
- kwds['_hints'] = kwds['hints']
- del kwds['hints']
- I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
- return I
-
- malloc = staticmethod(ootype.new)
- nullptr = staticmethod(ootype.null)
-
- @staticmethod
- def malloc_immortal(T):
- return ootype.new(T)
-
- def _get_NODE(self):
- NODE = ootype.Instance('NODE', ootype.ROOT, {})
- NODE._add_fields({'value': ootype.Signed,
- 'next': NODE})
- return NODE
-
-
-class BasicTests:
-
- def test_basic(self):
- def f(x, y):
- return x + y
- res = self.interp_operations(f, [40, 2])
- assert res == 42
-
- def test_basic_inst(self):
- class A:
- pass
- def f(n):
- a = A()
- a.x = n
- return a.x
- res = self.interp_operations(f, [42])
- assert res == 42
-
- def test_uint_floordiv(self):
- from pypy.rlib.rarithmetic import r_uint
-
- def f(a, b):
- a = r_uint(a)
- b = r_uint(b)
- return a/b
-
- res = self.interp_operations(f, [-4, 3])
- assert res == long(r_uint(-4)) // 3
-
- def test_direct_call(self):
- def g(n):
- return n + 2
- def f(a, b):
- return g(a) + g(b)
- res = self.interp_operations(f, [8, 98])
- assert res == 110
-
- def test_direct_call_with_guard(self):
- def g(n):
- if n < 0:
- return 0
- return n + 2
- def f(a, b):
- return g(a) + g(b)
- res = self.interp_operations(f, [8, 98])
- assert res == 110
-
- def test_loop(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
- if self.basic:
- found = 0
- for op in get_stats().loops[0]._all_operations():
- if op.getopname() == 'guard_true':
- liveboxes = op.getfailargs()
- assert len(liveboxes) == 3
- for box in liveboxes:
- assert isinstance(box, history.BoxInt)
- found += 1
- assert found == 1
-
- def test_loop_invariant_mul1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 252
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
-
- def test_loop_invariant_mul_ovf(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- b = y * 2
- res += ovfcheck(x * x) + b
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 308
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 2, 'int_sub': 1, 'int_gt': 1,
- 'int_lshift': 1,
- 'jump': 1})
-
- def test_loop_invariant_mul_bridge1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- if y<16:
- x += 1
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 3427
- self.check_loop_count(3)
-
- def test_loop_invariant_mul_bridge_maintaining1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- if y<16:
- res += 1
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 1167
- self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
-
-
- def test_loop_invariant_mul_bridge_maintaining2(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- z = x * x
- res += z
- if y<16:
- res += z
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 1692
- self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
-
- def test_loop_invariant_mul_bridge_maintaining3(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x', 'm'])
- def f(x, y, m):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res, m=m)
- myjitdriver.jit_merge_point(x=x, y=y, res=res, m=m)
- z = x * x
- res += z
- if y<m:
- res += z
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32, 16])
- assert res == 1692
- self.check_loop_count(3)
- self.check_loops({'int_add': 2, 'int_lt': 1,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2, 'int_mul': 1,
- 'int_gt': 2, 'guard_true': 2})
-
- def test_loop_invariant_intbox(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- class I:
- __slots__ = 'intval'
- _immutable_ = True
- def __init__(self, intval):
- self.intval = intval
- def f(i, y):
- res = 0
- x = I(i)
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x.intval * x.intval
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 252
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
-
- def test_loops_are_transient(self):
- import gc, weakref
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- if y%2:
- res *= 2
- y -= 1
- return res
- wr_loops = []
- old_init = history.TreeLoop.__init__.im_func
- try:
- def track_init(self, name):
- old_init(self, name)
- wr_loops.append(weakref.ref(self))
- history.TreeLoop.__init__ = track_init
- res = self.meta_interp(f, [6, 15], no_stats=True)
- finally:
- history.TreeLoop.__init__ = old_init
-
- assert res == f(6, 15)
- gc.collect()
-
- #assert not [wr for wr in wr_loops if wr()]
- for loop in [wr for wr in wr_loops if wr()]:
- assert loop().name == 'short preamble'
-
- def test_string(self):
- def f(n):
- bytecode = 'adlfkj' + chr(n)
- if n < len(bytecode):
- return bytecode[n]
- else:
- return "?"
- res = self.interp_operations(f, [1])
- assert res == ord("d") # XXX should be "d"
- res = self.interp_operations(f, [6])
- assert res == 6
- res = self.interp_operations(f, [42])
- assert res == ord("?")
-
- def test_chr2str(self):
- def f(n):
- s = chr(n)
- return s[0]
- res = self.interp_operations(f, [3])
- assert res == 3
-
- def test_unicode(self):
- def f(n):
- bytecode = u'adlfkj' + unichr(n)
- if n < len(bytecode):
- return bytecode[n]
- else:
- return u"?"
- res = self.interp_operations(f, [1])
- assert res == ord(u"d") # XXX should be "d"
- res = self.interp_operations(f, [6])
- assert res == 6
- res = self.interp_operations(f, [42])
- assert res == ord(u"?")
-
- def test_residual_call(self):
- @dont_look_inside
- def externfn(x, y):
- return x * y
- def f(n):
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0)
-
- def test_residual_call_pure(self):
- def externfn(x, y):
- return x * y
- externfn._pure_function_ = True
- def f(n):
- n = hint(n, promote=True)
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- # CALL_PURE is not recorded in the history if all-constant args
- self.check_operations_history(int_add=0, int_mul=0,
- call=0, call_pure=0)
-
- def test_residual_call_pure_1(self):
- def externfn(x, y):
- return x * y
- externfn._pure_function_ = True
- def f(n):
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- # CALL_PURE is recorded in the history if not-all-constant args
- self.check_operations_history(int_add=1, int_mul=0,
- call=0, call_pure=1)
-
- def test_residual_call_pure_2(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- def externfn(x):
- return x - 1
- externfn._pure_function_ = True
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- n = externfn(n)
- return n
- res = self.meta_interp(f, [7])
- assert res == 0
- # CALL_PURE is recorded in the history, but turned into a CALL
- # by optimizeopt.py
- self.check_loops(int_sub=0, call=1, call_pure=0)
-
- def test_constfold_call_pure(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def externfn(x):
- return x - 3
- externfn._pure_function_ = True
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- n -= externfn(m)
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
-
- def test_constfold_call_pure_2(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def externfn(x):
- return x - 3
- externfn._pure_function_ = True
- class V:
- def __init__(self, value):
- self.value = value
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- v = V(m)
- n -= externfn(v.value)
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
-
- def test_pure_function_returning_object(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- class V:
- def __init__(self, x):
- self.x = x
- v1 = V(1)
- v2 = V(2)
- def externfn(x):
- if x:
- return v1
- else:
- return v2
- externfn._pure_function_ = True
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- m = V(m).x
- n -= externfn(m).x + externfn(m + m - m).x
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0)
-
- def test_constant_across_mp(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- class X(object):
- pass
- def f(n):
- while n > -100:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- x = X()
- x.arg = 5
- if n <= 0: break
- n -= x.arg
- x.arg = 6 # prevents 'x.arg' from being annotated as constant
- return n
- res = self.meta_interp(f, [31])
- assert res == -4
-
- def test_stopatxpolicy(self):
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def internfn(y):
- return y * 3
- def externfn(y):
- return y % 4
- def f(y):
- while y >= 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- if y & 7:
- f = internfn
- else:
- f = externfn
- f(y)
- y -= 1
- return 42
- policy = StopAtXPolicy(externfn)
- res = self.meta_interp(f, [31], policy=policy)
- assert res == 42
- self.check_loops(int_mul=1, int_mod=0)
-
- def test_we_are_jitted(self):
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def f(y):
- while y >= 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- if we_are_jitted():
- x = 1
- else:
- x = 10
- y -= x
- return y
- assert f(55) == -5
- res = self.meta_interp(f, [55])
- assert res == -1
-
- def test_confirm_enter_jit(self):
- def confirm_enter_jit(x, y):
- return x <= 5
- myjitdriver = JitDriver(greens = ['x'], reds = ['y'],
- confirm_enter_jit = confirm_enter_jit)
- def f(x, y):
- while y >= 0:
- myjitdriver.can_enter_jit(x=x, y=y)
- myjitdriver.jit_merge_point(x=x, y=y)
- y -= x
- return y
- #
- res = self.meta_interp(f, [10, 84])
- assert res == -6
- self.check_loop_count(0)
- #
- res = self.meta_interp(f, [3, 19])
- assert res == -2
- self.check_loop_count(1)
-
- def test_can_never_inline(self):
- def can_never_inline(x):
- return x > 50
- myjitdriver = JitDriver(greens = ['x'], reds = ['y'],
- can_never_inline = can_never_inline)
- @dont_look_inside
- def marker():
- pass
- def f(x, y):
- while y >= 0:
- myjitdriver.can_enter_jit(x=x, y=y)
- myjitdriver.jit_merge_point(x=x, y=y)
- x += 1
- if x == 4 or x == 61:
- marker()
- y -= x
- return y
- #
- res = self.meta_interp(f, [3, 6], repeat=7)
- assert res == 6 - 4 - 5
- self.check_history(call=0) # because the trace starts in the middle
- #
- res = self.meta_interp(f, [60, 84], repeat=7)
- assert res == 84 - 61 - 62
- self.check_history(call=1) # because the trace starts immediately
-
- def test_format(self):
- def f(n):
- return len("<%d>" % n)
- res = self.interp_operations(f, [421])
- assert res == 5
-
- def test_switch(self):
- def f(n):
- if n == -5: return 12
- elif n == 2: return 51
- elif n == 7: return 1212
- else: return 42
- res = self.interp_operations(f, [7])
- assert res == 1212
- res = self.interp_operations(f, [12311])
- assert res == 42
-
- def test_r_uint(self):
- from pypy.rlib.rarithmetic import r_uint
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def f(y):
- y = r_uint(y)
- while y > 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- y -= 1
- return y
- res = self.meta_interp(f, [10])
- assert res == 0
-
- def test_uint_operations(self):
- from pypy.rlib.rarithmetic import r_uint
- def f(n):
- return ((r_uint(n) - 123) >> 1) <= r_uint(456)
- res = self.interp_operations(f, [50])
- assert res == False
- self.check_operations_history(int_rshift=0, uint_rshift=1,
- int_le=0, uint_le=1,
- int_sub=1)
-
- def test_uint_condition(self):
- from pypy.rlib.rarithmetic import r_uint
- def f(n):
- if ((r_uint(n) - 123) >> 1) <= r_uint(456):
- return 24
- else:
- return 12
- res = self.interp_operations(f, [50])
- assert res == 12
- self.check_operations_history(int_rshift=0, uint_rshift=1,
- int_le=0, uint_le=1,
- int_sub=1)
-
- def test_int_between(self):
- #
- def check(arg1, arg2, arg3, expect_result, **expect_operations):
- from pypy.rpython.lltypesystem import lltype
- from pypy.rpython.lltypesystem.lloperation import llop
- loc = locals().copy()
- exec py.code.Source("""
- def f(n, m, p):
- arg1 = %(arg1)s
- arg2 = %(arg2)s
- arg3 = %(arg3)s
- return llop.int_between(lltype.Bool, arg1, arg2, arg3)
- """ % locals()).compile() in loc
- res = self.interp_operations(loc['f'], [5, 6, 7])
- assert res == expect_result
- self.check_operations_history(expect_operations)
- #
- check('n', 'm', 'p', True, int_sub=2, uint_lt=1)
- check('n', 'p', 'm', False, int_sub=2, uint_lt=1)
- #
- check('n', 'm', 6, False, int_sub=2, uint_lt=1)
- #
- check('n', 4, 'p', False, int_sub=2, uint_lt=1)
- check('n', 5, 'p', True, int_sub=2, uint_lt=1)
- check('n', 8, 'p', False, int_sub=2, uint_lt=1)
- #
- check('n', 6, 7, True, int_sub=2, uint_lt=1)
- #
- check(-2, 'n', 'p', True, int_sub=2, uint_lt=1)
- check(-2, 'm', 'p', True, int_sub=2, uint_lt=1)
- check(-2, 'p', 'm', False, int_sub=2, uint_lt=1)
- #check(0, 'n', 'p', True, uint_lt=1) xxx implement me
- #check(0, 'm', 'p', True, uint_lt=1)
- #check(0, 'p', 'm', False, uint_lt=1)
- #
- check(2, 'n', 6, True, int_sub=1, uint_lt=1)
- check(2, 'm', 6, False, int_sub=1, uint_lt=1)
- check(2, 'p', 6, False, int_sub=1, uint_lt=1)
- check(5, 'n', 6, True, int_eq=1) # 6 == 5+1
- check(5, 'm', 6, False, int_eq=1) # 6 == 5+1
- #
- check(2, 6, 'm', False, int_sub=1, uint_lt=1)
- check(2, 6, 'p', True, int_sub=1, uint_lt=1)
- #
- check(2, 40, 6, False)
- check(2, 40, 60, True)
-
- def test_getfield(self):
- class A:
- pass
- a1 = A()
- a1.foo = 5
- a2 = A()
- a2.foo = 8
- def f(x):
- if x > 5:
- a = a1
- else:
- a = a2
- return a.foo * x
- res = self.interp_operations(f, [42])
- assert res == 210
- self.check_operations_history(getfield_gc=1)
-
- def test_getfield_immutable(self):
- class A:
- _immutable_ = True
- a1 = A()
- a1.foo = 5
- a2 = A()
- a2.foo = 8
- def f(x):
- if x > 5:
- a = a1
- else:
- a = a2
- return a.foo * x
- res = self.interp_operations(f, [42])
- assert res == 210
- self.check_operations_history(getfield_gc=0)
-
- def test_setfield_bool(self):
- class A:
- def __init__(self):
- self.flag = True
- myjitdriver = JitDriver(greens = [], reds = ['n', 'obj'])
- def f(n):
- obj = A()
- res = False
- while n > 0:
- myjitdriver.can_enter_jit(n=n, obj=obj)
- myjitdriver.jit_merge_point(n=n, obj=obj)
- obj.flag = False
- n -= 1
- return res
- res = self.meta_interp(f, [7])
- assert type(res) == bool
- assert not res
-
- def test_switch_dict(self):
- def f(x):
- if x == 1: return 61
- elif x == 2: return 511
- elif x == 3: return -22
- elif x == 4: return 81
- elif x == 5: return 17
- elif x == 6: return 54
- elif x == 7: return 987
- elif x == 8: return -12
- elif x == 9: return 321
- return -1
- res = self.interp_operations(f, [5])
- assert res == 17
- res = self.interp_operations(f, [15])
- assert res == -1
-
- def test_int_add_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x + y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -98
- res = self.interp_operations(f, [1, sys.maxint])
- assert res == -42
-
- def test_int_sub_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x - y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -102
- res = self.interp_operations(f, [1, -sys.maxint])
- assert res == -42
-
- def test_int_mul_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x * y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -200
- res = self.interp_operations(f, [-3, sys.maxint//2])
- assert res == -42
-
- def test_mod_ovf(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x', 'y'])
- def f(n, x, y):
- while n > 0:
- myjitdriver.can_enter_jit(x=x, y=y, n=n)
- myjitdriver.jit_merge_point(x=x, y=y, n=n)
- n -= ovfcheck(x % y)
- return n
- res = self.meta_interp(f, [20, 1, 2])
- assert res == 0
- self.check_loops(call=0)
-
- def test_abs(self):
- myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
- def f(i):
- t = 0
- while i < 10:
- myjitdriver.can_enter_jit(i=i, t=t)
- myjitdriver.jit_merge_point(i=i, t=t)
- t += abs(i)
- i += 1
- return t
- res = self.meta_interp(f, [-5])
- assert res == 5+4+3+2+1+0+1+2+3+4+5+6+7+8+9
-
- def test_float(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- x = float(x)
- y = float(y)
- res = 0.0
- while y > 0.0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- y -= 1.0
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42.0
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'float_add': 1, 'float_sub': 1, 'float_gt': 1,
- 'jump': 1})
-
- def test_print(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- print n
- n -= 1
- return n
- res = self.meta_interp(f, [7])
- assert res == 0
-
- def test_bridge_from_interpreter(self):
- mydriver = JitDriver(reds = ['n'], greens = [])
-
- def f(n):
- while n > 0:
- mydriver.can_enter_jit(n=n)
- mydriver.jit_merge_point(n=n)
- n -= 1
-
- self.meta_interp(f, [20], repeat=7)
- self.check_tree_loop_count(2) # the loop and the entry path
- # we get:
- # ENTER - compile the new loop and the entry bridge
- # ENTER - compile the leaving path
- self.check_enter_count(2)
-
- def test_bridge_from_interpreter_2(self):
- # one case for backend - computing of framesize on guard failure
- mydriver = JitDriver(reds = ['n'], greens = [])
- glob = [1]
-
- def f(n):
- while n > 0:
- mydriver.can_enter_jit(n=n)
- mydriver.jit_merge_point(n=n)
- if n == 17 and glob[0]:
- glob[0] = 0
- x = n + 1
- y = n + 2
- z = n + 3
- k = n + 4
- n -= 1
- n += x + y + z + k
- n -= x + y + z + k
- n -= 1
-
- self.meta_interp(f, [20], repeat=7)
-
- def test_bridge_from_interpreter_3(self):
- # one case for backend - computing of framesize on guard failure
- mydriver = JitDriver(reds = ['n', 'x', 'y', 'z', 'k'], greens = [])
- class Global:
- pass
- glob = Global()
-
- def f(n):
- glob.x = 1
- x = 0
- y = 0
- z = 0
- k = 0
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x, y=y, z=z, k=k)
- mydriver.jit_merge_point(n=n, x=x, y=y, z=z, k=k)
- x += 10
- y += 3
- z -= 15
- k += 4
- if n == 17 and glob.x:
- glob.x = 0
- x += n + 1
- y += n + 2
- z += n + 3
- k += n + 4
- n -= 1
- n -= 1
- return x + 2*y + 3*z + 5*k + 13*n
-
- res = self.meta_interp(f, [20], repeat=7)
- assert res == f(20)
-
- def test_bridge_from_interpreter_4(self):
- jitdriver = JitDriver(reds = ['n', 'k'], greens = [])
-
- def f(n, k):
- while n > 0:
- jitdriver.can_enter_jit(n=n, k=k)
- jitdriver.jit_merge_point(n=n, k=k)
- if k:
- n -= 2
- else:
- n -= 1
- return n + k
-
- from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
- from pypy.jit.metainterp.warmspot import WarmRunnerDesc
-
- interp, graph = get_interpreter(f, [0, 0], backendopt=False,
- inline_threshold=0, type_system=self.type_system)
- clear_tcache()
- translator = interp.typer.annotator.translator
- translator.config.translation.gc = "boehm"
- warmrunnerdesc = WarmRunnerDesc(translator,
- CPUClass=self.CPUClass)
- state = warmrunnerdesc.jitdrivers_sd[0].warmstate
- state.set_param_threshold(3) # for tests
- state.set_param_trace_eagerness(0) # for tests
- warmrunnerdesc.finish()
- for n, k in [(20, 0), (20, 1)]:
- interp.eval_graph(graph, [n, k])
-
- def test_bridge_leaving_interpreter_5(self):
- mydriver = JitDriver(reds = ['n', 'x'], greens = [])
- class Global:
- pass
- glob = Global()
-
- def f(n):
- x = 0
- glob.x = 1
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x)
- mydriver.jit_merge_point(n=n, x=x)
- glob.x += 1
- x += 3
- n -= 1
- glob.x += 100
- return glob.x + x
- res = self.meta_interp(f, [20], repeat=7)
- assert res == f(20)
-
- def test_instantiate_classes(self):
- class Base: pass
- class A(Base): foo = 72
- class B(Base): foo = 8
- def f(n):
- if n > 5:
- cls = A
- else:
- cls = B
- return cls().foo
- res = self.interp_operations(f, [3])
- assert res == 8
- res = self.interp_operations(f, [13])
- assert res == 72
-
- def test_instantiate_does_not_call(self):
- mydriver = JitDriver(reds = ['n', 'x'], greens = [])
- class Base: pass
- class A(Base): foo = 72
- class B(Base): foo = 8
-
- def f(n):
- x = 0
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x)
- mydriver.jit_merge_point(n=n, x=x)
- if n % 2 == 0:
- cls = A
- else:
- cls = B
- inst = cls()
- x += inst.foo
- n -= 1
- return x
- res = self.meta_interp(f, [20], enable_opts='')
- assert res == f(20)
- self.check_loops(call=0)
-
- def test_zerodivisionerror(self):
- # test the case of exception-raising operation that is not delegated
- # to the backend at all: ZeroDivisionError
- #
- def f(n):
- assert n >= 0
- try:
- return ovfcheck(5 % n)
- except ZeroDivisionError:
- return -666
- except OverflowError:
- return -777
- res = self.interp_operations(f, [0])
- assert res == -666
- #
- def f(n):
- assert n >= 0
- try:
- return ovfcheck(6 // n)
- except ZeroDivisionError:
- return -667
- except OverflowError:
- return -778
- res = self.interp_operations(f, [0])
- assert res == -667
-
- def test_div_overflow(self):
- import sys
- from pypy.rpython.lltypesystem.lloperation import llop
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- try:
- res += llop.int_floordiv_ovf(lltype.Signed,
- -sys.maxint-1, x)
- x += 5
- except OverflowError:
- res += 100
- y -= 1
- return res
- res = self.meta_interp(f, [-41, 16])
- assert res == ((-sys.maxint-1) // (-41) +
- (-sys.maxint-1) // (-36) +
- (-sys.maxint-1) // (-31) +
- (-sys.maxint-1) // (-26) +
- (-sys.maxint-1) // (-21) +
- (-sys.maxint-1) // (-16) +
- (-sys.maxint-1) // (-11) +
- (-sys.maxint-1) // (-6) +
- 100 * 8)
-
- def test_isinstance(self):
- class A:
- pass
- class B(A):
- pass
- def fn(n):
- if n:
- obj = A()
- else:
- obj = B()
- return isinstance(obj, B)
- res = self.interp_operations(fn, [0])
- assert res
- self.check_operations_history(guard_class=1)
- res = self.interp_operations(fn, [1])
- assert not res
-
- def test_isinstance_2(self):
- driver = JitDriver(greens = [], reds = ['n', 'sum', 'x'])
- class A:
- pass
- class B(A):
- pass
- class C(B):
- pass
-
- def main():
- return f(5, B()) * 10 + f(5, C()) + f(5, A()) * 100
-
- def f(n, x):
- sum = 0
- while n > 0:
- driver.can_enter_jit(x=x, n=n, sum=sum)
- driver.jit_merge_point(x=x, n=n, sum=sum)
- if isinstance(x, B):
- sum += 1
- n -= 1
- return sum
-
- res = self.meta_interp(main, [])
- assert res == 55
-
- def test_assert_isinstance(self):
- class A:
- pass
- class B(A):
- pass
- def fn(n):
- # this should only be called with n != 0
- if n:
- obj = B()
- obj.a = n
- else:
- obj = A()
- obj.a = 17
- assert isinstance(obj, B)
- return obj.a
- res = self.interp_operations(fn, [1])
- assert res == 1
- self.check_operations_history(guard_class=0)
- if self.type_system == 'ootype':
- self.check_operations_history(instanceof=0)
-
- def test_r_dict(self):
- from pypy.rlib.objectmodel import r_dict
- class FooError(Exception):
- pass
- def myeq(n, m):
- return n == m
- def myhash(n):
- if n < 0:
- raise FooError
- return -n
- def f(n):
- d = r_dict(myeq, myhash)
- for i in range(10):
- d[i] = i*i
- try:
- return d[n]
- except FooError:
- return 99
- res = self.interp_operations(f, [5])
- assert res == f(5)
-
- def test_free_object(self):
- import weakref
- from pypy.rlib import rgc
- from pypy.rpython.lltypesystem.lloperation import llop
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
- class X(object):
- pass
- def main(n, x):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- n -= x.foo
- def g(n):
- x = X()
- x.foo = 2
- main(n, x)
- x.foo = 5
- return weakref.ref(x)
- def f(n):
- r = g(n)
- rgc.collect(); rgc.collect(); rgc.collect()
- return r() is None
- #
- assert f(30) == 1
- res = self.meta_interp(f, [30], no_stats=True)
- assert res == 1
-
- def test_pass_around(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
-
- def call():
- pass
-
- def f(n, x):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- if n % 2:
- call()
- if n == 8:
- return x
- x = 3
- else:
- x = 5
- n -= 1
- return 0
-
- self.meta_interp(f, [40, 0])
-
- def test_const_inputargs(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'x'])
- def f(n, x):
- m = 0x7FFFFFFF
- while n > 0:
- myjitdriver.can_enter_jit(m=m, n=n, x=x)
- myjitdriver.jit_merge_point(m=m, n=n, x=x)
- x = 42
- n -= 1
- m = m >> 1
- return x
-
- res = self.meta_interp(f, [50, 1], enable_opts='')
- assert res == 42
-
- def test_set_param(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
- def g(n):
- x = 0
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- n -= 1
- x += n
- return x
- def f(n, threshold):
- myjitdriver.set_param('threshold', threshold)
- return g(n)
-
- res = self.meta_interp(f, [10, 3])
- assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
- self.check_tree_loop_count(2)
-
- res = self.meta_interp(f, [10, 13])
- assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
- self.check_tree_loop_count(0)
-
- def test_dont_look_inside(self):
- @dont_look_inside
- def g(a, b):
- return a + b
- def f(a, b):
- return g(a, b)
- res = self.interp_operations(f, [3, 5])
- assert res == 8
- self.check_operations_history(int_add=0, call=1)
-
- def test_listcomp(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst'])
- def f(x, y):
- lst = [0, 0, 0]
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, lst=lst)
- myjitdriver.jit_merge_point(x=x, y=y, lst=lst)
- lst = [i+x for i in lst if i >=0]
- y -= 1
- return lst[0]
- res = self.meta_interp(f, [6, 7], listcomp=True, backendopt=True, listops=True)
- # XXX: the loop looks inefficient
- assert res == 42
-
- def test_tuple_immutable(self):
- def new(a, b):
- return a, b
- def f(a, b):
- tup = new(a, b)
- return tup[1]
- res = self.interp_operations(f, [3, 5])
- assert res == 5
- self.check_operations_history(setfield_gc=2, getfield_gc_pure=1)
-
- def test_oosend_look_inside_only_one(self):
- class A:
- pass
- class B(A):
- def g(self):
- return 123
- class C(A):
- @dont_look_inside
- def g(self):
- return 456
- def f(n):
- if n > 3:
- x = B()
- else:
- x = C()
- return x.g() + x.g()
- res = self.interp_operations(f, [10])
- assert res == 123 * 2
- res = self.interp_operations(f, [-10])
- assert res == 456 * 2
-
- def test_residual_external_call(self):
- import math
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- def f(x, y):
- x = float(x)
- res = 0.0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- # this is an external call that the default policy ignores
- rpart, ipart = math.modf(x)
- res += ipart
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42
- self.check_loop_count(1)
- self.check_loops(call=1)
-
- def test_merge_guardclass_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 5
- class B(A):
- def g(self, y):
- return y - 3
-
- a1 = A()
- a2 = A()
- b = B()
- def f(x):
- l = [a1] * 100 + [a2] * 100 + [b] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- x = a.g(x)
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_value=2)
- self.check_loops(guard_class=0, guard_value=5, everywhere=True)
-
- def test_merge_guardnonnull_guardclass(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 3
- class B(A):
- def g(self, y):
- return y - 5
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x = a.g(x)
- else:
- x -= 7
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0,
- guard_nonnull_class=2, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0,
- guard_nonnull_class=4, guard_isnull=1,
- everywhere=True)
-
- def test_merge_guardnonnull_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- pass
- class B(A):
- pass
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [b1] * 100 + [None] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x -= 5
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=1,
- guard_nonnull_class=0, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=3,
- guard_nonnull_class=0, guard_isnull=2,
- everywhere=True)
-
- def test_merge_guardnonnull_guardvalue_2(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- pass
- class B(A):
- pass
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x -= 5
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
- guard_nonnull_class=0, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=4,
- guard_nonnull_class=0, guard_isnull=1,
- everywhere=True)
-
- def test_merge_guardnonnull_guardclass_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 3
- class B(A):
- def g(self, y):
- return y - 5
-
- a1 = A()
- a2 = A()
- b1 = B()
- def f(x):
- l = [a2] * 100 + [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x = a.g(x)
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [399], listops=True)
- assert res == f(399)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
- guard_nonnull_class=0, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=5,
- guard_nonnull_class=0, guard_isnull=1,
- everywhere=True)
-
- def test_residual_call_doesnt_lose_info(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
-
- class A(object):
- pass
-
- globall = [""]
- @dont_look_inside
- def g(x):
- globall[0] = str(x)
- return x
-
- def f(x):
- y = A()
- y.v = x
- l = [0]
- while y.v > 0:
- myjitdriver.can_enter_jit(x=x, y=y, l=l)
- myjitdriver.jit_merge_point(x=x, y=y, l=l)
- l[0] = y.v
- lc = l[0]
- y.v = g(y.v) - y.v/y.v + lc/l[0] - 1
- return y.v
- res = self.meta_interp(f, [20], listops=True)
- self.check_loops(getfield_gc=0, getarrayitem_gc=0)
- self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True)
-
- def test_guard_isnull_nonnull(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
- class A(object):
- pass
-
- @dont_look_inside
- def create(x):
- if x >= -40:
- return A()
- return None
-
- def f(x):
- res = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res)
- myjitdriver.jit_merge_point(x=x, res=res)
- obj = create(x-1)
- if obj is not None:
- res += 1
- obj2 = create(x-1000)
- if obj2 is None:
- res += 1
- x -= 1
- return res
- res = self.meta_interp(f, [21])
- assert res == 42
- self.check_loops(guard_nonnull=1, guard_isnull=1)
-
- def test_loop_invariant1(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
- class A(object):
- pass
- a = A()
- a.current_a = A()
- a.current_a.x = 1
- @loop_invariant
- def f():
- return a.current_a
-
- def g(x):
- res = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res)
- myjitdriver.jit_merge_point(x=x, res=res)
- res += f().x
- res += f().x
- res += f().x
- x -= 1
- a.current_a = A()
- a.current_a.x = 2
- return res
- res = self.meta_interp(g, [21])
- assert res == 3 * 21
- self.check_loops(call=0)
- self.check_loops(call=1, everywhere=True)
-
- def test_bug_optimizeopt_mutates_ops(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'const', 'a'])
- class A(object):
- pass
- class B(A):
- pass
-
- glob = A()
- glob.a = None
- def f(x):
- res = 0
- a = A()
- a.x = 0
- glob.a = A()
- const = 2
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res, a=a, const=const)
- myjitdriver.jit_merge_point(x=x, res=res, a=a, const=const)
- if type(glob.a) is B:
- res += 1
- if a is None:
- a = A()
- a.x = x
- glob.a = B()
- const = 2
- else:
- const = hint(const, promote=True)
- x -= const
- res += a.x
- a = None
- glob.a = A()
- const = 1
- return res
- res = self.meta_interp(f, [21])
- assert res == f(21)
-
- def test_getitem_indexerror(self):
- lst = [10, 4, 9, 16]
- def f(n):
- try:
- return lst[n]
- except IndexError:
- return -2
- res = self.interp_operations(f, [2])
- assert res == 9
- res = self.interp_operations(f, [4])
- assert res == -2
- res = self.interp_operations(f, [-4])
- assert res == 10
- res = self.interp_operations(f, [-5])
- assert res == -2
-
- def test_guard_always_changing_value(self):
- myjitdriver = JitDriver(greens = [], reds = ['x'])
- class A:
- pass
- def f(x):
- while x > 0:
- myjitdriver.can_enter_jit(x=x)
- myjitdriver.jit_merge_point(x=x)
- a = A()
- hint(a, promote=True)
- x -= 1
- self.meta_interp(f, [50])
- self.check_loop_count(1)
- # this checks that the logic triggered by make_a_counter_per_value()
- # works and prevents generating tons of bridges
-
- def test_swap_values(self):
- def f(x, y):
- if x > 5:
- x, y = y, x
- return x - y
- res = self.interp_operations(f, [10, 2])
- assert res == -8
- res = self.interp_operations(f, [3, 2])
- assert res == 1
-
- def test_raw_malloc_and_access(self):
- from pypy.rpython.lltypesystem import rffi
-
- TP = rffi.CArray(lltype.Signed)
-
- def f(n):
- a = lltype.malloc(TP, n, flavor='raw')
- a[0] = n
- res = a[0]
- lltype.free(a, flavor='raw')
- return res
-
- res = self.interp_operations(f, [10])
- assert res == 10
-
- def test_raw_malloc_and_access_float(self):
- from pypy.rpython.lltypesystem import rffi
-
- TP = rffi.CArray(lltype.Float)
-
- def f(n, f):
- a = lltype.malloc(TP, n, flavor='raw')
- a[0] = f
- res = a[0]
- lltype.free(a, flavor='raw')
- return res
-
- res = self.interp_operations(f, [10, 3.5])
- assert res == 3.5
-
- def test_jit_debug(self):
- myjitdriver = JitDriver(greens = [], reds = ['x'])
- class A:
- pass
- def f(x):
- while x > 0:
- myjitdriver.can_enter_jit(x=x)
- myjitdriver.jit_merge_point(x=x)
- jit_debug("hi there:", x)
- jit_debug("foobar")
- x -= 1
- return x
- res = self.meta_interp(f, [8])
- assert res == 0
- self.check_loops(jit_debug=2)
-
- def test_assert_green(self):
- def f(x, promote):
- if promote:
- x = hint(x, promote=True)
- assert_green(x)
- return x
- res = self.interp_operations(f, [8, 1])
- assert res == 8
- py.test.raises(AssertGreenFailed, self.interp_operations, f, [8, 0])
-
- def test_multiple_specialied_versions1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- class B(Base):
- def binop(self, other):
- return B(self.val * other.val)
- def f(x, y):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- res = res.binop(x)
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [6, 7])
- assert res == 6*8 + 6**8
- self.check_loop_count(5)
- self.check_loops({'guard_true': 2,
- 'int_add': 1, 'int_mul': 1, 'int_sub': 2,
- 'int_gt': 2, 'jump': 2})
-
- def test_multiple_specialied_versions_array(self):
- myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
- 'array'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- class B(Base):
- def binop(self, other):
- return B(self.val - other.val)
- def f(x, y):
- res = x
- array = [1, 2, 3]
- array[1] = 7
- idx = 0
- while y > 0:
- myjitdriver.can_enter_jit(idx=idx, y=y, x=x, res=res,
- array=array)
- myjitdriver.jit_merge_point(idx=idx, y=y, x=x, res=res,
- array=array)
- res = res.binop(x)
- res.val += array[idx] + array[1]
- if y < 7:
- idx = 2
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
- self.check_loop_count(9)
- self.check_loops(getarrayitem_gc=6, everywhere=True)
-
- def test_multiple_specialied_versions_bridge(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- class A(Base):
- def binop(self, other):
- return A(self.getval() + other.getval())
- class B(Base):
- def binop(self, other):
- return B(self.getval() * other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 7:
- x = z
- return res
- def g(x, y):
- a1 = f(A(x), y, A(x))
- a2 = f(A(x), y, A(x))
- assert a1.val == a2.val
- b1 = f(B(x), y, B(x))
- b2 = f(B(x), y, B(x))
- assert b1.val == b2.val
- c1 = f(B(x), y, A(x))
- c2 = f(B(x), y, A(x))
- assert c1.val == c2.val
- d1 = f(A(x), y, B(x))
- d2 = f(A(x), y, B(x))
- assert d1.val == d2.val
- return a1.val + b1.val + c1.val + d1.val
- res = self.meta_interp(g, [3, 14])
- assert res == g(3, 14)
-
- def test_failing_inlined_guard(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- class A(Base):
- def binop(self, other):
- return A(self.getval() + other.getval())
- class B(Base):
- def binop(self, other):
- return B(self.getval() * other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 8:
- x = z
- return res
- def g(x, y):
- c1 = f(A(x), y, B(x))
- c2 = f(A(x), y, B(x))
- assert c1.val == c2.val
- return c1.val
- res = self.meta_interp(g, [3, 16])
- assert res == g(3, 16)
-
- def test_inlined_guard_in_short_preamble(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- def binop(self, other):
- return A(self.getval() + other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 7:
- x = z
- return res
- def g(x, y):
- a1 = f(A(x), y, A(x))
- a2 = f(A(x), y, A(x))
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [3, 14])
- assert res == g(3, 14)
-
- def test_specialied_bridge(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def binop(self, other):
- return A(self.val + other.val)
- def f(x, y):
- res = A(0)
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- res = res.binop(A(y))
- if y<7:
- res = x
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
-
- def test_specialied_bridge_const(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'const', 'x', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def binop(self, other):
- return A(self.val + other.val)
- def f(x, y):
- res = A(0)
- const = 7
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const)
- myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const)
- const = hint(const, promote=True)
- res = res.binop(A(const))
- if y<7:
- res = x
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
-
- def test_multiple_specialied_zigzag(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- def switch(self):
- return B(self.val)
- class B(Base):
- def binop(self, other):
- return B(self.val * other.val)
- def switch(self):
- return A(self.val)
- def f(x, y):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- if y % 4 == 0:
- res = res.switch()
- res = res.binop(x)
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [3, 23])
- assert res == 7068153
- self.check_loop_count(6)
- self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
- guard_false=2)
-
- def test_dont_trace_every_iteration(self):
- myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
-
- def main(a, b):
- i = sa = 0
- #while i < 200:
- while i < 200:
- myjitdriver.can_enter_jit(a=a, b=b, i=i, sa=sa)
- myjitdriver.jit_merge_point(a=a, b=b, i=i, sa=sa)
- if a > 0: pass
- if b < 2: pass
- sa += a % b
- i += 1
- return sa
- def g():
- return main(10, 20) + main(-10, -20)
- res = self.meta_interp(g, [])
- assert res == g()
- self.check_enter_count(2)
-
- def test_current_trace_length(self):
- myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
- @dont_look_inside
- def residual():
- print "hi there"
- @unroll_safe
- def loop(g):
- y = 0
- while y < g:
- residual()
- y += 1
- def f(x, g):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, g=g)
- myjitdriver.jit_merge_point(x=x, g=g)
- loop(g)
- x -= 1
- n = current_trace_length()
- return n
- res = self.meta_interp(f, [5, 8])
- assert 14 < res < 42
- res = self.meta_interp(f, [5, 2])
- assert 4 < res < 14
-
- def test_compute_identity_hash(self):
- from pypy.rlib.objectmodel import compute_identity_hash
- class A(object):
- pass
- def f():
- a = A()
- return compute_identity_hash(a) == compute_identity_hash(a)
- res = self.interp_operations(f, [])
- assert res
- # a "did not crash" kind of test
-
- def test_compute_unique_id(self):
- from pypy.rlib.objectmodel import compute_unique_id
- class A(object):
- pass
- def f():
- a1 = A()
- a2 = A()
- return (compute_unique_id(a1) == compute_unique_id(a1) and
- compute_unique_id(a1) != compute_unique_id(a2))
- res = self.interp_operations(f, [])
- assert res
-
- def test_wrap_around_add(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x += 1
- n += 1
- return n
- res = self.meta_interp(f, [sys.maxint-10])
- assert res == 11
- self.check_tree_loop_count(2)
-
- def test_wrap_around_mul(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x *= 2
- n += 1
- return n
- res = self.meta_interp(f, [sys.maxint>>10])
- assert res == 11
- self.check_tree_loop_count(2)
-
- def test_wrap_around_sub(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x < 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x -= 1
- n += 1
- return n
- res = self.meta_interp(f, [10-sys.maxint])
- assert res == 12
- self.check_tree_loop_count(2)
-
-
-
-class TestOOtype(BasicTests, OOJitMixin):
-
- def test_oohash(self):
- def f(n):
- s = ootype.oostring(n, -1)
- return s.ll_hash()
- res = self.interp_operations(f, [5])
- assert res == ootype.oostring(5, -1).ll_hash()
-
- def test_identityhash(self):
- A = ootype.Instance("A", ootype.ROOT)
- def f():
- obj1 = ootype.new(A)
- obj2 = ootype.new(A)
- return ootype.identityhash(obj1) == ootype.identityhash(obj2)
- assert not f()
- res = self.interp_operations(f, [])
- assert not res
-
- def test_oois(self):
- A = ootype.Instance("A", ootype.ROOT)
- def f(n):
- obj1 = ootype.new(A)
- if n:
- obj2 = obj1
- else:
- obj2 = ootype.new(A)
- return obj1 is obj2
- res = self.interp_operations(f, [0])
- assert not res
- res = self.interp_operations(f, [1])
- assert res
-
- def test_oostring_instance(self):
- A = ootype.Instance("A", ootype.ROOT)
- B = ootype.Instance("B", ootype.ROOT)
- def f(n):
- obj1 = ootype.new(A)
- obj2 = ootype.new(B)
- s1 = ootype.oostring(obj1, -1)
- s2 = ootype.oostring(obj2, -1)
- ch1 = s1.ll_stritem_nonneg(1)
- ch2 = s2.ll_stritem_nonneg(1)
- return ord(ch1) + ord(ch2)
- res = self.interp_operations(f, [0])
- assert res == ord('A') + ord('B')
-
- def test_subclassof(self):
- A = ootype.Instance("A", ootype.ROOT)
- B = ootype.Instance("B", A)
- clsA = ootype.runtimeClass(A)
- clsB = ootype.runtimeClass(B)
- myjitdriver = JitDriver(greens = [], reds = ['n', 'flag', 'res'])
-
- def getcls(flag):
- if flag:
- return clsA
- else:
- return clsB
-
- def f(flag, n):
- res = True
- while n > -100:
- myjitdriver.can_enter_jit(n=n, flag=flag, res=res)
- myjitdriver.jit_merge_point(n=n, flag=flag, res=res)
- cls = getcls(flag)
- n -= 1
- res = ootype.subclassof(cls, clsB)
- return res
-
- res = self.meta_interp(f, [1, 100],
- policy=StopAtXPolicy(getcls),
- enable_opts='')
- assert not res
-
- res = self.meta_interp(f, [0, 100],
- policy=StopAtXPolicy(getcls),
- enable_opts='')
- assert res
-
-class BaseLLtypeTests(BasicTests):
-
- def test_identityhash(self):
- A = lltype.GcStruct("A")
- def f():
- obj1 = lltype.malloc(A)
- obj2 = lltype.malloc(A)
- return lltype.identityhash(obj1) == lltype.identityhash(obj2)
- assert not f()
- res = self.interp_operations(f, [])
- assert not res
-
- def test_oops_on_nongc(self):
- from pypy.rpython.lltypesystem import lltype
-
- TP = lltype.Struct('x')
- def f(i1, i2):
- p1 = prebuilt[i1]
- p2 = prebuilt[i2]
- a = p1 is p2
- b = p1 is not p2
- c = bool(p1)
- d = not bool(p2)
- return 1000*a + 100*b + 10*c + d
- prebuilt = [lltype.malloc(TP, flavor='raw', immortal=True)] * 2
- expected = f(0, 1)
- assert self.interp_operations(f, [0, 1]) == expected
-
- def test_casts(self):
- py.test.skip("xxx fix or kill")
- if not self.basic:
- py.test.skip("test written in a style that "
- "means it's frontend only")
- from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-
- TP = lltype.GcStruct('S1')
- def f(p):
- n = lltype.cast_ptr_to_int(p)
- return n
- x = lltype.malloc(TP)
- xref = lltype.cast_opaque_ptr(llmemory.GCREF, x)
- res = self.interp_operations(f, [xref])
- y = llmemory.cast_ptr_to_adr(x)
- y = llmemory.cast_adr_to_int(y)
- assert rffi.get_real_int(res) == rffi.get_real_int(y)
- #
- TP = lltype.Struct('S2')
- prebuilt = [lltype.malloc(TP, immortal=True),
- lltype.malloc(TP, immortal=True)]
- def f(x):
- p = prebuilt[x]
- n = lltype.cast_ptr_to_int(p)
- return n
- res = self.interp_operations(f, [1])
- y = llmemory.cast_ptr_to_adr(prebuilt[1])
- y = llmemory.cast_adr_to_int(y)
- assert rffi.get_real_int(res) == rffi.get_real_int(y)
-
- def test_collapsing_ptr_eq(self):
- S = lltype.GcStruct('S')
- p = lltype.malloc(S)
- driver = JitDriver(greens = [], reds = ['n', 'x'])
-
- def f(n, x):
- while n > 0:
- driver.can_enter_jit(n=n, x=x)
- driver.jit_merge_point(n=n, x=x)
- if x:
- n -= 1
- n -= 1
-
- def main():
- f(10, p)
- f(10, lltype.nullptr(S))
-
- self.meta_interp(main, [])
-
- def test_enable_opts(self):
- jitdriver = JitDriver(greens = [], reds = ['a'])
-
- class A(object):
- def __init__(self, i):
- self.i = i
-
- def f():
- a = A(0)
-
- while a.i < 10:
- jitdriver.jit_merge_point(a=a)
- jitdriver.can_enter_jit(a=a)
- a = A(a.i + 1)
-
- self.meta_interp(f, [])
- self.check_loops(new_with_vtable=0)
- self.meta_interp(f, [], enable_opts='')
- self.check_loops(new_with_vtable=1)
-
-class TestLLtype(BaseLLtypeTests, LLJitMixin):
- pass
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1,8 +1,8 @@
from __future__ import with_statement
import new
import py
-from pypy.objspace.flow.model import Constant, Block, Link, Variable, traverse
-from pypy.objspace.flow.model import flatten, mkentrymap, c_last_exception
+from pypy.objspace.flow.model import Constant, Block, Link, Variable
+from pypy.objspace.flow.model import mkentrymap, c_last_exception
from pypy.interpreter.argument import Arguments
from pypy.translator.simplify import simplify_graph
from pypy.objspace.flow.objspace import FlowObjSpace, error
@@ -37,12 +37,10 @@
def all_operations(self, graph):
result = {}
- def visit(node):
- if isinstance(node, Block):
- for op in node.operations:
- result.setdefault(op.opname, 0)
- result[op.opname] += 1
- traverse(visit, graph)
+ for node in graph.iterblocks():
+ for op in node.operations:
+ result.setdefault(op.opname, 0)
+ result[op.opname] += 1
return result
@@ -246,12 +244,9 @@
x = self.codetest(self.implicitException)
simplify_graph(x)
self.show(x)
- def cannot_reach_exceptblock(link):
- if isinstance(link, Link):
- assert link.target is not x.exceptblock
- traverse(cannot_reach_exceptblock, x)
+ for link in x.iterlinks():
+ assert link.target is not x.exceptblock
-
def implicitAttributeError(x):
try:
x = getattr(x, "y")
@@ -263,10 +258,8 @@
x = self.codetest(self.implicitAttributeError)
simplify_graph(x)
self.show(x)
- def cannot_reach_exceptblock(link):
- if isinstance(link, Link):
- assert link.target is not x.exceptblock
- traverse(cannot_reach_exceptblock, x)
+ for link in x.iterlinks():
+ assert link.target is not x.exceptblock
#__________________________________________________________
def implicitException_int_and_id(x):
@@ -311,14 +304,12 @@
simplify_graph(x)
self.show(x)
found = {}
- def find_exceptions(link):
- if isinstance(link, Link):
+ for link in x.iterlinks():
if link.target is x.exceptblock:
if isinstance(link.args[0], Constant):
found[link.args[0].value] = True
else:
found[link.exitcase] = None
- traverse(find_exceptions, x)
assert found == {IndexError: True, KeyError: True, Exception: None}
def reraiseAnything(x):
@@ -332,12 +323,10 @@
simplify_graph(x)
self.show(x)
found = {}
- def find_exceptions(link):
- if isinstance(link, Link):
+ for link in x.iterlinks():
if link.target is x.exceptblock:
assert isinstance(link.args[0], Constant)
found[link.args[0].value] = True
- traverse(find_exceptions, x)
assert found == {ValueError: True, ZeroDivisionError: True, OverflowError: True}
def loop_in_bare_except_bug(lst):
@@ -521,11 +510,9 @@
def test_jump_target_specialization(self):
x = self.codetest(self.jump_target_specialization)
- def visitor(node):
- if isinstance(node, Block):
- for op in node.operations:
- assert op.opname != 'mul', "mul should have disappeared"
- traverse(visitor, x)
+ for block in x.iterblocks():
+ for op in block.operations:
+ assert op.opname != 'mul', "mul should have disappeared"
#__________________________________________________________
def highly_branching_example(a,b,c,d,e,f,g,h,i,j):
@@ -573,7 +560,8 @@
def test_highly_branching_example(self):
x = self.codetest(self.highly_branching_example)
- assert len(flatten(x)) < 60 # roughly 20 blocks + 30 links
+ # roughly 20 blocks + 30 links
+ assert len(list(x.iterblocks())) + len(list(x.iterlinks())) < 60
#__________________________________________________________
def test_unfrozen_user_class1(self):
@@ -589,11 +577,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert len(results) == 2
def test_unfrozen_user_class2(self):
@@ -607,11 +593,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert not isinstance(results[0], Constant)
def test_frozen_user_class1(self):
@@ -630,11 +614,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert len(results) == 1
def test_frozen_user_class2(self):
@@ -650,11 +632,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert results == [Constant(4)]
def test_const_star_call(self):
@@ -663,14 +643,9 @@
def f():
return g(1,*(2,3))
graph = self.codetest(f)
- call_args = []
- def visit(block):
- if isinstance(block, Block):
- for op in block.operations:
- if op.opname == "call_args":
- call_args.append(op)
- traverse(visit, graph)
- assert not call_args
+ for block in graph.iterblocks():
+ for op in block.operations:
+ assert not op.opname == "call_args"
def test_catch_importerror_1(self):
def f():
@@ -997,11 +972,9 @@
simplify_graph(x)
self.show(x)
excfound = []
- def check(link):
- if isinstance(link, Link):
- if link.target is x.exceptblock:
- excfound.append(link.exitcase)
- traverse(check, x)
+ for link in x.iterlinks():
+ if link.target is x.exceptblock:
+ excfound.append(link.exitcase)
assert len(excfound) == 2
excfound.sort()
expected = [Exception, AttributeError]
@@ -1019,11 +992,9 @@
simplify_graph(x)
self.show(x)
excfound = []
- def check(link):
- if isinstance(link, Link):
- if link.target is x.exceptblock:
- excfound.append(link.exitcase)
- traverse(check, x)
+ for link in x.iterlinks():
+ if link.target is x.exceptblock:
+ excfound.append(link.exitcase)
assert len(excfound) == 2
excfound.sort()
expected = [Exception, TypeError]
diff --git a/lib_pypy/pypy_test/test_os_wait3.py b/lib_pypy/pypy_test/test_os_wait3.py
deleted file mode 100644
--- a/lib_pypy/pypy_test/test_os_wait3.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import os
-
-if hasattr(os, 'wait3'):
- def test_os_wait3():
- exit_status = 0x33
-
- if not hasattr(os, "fork"):
- skip("Need fork() to test wait3()")
-
- child = os.fork()
- if child == 0: # in child
- os._exit(exit_status)
- else:
- pid, status, rusage = os.wait3(0)
- assert child == pid
- assert os.WIFEXITED(status)
- assert os.WEXITSTATUS(status) == exit_status
- assert isinstance(rusage.ru_utime, float)
- assert isinstance(rusage.ru_maxrss, int)
diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py
--- a/pypy/translator/c/database.py
+++ b/pypy/translator/c/database.py
@@ -1,7 +1,7 @@
-from pypy.rpython.lltypesystem.lltype import \
- Primitive, Ptr, typeOf, RuntimeTypeInfo, \
- Struct, Array, FuncType, PyObject, Void, \
- ContainerType, OpaqueType, FixedSizeArray, _uninitialized
+
+from pypy.rpython.lltypesystem.lltype import (
+ Primitive, Ptr, typeOf, RuntimeTypeInfo, Struct, Array, FuncType, PyObject,
+ Void, ContainerType, OpaqueType, FixedSizeArray, _uninitialized, Typedef)
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rpython.lltypesystem.llmemory import WeakRef, _WeakRefType, GCREF
from pypy.rpython.lltypesystem.rffi import CConstant
@@ -100,6 +100,8 @@
def gettype(self, T, varlength=1, who_asks=None, argnames=[]):
if isinstance(T, Primitive) or T == GCREF:
return PrimitiveType[T]
+ elif isinstance(T, Typedef):
+ return '%s @' % T.c_name
elif isinstance(T, Ptr):
if (isinstance(T.TO, OpaqueType) and
T.TO.hints.get('c_pointer_typedef') is not None):
diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -20,8 +20,7 @@
separate_module_files=[cdir.join('src', 'll_math.c')],
export_symbols=['_pypy_math_acosh', '_pypy_math_asinh',
'_pypy_math_atanh',
- '_pypy_math_expm1', '_pypy_math_log1p',
- '_pypy_math_isinf', '_pypy_math_isnan'],
+ '_pypy_math_expm1', '_pypy_math_log1p'],
)
math_prefix = '_pypy_math_'
else:
@@ -58,7 +57,6 @@
math_hypot = llexternal(underscore + 'hypot',
[rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE)
math_isinf = math_llexternal('isinf', [rffi.DOUBLE], rffi.INT)
-math_isnan = math_llexternal('isnan', [rffi.DOUBLE], rffi.INT)
# ____________________________________________________________
#
@@ -91,13 +89,14 @@
#
# Custom implementations
- at jit.purefunction
def ll_math_isnan(y):
- return bool(math_isnan(y))
+ # By not calling into the extenal function the JIT can inline this. Floats
+ # are awesome.
+ return y != y
- at jit.purefunction
def ll_math_isinf(y):
- return bool(math_isinf(y))
+ # Use a bitwise OR so the JIT doesn't produce 2 different guards.
+ return (y == INFINITY) | (y == -INFINITY)
ll_math_copysign = math_copysign
diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py
--- a/pypy/jit/backend/x86/test/test_assembler.py
+++ b/pypy/jit/backend/x86/test/test_assembler.py
@@ -140,7 +140,7 @@
xmmregisters = lltype.malloc(rffi.LONGP.TO, 16+ACTUAL_CPU.NUM_REGS+1,
flavor='raw', immortal=True)
registers = rffi.ptradd(xmmregisters, 16)
- stacklen = baseloc + 10
+ stacklen = baseloc + 30
stack = lltype.malloc(rffi.LONGP.TO, stacklen, flavor='raw',
immortal=True)
expected_ints = [0] * len(content)
diff --git a/pypy/translator/backendopt/test/test_malloc.py b/pypy/translator/backendopt/test/test_malloc.py
--- a/pypy/translator/backendopt/test/test_malloc.py
+++ b/pypy/translator/backendopt/test/test_malloc.py
@@ -3,7 +3,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator import simplify
-from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap
+from pypy.objspace.flow.model import checkgraph, Block, mkentrymap
from pypy.rpython.llinterp import LLInterpreter
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
@@ -22,8 +22,7 @@
remover = cls.MallocRemover()
checkgraph(graph)
count1 = count2 = 0
- for node in flatten(graph):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname == cls.MallocRemover.MALLOC_OP:
S = op.args[0].value
@@ -47,7 +46,7 @@
auto_inline_graphs(t, t.graphs, inline)
if option.view:
t.view()
- # to detect missing keepalives and broken intermediate graphs,
+ # to detect broken intermediate graphs,
# we do the loop ourselves instead of calling remove_simple_mallocs()
while True:
progress = remover.remove_mallocs_once(graph)
@@ -158,18 +157,6 @@
type_system = 'lltype'
MallocRemover = LLTypeMallocRemover
- def test_with_keepalive(self):
- from pypy.rlib.objectmodel import keepalive_until_here
- def fn1(x, y):
- if x > 0:
- t = x+y, x-y
- else:
- t = x-y, x+y
- s, d = t
- keepalive_until_here(t)
- return s*d
- self.check(fn1, [int, int], [15, 10], 125)
-
def test_dont_remove_with__del__(self):
import os
delcalls = [0]
@@ -199,50 +186,6 @@
op = graph.startblock.exits[0].target.exits[1].target.operations[0]
assert op.opname == "malloc"
- def test_add_keepalives(self):
- class A:
- pass
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
- def fn7(i):
- big = lltype.malloc(BIG)
- a = A()
- a.big = big
- a.small = big.s
- a.small.x = 0
- while i > 0:
- a.small.x += i
- i -= 1
- return a.small.x
- self.check(fn7, [int], [10], 55, must_be_removed=False)
-
- def test_getsubstruct(self):
- py.test.skip("fails because of the interior structure changes")
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
-
- def fn(n1, n2):
- b = lltype.malloc(BIG)
- b.z = n1
- b.s.x = n2
- return b.z - b.s.x
-
- self.check(fn, [int, int], [100, 58], 42)
-
- def test_fixedsizearray(self):
- py.test.skip("fails because of the interior structure changes")
- A = lltype.FixedSizeArray(lltype.Signed, 3)
- S = lltype.GcStruct('S', ('a', A))
-
- def fn(n1, n2):
- s = lltype.malloc(S)
- a = s.a
- a[0] = n1
- a[2] = n2
- return a[0]-a[2]
-
- self.check(fn, [int, int], [100, 42], 58)
-
def test_wrapper_cannot_be_removed(self):
SMALL = lltype.OpaqueType('SMALL')
BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
diff --git a/pypy/translator/cli/test/test_list.py b/pypy/translator/cli/test/test_list.py
--- a/pypy/translator/cli/test/test_list.py
+++ b/pypy/translator/cli/test/test_list.py
@@ -7,7 +7,10 @@
def test_recursive(self):
py.test.skip("CLI doesn't support recursive lists")
- def test_getitem_exc(self):
+ def test_getitem_exc_1(self):
+ py.test.skip('fixme!')
+
+ def test_getitem_exc_2(self):
py.test.skip('fixme!')
def test_list_unsigned(self):
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
@@ -9,6 +9,7 @@
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rlib import rstack, rgc
from pypy.rlib.debug import ll_assert
+from pypy.rlib.objectmodel import we_are_translated
from pypy.translator.backendopt import graphanalyze
from pypy.translator.backendopt.support import var_needsgc
from pypy.annotation import model as annmodel
@@ -151,8 +152,13 @@
# for regular translation: pick the GC from the config
GCClass, GC_PARAMS = choose_gc_from_config(translator.config)
+ self.root_stack_jit_hook = None
if hasattr(translator, '_jit2gc'):
self.layoutbuilder = translator._jit2gc['layoutbuilder']
+ try:
+ self.root_stack_jit_hook = translator._jit2gc['rootstackhook']
+ except KeyError:
+ pass
else:
self.layoutbuilder = TransformerLayoutBuilder(translator, GCClass)
self.layoutbuilder.transformer = self
@@ -500,6 +506,10 @@
s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass)
r_gc = self.translator.rtyper.getrepr(s_gc)
self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
+ s_gc_data = self.translator.annotator.bookkeeper.valueoftype(
+ gctypelayout.GCData)
+ r_gc_data = self.translator.rtyper.getrepr(s_gc_data)
+ self.c_const_gcdata = rmodel.inputconst(r_gc_data, self.gcdata)
self.malloc_zero_filled = GCClass.malloc_zero_filled
HDR = self.HDR = self.gcdata.gc.gcheaderbuilder.HDR
@@ -786,6 +796,15 @@
resulttype=llmemory.Address)
hop.genop('adr_add', [v_gc_adr, c_ofs], resultvar=op.result)
+ def gct_gc_adr_of_root_stack_top(self, hop):
+ op = hop.spaceop
+ ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO,
+ 'inst_root_stack_top')
+ c_ofs = rmodel.inputconst(lltype.Signed, ofs)
+ v_gcdata_adr = hop.genop('cast_ptr_to_adr', [self.c_const_gcdata],
+ resulttype=llmemory.Address)
+ hop.genop('adr_add', [v_gcdata_adr, c_ofs], resultvar=op.result)
+
def gct_gc_x_swap_pool(self, hop):
op = hop.spaceop
[v_malloced] = op.args
@@ -1327,6 +1346,14 @@
return top
self.decr_stack = decr_stack
+ self.rootstackhook = gctransformer.root_stack_jit_hook
+ if self.rootstackhook is None:
+ def collect_stack_root(callback, gc, addr):
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ return sizeofaddr
+ self.rootstackhook = collect_stack_root
+
def push_stack(self, addr):
top = self.incr_stack(1)
top.address[0] = addr
@@ -1348,12 +1375,11 @@
def walk_stack_roots(self, collect_stack_root):
gcdata = self.gcdata
gc = self.gc
+ rootstackhook = self.rootstackhook
addr = gcdata.root_stack_base
end = gcdata.root_stack_top
while addr != end:
- if gc.points_to_valid_gc_object(addr):
- collect_stack_root(gc, addr)
- addr += sizeofaddr
+ addr += rootstackhook(collect_stack_root, gc, addr)
if self.collect_stacks_from_other_threads is not None:
self.collect_stacks_from_other_threads(collect_stack_root)
@@ -1460,12 +1486,11 @@
# collect all valid stacks from the dict (the entry
# corresponding to the current thread is not valid)
gc = self.gc
+ rootstackhook = self.rootstackhook
end = stacktop - sizeofaddr
addr = end.address[0]
while addr != end:
- if gc.points_to_valid_gc_object(addr):
- callback(gc, addr)
- addr += sizeofaddr
+ addr += rootstackhook(callback, gc, addr)
def collect_more_stacks(callback):
ll_assert(get_aid() == gcdata.active_thread,
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
@@ -19,7 +19,8 @@
from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
TempBox
-from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE, IS_X86_32, IS_X86_64
+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
class X86RegisterManager(RegisterManager):
@@ -34,6 +35,12 @@
esi: 2,
edi: 3,
}
+ REGLOC_TO_COPY_AREA_OFS = {
+ ecx: MY_COPY_OF_REGS + 0 * WORD,
+ ebx: MY_COPY_OF_REGS + 1 * WORD,
+ esi: MY_COPY_OF_REGS + 2 * WORD,
+ edi: MY_COPY_OF_REGS + 3 * WORD,
+ }
def call_result_location(self, v):
return eax
@@ -61,6 +68,19 @@
r14: 4,
r15: 5,
}
+ REGLOC_TO_COPY_AREA_OFS = {
+ ecx: MY_COPY_OF_REGS + 0 * WORD,
+ ebx: MY_COPY_OF_REGS + 1 * WORD,
+ esi: MY_COPY_OF_REGS + 2 * WORD,
+ edi: MY_COPY_OF_REGS + 3 * WORD,
+ r8: MY_COPY_OF_REGS + 4 * WORD,
+ r9: MY_COPY_OF_REGS + 5 * WORD,
+ r10: MY_COPY_OF_REGS + 6 * WORD,
+ r12: MY_COPY_OF_REGS + 7 * WORD,
+ r13: MY_COPY_OF_REGS + 8 * WORD,
+ r14: MY_COPY_OF_REGS + 9 * WORD,
+ r15: MY_COPY_OF_REGS + 10 * WORD,
+ }
class X86XMMRegisterManager(RegisterManager):
@@ -117,6 +137,16 @@
else:
return 1
+if WORD == 4:
+ gpr_reg_mgr_cls = X86RegisterManager
+ xmm_reg_mgr_cls = X86XMMRegisterManager
+elif WORD == 8:
+ gpr_reg_mgr_cls = X86_64_RegisterManager
+ xmm_reg_mgr_cls = X86_64_XMMRegisterManager
+else:
+ raise AssertionError("Word size should be 4 or 8")
+
+
class RegAlloc(object):
def __init__(self, assembler, translate_support_code=False):
@@ -135,16 +165,6 @@
# compute longevity of variables
longevity = self._compute_vars_longevity(inputargs, operations)
self.longevity = longevity
- # XXX
- if cpu.WORD == 4:
- gpr_reg_mgr_cls = X86RegisterManager
- xmm_reg_mgr_cls = X86XMMRegisterManager
- elif cpu.WORD == 8:
- gpr_reg_mgr_cls = X86_64_RegisterManager
- xmm_reg_mgr_cls = X86_64_XMMRegisterManager
- else:
- raise AssertionError("Word size should be 4 or 8")
-
self.rm = gpr_reg_mgr_cls(longevity,
frame_manager = self.fm,
assembler = self.assembler)
@@ -738,8 +758,12 @@
def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
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
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ save_all_regs = 2
self.rm.before_call(force_store, save_all_regs=save_all_regs)
- self.xrm.before_call(force_store, save_all_regs=save_all_regs)
if op.result is not None:
if op.result.type == FLOAT:
resloc = self.xrm.after_call(op.result)
@@ -836,31 +860,53 @@
self.PerformDiscard(op, arglocs)
self.rm.possibly_free_vars_for_op(op)
- def _fastpath_malloc(self, op, descr):
+ def fastpath_malloc_fixedsize(self, op, descr):
assert isinstance(descr, BaseSizeDescr)
+ self._do_fastpath_malloc(op, descr.size, descr.tid)
+
+ def fastpath_malloc_varsize(self, op, arraydescr, num_elem):
+ assert isinstance(arraydescr, BaseArrayDescr)
+ 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
+ self._do_fastpath_malloc(op, size, arraydescr.tid)
+ self.assembler.set_new_array_length(eax, ofs_length, imm(num_elem))
+
+ def _do_fastpath_malloc(self, op, size, tid):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
self.rm.force_allocate_reg(op.result, selected_reg=eax)
- # We need to force-allocate each of save_around_call_regs now.
- # The alternative would be to save and restore them around the
- # actual call to malloc(), in the rare case where we need to do
- # it; however, mark_gc_roots() would need to be adapted to know
- # where the variables end up being saved. Messy.
- for reg in self.rm.save_around_call_regs:
- if reg is not eax:
- tmp_box = TempBox()
- self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
- self.rm.possibly_free_var(tmp_box)
- self.assembler.malloc_cond_fixedsize(
+ if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack:
+ # ---- shadowstack ----
+ # We need edx as a temporary, but otherwise don't save any more
+ # register. See comments in _build_malloc_slowpath().
+ tmp_box = TempBox()
+ self.rm.force_allocate_reg(tmp_box, selected_reg=edx)
+ self.rm.possibly_free_var(tmp_box)
+ else:
+ # ---- asmgcc ----
+ # We need to force-allocate each of save_around_call_regs now.
+ # The alternative would be to save and restore them around the
+ # actual call to malloc(), in the rare case where we need to do
+ # it; however, mark_gc_roots() would need to be adapted to know
+ # where the variables end up being saved. Messy.
+ for reg in self.rm.save_around_call_regs:
+ if reg is not eax:
+ tmp_box = TempBox()
+ self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
+ self.rm.possibly_free_var(tmp_box)
+
+ self.assembler.malloc_cond(
gc_ll_descr.get_nursery_free_addr(),
gc_ll_descr.get_nursery_top_addr(),
- descr.size, descr.tid,
+ size, tid,
)
def consider_new(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.can_inline_malloc(op.getdescr()):
- self._fastpath_malloc(op, op.getdescr())
+ self.fastpath_malloc_fixedsize(op, op.getdescr())
else:
args = gc_ll_descr.args_for_new(op.getdescr())
arglocs = [imm(x) for x in args]
@@ -870,7 +916,7 @@
classint = op.getarg(0).getint()
descrsize = heaptracker.vtable2descr(self.assembler.cpu, classint)
if self.assembler.cpu.gc_ll_descr.can_inline_malloc(descrsize):
- self._fastpath_malloc(op, descrsize)
+ self.fastpath_malloc_fixedsize(op, descrsize)
self.assembler.set_vtable(eax, imm(classint))
# result of fastpath malloc is in eax
else:
@@ -929,16 +975,25 @@
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.get_funcptr_for_newarray is not None:
# framework GC
- args = self.assembler.cpu.gc_ll_descr.args_for_new_array(op.getdescr())
+ 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(op.getarg(0)))
- return self._call(op, arglocs)
+ 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)
- return self._malloc_varsize(basesize, ofs_length, scale_of_field,
- op.getarg(0), op.result)
+ self._malloc_varsize(basesize, ofs_length, scale_of_field,
+ op.getarg(0), op.result)
def _unpack_arraydescr(self, arraydescr):
assert isinstance(arraydescr, BaseArrayDescr)
@@ -1132,7 +1187,7 @@
# call memcpy()
self.rm.before_call()
self.xrm.before_call()
- self.assembler._emit_call(imm(self.assembler.memcpy_addr),
+ self.assembler._emit_call(-1, imm(self.assembler.memcpy_addr),
[dstaddr_loc, srcaddr_loc, length_loc])
self.rm.possibly_free_var(length_box)
self.rm.possibly_free_var(dstaddr_box)
@@ -1200,18 +1255,24 @@
def consider_jit_debug(self, op):
pass
- def get_mark_gc_roots(self, gcrootmap):
+ def get_mark_gc_roots(self, gcrootmap, use_copy_area=False):
shape = gcrootmap.get_basic_shape(IS_X86_64)
for v, val in self.fm.frame_bindings.items():
if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
assert isinstance(val, StackLoc)
- gcrootmap.add_ebp_offset(shape, get_ebp_ofs(val.position))
+ gcrootmap.add_frame_offset(shape, get_ebp_ofs(val.position))
for v, reg in self.rm.reg_bindings.items():
if reg is eax:
continue # ok to ignore this one
if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
- assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX
- gcrootmap.add_callee_save_reg(shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg])
+ if use_copy_area:
+ assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS
+ area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg]
+ gcrootmap.add_frame_offset(shape, area_offset)
+ else:
+ assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX
+ gcrootmap.add_callee_save_reg(
+ shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg])
return gcrootmap.compress_callshape(shape,
self.assembler.datablockwrapper)
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -46,6 +46,7 @@
import pypy.module.cpyext.complexobject
import pypy.module.cpyext.weakrefobject
import pypy.module.cpyext.funcobject
+import pypy.module.cpyext.frameobject
import pypy.module.cpyext.classobject
import pypy.module.cpyext.pypyintf
import pypy.module.cpyext.memoryobject
diff --git a/pypy/translator/backendopt/mallocprediction.py b/pypy/translator/backendopt/mallocprediction.py
--- a/pypy/translator/backendopt/mallocprediction.py
+++ b/pypy/translator/backendopt/mallocprediction.py
@@ -176,7 +176,6 @@
break
count += newcount
for graph in graphs:
- removenoops.remove_superfluous_keep_alive(graph)
removenoops.remove_duplicate_casts(graph, translator)
return count
diff --git a/pypy/jit/tl/pypyjit_child.py b/pypy/jit/tl/pypyjit_child.py
--- a/pypy/jit/tl/pypyjit_child.py
+++ b/pypy/jit/tl/pypyjit_child.py
@@ -2,7 +2,6 @@
from pypy.rpython.lltypesystem import lltype
from pypy.jit.metainterp import warmspot
from pypy.module.pypyjit.policy import PyPyJitPolicy
-from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_NO_UNROLL
def run_child(glob, loc):
@@ -34,6 +33,5 @@
option.view = True
warmspot.jittify_and_run(interp, graph, [], policy=policy,
listops=True, CPUClass=CPUClass,
- backendopt=True, inline=True,
- optimizer=OPTIMIZER_FULL)
+ backendopt=True, inline=True)
diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py
--- a/pypy/translator/goal/translate.py
+++ b/pypy/translator/goal/translate.py
@@ -285,6 +285,15 @@
elif drv.exe_name is None and '__name__' in targetspec_dic:
drv.exe_name = targetspec_dic['__name__'] + '-%(backend)s'
+ # Double check to ensure we are not overwriting the current interpreter
+ try:
+ exe_name = str(drv.compute_exe_name())
+ assert not os.path.samefile(exe_name, sys.executable), (
+ 'Output file %r is the currently running '
+ 'interpreter (use --output=...)'% exe_name)
+ except OSError:
+ pass
+
goals = translateconfig.goals
try:
drv.proceed(goals)
diff --git a/pypy/jit/codewriter/test/test_regalloc.py b/pypy/jit/codewriter/test/test_regalloc.py
--- a/pypy/jit/codewriter/test/test_regalloc.py
+++ b/pypy/jit/codewriter/test/test_regalloc.py
@@ -9,7 +9,6 @@
from pypy.objspace.flow.model import c_last_exception
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rlib.objectmodel import keepalive_until_here
class TestRegAlloc:
diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py
--- a/pypy/rpython/test/test_rdict.py
+++ b/pypy/rpython/test/test_rdict.py
@@ -578,6 +578,26 @@
res = self.interpret(fn, [3, 3])
assert res == 123
+ def test_dict_popitem(self):
+ def func():
+ d = {}
+ d[5] = 2
+ d[6] = 3
+ k1, v1 = d.popitem()
+ assert len(d) == 1
+ k2, v2 = d.popitem()
+ try:
+ d.popitem()
+ except KeyError:
+ pass
+ else:
+ assert 0, "should have raised KeyError"
+ assert len(d) == 0
+ return k1*1000 + v1*100 + k2*10 + v2
+
+ res = self.interpret(func, [])
+ assert res in [5263, 6352]
+
class TestLLtype(BaseTestRdict, LLRtypeMixin):
def test_dict_but_not_with_char_keys(self):
@@ -682,26 +702,6 @@
# if it does not crash, we are fine. It crashes if you forget the hash field.
self.interpret(func, [])
- def test_dict_popitem(self):
- def func():
- d = {}
- d[5] = 2
- d[6] = 3
- k1, v1 = d.popitem()
- assert len(d) == 1
- k2, v2 = d.popitem()
- try:
- d.popitem()
- except KeyError:
- pass
- else:
- assert 0, "should have raised KeyError"
- assert len(d) == 0
- return k1*1000 + v1*100 + k2*10 + v2
-
- res = self.interpret(func, [])
- assert res in [5263, 6352]
-
# ____________________________________________________________
def test_opt_nullkeymarker(self):
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -746,6 +746,7 @@
def charpsize2str(cp, size):
l = [cp[i] for i in range(size)]
return emptystr.join(l)
+ charpsize2str._annenforceargs_ = [None, int]
return (str2charp, free_charp, charp2str,
get_nonmovingbuffer, free_nonmovingbuffer,
@@ -817,6 +818,8 @@
"""Similar to llmemory.sizeof() but tries hard to return a integer
instead of a symbolic value.
"""
+ if isinstance(tp, lltype.Typedef):
+ tp = tp.OF
if isinstance(tp, lltype.FixedSizeArray):
return sizeof(tp.OF) * tp.length
if isinstance(tp, lltype.Struct):
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -110,6 +110,8 @@
#include "intobject.h"
#include "listobject.h"
#include "unicodeobject.h"
+#include "compile.h"
+#include "frameobject.h"
#include "eval.h"
#include "pymem.h"
#include "pycobject.h"
diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py
--- a/pypy/translator/backendopt/removenoops.py
+++ b/pypy/translator/backendopt/removenoops.py
@@ -108,15 +108,3 @@
for i, op in list(enumerate(block.operations))[::-1]:
if op.opname == "debug_assert":
del block.operations[i]
-
-def remove_superfluous_keep_alive(graph):
- for block in graph.iterblocks():
- used = {}
- for i, op in list(enumerate(block.operations))[::-1]:
- if op.opname == "keepalive":
- if op.args[0] in used:
- del block.operations[i]
- else:
- used[op.args[0]] = True
-
-
diff --git a/pypy/rpython/test/test_rbuiltin.py b/pypy/rpython/test/test_rbuiltin.py
--- a/pypy/rpython/test/test_rbuiltin.py
+++ b/pypy/rpython/test/test_rbuiltin.py
@@ -496,6 +496,13 @@
res = self.interpret(llf, [rffi.r_short(123)], policy=LowLevelAnnotatorPolicy())
assert res == 123
+ def test_force_cast(self):
+ def llfn(v):
+ return rffi.cast(rffi.SHORT, v)
+ res = self.interpret(llfn, [0x12345678])
+ assert res == 0x5678
+
+
class TestLLtype(BaseTestRbuiltin, LLRtypeMixin):
def test_isinstance_obj(self):
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -12,7 +12,6 @@
W_IOBase, DEFAULT_BUFFER_SIZE, convert_size,
check_readable_w, check_writable_w, check_seekable_w)
from pypy.module._io.interp_io import W_BlockingIOError
-from pypy.module.thread.os_lock import Lock
STATE_ZERO, STATE_OK, STATE_DETACHED = range(3)
@@ -121,7 +120,7 @@
## XXX cannot free a Lock?
## if self.lock:
## self.lock.free()
- self.lock = Lock(space)
+ self.lock = space.allocate_lock()
try:
self._raw_tell(space)
diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py
--- a/pypy/jit/backend/x86/test/test_gc_integration.py
+++ b/pypy/jit/backend/x86/test/test_gc_integration.py
@@ -26,9 +26,10 @@
CPU = getcpuclass()
class MockGcRootMap(object):
+ is_shadow_stack = False
def get_basic_shape(self, is_64_bit):
return ['shape']
- def add_ebp_offset(self, shape, offset):
+ def add_frame_offset(self, shape, offset):
shape.append(offset)
def add_callee_save_reg(self, shape, reg_index):
index_to_name = { 1: 'ebx', 2: 'esi', 3: 'edi' }
@@ -44,7 +45,8 @@
get_funcptr_for_newarray = get_funcptr_for_new
get_funcptr_for_newstr = get_funcptr_for_new
get_funcptr_for_newunicode = get_funcptr_for_new
-
+ get_malloc_slowpath_addr = None
+
moving_gc = True
gcrootmap = MockGcRootMap()
@@ -166,26 +168,29 @@
class GCDescrFastpathMalloc(GcLLDescription):
gcrootmap = None
-
+ expected_malloc_slowpath_size = WORD*2
+
def __init__(self):
GcCache.__init__(self, False)
# create a nursery
NTP = rffi.CArray(lltype.Signed)
self.nursery = lltype.malloc(NTP, 16, flavor='raw')
- self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2,
+ self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 3,
flavor='raw')
self.addrs[0] = rffi.cast(lltype.Signed, self.nursery)
- self.addrs[1] = self.addrs[0] + 64
- # 64 bytes
+ self.addrs[1] = self.addrs[0] + 16*WORD
+ self.addrs[2] = 0
+ # 16 WORDs
def malloc_slowpath(size):
- assert size == WORD*2
+ assert size == self.expected_malloc_slowpath_size
nadr = rffi.cast(lltype.Signed, self.nursery)
self.addrs[0] = nadr + size
+ self.addrs[2] += 1
return nadr
self.malloc_slowpath = malloc_slowpath
self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed],
lltype.Signed)
- self._counter = 123
+ self._counter = 123000
def can_inline_malloc(self, descr):
return True
@@ -204,7 +209,7 @@
def get_nursery_top_addr(self):
return rffi.cast(lltype.Signed, self.addrs) + WORD
- def get_malloc_fixedsize_slowpath_addr(self):
+ def get_malloc_slowpath_addr(self):
fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
return rffi.cast(lltype.Signed, fptr)
@@ -220,9 +225,11 @@
cpu.gc_ll_descr = GCDescrFastpathMalloc()
cpu.setup_once()
- NODE = lltype.Struct('node', ('tid', lltype.Signed),
- ('value', lltype.Signed))
- nodedescr = cpu.sizeof(NODE) # xxx hack: NODE is not a GcStruct
+ # hack: specify 'tid' explicitly, because this test is not running
+ # with the gc transformer
+ NODE = lltype.GcStruct('node', ('tid', lltype.Signed),
+ ('value', lltype.Signed))
+ nodedescr = cpu.sizeof(NODE)
valuedescr = cpu.fielddescrof(NODE, 'value')
self.cpu = cpu
@@ -254,6 +261,7 @@
assert gc_ll_descr.nursery[1] == 42
nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*2)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
def test_malloc_slowpath(self):
ops = '''
@@ -274,6 +282,7 @@
gc_ll_descr = self.cpu.gc_ll_descr
nadr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nadr + (WORD*2)
+ assert gc_ll_descr.addrs[2] == 1 # slowpath called once
def test_new_with_vtable(self):
ops = '''
@@ -289,3 +298,93 @@
assert gc_ll_descr.nursery[1] == self.vtable_int
nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*3)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
+
+
+class Seen(Exception):
+ pass
+
+class GCDescrFastpathMallocVarsize(GCDescrFastpathMalloc):
+ def can_inline_malloc_varsize(self, arraydescr, num_elem):
+ return num_elem < 5
+ def get_funcptr_for_newarray(self):
+ return 52
+ def init_array_descr(self, A, descr):
+ descr.tid = self._counter
+ self._counter += 1
+ def args_for_new_array(self, descr):
+ raise Seen("args_for_new_array")
+
+class TestMallocVarsizeFastpath(BaseTestRegalloc):
+ def setup_method(self, method):
+ cpu = CPU(None, None)
+ cpu.vtable_offset = WORD
+ cpu.gc_ll_descr = GCDescrFastpathMallocVarsize()
+ cpu.setup_once()
+ self.cpu = cpu
+
+ ARRAY = lltype.GcArray(lltype.Signed)
+ arraydescr = cpu.arraydescrof(ARRAY)
+ self.arraydescr = arraydescr
+
+ self.namespace = locals().copy()
+
+ def test_malloc_varsize_fastpath(self):
+ # Hack. Running the GcLLDescr_framework without really having
+ # a complete GC means that we end up with both the tid and the
+ # length being at offset 0. In this case, so the length overwrites
+ # the tid. This is of course only the case in this test class.
+ ops = '''
+ []
+ p0 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p0, 0, 142, descr=arraydescr)
+ setarrayitem_gc(p0, 3, 143, descr=arraydescr)
+ finish(p0)
+ '''
+ self.interpret(ops, [])
+ # check the nursery
+ gc_ll_descr = self.cpu.gc_ll_descr
+ assert gc_ll_descr.nursery[0] == 4
+ assert gc_ll_descr.nursery[1] == 142
+ assert gc_ll_descr.nursery[4] == 143
+ nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+ assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*5)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
+
+ def test_malloc_varsize_slowpath(self):
+ ops = '''
+ []
+ p0 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p0, 0, 420, descr=arraydescr)
+ setarrayitem_gc(p0, 3, 430, descr=arraydescr)
+ p1 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p1, 0, 421, descr=arraydescr)
+ setarrayitem_gc(p1, 3, 431, descr=arraydescr)
+ p2 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p2, 0, 422, descr=arraydescr)
+ setarrayitem_gc(p2, 3, 432, descr=arraydescr)
+ p3 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p3, 0, 423, descr=arraydescr)
+ setarrayitem_gc(p3, 3, 433, descr=arraydescr)
+ finish(p0, p1, p2, p3)
+ '''
+ gc_ll_descr = self.cpu.gc_ll_descr
+ gc_ll_descr.expected_malloc_slowpath_size = 5*WORD
+ self.interpret(ops, [])
+ assert gc_ll_descr.addrs[2] == 1 # slowpath called once
+
+ def test_malloc_varsize_too_big(self):
+ ops = '''
+ []
+ p0 = new_array(5, descr=arraydescr)
+ finish(p0)
+ '''
+ py.test.raises(Seen, self.interpret, ops, [])
+
+ def test_malloc_varsize_variable(self):
+ ops = '''
+ [i0]
+ p0 = new_array(i0, descr=arraydescr)
+ finish(p0)
+ '''
+ py.test.raises(Seen, self.interpret, ops, [])
diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py
--- a/pypy/interpreter/test/test_interpreter.py
+++ b/pypy/interpreter/test/test_interpreter.py
@@ -283,9 +283,14 @@
sys.stdout = out = Out()
try:
raises(UnicodeError, "print unichr(0xa2)")
+ assert out.data == []
out.encoding = "cp424"
print unichr(0xa2)
assert out.data == [unichr(0xa2).encode("cp424"), "\n"]
+ del out.data[:]
+ del out.encoding
+ print u"foo\t", u"bar\n", u"trick", u"baz\n" # softspace handling
+ assert out.data == ["foo\t", "bar\n", "trick", " ", "baz\n", "\n"]
finally:
sys.stdout = save
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -35,7 +35,8 @@
def test_load_dynamic(self):
raises(ImportError, self.imp.load_dynamic, 'foo', 'bar')
- raises(ImportError, self.imp.load_dynamic, 'foo', 'bar', 'baz.so')
+ raises(ImportError, self.imp.load_dynamic, 'foo', 'bar',
+ open(self.file_module))
def test_suffixes(self):
for suffix, mode, type in self.imp.get_suffixes():
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -112,6 +112,7 @@
try:
while True:
count = fread(buf, 1, BUF_SIZE, fp)
+ count = rffi.cast(lltype.Signed, count)
source += rffi.charpsize2str(buf, count)
if count < BUF_SIZE:
if feof(fp):
diff --git a/pypy/module/cpyext/test/test_pystate.py b/pypy/module/cpyext/test/test_pystate.py
--- a/pypy/module/cpyext/test/test_pystate.py
+++ b/pypy/module/cpyext/test/test_pystate.py
@@ -29,20 +29,14 @@
state = api.PyInterpreterState_Head()
assert nullptr(PyInterpreterState.TO) == api.PyInterpreterState_Next(state)
-def clear_threadstate(space):
- # XXX: this should collect the ThreadState memory
- del space.getexecutioncontext().cpyext_threadstate
-
class TestThreadState(BaseApiTest):
def test_thread_state_get(self, space, api):
ts = api.PyThreadState_Get()
assert ts != nullptr(PyThreadState.TO)
- clear_threadstate(space)
def test_thread_state_interp(self, space, api):
ts = api.PyThreadState_Get()
assert ts.c_interp == api.PyInterpreterState_Head()
- clear_threadstate(space)
def test_basic_threadstate_dance(self, space, api):
# Let extension modules call these functions,
@@ -54,5 +48,3 @@
api.PyEval_AcquireThread(tstate)
api.PyEval_ReleaseThread(tstate)
-
- clear_threadstate(space)
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -91,9 +91,10 @@
else:
# XXX that's slow
def case_ok(filename):
- index1 = filename.rfind(os.sep)
- index2 = filename.rfind(os.altsep)
- index = max(index1, index2)
+ index = filename.rfind(os.sep)
+ if os.altsep is not None:
+ index2 = filename.rfind(os.altsep)
+ index = max(index, index2)
if index < 0:
directory = os.curdir
else:
diff --git a/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
--- a/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
+++ b/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
@@ -18,7 +18,6 @@
def should_skip_instruction(self, instrname, argmodes):
return (
super(TestRx86_64, self).should_skip_instruction(instrname, argmodes) or
- ('j' in argmodes) or
# Not testing FSTP on 64-bit for now
(instrname == 'FSTP')
)
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -311,8 +311,7 @@
# EggBlocks reuse the variables of their previous block,
# which is deemed not acceptable for simplicity of the operations
# that will be performed later on the flow graph.
- def fixegg(link):
- if isinstance(link, Link):
+ for link in list(self.graph.iterlinks()):
block = link.target
if isinstance(block, EggBlock):
if (not block.operations and len(block.exits) == 1 and
@@ -324,15 +323,14 @@
link.args = list(link2.args)
link.target = link2.target
assert link2.exitcase is None
- fixegg(link)
else:
mapping = {}
for a in block.inputargs:
mapping[a] = Variable(a)
block.renamevariables(mapping)
- elif isinstance(link, SpamBlock):
+ for block in self.graph.iterblocks():
+ if isinstance(link, SpamBlock):
del link.framestate # memory saver
- traverse(fixegg, self.graph)
def mergeblock(self, currentblock, currentstate):
next_instr = currentstate.next_instr
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
@@ -18,12 +18,33 @@
descr_t = get_size_descr(c0, T)
assert descr_s.size == symbolic.get_size(S, False)
assert descr_t.size == symbolic.get_size(T, False)
+ assert descr_s.count_fields_if_immutable() == -1
+ assert descr_t.count_fields_if_immutable() == -1
assert descr_s == get_size_descr(c0, S)
assert descr_s != get_size_descr(c1, S)
#
descr_s = get_size_descr(c1, S)
assert isinstance(descr_s.size, Symbolic)
+ assert descr_s.count_fields_if_immutable() == -1
+def test_get_size_descr_immut():
+ S = lltype.GcStruct('S', hints={'immutable': True})
+ T = lltype.GcStruct('T', ('parent', S),
+ ('x', lltype.Char),
+ hints={'immutable': True})
+ U = lltype.GcStruct('U', ('parent', T),
+ ('u', lltype.Ptr(T)),
+ ('v', lltype.Signed),
+ hints={'immutable': True})
+ V = lltype.GcStruct('V', ('parent', U),
+ ('miss1', lltype.Void),
+ ('miss2', lltype.Void),
+ hints={'immutable': True})
+ for STRUCT, expected in [(S, 0), (T, 1), (U, 3), (V, 3)]:
+ for translated in [False, True]:
+ c0 = GcCache(translated)
+ descr_s = get_size_descr(c0, STRUCT)
+ assert descr_s.count_fields_if_immutable() == expected
def test_get_field_descr():
U = lltype.Struct('U')
diff --git a/pypy/translator/backendopt/mallocv.py b/pypy/translator/backendopt/mallocv.py
--- a/pypy/translator/backendopt/mallocv.py
+++ b/pypy/translator/backendopt/mallocv.py
@@ -846,22 +846,6 @@
else:
return self.handle_default(op)
- def handle_op_keepalive(self, op):
- node = self.getnode(op.args[0])
- if isinstance(node, VirtualSpecNode):
- rtnodes, vtnodes = find_all_nodes([node])
- newops = []
- for rtnode in rtnodes:
- v = self.renamings[rtnode]
- if isinstance(v, Variable):
- T = v.concretetype
- if isinstance(T, lltype.Ptr) and T._needsgc():
- v0 = varoftype(lltype.Void)
- newops.append(SpaceOperation('keepalive', [v], v0))
- return newops
- else:
- return self.handle_default(op)
-
def handle_op_ptr_nonzero(self, op):
node = self.getnode(op.args[0])
if isinstance(node, VirtualSpecNode):
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
@@ -43,9 +43,14 @@
class SizeDescr(AbstractDescr):
size = 0 # help translation
+ is_immutable = False
- def __init__(self, size):
+ def __init__(self, size, count_fields_if_immut=-1):
self.size = size
+ self.count_fields_if_immut = count_fields_if_immut
+
+ def count_fields_if_immutable(self):
+ return self.count_fields_if_immut
def repr_of_descr(self):
return '<SizeDescr %s>' % self.size
@@ -62,15 +67,15 @@
return cache[STRUCT]
except KeyError:
size = symbolic.get_size(STRUCT, gccache.translate_support_code)
+ count_fields_if_immut = heaptracker.count_fields_if_immutable(STRUCT)
if heaptracker.has_gcstruct_a_vtable(STRUCT):
- sizedescr = SizeDescrWithVTable(size)
+ sizedescr = SizeDescrWithVTable(size, count_fields_if_immut)
else:
- sizedescr = SizeDescr(size)
+ sizedescr = SizeDescr(size, count_fields_if_immut)
gccache.init_size_descr(STRUCT, sizedescr)
cache[STRUCT] = sizedescr
return sizedescr
-
# ____________________________________________________________
# FieldDescrs
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -283,9 +283,15 @@
# These are the worst cases:
val2 = loc2.value_i()
code1 = loc1.location_code()
- if (code1 == 'j'
- or (code1 == 'm' and not rx86.fits_in_32bits(loc1.value_m()[1]))
- or (code1 == 'a' and not rx86.fits_in_32bits(loc1.value_a()[3]))):
+ if code1 == 'j':
+ checkvalue = loc1.value_j()
+ elif code1 == 'm':
+ checkvalue = loc1.value_m()[1]
+ elif code1 == 'a':
+ checkvalue = loc1.value_a()[3]
+ else:
+ checkvalue = 0
+ if not rx86.fits_in_32bits(checkvalue):
# INSN_ji, and both operands are 64-bit; or INSN_mi or INSN_ai
# and the constant offset in the address is 64-bit.
# Hopefully this doesn't happen too often
@@ -330,10 +336,10 @@
if code1 == possible_code1:
val1 = getattr(loc1, "value_" + possible_code1)()
# More faking out of certain operations for x86_64
- if self.WORD == 8 and possible_code1 == 'j':
+ if possible_code1 == 'j' and not rx86.fits_in_32bits(val1):
val1 = self._addr_as_reg_offset(val1)
invoke(self, "m" + possible_code2, val1, val2)
- elif self.WORD == 8 and possible_code2 == 'j':
+ elif possible_code2 == 'j' and not rx86.fits_in_32bits(val2):
val2 = self._addr_as_reg_offset(val2)
invoke(self, possible_code1 + "m", val1, val2)
elif possible_code1 == 'm' and not rx86.fits_in_32bits(val1[1]):
@@ -378,6 +384,10 @@
_rx86_getattr(self, name + "_l")(val)
self.add_pending_relocation()
else:
+ # xxx can we avoid "MOV r11, $val; JMP/CALL *r11"
+ # in case it would fit a 32-bit displacement?
+ # Hard, because we don't know yet where this insn
+ # will end up...
assert self.WORD == 8
self._load_scratch(val)
_rx86_getattr(self, name + "_r")(X86_64_SCRATCH_REG.value)
diff --git a/pypy/translator/backendopt/test/test_tailrecursion.py b/pypy/translator/backendopt/test/test_tailrecursion.py
--- a/pypy/translator/backendopt/test/test_tailrecursion.py
+++ b/pypy/translator/backendopt/test/test_tailrecursion.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.translator.backendopt.tailrecursion import remove_tail_calls_to_self
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.llinterp import LLInterpreter
diff --git a/pypy/module/cpyext/test/comparisons.c b/pypy/module/cpyext/test/comparisons.c
--- a/pypy/module/cpyext/test/comparisons.c
+++ b/pypy/module/cpyext/test/comparisons.c
@@ -69,12 +69,31 @@
};
+static int cmp_compare(PyObject *self, PyObject *other) {
+ return -1;
+}
+
+PyTypeObject OldCmpType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "comparisons.OldCmpType", /* tp_name */
+ sizeof(CmpObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)cmp_compare, /* tp_compare */
+};
+
+
void initcomparisons(void)
{
PyObject *m, *d;
if (PyType_Ready(&CmpType) < 0)
return;
+ if (PyType_Ready(&OldCmpType) < 0)
+ return;
m = Py_InitModule("comparisons", NULL);
if (m == NULL)
return;
@@ -83,4 +102,6 @@
return;
if (PyDict_SetItemString(d, "CmpType", (PyObject *)&CmpType) < 0)
return;
+ if (PyDict_SetItemString(d, "OldCmpType", (PyObject *)&OldCmpType) < 0)
+ return;
}
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -262,6 +262,8 @@
signal(SIGALRM, SIG_DFL)
class AppTestItimer:
+ spaceconfig = dict(usemodules=['signal'])
+
def test_itimer_real(self):
import signal
diff --git a/pypy/translator/c/src/ll_math.c b/pypy/translator/c/src/ll_math.c
--- a/pypy/translator/c/src/ll_math.c
+++ b/pypy/translator/c/src/ll_math.c
@@ -22,18 +22,6 @@
#endif
#define PyPy_NAN (HUGE_VAL * 0.)
-int
-_pypy_math_isinf(double x)
-{
- return PyPy_IS_INFINITY(x);
-}
-
-int
-_pypy_math_isnan(double x)
-{
- return PyPy_IS_NAN(x);
-}
-
/* The following copyright notice applies to the original
implementations of acosh, asinh and atanh. */
diff --git a/pypy/rpython/lltypesystem/test/test_lltype.py b/pypy/rpython/lltypesystem/test/test_lltype.py
--- a/pypy/rpython/lltypesystem/test/test_lltype.py
+++ b/pypy/rpython/lltypesystem/test/test_lltype.py
@@ -804,6 +804,21 @@
hints={'immutable_fields': FieldListAccessor({'x':'[*]'})})
assert S._immutable_field('x') == '[*]'
+def test_typedef():
+ T = Typedef(Signed, 'T')
+ assert T == Signed
+ assert Signed == T
+ T2 = Typedef(T, 'T2')
+ assert T2 == T
+ assert T2.OF is Signed
+ py.test.raises(TypeError, Ptr, T)
+ assert rffi.CArrayPtr(T) == rffi.CArrayPtr(Signed)
+ assert rffi.CArrayPtr(Signed) == rffi.CArrayPtr(T)
+
+ F = FuncType((T,), T)
+ assert F.RESULT == Signed
+ assert F.ARGS == (Signed,)
+
class TestTrackAllocation:
def test_automatic_tracking(self):
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
@@ -153,10 +153,10 @@
for op in self._ops_for_chunk(chunk, include_debug_merge_points):
yield op
- def match(self, expected_src):
+ def match(self, expected_src, **kwds):
ops = list(self.allops())
matcher = OpMatcher(ops, src=self.format_ops())
- return matcher.match(expected_src)
+ return matcher.match(expected_src, **kwds)
def match_by_id(self, id, expected_src, **kwds):
ops = list(self.ops_by_id(id, **kwds))
@@ -250,7 +250,6 @@
# this is the ticker check generated in PyFrame.handle_operation_error
exc_ticker_check = """
ticker2 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
- setfield_gc(_, _, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_w_f_trace .*>)
ticker_cond1 = int_lt(ticker2, 0)
guard_false(ticker_cond1, descr=...)
"""
@@ -266,7 +265,7 @@
if exp_v2 == '_':
return True
if self.is_const(v1) or self.is_const(exp_v2):
- return v1 == exp_v2
+ return v1[:-1].startswith(exp_v2[:-1])
if v1 not in self.alpha_map:
self.alpha_map[v1] = exp_v2
return self.alpha_map[v1] == exp_v2
@@ -315,7 +314,7 @@
# it matched! The '...' operator ends here
return op
- def match_loop(self, expected_ops):
+ def match_loop(self, expected_ops, ignore_ops):
"""
A note about partial matching: the '...' operator is non-greedy,
i.e. it matches all the operations until it finds one that matches
@@ -334,13 +333,16 @@
return
op = self.match_until(exp_op, iter_ops)
else:
- op = self._next_op(iter_ops)
+ while True:
+ op = self._next_op(iter_ops)
+ if op.name not in ignore_ops:
+ break
self.match_op(op, exp_op)
#
# make sure we exhausted iter_ops
self._next_op(iter_ops, assert_raises=True)
- def match(self, expected_src):
+ def match(self, expected_src, ignore_ops=[]):
def format(src):
if src is None:
return ''
@@ -349,7 +351,7 @@
expected_src = self.preprocess_expected_src(expected_src)
expected_ops = self.parse_ops(expected_src)
try:
- self.match_loop(expected_ops)
+ self.match_loop(expected_ops, ignore_ops)
except InvalidMatch, e:
#raise # uncomment this and use py.test --pdb for better debugging
print '@' * 40
@@ -358,6 +360,7 @@
print e.args
print e.msg
print
+ print "Ignore ops:", ignore_ops
print "Got:"
print format(self.src)
print
diff --git a/pypy/translator/c/test/test_database.py b/pypy/translator/c/test/test_database.py
--- a/pypy/translator/c/test/test_database.py
+++ b/pypy/translator/c/test/test_database.py
@@ -5,7 +5,7 @@
from pypy.objspace.flow.model import Constant, Variable, SpaceOperation
from pypy.objspace.flow.model import Block, Link, FunctionGraph
from pypy.rpython.typesystem import getfunctionptr
-from pypy.rpython.lltypesystem.rffi import VOIDP, INT_real, INT
+from pypy.rpython.lltypesystem.rffi import VOIDP, INT_real, INT, CArrayPtr
def dump_on_stdout(database):
@@ -244,3 +244,15 @@
db.get(p)
db.complete()
dump_on_stdout(db)
+
+def test_typedef():
+ A = Typedef(Signed, 'test4')
+ db = LowLevelDatabase()
+ assert db.gettype(A) == "test4 @"
+
+ PA = CArrayPtr(A)
+ assert db.gettype(PA) == "test4 *@"
+
+ F = FuncType((A,), A)
+ assert db.gettype(F) == "test4 (@)(test4)"
+
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
@@ -1,5 +1,5 @@
-from pypy.jit.metainterp.history import Const, Box
+from pypy.jit.metainterp.history import Const, Box, REF
from pypy.rlib.objectmodel import we_are_translated
class TempBox(Box):
@@ -313,11 +313,12 @@
self.assembler.regalloc_mov(reg, to)
# otherwise it's clean
- def before_call(self, force_store=[], save_all_regs=False):
+ def before_call(self, force_store=[], save_all_regs=0):
""" Spill registers before a call, as described by
'self.save_around_call_regs'. Registers are not spilled if
they don't survive past the current operation, unless they
- are listed in 'force_store'.
+ are listed in 'force_store'. 'save_all_regs' can be 0 (default),
+ 1 (save all), or 2 (save default+PTRs).
"""
for v, reg in self.reg_bindings.items():
if v not in force_store and self.longevity[v][1] <= self.position:
@@ -325,9 +326,11 @@
del self.reg_bindings[v]
self.free_regs.append(reg)
continue
- if not save_all_regs and reg not in self.save_around_call_regs:
- # we don't have to
- continue
+ if save_all_regs != 1 and reg not in self.save_around_call_regs:
+ if save_all_regs == 0:
+ continue # we don't have to
+ if v.type != REF:
+ continue # only save GC pointers
self._sync_var(v)
del self.reg_bindings[v]
self.free_regs.append(reg)
diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -3,6 +3,7 @@
import py
from py.test import skip
import sys, os, re
+import subprocess
class BytecodeTrace(list):
def get_opnames(self, prefix=""):
@@ -116,13 +117,12 @@
print >> f, "print 'OK :-)'"
f.close()
- if sys.platform.startswith('win'):
- py.test.skip("XXX this is not Windows-friendly")
print logfilepath
- child_stdout = os.popen('PYPYLOG=":%s" "%s" "%s"' % (
- logfilepath, self.pypy_c, filepath), 'r')
- result = child_stdout.read()
- child_stdout.close()
+ env = os.environ.copy()
+ env['PYPYLOG'] = ":%s" % (logfilepath,)
+ p = subprocess.Popen([self.pypy_c, str(filepath)],
+ env=env, stdout=subprocess.PIPE)
+ result, _ = p.communicate()
assert result
if result.strip().startswith('SKIP:'):
py.test.skip(result.strip())
@@ -198,44 +198,6 @@
print
print '@' * 79
- def test_f1(self):
- self.run_source('''
- def main(n):
- "Arbitrary test function."
- i = 0
- x = 1
- while i<n:
- j = 0 #ZERO
- while j<=i:
- j = j + 1
- x = x + (i&j)
- i = i + 1
- return x
- ''', 220,
- ([2117], 1083876708))
-
- def test_factorial(self):
- self.run_source('''
- def main(n):
- r = 1
- while n > 1:
- r *= n
- n -= 1
- return r
- ''', 28,
- ([5], 120),
- ([25], 15511210043330985984000000L))
-
- def test_factorialrec(self):
- self.run_source('''
- def main(n):
- if n > 1:
- return n * main(n-1)
- else:
- return 1
- ''', 0,
- ([5], 120),
- ([25], 15511210043330985984000000L))
def test_richards(self):
self.run_source('''
@@ -247,529 +209,6 @@
''' % (sys.path,), 7200,
([], 42))
- def test_simple_call(self):
- self.run_source('''
- OFFSET = 0
- def f(i):
- return i + 1 + OFFSET
- def main(n):
- i = 0
- while i < n+OFFSET:
- i = f(f(i))
- return i
- ''', 98,
- ([20], 20),
- ([31], 32))
- ops = self.get_by_bytecode("LOAD_GLOBAL", True)
- assert len(ops) == 5
- assert ops[0].get_opnames() == ["guard_value",
- "getfield_gc", "guard_value",
- "getfield_gc", "guard_isnull",
- "getfield_gc", "guard_nonnull_class"]
- # the second getfield on the same globals is quicker
- assert ops[1].get_opnames() == ["getfield_gc", "guard_nonnull_class"]
- assert not ops[2] # second LOAD_GLOBAL of the same name folded away
- # LOAD_GLOBAL of the same name but in different function partially
- # folded away
- # XXX could be improved
- assert ops[3].get_opnames() == ["guard_value",
- "getfield_gc", "guard_isnull"]
- assert not ops[4]
- ops = self.get_by_bytecode("CALL_FUNCTION", True)
- assert len(ops) == 2
- for i, bytecode in enumerate(ops):
- if i == 0:
- assert "call(getexecutioncontext)" in str(bytecode)
- else:
- assert not bytecode.get_opnames("call")
- assert not bytecode.get_opnames("new")
- assert len(bytecode.get_opnames("guard")) <= 10
-
- ops = self.get_by_bytecode("LOAD_GLOBAL")
- assert len(ops) == 5
- for bytecode in ops:
- assert not bytecode
-
- ops = self.get_by_bytecode("CALL_FUNCTION")
- assert len(ops) == 2
- for bytecode in ops:
- assert len(bytecode) <= 1
-
-
- def test_method_call(self):
- self.run_source('''
- class A(object):
- def __init__(self, a):
- self.a = a
- def f(self, i):
- return self.a + i
- def main(n):
- i = 0
- a = A(1)
- while i < n:
- x = a.f(i)
- i = a.f(x)
- return i
- ''', 93,
- ([20], 20),
- ([31], 32))
- ops = self.get_by_bytecode("LOOKUP_METHOD", True)
- assert len(ops) == 2
- assert not ops[0].get_opnames("call")
- assert not ops[0].get_opnames("new")
- assert len(ops[0].get_opnames("guard")) <= 3
- assert not ops[1] # second LOOKUP_METHOD folded away
-
- ops = self.get_by_bytecode("LOOKUP_METHOD")
- assert not ops[0] # first LOOKUP_METHOD folded away
- assert not ops[1] # second LOOKUP_METHOD folded away
-
- ops = self.get_by_bytecode("CALL_METHOD", True)
- assert len(ops) == 2
- for i, bytecode in enumerate(ops):
- if i == 0:
- assert "call(getexecutioncontext)" in str(bytecode)
- else:
- assert not bytecode.get_opnames("call")
- assert not bytecode.get_opnames("new")
- assert len(bytecode.get_opnames("guard")) <= 6
- assert len(ops[1]) < len(ops[0])
-
- ops = self.get_by_bytecode("CALL_METHOD")
- assert len(ops) == 2
- assert len(ops[0]) <= 1
- assert len(ops[1]) <= 1
-
- ops = self.get_by_bytecode("LOAD_ATTR", True)
- assert len(ops) == 2
- # With mapdict, we get fast access to (so far) the 5 first
- # attributes, which means it is done with only the following
- # operations. (For the other attributes there is additionally
- # a getarrayitem_gc.)
- assert ops[0].get_opnames() == ["getfield_gc",
- "guard_nonnull_class"]
- assert not ops[1] # second LOAD_ATTR folded away
-
- ops = self.get_by_bytecode("LOAD_ATTR")
- assert not ops[0] # first LOAD_ATTR folded away
- assert not ops[1] # second LOAD_ATTR folded away
-
- def test_static_classmethod_call(self):
- self.run_source('''
- class A(object):
- @classmethod
- def f(cls, i):
- return i + (cls is A) + 1
-
- @staticmethod
- def g(i):
- return i - 1
-
- def main(n):
- i = 0
- a = A()
- while i < n:
- x = a.f(i)
- i = a.g(x)
- return i
- ''', 106,
- ([20], 20),
- ([31], 31))
- ops = self.get_by_bytecode("LOOKUP_METHOD")
- assert len(ops) == 2
- assert not ops[0].get_opnames("call")
- assert not ops[0].get_opnames("new")
- assert len(ops[0].get_opnames("guard")) <= 2
- assert len(ops[0].get_opnames("getfield")) <= 4
- assert not ops[1] # second LOOKUP_METHOD folded away
-
- def test_default_and_kw(self):
- self.run_source('''
- def f(i, j=1):
- return i + j
- def main(n):
- i = 0
- while i < n:
- i = f(f(i), j=1)
- return i
- ''', 100,
- ([20], 20),
- ([31], 32))
- ops = self.get_by_bytecode("CALL_FUNCTION")
- assert len(ops) == 2
- for i, bytecode in enumerate(ops):
- assert not bytecode.get_opnames("call")
- assert not bytecode.get_opnames("new")
- assert len(ops[0].get_opnames("guard")) <= 14
- assert len(ops[1].get_opnames("guard")) <= 3
-
- ops = self.get_by_bytecode("CALL_FUNCTION", True)
- assert len(ops) == 2
- for i, bytecode in enumerate(ops):
- if i == 0:
- assert "call(getexecutioncontext)" in str(bytecode)
- else:
- assert not bytecode.get_opnames("call")
- assert not bytecode.get_opnames("new")
- assert len(ops[0].get_opnames("guard")) <= 14
- assert len(ops[1].get_opnames("guard")) <= 3
-
- def test_kwargs(self):
- self.run_source('''
- d = {}
-
- def g(**args):
- return len(args)
-
- def main(x):
- s = 0
- d = {}
- for i in range(x):
- s += g(**d)
- d[str(i)] = i
- if i % 100 == 99:
- d = {}
- return s
- ''', 100000, ([100], 4950),
- ([1000], 49500),
- ([10000], 495000),
- ([100000], 4950000))
- assert len(self.rawloops) + len(self.rawentrybridges) == 4
- op, = self.get_by_bytecode("CALL_FUNCTION_KW")
- # XXX a bit too many guards, but better than before
- assert len(op.get_opnames("guard")) <= 12
-
- def test_stararg_virtual(self):
- self.run_source('''
- d = {}
-
- def g(*args):
- return len(args)
- def h(a, b, c):
- return c
-
- def main(x):
- s = 0
- for i in range(x):
- l = [i, x, 2]
- s += g(*l)
- s += h(*l)
- s += g(i, x, 2)
- for i in range(x):
- l = [x, 2]
- s += g(i, *l)
- s += h(i, *l)
- return s
- ''', 100000, ([100], 1300),
- ([1000], 13000),
- ([10000], 130000),
- ([100000], 1300000))
- assert len(self.loops) == 2
- ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
- assert len(ops) == 4
- for op in ops:
- assert len(op.get_opnames("new")) == 0
- assert len(op.get_opnames("call_may_force")) == 0
-
- ops = self.get_by_bytecode("CALL_FUNCTION")
- for op in ops:
- assert len(op.get_opnames("new")) == 0
- assert len(op.get_opnames("call_may_force")) == 0
-
- def test_stararg(self):
- self.run_source('''
- d = {}
-
- def g(*args):
- return args[-1]
- def h(*args):
- return len(args)
-
- def main(x):
- s = 0
- l = []
- i = 0
- while i < x:
- l.append(1)
- s += g(*l)
- i = h(*l)
- return s
- ''', 100000, ([100], 100),
- ([1000], 1000),
- ([2000], 2000),
- ([4000], 4000))
- assert len(self.loops) == 1
- ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
- for op in ops:
- assert len(op.get_opnames("new_with_vtable")) == 0
- assert len(op.get_opnames("call_may_force")) == 0
-
- def test_virtual_instance(self):
- self.run_source('''
- class A(object):
- pass
- def main(n):
- i = 0
- while i < n:
- a = A()
- assert isinstance(a, A)
- assert not isinstance(a, int)
- a.x = 2
- i = i + a.x
- return i
- ''', 69,
- ([20], 20),
- ([31], 32))
-
- callA, callisinstance1, callisinstance2 = (
- self.get_by_bytecode("CALL_FUNCTION"))
- assert not callA.get_opnames("call")
- assert not callA.get_opnames("new")
- assert len(callA.get_opnames("guard")) <= 2
- assert not callisinstance1.get_opnames("call")
- assert not callisinstance1.get_opnames("new")
- assert len(callisinstance1.get_opnames("guard")) <= 2
- # calling isinstance on a builtin type gives zero guards
- # because the version_tag of a builtin type is immutable
- assert not len(callisinstance1.get_opnames("guard"))
-
-
- bytecode, = self.get_by_bytecode("STORE_ATTR")
- assert bytecode.get_opnames() == []
-
- def test_load_attr(self):
- self.run_source('''
- class A(object):
- pass
- a = A()
- a.x = 2
- def main(n):
- i = 0
- while i < n:
- i = i + a.x
- return i
- ''', 41,
- ([20], 20),
- ([31], 32))
-
- load, = self.get_by_bytecode("LOAD_ATTR")
- # 1 guard_value for the class
- # 1 guard_value for the version_tag
- # 1 guard_value for the structure
- # 1 guard_nonnull_class for the result since it is used later
- assert len(load.get_opnames("guard")) <= 4
-
- def test_mixed_type_loop(self):
- self.run_source('''
- class A(object):
- pass
- def main(n):
- i = 0.0
- j = 2
- while i < n:
- i = j + i
- return i, type(i) is float
- ''', 35,
- ([20], (20, True)),
- ([31], (32, True)))
-
- bytecode, = self.get_by_bytecode("BINARY_ADD")
- assert not bytecode.get_opnames("call")
- assert not bytecode.get_opnames("new")
- assert len(bytecode.get_opnames("guard")) <= 2
-
- def test_call_builtin_function(self):
- self.run_source('''
- class A(object):
- pass
- def main(n):
- i = 2
- l = []
- while i < n:
- i += 1
- l.append(i)
- return i, len(l)
- ''', 39,
- ([20], (20, 18)),
- ([31], (31, 29)))
-
- bytecode, = self.get_by_bytecode("CALL_METHOD")
- assert len(bytecode.get_opnames("new_with_vtable")) == 1 # the forcing of the int
- assert len(bytecode.get_opnames("call")) == 1 # the call to append
- assert len(bytecode.get_opnames("guard")) == 1 # guard for guard_no_exception after the call
- bytecode, = self.get_by_bytecode("CALL_METHOD", True)
- assert len(bytecode.get_opnames("guard")) == 2 # guard for profiling disabledness + guard_no_exception after the call
-
- def test_range_iter(self):
- self.run_source('''
- def g(n):
- return range(n)
-
- def main(n):
- s = 0
- for i in range(n):
- s += g(n)[i]
- return s
- ''', 143, ([1000], 1000 * 999 / 2))
- bytecode, = self.get_by_bytecode("BINARY_SUBSCR", True)
- assert bytecode.get_opnames("guard") == [
- "guard_false", # check that the index is >= 0
- "guard_false", # check that the index is lower than the current length
- ]
- bytecode, _ = self.get_by_bytecode("FOR_ITER", True) # second bytecode is the end of the loop
- assert bytecode.get_opnames("guard") == [
- "guard_value",
- "guard_class", # check the class of the iterator
- "guard_nonnull", # check that the iterator is not finished
- "guard_isnull", # check that the range list is not forced
- "guard_false", # check that the index is lower than the current length
- ]
-
- bytecode, = self.get_by_bytecode("BINARY_SUBSCR")
- assert bytecode.get_opnames("guard") == [
- "guard_false", # check that the index is >= 0
- "guard_false", # check that the index is lower than the current length
- ]
- bytecode, _ = self.get_by_bytecode("FOR_ITER") # second bytecode is the end of the loop
- assert bytecode.get_opnames("guard") == [
- "guard_false", # check that the index is lower than the current length
- ]
-
- def test_exception_inside_loop_1(self):
- self.run_source('''
- def main(n):
- while n:
- try:
- raise ValueError
- except ValueError:
- pass
- n -= 1
- return n
- ''', 33,
- ([30], 0))
-
- bytecode, = self.get_by_bytecode("SETUP_EXCEPT")
- #assert not bytecode.get_opnames("new") -- currently, we have
- # new_with_vtable(pypy.interpreter.pyopcode.ExceptBlock)
- bytecode, = self.get_by_bytecode("RAISE_VARARGS")
- assert not bytecode.get_opnames("new")
- bytecode, = self.get_by_bytecode("COMPARE_OP")
- assert not bytecode.get_opnames()
-
- def test_exception_inside_loop_2(self):
- self.run_source('''
- def g(n):
- raise ValueError(n)
- def f(n):
- g(n)
- def main(n):
- while n:
- try:
- f(n)
- except ValueError:
- pass
- n -= 1
- return n
- ''', 51,
- ([30], 0))
-
- bytecode, = self.get_by_bytecode("RAISE_VARARGS")
- assert not bytecode.get_opnames("new")
- bytecode, = self.get_by_bytecode("COMPARE_OP")
- assert len(bytecode.get_opnames()) <= 2 # oois, guard_true
-
- def test_chain_of_guards(self):
- self.run_source('''
- class A(object):
- def method_x(self):
- return 3
-
- l = ["x", "y"]
-
- def main(arg):
- sum = 0
- a = A()
- i = 0
- while i < 2000:
- name = l[arg]
- sum += getattr(a, 'method_' + name)()
- i += 1
- return sum
- ''', 3000, ([0], 2000*3))
- assert len(self.loops) == 1
-
- def test_getattr_with_dynamic_attribute(self):
- self.run_source('''
- class A(object):
- pass
-
- l = ["x", "y"]
-
- def main(arg):
- sum = 0
- a = A()
- a.a1 = 0
- a.a2 = 0
- a.a3 = 0
- a.a4 = 0
- a.a5 = 0 # workaround, because the first five attributes need a promotion
- a.x = 1
- a.y = 2
- i = 0
- while i < 2000:
- name = l[i % 2]
- sum += getattr(a, name)
- i += 1
- return sum
- ''', 3000, ([0], 3000))
- assert len(self.loops) == 1
-
- def test_blockstack_virtualizable(self):
- self.run_source('''
- from pypyjit import residual_call
-
- def main():
- i = 0
- while i < 100:
- try:
- residual_call(len, [])
- except:
- pass
- i += 1
- return i
- ''', 1000, ([], 100))
- bytecode, = self.get_by_bytecode("CALL_FUNCTION")
- # we allocate virtual ref and frame, we don't want block
- assert len(bytecode.get_opnames('new_with_vtable')) == 2
-
- def test_import_in_function(self):
- self.run_source('''
- def main():
- i = 0
- while i < 100:
- from sys import version
- i += 1
- return i
- ''', 100, ([], 100))
- bytecode, = self.get_by_bytecode('IMPORT_NAME')
- bytecode2, = self.get_by_bytecode('IMPORT_FROM')
- assert len(bytecode.get_opnames('call')) == 2 # split_chr and list_pop
- assert len(bytecode2.get_opnames('call')) == 0
-
- def test_arraycopy_disappears(self):
- self.run_source('''
- def main():
- i = 0
- while i < 100:
- t = (1, 2, 3, i + 1)
- t2 = t[:]
- del t
- i = t2[3]
- del t2
- return i
- ''', 40, ([], 100))
- bytecode, = self.get_by_bytecode('BINARY_SUBSCR')
- assert len(bytecode.get_opnames('new_array')) == 0
def test_overflow_checking(self):
startvalue = sys.maxint - 2147483647
@@ -784,514 +223,6 @@
return total
''' % startvalue, 170, ([], startvalue + 4999450000L))
- def test_boolrewrite_invers(self):
- for a, b, res, ops in (('2000', '2000', 20001000, 51),
- ( '500', '500', 15001500, 81),
- ( '300', '600', 16001700, 83),
- ( 'a', 'b', 16001700, 89),
- ( 'a', 'a', 13001700, 85)):
-
- self.run_source('''
- def main():
- sa = 0
- a = 300
- b = 600
- for i in range(1000):
- if i < %s: sa += 1
- else: sa += 2
- if i >= %s: sa += 10000
- else: sa += 20000
- return sa
- '''%(a, b), ops, ([], res))
-
- def test_boolrewrite_reflex(self):
- for a, b, res, ops in (('2000', '2000', 10001000, 51),
- ( '500', '500', 15001500, 81),
- ( '300', '600', 14001700, 83),
- ( 'a', 'b', 14001700, 89),
- ( 'a', 'a', 17001700, 85)):
-
- self.run_source('''
- def main():
- sa = 0
- a = 300
- b = 600
- for i in range(1000):
- if i < %s: sa += 1
- else: sa += 2
- if %s > i: sa += 10000
- else: sa += 20000
- return sa
- '''%(a, b), ops, ([], res))
-
-
- def test_boolrewrite_correct_invers(self):
- def opval(i, op, a):
- if eval('%d %s %d' % (i, op, a)): return 1
- return 2
-
- ops = ('<', '>', '<=', '>=', '==', '!=')
- for op1 in ops:
- for op2 in ops:
- for a,b in ((500, 500), (300, 600)):
- res = 0
- res += opval(a-1, op1, a) * (a)
- res += opval( a, op1, a)
- res += opval(a+1, op1, a) * (1000 - a - 1)
- res += opval(b-1, op2, b) * 10000 * (b)
- res += opval( b, op2, b) * 10000
- res += opval(b+1, op2, b) * 10000 * (1000 - b - 1)
-
- self.run_source('''
- def main():
- sa = 0
- for i in range(1000):
- if i %s %d: sa += 1
- else: sa += 2
- if i %s %d: sa += 10000
- else: sa += 20000
- return sa
- '''%(op1, a, op2, b), 83, ([], res))
-
- self.run_source('''
- def main():
- sa = 0
- i = 0.0
- while i < 250.0:
- if i %s %f: sa += 1
- else: sa += 2
- if i %s %f: sa += 10000
- else: sa += 20000
- i += 0.25
- return sa
- '''%(op1, float(a)/4.0, op2, float(b)/4.0), 156, ([], res))
-
-
- def test_boolrewrite_correct_reflex(self):
- def opval(i, op, a):
- if eval('%d %s %d' % (i, op, a)): return 1
- return 2
-
- ops = ('<', '>', '<=', '>=', '==', '!=')
- for op1 in ops:
- for op2 in ops:
- for a,b in ((500, 500), (300, 600)):
- res = 0
- res += opval(a-1, op1, a) * (a)
- res += opval( a, op1, a)
- res += opval(a+1, op1, a) * (1000 - a - 1)
- res += opval(b, op2, b-1) * 10000 * (b)
- res += opval(b, op2, b) * 10000
- res += opval(b, op2, b+1) * 10000 * (1000 - b - 1)
-
- self.run_source('''
- def main():
- sa = 0
- for i in range(1000):
- if i %s %d: sa += 1
- else: sa += 2
- if %d %s i: sa += 10000
- else: sa += 20000
- return sa
- '''%(op1, a, b, op2), 83, ([], res))
-
- self.run_source('''
- def main():
- sa = 0
- i = 0.0
- while i < 250.0:
- if i %s %f: sa += 1
- else: sa += 2
- if %f %s i: sa += 10000
- else: sa += 20000
- i += 0.25
- return sa
- '''%(op1, float(a)/4.0, float(b)/4.0, op2), 156, ([], res))
-
- def test_boolrewrite_ptr(self):
- # XXX this test is way too imprecise in what it is actually testing
- # it should count the number of guards instead
- compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b')
- for e1 in compares:
- for e2 in compares:
- a, b, c = 1, 2, 3
- if eval(e1): res = 752 * 1
- else: res = 752 * 2
- if eval(e2): res += 752 * 10000
- else: res += 752 * 20000
- a = b
- if eval(e1): res += 248 * 1
- else: res += 248 * 2
- if eval(e2): res += 248 * 10000
- else: res += 248 * 20000
-
-
- if 'c' in e1 or 'c' in e2:
- n = 337
- else:
- n = 215
-
- print
- print 'Test:', e1, e2, n, res
- self.run_source('''
- class tst(object):
- pass
- def main():
- a = tst()
- b = tst()
- c = tst()
- sa = 0
- for i in range(1000):
- if %s: sa += 1
- else: sa += 2
- if %s: sa += 10000
- else: sa += 20000
- if i > 750: a = b
- return sa
- '''%(e1, e2), n, ([], res))
-
- def test_array_sum(self):
- for tc, maxops in zip('bhilBHILfd', (38,) * 6 + (40, 40, 41, 38)):
- res = 19352859
- if tc == 'L':
- res = long(res)
- elif tc in 'fd':
- res = float(res)
- elif tc == 'I' and sys.maxint == 2147483647:
- res = long(res)
- # note: in CPython we always get longs here, even on 64-bits
-
- self.run_source('''
- from array import array
-
- def main():
- img = array("%s", range(127) * 5) * 484
- l, i = 0, 0
- while i < 640 * 480:
- l += img[i]
- i += 1
- return l
- ''' % tc, maxops, ([], res))
-
- def test_array_sum_char(self):
- self.run_source('''
- from array import array
-
- def main():
- img = array("c", "Hello") * 130 * 480
- l, i = 0, 0
- while i < 640 * 480:
- l += ord(img[i])
- i += 1
- return l
- ''', 60, ([], 30720000))
-
- def test_array_sum_unicode(self):
- self.run_source('''
- from array import array
-
- def main():
- img = array("u", u"Hello") * 130 * 480
- l, i = 0, 0
- while i < 640 * 480:
- if img[i] == u"l":
- l += 1
- i += 1
- return l
- ''', 65, ([], 122880))
-
- def test_array_intimg(self):
- # XXX this test is way too imprecise in what it is actually testing
- # it should count the number of guards instead
- for tc, maxops in zip('ilILd', (67, 67, 70, 70, 61)):
- print
- print '='*65
- print '='*20, 'running test for tc=%r' % (tc,), '='*20
- res = 73574560
- if tc == 'L':
- res = long(res)
- elif tc in 'fd':
- res = float(res)
- elif tc == 'I' and sys.maxint == 2147483647:
- res = long(res)
- # note: in CPython we always get longs here, even on 64-bits
-
- self.run_source('''
- from array import array
-
- def main(tc):
- img = array(tc, range(3)) * (350 * 480)
- intimg = array(tc, (0,)) * (640 * 480)
- l, i = 0, 640
- while i < 640 * 480:
- l = l + img[i]
- intimg[i] = (intimg[i-640] + l)
- i += 1
- return intimg[i - 1]
- ''', maxops, ([tc], res))
-
- def test_unpackiterable(self):
- self.run_source('''
- from array import array
-
- def main():
- i = 0
- t = array('l', (1, 2))
- while i < 2000:
- a, b = t
- i += 1
- return 3
-
- ''', 100, ([], 3))
- bytecode, = self.get_by_bytecode("UNPACK_SEQUENCE")
- # we allocate virtual ref and frame, we don't want block
- assert len(bytecode.get_opnames('call_may_force')) == 0
-
-
- def test_intbound_simple(self):
- ops = ('<', '>', '<=', '>=', '==', '!=')
- nbr = (3, 7)
- for o1 in ops:
- for o2 in ops:
- for n1 in nbr:
- for n2 in nbr:
- src = '''
- def f(i):
- a, b = 3, 3
- if i %s %d:
- a = 0
- else:
- a = 1
- if i %s %d:
- b = 0
- else:
- b = 1
- return a + b * 2
-
- def main():
- res = [0] * 4
- idx = []
- for i in range(15):
- idx.extend([i] * 1500)
- for i in idx:
- res[f(i)] += 1
- return res
-
- ''' % (o1, n1, o2, n2)
-
- exec(str(py.code.Source(src)))
- res = [0] * 4
- for i in range(15):
- res[f(i)] += 1500
- self.run_source(src, 268, ([], res))
-
- def test_intbound_addsub_mix(self):
- tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4',
- 'i - 1 > 1', '1 - i > 1', '1 - i < -3',
- 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4')
- for t1 in tests:
- for t2 in tests:
- print t1, t2
- src = '''
- def f(i):
- a, b = 3, 3
- if %s:
- a = 0
- else:
- a = 1
- if %s:
- b = 0
- else:
- b = 1
- return a + b * 2
-
- def main():
- res = [0] * 4
- idx = []
- for i in range(15):
- idx.extend([i] * 1500)
- for i in idx:
- res[f(i)] += 1
- return res
-
- ''' % (t1, t2)
-
- exec(str(py.code.Source(src)))
- res = [0] * 4
- for i in range(15):
- res[f(i)] += 1500
- self.run_source(src, 280, ([], res))
-
- def test_intbound_gt(self):
- self.run_source('''
- def main():
- i, a, b = 0, 0, 0
- while i < 2000:
- if i > -1:
- a += 1
- if i > -2:
- b += 1
- i += 1
- return (a, b)
- ''', 48, ([], (2000, 2000)))
-
- def test_intbound_sub_lt(self):
- self.run_source('''
- def main():
- i, a, b = 0, 0, 0
- while i < 2000:
- if i - 10 < 1995:
- a += 1
- i += 1
- return (a, b)
- ''', 38, ([], (2000, 0)))
-
- def test_intbound_addsub_ge(self):
- self.run_source('''
- def main():
- i, a, b = 0, 0, 0
- while i < 2000:
- if i + 5 >= 5:
- a += 1
- if i - 1 >= -1:
- b += 1
- i += 1
- return (a, b)
- ''', 56, ([], (2000, 2000)))
-
- def test_intbound_addmul_ge(self):
- self.run_source('''
- def main():
- i, a, b = 0, 0, 0
- while i < 2000:
- if i + 5 >= 5:
- a += 1
- if 2 * i >= 0:
- b += 1
- i += 1
- return (a, b)
- ''', 53, ([], (2000, 2000)))
-
- def test_intbound_eq(self):
- self.run_source('''
- def main(a):
- i, s = 0, 0
- while i < 1500:
- if a == 7:
- s += a + 1
- elif i == 10:
- s += i
- else:
- s += 1
- i += 1
- return s
- ''', 69, ([7], 12000), ([42], 1509), ([10], 1509))
-
- def test_intbound_mul(self):
- self.run_source('''
- def main(a):
- i, s = 0, 0
- while i < 1500:
- assert i >= 0
- if 2 * i < 30000:
- s += 1
- else:
- s += a
- i += 1
- return s
- ''', 43, ([7], 1500))
-
- def test_assert(self):
- self.run_source('''
- def main(a):
- i, s = 0, 0
- while i < 1500:
- assert a == 7
- s += a + 1
- i += 1
- return s
- ''', 38, ([7], 8*1500))
-
- def test_zeropadded(self):
- self.run_source('''
- from array import array
- class ZeroPadded(array):
- def __new__(cls, l):
- self = array.__new__(cls, 'd', range(l))
- return self
-
- def __getitem__(self, i):
- if i < 0 or i >= self.__len__():
- return 0
- return array.__getitem__(self, i)
-
-
- def main():
- buf = ZeroPadded(2000)
- i = 10
- sa = 0
- while i < 2000 - 10:
- sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2]
- i += 1
- return sa
-
- ''', 232, ([], 9895050.0))
-
- def test_circular(self):
- self.run_source('''
- from array import array
- class Circular(array):
- def __new__(cls):
- self = array.__new__(cls, 'd', range(256))
- return self
- def __getitem__(self, i):
- # assert self.__len__() == 256 (FIXME: does not improve)
- return array.__getitem__(self, i & 255)
-
- def main():
- buf = Circular()
- i = 10
- sa = 0
- while i < 2000 - 10:
- sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2]
- i += 1
- return sa
-
- ''', 170, ([], 1239690.0))
-
- def test_min_max(self):
- self.run_source('''
- def main():
- i=0
- sa=0
- while i < 2000:
- sa+=min(max(i, 3000), 4000)
- i+=1
- return sa
- ''', 51, ([], 2000*3000))
-
- def test_silly_max(self):
- self.run_source('''
- def main():
- i=2
- sa=0
- while i < 2000:
- sa+=max(*range(i))
- i+=1
- return sa
- ''', 125, ([], 1997001))
-
- def test_iter_max(self):
- self.run_source('''
- def main():
- i=2
- sa=0
- while i < 2000:
- sa+=max(range(i))
- i+=1
- return sa
- ''', 88, ([], 1997001))
-
def test__ffi_call(self):
from pypy.rlib.test.test_libffi import get_libm_name
libm_name = get_libm_name(sys.platform)
diff --git a/pypy/jit/metainterp/test/test_blackhole.py b/pypy/jit/metainterp/test/test_blackhole.py
--- a/pypy/jit/metainterp/test/test_blackhole.py
+++ b/pypy/jit/metainterp/test/test_blackhole.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
from pypy.jit.metainterp.blackhole import BlackholeInterpreter
from pypy.jit.metainterp.blackhole import convert_and_run_from_pyjitpl
diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py
--- a/pypy/rpython/test/test_rint.py
+++ b/pypy/rpython/test/test_rint.py
@@ -4,7 +4,7 @@
from pypy.annotation import model as annmodel
from pypy.rpython.test import snippet
from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
-from pypy.rlib.rarithmetic import ovfcheck, r_int64, intmask
+from pypy.rlib.rarithmetic import ovfcheck, r_int64, intmask, int_between
from pypy.rlib import objectmodel
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
@@ -215,6 +215,14 @@
assert res == f(inttype(0))
assert type(res) == inttype
+ def test_and_or(self):
+ inttypes = [int, r_uint, r_int64, r_ulonglong]
+ for inttype in inttypes:
+ def f(a, b, c):
+ return a&b|c
+ res = self.interpret(f, [inttype(0x1234), inttype(0x00FF), inttype(0x5600)])
+ assert res == f(0x1234, 0x00FF, 0x5600)
+
def test_neg_abs_ovf(self):
for op in (operator.neg, abs):
def f(x):
@@ -388,6 +396,18 @@
else:
assert res == 123456789012345678
+ def test_int_between(self):
+ def fn(a, b, c):
+ return int_between(a, b, c)
+ assert self.interpret(fn, [1, 1, 3])
+ assert self.interpret(fn, [1, 2, 3])
+ assert not self.interpret(fn, [1, 0, 2])
+ assert not self.interpret(fn, [1, 5, 2])
+ assert not self.interpret(fn, [1, 2, 2])
+ assert not self.interpret(fn, [1, 1, 1])
+
+
+
class TestLLtype(BaseTestRint, LLRtypeMixin):
pass
diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java
--- a/pypy/translator/jvm/src/pypy/PyPy.java
+++ b/pypy/translator/jvm/src/pypy/PyPy.java
@@ -38,6 +38,10 @@
public final static int INT_MIN = Integer.MIN_VALUE;
public final static double ULONG_MAX = 18446744073709551616.0;
+ public static boolean int_between(int a, int b, int c) {
+ return a <= b && b < c;
+ }
+
/**
* Compares two unsigned integers (value1 and value2) and returns
* a value greater than, equal to, or less than zero if value 1 is
@@ -163,6 +167,13 @@
return ULONG_MAX + value;
}
}
+
+ public static long double_to_ulong(double value) {
+ if (value < 0)
+ return (long)(ULONG_MAX + value);
+ else
+ return (long)value;
+ }
public static int double_to_uint(double value) {
if (value <= Integer.MAX_VALUE)
@@ -1175,6 +1186,18 @@
return Math.tanh(x);
}
+ public double ll_math_copysign(double x, double y) {
+ return Math.copySign(x, y);
+ }
+
+ public boolean ll_math_isnan(double x) {
+ return Double.isNaN(x);
+ }
+
+ public boolean ll_math_isinf(double x) {
+ return Double.isInfinite(x);
+ }
+
private double check(double v) {
if (Double.isNaN(v))
interlink.throwValueError();
@@ -1187,9 +1210,42 @@
return Character.toLowerCase(c);
}
+ public int locale_tolower(int chr)
+ {
+ return Character.toLowerCase(chr);
+ }
+
+ public int locale_isupper(int chr)
+ {
+ return boolean2int(Character.isUpperCase(chr));
+ }
+
+ public int locale_islower(int chr)
+ {
+ return boolean2int(Character.isLowerCase(chr));
+ }
+
+ public int locale_isalpha(int chr)
+ {
+ return boolean2int(Character.isLetter(chr));
+ }
+
+ public int locale_isalnum(int chr)
+ {
+ return boolean2int(Character.isLetterOrDigit(chr));
+ }
+
+
// ----------------------------------------------------------------------
// Self Test
+ public static int boolean2int(boolean b)
+ {
+ if (b)
+ return 1;
+ return 0;
+ }
+
public static int __counter = 0, __failures = 0;
public static void ensure(boolean f) {
if (f) {
diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py
--- a/pypy/jit/metainterp/test/test_string.py
+++ b/pypy/jit/metainterp/test/test_string.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver, dont_look_inside, we_are_jitted
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rpython.ootypesystem import ootype
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class StringTests:
diff --git a/pypy/translator/cli/ilgenerator.py b/pypy/translator/cli/ilgenerator.py
--- a/pypy/translator/cli/ilgenerator.py
+++ b/pypy/translator/cli/ilgenerator.py
@@ -443,8 +443,8 @@
self.ilasm.opcode('newarr', clitype.itemtype.typename())
def _array_suffix(self, ARRAY, erase_unsigned=False):
- from pypy.translator.cli.metavm import OOTYPE_TO_MNEMONIC
- suffix = OOTYPE_TO_MNEMONIC.get(ARRAY.ITEM, 'ref')
+ from pypy.translator.cli.metavm import ootype_to_mnemonic
+ suffix = ootype_to_mnemonic(ARRAY.ITEM, ARRAY.ITEM, 'ref')
if erase_unsigned:
suffix = suffix.replace('u', 'i')
return suffix
diff --git a/pypy/jit/codewriter/heaptracker.py b/pypy/jit/codewriter/heaptracker.py
--- a/pypy/jit/codewriter/heaptracker.py
+++ b/pypy/jit/codewriter/heaptracker.py
@@ -10,6 +10,30 @@
def int2adr(int):
return llmemory.cast_int_to_adr(int)
+def count_fields_if_immutable(STRUCT):
+ assert isinstance(STRUCT, lltype.GcStruct)
+ if STRUCT._hints.get('immutable', False):
+ try:
+ return _count_fields(STRUCT)
+ except ValueError:
+ pass
+ return -1
+
+def _count_fields(STRUCT):
+ if STRUCT == rclass.OBJECT:
+ return 0 # don't count 'typeptr'
+ result = 0
+ for fieldname, TYPE in STRUCT._flds.items():
+ if TYPE is lltype.Void:
+ pass # ignore Voids
+ elif not isinstance(TYPE, lltype.ContainerType):
+ result += 1
+ elif isinstance(TYPE, lltype.GcStruct):
+ result += _count_fields(TYPE)
+ else:
+ raise ValueError(TYPE)
+ return result
+
# ____________________________________________________________
def has_gcstruct_a_vtable(GCSTRUCT):
diff --git a/pypy/jit/metainterp/test/test_greenfield.py b/pypy/jit/metainterp/test/test_greenfield.py
--- a/pypy/jit/metainterp/test/test_greenfield.py
+++ b/pypy/jit/metainterp/test/test_greenfield.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
diff --git a/pypy/rlib/rlocale.py b/pypy/rlib/rlocale.py
--- a/pypy/rlib/rlocale.py
+++ b/pypy/rlib/rlocale.py
@@ -7,6 +7,7 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rpython.tool import rffi_platform as platform
+from pypy.rpython.extfunc import register_external
class LocaleError(Exception):
def __init__(self, message):
@@ -156,23 +157,35 @@
HAVE_BIND_TEXTDOMAIN_CODESET = cConfig.HAVE_BIND_TEXTDOMAIN_CODESET
-def external(name, args, result, calling_conv='c'):
+def external(name, args, result, calling_conv='c', **kwds):
return rffi.llexternal(name, args, result,
compilation_info=CConfig._compilation_info_,
calling_conv=calling_conv,
- sandboxsafe=True)
+ sandboxsafe=True, **kwds)
_lconv = lltype.Ptr(cConfig.lconv)
localeconv = external('localeconv', [], _lconv)
def numeric_formatting():
"""Specialized function to get formatting for numbers"""
+ return numeric_formatting_impl()
+
+def numeric_formatting_impl():
conv = localeconv()
decimal_point = rffi.charp2str(conv.c_decimal_point)
thousands_sep = rffi.charp2str(conv.c_thousands_sep)
grouping = rffi.charp2str(conv.c_grouping)
return decimal_point, thousands_sep, grouping
+def oo_numeric_formatting():
+ return '.', '', ''
+
+register_external(numeric_formatting, [], (str, str, str),
+ llimpl=numeric_formatting_impl,
+ ooimpl=oo_numeric_formatting,
+ sandboxsafe=True)
+
+
_setlocale = external('setlocale', [rffi.INT, rffi.CCHARP], rffi.CCHARP)
def setlocale(category, locale):
@@ -184,11 +197,11 @@
raise LocaleError("unsupported locale setting")
return rffi.charp2str(ll_result)
-isalpha = external('isalpha', [rffi.INT], rffi.INT)
-isupper = external('isupper', [rffi.INT], rffi.INT)
-islower = external('islower', [rffi.INT], rffi.INT)
-tolower = external('tolower', [rffi.INT], rffi.INT)
-isalnum = external('isalnum', [rffi.INT], rffi.INT)
+isalpha = external('isalpha', [rffi.INT], rffi.INT, oo_primitive='locale_isalpha')
+isupper = external('isupper', [rffi.INT], rffi.INT, oo_primitive='locale_isupper')
+islower = external('islower', [rffi.INT], rffi.INT, oo_primitive='locale_islower')
+tolower = external('tolower', [rffi.INT], rffi.INT, oo_primitive='locale_tolower')
+isalnum = external('isalnum', [rffi.INT], rffi.INT, oo_primitive='locale_isalnum')
if HAVE_LANGINFO:
_nl_langinfo = external('nl_langinfo', [rffi.INT], rffi.CCHARP)
diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py
--- a/pypy/module/thread/ll_thread.py
+++ b/pypy/module/thread/ll_thread.py
@@ -1,10 +1,10 @@
-from pypy.rpython.lltypesystem import rffi
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import rffi, lltype, llmemory
from pypy.rpython.tool import rffi_platform as platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
import py, os
from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rlib import jit
from pypy.rlib.debug import ll_assert
from pypy.rlib.objectmodel import we_are_translated
from pypy.rpython.lltypesystem.lloperation import llop
@@ -79,6 +79,7 @@
# wrappers...
+ at jit.loop_invariant
def get_ident():
return rffi.cast(lltype.Signed, c_thread_get_ident())
@@ -113,6 +114,12 @@
def __del__(self):
free_ll_lock(self._lock)
+ def __enter__(self):
+ self.acquire(True)
+
+ def __exit__(self, *args):
+ self.release()
+
# ____________________________________________________________
#
# Stack size
diff --git a/pypy/objspace/flow/model.py b/pypy/objspace/flow/model.py
--- a/pypy/objspace/flow/model.py
+++ b/pypy/objspace/flow/model.py
@@ -379,27 +379,6 @@
return result
-def traverse(visit, functiongraph):
- block = functiongraph.startblock
- visit(block)
- seen = identity_dict()
- seen[block] = True
- stack = list(block.exits[::-1])
- while stack:
- link = stack.pop()
- visit(link)
- block = link.target
- if block not in seen:
- visit(block)
- seen[block] = True
- stack += block.exits[::-1]
-
-
-def flatten(funcgraph):
- l = []
- traverse(l.append, funcgraph)
- return l
-
def flattenobj(*args):
for arg in args:
try:
@@ -497,6 +476,19 @@
assert block.operations == ()
assert block.exits == ()
+ def definevar(v, only_in_link=None):
+ assert isinstance(v, Variable)
+ assert v not in vars, "duplicate variable %r" % (v,)
+ assert v not in vars_previous_blocks, (
+ "variable %r used in more than one block" % (v,))
+ vars[v] = only_in_link
+
+ def usevar(v, in_link=None):
+ assert v in vars
+ if in_link is not None:
+ assert vars[v] is None or vars[v] is in_link
+
+
for block in graph.iterblocks():
assert bool(block.isstartblock) == (block is graph.startblock)
assert type(block.exits) is tuple, (
@@ -506,18 +498,6 @@
assert block in exitblocks
vars = {}
- def definevar(v, only_in_link=None):
- assert isinstance(v, Variable)
- assert v not in vars, "duplicate variable %r" % (v,)
- assert v not in vars_previous_blocks, (
- "variable %r used in more than one block" % (v,))
- vars[v] = only_in_link
-
- def usevar(v, in_link=None):
- assert v in vars
- if in_link is not None:
- assert vars[v] is None or vars[v] is in_link
-
for v in block.inputargs:
definevar(v)
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -46,15 +46,15 @@
w_f_trace = None
# For tracing
instr_lb = 0
- instr_ub = -1
- instr_prev = -1
+ instr_ub = 0
+ instr_prev_plus_one = 0
is_being_profiled = False
def __init__(self, space, code, w_globals, closure):
self = hint(self, access_directly=True, fresh_virtualizable=True)
assert isinstance(code, pycode.PyCode)
self.pycode = code
- eval.Frame.__init__(self, space, w_globals, code.co_nlocals)
+ eval.Frame.__init__(self, space, w_globals)
self.valuestack_w = [None] * code.co_stacksize
self.valuestackdepth = 0
self.lastblock = None
@@ -63,7 +63,7 @@
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
# class bodies only have CO_NEWLOCALS.
self.initialize_frame_scopes(closure, code)
- self.fastlocals_w = [None]*self.numlocals
+ self.fastlocals_w = [None] * code.co_nlocals
make_sure_not_resized(self.fastlocals_w)
self.f_lineno = code.co_firstlineno
@@ -335,7 +335,7 @@
w(self.instr_lb), #do we need these three (that are for tracing)
w(self.instr_ub),
- w(self.instr_prev),
+ w(self.instr_prev_plus_one),
w_cells,
]
@@ -349,7 +349,7 @@
args_w = space.unpackiterable(w_args)
w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, w_exc_value, w_tb,\
w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, w_f_locals, \
- w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev, w_cells = args_w
+ w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, w_cells = args_w
new_frame = self
pycode = space.interp_w(PyCode, w_pycode)
@@ -397,7 +397,7 @@
new_frame.instr_lb = space.int_w(w_instr_lb) #the three for tracing
new_frame.instr_ub = space.int_w(w_instr_ub)
- new_frame.instr_prev = space.int_w(w_instr_prev)
+ new_frame.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
self._setcellvars(cellvars)
# XXX what if the frame is in another thread??
@@ -430,7 +430,10 @@
"""Initialize cellvars from self.fastlocals_w
This is overridden in nestedscope.py"""
pass
-
+
+ def getfastscopelength(self):
+ return self.pycode.co_nlocals
+
def getclosure(self):
return None
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -13,7 +13,7 @@
and not p.basename.startswith('test')]
essential_modules = dict.fromkeys(
- ["exceptions", "_file", "sys", "__builtin__", "posix", "signal"]
+ ["exceptions", "_file", "sys", "__builtin__", "posix"]
)
default_modules = essential_modules.copy()
@@ -39,7 +39,7 @@
translation_modules = default_modules.copy()
translation_modules.update(dict.fromkeys(
["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
- "struct", "md5", "cStringIO", "array"]))
+ "struct", "_md5", "cStringIO", "array"]))
working_oo_modules = default_modules.copy()
working_oo_modules.update(dict.fromkeys(
diff --git a/pypy/translator/simplify.py b/pypy/translator/simplify.py
--- a/pypy/translator/simplify.py
+++ b/pypy/translator/simplify.py
@@ -9,7 +9,7 @@
from pypy.objspace.flow import operation
from pypy.objspace.flow.model import (SpaceOperation, Variable, Constant, Block,
Link, c_last_exception, checkgraph,
- traverse, mkentrymap)
+ mkentrymap)
from pypy.rlib import rarithmetic
from pypy.translator import unsimplify
from pypy.translator.backendopt import ssa
@@ -76,23 +76,19 @@
def desugar_isinstance(graph):
"""Replace isinstance operation with a call to isinstance."""
constant_isinstance = Constant(isinstance)
- def visit(block):
- if not isinstance(block, Block):
- return
+ for block in graph.iterblocks():
for i in range(len(block.operations) - 1, -1, -1):
op = block.operations[i]
if op.opname == "isinstance":
args = [constant_isinstance, op.args[0], op.args[1]]
new_op = SpaceOperation("simple_call", args, op.result)
block.operations[i] = new_op
- traverse(visit, graph)
def eliminate_empty_blocks(graph):
"""Eliminate basic blocks that do not contain any operations.
When this happens, we need to replace the preceeding link with the
following link. Arguments of the links should be updated."""
- def visit(link):
- if isinstance(link, Link):
+ for link in list(graph.iterlinks()):
while not link.target.operations:
block1 = link.target
if block1.exitswitch is not None:
@@ -113,7 +109,6 @@
link.args = outputargs
link.target = exit.target
# the while loop above will simplify recursively the new link
- traverse(visit, graph)
def transform_ovfcheck(graph):
"""The special function calls ovfcheck and ovfcheck_lshift need to
@@ -174,11 +169,10 @@
def rename(v):
return renaming.get(v, v)
- def visit(block):
- if not (isinstance(block, Block)
- and block.exitswitch == clastexc
+ for block in graph.iterblocks():
+ if not (block.exitswitch == clastexc
and block.exits[-1].exitcase is Exception):
- return
+ continue
covered = [link.exitcase for link in block.exits[1:-1]]
seen = []
preserve = list(block.exits[:-1])
@@ -233,8 +227,6 @@
exits.append(link)
block.recloseblock(*(preserve + exits))
- traverse(visit, graph)
-
def transform_xxxitem(graph):
# xxx setitem too
for block in graph.iterblocks():
@@ -262,9 +254,9 @@
return True
return False
- def visit(block):
- if not (isinstance(block, Block) and block.exitswitch == clastexc):
- return
+ for block in list(graph.iterblocks()):
+ if block.exitswitch != clastexc:
+ continue
exits = []
seen = []
for link in block.exits:
@@ -283,8 +275,6 @@
seen.append(case)
block.recloseblock(*exits)
- traverse(visit, graph)
-
def join_blocks(graph):
"""Links can be deleted if they are the single exit of a block and
the single entry point of the next block. When this happens, we can
@@ -340,8 +330,7 @@
this is how implicit exceptions are removed (see _implicit_ in
flowcontext.py).
"""
- def visit(block):
- if isinstance(block, Block):
+ for block in list(graph.iterblocks()):
for i in range(len(block.exits)-1, -1, -1):
exit = block.exits[i]
if not (exit.target is graph.exceptblock and
@@ -361,7 +350,6 @@
lst = list(block.exits)
del lst[i]
block.recloseblock(*lst)
- traverse(visit, graph)
# _____________________________________________________________________
@@ -627,12 +615,11 @@
tgts.append((exit.exitcase, tgt))
return tgts
- def visit(block):
- if isinstance(block, Block) and block.operations and block.operations[-1].opname == 'is_true':
+ for block in graph.iterblocks():
+ if block.operations and block.operations[-1].opname == 'is_true':
tgts = has_is_true_exitpath(block)
if tgts:
candidates.append((block, tgts))
- traverse(visit, graph)
while candidates:
cand, tgts = candidates.pop()
diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py
--- a/pypy/translator/stackless/transform.py
+++ b/pypy/translator/stackless/transform.py
@@ -2,7 +2,7 @@
from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS
from pypy.rlib import rarithmetic
from pypy.rpython import rclass, rmodel
-from pypy.translator.backendopt import support
+from pypy.translator.unsimplify import split_block
from pypy.objspace.flow import model
from pypy.translator import unsimplify, simplify
from pypy.translator.unsimplify import varoftype
@@ -598,7 +598,7 @@
link = block.exits[0]
nextblock = None
else:
- link = support.split_block_with_keepalive(block, i+1)
+ link = split_block(None, block, i+1)
i = 0
nextblock = link.target
@@ -765,7 +765,7 @@
exitcases = dict.fromkeys([l.exitcase for l in block.exits])
nextblock = None
else:
- link = support.split_block_with_keepalive(block, i+1)
+ link = split_block(None, block, i+1)
nextblock = link.target
block.exitswitch = model.c_last_exception
link.llexitcase = None
diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py
--- a/pypy/rpython/lltypesystem/rlist.py
+++ b/pypy/rpython/lltypesystem/rlist.py
@@ -16,7 +16,6 @@
from pypy.rlib.debug import ll_assert
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rpython.lltypesystem import rffi
-from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib import rgc
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -5,6 +5,25 @@
import os, sys
exec 'import %s as posix' % os.name
+# this is the list of function which is *not* present in the posix module of
+# IronPython 2.6, and that we want to ignore for now
+lltype_only_defs = [
+ 'chown', 'chroot', 'closerange', 'confstr', 'confstr_names', 'ctermid', 'dup',
+ 'dup2', 'execv', 'execve', 'fchdir', 'fchmod', 'fchown', 'fdatasync', 'fork',
+ 'forkpty', 'fpathconf', 'fstatvfs', 'fsync', 'ftruncate', 'getegid', 'geteuid',
+ 'getgid', 'getgroups', 'getloadavg', 'getlogin', 'getpgid', 'getpgrp', 'getppid',
+ 'getsid', 'getuid', 'kill', 'killpg', 'lchown', 'link', 'lseek', 'major',
+ 'makedev', 'minor', 'mkfifo', 'mknod', 'nice', 'openpty', 'pathconf', 'pathconf_names',
+ 'pipe', 'readlink', 'setegid', 'seteuid', 'setgid', 'setgroups', 'setpgid', 'setpgrp',
+ 'setregid', 'setreuid', 'setsid', 'setuid', 'stat_float_times', 'statvfs',
+ 'statvfs_result', 'symlink', 'sysconf', 'sysconf_names', 'tcgetpgrp', 'tcsetpgrp',
+ 'ttyname', 'uname', 'wait', 'wait3', 'wait4'
+ ]
+
+# the Win32 urandom implementation isn't going to translate on JVM or CLI so
+# we have to remove it
+lltype_only_defs.append('urandom')
+
class Module(MixedModule):
"""This module provides access to operating system functionality that is
standardized by the C Standard and the POSIX standard (a thinly
@@ -33,6 +52,8 @@
appleveldefs['wait'] = 'app_posix.wait'
if hasattr(os, 'wait3'):
appleveldefs['wait3'] = 'app_posix.wait3'
+ if hasattr(os, 'wait4'):
+ appleveldefs['wait4'] = 'app_posix.wait4'
interpleveldefs = {
'open' : 'interp_posix.open',
@@ -158,11 +179,12 @@
interpleveldefs[name] = 'interp_posix.' + name
def __init__(self, space, w_name):
+ # if it's an ootype translation, remove all the defs that are lltype
+ # only
backend = space.config.translation.backend
- # the Win32 urandom implementation isn't going to translate on JVM or CLI
- # so we have to remove it
- if 'urandom' in self.interpleveldefs and (backend == 'cli' or backend == 'jvm'):
- del self.interpleveldefs['urandom']
+ if backend == 'cli' or backend == 'jvm':
+ for name in lltype_only_defs:
+ self.interpleveldefs.pop(name, None)
MixedModule.__init__(self, space, w_name)
def startup(self, space):
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
@@ -1000,6 +1000,13 @@
p = ctypes2lltype(lltype.Ptr(NODE), ctypes.pointer(pc))
assert p.pong.ping == p
+ def test_typedef(self):
+ assert ctypes2lltype(lltype.Typedef(lltype.Signed, 'test'), 6) == 6
+ assert ctypes2lltype(lltype.Typedef(lltype.Float, 'test2'), 3.4) == 3.4
+
+ assert get_ctypes_type(lltype.Signed) == get_ctypes_type(
+ lltype.Typedef(lltype.Signed, 'test3'))
+
def test_cast_adr_to_int(self):
class someaddr(object):
def _cast_to_int(self):
@@ -1014,7 +1021,7 @@
node = lltype.malloc(NODE)
ref = lltype.cast_opaque_ptr(llmemory.GCREF, node)
back = rffi.cast(llmemory.GCREF, rffi.cast(lltype.Signed, ref))
- assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), ref) == node
+ assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), back) == node
def test_gcref_forth_and_back(self):
cp = ctypes.c_void_p(1234)
diff --git a/pypy/rpython/extfunc.py b/pypy/rpython/extfunc.py
--- a/pypy/rpython/extfunc.py
+++ b/pypy/rpython/extfunc.py
@@ -249,6 +249,9 @@
llfakeimpl, oofakeimpl: optional; if provided, they are called by the llinterpreter
sandboxsafe: use True if the function performs no I/O (safe for --sandbox)
"""
+
+ if export_name is None:
+ export_name = function.__name__
class FunEntry(ExtFuncEntry):
_about_ = function
diff --git a/pypy/translator/goal/query.py b/pypy/translator/goal/query.py
--- a/pypy/translator/goal/query.py
+++ b/pypy/translator/goal/query.py
@@ -30,15 +30,13 @@
def polluted_qgen(translator):
"""list functions with still real SomeObject variables"""
annotator = translator.annotator
- def visit(block):
- if isinstance(block, flowmodel.Block):
- for v in block.getvariables():
- s = annotator.binding(v, None)
- if s and s.__class__ == annmodel.SomeObject and s.knowntype != type:
- raise Found
for g in translator.graphs:
try:
- flowmodel.traverse(visit, g)
+ for block in g.iterblocks():
+ for v in block.getvariables():
+ s = annotator.binding(v, None)
+ if s and s.__class__ == annmodel.SomeObject and s.knowntype != type:
+ raise Found
except Found:
line = "%s: %s" % (g, graph_sig(translator, g))
yield line
diff --git a/pypy/tool/jitlogparser/storage.py b/pypy/tool/jitlogparser/storage.py
--- a/pypy/tool/jitlogparser/storage.py
+++ b/pypy/tool/jitlogparser/storage.py
@@ -30,18 +30,18 @@
self.codes[fname] = res
return res
- def disassemble_code(self, fname, startlineno):
+ def disassemble_code(self, fname, startlineno, name):
try:
if py.path.local(fname).check(file=False):
return None # cannot find source file
except py.error.EACCES:
return None # cannot open the file
- key = (fname, startlineno)
+ key = (fname, startlineno, name)
try:
return self.disassembled_codes[key]
except KeyError:
codeobjs = self.load_code(fname)
- if startlineno not in codeobjs:
+ if (startlineno, name) not in codeobjs:
# cannot find the code obj at this line: this can happen for
# various reasons, e.g. because the .py files changed since
# the log was produced, or because the co_firstlineno
@@ -49,7 +49,7 @@
# produced by gateway.applevel(), such as the ones found in
# nanos.py)
return None
- code = codeobjs[startlineno]
+ code = codeobjs[(startlineno, name)]
res = dis(code)
self.disassembled_codes[key] = res
return res
diff --git a/pypy/jit/metainterp/test/test_longlong.py b/pypy/jit/metainterp/test/test_longlong.py
--- a/pypy/jit/metainterp/test/test_longlong.py
+++ b/pypy/jit/metainterp/test/test_longlong.py
@@ -1,6 +1,6 @@
import py, sys
from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class WrongResult(Exception):
pass
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -110,6 +110,13 @@
__dict__ = 8
raises(TypeError, dir, Foo("foo"))
+ def test_dir_broken_object(self):
+ class Foo(object):
+ x = 3
+ def __getattribute__(self, name):
+ return name
+ assert dir(Foo()) == []
+
def test_dir_custom(self):
class Foo(object):
def __dir__(self):
diff --git a/lib_pypy/_ctypes/builtin.py b/lib_pypy/_ctypes/builtin.py
--- a/lib_pypy/_ctypes/builtin.py
+++ b/lib_pypy/_ctypes/builtin.py
@@ -1,6 +1,9 @@
import _rawffi, sys
-import threading
+try:
+ from thread import _local as local
+except ImportError:
+ local = object # no threads
class ConvMode:
encoding = 'ascii'
@@ -28,7 +31,7 @@
arg = cobj._get_buffer_value()
return _rawffi.wcharp2rawunicode(arg, lgt)
-class ErrorObject(threading.local):
+class ErrorObject(local):
def __init__(self):
self.errno = 0
self.winerror = 0
diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py
--- a/pypy/module/cpyext/test/test_stringobject.py
+++ b/pypy/module/cpyext/test/test_stringobject.py
@@ -194,8 +194,8 @@
c_buf = py_str.c_ob_type.c_tp_as_buffer
assert c_buf
py_obj = rffi.cast(PyObject, py_str)
- assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(rffi.INTP.TO)) == 1
- ref = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+ assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(Py_ssize_tP.TO)) == 1
+ ref = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw')
assert c_buf.c_bf_getsegcount(py_obj, ref) == 1
assert ref[0] == 10
lltype.free(ref, flavor='raw')
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -255,7 +255,7 @@
x = ord(s[0]) << 7
i = 0
while i < length:
- x = (1000003*x) ^ ord(s[i])
+ x = intmask((1000003*x) ^ ord(s[i]))
i += 1
x ^= length
return intmask(x)
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
@@ -95,6 +95,8 @@
__slots__ = ['__dict__', '__cached_hash']
def __eq__(self, other):
+ if isinstance(other, Typedef):
+ return other.__eq__(self)
return self.__class__ is other.__class__ and (
self is other or safe_equal(self.__dict__, other.__dict__))
@@ -194,6 +196,36 @@
raise NotImplementedError
+class Typedef(LowLevelType):
+ """A typedef is just another name for an existing type"""
+ def __init__(self, OF, c_name):
+ """
+ @param OF: the equivalent rffi type
+ @param c_name: the name we want in C code
+ """
+ assert isinstance(OF, LowLevelType)
+ # Look through typedefs, so other places don't have to
+ if isinstance(OF, Typedef):
+ OF = OF.OF # haha
+ self.OF = OF
+ self.c_name = c_name
+
+ def __repr__(self):
+ return '<Typedef "%s" of %r>' % (self.c_name, self.OF)
+
+ def __eq__(self, other):
+ return other == self.OF
+
+ def __getattr__(self, name):
+ return self.OF.get(name)
+
+ def _defl(self, parent=None, parentindex=None):
+ return self.OF._defl()
+
+ def _allocate(self, initialization, parent=None, parentindex=None):
+ return self.OF._allocate(initialization, parent, parentindex)
+
+
class Struct(ContainerType):
_gckind = 'raw'
diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py
--- a/pypy/translator/jvm/typesystem.py
+++ b/pypy/translator/jvm/typesystem.py
@@ -181,6 +181,7 @@
jIntegerClass = JvmClassType('java.lang.Integer')
jLongClass = JvmClassType('java.lang.Long')
+jShortClass = JvmClassType('java.lang.Short')
jDoubleClass = JvmClassType('java.lang.Double')
jByteClass = JvmClassType('java.lang.Byte')
jCharClass = JvmClassType('java.lang.Character')
@@ -239,6 +240,7 @@
jDouble = JvmScalarType('D', jDoubleClass, 'doubleValue')
jByte = JvmScalarType('B', jByteClass, 'byteValue')
jChar = JvmScalarType('C', jCharClass, 'charValue')
+jShort = JvmScalarType('S', jShortClass, 'shortValue')
class Generifier(object):
@@ -527,6 +529,7 @@
if desc == 'C': return self._o("i") # Characters
if desc == 'B': return self._o("i") # Bytes
if desc == 'Z': return self._o("i") # Boolean
+ if desc == 'S': return self._o("i") # Short
assert False, "Unknown argtype=%s" % repr(argtype)
raise NotImplementedError
@@ -625,6 +628,7 @@
NOP = Opcode('nop')
I2D = Opcode('i2d')
I2L = Opcode('i2l')
+I2S = Opcode('i2s')
D2I= Opcode('d2i')
#D2L= Opcode('d2l') #PAUL
L2I = Opcode('l2i')
@@ -891,6 +895,7 @@
SYSTEMIDENTITYHASH = Method.s(jSystem, 'identityHashCode', (jObject,), jInt)
SYSTEMGC = Method.s(jSystem, 'gc', (), jVoid)
INTTOSTRINGI = Method.s(jIntegerClass, 'toString', (jInt,), jString)
+SHORTTOSTRINGS = Method.s(jShortClass, 'toString', (jShort,), jString)
LONGTOSTRINGL = Method.s(jLongClass, 'toString', (jLong,), jString)
DOUBLETOSTRINGD = Method.s(jDoubleClass, 'toString', (jDouble,), jString)
CHARTOSTRINGC = Method.s(jCharClass, 'toString', (jChar,), jString)
@@ -922,15 +927,19 @@
CLASSISASSIGNABLEFROM = Method.v(jClass, 'isAssignableFrom', (jClass,), jBool)
STRINGBUILDERAPPEND = Method.v(jStringBuilder, 'append',
(jString,), jStringBuilder)
+PYPYINTBETWEEN = Method.s(jPyPy, 'int_between', (jInt,jInt,jInt), jBool)
PYPYUINTCMP = Method.s(jPyPy, 'uint_cmp', (jInt,jInt,), jInt)
PYPYULONGCMP = Method.s(jPyPy, 'ulong_cmp', (jLong,jLong), jInt)
PYPYUINTMOD = Method.v(jPyPy, 'uint_mod', (jInt, jInt), jInt)
PYPYUINTMUL = Method.v(jPyPy, 'uint_mul', (jInt, jInt), jInt)
PYPYUINTDIV = Method.v(jPyPy, 'uint_div', (jInt, jInt), jInt)
PYPYULONGMOD = Method.v(jPyPy, 'ulong_mod', (jLong, jLong), jLong)
+PYPYUINTTOLONG = Method.s(jPyPy, 'uint_to_long', (jInt,), jLong)
PYPYUINTTODOUBLE = Method.s(jPyPy, 'uint_to_double', (jInt,), jDouble)
PYPYDOUBLETOUINT = Method.s(jPyPy, 'double_to_uint', (jDouble,), jInt)
PYPYDOUBLETOLONG = Method.v(jPyPy, 'double_to_long', (jDouble,), jLong) #PAUL
+PYPYDOUBLETOULONG = Method.s(jPyPy, 'double_to_ulong', (jDouble,), jLong)
+PYPYULONGTODOUBLE = Method.s(jPyPy, 'ulong_to_double', (jLong,), jDouble)
PYPYLONGBITWISENEGATE = Method.v(jPyPy, 'long_bitwise_negate', (jLong,), jLong)
PYPYSTRTOINT = Method.v(jPyPy, 'str_to_int', (jString,), jInt)
PYPYSTRTOUINT = Method.v(jPyPy, 'str_to_uint', (jString,), jInt)
diff --git a/pypy/translator/backendopt/test/test_removenoops.py b/pypy/translator/backendopt/test/test_removenoops.py
--- a/pypy/translator/backendopt/test/test_removenoops.py
+++ b/pypy/translator/backendopt/test/test_removenoops.py
@@ -1,12 +1,12 @@
from pypy.translator.backendopt.removenoops import remove_same_as, \
- remove_unaryops, remove_duplicate_casts, remove_superfluous_keep_alive
+ remove_unaryops, remove_duplicate_casts
from pypy.translator.backendopt.inline import simple_inline_function
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.memory.gctransform.test.test_transform import getops
from pypy.translator.test.snippet import simple_method
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.backendopt.all import INLINE_THRESHOLD_FOR_TEST
-from pypy.objspace.flow.model import checkgraph, flatten, Block
+from pypy.objspace.flow.model import checkgraph, Block
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.llinterp import LLInterpreter
@@ -115,20 +115,6 @@
result = interp.eval_graph(f_graph, [-2])
assert result == -1
-def test_remove_keepalive():
- S = lltype.GcStruct("s", ("f", lltype.Signed))
- def f():
- s1 = lltype.malloc(S)
- llop.keepalive(lltype.Void, s1)
- s2 = lltype.malloc(S)
- llop.keepalive(lltype.Void, s1)
- llop.keepalive(lltype.Void, s2)
- return lltype.cast_ptr_to_int(s1) + lltype.cast_ptr_to_int(s2)
- graph, t = get_graph(f, [])
- remove_superfluous_keep_alive(graph)
- ops = getops(graph)
- assert len(ops['keepalive']) == 2
-
def test_remove_duplicate_casts():
class A(object):
def __init__(self, x, y):
diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py
--- a/pypy/translator/cli/metavm.py
+++ b/pypy/translator/cli/metavm.py
@@ -270,23 +270,38 @@
generator.ilasm.call('void [pypylib]pypy.runtime.DebugPrint::DEBUG_PRINT(%s)' % signature)
+INT_SIZE = {
+ ootype.Bool: 1,
+ ootype.Char: 2,
+ ootype.UniChar: 2,
+ rffi.SHORT: 2,
+ ootype.Signed: 4,
+ ootype.Unsigned: 4,
+ ootype.SignedLongLong: 8,
+ ootype.UnsignedLongLong: 8
+ }
-OOTYPE_TO_MNEMONIC = {
- ootype.Bool: 'i1',
- ootype.Char: 'i2',
- ootype.UniChar: 'i2',
- rffi.SHORT: 'i2',
- ootype.Signed: 'i4',
- ootype.SignedLongLong: 'i8',
- ootype.Unsigned: 'u4',
- ootype.UnsignedLongLong: 'u8',
- ootype.Float: 'r8',
- }
+UNSIGNED_TYPES = [ootype.Char, ootype.UniChar, rffi.USHORT,
+ ootype.Unsigned, ootype.UnsignedLongLong]
+
+def ootype_to_mnemonic(FROM, TO, default=None):
+ if TO == ootype.Float:
+ return 'r8'
+ #
+ try:
+ size = str(INT_SIZE[TO])
+ except KeyError:
+ return default
+ if FROM in UNSIGNED_TYPES:
+ return 'u' + size
+ else:
+ return 'i' + size
class _CastPrimitive(MicroInstruction):
def render(self, generator, op):
+ FROM = op.args[0].concretetype
TO = op.result.concretetype
- mnemonic = OOTYPE_TO_MNEMONIC[TO]
+ mnemonic = ootype_to_mnemonic(FROM, TO)
generator.ilasm.opcode('conv.%s' % mnemonic)
Call = _Call()
diff --git a/pypy/module/cpyext/include/frameobject.h b/pypy/module/cpyext/include/frameobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/frameobject.h
@@ -0,0 +1,17 @@
+#ifndef Py_FRAMEOBJECT_H
+#define Py_FRAMEOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ PyCodeObject *f_code;
+ PyObject *f_globals;
+ int f_lineno;
+} PyFrameObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_FRAMEOBJECT_H */
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -5,7 +5,7 @@
from pypy.rlib.libffi import ArgChain
from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class TestFfiCall(LLJitMixin, _TestLibffiCall):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -138,11 +138,13 @@
# raised after the exception handler block was popped.
try:
trace = self.w_f_trace
- self.w_f_trace = None
+ if trace is not None:
+ self.w_f_trace = None
try:
ec.bytecode_trace_after_exception(self)
finally:
- self.w_f_trace = trace
+ if trace is not None:
+ self.w_f_trace = trace
except OperationError, e:
operr = e
pytraceback.record_application_traceback(
@@ -1421,9 +1423,10 @@
# add a softspace unless we just printed a string which ends in a '\t'
# or '\n' -- or more generally any whitespace character but ' '
- if isinstance(x, str) and x and x[-1].isspace() and x[-1]!=' ':
- return
- # XXX add unicode handling
+ if isinstance(x, (str, unicode)) and x:
+ lastchar = x[-1]
+ if lastchar.isspace() and lastchar != ' ':
+ return
file_softspace(stream, True)
print_item_to._annspecialcase_ = "specialize:argtype(0)"
diff --git a/pypy/translator/goal/old_queries.py b/pypy/translator/goal/old_queries.py
--- a/pypy/translator/goal/old_queries.py
+++ b/pypy/translator/goal/old_queries.py
@@ -415,12 +415,10 @@
ops = 0
count = Counter()
def visit(block):
- if isinstance(block, flowmodel.Block):
+ for block in graph.iterblocks():
count.blocks += 1
count.ops += len(block.operations)
- elif isinstance(block, flowmodel.Link):
- count.links += 1
- flowmodel.traverse(visit, graph)
+ count.links = len(list(graph.iterlinks()))
return count.blocks, count.links, count.ops
# better used before backends opts
diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py
--- a/pypy/module/_multiprocessing/test/test_connection.py
+++ b/pypy/module/_multiprocessing/test/test_connection.py
@@ -10,7 +10,7 @@
class AppTestBufferTooShort:
def setup_class(cls):
- space = gettestobjspace(usemodules=('_multiprocessing', 'thread'))
+ space = gettestobjspace(usemodules=('_multiprocessing', 'thread', 'signal'))
cls.space = space
if option.runappdirect:
@@ -88,7 +88,7 @@
class AppTestSocketConnection(BaseConnectionTest):
def setup_class(cls):
- space = gettestobjspace(usemodules=('_multiprocessing', 'thread'))
+ space = gettestobjspace(usemodules=('_multiprocessing', 'thread', 'signal'))
cls.space = space
cls.w_connections = space.newlist([])
diff --git a/pypy/module/thread/test/support.py b/pypy/module/thread/test/support.py
--- a/pypy/module/thread/test/support.py
+++ b/pypy/module/thread/test/support.py
@@ -32,7 +32,7 @@
class GenericTestThread:
def setup_class(cls):
- space = gettestobjspace(usemodules=('thread', 'time'))
+ space = gettestobjspace(usemodules=('thread', 'time', 'signal'))
cls.space = space
if option.runappdirect:
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -219,12 +219,14 @@
freevars = [self.space.interp_w(Cell, cell)
for cell in self.space.fixedview(w_freevarstuple)]
else:
- nfreevars = len(codeobj.co_freevars)
- freevars = [self.space.interp_w(Cell, self.popvalue())
- for i in range(nfreevars)]
- freevars.reverse()
- defaultarguments = [self.popvalue() for i in range(numdefaults)]
- defaultarguments.reverse()
+ n = len(codeobj.co_freevars)
+ freevars = [None] * n
+ while True:
+ n -= 1
+ if n < 0:
+ break
+ freevars[n] = self.space.interp_w(Cell, self.popvalue())
+ defaultarguments = self.popvalues(numdefaults)
fn = function.Function(self.space, codeobj, self.w_globals,
defaultarguments, freevars)
self.pushvalue(self.space.wrap(fn))
diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs
--- a/pypy/translator/cli/src/debug.cs
+++ b/pypy/translator/cli/src/debug.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Collections.Generic;
using System.Diagnostics;
// this code is modeled after translator/c/src/debug.h
@@ -21,7 +22,7 @@
static int have_debug_prints = -1;
static bool debug_ready = false;
static bool debug_profile = false;
- static string debug_prefix = null;
+ static string[] active_categories = null;
public static void close_file()
{
@@ -29,6 +30,14 @@
debug_file.Close();
}
+ public static bool startswithoneof(string category, string[] active_categories)
+ {
+ foreach(string cat in active_categories)
+ if (category.StartsWith(cat))
+ return true;
+ return false;
+ }
+
public static bool HAVE_DEBUG_PRINTS()
{
if ((have_debug_prints & 1) != 0) {
@@ -48,7 +57,8 @@
have_debug_prints <<= 1;
if (!debug_profile) {
/* non-profiling version */
- if (debug_prefix == null || !category.StartsWith(debug_prefix)) {
+ if (active_categories == null ||
+ !startswithoneof(category, active_categories)) {
/* wrong section name, or no PYPYLOG at all, skip it */
return;
}
@@ -83,7 +93,8 @@
}
else {
/* PYPYLOG=prefix:filename --- conditional logging */
- debug_prefix = filename.Substring(0, colon);
+ string debug_prefix = filename.Substring(0, colon);
+ active_categories = debug_prefix.Split(',');
filename = filename.Substring(colon+1);
}
if (filename != "-")
diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs
--- a/pypy/translator/cli/src/pypylib.cs
+++ b/pypy/translator/cli/src/pypylib.cs
@@ -501,6 +501,11 @@
}
}
+ public static bool IntBetween(int a, int b, int c)
+ {
+ return a <= b && b < c;
+ }
+
public static bool Equal<T>(T t1, T t2)
{
if (t1 == null)
@@ -1148,10 +1153,36 @@
public class rffi
{
- public static int tolower(int chr)
- {
- return (int)Char.ToLower((char)chr);
- }
+ public static int tolower(int chr)
+ {
+ return (int)Char.ToLower((char)chr);
+ }
+
+ public static int locale_tolower(int chr)
+ {
+ return (int)Char.ToLower((char)chr);
+ }
+
+ public static int locale_isupper(int chr)
+ {
+ return Convert.ToInt32(Char.IsUpper((char)chr));
+ }
+
+ public static int locale_islower(int chr)
+ {
+ return Convert.ToInt32(Char.IsLower((char)chr));
+ }
+
+ public static int locale_isalpha(int chr)
+ {
+ return Convert.ToInt32(Char.IsLetter((char)chr));
+ }
+
+ public static int locale_isalnum(int chr)
+ {
+ return Convert.ToInt32(Char.IsLetterOrDigit((char)chr));
+ }
+
}
}
diff --git a/pypy/jit/backend/x86/test/test_basic.py b/pypy/jit/backend/x86/test/test_basic.py
--- a/pypy/jit/backend/x86/test/test_basic.py
+++ b/pypy/jit/backend/x86/test/test_basic.py
@@ -1,18 +1,18 @@
import py
from pypy.jit.backend.detect_cpu import getcpuclass
from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.jit.metainterp.test import test_basic
+from pypy.jit.metainterp.test import support, test_ajit
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rlib.jit import JitDriver
-class Jit386Mixin(test_basic.LLJitMixin):
+class Jit386Mixin(support.LLJitMixin):
type_system = 'lltype'
CPUClass = getcpuclass()
def check_jumps(self, maxcount):
pass
-class TestBasic(Jit386Mixin, test_basic.BaseLLtypeTests):
+class TestBasic(Jit386Mixin, test_ajit.BaseLLtypeTests):
# for the individual tests see
# ====> ../../../metainterp/test/test_basic.py
def test_bug(self):
diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py
--- a/pypy/module/thread/os_local.py
+++ b/pypy/module/thread/os_local.py
@@ -12,7 +12,7 @@
def __init__(self, space, initargs):
self.initargs = initargs
ident = thread.get_ident()
- self.dicts = {ident: space.newdict()}
+ self.dicts = {ident: space.newdict(instance=True)}
def getdict(self, space):
ident = thread.get_ident()
@@ -51,10 +51,6 @@
__dict__ = GetSetProperty(descr_get_dict, cls=Local),
)
-def getlocaltype(space):
- return space.gettypeobject(Local.typedef)
-
-
def finish_thread(w_obj):
assert isinstance(w_obj, Local)
ident = thread.get_ident()
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -29,7 +29,7 @@
from pypy.rpython.lltypesystem.rstr import STR
from pypy.rpython.annlowlevel import llstr
from pypy.rlib import rgc
-from pypy.rlib.objectmodel import keepalive_until_here, specialize
+from pypy.rlib.objectmodel import specialize
def monkeypatch_rposix(posixfunc, unicodefunc, signature):
func_name = posixfunc.__name__
diff --git a/pypy/translator/jvm/src/pypy/StatResult.java b/pypy/translator/jvm/src/pypy/StatResult.java
--- a/pypy/translator/jvm/src/pypy/StatResult.java
+++ b/pypy/translator/jvm/src/pypy/StatResult.java
@@ -8,7 +8,7 @@
*
* <p>The actual stat() function is defined in PyPy.java.
*/
-class StatResult {
+public class StatResult {
public int item0, item3, item4, item5;
public long item1, item2, item6;
public double item7, item8, item9;
diff --git a/pypy/translator/gensupp.py b/pypy/translator/gensupp.py
--- a/pypy/translator/gensupp.py
+++ b/pypy/translator/gensupp.py
@@ -6,15 +6,13 @@
import sys
from pypy.objspace.flow.model import Block
-from pypy.objspace.flow.model import traverse
# ordering the blocks of a graph by source position
def ordered_blocks(graph):
# collect all blocks
allblocks = []
- def visit(block):
- if isinstance(block, Block):
+ for block in graph.iterblocks():
# first we order by offset in the code string
if block.operations:
ofs = block.operations[0].offset
@@ -26,7 +24,6 @@
else:
txt = "dummy"
allblocks.append((ofs, txt, block))
- traverse(visit, graph)
allblocks.sort()
#for ofs, txt, block in allblocks:
# print ofs, txt, block
diff --git a/pypy/translator/jvm/src/pypy/ll_os.java b/pypy/translator/jvm/src/pypy/ll_os.java
--- a/pypy/translator/jvm/src/pypy/ll_os.java
+++ b/pypy/translator/jvm/src/pypy/ll_os.java
@@ -14,10 +14,22 @@
abstract class FileWrapper
{
+ private final String name;
+
+ public FileWrapper(String name)
+ {
+ this.name = name;
+ }
+
public abstract void write(String buffer);
public abstract String read(int count);
public abstract void close();
public abstract RandomAccessFile getFile();
+
+ public String getName()
+ {
+ return this.name;
+ }
}
class PrintStreamWrapper extends FileWrapper
@@ -25,8 +37,9 @@
private final PrintStream stream;
private final ll_os os;
- public PrintStreamWrapper(PrintStream stream, ll_os os)
+ public PrintStreamWrapper(String name, PrintStream stream, ll_os os)
{
+ super(name);
this.stream = stream;
this.os = os;
}
@@ -58,8 +71,9 @@
private final InputStream stream;
private final ll_os os;
- public InputStreamWrapper(InputStream stream, ll_os os)
+ public InputStreamWrapper(String name, InputStream stream, ll_os os)
{
+ super(name);
this.stream = stream;
this.os = os;
}
@@ -102,11 +116,13 @@
private final boolean canWrite;
private final ll_os os;
- public RandomAccessFileWrapper(RandomAccessFile file,
+ public RandomAccessFileWrapper(String name,
+ RandomAccessFile file,
boolean canRead,
boolean canWrite,
ll_os os)
{
+ super(name);
this.file = file;
this.canRead = canRead;
this.canWrite = canWrite;
@@ -228,9 +244,9 @@
public ll_os(Interlink interlink) {
this.interlink = interlink;
- FileDescriptors.put(0, new InputStreamWrapper(System.in, this));
- FileDescriptors.put(1, new PrintStreamWrapper(System.out, this));
- FileDescriptors.put(2, new PrintStreamWrapper(System.err, this));
+ FileDescriptors.put(0, new InputStreamWrapper("<stdin>", System.in, this));
+ FileDescriptors.put(1, new PrintStreamWrapper("<stdout>", System.out, this));
+ FileDescriptors.put(2, new PrintStreamWrapper("<stderr>", System.err, this));
fdcount = 2;
}
@@ -339,7 +355,7 @@
// XXX: we ignore O_CREAT
RandomAccessFile file = open_file(name, javaMode, flags);
RandomAccessFileWrapper wrapper =
- new RandomAccessFileWrapper(file, canRead, canWrite, this);
+ new RandomAccessFileWrapper(name, file, canRead, canWrite, this);
fdcount++;
FileDescriptors.put(fdcount, wrapper);
@@ -418,6 +434,12 @@
return ll_os_stat(path); // XXX
}
+ public StatResult ll_os_fstat(int fd)
+ {
+ String name = getfd(fd).getName();
+ return ll_os_stat(name);
+ }
+
public String ll_os_strerror(int errno)
{
String msg = ErrorMessages.remove(errno);
diff --git a/pypy/translator/jvm/test/test_list.py b/pypy/translator/jvm/test/test_list.py
--- a/pypy/translator/jvm/test/test_list.py
+++ b/pypy/translator/jvm/test/test_list.py
@@ -6,7 +6,10 @@
def test_recursive(self):
py.test.skip("JVM doesn't support recursive lists")
- def test_getitem_exc(self):
+ def test_getitem_exc_1(self):
+ py.test.skip('fixme!')
+
+ def test_getitem_exc_2(self):
py.test.skip('fixme!')
def test_r_short_list(self):
diff --git a/pypy/translator/backendopt/test/test_mallocv.py b/pypy/translator/backendopt/test/test_mallocv.py
--- a/pypy/translator/backendopt/test/test_mallocv.py
+++ b/pypy/translator/backendopt/test/test_mallocv.py
@@ -5,7 +5,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator import simplify
-from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap
+from pypy.objspace.flow.model import checkgraph, Block, mkentrymap
from pypy.objspace.flow.model import summary
from pypy.rpython.llinterp import LLInterpreter, LLException
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
@@ -33,8 +33,7 @@
def check_malloc_removed(cls, graph, expected_mallocs, expected_calls):
count_mallocs = 0
count_calls = 0
- for node in flatten(graph):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname == 'malloc':
count_mallocs += 1
@@ -54,7 +53,7 @@
if option.view:
t.view()
self.original_graph_count = len(t.graphs)
- # to detect missing keepalives and broken intermediate graphs,
+ # to detect broken intermediate graphs,
# we do the loop ourselves instead of calling remove_simple_mallocs()
maxiter = 100
mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True)
@@ -557,36 +556,6 @@
type_system = 'lltype'
#MallocRemover = LLTypeMallocRemover
- def test_with_keepalive(self):
- from pypy.rlib.objectmodel import keepalive_until_here
- def fn1(x, y):
- if x > 0:
- t = x+y, x-y
- else:
- t = x-y, x+y
- s, d = t
- keepalive_until_here(t)
- return s*d
- self.check(fn1, [int, int], [15, 10], 125)
-
- def test_add_keepalives(self):
- class A:
- pass
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
- def fn7(i):
- big = lltype.malloc(BIG)
- a = A()
- a.big = big
- a.small = big.s
- a.small.x = 0
- while i > 0:
- a.small.x += i
- i -= 1
- return a.small.x
- self.check(fn7, [int], [10], 55,
- expected_mallocs=1) # no support for interior structs
-
def test_getsubstruct(self):
SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
@@ -770,39 +739,6 @@
return x.u1.b * x.u2.a
self.check(fn, [], [], DONT_CHECK_RESULT)
- def test_keep_all_keepalives(self):
- SIZE = llmemory.sizeof(lltype.Signed)
- PARRAY = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1))
- class A:
- def __init__(self):
- self.addr = llmemory.raw_malloc(SIZE)
- def __del__(self):
- llmemory.raw_free(self.addr)
- class B:
- pass
- def myfunc():
- b = B()
- b.keep = A()
- b.data = llmemory.cast_adr_to_ptr(b.keep.addr, PARRAY)
- b.data[0] = 42
- ptr = b.data
- # normally 'b' could go away as early as here, which would free
- # the memory held by the instance of A in b.keep...
- res = ptr[0]
- # ...so we explicitly keep 'b' alive until here
- objectmodel.keepalive_until_here(b)
- return res
- graph = self.check(myfunc, [], [], 42,
- expected_mallocs=1, # 'A' instance left
- expected_calls=1) # to A.__init__()
-
- # there is a getarrayitem near the end of the graph of myfunc.
- # However, the memory it accesses must still be protected by the
- # following keepalive, even after malloc removal
- entrymap = mkentrymap(graph)
- [link] = entrymap[graph.returnblock]
- assert link.prevblock.operations[-1].opname == 'keepalive'
-
def test_nested_struct(self):
S = lltype.GcStruct("S", ('x', lltype.Signed))
T = lltype.GcStruct("T", ('s', S))
diff --git a/pypy/jit/metainterp/test/test_loop_unroll.py b/pypy/jit/metainterp/test/test_loop_unroll.py
--- a/pypy/jit/metainterp/test/test_loop_unroll.py
+++ b/pypy/jit/metainterp/test/test_loop_unroll.py
@@ -1,7 +1,7 @@
import py
from pypy.rlib.jit import JitDriver
from pypy.jit.metainterp.test import test_loop
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
class LoopUnrollTest(test_loop.LoopTest):
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
@@ -6,8 +6,12 @@
from pypy.annotation.annrpython import RPythonAnnotator
from pypy.rpython.test.test_llinterp import interpret
from pypy.rpython.lltypesystem.rclass import OBJECTPTR
+from pypy.rpython.ootypesystem.rclass import OBJECT
from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
+
+from pypy.rpython.ootypesystem import ootype
class X(object):
pass
@@ -79,37 +83,48 @@
assert s.s_instance.can_be_None
assert s.s_instance.classdef == a.bookkeeper.getuniqueclassdef(X)
-def test_rtype_1():
- def f():
- return virtual_ref(X())
- x = interpret(f, [])
- assert lltype.typeOf(x) == OBJECTPTR
+class BaseTestVRef(BaseRtypingTest):
+ def test_rtype_1(self):
+ def f():
+ return virtual_ref(X())
+ x = self.interpret(f, [])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
-def test_rtype_2():
- def f():
- x1 = X()
- vref = virtual_ref(x1)
- x2 = vref()
- virtual_ref_finish(x2)
- return x2
- x = interpret(f, [])
- assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0
+ def test_rtype_2(self):
+ def f():
+ x1 = X()
+ vref = virtual_ref(x1)
+ x2 = vref()
+ virtual_ref_finish(x2)
+ return x2
+ x = self.interpret(f, [])
+ assert self.castable(self.OBJECTTYPE, x)
-def test_rtype_3():
- def f(n):
- if n > 0:
- return virtual_ref(Y())
- else:
- return non_virtual_ref(Z())
- x = interpret(f, [-5])
- assert lltype.typeOf(x) == OBJECTPTR
+ def test_rtype_3(self):
+ def f(n):
+ if n > 0:
+ return virtual_ref(Y())
+ else:
+ return non_virtual_ref(Z())
+ x = self.interpret(f, [-5])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
-def test_rtype_4():
- def f(n):
- if n > 0:
- return virtual_ref(X())
- else:
- return vref_None
- x = interpret(f, [-5])
- assert lltype.typeOf(x) == OBJECTPTR
- assert not x
+ def test_rtype_4(self):
+ def f(n):
+ if n > 0:
+ return virtual_ref(X())
+ else:
+ return vref_None
+ x = self.interpret(f, [-5])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
+ assert not x
+
+class TestLLtype(BaseTestVRef, LLRtypeMixin):
+ OBJECTTYPE = OBJECTPTR
+ def castable(self, TO, var):
+ return lltype.castable(TO, lltype.typeOf(var)) > 0
+
+class TestOOtype(BaseTestVRef, OORtypeMixin):
+ OBJECTTYPE = OBJECT
+ def castable(self, TO, var):
+ return ootype.isSubclass(lltype.typeOf(var), TO)
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -245,6 +245,16 @@
expression cmp(o1, o2)."""
return space.int_w(space.cmp(w_o1, w_o2))
+ at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
+def PyObject_Cmp(space, w_o1, w_o2, result):
+ """Compare the values of o1 and o2 using a routine provided by o1, if one
+ exists, otherwise with a routine provided by o2. The result of the
+ comparison is returned in result. Returns -1 on failure. This is the
+ equivalent of the Python statement result = cmp(o1, o2)."""
+ res = space.int_w(space.cmp(w_o1, w_o2))
+ result[0] = rffi.cast(rffi.INT, res)
+ return 0
+
@cpython_api([PyObject, PyObject, rffi.INT_real], PyObject)
def PyObject_RichCompare(space, w_o1, w_o2, opid_int):
"""Compare the values of o1 and o2 using the operation specified by opid,
@@ -385,7 +395,7 @@
raise OperationError(space.w_TypeError, space.wrap(
"expected a character buffer object"))
if generic_cpy_call(space, pb.c_bf_getsegcount,
- obj, lltype.nullptr(rffi.INTP.TO)) != 1:
+ obj, lltype.nullptr(Py_ssize_tP.TO)) != 1:
raise OperationError(space.w_TypeError, space.wrap(
"expected a single-segment buffer object"))
size = generic_cpy_call(space, pb.c_bf_getcharbuffer,
diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py
--- a/pypy/translator/c/gcc/trackgcroot.py
+++ b/pypy/translator/c/gcc/trackgcroot.py
@@ -446,7 +446,6 @@
IGNORE_OPS_WITH_PREFIXES = dict.fromkeys([
'cmp', 'test', 'set', 'sahf', 'lahf', 'cltd', 'cld', 'std',
'rep', 'movs', 'lods', 'stos', 'scas', 'cwtl', 'cwde', 'prefetch',
- 'pslld',
# floating-point operations cannot produce GC pointers
'f',
'cvt', 'ucomi', 'comi', 'subs', 'subp' , 'adds', 'addp', 'xorp',
@@ -457,6 +456,7 @@
'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'mul', 'imul', 'div', 'idiv',
'bswap', 'bt', 'rdtsc',
'punpck', 'pshufd', 'pcmp', 'pand', 'psllw', 'pslld', 'psllq',
+ 'paddq', 'pinsr',
# zero-extending moves should not produce GC pointers
'movz',
])
@@ -1645,7 +1645,7 @@
darwin64='')
print >> output, "%s:" % _globalname('pypy_asm_stackwalk')
- print >> output, """\
+ s = """\
/* See description in asmgcroot.py */
.cfi_startproc
movq\t%rdi, %rdx\t/* 1st argument, which is the callback */
@@ -1691,6 +1691,12 @@
ret
.cfi_endproc
"""
+ if self.format == 'darwin64':
+ # obscure. gcc there seems not to support .cfi_...
+ # hack it out...
+ s = re.sub(r'([.]cfi_[^/\n]+)([/\n])',
+ r'/* \1 disabled on darwin */\2', s)
+ print >> output, s
_variant(elf64='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk',
darwin64='')
else:
diff --git a/pypy/rlib/runicode.py b/pypy/rlib/runicode.py
--- a/pypy/rlib/runicode.py
+++ b/pypy/rlib/runicode.py
@@ -87,8 +87,9 @@
result = UnicodeBuilder(size)
pos = 0
while pos < size:
- ch = s[pos]
- ordch1 = ord(ch)
+ ordch1 = ord(s[pos])
+ # fast path for ASCII
+ # XXX maybe use a while loop here
if ordch1 < 0x80:
result.append(unichr(ordch1))
pos += 1
@@ -98,110 +99,149 @@
if pos + n > size:
if not final:
break
- else:
- endpos = pos + 1
- while endpos < size and ord(s[endpos]) & 0xC0 == 0x80:
- endpos += 1
- r, pos = errorhandler(errors, "utf-8",
- "unexpected end of data",
- s, pos, endpos)
+ charsleft = size - pos - 1 # either 0, 1, 2
+ # note: when we get the 'unexpected end of data' we don't care
+ # about the pos anymore and we just ignore the value
+ if not charsleft:
+ # there's only the start byte and nothing else
+ r, pos = errorhandler(errors, 'utf-8',
+ 'unexpected end of data',
+ s, pos, pos+1)
+ result.append(r)
+ break
+ ordch2 = ord(s[pos+1])
+ if n == 3:
+ # 3-bytes seq with only a continuation byte
+ if (ordch2>>6 != 0x2 or # 0b10
+ (ordch1 == 0xe0 and ordch2 < 0xa0)):
+ # or (ordch1 == 0xed and ordch2 > 0x9f)
+ # second byte invalid, take the first and continue
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+1)
+ result.append(r)
+ continue
+ else:
+ # second byte valid, but third byte missing
+ r, pos = errorhandler(errors, 'utf-8',
+ 'unexpected end of data',
+ s, pos, pos+2)
+ result.append(r)
+ break
+ elif n == 4:
+ # 4-bytes seq with 1 or 2 continuation bytes
+ if (ordch2>>6 != 0x2 or # 0b10
+ (ordch1 == 0xf0 and ordch2 < 0x90) or
+ (ordch1 == 0xf4 and ordch2 > 0x8f)):
+ # second byte invalid, take the first and continue
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+1)
+ result.append(r)
+ continue
+ elif charsleft == 2 and ord(s[pos+2])>>6 != 0x2: # 0b10
+ # third byte invalid, take the first two and continue
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+2)
+ result.append(r)
+ continue
+ else:
+ # there's only 1 or 2 valid cb, but the others are missing
+ r, pos = errorhandler(errors, 'utf-8',
+ 'unexpected end of data',
+ s, pos, pos+charsleft+1)
+ result.append(r)
+ break
+
+ if n == 0:
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid start byte',
+ s, pos, pos+1)
+ result.append(r)
+
+ elif n == 1:
+ assert 0, "ascii should have gone through the fast path"
+
+ elif n == 2:
+ ordch2 = ord(s[pos+1])
+ if ordch2>>6 != 0x2: # 0b10
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+1)
result.append(r)
continue
+ # 110yyyyy 10zzzzzz -> 00000000 00000yyy yyzzzzzz
+ result.append(unichr(((ordch1 & 0x1F) << 6) + # 0b00011111
+ (ordch2 & 0x3F))) # 0b00111111
+ pos += 2
- if n == 0:
- r, pos = errorhandler(errors, "utf-8",
- "invalid start byte",
- s, pos, pos + 1)
- result.append(r)
- elif n == 1:
- assert 0, "you can never get here"
- elif n == 2:
- # 110yyyyy 10zzzzzz ====> 00000000 00000yyy yyzzzzzz
-
- ordch2 = ord(s[pos+1])
- z, two = splitter[6, 2](ordch2)
- y, six = splitter[5, 3](ordch1)
- assert six == 6
- if two != 2:
- r, pos = errorhandler(errors, "utf-8",
- "invalid continuation byte",
- s, pos, pos + 1)
- result.append(r)
- else:
- c = (y << 6) + z
- result.append(unichr(c))
- pos += n
elif n == 3:
- # 1110xxxx 10yyyyyy 10zzzzzz ====> 00000000 xxxxyyyy yyzzzzzz
ordch2 = ord(s[pos+1])
ordch3 = ord(s[pos+2])
- z, two1 = splitter[6, 2](ordch3)
- y, two2 = splitter[6, 2](ordch2)
- x, fourteen = splitter[4, 4](ordch1)
- assert fourteen == 14
- if (two1 != 2 or two2 != 2 or
+ if (ordch2>>6 != 0x2 or # 0b10
(ordch1 == 0xe0 and ordch2 < 0xa0)
# surrogates shouldn't be valid UTF-8!
# Uncomment the line below to make them invalid.
# or (ordch1 == 0xed and ordch2 > 0x9f)
):
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+1)
+ result.append(r)
+ continue
+ elif ordch3>>6 != 0x2: # 0b10
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+2)
+ result.append(r)
+ continue
+ # 1110xxxx 10yyyyyy 10zzzzzz -> 00000000 xxxxyyyy yyzzzzzz
+ result.append(unichr(((ordch1 & 0x0F) << 12) + # 0b00001111
+ ((ordch2 & 0x3F) << 6) + # 0b00111111
+ (ordch3 & 0x3F))) # 0b00111111
+ pos += 3
- # if ordch2 first two bits are 1 and 0, then the invalid
- # continuation byte is ordch3; else ordch2 is invalid.
- if two2 == 2:
- endpos = pos + 2
- else:
- endpos = pos + 1
- r, pos = errorhandler(errors, "utf-8",
- "invalid continuation byte",
- s, pos, endpos)
- result.append(r)
- else:
- c = (x << 12) + (y << 6) + z
- result.append(unichr(c))
- pos += n
elif n == 4:
- # 11110www 10xxxxxx 10yyyyyy 10zzzzzz ====>
- # 000wwwxx xxxxyyyy yyzzzzzz
ordch2 = ord(s[pos+1])
ordch3 = ord(s[pos+2])
ordch4 = ord(s[pos+3])
- z, two1 = splitter[6, 2](ordch4)
- y, two2 = splitter[6, 2](ordch3)
- x, two3 = splitter[6, 2](ordch2)
- w, thirty = splitter[3, 5](ordch1)
- assert thirty == 30
- if (two1 != 2 or two2 != 2 or two3 != 2 or
+ if (ordch2>>6 != 0x2 or # 0b10
(ordch1 == 0xf0 and ordch2 < 0x90) or
(ordch1 == 0xf4 and ordch2 > 0x8f)):
- endpos = pos + 1
- if ordch2 & 0xc0 == 0x80:
- endpos += 1
- if ordch3 & 0xc0 == 0x80:
- endpos += 1
- r, pos = errorhandler(errors, "utf-8",
- "invalid continuation byte",
- s, pos, endpos)
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+1)
result.append(r)
+ continue
+ elif ordch3>>6 != 0x2: # 0b10
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+2)
+ result.append(r)
+ continue
+ elif ordch4>>6 != 0x2: # 0b10
+ r, pos = errorhandler(errors, 'utf-8',
+ 'invalid continuation byte',
+ s, pos, pos+3)
+ result.append(r)
+ continue
+ # 11110www 10xxxxxx 10yyyyyy 10zzzzzz -> 000wwwxx xxxxyyyy yyzzzzzz
+ c = (((ordch1 & 0x07) << 18) + # 0b00000111
+ ((ordch2 & 0x3F) << 12) + # 0b00111111
+ ((ordch3 & 0x3F) << 6) + # 0b00111111
+ (ordch4 & 0x3F)) # 0b00111111
+ if c <= MAXUNICODE:
+ result.append(UNICHR(c))
else:
- c = (w << 18) + (x << 12) + (y << 6) + z
- # convert to UTF-16 if necessary
- if c <= MAXUNICODE:
- result.append(UNICHR(c))
- else:
- # compute and append the two surrogates:
- # translate from 10000..10FFFF to 0..FFFF
- c -= 0x10000
- # high surrogate = top 10 bits added to D800
- result.append(unichr(0xD800 + (c >> 10)))
- # low surrogate = bottom 10 bits added to DC00
- result.append(unichr(0xDC00 + (c & 0x03FF)))
- pos += n
- else:
- r, pos = errorhandler(errors, "utf-8",
- "unsupported Unicode code range",
- s, pos, pos + n)
- result.append(r)
+ # compute and append the two surrogates:
+ # translate from 10000..10FFFF to 0..FFFF
+ c -= 0x10000
+ # high surrogate = top 10 bits added to D800
+ result.append(unichr(0xD800 + (c >> 10)))
+ # low surrogate = bottom 10 bits added to DC00
+ result.append(unichr(0xDC00 + (c & 0x03FF)))
+ pos += 4
return result.build(), pos
@@ -629,7 +669,7 @@
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
# sp ! " # $ % & ' ( ) * + , - . /
2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 0,
-# 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
+# 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
# @ A B C D E F G H I J K L M N O
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -905,20 +945,20 @@
pos = 0
while pos < size:
ch = p[pos]
-
+
if ord(ch) < limit:
result.append(chr(ord(ch)))
pos += 1
else:
# startpos for collecting unencodable chars
- collstart = pos
- collend = pos+1
+ collstart = pos
+ collend = pos+1
while collend < len(p) and ord(p[collend]) >= limit:
collend += 1
r, pos = errorhandler(errors, encoding, reason, p,
collstart, collend)
result.append(r)
-
+
return result.build()
def unicode_encode_latin_1(p, size, errors, errorhandler=None):
diff --git a/pypy/jit/tl/spli/test/test_jit.py b/pypy/jit/tl/spli/test/test_jit.py
--- a/pypy/jit/tl/spli/test/test_jit.py
+++ b/pypy/jit/tl/spli/test/test_jit.py
@@ -1,6 +1,6 @@
import py
-from pypy.jit.metainterp.test.test_basic import JitMixin
+from pypy.jit.metainterp.test.support import JitMixin
from pypy.jit.tl.spli import interpreter, objects, serializer
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
from pypy.jit.backend.llgraph import runner
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver, hint
from pypy.rlib.objectmodel import compute_unique_id
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rpython.lltypesystem import lltype, rclass
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.ootypesystem import ootype
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/support.py
@@ -0,0 +1,261 @@
+
+import py, sys
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.ootypesystem import ootype
+from pypy.jit.backend.llgraph import runner
+from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
+from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
+from pypy.jit.metainterp import pyjitpl, history
+from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.jit.codewriter.policy import JitPolicy
+from pypy.jit.codewriter import longlong
+
+def _get_jitcodes(testself, CPUClass, func, values, type_system,
+ supports_longlong=False, **kwds):
+ from pypy.jit.codewriter import support, codewriter
+
+ class FakeJitCell:
+ __compiled_merge_points = []
+ def get_compiled_merge_points(self):
+ return self.__compiled_merge_points[:]
+ def set_compiled_merge_points(self, lst):
+ self.__compiled_merge_points = lst
+
+ class FakeWarmRunnerState:
+ def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
+ pass
+
+ def jit_cell_at_key(self, greenkey):
+ assert greenkey == []
+ return self._cell
+ _cell = FakeJitCell()
+
+ trace_limit = sys.maxint
+ enable_opts = ALL_OPTS_DICT
+
+ func._jit_unroll_safe_ = True
+ rtyper = support.annotate(func, values, type_system=type_system)
+ graphs = rtyper.annotator.translator.graphs
+ result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
+
+ class FakeJitDriverSD:
+ num_green_args = 0
+ portal_graph = graphs[0]
+ virtualizable_info = None
+ greenfield_info = None
+ result_type = result_kind
+ portal_runner_ptr = "???"
+
+ stats = history.Stats()
+ cpu = CPUClass(rtyper, stats, None, False)
+ cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
+ testself.cw = cw
+ policy = JitPolicy()
+ policy.set_supports_longlong(supports_longlong)
+ cw.find_all_graphs(policy)
+ #
+ testself.warmrunnerstate = FakeWarmRunnerState()
+ testself.warmrunnerstate.cpu = cpu
+ FakeJitDriverSD.warmstate = testself.warmrunnerstate
+ if hasattr(testself, 'finish_setup_for_interp_operations'):
+ testself.finish_setup_for_interp_operations()
+ #
+ cw.make_jitcodes(verbose=True)
+
+def _run_with_blackhole(testself, args):
+ from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
+ cw = testself.cw
+ blackholeinterpbuilder = BlackholeInterpBuilder(cw)
+ blackholeinterp = blackholeinterpbuilder.acquire_interp()
+ count_i = count_r = count_f = 0
+ for value in args:
+ T = lltype.typeOf(value)
+ if T == lltype.Signed:
+ blackholeinterp.setarg_i(count_i, value)
+ count_i += 1
+ elif T == llmemory.GCREF:
+ blackholeinterp.setarg_r(count_r, value)
+ count_r += 1
+ elif T == lltype.Float:
+ value = longlong.getfloatstorage(value)
+ blackholeinterp.setarg_f(count_f, value)
+ count_f += 1
+ else:
+ raise TypeError(T)
+ [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
+ blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
+ blackholeinterp.run()
+ return blackholeinterp._final_result_anytype()
+
+def _run_with_pyjitpl(testself, args):
+
+ class DoneWithThisFrame(Exception):
+ pass
+
+ class DoneWithThisFrameRef(DoneWithThisFrame):
+ def __init__(self, cpu, *args):
+ DoneWithThisFrame.__init__(self, *args)
+
+ cw = testself.cw
+ opt = history.Options(listops=True)
+ metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
+ metainterp_sd.finish_setup(cw)
+ [jitdriver_sd] = metainterp_sd.jitdrivers_sd
+ metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
+ metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
+ metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
+ metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
+ testself.metainterp = metainterp
+ try:
+ metainterp.compile_and_run_once(jitdriver_sd, *args)
+ except DoneWithThisFrame, e:
+ #if conftest.option.view:
+ # metainterp.stats.view()
+ return e.args[0]
+ else:
+ raise Exception("FAILED")
+
+def _run_with_machine_code(testself, args):
+ metainterp = testself.metainterp
+ num_green_args = metainterp.jitdriver_sd.num_green_args
+ loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
+ if len(loop_tokens) != 1:
+ return NotImplemented
+ # a loop was successfully created by _run_with_pyjitpl(); call it
+ cpu = metainterp.cpu
+ for i in range(len(args) - num_green_args):
+ x = args[num_green_args + i]
+ typecode = history.getkind(lltype.typeOf(x))
+ set_future_value(cpu, i, x, typecode)
+ faildescr = cpu.execute_token(loop_tokens[0])
+ assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
+ if metainterp.jitdriver_sd.result_type == history.INT:
+ return cpu.get_latest_value_int(0)
+ elif metainterp.jitdriver_sd.result_type == history.REF:
+ return cpu.get_latest_value_ref(0)
+ elif metainterp.jitdriver_sd.result_type == history.FLOAT:
+ return cpu.get_latest_value_float(0)
+ else:
+ return None
+
+
+class JitMixin:
+ basic = True
+ def check_loops(self, expected=None, everywhere=False, **check):
+ get_stats().check_loops(expected=expected, everywhere=everywhere,
+ **check)
+ def check_loop_count(self, count):
+ """NB. This is a hack; use check_tree_loop_count() or
+ check_enter_count() for the real thing.
+ This counts as 1 every bridge in addition to every loop; and it does
+ not count at all the entry bridges from interpreter, although they
+ are TreeLoops as well."""
+ assert get_stats().compiled_count == count
+ def check_tree_loop_count(self, count):
+ assert len(get_stats().loops) == count
+ def check_loop_count_at_most(self, count):
+ assert get_stats().compiled_count <= count
+ def check_enter_count(self, count):
+ assert get_stats().enter_count == count
+ def check_enter_count_at_most(self, count):
+ assert get_stats().enter_count <= count
+ def check_jumps(self, maxcount):
+ assert get_stats().exec_jumps <= maxcount
+ def check_aborted_count(self, count):
+ assert get_stats().aborted_count == count
+ def check_aborted_count_at_least(self, count):
+ assert get_stats().aborted_count >= count
+
+ def meta_interp(self, *args, **kwds):
+ kwds['CPUClass'] = self.CPUClass
+ kwds['type_system'] = self.type_system
+ if "backendopt" not in kwds:
+ kwds["backendopt"] = False
+ return ll_meta_interp(*args, **kwds)
+
+ def interp_operations(self, f, args, **kwds):
+ # get the JitCodes for the function f
+ _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
+ # try to run it with blackhole.py
+ result1 = _run_with_blackhole(self, args)
+ # try to run it with pyjitpl.py
+ result2 = _run_with_pyjitpl(self, args)
+ assert result1 == result2
+ # try to run it by running the code compiled just before
+ result3 = _run_with_machine_code(self, args)
+ assert result1 == result3 or result3 == NotImplemented
+ #
+ if (longlong.supports_longlong and
+ isinstance(result1, longlong.r_float_storage)):
+ result1 = longlong.getrealfloat(result1)
+ return result1
+
+ def check_history(self, expected=None, **isns):
+ # this can be used after calling meta_interp
+ get_stats().check_history(expected, **isns)
+
+ def check_operations_history(self, expected=None, **isns):
+ # this can be used after interp_operations
+ if expected is not None:
+ expected = dict(expected)
+ expected['jump'] = 1
+ self.metainterp.staticdata.stats.check_history(expected, **isns)
+
+
+class LLJitMixin(JitMixin):
+ type_system = 'lltype'
+ CPUClass = runner.LLtypeCPU
+
+ @staticmethod
+ def Ptr(T):
+ return lltype.Ptr(T)
+
+ @staticmethod
+ def GcStruct(name, *fields, **kwds):
+ S = lltype.GcStruct(name, *fields, **kwds)
+ return S
+
+ malloc = staticmethod(lltype.malloc)
+ nullptr = staticmethod(lltype.nullptr)
+
+ @staticmethod
+ def malloc_immortal(T):
+ return lltype.malloc(T, immortal=True)
+
+ def _get_NODE(self):
+ NODE = lltype.GcForwardReference()
+ NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
+ ('next', lltype.Ptr(NODE))))
+ return NODE
+
+class OOJitMixin(JitMixin):
+ type_system = 'ootype'
+ #CPUClass = runner.OOtypeCPU
+
+ def setup_class(cls):
+ py.test.skip("ootype tests skipped for now")
+
+ @staticmethod
+ def Ptr(T):
+ return T
+
+ @staticmethod
+ def GcStruct(name, *fields, **kwds):
+ if 'hints' in kwds:
+ kwds['_hints'] = kwds['hints']
+ del kwds['hints']
+ I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
+ return I
+
+ malloc = staticmethod(ootype.new)
+ nullptr = staticmethod(ootype.null)
+
+ @staticmethod
+ def malloc_immortal(T):
+ return ootype.new(T)
+
+ def _get_NODE(self):
+ NODE = ootype.Instance('NODE', ootype.ROOT, {})
+ NODE._add_fields({'value': ootype.Signed,
+ 'next': NODE})
+ return NODE
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -22,13 +22,21 @@
return func.code
class Defaults(object):
- _immutable_fields_ = ["items[*]"]
+ _immutable_fields_ = ["items[*]", "promote"]
- def __init__(self, items):
+ def __init__(self, items, promote=False):
self.items = items
+ self.promote = promote
def getitems(self):
- return jit.hint(self, promote=True).items
+ # an idea - we want to promote only items that we know won't change
+ # too often. this is the case for builtin functions and functions
+ # with known constant defaults. Otherwise we don't want to promote
+ # this so lambda a=a won't create a new trace each time it's
+ # encountered
+ if self.promote:
+ return jit.hint(self, promote=True).items
+ return self.items
def getitem(self, idx):
return self.getitems()[idx]
@@ -44,14 +52,15 @@
can_change_code = True
def __init__(self, space, code, w_globals=None, defs_w=[], closure=None,
- forcename=None):
+ forcename=None, promote_defs=False):
self.space = space
self.name = forcename or code.co_name
self.w_doc = None # lazily read from code.getdocstring()
self.code = code # Code instance
self.w_func_globals = w_globals # the globals dictionary
self.closure = closure # normally, list of Cell instances or None
- self.defs = Defaults(defs_w) # wrapper around list of w_default's
+ self.defs = Defaults(defs_w, promote=promote_defs)
+ # wrapper around list of w_default's
self.w_func_dict = None # filled out below if needed
self.w_module = None
@@ -620,7 +629,8 @@
def __init__(self, func):
assert isinstance(func, Function)
Function.__init__(self, func.space, func.code, func.w_func_globals,
- func.defs.getitems(), func.closure, func.name)
+ func.defs.getitems(), func.closure, func.name,
+ promote_defs=True)
self.w_doc = func.w_doc
self.w_func_dict = func.w_func_dict
self.w_module = func.w_module
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
@@ -10,7 +10,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash
from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted
-from pypy.rlib.jit import purefunction, dont_look_inside
+from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe
from pypy.rlib.rarithmetic import intmask, r_uint
class TypeCell(W_Root):
@@ -173,7 +173,7 @@
if (not we_are_jitted() or w_self.is_heaptype() or
w_self.space.config.objspace.std.mutable_builtintypes):
return w_self._version_tag
- # heap objects cannot get their version_tag changed
+ # prebuilt objects cannot get their version_tag changed
return w_self._pure_version_tag()
@purefunction_promote()
@@ -316,7 +316,7 @@
return w_value
return None
-
+ @unroll_safe
def _lookup(w_self, key):
space = w_self.space
for w_class in w_self.mro_w:
@@ -325,6 +325,7 @@
return w_value
return None
+ @unroll_safe
def _lookup_where(w_self, key):
# like lookup() but also returns the parent class in which the
# attribute was found
diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
--- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
@@ -277,6 +277,7 @@
""")
def test_default_and_kw(self):
+ py.test.skip("Wait until we have saner defaults strat")
def main(n):
def f(i, j=1):
return i + j
@@ -539,7 +540,7 @@
i12 = int_sub_ovf(i3, 1)
guard_no_overflow(descr=<Guard5>)
--TICK--
- jump(p0, p1, p2, i12, p4, descr=<Loop0>)
+ jump(p0, p1, p2, i12, descr=<Loop0>)
""")
def test_exception_inside_loop_2(self):
@@ -585,7 +586,7 @@
--EXC-TICK--
i14 = int_add(i4, 1)
--TICK--
- jump(p0, p1, p2, p3, i14, i5, p6, descr=<Loop0>)
+ jump(p0, p1, p2, p3, i14, i5, descr=<Loop0>)
""")
def test_chain_of_guards(self):
@@ -685,13 +686,13 @@
assert log.result == 500
loop, = log.loops_by_id('import')
assert loop.match_by_id('import', """
- p14 = call(ConstClass(ll_split_chr__GcStruct_listLlT_rpy_stringPtr_Char), p8, 46, descr=<GcPtrCallDescr>)
+ p14 = call(ConstClass(ll_split_chr), p8, 46, -1, descr=<GcPtrCallDescr>)
guard_no_exception(descr=<Guard4>)
guard_nonnull(p14, descr=<Guard5>)
i15 = getfield_gc(p14, descr=<SignedFieldDescr list.length .*>)
i16 = int_is_true(i15)
guard_true(i16, descr=<Guard6>)
- p18 = call(ConstClass(ll_pop_default__dum_nocheckConst_listPtr), p14, descr=<GcPtrCallDescr>)
+ p18 = call(ConstClass(ll_pop_default), p14, descr=<GcPtrCallDescr>)
guard_no_exception(descr=<Guard7>)
i19 = getfield_gc(p14, descr=<SignedFieldDescr list.length .*>)
i20 = int_is_true(i19)
@@ -837,7 +838,7 @@
src = """
def main():
sa = 0
- for i in range(1000):
+ for i in range(300):
if i %s %d:
sa += 1
else:
@@ -848,7 +849,7 @@
sa += 20000
return sa
""" % (op1, a, op2, b)
- self.run_and_check(src, threshold=400)
+ self.run_and_check(src, threshold=200)
src = """
def main():
@@ -866,7 +867,7 @@
i += 0.25
return sa
""" % (op1, float(a)/4.0, op2, float(b)/4.0)
- self.run_and_check(src, threshold=400)
+ self.run_and_check(src, threshold=300)
def test_boolrewrite_allcases_reflex(self):
@@ -887,7 +888,7 @@
src = """
def main():
sa = 0
- for i in range(1000):
+ for i in range(300):
if i %s %d:
sa += 1
else:
@@ -898,7 +899,7 @@
sa += 20000
return sa
""" % (op1, a, b, op2)
- self.run_and_check(src, threshold=400)
+ self.run_and_check(src, threshold=200)
src = """
def main():
@@ -916,11 +917,13 @@
i += 0.25
return sa
""" % (op1, float(a)/4.0, float(b)/4.0, op2)
- self.run_and_check(src, threshold=400)
+ self.run_and_check(src, threshold=300)
def test_boolrewrite_ptr(self):
- # XXX this test is way too imprecise in what it is actually testing
- # it should count the number of guards instead
+ """
+ This test only checks that we get the expected result, not that any
+ optimization has been applied.
+ """
compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b')
for e1 in compares:
for e2 in compares:
@@ -932,7 +935,7 @@
b = tst()
c = tst()
sa = 0
- for i in range(1000):
+ for i in range(300):
if %s:
sa += 1
else:
@@ -945,7 +948,7 @@
a = b
return sa
""" % (e1, e2)
- self.run_and_check(src, threshold=400)
+ self.run_and_check(src, threshold=200)
def test_array_sum(self):
def main():
@@ -1009,6 +1012,7 @@
""")
def test_func_defaults(self):
+ py.test.skip("until we fix defaults")
def main(n):
i = 1
while i < n:
@@ -1061,7 +1065,7 @@
i23 = int_lt(0, i21)
guard_true(i23, descr=<Guard5>)
i24 = getfield_gc(p17, descr=<NonGcPtrFieldDescr .*W_ArrayTypei.inst_buffer .*>)
- i25 = getarrayitem_raw(i24, 0, descr=<SignedArrayNoLengthDescr>)
+ i25 = getarrayitem_raw(i24, 0, descr=<.*>)
i27 = int_lt(1, i21)
guard_false(i27, descr=<Guard6>)
i28 = int_add_ovf(i10, i25)
@@ -1069,7 +1073,7 @@
--TICK--
jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=<Loop0>)
""")
-
+
def test_mutate_class(self):
def fn(n):
class A(object):
@@ -1112,3 +1116,461 @@
setfield_gc(ConstPtr(ptr21), p20, descr=<GcPtrFieldDescr .*TypeCell.inst_w_value .*>)
jump(p0, p1, p2, p3, p4, p20, p6, i7, descr=<Loop.>)
""")
+
+
+ def test_intbound_simple(self):
+ """
+ This test only checks that we get the expected result, not that any
+ optimization has been applied.
+ """
+ ops = ('<', '>', '<=', '>=', '==', '!=')
+ nbr = (3, 7)
+ for o1 in ops:
+ for o2 in ops:
+ for n1 in nbr:
+ for n2 in nbr:
+ src = '''
+ def f(i):
+ a, b = 3, 3
+ if i %s %d:
+ a = 0
+ else:
+ a = 1
+ if i %s %d:
+ b = 0
+ else:
+ b = 1
+ return a + b * 2
+
+ def main():
+ res = [0] * 4
+ idx = []
+ for i in range(15):
+ idx.extend([i] * 15)
+ for i in idx:
+ res[f(i)] += 1
+ return res
+
+ ''' % (o1, n1, o2, n2)
+ self.run_and_check(src, threshold=200)
+
+ def test_intbound_addsub_mix(self):
+ """
+ This test only checks that we get the expected result, not that any
+ optimization has been applied.
+ """
+ tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4',
+ 'i - 1 > 1', '1 - i > 1', '1 - i < -3',
+ 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4')
+ for t1 in tests:
+ for t2 in tests:
+ src = '''
+ def f(i):
+ a, b = 3, 3
+ if %s:
+ a = 0
+ else:
+ a = 1
+ if %s:
+ b = 0
+ else:
+ b = 1
+ return a + b * 2
+
+ def main():
+ res = [0] * 4
+ idx = []
+ for i in range(15):
+ idx.extend([i] * 15)
+ for i in idx:
+ res[f(i)] += 1
+ return res
+
+ ''' % (t1, t2)
+ self.run_and_check(src, threshold=200)
+
+ def test_intbound_gt(self):
+ def main(n):
+ i, a, b = 0, 0, 0
+ while i < n:
+ if i > -1:
+ a += 1
+ if i > -2:
+ b += 1
+ i += 1
+ return (a, b)
+ #
+ log = self.run(main, [300], threshold=200)
+ assert log.result == (300, 300)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i10 = int_lt(i8, i9)
+ guard_true(i10, descr=...)
+ i12 = int_add_ovf(i7, 1)
+ guard_no_overflow(descr=...)
+ i14 = int_add_ovf(i6, 1)
+ guard_no_overflow(descr=...)
+ i17 = int_add(i8, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, i14, i12, i17, i9, descr=<Loop0>)
+ """)
+
+ def test_intbound_sub_lt(self):
+ def main():
+ i, a = 0, 0
+ while i < 300:
+ if i - 10 < 295:
+ a += 1
+ i += 1
+ return a
+ #
+ log = self.run(main, [], threshold=200)
+ assert log.result == 300
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i7 = int_lt(i5, 300)
+ guard_true(i7, descr=...)
+ i9 = int_sub_ovf(i5, 10)
+ guard_no_overflow(descr=...)
+ i11 = int_add_ovf(i4, 1)
+ guard_no_overflow(descr=...)
+ i13 = int_add(i5, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, i11, i13, descr=<Loop0>)
+ """)
+
+ def test_intbound_addsub_ge(self):
+ def main(n):
+ i, a, b = 0, 0, 0
+ while i < n:
+ if i + 5 >= 5:
+ a += 1
+ if i - 1 >= -1:
+ b += 1
+ i += 1
+ return (a, b)
+ #
+ log = self.run(main, [300], threshold=200)
+ assert log.result == (300, 300)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i10 = int_lt(i8, i9)
+ guard_true(i10, descr=...)
+ i12 = int_add_ovf(i8, 5)
+ guard_no_overflow(descr=...)
+ i14 = int_add_ovf(i7, 1)
+ guard_no_overflow(descr=...)
+ i16 = int_add_ovf(i6, 1)
+ guard_no_overflow(descr=...)
+ i19 = int_add(i8, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, i16, i14, i19, i9, descr=<Loop0>)
+ """)
+
+ def test_intbound_addmul_ge(self):
+ def main(n):
+ i, a, b = 0, 0, 0
+ while i < 300:
+ if i + 5 >= 5:
+ a += 1
+ if 2 * i >= 0:
+ b += 1
+ i += 1
+ return (a, b)
+ #
+ log = self.run(main, [300], threshold=200)
+ assert log.result == (300, 300)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i10 = int_lt(i8, 300)
+ guard_true(i10, descr=...)
+ i12 = int_add(i8, 5)
+ i14 = int_add_ovf(i7, 1)
+ guard_no_overflow(descr=...)
+ i16 = int_lshift(i8, 1)
+ i18 = int_add_ovf(i6, 1)
+ guard_no_overflow(descr=...)
+ i21 = int_add(i8, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, i18, i14, i21, descr=<Loop0>)
+ """)
+
+ def test_intbound_eq(self):
+ def main(a, n):
+ i, s = 0, 0
+ while i < 300:
+ if a == 7:
+ s += a + 1
+ elif i == 10:
+ s += i
+ else:
+ s += 1
+ i += 1
+ return s
+ #
+ log = self.run(main, [7, 300], threshold=200)
+ assert log.result == main(7, 300)
+ log = self.run(main, [10, 300], threshold=200)
+ assert log.result == main(10, 300)
+ log = self.run(main, [42, 300], threshold=200)
+ assert log.result == main(42, 300)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i10 = int_lt(i8, 300)
+ guard_true(i10, descr=...)
+ i12 = int_eq(i8, 10)
+ guard_false(i12, descr=...)
+ i14 = int_add_ovf(i7, 1)
+ guard_no_overflow(descr=...)
+ i16 = int_add(i8, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, p6, i14, i16, descr=<Loop0>)
+ """)
+
+ def test_intbound_mul(self):
+ def main(a):
+ i, s = 0, 0
+ while i < 300:
+ assert i >= 0
+ if 2 * i < 30000:
+ s += 1
+ else:
+ s += a
+ i += 1
+ return s
+ #
+ log = self.run(main, [7], threshold=200)
+ assert log.result == 300
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i8 = int_lt(i6, 300)
+ guard_true(i8, descr=...)
+ i10 = int_lshift(i6, 1)
+ i12 = int_add_ovf(i5, 1)
+ guard_no_overflow(descr=...)
+ i14 = int_add(i6, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, i12, i14, descr=<Loop0>)
+ """)
+
+ def test_assert(self):
+ def main(a):
+ i, s = 0, 0
+ while i < 300:
+ assert a == 7
+ s += a + 1
+ i += 1
+ return s
+ log = self.run(main, [7], threshold=200)
+ assert log.result == 300*8
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i8 = int_lt(i6, 300)
+ guard_true(i8, descr=...)
+ i10 = int_add_ovf(i5, 8)
+ guard_no_overflow(descr=...)
+ i12 = int_add(i6, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, i10, i12, descr=<Loop0>)
+ """)
+
+ def test_zeropadded(self):
+ def main():
+ from array import array
+ class ZeroPadded(array):
+ def __new__(cls, l):
+ self = array.__new__(cls, 'd', range(l))
+ return self
+
+ def __getitem__(self, i):
+ if i < 0 or i >= len(self):
+ return 0
+ return array.__getitem__(self, i) # ID: get
+ #
+ buf = ZeroPadded(2000)
+ i = 10
+ sa = 0
+ while i < 2000 - 10:
+ sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2]
+ i += 1
+ return sa
+
+ log = self.run(main, [], threshold=200)
+ assert log.result == 9895050.0
+ loop, = log.loops_by_filename(self.filepath)
+ #
+ # check that the overloaded __getitem__ does not introduce double
+ # array bound checks.
+ #
+ # The force_token()s are still there, but will be eliminated by the
+ # backend regalloc, so they are harmless
+ assert loop.match(ignore_ops=['force_token'],
+ expected_src="""
+ ...
+ i20 = int_ge(i18, i8)
+ guard_false(i20, descr=...)
+ f21 = getarrayitem_raw(i13, i18, descr=...)
+ f23 = getarrayitem_raw(i13, i14, descr=...)
+ f24 = float_add(f21, f23)
+ f26 = getarrayitem_raw(i13, i6, descr=...)
+ f27 = float_add(f24, f26)
+ i29 = int_add(i6, 1)
+ i31 = int_ge(i29, i8)
+ guard_false(i31, descr=...)
+ f33 = getarrayitem_raw(i13, i29, descr=...)
+ f34 = float_add(f27, f33)
+ i36 = int_add(i6, 2)
+ i38 = int_ge(i36, i8)
+ guard_false(i38, descr=...)
+ f39 = getarrayitem_raw(i13, i36, descr=...)
+ ...
+ """)
+
+
+ def test_circular(self):
+ def main():
+ from array import array
+ class Circular(array):
+ def __new__(cls):
+ self = array.__new__(cls, 'd', range(256))
+ return self
+ def __getitem__(self, i):
+ assert len(self) == 256
+ return array.__getitem__(self, i & 255)
+ #
+ buf = Circular()
+ i = 10
+ sa = 0
+ while i < 2000 - 10:
+ sa += buf[i-2] + buf[i-1] + buf[i] + buf[i+1] + buf[i+2]
+ i += 1
+ return sa
+ #
+ log = self.run(main, [], threshold=200)
+ assert log.result == 1239690.0
+ loop, = log.loops_by_filename(self.filepath)
+ #
+ # check that the array bound checks are removed
+ #
+ # The force_token()s are still there, but will be eliminated by the
+ # backend regalloc, so they are harmless
+ assert loop.match(ignore_ops=['force_token'],
+ expected_src="""
+ ...
+ i17 = int_and(i14, 255)
+ f18 = getarrayitem_raw(i8, i17, descr=...)
+ f20 = getarrayitem_raw(i8, i9, descr=...)
+ f21 = float_add(f18, f20)
+ f23 = getarrayitem_raw(i8, i10, descr=...)
+ f24 = float_add(f21, f23)
+ i26 = int_add(i6, 1)
+ i29 = int_and(i26, 255)
+ f30 = getarrayitem_raw(i8, i29, descr=...)
+ f31 = float_add(f24, f30)
+ i33 = int_add(i6, 2)
+ i36 = int_and(i33, 255)
+ f37 = getarrayitem_raw(i8, i36, descr=...)
+ ...
+ """)
+
+ def test_min_max(self):
+ def main():
+ i=0
+ sa=0
+ while i < 300:
+ sa+=min(max(i, 3000), 4000)
+ i+=1
+ return sa
+ log = self.run(main, [], threshold=200)
+ assert log.result == 300*3000
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i7 = int_lt(i4, 300)
+ guard_true(i7, descr=...)
+ i9 = int_add_ovf(i5, 3000)
+ guard_no_overflow(descr=...)
+ i11 = int_add(i4, 1)
+ --TICK--
+ jump(p0, p1, p2, p3, i11, i9, descr=<Loop0>)
+ """)
+
+ def test_silly_max(self):
+ def main():
+ i = 2
+ sa = 0
+ while i < 300:
+ lst = range(i)
+ sa += max(*lst) # ID: max
+ i += 1
+ return sa
+ log = self.run(main, [], threshold=200)
+ assert log.result == main()
+ loop, = log.loops_by_filename(self.filepath)
+ # We dont want too many guards, but a residual call to min_max_loop
+ guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')]
+ assert len(guards) < 20
+ assert loop.match_by_id('max',"""
+ ...
+ p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...)
+ ...
+ """)
+
+ def test_iter_max(self):
+ def main():
+ i = 2
+ sa = 0
+ while i < 300:
+ lst = range(i)
+ sa += max(lst) # ID: max
+ i += 1
+ return sa
+ log = self.run(main, [], threshold=200)
+ assert log.result == main()
+ loop, = log.loops_by_filename(self.filepath)
+ # We dont want too many guards, but a residual call to min_max_loop
+ guards = [n for n in log.opnames(loop.ops_by_id("max")) if n.startswith('guard')]
+ assert len(guards) < 20
+ assert loop.match_by_id('max',"""
+ ...
+ p76 = call_may_force(ConstClass(min_max_loop__max), _, _, descr=...)
+ ...
+ """)
+
+ def test__ffi_call(self):
+ from pypy.rlib.test.test_libffi import get_libm_name
+ def main(libm_name):
+ try:
+ from _ffi import CDLL, types
+ except ImportError:
+ sys.stderr.write('SKIP: cannot import _ffi\n')
+ return 0
+
+ libm = CDLL(libm_name)
+ pow = libm.getfunc('pow', [types.double, types.double],
+ types.double)
+ i = 0
+ res = 0
+ while i < 300:
+ res += pow(2, 3)
+ i += 1
+ return pow.getaddr(), res
+ #
+ libm_name = get_libm_name(sys.platform)
+ log = self.run(main, [libm_name], threshold=200)
+ pow_addr, res = log.result
+ assert res == 8.0 * 300
+ loop, = log.loops_by_filename(self.filepath)
+ # XXX: write the actual test when we merge this to jitypes2
+ ## ops = self.get_by_bytecode('CALL_FUNCTION')
+ ## assert len(ops) == 2 # we get two loops, because of specialization
+ ## call_function = ops[0]
+ ## last_ops = [op.getopname() for op in call_function[-5:]]
+ ## assert last_ops == ['force_token',
+ ## 'setfield_gc',
+ ## 'call_may_force',
+ ## 'guard_not_forced',
+ ## 'guard_no_exception']
+ ## call = call_function[-3]
+ ## assert call.getarg(0).value == pow_addr
+ ## assert call.getarg(1).value == 2.0
+ ## assert call.getarg(2).value == 3.0
diff --git a/pypy/objspace/flow/test/test_model.py b/pypy/objspace/flow/test/test_model.py
--- a/pypy/objspace/flow/test/test_model.py
+++ b/pypy/objspace/flow/test/test_model.py
@@ -71,19 +71,6 @@
pieces.headerblock.exits[1],
pieces.whileblock.exits[0]]
-def test_traverse():
- lst = []
- traverse(lst.append, graph)
- assert lst == [pieces.startblock,
- pieces.startblock.exits[0],
- pieces.headerblock,
- pieces.headerblock.exits[0],
- graph.returnblock,
- pieces.headerblock.exits[1],
- pieces.whileblock,
- pieces.whileblock.exits[0]]
- assert flatten(graph) == lst
-
def test_mkentrymap():
entrymap = mkentrymap(graph)
startlink = entrymap[graph.startblock][0]
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -8,7 +8,7 @@
from pypy.rpython.lltypesystem.rstr import STR
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.objectmodel import compute_unique_id, keepalive_until_here
+from pypy.rlib.objectmodel import compute_unique_id
from pypy.rlib import rgc
from pypy.rlib.rstring import StringBuilder
from pypy.rlib.rarithmetic import LONG_BIT
diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py
--- a/pypy/module/thread/os_lock.py
+++ b/pypy/module/thread/os_lock.py
@@ -113,7 +113,4 @@
def allocate_lock(space):
"""Create a new lock object. (allocate() is an obsolete synonym.)
See LockType.__doc__ for information about locks."""
- return space.wrap(Lock(space))
-
-def getlocktype(space):
- return space.gettypeobject(Lock.typedef)
+ return space.wrap(Lock(space))
\ No newline at end of file
diff --git a/pypy/jit/metainterp/test/test_tlc.py b/pypy/jit/metainterp/test/test_tlc.py
--- a/pypy/jit/metainterp/test/test_tlc.py
+++ b/pypy/jit/metainterp/test/test_tlc.py
@@ -3,7 +3,7 @@
from pypy.jit.tl import tlc
-from pypy.jit.metainterp.test.test_basic import OOJitMixin, LLJitMixin
+from pypy.jit.metainterp.test.support import OOJitMixin, LLJitMixin
class TLCTests:
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -106,6 +106,11 @@
del obj
import gc; gc.collect()
+ try:
+ del space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
for w_obj in state.non_heaptypes_w:
Py_DecRef(space, w_obj)
state.non_heaptypes_w[:] = []
diff --git a/pypy/jit/metainterp/test/test_slist.py b/pypy/jit/metainterp/test/test_slist.py
--- a/pypy/jit/metainterp/test/test_slist.py
+++ b/pypy/jit/metainterp/test/test_slist.py
@@ -1,5 +1,5 @@
import py
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
class ListTests(object):
diff --git a/pypy/translator/cli/src/ll_math.cs b/pypy/translator/cli/src/ll_math.cs
--- a/pypy/translator/cli/src/ll_math.cs
+++ b/pypy/translator/cli/src/ll_math.cs
@@ -224,5 +224,25 @@
{
return Math.Tanh(x);
}
+
+ static public bool ll_math_isnan(double x)
+ {
+ return double.IsNaN(x);
+ }
+
+ static public bool ll_math_isinf(double x)
+ {
+ return double.IsInfinity(x);
+ }
+
+ static public double ll_math_copysign(double x, double y)
+ {
+ if (x < 0.0)
+ x = -x;
+ if (y > 0.0 || (y == 0.0 && Math.Atan2(y, -1.0) > 0.0))
+ return x;
+ else
+ return -x;
+ }
}
}
diff --git a/pypy/translator/backendopt/support.py b/pypy/translator/backendopt/support.py
--- a/pypy/translator/backendopt/support.py
+++ b/pypy/translator/backendopt/support.py
@@ -39,74 +39,6 @@
# assume PyObjPtr
return True
-def needs_conservative_livevar_calculation(block):
- from pypy.rpython.lltypesystem import rclass
- vars = block.getvariables()
- assert len(block.exits) == 1
- exitingvars = block.exits[0].args
- for var in vars:
- TYPE = getattr(var, "concretetype", lltype.Ptr(lltype.PyObject))
- if isinstance(TYPE, lltype.Ptr) and not var_needsgc(var):
- if isinstance(TYPE.TO, lltype.FuncType):
- continue
- try:
- lltype.castable(TYPE, rclass.CLASSTYPE)
- except lltype.InvalidCast:
- if var in exitingvars:
- return True
- else:
- return False
-
-def generate_keepalive(vars, annotator=None):
- keepalive_ops = []
- for v in vars:
- if isinstance(v, Constant):
- continue
- if v.concretetype._is_atomic():
- continue
- v_keepalive = Variable()
- v_keepalive.concretetype = lltype.Void
- if annotator is not None:
- annotator.setbinding(v_keepalive, s_ImpossibleValue)
- keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive))
- return keepalive_ops
-
-def split_block_with_keepalive(block, index_operation,
- keep_alive_op_args=True,
- annotator=None):
- splitlink = split_block(annotator, block, index_operation)
- afterblock = splitlink.target
- conservative_keepalives = needs_conservative_livevar_calculation(block)
- if conservative_keepalives:
- keep_alive_vars = [var for var in block.getvariables()
- if var_needsgc(var)]
- # XXX you could maybe remove more, if the variables are kept
- # alive by something else. but this is sometimes hard to know
- for i, var in enumerate(keep_alive_vars):
- try:
- index = splitlink.args.index(var)
- newvar = afterblock.inputargs[index]
- except ValueError:
- splitlink.args.append(var)
- newvar = copyvar(annotator, var)
- afterblock.inputargs.append(newvar)
- keep_alive_vars[i] = newvar
- elif keep_alive_op_args and afterblock.operations:
- keep_alive_vars = [var for var in afterblock.operations[0].args
- if isinstance(var, Variable) and var_needsgc(var)]
- if len(afterblock.operations) > 1 or afterblock.exitswitch != c_last_exception:
- afterblock.operations[1:1] = generate_keepalive(keep_alive_vars,
- annotator=annotator)
- keep_alive_vars = []
- else:
- keep_alive_vars = []
- pos = len(afterblock.operations)
- if afterblock.exitswitch == c_last_exception:
- pos -= 1 # insert the keepalives just before the last operation
- # in case of exception-catching
- afterblock.operations[pos:pos] = generate_keepalive(keep_alive_vars)
- return splitlink
-
def find_calls_from(translator, graph, memo=None):
if memo and graph in memo:
return memo[graph]
diff --git a/pypy/rpython/rpbc.py b/pypy/rpython/rpbc.py
--- a/pypy/rpython/rpbc.py
+++ b/pypy/rpython/rpbc.py
@@ -485,7 +485,7 @@
try:
thisattrvalue = frozendesc.attrcache[attr]
except KeyError:
- if not frozendesc.has_attribute(attr):
+ if frozendesc.warn_missing_attribute(attr):
warning("Desc %r has no attribute %r" % (frozendesc, attr))
continue
llvalue = r_value.convert_const(thisattrvalue)
diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py
--- a/pypy/translator/exceptiontransform.py
+++ b/pypy/translator/exceptiontransform.py
@@ -229,7 +229,6 @@
n_need_exc_matching_blocks += need_exc_matching
n_gen_exc_checks += gen_exc_checks
cleanup_graph(graph)
- removenoops.remove_superfluous_keep_alive(graph)
return n_need_exc_matching_blocks, n_gen_exc_checks
def replace_stack_unwind(self, block):
diff --git a/pypy/jit/metainterp/test/test_dlist.py b/pypy/jit/metainterp/test/test_dlist.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_dlist.py
+++ /dev/null
@@ -1,165 +0,0 @@
-
-import py
-from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-py.test.skip("Disabled")
-
-class ListTests:
- def test_basic(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(getarrayitem_gc=0, setarrayitem_gc=1)
-# XXX fix codewriter
-# guard_exception=0,
-# guard_no_exception=1)
-
- def test_list_escapes(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0] * (n + 1)
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- l[n] = n
- n -= 1
- return l[3]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=2, getarrayitem_gc=0)
-
- def test_list_escapes_but_getitem_goes(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0] * (n + 1)
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- l[n] = n
- x = l[2]
- y = l[1] + l[2]
- l[1] = x + y
- n -= 1
- return l[3]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=3, getarrayitem_gc=0)
-
- def test_list_of_ptrs(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- class A(object):
- def __init__(self, x):
- self.x = x
-
- def f(n):
- l = [A(3)]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0].x + 1
- l[0] = A(x)
- n -= 1
- return l[0].x
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=1, getarrayitem_gc=0,
- new_with_vtable=1) # A should escape
-
- def test_list_checklength(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n, a):
- l = [0] * a
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) < 3:
- return 42
- l[0] = n
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [10, 13], listops=True)
- assert res == f(10, 13)
- self.check_loops(setarrayitem_gc=1, arraylen_gc=1)
-
- def test_list_checklength_run(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n, a):
- l = [0] * a
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) > n:
- return 42
- l[0] = n
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [50, 13], listops=True)
- assert res == 42
- self.check_loops(setarrayitem_gc=1, arraylen_gc=1)
-
- def test_checklength_cannot_go_away(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n):
- l = [0] * n
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) < 3:
- return len(l)
- l = [0] * n
- n -= 1
- return 0
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == 2
- self.check_loops(arraylen_gc=1)
-
- def test_list_indexerror(self):
- # this is an example where IndexError is raised before
- # even getting to the JIT
- py.test.skip("I suspect bug somewhere outside of the JIT")
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- l[n] = n
- n -= 1
- return l[3]
-
- def g(n):
- try:
- f(n)
- return 0
- except IndexError:
- return 42
-
- res = self.meta_interp(g, [10])
- assert res == 42
- self.check_loops(setitem=2)
-
-class TestLLtype(ListTests, LLJitMixin):
- pass
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
@@ -4,6 +4,8 @@
from pypy.jit.metainterp.optimizeutil import descrlist_dict
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.optimizeopt import optimizer
+from pypy.jit.metainterp.executor import execute
+from pypy.jit.codewriter.heaptracker import vtable2descr
class AbstractVirtualValue(optimizer.OptValue):
@@ -72,28 +74,53 @@
assert isinstance(fieldvalue, optimizer.OptValue)
self._fields[ofs] = fieldvalue
+ def _get_descr(self):
+ raise NotImplementedError
+
+ def _is_immutable_and_filled_with_constants(self):
+ count = self._get_descr().count_fields_if_immutable()
+ if count != len(self._fields): # always the case if count == -1
+ return False
+ for value in self._fields.itervalues():
+ subbox = value.force_box()
+ if not isinstance(subbox, Const):
+ return False
+ return True
+
def _really_force(self):
- assert self.source_op is not None
+ op = self.source_op
+ assert op is not None
# ^^^ This case should not occur any more (see test_bug_3).
#
if not we_are_translated():
- self.source_op.name = 'FORCE ' + self.source_op.name
- newoperations = self.optimizer.newoperations
- newoperations.append(self.source_op)
- self.box = box = self.source_op.result
- #
- iteritems = self._fields.iteritems()
- if not we_are_translated(): #random order is fine, except for tests
- iteritems = list(iteritems)
- iteritems.sort(key = lambda (x,y): x.sort_key())
- for ofs, value in iteritems:
- if value.is_null():
- continue
- subbox = value.force_box()
- op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
- descr=ofs)
+ op.name = 'FORCE ' + self.source_op.name
+
+ if self._is_immutable_and_filled_with_constants():
+ box = self.optimizer.constant_fold(op)
+ self.make_constant(box)
+ for ofs, value in self._fields.iteritems():
+ subbox = value.force_box()
+ assert isinstance(subbox, Const)
+ execute(self.optimizer.cpu, None, rop.SETFIELD_GC,
+ ofs, box, subbox)
+ # keep self._fields, because it's all immutable anyway
+ else:
+ newoperations = self.optimizer.newoperations
newoperations.append(op)
- self._fields = None
+ self.box = box = op.result
+ #
+ iteritems = self._fields.iteritems()
+ if not we_are_translated(): #random order is fine, except for tests
+ iteritems = list(iteritems)
+ iteritems.sort(key = lambda (x,y): x.sort_key())
+ for ofs, value in iteritems:
+ if value.is_null():
+ continue
+ subbox = value.force_box()
+ op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
+ descr=ofs)
+ newoperations.append(op)
+ self._fields = None
def _get_field_descr_list(self):
_cached_sorted_fields = self._cached_sorted_fields
@@ -168,6 +195,9 @@
fielddescrs = self._get_field_descr_list()
return modifier.make_virtual(self.known_class, fielddescrs)
+ def _get_descr(self):
+ return vtable2descr(self.optimizer.cpu, self.known_class.getint())
+
def __repr__(self):
cls_name = self.known_class.value.adr.ptr._obj._TYPE._name
if self._fields is None:
@@ -185,6 +215,9 @@
fielddescrs = self._get_field_descr_list()
return modifier.make_vstruct(self.structdescr, fielddescrs)
+ def _get_descr(self):
+ return self.structdescr
+
class VArrayValue(AbstractVirtualValue):
def __init__(self, optimizer, arraydescr, size, keybox, source_op=None):
diff --git a/pypy/rlib/rsre/test/test_zjit.py b/pypy/rlib/rsre/test/test_zjit.py
--- a/pypy/rlib/rsre/test/test_zjit.py
+++ b/pypy/rlib/rsre/test/test_zjit.py
@@ -1,5 +1,5 @@
import py
-from pypy.jit.metainterp.test import test_basic
+from pypy.jit.metainterp.test import support
from pypy.rlib.nonconst import NonConstant
from pypy.rlib.rsre.test.test_match import get_code
from pypy.rlib.rsre import rsre_core
@@ -45,7 +45,7 @@
assert m._jit_unroll_safe_
-class TestJitRSre(test_basic.LLJitMixin):
+class TestJitRSre(support.LLJitMixin):
def meta_interp_match(self, pattern, string, repeat=1):
r = get_code(pattern)
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -351,14 +351,6 @@
"""Return the number of free variables in co."""
raise NotImplementedError
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
-def PyCode_New(space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars, cellvars, filename, name, firstlineno, lnotab):
- """Return a new code object. If you need a dummy code object to
- create a frame, use PyCode_NewEmpty() instead. Calling
- PyCode_New() directly can bind you to a precise Python
- version since the definition of the bytecode changes often."""
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.INT_real, error=-1)
def PyCodec_Register(space, search_function):
"""Register a new codec search function.
@@ -1116,20 +1108,6 @@
with an exception set on failure (the module still exists in this case)."""
raise NotImplementedError
- at cpython_api([rffi.CCHARP], PyObject)
-def PyImport_AddModule(space, name):
- """Return the module object corresponding to a module name. The name argument
- may be of the form package.module. First check the modules dictionary if
- there's one there, and if not, create a new one and insert it in the modules
- dictionary. Return NULL with an exception set on failure.
-
- This function does not load or import the module; if the module wasn't already
- loaded, you will get an empty module object. Use PyImport_ImportModule()
- or one of its variants to import a module. Package structures implied by a
- dotted name for name are not created if not already present."""
- borrow_from()
- raise NotImplementedError
-
@cpython_api([rffi.CCHARP, PyObject], PyObject)
def PyImport_ExecCodeModule(space, name, co):
"""Given a module name (possibly of the form package.module) and a code
@@ -1965,14 +1943,6 @@
"""
raise NotImplementedError
- at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
-def PyObject_Cmp(space, o1, o2, result):
- """Compare the values of o1 and o2 using a routine provided by o1, if one
- exists, otherwise with a routine provided by o2. The result of the
- comparison is returned in result. Returns -1 on failure. This is the
- equivalent of the Python statement result = cmp(o1, o2)."""
- raise NotImplementedError
-
@cpython_api([PyObject], PyObject)
def PyObject_Bytes(space, o):
"""Compute a bytes representation of object o. In 2.x, this is just a alias
diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py
--- a/pypy/jit/backend/x86/test/test_rx86.py
+++ b/pypy/jit/backend/x86/test/test_rx86.py
@@ -206,3 +206,8 @@
s = CodeBuilder64()
s.MOV_rm(edx, (edi, -1))
assert s.getvalue() == '\x48\x8B\x57\xFF'
+
+def test_movsd_xj_64():
+ s = CodeBuilder64()
+ s.MOVSD_xj(xmm2, 0x01234567)
+ assert s.getvalue() == '\xF2\x0F\x10\x14\x25\x67\x45\x23\x01'
diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_model.py
@@ -52,6 +52,8 @@
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = pipe.communicate()
+ if stderr.startswith('SKIP:'):
+ py.test.skip(stderr)
assert not stderr
#
# parse the JIT log
@@ -100,11 +102,11 @@
class TestOpMatcher(object):
- def match(self, src1, src2):
+ def match(self, src1, src2, **kwds):
from pypy.tool.jitlogparser.parser import SimpleParser
loop = SimpleParser.parse_from_input(src1)
matcher = OpMatcher(loop.operations, src=src1)
- return matcher.match(src2)
+ return matcher.match(src2, **kwds)
def test_match_var(self):
match_var = OpMatcher([]).match_var
@@ -234,6 +236,21 @@
"""
assert self.match(loop, expected)
+ def test_ignore_opcodes(self):
+ loop = """
+ [i0]
+ i1 = int_add(i0, 1)
+ i4 = force_token()
+ i2 = int_sub(i1, 10)
+ jump(i4)
+ """
+ expected = """
+ i1 = int_add(i0, 1)
+ i2 = int_sub(i1, 10)
+ jump(i4, descr=...)
+ """
+ assert self.match(loop, expected, ignore_ops=['force_token'])
+
class TestRunPyPyC(BaseTestPyPyC):
@@ -253,6 +270,14 @@
log = self.run(src, [30, 12])
assert log.result == 42
+ def test_skip(self):
+ import pytest
+ def f():
+ import sys
+ print >> sys.stderr, 'SKIP: foobar'
+ #
+ raises(pytest.skip.Exception, "self.run(f, [])")
+
def test_parse_jitlog(self):
def f():
i = 0
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -37,7 +37,7 @@
DEBUG_WRAPPER = True
# update these for other platforms
-Py_ssize_t = lltype.Signed
+Py_ssize_t = lltype.Typedef(rffi.SSIZE_T, 'Py_ssize_t')
Py_ssize_tP = rffi.CArrayPtr(Py_ssize_t)
size_t = rffi.ULONG
ADDR = lltype.Signed
@@ -192,14 +192,19 @@
- set `external` to False to get a C function pointer, but not exported by
the API headers.
"""
+ if isinstance(restype, lltype.Typedef):
+ real_restype = restype.OF
+ else:
+ real_restype = restype
+
if error is _NOT_SPECIFIED:
- if isinstance(restype, lltype.Ptr):
- error = lltype.nullptr(restype.TO)
- elif restype is lltype.Void:
+ if isinstance(real_restype, lltype.Ptr):
+ error = lltype.nullptr(real_restype.TO)
+ elif real_restype is lltype.Void:
error = CANNOT_FAIL
if type(error) is int:
- error = rffi.cast(restype, error)
- expect_integer = (isinstance(restype, lltype.Primitive) and
+ error = rffi.cast(real_restype, error)
+ expect_integer = (isinstance(real_restype, lltype.Primitive) and
rffi.cast(restype, 0) == 0)
def decorate(func):
@@ -400,21 +405,9 @@
# So we need a forward and backward mapping in our State instance
PyObjectStruct = lltype.ForwardReference()
PyObject = lltype.Ptr(PyObjectStruct)
-PyBufferProcs = lltype.ForwardReference()
PyObjectFields = (("ob_refcnt", lltype.Signed), ("ob_type", PyTypeObjectPtr))
-def F(ARGS, RESULT=lltype.Signed):
- return lltype.Ptr(lltype.FuncType(ARGS, RESULT))
-PyBufferProcsFields = (
- ("bf_getreadbuffer", F([PyObject, lltype.Signed, rffi.VOIDPP])),
- ("bf_getwritebuffer", F([PyObject, lltype.Signed, rffi.VOIDPP])),
- ("bf_getsegcount", F([PyObject, rffi.INTP])),
- ("bf_getcharbuffer", F([PyObject, lltype.Signed, rffi.CCHARPP])),
-# we don't support new buffer interface for now
- ("bf_getbuffer", rffi.VOIDP),
- ("bf_releasebuffer", rffi.VOIDP))
PyVarObjectFields = PyObjectFields + (("ob_size", Py_ssize_t), )
cpython_struct('PyObject', PyObjectFields, PyObjectStruct)
-cpython_struct('PyBufferProcs', PyBufferProcsFields, PyBufferProcs)
PyVarObjectStruct = cpython_struct("PyVarObject", PyVarObjectFields)
PyVarObject = lltype.Ptr(PyVarObjectStruct)
@@ -539,7 +532,8 @@
elif is_PyObject(callable.api_func.restype):
if result is None:
- retval = make_ref(space, None)
+ retval = rffi.cast(callable.api_func.restype,
+ make_ref(space, None))
elif isinstance(result, Reference):
retval = result.get_ref(space)
elif not rffi._isllptr(result):
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
@@ -255,6 +255,9 @@
return cls
def build_new_ctypes_type(T, delayed_builders):
+ if isinstance(T, lltype.Typedef):
+ T = T.OF
+
if isinstance(T, lltype.Ptr):
if isinstance(T.TO, lltype.FuncType):
argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS
@@ -758,6 +761,8 @@
"""
if T is lltype.Void:
return None
+ if isinstance(T, lltype.Typedef):
+ T = T.OF
if isinstance(T, lltype.Ptr):
if not cobj or not ctypes.cast(cobj, ctypes.c_void_p).value: # NULL pointer
# CFunctionType.__nonzero__ is broken before Python 2.6
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -7,10 +7,10 @@
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.interpreter.typedef import GetSetProperty
from pypy.module.cpyext.api import (
- cpython_api, cpython_struct, bootstrap_function, Py_ssize_t,
+ cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
- PyBufferProcs, build_type_checkers)
+ build_type_checkers)
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
track_reference, RefcountState, borrow_from)
@@ -24,7 +24,7 @@
from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
from pypy.module.cpyext.typeobjectdefs import (
PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
- PyNumberMethods, PySequenceMethods)
+ PyNumberMethods, PySequenceMethods, PyBufferProcs)
from pypy.module.cpyext.slotdefs import (
slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
from pypy.interpreter.error import OperationError
@@ -361,14 +361,14 @@
# hopefully this does not clash with the memory model assumed in
# extension modules
- at cpython_api([PyObject, rffi.INTP], lltype.Signed, external=False,
+ at cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
error=CANNOT_FAIL)
def str_segcount(space, w_obj, ref):
if ref:
- ref[0] = rffi.cast(rffi.INT, space.len_w(w_obj))
+ ref[0] = space.len_w(w_obj)
return 1
- at cpython_api([PyObject, lltype.Signed, rffi.VOIDPP], lltype.Signed,
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
external=False, error=-1)
def str_getreadbuffer(space, w_str, segment, ref):
from pypy.module.cpyext.stringobject import PyString_AsString
@@ -381,7 +381,7 @@
Py_DecRef(space, pyref)
return space.len_w(w_str)
- at cpython_api([PyObject, lltype.Signed, rffi.CCHARPP], lltype.Signed,
+ at cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
external=False, error=-1)
def str_getcharbuffer(space, w_str, segment, ref):
from pypy.module.cpyext.stringobject import PyString_AsString
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -347,8 +347,9 @@
assert list('') == []
assert list('abc') == ['a', 'b', 'c']
assert list((1, 2)) == [1, 2]
- l = []
+ l = [1]
assert list(l) is not l
+ assert list(l) == l
assert list(range(10)) == range(10)
def test_explicit_new_init(self):
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -798,7 +798,6 @@
return w_default
def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default):
- # XXX should be more efficient, with only one dict lookup
return w_dict.setdefault(w_key, w_default)
def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w):
diff --git a/pypy/translator/backendopt/test/test_inline.py b/pypy/translator/backendopt/test/test_inline.py
--- a/pypy/translator/backendopt/test/test_inline.py
+++ b/pypy/translator/backendopt/test/test_inline.py
@@ -1,7 +1,7 @@
# XXX clean up these tests to use more uniform helpers
import py
import os
-from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.objspace.flow.model import last_exception, checkgraph
from pypy.translator.backendopt import canraise
from pypy.translator.backendopt.inline import simple_inline_function, CannotInline
@@ -20,29 +20,27 @@
from pypy.translator.backendopt import removenoops
from pypy.objspace.flow.model import summary
-def no_missing_concretetype(node):
- if isinstance(node, Block):
- for v in node.inputargs:
- assert hasattr(v, 'concretetype')
- for op in node.operations:
- for v in op.args:
- assert hasattr(v, 'concretetype')
- assert hasattr(op.result, 'concretetype')
- if isinstance(node, Link):
- if node.exitcase is not None:
- assert hasattr(node, 'llexitcase')
- for v in node.args:
- assert hasattr(v, 'concretetype')
- if isinstance(node.last_exception, (Variable, Constant)):
- assert hasattr(node.last_exception, 'concretetype')
- if isinstance(node.last_exc_value, (Variable, Constant)):
- assert hasattr(node.last_exc_value, 'concretetype')
-
def sanity_check(t):
# look for missing '.concretetype'
for graph in t.graphs:
checkgraph(graph)
- traverse(no_missing_concretetype, graph)
+ for node in graph.iterblocks():
+ for v in node.inputargs:
+ assert hasattr(v, 'concretetype')
+ for op in node.operations:
+ for v in op.args:
+ assert hasattr(v, 'concretetype')
+ assert hasattr(op.result, 'concretetype')
+ for node in graph.iterlinks():
+ if node.exitcase is not None:
+ assert hasattr(node, 'llexitcase')
+ for v in node.args:
+ assert hasattr(v, 'concretetype')
+ if isinstance(node.last_exception, (Variable, Constant)):
+ assert hasattr(node.last_exception, 'concretetype')
+ if isinstance(node.last_exc_value, (Variable, Constant)):
+ assert hasattr(node.last_exc_value, 'concretetype')
+
class CustomError1(Exception):
def __init__(self):
diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py
--- a/pypy/module/cpyext/import_.py
+++ b/pypy/module/cpyext/import_.py
@@ -1,8 +1,10 @@
from pypy.interpreter import module
from pypy.module.cpyext.api import (
generic_cpy_call, cpython_api, PyObject, CONST_STRING)
+from pypy.module.cpyext.pyobject import borrow_from
from pypy.rpython.lltypesystem import rffi
from pypy.interpreter.error import OperationError
+from pypy.interpreter.module import Module
@cpython_api([PyObject], PyObject)
def PyImport_Import(space, w_name):
@@ -51,3 +53,23 @@
from pypy.module.imp.importing import reload
return reload(space, w_mod)
+ at cpython_api([CONST_STRING], PyObject)
+def PyImport_AddModule(space, name):
+ """Return the module object corresponding to a module name. The name
+ argument may be of the form package.module. First check the modules
+ dictionary if there's one there, and if not, create a new one and insert
+ it in the modules dictionary. Return NULL with an exception set on
+ failure.
+
+ This function does not load or import the module; if the module wasn't
+ already loaded, you will get an empty module object. Use
+ PyImport_ImportModule() or one of its variants to import a module.
+ Package structures implied by a dotted name for name are not created if
+ not already present."""
+ from pypy.module.imp.importing import check_sys_modules_w
+ modulename = rffi.charp2str(name)
+ w_mod = check_sys_modules_w(space, modulename)
+ if not w_mod or space.is_w(w_mod, space.w_None):
+ w_mod = Module(space, space.wrap(modulename))
+ return borrow_from(None, w_mod)
+
diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py
--- a/pypy/module/cpyext/test/test_import.py
+++ b/pypy/module/cpyext/test/test_import.py
@@ -1,5 +1,6 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.rpython.lltypesystem import rffi, lltype
class TestImport(BaseApiTest):
def test_import(self, space, api):
@@ -7,6 +8,16 @@
assert pdb
assert space.getattr(pdb, space.wrap("pm"))
+ def test_addmodule(self, space, api):
+ with rffi.scoped_str2charp("sys") as modname:
+ w_sys = api.PyImport_AddModule(modname)
+ assert w_sys is space.sys
+
+ with rffi.scoped_str2charp("foobar") as modname:
+ w_foobar = api.PyImport_AddModule(modname)
+ assert space.str_w(space.getattr(w_foobar,
+ space.wrap('__name__'))) == 'foobar'
+
def test_reload(self, space, api):
pdb = api.PyImport_Import(space.wrap("pdb"))
space.delattr(pdb, space.wrap("set_trace"))
diff --git a/pypy/tool/jitlogparser/module_finder.py b/pypy/tool/jitlogparser/module_finder.py
--- a/pypy/tool/jitlogparser/module_finder.py
+++ b/pypy/tool/jitlogparser/module_finder.py
@@ -6,7 +6,7 @@
more = [code]
while more:
next = more.pop()
- res[next.co_firstlineno] = next
+ res[(next.co_firstlineno, next.co_name)] = next
more += [co for co in next.co_consts
if isinstance(co, types.CodeType)]
return res
diff --git a/pypy/translator/oosupport/test_template/builtin.py b/pypy/translator/oosupport/test_template/builtin.py
--- a/pypy/translator/oosupport/test_template/builtin.py
+++ b/pypy/translator/oosupport/test_template/builtin.py
@@ -227,6 +227,17 @@
assert res == ord('a')
+ def test_rlocale(self):
+ from pypy.rlib.rlocale import isupper, islower, isalpha, isalnum, tolower
+ def fn():
+ assert isupper(ord("A"))
+ assert islower(ord("a"))
+ assert not isalpha(ord(" "))
+ assert isalnum(ord("1"))
+ assert tolower(ord("A")) == ord("a")
+ self.interpret(fn, [])
+
+
class BaseTestTime(llBaseTestTime):
def test_time_clock(self):
diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -261,7 +261,8 @@
if ret != 0:
raiseWindowsError(space, ret, 'RegQueryValue')
- return space.wrap(rffi.charp2strn(buf, bufsize_p[0] - 1))
+ length = intmask(bufsize_p[0] - 1)
+ return space.wrap(rffi.charp2strn(buf, length))
def convert_to_regdata(space, w_value, typ):
buf = None
@@ -445,9 +446,10 @@
continue
if ret != 0:
raiseWindowsError(space, ret, 'RegQueryValueEx')
+ length = intmask(retDataSize[0])
return space.newtuple([
convert_from_regdata(space, databuf,
- retDataSize[0], retType[0]),
+ length, retType[0]),
space.wrap(retType[0]),
])
@@ -595,11 +597,11 @@
if ret != 0:
raiseWindowsError(space, ret, 'RegEnumValue')
+ length = intmask(retDataSize[0])
return space.newtuple([
space.wrap(rffi.charp2str(valuebuf)),
convert_from_regdata(space, databuf,
- retDataSize[0],
- retType[0]),
+ length, retType[0]),
space.wrap(retType[0]),
])
diff --git a/pypy/jit/backend/cli/test/test_basic.py b/pypy/jit/backend/cli/test/test_basic.py
--- a/pypy/jit/backend/cli/test/test_basic.py
+++ b/pypy/jit/backend/cli/test/test_basic.py
@@ -1,14 +1,14 @@
import py
from pypy.jit.backend.cli.runner import CliCPU
-from pypy.jit.metainterp.test import test_basic
+from pypy.jit.metainterp.test import support, test_ajit
-class CliJitMixin(test_basic.OOJitMixin):
+class CliJitMixin(suport.OOJitMixin):
CPUClass = CliCPU
def setup_class(cls):
from pypy.translator.cli.support import PythonNet
PythonNet.System # possibly raises Skip
-class TestBasic(CliJitMixin, test_basic.TestOOtype):
+class TestBasic(CliJitMixin, test_ajit.TestOOtype):
# for the individual tests see
# ====> ../../../metainterp/test/test_basic.py
diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py
--- a/pypy/translator/jvm/opcodes.py
+++ b/pypy/translator/jvm/opcodes.py
@@ -106,6 +106,10 @@
'debug_catch_exception': Ignore,
'debug_reraise_traceback': Ignore,
'debug_print_traceback': Ignore,
+ 'debug_start': Ignore,
+ 'debug_stop': Ignore,
+ 'debug_print': Ignore,
+ 'keepalive': Ignore,
# __________ numeric operations __________
@@ -144,6 +148,7 @@
'int_xor_ovf': jvm.IXOR,
'int_floordiv_ovf_zer': jvm.IFLOORDIVZEROVF,
'int_mod_ovf_zer': _check_zer(jvm.IREMOVF),
+ 'int_between': jvm.PYPYINTBETWEEN,
'uint_invert': 'bitwise_negate',
@@ -185,8 +190,8 @@
'llong_mod_zer': _check_zer(jvm.LREM),
'llong_and': jvm.LAND,
'llong_or': jvm.LOR,
- 'llong_lshift': [PushAllArgs, jvm.L2I, jvm.LSHL, StoreResult],
- 'llong_rshift': [PushAllArgs, jvm.L2I, jvm.LSHR, StoreResult],
+ 'llong_lshift': [PushAllArgs, jvm.LSHL, StoreResult],
+ 'llong_rshift': [PushAllArgs, jvm.LSHR, StoreResult],
'llong_xor': jvm.LXOR,
'llong_floordiv_ovf': jvm.LFLOORDIVOVF,
'llong_floordiv_ovf_zer': jvm.LFLOORDIVZEROVF,
@@ -202,9 +207,11 @@
'ullong_truediv': None, # TODO
'ullong_floordiv': jvm.LDIV, # valid?
'ullong_mod': jvm.PYPYULONGMOD,
- 'ullong_lshift': [PushAllArgs, jvm.L2I, jvm.LSHL, StoreResult],
- 'ullong_rshift': [PushAllArgs, jvm.L2I, jvm.LUSHR, StoreResult],
+ 'ullong_lshift': [PushAllArgs, jvm.LSHL, StoreResult],
+ 'ullong_rshift': [PushAllArgs, jvm.LUSHR, StoreResult],
'ullong_mod_zer': jvm.PYPYULONGMOD,
+ 'ullong_or': jvm.LOR,
+ 'ullong_and': jvm.LAND,
# when casting from bool we want that every truth value is casted
# to 1: we can't simply DoNothing, because the CLI stack could
@@ -227,5 +234,8 @@
'cast_float_to_uint': jvm.PYPYDOUBLETOUINT,
'truncate_longlong_to_int': jvm.L2I,
'cast_longlong_to_float': jvm.L2D,
+ 'cast_float_to_ulonglong': jvm.PYPYDOUBLETOULONG,
+ 'cast_ulonglong_to_float': jvm.PYPYULONGTODOUBLE,
'cast_primitive': [PushAllArgs, CastPrimitive, StoreResult],
+ 'force_cast': [PushAllArgs, CastPrimitive, StoreResult],
})
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -1,6 +1,6 @@
import py
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import OOJitMixin, LLJitMixin
+from pypy.jit.metainterp.test.support import OOJitMixin, LLJitMixin
class ToyLanguageTests:
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
@@ -25,12 +25,13 @@
class Descr(history.AbstractDescr):
def __init__(self, ofs, typeinfo, extrainfo=None, name=None,
- arg_types=None):
+ arg_types=None, count_fields_if_immut=-1):
self.ofs = ofs
self.typeinfo = typeinfo
self.extrainfo = extrainfo
self.name = name
self.arg_types = arg_types
+ self.count_fields_if_immut = count_fields_if_immut
def get_arg_types(self):
return self.arg_types
@@ -63,6 +64,9 @@
def as_vtable_size_descr(self):
return self
+ def count_fields_if_immutable(self):
+ return self.count_fields_if_immut
+
def __lt__(self, other):
raise TypeError("cannot use comparison on Descrs")
def __le__(self, other):
@@ -109,12 +113,14 @@
return False
def getdescr(self, ofs, typeinfo='?', extrainfo=None, name=None,
- arg_types=None):
- key = (ofs, typeinfo, extrainfo, name, arg_types)
+ arg_types=None, count_fields_if_immut=-1):
+ key = (ofs, typeinfo, extrainfo, name, arg_types,
+ count_fields_if_immut)
try:
return self._descrs[key]
except KeyError:
- descr = Descr(ofs, typeinfo, extrainfo, name, arg_types)
+ descr = Descr(ofs, typeinfo, extrainfo, name, arg_types,
+ count_fields_if_immut)
self._descrs[key] = descr
return descr
@@ -284,7 +290,8 @@
def sizeof(self, S):
assert not isinstance(S, lltype.Ptr)
- return self.getdescr(symbolic.get_size(S))
+ count = heaptracker.count_fields_if_immutable(S)
+ return self.getdescr(symbolic.get_size(S), count_fields_if_immut=count)
class LLtypeCPU(BaseCPU):
diff --git a/pypy/module/cpyext/typeobjectdefs.py b/pypy/module/cpyext/typeobjectdefs.py
--- a/pypy/module/cpyext/typeobjectdefs.py
+++ b/pypy/module/cpyext/typeobjectdefs.py
@@ -1,9 +1,8 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
-from pypy.module.cpyext.api import cpython_struct, \
- PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, \
- Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, \
- PyTypeObject, PyTypeObjectPtr, PyBufferProcs, FILEP
+from pypy.module.cpyext.api import (cpython_struct, Py_ssize_t, Py_ssize_tP,
+ PyVarObjectFields, PyTypeObject, PyTypeObjectPtr, FILEP,
+ Py_TPFLAGS_READYING, Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE)
from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
from pypy.module.cpyext.modsupport import PyMethodDef
@@ -55,6 +54,14 @@
wrapperfunc = P(FT([PyO, PyO, rffi.VOIDP], PyO))
wrapperfunc_kwds = P(FT([PyO, PyO, rffi.VOIDP, PyO], PyO))
+readbufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
+writebufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
+segcountproc = P(FT([PyO, Py_ssize_tP], Py_ssize_t))
+charbufferproc = P(FT([PyO, Py_ssize_t, rffi.CCHARPP], Py_ssize_t))
+## We don't support new buffer interface for now
+getbufferproc = rffi.VOIDP
+releasebufferproc = rffi.VOIDP
+
PyGetSetDef = cpython_struct("PyGetSetDef", (
("name", rffi.CCHARP),
@@ -127,7 +134,6 @@
("mp_ass_subscript", objobjargproc),
))
-"""
PyBufferProcs = cpython_struct("PyBufferProcs", (
("bf_getreadbuffer", readbufferproc),
("bf_getwritebuffer", writebufferproc),
@@ -136,7 +142,6 @@
("bf_getbuffer", getbufferproc),
("bf_releasebuffer", releasebufferproc),
))
-"""
PyMemberDef = cpython_struct("PyMemberDef", (
("name", rffi.CCHARP),
diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py
--- a/pypy/module/posix/app_posix.py
+++ b/pypy/module/posix/app_posix.py
@@ -190,22 +190,30 @@
def wait():
""" wait() -> (pid, status)
-
+
Wait for completion of a child process.
"""
return posix.waitpid(-1, 0)
def wait3(options):
- """ wait3() -> (pid, status, rusage)
+ """ wait3(options) -> (pid, status, rusage)
Wait for completion of a child process and provides resource usage informations
"""
from _pypy_wait import wait3
return wait3(options)
+ def wait4(pid, options):
+ """ wait4(pid, options) -> (pid, status, rusage)
+
+ Wait for completion of the child process "pid" and provides resource usage informations
+ """
+ from _pypy_wait import wait4
+ return wait4(pid, options)
+
else:
# Windows implementations
-
+
# Supply os.popen() based on subprocess
def popen(cmd, mode="r", bufsize=-1):
"""popen(command [, mode='r' [, bufsize]]) -> pipe
@@ -293,7 +301,7 @@
raise TypeError("invalid cmd type (%s, expected string)" %
(type(cmd),))
return cmd
-
+
# A proxy for a file whose close waits for the process
class _wrap_close(object):
def __init__(self, stream, proc):
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -14,6 +14,10 @@
(("func_name", PyObject),)
cpython_struct("PyFunctionObject", PyFunctionObjectFields, PyFunctionObjectStruct)
+PyCodeObjectStruct = lltype.ForwardReference()
+PyCodeObject = lltype.Ptr(PyCodeObjectStruct)
+cpython_struct("PyCodeObject", PyObjectFields, PyCodeObjectStruct)
+
@bootstrap_function
def init_functionobject(space):
make_typedescr(Function.typedef,
@@ -65,7 +69,36 @@
assert isinstance(w_method, Method)
return borrow_from(w_method, w_method.w_class)
- at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyObject)
+def unwrap_list_of_strings(space, w_list):
+ return [space.str_w(w_item) for w_item in space.fixedview(w_list)]
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyObject, PyObject, PyObject, PyObject, PyObject,
+ PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
+def PyCode_New(space, argcount, nlocals, stacksize, flags,
+ w_code, w_consts, w_names, w_varnames, w_freevars, w_cellvars,
+ w_filename, w_funcname, firstlineno, w_lnotab):
+ """Return a new code object. If you need a dummy code object to
+ create a frame, use PyCode_NewEmpty() instead. Calling
+ PyCode_New() directly can bind you to a precise Python
+ version since the definition of the bytecode changes often."""
+ return space.wrap(PyCode(space,
+ argcount=rffi.cast(lltype.Signed, argcount),
+ nlocals=rffi.cast(lltype.Signed, nlocals),
+ stacksize=rffi.cast(lltype.Signed, stacksize),
+ flags=rffi.cast(lltype.Signed, flags),
+ code=space.str_w(w_code),
+ consts=space.fixedview(w_consts),
+ names=unwrap_list_of_strings(space, w_names),
+ varnames=unwrap_list_of_strings(space, w_varnames),
+ filename=space.str_w(w_filename),
+ name=space.str_w(w_funcname),
+ firstlineno=rffi.cast(lltype.Signed, firstlineno),
+ lnotab=space.str_w(w_lnotab),
+ freevars=unwrap_list_of_strings(space, w_freevars),
+ cellvars=unwrap_list_of_strings(space, w_cellvars)))
+
+ at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyCodeObject)
def PyCode_NewEmpty(space, filename, funcname, firstlineno):
"""Creates a new empty code object with the specified source location."""
return space.wrap(PyCode(space,
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -1007,7 +1007,8 @@
class AppTestPyPyExtension(object):
def setup_class(cls):
- cls.space = gettestobjspace(usemodules=['imp', 'zipimport'])
+ cls.space = gettestobjspace(usemodules=['imp', 'zipimport',
+ '__pypy__'])
cls.w_udir = cls.space.wrap(str(udir))
def test_run_compiled_module(self):
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -135,7 +135,7 @@
return importing.check_sys_modules(space, w_modulename)
def new_module(space, w_name):
- return space.wrap(Module(space, w_name))
+ return space.wrap(Module(space, w_name, add_package=False))
def init_builtin(space, w_name):
name = space.str_w(w_name)
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
@@ -253,8 +253,10 @@
except OperationError, e:
parser._exc_info = e
XML_StopParser(parser.itself, XML_FALSE)
- return 0
- return 1
+ result = 0
+ else:
+ result = 1
+ return rffi.cast(rffi.INT, result)
callback_type = lltype.Ptr(lltype.FuncType(
[rffi.VOIDP, rffi.CCHARP, XML_Encoding_Ptr], rffi.INT))
XML_SetUnknownEncodingHandler = expat_external(
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -754,6 +754,8 @@
("{x for x in z}", "set comprehension"),
("{x : x for x in z}", "dict comprehension"),
("'str'", "literal"),
+ ("u'str'", "literal"),
+ ("b'bytes'", "literal"),
("()", "()"),
("23", "literal"),
("{}", "literal"),
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,7 +3,7 @@
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
from pypy.rlib.jit import virtual_ref, virtual_ref_finish
from pypy.rlib.objectmodel import compute_unique_id
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.virtualref import VirtualRefInfo
diff --git a/pypy/translator/jvm/test/test_extreme.py b/pypy/translator/jvm/test/test_extreme.py
--- a/pypy/translator/jvm/test/test_extreme.py
+++ b/pypy/translator/jvm/test/test_extreme.py
@@ -1,5 +1,8 @@
+import py
from pypy.translator.jvm.test.runtest import JvmTest
from pypy.translator.oosupport.test_template.extreme import BaseTestExtreme
class TestExtreme(BaseTestExtreme, JvmTest):
- pass
+
+ def test_runtimeerror_due_to_stack_overflow(self):
+ py.test.skip('hotspot bug')
diff --git a/pypy/jit/tl/tla/test_tla.py b/pypy/jit/tl/tla/test_tla.py
--- a/pypy/jit/tl/tla/test_tla.py
+++ b/pypy/jit/tl/tla/test_tla.py
@@ -155,7 +155,7 @@
# ____________________________________________________________
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class TestLLtype(LLJitMixin):
def test_loop(self):
diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py
--- a/pypy/tool/jitlogparser/test/test_parser.py
+++ b/pypy/tool/jitlogparser/test/test_parser.py
@@ -114,11 +114,11 @@
fname = str(py.path.local(__file__).join('..', 'x.py'))
ops = parse('''
[i0, i1]
- debug_merge_point("<code object f, file '%(fname)s', line 5> #9 LOAD_FAST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #12 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #22 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #28 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #6 SETUP_LOOP", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #9 LOAD_FAST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #12 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #22 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #28 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #6 SETUP_LOOP", 0)
''' % locals())
res = Function.from_operations(ops.operations, LoopStorage())
assert res.linerange == (7, 9)
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -196,7 +196,7 @@
class _ExceptionInfo(object):
def __init__(self):
import sys
- self.type, self.value, _ = sys.exc_info()
+ self.type, self.value, self.traceback = sys.exc_info()
return _ExceptionInfo
""")
diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/frameobject.py
@@ -0,0 +1,82 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+ cpython_api, bootstrap_function, PyObjectFields, cpython_struct)
+from pypy.module.cpyext.pyobject import (
+ PyObject, Py_DecRef, make_ref, from_ref, track_reference,
+ make_typedescr, get_typedescr)
+from pypy.module.cpyext.state import State
+from pypy.module.cpyext.pystate import PyThreadState
+from pypy.module.cpyext.funcobject import PyCodeObject
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pycode import PyCode
+
+PyFrameObjectStruct = lltype.ForwardReference()
+PyFrameObject = lltype.Ptr(PyFrameObjectStruct)
+PyFrameObjectFields = (PyObjectFields +
+ (("f_code", PyCodeObject),
+ ("f_globals", PyObject),
+ ("f_lineno", rffi.INT),
+ ))
+cpython_struct("PyFrameObject", PyFrameObjectFields, PyFrameObjectStruct)
+
+ at bootstrap_function
+def init_frameobject(space):
+ make_typedescr(PyFrame.typedef,
+ basestruct=PyFrameObject.TO,
+ attach=frame_attach,
+ dealloc=frame_dealloc,
+ realize=frame_realize)
+
+def frame_attach(space, py_obj, w_obj):
+ "Fills a newly allocated PyFrameObject with a frame object"
+ frame = space.interp_w(PyFrame, w_obj)
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, frame.pycode))
+ py_frame.c_f_globals = make_ref(space, frame.w_globals)
+ rffi.setintfield(py_frame, 'c_f_lineno', frame.f_lineno)
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def frame_dealloc(space, py_obj):
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ Py_DecRef(space, py_code)
+ Py_DecRef(space, py_frame.c_f_globals)
+ from pypy.module.cpyext.object import PyObject_dealloc
+ PyObject_dealloc(space, py_obj)
+
+def frame_realize(space, py_obj):
+ """
+ Creates the frame in the interpreter. The PyFrameObject structure must not
+ be modified after this call.
+ """
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ w_code = from_ref(space, py_code)
+ code = space.interp_w(PyCode, w_code)
+ w_globals = from_ref(space, py_frame.c_f_globals)
+
+ frame = PyFrame(space, code, w_globals, closure=None)
+ frame.f_lineno = py_frame.c_f_lineno
+ w_obj = space.wrap(frame)
+ track_reference(space, py_obj, w_obj)
+ return w_obj
+
+ at cpython_api([PyThreadState, PyCodeObject, PyObject, PyObject], PyFrameObject)
+def PyFrame_New(space, tstate, w_code, w_globals, w_locals):
+ typedescr = get_typedescr(PyFrame.typedef)
+ py_obj = typedescr.allocate(space, space.gettypeobject(PyFrame.typedef))
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ space.interp_w(PyCode, w_code) # sanity check
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, w_code))
+ py_frame.c_f_globals = make_ref(space, w_globals)
+ return py_frame
+
+ at cpython_api([PyFrameObject], rffi.INT_real, error=-1)
+def PyTraceBack_Here(space, w_frame):
+ from pypy.interpreter.pytraceback import record_application_traceback
+ state = space.fromcache(State)
+ if state.operror is None:
+ return -1
+ frame = space.interp_w(PyFrame, w_frame)
+ record_application_traceback(space, state.operror, frame, 0)
+ return 0
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -19,6 +19,8 @@
def __init__(self, rtyper, stats, opts=None, translate_support_code=False,
gcdescr=None):
+ if gcdescr is not None:
+ gcdescr.force_index_ofs = FORCE_INDEX_OFS
AbstractLLCPU.__init__(self, rtyper, stats, opts,
translate_support_code, gcdescr)
@@ -127,7 +129,7 @@
fail_index = rffi.cast(TP, addr_of_force_index)[0]
assert fail_index >= 0, "already forced!"
faildescr = self.get_fail_descr_from_number(fail_index)
- rffi.cast(TP, addr_of_force_index)[0] = -1
+ rffi.cast(TP, addr_of_force_index)[0] = ~fail_index
frb = self.assembler._find_failure_recovery_bytecode(faildescr)
bytecode = rffi.cast(rffi.UCHARP, frb)
# start of "no gc operation!" block
@@ -147,7 +149,6 @@
WORD = 4
NUM_REGS = 8
CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.esi, regloc.edi]
- FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
supports_longlong = True
@@ -163,7 +164,6 @@
WORD = 8
NUM_REGS = 16
CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, regloc.r15]
- FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
def __init__(self, *args, **kwargs):
assert sys.maxint == (2**63 - 1)
diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -86,6 +86,8 @@
metainterp.history = History()
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
+ cpu._all_size_descrs_with_vtable = (
+ LLtypeMixin.cpu._all_size_descrs_with_vtable)
#
loop_tokens = []
loop_token = compile_new_loop(metainterp, loop_tokens, [], 0, None)
diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py
--- a/pypy/jit/metainterp/test/test_recursive.py
+++ b/pypy/jit/metainterp/test/test_recursive.py
@@ -3,7 +3,7 @@
from pypy.rlib.jit import unroll_safe, dont_look_inside
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import fatalerror
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rpython.annlowlevel import hlstr
from pypy.jit.metainterp.warmspot import get_stats
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
@@ -487,7 +487,9 @@
# ^^^ returns an address of nursery free pointer, for later modifications
'gc_adr_of_nursery_top' : LLOp(),
# ^^^ returns an address of pointer, since it can change at runtime
-
+ 'gc_adr_of_root_stack_top': LLOp(),
+ # ^^^ returns the address of gcdata.root_stack_top (for shadowstack only)
+
# experimental operations in support of thread cloning, only
# implemented by the Mark&Sweep GC
'gc_x_swap_pool': LLOp(canraise=(MemoryError,), canunwindgc=True),
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1350,6 +1350,11 @@
pass
def _freeze_(self):
return True
+ def __enter__(self):
+ pass
+ def __exit__(self, *args):
+ pass
+
dummy_lock = DummyLock()
## Table describing the regular part of the interface of object spaces,
diff --git a/pypy/translator/jvm/test/test_builtin.py b/pypy/translator/jvm/test/test_builtin.py
--- a/pypy/translator/jvm/test/test_builtin.py
+++ b/pypy/translator/jvm/test/test_builtin.py
@@ -37,6 +37,15 @@
def test_cast_primitive(self):
py.test.skip('fixme!')
+ def test_os_fstat(self):
+ import os, stat
+ def fn():
+ fd = os.open(__file__, os.O_RDONLY, 0)
+ st = os.fstat(fd)
+ os.close(fd)
+ return st.st_mode
+ res = self.interpret(fn, [])
+ assert stat.S_ISREG(res)
class TestJvmTime(JvmTest, BaseTestTime):
diff --git a/pypy/module/cpyext/include/code.h b/pypy/module/cpyext/include/code.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/code.h
@@ -0,0 +1,12 @@
+#ifndef Py_CODE_H
+#define Py_CODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyCodeObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_CODE_H */
diff --git a/pypy/translator/backendopt/ssa.py b/pypy/translator/backendopt/ssa.py
--- a/pypy/translator/backendopt/ssa.py
+++ b/pypy/translator/backendopt/ssa.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import Variable, mkentrymap, flatten, Block
+from pypy.objspace.flow.model import Variable, mkentrymap, Block
from pypy.tool.algo.unionfind import UnionFind
class DataFlowFamilyBuilder:
diff --git a/pypy/translator/unsimplify.py b/pypy/translator/unsimplify.py
--- a/pypy/translator/unsimplify.py
+++ b/pypy/translator/unsimplify.py
@@ -54,8 +54,7 @@
def split_block(annotator, block, index, _forcelink=None):
"""return a link where prevblock is the block leading up but excluding the
index'th operation and target is a new block with the neccessary variables
- passed on. NOTE: if you call this after rtyping, you WILL need to worry
- about keepalives, you may use backendopt.support.split_block_with_keepalive.
+ passed on.
"""
assert 0 <= index <= len(block.operations)
if block.exitswitch == c_last_exception:
@@ -115,46 +114,6 @@
# in the second block!
return split_block(annotator, block, 0, _forcelink=block.inputargs)
-def remove_direct_loops(annotator, graph):
- """This is useful for code generators: it ensures that no link has
- common input and output variables, which could occur if a block's exit
- points back directly to the same block. It allows code generators to be
- simpler because they don't have to worry about overwriting input
- variables when generating a sequence of assignments."""
- def visit(link):
- if isinstance(link, Link) and link.prevblock is link.target:
- insert_empty_block(annotator, link)
- traverse(visit, graph)
-
-def remove_double_links(annotator, graph):
- """This can be useful for code generators: it ensures that no block has
- more than one incoming links from one and the same other block. It allows
- argument passing along links to be implemented with phi nodes since the
- value of an argument can be determined by looking from which block the
- control passed. """
- def visit(block):
- if isinstance(block, Block):
- double_links = []
- seen = {}
- for link in block.exits:
- if link.target in seen:
- double_links.append(link)
- seen[link.target] = True
- for link in double_links:
- insert_empty_block(annotator, link)
- traverse(visit, graph)
-
-def no_links_to_startblock(graph):
- """Ensure no links to start block."""
- links_to_start_block = False
- for block in graph.iterblocks():
- for link in block.exits:
- if link.target == graph.startblock:
- links_to_start_block = True
- break
- if links_to_start_block:
- insert_empty_startblock(None, graph)
-
def call_initial_function(translator, initial_func, annhelper=None):
"""Before the program starts, call 'initial_func()'."""
from pypy.annotation import model as annmodel
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -36,29 +36,35 @@
init_defaults = Defaults([None])
def init__List(space, w_list, __args__):
+ from pypy.objspace.std.tupleobject import W_TupleObject
# this is on the silly side
w_iterable, = __args__.parse_obj(
None, 'list', init_signature, init_defaults)
- #
- # this is the old version of the loop at the end of this function:
- #
- # w_list.wrappeditems = space.unpackiterable(w_iterable)
- #
- # This is commented out to avoid assigning a new RPython list to
- # 'wrappeditems', which defeats the W_FastSeqIterObject optimization.
- #
items_w = w_list.wrappeditems
del items_w[:]
if w_iterable is not None:
- w_iterator = space.iter(w_iterable)
- while True:
- try:
- w_item = space.next(w_iterator)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- break # done
- items_w.append(w_item)
+ # unfortunately this is duplicating space.unpackiterable to avoid
+ # assigning a new RPython list to 'wrappeditems', which defeats the
+ # W_FastSeqIterObject optimization.
+ if isinstance(w_iterable, W_ListObject):
+ items_w.extend(w_iterable.wrappeditems)
+ elif isinstance(w_iterable, W_TupleObject):
+ items_w.extend(w_iterable.wrappeditems)
+ else:
+ _init_from_iterable(space, items_w, w_iterable)
+
+def _init_from_iterable(space, items_w, w_iterable):
+ # in its own function to make the JIT look into init__List
+ # XXX this would need a JIT driver somehow?
+ w_iterator = space.iter(w_iterable)
+ while True:
+ try:
+ w_item = space.next(w_iterator)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break # done
+ items_w.append(w_item)
def len__List(space, w_list):
result = len(w_list.wrappeditems)
diff --git a/pypy/module/cpyext/include/compile.h b/pypy/module/cpyext/include/compile.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/compile.h
@@ -0,0 +1,13 @@
+#ifndef Py_COMPILE_H
+#define Py_COMPILE_H
+
+#include "code.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_COMPILE_H */
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -6,7 +6,7 @@
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp.history import BoxInt
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
# built documents.
#
# The short X.Y version.
-version = '1.4.1'
+version = '1.5'
# The full version, including alpha/beta/rc tags.
-release = '1.4.1'
+release = '1.5-alpha'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/translator/backendopt/test/test_ssa.py b/pypy/translator/backendopt/test/test_ssa.py
--- a/pypy/translator/backendopt/test/test_ssa.py
+++ b/pypy/translator/backendopt/test/test_ssa.py
@@ -1,6 +1,6 @@
from pypy.translator.backendopt.ssa import *
from pypy.translator.translator import TranslationContext
-from pypy.objspace.flow.model import flatten, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.objspace.flow.model import SpaceOperation
diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -61,14 +61,44 @@
except OperationError, e:
print e.errorstr(self.space)
raise
+
+ try:
+ del self.space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
if self.check_and_print_leaks():
assert False, "Test leaks or loses object(s)."
+ at api.cpython_api([api.Py_ssize_t], api.Py_ssize_t, error=-1)
+def PyPy_TypedefTest1(space, arg):
+ assert lltype.typeOf(arg) == api.Py_ssize_t
+ return 0
+
+ at api.cpython_api([api.Py_ssize_tP], api.Py_ssize_tP)
+def PyPy_TypedefTest2(space, arg):
+ assert lltype.typeOf(arg) == api.Py_ssize_tP
+ return None
+
class TestConversion(BaseApiTest):
def test_conversions(self, space, api):
api.PyPy_GetWrapped(space.w_None)
api.PyPy_GetReference(space.w_None)
+ def test_typedef(self, space):
+ from pypy.translator.c.database import LowLevelDatabase
+ db = LowLevelDatabase()
+ assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest1'])
+ == ('Py_ssize_t', 'Py_ssize_t arg0'))
+ assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest2'])
+ == ('Py_ssize_t *', 'Py_ssize_t *arg0'))
+
+ PyPy_TypedefTest1(space, 0)
+ ppos = lltype.malloc(api.Py_ssize_tP.TO, 1, flavor='raw')
+ ppos[0] = 0
+ PyPy_TypedefTest2(space, ppos)
+ lltype.free(ppos, flavor='raw')
+
def test_copy_header_files(tmpdir):
api.copy_header_files(tmpdir)
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
@@ -23,18 +23,22 @@
self.fail_descr_list = []
self.fail_descr_free_list = []
+ def reserve_some_free_fail_descr_number(self):
+ lst = self.fail_descr_list
+ if len(self.fail_descr_free_list) > 0:
+ n = self.fail_descr_free_list.pop()
+ assert lst[n] is None
+ else:
+ n = len(lst)
+ lst.append(None)
+ return n
+
def get_fail_descr_number(self, descr):
assert isinstance(descr, history.AbstractFailDescr)
n = descr.index
if n < 0:
- lst = self.fail_descr_list
- if len(self.fail_descr_free_list) > 0:
- n = self.fail_descr_free_list.pop()
- assert lst[n] is None
- lst[n] = descr
- else:
- n = len(lst)
- lst.append(descr)
+ n = self.reserve_some_free_fail_descr_number()
+ self.fail_descr_list[n] = descr
descr.index = n
return n
@@ -294,6 +298,13 @@
def record_faildescr_index(self, n):
self.faildescr_indices.append(n)
+ def reserve_and_record_some_faildescr_index(self):
+ # like record_faildescr_index(), but invent and return a new,
+ # unused faildescr index
+ n = self.cpu.reserve_some_free_fail_descr_number()
+ self.record_faildescr_index(n)
+ return n
+
def compiling_a_bridge(self):
self.cpu.total_compiled_bridges += 1
self.bridges_count += 1
diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py
+++ b/pypy/translator/backendopt/inline.py
@@ -5,7 +5,7 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
from pypy.objspace.flow.model import SpaceOperation, c_last_exception
from pypy.objspace.flow.model import FunctionGraph
-from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph
+from pypy.objspace.flow.model import mkentrymap, checkgraph
from pypy.annotation import model as annmodel
from pypy.rpython.lltypesystem.lltype import Bool, Signed, typeOf, Void, Ptr
from pypy.rpython.lltypesystem.lltype import normalizeptr
@@ -13,7 +13,7 @@
from pypy.rpython import rmodel
from pypy.tool.algo import sparsemat
from pypy.translator.backendopt import removenoops
-from pypy.translator.backendopt.support import log, split_block_with_keepalive
+from pypy.translator.backendopt.support import log
from pypy.translator.unsimplify import split_block
from pypy.translator.backendopt.support import find_backedges, find_loop_blocks
from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -280,13 +280,6 @@
self.varmap[var] = copyvar(None, var)
return self.varmap[var]
- def generate_keepalive(self, *args):
- from pypy.translator.backendopt.support import generate_keepalive
- if self.translator.rtyper.type_system.name == 'lltypesystem':
- return generate_keepalive(*args)
- else:
- return []
-
def passon_vars(self, cache_key):
if cache_key in self._passon_vars:
return self._passon_vars[cache_key]
@@ -397,7 +390,6 @@
for exceptionlink in afterblock.exits[1:]:
if exc_match(vtable, exceptionlink.llexitcase):
passon_vars = self.passon_vars(link.prevblock)
- copiedblock.operations += self.generate_keepalive(passon_vars)
copiedlink.target = exceptionlink.target
linkargs = self.find_args_in_exceptional_case(
exceptionlink, link.prevblock, var_etype, var_evalue, afterblock, passon_vars)
@@ -445,7 +437,6 @@
del blocks[-1].exits[0].llexitcase
linkargs = copiedexceptblock.inputargs
copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
- copiedexceptblock.operations += self.generate_keepalive(linkargs)
def do_inline(self, block, index_operation):
splitlink = split_block(None, block, index_operation)
@@ -457,11 +448,8 @@
# this copy is created with the method passon_vars
self.original_passon_vars = [arg for arg in block.exits[0].args
if isinstance(arg, Variable)]
- n = 0
- while afterblock.operations[n].opname == 'keepalive':
- n += 1
- assert afterblock.operations[n].opname == self.op.opname
- self.op = afterblock.operations.pop(n)
+ assert afterblock.operations[0].opname == self.op.opname
+ self.op = afterblock.operations.pop(0)
#vars that need to be passed through the blocks of the inlined function
linktoinlined = splitlink
copiedstartblock = self.copy_block(self.graph_to_inline.startblock)
@@ -551,7 +539,6 @@
OP_WEIGHTS = {'same_as': 0,
'cast_pointer': 0,
- 'keepalive': 0,
'malloc': 2,
'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme
'resume_point': sys.maxint, # XXX bit extreme
@@ -784,5 +771,4 @@
call_count_pred=call_count_pred)
log.inlining('inlined %d callsites.'% (count,))
for graph in graphs:
- removenoops.remove_superfluous_keep_alive(graph)
removenoops.remove_duplicate_casts(graph, translator)
diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_frameobject.py
@@ -0,0 +1,66 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestFrameObject(AppTestCpythonExtensionBase):
+
+ def test_forge_frame(self):
+ module = self.import_extension('foo', [
+ ("raise_exception", "METH_NOARGS",
+ """
+ PyObject *py_srcfile = PyString_FromString("filename");
+ PyObject *py_funcname = PyString_FromString("funcname");
+ PyObject *py_globals = PyDict_New();
+ PyObject *empty_string = PyString_FromString("");
+ PyObject *empty_tuple = PyTuple_New(0);
+ PyCodeObject *py_code;
+ PyFrameObject *py_frame;
+
+ py_code = PyCode_New(
+ 0, /*int argcount,*/
+ #if PY_MAJOR_VERSION >= 3
+ 0, /*int kwonlyargcount,*/
+ #endif
+ 0, /*int nlocals,*/
+ 0, /*int stacksize,*/
+ 0, /*int flags,*/
+ empty_string, /*PyObject *code,*/
+ empty_tuple, /*PyObject *consts,*/
+ empty_tuple, /*PyObject *names,*/
+ empty_tuple, /*PyObject *varnames,*/
+ empty_tuple, /*PyObject *freevars,*/
+ empty_tuple, /*PyObject *cellvars,*/
+ py_srcfile, /*PyObject *filename,*/
+ py_funcname, /*PyObject *name,*/
+ 42, /*int firstlineno,*/
+ empty_string /*PyObject *lnotab*/
+ );
+
+ if (!py_code) goto bad;
+ py_frame = PyFrame_New(
+ PyThreadState_Get(), /*PyThreadState *tstate,*/
+ py_code, /*PyCodeObject *code,*/
+ py_globals, /*PyObject *globals,*/
+ 0 /*PyObject *locals*/
+ );
+ if (!py_frame) goto bad;
+ py_frame->f_lineno = 48; /* Does not work with CPython */
+ PyErr_SetString(PyExc_ValueError, "error message");
+ PyTraceBack_Here(py_frame);
+ bad:
+ Py_XDECREF(py_srcfile);
+ Py_XDECREF(py_funcname);
+ Py_XDECREF(empty_string);
+ Py_XDECREF(empty_tuple);
+ Py_XDECREF(py_globals);
+ Py_XDECREF(py_code);
+ Py_XDECREF(py_frame);
+ return NULL;
+ """),
+ ])
+ exc = raises(ValueError, module.raise_exception)
+ frame = exc.traceback.tb_frame
+ assert frame.f_code.co_filename == "filename"
+ assert frame.f_code.co_name == "funcname"
+
+ # Cython does not work on CPython as well...
+ assert exc.traceback.tb_lineno == 42 # should be 48
+ assert frame.f_lineno == 42
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -1,16 +1,20 @@
+from __future__ import with_statement
+
import re
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import generic_cpy_call, cpython_api, PyObject
+from pypy.module.cpyext.api import (
+ cpython_api, generic_cpy_call, PyObject, Py_ssize_t)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc,
ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
- hashfunc, descrgetfunc, descrsetfunc, objobjproc)
+ cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, readbufferproc)
from pypy.module.cpyext.pyobject import from_ref
from pypy.module.cpyext.pyerrors import PyErr_Occurred
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.buffer import Buffer as W_Buffer
from pypy.interpreter.argument import Arguments
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import specialize
@@ -193,18 +197,59 @@
check_num_args(space, w_args, 0)
return space.wrap(generic_cpy_call(space, func_target, w_self))
+class CPyBuffer(W_Buffer):
+ # Similar to Py_buffer
+
+ def __init__(self, ptr, size, w_obj):
+ self.ptr = ptr
+ self.size = size
+ self.w_obj = w_obj # kept alive
+
+ def getlength(self):
+ return self.size
+
+ def getitem(self, index):
+ return self.ptr[index]
+
+def wrap_getreadbuffer(space, w_self, w_args, func):
+ func_target = rffi.cast(readbufferproc, func)
+ with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
+ index = rffi.cast(Py_ssize_t, 0)
+ size = generic_cpy_call(space, func_target, w_self, index, ptr)
+ if size < 0:
+ space.fromcache(State).check_and_raise_exception(always=True)
+ return space.wrap(CPyBuffer(ptr[0], size, w_self))
+
def get_richcmp_func(OP_CONST):
def inner(space, w_self, w_args, func):
func_target = rffi.cast(richcmpfunc, func)
check_num_args(space, w_args, 1)
- args_w = space.fixedview(w_args)
- other_w = args_w[0]
+ w_other, = space.fixedview(w_args)
return generic_cpy_call(space, func_target,
- w_self, other_w, rffi.cast(rffi.INT_real, OP_CONST))
+ w_self, w_other, rffi.cast(rffi.INT_real, OP_CONST))
return inner
richcmp_eq = get_richcmp_func(Py_EQ)
richcmp_ne = get_richcmp_func(Py_NE)
+richcmp_lt = get_richcmp_func(Py_LT)
+richcmp_le = get_richcmp_func(Py_LE)
+richcmp_gt = get_richcmp_func(Py_GT)
+richcmp_ge = get_richcmp_func(Py_GE)
+
+def wrap_cmpfunc(space, w_self, w_args, func):
+ func_target = rffi.cast(cmpfunc, func)
+ check_num_args(space, w_args, 1)
+ w_other, = space.fixedview(w_args)
+
+ if not space.is_true(space.issubtype(space.type(w_self),
+ space.type(w_other))):
+ raise OperationError(space.w_TypeError, space.wrap(
+ "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'" %
+ (space.type(w_self).getname(space),
+ space.type(w_self).getname(space),
+ space.type(w_other).getname(space))))
+
+ return space.wrap(generic_cpy_call(space, func_target, w_self, w_other))
@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=False)
def slot_tp_new(space, type, w_args, w_kwds):
@@ -466,7 +511,7 @@
"oct(x)"),
UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
"hex(x)"),
- NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
+ NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
"x[y:z] <==> x[y.__index__():z.__index__()]"),
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
wrap_binaryfunc, "+"),
@@ -571,12 +616,19 @@
for regex, repl in slotdef_replacements:
slotdefs_str = re.sub(regex, repl, slotdefs_str)
+slotdefs = eval(slotdefs_str)
+# PyPy addition
+slotdefs += (
+ TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""),
+)
+
slotdefs_for_tp_slots = unrolling_iterable(
[(x.method_name, x.slot_name, x.slot_names, x.slot_func)
- for x in eval(slotdefs_str)])
+ for x in slotdefs])
+
slotdefs_for_wrappers = unrolling_iterable(
[(x.method_name, x.slot_names, x.wrapper_func, x.wrapper_func_kwds, x.doc)
- for x in eval(slotdefs_str)])
+ for x in slotdefs])
if __name__ == "__main__":
print slotdefs_str
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
@@ -154,6 +154,24 @@
self.emit_operation(op)
+ def optimize_INT_LSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+
+ if v2.is_constant() and v2.box.getint() == 0:
+ self.make_equal_to(op.result, v1)
+ else:
+ self.emit_operation(op)
+
+ def optimize_INT_RSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+
+ if v2.is_constant() and v2.box.getint() == 0:
+ self.make_equal_to(op.result, v1)
+ else:
+ self.emit_operation(op)
+
def optimize_CALL_PURE(self, op):
arg_consts = []
for i in range(op.numargs()):
diff --git a/pypy/objspace/std/fake.py b/pypy/objspace/std/fake.py
--- a/pypy/objspace/std/fake.py
+++ b/pypy/objspace/std/fake.py
@@ -151,9 +151,9 @@
class CPythonFakeFrame(eval.Frame):
- def __init__(self, space, code, w_globals=None, numlocals=-1):
+ def __init__(self, space, code, w_globals=None):
self.fakecode = code
- eval.Frame.__init__(self, space, w_globals, numlocals)
+ eval.Frame.__init__(self, space, w_globals)
def getcode(self):
return self.fakecode
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -101,7 +101,7 @@
# first annotate, rtype, and backendoptimize PyPy
try:
- interp, graph = get_interpreter(entry_point, [], backendopt=True,
+ interp, graph = get_interpreter(entry_point, [], backendopt=False,
config=config,
type_system=config.translation.type_system,
policy=PyPyAnnotatorPolicy(space))
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
@@ -8,9 +8,8 @@
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.annlowlevel import llhelper
from pypy.jit.backend.model import CompiledLoopToken
-from pypy.jit.backend.x86.regalloc import (RegAlloc, X86RegisterManager,
- X86XMMRegisterManager, get_ebp_ofs,
- _get_scale)
+from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs,
+ _get_scale, gpr_reg_mgr_cls)
from pypy.jit.backend.x86.arch import (FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD,
IS_X86_32, IS_X86_64)
@@ -78,8 +77,8 @@
self.loop_run_counters = []
self.float_const_neg_addr = 0
self.float_const_abs_addr = 0
- self.malloc_fixedsize_slowpath1 = 0
- self.malloc_fixedsize_slowpath2 = 0
+ self.malloc_slowpath1 = 0
+ self.malloc_slowpath2 = 0
self.memcpy_addr = 0
self.setup_failure_recovery()
self._debug = False
@@ -124,8 +123,8 @@
self._build_failure_recovery(True, withfloats=True)
support.ensure_sse2_floats()
self._build_float_constants()
- if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
- self._build_malloc_fixedsize_slowpath()
+ if gc_ll_descr.get_malloc_slowpath_addr is not None:
+ self._build_malloc_slowpath()
self._build_stack_check_slowpath()
debug_start('jit-backend-counts')
self.set_debug(have_debug_prints())
@@ -133,6 +132,7 @@
def setup(self, looptoken):
assert self.memcpy_addr != 0, "setup_once() not called?"
+ self.current_clt = looptoken.compiled_loop_token
self.pending_guard_tokens = []
self.mc = codebuf.MachineCodeBlockWrapper()
if self.datablockwrapper is None:
@@ -145,6 +145,7 @@
self.mc = None
self.looppos = -1
self.currently_compiling_loop = None
+ self.current_clt = None
def finish_once(self):
if self._debug:
@@ -170,26 +171,47 @@
self.float_const_neg_addr = float_constants
self.float_const_abs_addr = float_constants + 16
- def _build_malloc_fixedsize_slowpath(self):
+ def _build_malloc_slowpath(self):
+ # With asmgcc, we need two helpers, so that we can write two CALL
+ # instructions in assembler, with a mark_gc_roots in between.
+ # With shadowstack, this is not needed, so we produce a single helper.
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ #
# ---------- first helper for the slow path of malloc ----------
mc = codebuf.MachineCodeBlockWrapper()
if self.cpu.supports_floats: # save the XMM registers in
for i in range(self.cpu.NUM_REGS):# the *caller* frame, from esp+8
mc.MOVSD_sx((WORD*2)+8*i, i)
mc.SUB_rr(edx.value, eax.value) # compute the size we want
- if IS_X86_32:
- mc.MOV_sr(WORD, edx.value) # save it as the new argument
- elif IS_X86_64:
- # rdi can be clobbered: its content was forced to the stack
- # by _fastpath_malloc(), like all other save_around_call_regs.
- mc.MOV_rr(edi.value, edx.value)
-
- addr = self.cpu.gc_ll_descr.get_malloc_fixedsize_slowpath_addr()
- mc.JMP(imm(addr)) # tail call to the real malloc
- rawstart = mc.materialize(self.cpu.asmmemmgr, [])
- self.malloc_fixedsize_slowpath1 = rawstart
- # ---------- second helper for the slow path of malloc ----------
- mc = codebuf.MachineCodeBlockWrapper()
+ addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr()
+ #
+ if gcrootmap is not None and gcrootmap.is_shadow_stack:
+ # ---- shadowstack ----
+ for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items():
+ mc.MOV_br(ofs, reg.value)
+ mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes
+ if IS_X86_32:
+ mc.MOV_sr(0, edx.value) # push argument
+ elif IS_X86_64:
+ mc.MOV_rr(edi.value, edx.value)
+ mc.CALL(imm(addr))
+ mc.ADD_ri(esp.value, 16 - WORD)
+ for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items():
+ mc.MOV_rb(reg.value, ofs)
+ else:
+ # ---- asmgcc ----
+ if IS_X86_32:
+ mc.MOV_sr(WORD, edx.value) # save it as the new argument
+ elif IS_X86_64:
+ # rdi can be clobbered: its content was forced to the stack
+ # by _fastpath_malloc(), like all other save_around_call_regs.
+ mc.MOV_rr(edi.value, edx.value)
+ mc.JMP(imm(addr)) # tail call to the real malloc
+ rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+ self.malloc_slowpath1 = rawstart
+ # ---------- second helper for the slow path of malloc ----------
+ mc = codebuf.MachineCodeBlockWrapper()
+ #
if self.cpu.supports_floats: # restore the XMM registers
for i in range(self.cpu.NUM_REGS):# from where they were saved
mc.MOVSD_xs(i, (WORD*2)+8*i)
@@ -197,7 +219,7 @@
mc.MOV(edx, heap(nursery_free_adr)) # load this in EDX
mc.RET()
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
- self.malloc_fixedsize_slowpath2 = rawstart
+ self.malloc_slowpath2 = rawstart
def _build_stack_check_slowpath(self):
_, _, slowpathaddr = self.cpu.insert_stack_check()
@@ -544,7 +566,7 @@
def _get_offset_of_ebp_from_esp(self, allocated_depth):
# Given that [EBP] is where we saved EBP, i.e. in the last word
# of our fixed frame, then the 'words' value is:
- words = (self.cpu.FRAME_FIXED_SIZE - 1) + allocated_depth
+ words = (FRAME_FIXED_SIZE - 1) + allocated_depth
# align, e.g. for Mac OS X
aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
return -WORD * aligned_words
@@ -557,6 +579,10 @@
for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
self.mc.PUSH_r(regloc.value)
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ self._call_header_shadowstack(gcrootmap)
+
def _call_header_with_stack_check(self):
if self.stack_check_slowpath == 0:
pass # no stack check (e.g. not translated)
@@ -578,12 +604,32 @@
def _call_footer(self):
self.mc.LEA_rb(esp.value, -len(self.cpu.CALLEE_SAVE_REGISTERS) * WORD)
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ self._call_footer_shadowstack(gcrootmap)
+
for i in range(len(self.cpu.CALLEE_SAVE_REGISTERS)-1, -1, -1):
self.mc.POP_r(self.cpu.CALLEE_SAVE_REGISTERS[i].value)
self.mc.POP_r(ebp.value)
self.mc.RET()
+ def _call_header_shadowstack(self, gcrootmap):
+ # we need to put two words into the shadowstack: the MARKER
+ # and the address of the frame (ebp, actually)
+ rst = gcrootmap.get_root_stack_top_addr()
+ assert rx86.fits_in_32bits(rst)
+ self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop]
+ self.mc.LEA_rm(edx.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD]
+ self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER
+ self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp
+ self.mc.MOV_jr(rst, edx.value) # MOV [rootstacktop], edx
+
+ def _call_footer_shadowstack(self, gcrootmap):
+ rst = gcrootmap.get_root_stack_top_addr()
+ assert rx86.fits_in_32bits(rst)
+ self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD
+
def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth):
if IS_X86_64:
return self._assemble_bootstrap_direct_call_64(arglocs, jmppos, stackdepth)
@@ -693,8 +739,8 @@
nonfloatlocs, floatlocs = arglocs
self._call_header()
stackadjustpos = self._patchable_stackadjust()
- tmp = X86RegisterManager.all_regs[0]
- xmmtmp = X86XMMRegisterManager.all_regs[0]
+ tmp = eax
+ xmmtmp = xmm0
self.mc.begin_reuse_scratch_register()
for i in range(len(nonfloatlocs)):
loc = nonfloatlocs[i]
@@ -903,9 +949,9 @@
self.implement_guard(guard_token, checkfalsecond)
return genop_cmp_guard_float
- def _emit_call(self, x, arglocs, start=0, tmp=eax):
+ def _emit_call(self, force_index, x, arglocs, start=0, tmp=eax):
if IS_X86_64:
- return self._emit_call_64(x, arglocs, start)
+ return self._emit_call_64(force_index, x, arglocs, start)
p = 0
n = len(arglocs)
@@ -931,9 +977,9 @@
self._regalloc.reserve_param(p//WORD)
# x is a location
self.mc.CALL(x)
- self.mark_gc_roots()
+ self.mark_gc_roots(force_index)
- def _emit_call_64(self, x, arglocs, start=0):
+ def _emit_call_64(self, force_index, x, arglocs, start):
src_locs = []
dst_locs = []
xmm_src_locs = []
@@ -991,12 +1037,27 @@
self._regalloc.reserve_param(len(pass_on_stack))
self.mc.CALL(x)
- self.mark_gc_roots()
+ self.mark_gc_roots(force_index)
def call(self, addr, args, res):
- self._emit_call(imm(addr), args)
+ force_index = self.write_new_force_index()
+ self._emit_call(force_index, imm(addr), args)
assert res is eax
+ def write_new_force_index(self):
+ # for shadowstack only: get a new, unused force_index number and
+ # write it to FORCE_INDEX_OFS. Used to record the call shape
+ # (i.e. where the GC pointers are in the stack) around a CALL
+ # instruction that doesn't already have a force_index.
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ clt = self.current_clt
+ force_index = clt.reserve_and_record_some_faildescr_index()
+ self.mc.MOV_bi(FORCE_INDEX_OFS, force_index)
+ return force_index
+ else:
+ return 0
+
genop_int_neg = _unaryop("NEG")
genop_int_invert = _unaryop("NOT")
genop_int_add = _binaryop("ADD", True)
@@ -1212,6 +1273,11 @@
assert isinstance(loc_vtable, ImmedLoc)
self.mc.MOV(mem(loc, self.cpu.vtable_offset), loc_vtable)
+ def set_new_array_length(self, loc, ofs_length, loc_num_elem):
+ assert isinstance(loc, RegLoc)
+ assert isinstance(loc_num_elem, ImmedLoc)
+ self.mc.MOV(mem(loc, ofs_length), loc_num_elem)
+
# XXX genop_new is abused for all varsized mallocs with Boehm, for now
# (instead of genop_new_array, genop_newstr, genop_newunicode)
def genop_new(self, op, arglocs, result_loc):
@@ -1790,6 +1856,10 @@
self.pending_guard_tokens.append(guard_token)
def genop_call(self, op, arglocs, resloc):
+ force_index = self.write_new_force_index()
+ self._genop_call(op, arglocs, resloc, force_index)
+
+ def _genop_call(self, op, arglocs, resloc, force_index):
sizeloc = arglocs[0]
assert isinstance(sizeloc, ImmedLoc)
size = sizeloc.value
@@ -1803,8 +1873,8 @@
tmp = ecx
else:
tmp = eax
-
- self._emit_call(x, arglocs, 3, tmp=tmp)
+
+ self._emit_call(force_index, x, arglocs, 3, tmp=tmp)
if IS_X86_32 and isinstance(resloc, StackLoc) and resloc.width == 8:
# a float or a long long return
@@ -1835,7 +1905,7 @@
faildescr = guard_op.getdescr()
fail_index = self.cpu.get_fail_descr_number(faildescr)
self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index)
- self.genop_call(op, arglocs, result_loc)
+ self._genop_call(op, arglocs, result_loc, fail_index)
self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
self.implement_guard(guard_token, 'L')
@@ -1849,8 +1919,8 @@
assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
#
# Write a call to the direct_bootstrap_code of the target assembler
- self._emit_call(imm(descr._x86_direct_bootstrap_code), arglocs, 2,
- tmp=eax)
+ self._emit_call(fail_index, imm(descr._x86_direct_bootstrap_code),
+ arglocs, 2, tmp=eax)
if op.result is None:
assert result_loc is None
value = self.cpu.done_with_this_frame_void_v
@@ -1875,7 +1945,7 @@
jd = descr.outermost_jitdriver_sd
assert jd is not None
asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr)
- self._emit_call(imm(asm_helper_adr), [eax, arglocs[1]], 0,
+ self._emit_call(fail_index, imm(asm_helper_adr), [eax, arglocs[1]], 0,
tmp=ecx)
if IS_X86_32 and isinstance(result_loc, StackLoc) and result_loc.type == FLOAT:
self.mc.FSTP_b(result_loc.value)
@@ -1902,7 +1972,7 @@
# load the return value from fail_boxes_xxx[0]
kind = op.result.type
if kind == FLOAT:
- xmmtmp = X86XMMRegisterManager.all_regs[0]
+ xmmtmp = xmm0
adr = self.fail_boxes_float.get_addr_for_num(0)
self.mc.MOVSD(xmmtmp, heap(adr))
self.mc.MOVSD(result_loc, xmmtmp)
@@ -1997,11 +2067,16 @@
not_implemented("not implemented operation (guard): %s" %
op.getopname())
- def mark_gc_roots(self):
+ def mark_gc_roots(self, force_index, use_copy_area=False):
+ if force_index < 0:
+ return # not needed
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap:
- mark = self._regalloc.get_mark_gc_roots(gcrootmap)
- self.mc.insert_gcroot_marker(mark)
+ mark = self._regalloc.get_mark_gc_roots(gcrootmap, use_copy_area)
+ if gcrootmap.is_shadow_stack:
+ gcrootmap.write_callshape(mark, force_index)
+ else:
+ self.mc.insert_gcroot_marker(mark)
def target_arglocs(self, loop_token):
return loop_token._x86_arglocs
@@ -2013,8 +2088,7 @@
else:
self.mc.JMP(imm(loop_token._x86_loop_code))
- def malloc_cond_fixedsize(self, nursery_free_adr, nursery_top_adr,
- size, tid):
+ def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, tid):
size = max(size, self.cpu.gc_ll_descr.minimal_size_in_nursery)
self.mc.MOV(eax, heap(nursery_free_adr))
self.mc.LEA_rm(edx.value, (eax.value, size))
@@ -2022,7 +2096,7 @@
self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
jmp_adr = self.mc.get_relative_pos()
- # See comments in _build_malloc_fixedsize_slowpath for the
+ # See comments in _build_malloc_slowpath for the
# details of the two helper functions that we are calling below.
# First, we need to call two of them and not just one because we
# need to have a mark_gc_roots() in between. Then the calling
@@ -2032,19 +2106,27 @@
# result in EAX; slowpath_addr2 additionally returns in EDX a
# copy of heap(nursery_free_adr), so that the final MOV below is
# a no-op.
- slowpath_addr1 = self.malloc_fixedsize_slowpath1
+
# reserve room for the argument to the real malloc and the
# 8 saved XMM regs
self._regalloc.reserve_param(1+16)
- self.mc.CALL(imm(slowpath_addr1))
- self.mark_gc_roots()
- slowpath_addr2 = self.malloc_fixedsize_slowpath2
+
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack)
+ if not shadow_stack:
+ # there are two helpers to call only with asmgcc
+ slowpath_addr1 = self.malloc_slowpath1
+ self.mc.CALL(imm(slowpath_addr1))
+ self.mark_gc_roots(self.write_new_force_index(),
+ use_copy_area=shadow_stack)
+ slowpath_addr2 = self.malloc_slowpath2
self.mc.CALL(imm(slowpath_addr2))
offset = self.mc.get_relative_pos() - jmp_adr
assert 0 < offset <= 127
self.mc.overwrite(jmp_adr-1, chr(offset))
# on 64-bits, 'tid' is a value that fits in 31 bits
+ assert rx86.fits_in_32bits(tid)
self.mc.MOV_mi((eax.value, 0), tid)
self.mc.MOV(heap(nursery_free_adr), edx)
diff --git a/pypy/module/cpyext/include/traceback.h b/pypy/module/cpyext/include/traceback.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/traceback.h
@@ -0,0 +1,12 @@
+#ifndef Py_TRACEBACK_H
+#define Py_TRACEBACK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyTracebackObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_TRACEBACK_H */
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver
from pypy.rlib.objectmodel import compute_hash
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp import history
More information about the Pypy-commit
mailing list