Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-115999: Move specializer test from test_dis to test_opcache #126498

Merged
merged 3 commits into from
Nov 6, 2024
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