Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 1 addition & 44 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
import types
import unittest
from test.support import (captured_stdout, requires_debug_ranges,
requires_specialization, requires_specialization_ft,
cpython_only)
requires_specialization, cpython_only)
from test.support.bytecode_helper import BytecodeTestCase

import opcode
Expand Down Expand Up @@ -1261,27 +1260,6 @@ def test_super_instructions(self):
got = self.get_disassembly(load_test, adaptive=True)
self.do_disassembly_compare(got, dis_load_test_quickened_code)

@cpython_only
@requires_specialization_ft
def test_binary_specialize(self):
binary_op_quicken = """\
0 RESUME_CHECK 0

1 LOAD_NAME 0 (a)
LOAD_NAME 1 (b)
%s
RETURN_VALUE
"""
co_int = compile('a + b', "<int>", "eval")
self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2}))
got = self.get_disassembly(co_int, adaptive=True)
self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_INT 0 (+)")

co_unicode = compile('a + b', "<unicode>", "eval")
self.code_quicken(lambda: exec(co_unicode, {}, {'a': 'a', 'b': 'b'}))
got = self.get_disassembly(co_unicode, adaptive=True)
self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)")

@cpython_only
@requires_specialization
def test_binary_subscr_specialize(self):
Expand Down Expand Up @@ -1335,27 +1313,6 @@ def test_call_specialize(self):
got = self.get_disassembly(co, adaptive=True)
self.do_disassembly_compare(got, call_quicken)

@cpython_only
@requires_specialization_ft
def test_contains_specialize(self):
contains_op_quicken = """\
0 RESUME_CHECK 0

1 LOAD_NAME 0 (a)
LOAD_NAME 1 (b)
%s
RETURN_VALUE
"""
co_dict = compile('a in b', "<dict>", "eval")
self.code_quicken(lambda: exec(co_dict, {}, {'a': 1, 'b': {1: 5}}))
got = self.get_disassembly(co_dict, adaptive=True)
self.do_disassembly_compare(got, contains_op_quicken % "CONTAINS_OP_DICT 0 (in)")

co_set = compile('a in b', "<set>", "eval")
self.code_quicken(lambda: exec(co_set, {}, {'a': 1.0, 'b': {1, 2, 3}}))
got = self.get_disassembly(co_set, adaptive=True)
self.do_disassembly_compare(got, contains_op_quicken % "CONTAINS_OP_SET 0 (in)")

@cpython_only
@requires_specialization
def test_loop_quicken(self):
Expand Down
59 changes: 58 additions & 1 deletion Lib/test/test_opcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import threading
import types
import unittest
from test.support import threading_helper, check_impl_detail, requires_specialization
from test.support import (threading_helper, check_impl_detail,
requires_specialization, requires_specialization_ft,
cpython_only)
from test.support.import_helper import import_module

# Skip this module on other interpreters, it is cpython specific:
Expand Down Expand Up @@ -34,6 +36,11 @@ def assert_specialized(self, f, opname):
opnames = {instruction.opname for instruction in instructions}
self.assertIn(opname, opnames)

def assert_no_opcode(self, f, opname):
instructions = dis.get_instructions(f, adaptive=True)
opnames = {instruction.opname for instruction in instructions}
self.assertNotIn(opname, opnames)


class TestLoadSuperAttrCache(unittest.TestCase):
def test_descriptor_not_double_executed_on_spec_fail(self):
Expand Down Expand Up @@ -1200,5 +1207,55 @@ def f(o, n):
self.assertEqual(test_obj.b, 0)


class TestSpecializer(TestBase):

@cpython_only
@requires_specialization_ft
def test_binary_op(self):
def f():
for _ in range(100):
a, b = 1, 2
c = a + b
self.assertEqual(c, 3)

f()
self.assert_specialized(f, "BINARY_OP_ADD_INT")
self.assert_no_opcode(f, "BINARY_OP")

def g():
for _ in range(100):
a, b = "foo", "bar"
c = a + b
self.assertEqual(c, "foobar")

g()
self.assert_specialized(g, "BINARY_OP_ADD_UNICODE")
self.assert_no_opcode(g, "BINARY_OP")

@cpython_only
@requires_specialization_ft
def test_contain_op(self):
def f():
for _ in range(100):
a, b = 1, {1: 2, 2: 5}
self.assertTrue(a in b)
self.assertFalse(3 in b)

f()
self.assert_specialized(f, "CONTAINS_OP_DICT")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, if the opcodes become more complex, we may need to count how many specific opcodes have occurred.

self.assert_no_opcode(f, "CONTAINS_OP")

def g():
for _ in range(100):
a, b = 1, {1, 2}
self.assertTrue(a in b)
self.assertFalse(3 in b)

g()
self.assert_specialized(g, "CONTAINS_OP_SET")
self.assert_no_opcode(g, "CONTAINS_OP")



if __name__ == "__main__":
unittest.main()
Loading