bpo-46841: Use *inline* caching for `BINARY_OP` (GH-31543)

This commit is contained in:
Brandt Bucher 2022-02-25 04:11:34 -08:00 committed by GitHub
parent 18b5dd68c6
commit 0f41aac109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 429 additions and 351 deletions

View File

@ -24,6 +24,12 @@ interpreter.
Use 2 bytes for each instruction. Previously the number of bytes varied Use 2 bytes for each instruction. Previously the number of bytes varied
by instruction. by instruction.
.. versionchanged:: 3.11
Some instructions are accompanied by one or more inline cache entries,
which take the form of :opcode:`CACHE` instructions. These instructions
are hidden by default, but can be shown by passing ``show_caches=True`` to
any :mod:`dis` utility.
Example: Given the function :func:`myfunc`:: Example: Given the function :func:`myfunc`::
@ -54,7 +60,7 @@ The bytecode analysis API allows pieces of Python code to be wrapped in a
:class:`Bytecode` object that provides easy access to details of the compiled :class:`Bytecode` object that provides easy access to details of the compiled
code. code.
.. class:: Bytecode(x, *, first_line=None, current_offset=None) .. class:: Bytecode(x, *, first_line=None, current_offset=None, show_caches=False)
Analyse the bytecode corresponding to a function, generator, asynchronous Analyse the bytecode corresponding to a function, generator, asynchronous
@ -74,7 +80,7 @@ code.
disassembled code. Setting this means :meth:`.dis` will display a "current disassembled code. Setting this means :meth:`.dis` will display a "current
instruction" marker against the specified opcode. instruction" marker against the specified opcode.
.. classmethod:: from_traceback(tb) .. classmethod:: from_traceback(tb, *, show_caches=False)
Construct a :class:`Bytecode` instance from the given traceback, setting Construct a :class:`Bytecode` instance from the given traceback, setting
*current_offset* to the instruction responsible for the exception. *current_offset* to the instruction responsible for the exception.
@ -100,6 +106,9 @@ code.
.. versionchanged:: 3.7 .. versionchanged:: 3.7
This can now handle coroutine and asynchronous generator objects. This can now handle coroutine and asynchronous generator objects.
.. versionchanged:: 3.11
Added the ``show_caches`` parameter.
Example:: Example::
>>> bytecode = dis.Bytecode(myfunc) >>> bytecode = dis.Bytecode(myfunc)
@ -153,7 +162,7 @@ operation is being performed, so the intermediate analysis object isn't useful:
Added *file* parameter. Added *file* parameter.
.. function:: dis(x=None, *, file=None, depth=None) .. function:: dis(x=None, *, file=None, depth=None, show_caches=False)
Disassemble the *x* object. *x* can denote either a module, a class, a Disassemble the *x* object. *x* can denote either a module, a class, a
method, a function, a generator, an asynchronous generator, a coroutine, method, a function, a generator, an asynchronous generator, a coroutine,
@ -183,8 +192,11 @@ operation is being performed, so the intermediate analysis object isn't useful:
.. versionchanged:: 3.7 .. versionchanged:: 3.7
This can now handle coroutine and asynchronous generator objects. This can now handle coroutine and asynchronous generator objects.
.. versionchanged:: 3.11
Added the ``show_caches`` parameter.
.. function:: distb(tb=None, *, file=None)
.. function:: distb(tb=None, *, file=None, show_caches=False)
Disassemble the top-of-stack function of a traceback, using the last Disassemble the top-of-stack function of a traceback, using the last
traceback if none was passed. The instruction causing the exception is traceback if none was passed. The instruction causing the exception is
@ -196,9 +208,12 @@ operation is being performed, so the intermediate analysis object isn't useful:
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Added *file* parameter. Added *file* parameter.
.. versionchanged:: 3.11
Added the ``show_caches`` parameter.
.. function:: disassemble(code, lasti=-1, *, file=None)
disco(code, lasti=-1, *, file=None) .. function:: disassemble(code, lasti=-1, *, file=None, show_caches=False)
disco(code, lasti=-1, *, file=None, show_caches=False)
Disassemble a code object, indicating the last instruction if *lasti* was Disassemble a code object, indicating the last instruction if *lasti* was
provided. The output is divided in the following columns: provided. The output is divided in the following columns:
@ -220,8 +235,11 @@ operation is being performed, so the intermediate analysis object isn't useful:
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Added *file* parameter. Added *file* parameter.
.. versionchanged:: 3.11
Added the ``show_caches`` parameter.
.. function:: get_instructions(x, *, first_line=None)
.. function:: get_instructions(x, *, first_line=None, show_caches=False)
Return an iterator over the instructions in the supplied function, method, Return an iterator over the instructions in the supplied function, method,
source code string or code object. source code string or code object.
@ -236,6 +254,9 @@ operation is being performed, so the intermediate analysis object isn't useful:
.. versionadded:: 3.4 .. versionadded:: 3.4
.. versionchanged:: 3.11
Added the ``show_caches`` parameter.
.. function:: findlinestarts(code) .. function:: findlinestarts(code)

View File

@ -5,7 +5,7 @@
/* Each instruction in a code object is a fixed-width value, /* Each instruction in a code object is a fixed-width value,
* currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG * currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG
* opcode allows for larger values but the current limit is 3 uses * opcode allows for larger values but the current limit is 3 uses
* of EXTENDED_ARG (see Python/wordcode_helpers.h), for a maximum * of EXTENDED_ARG (see Python/compile.c), for a maximum
* 32-bit value. This aligns with the note in Python/compile.c * 32-bit value. This aligns with the note in Python/compile.c
* (compiler_addop_i_line) indicating that the max oparg value is * (compiler_addop_i_line) indicating that the max oparg value is
* 2**32 - 1, rather than INT_MAX. * 2**32 - 1, rather than INT_MAX.

View File

@ -64,6 +64,13 @@ typedef union {
#define INSTRUCTIONS_PER_ENTRY (sizeof(SpecializedCacheEntry)/sizeof(_Py_CODEUNIT)) #define INSTRUCTIONS_PER_ENTRY (sizeof(SpecializedCacheEntry)/sizeof(_Py_CODEUNIT))
typedef struct {
_Py_CODEUNIT counter;
} _PyBinaryOpCache;
#define INLINE_CACHE_ENTRIES_BINARY_OP \
(sizeof(_PyBinaryOpCache) / sizeof(_Py_CODEUNIT))
/* Maximum size of code to quicken, in code units. */ /* Maximum size of code to quicken, in code units. */
#define MAX_SIZE_TO_QUICKEN 5000 #define MAX_SIZE_TO_QUICKEN 5000
@ -276,7 +283,7 @@ int _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
int _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr, int nargs, int _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames, SpecializedCacheEntry *cache, PyObject *builtins); PyObject *kwnames, SpecializedCacheEntry *cache, PyObject *builtins);
void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache); int oparg);
void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache); SpecializedCacheEntry *cache);

145
Include/opcode.h generated
View File

@ -9,6 +9,7 @@ extern "C" {
/* Instruction opcodes for compiled code */ /* Instruction opcodes for compiled code */
#define POP_TOP 1 #define POP_TOP 1
#define PUSH_NULL 2 #define PUSH_NULL 2
#define CACHE 3
#define NOP 9 #define NOP 9
#define UNARY_POSITIVE 10 #define UNARY_POSITIVE 10
#define UNARY_NEGATIVE 11 #define UNARY_NEGATIVE 11
@ -113,76 +114,76 @@ extern "C" {
#define PRECALL 166 #define PRECALL 166
#define CALL 171 #define CALL 171
#define KW_NAMES 172 #define KW_NAMES 172
#define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADAPTIVE 4
#define BINARY_OP_ADD_INT 4 #define BINARY_OP_ADD_INT 5
#define BINARY_OP_ADD_FLOAT 5 #define BINARY_OP_ADD_FLOAT 6
#define BINARY_OP_ADD_UNICODE 6 #define BINARY_OP_ADD_UNICODE 7
#define BINARY_OP_INPLACE_ADD_UNICODE 7 #define BINARY_OP_INPLACE_ADD_UNICODE 8
#define BINARY_OP_MULTIPLY_INT 8 #define BINARY_OP_MULTIPLY_INT 13
#define BINARY_OP_MULTIPLY_FLOAT 13 #define BINARY_OP_MULTIPLY_FLOAT 14
#define BINARY_OP_SUBTRACT_INT 14 #define BINARY_OP_SUBTRACT_INT 16
#define BINARY_OP_SUBTRACT_FLOAT 16 #define BINARY_OP_SUBTRACT_FLOAT 17
#define COMPARE_OP_ADAPTIVE 17 #define COMPARE_OP_ADAPTIVE 18
#define COMPARE_OP_FLOAT_JUMP 18 #define COMPARE_OP_FLOAT_JUMP 19
#define COMPARE_OP_INT_JUMP 19 #define COMPARE_OP_INT_JUMP 20
#define COMPARE_OP_STR_JUMP 20 #define COMPARE_OP_STR_JUMP 21
#define BINARY_SUBSCR_ADAPTIVE 21 #define BINARY_SUBSCR_ADAPTIVE 22
#define BINARY_SUBSCR_GETITEM 22 #define BINARY_SUBSCR_GETITEM 23
#define BINARY_SUBSCR_LIST_INT 23 #define BINARY_SUBSCR_LIST_INT 24
#define BINARY_SUBSCR_TUPLE_INT 24 #define BINARY_SUBSCR_TUPLE_INT 26
#define BINARY_SUBSCR_DICT 26 #define BINARY_SUBSCR_DICT 27
#define STORE_SUBSCR_ADAPTIVE 27 #define STORE_SUBSCR_ADAPTIVE 28
#define STORE_SUBSCR_LIST_INT 28 #define STORE_SUBSCR_LIST_INT 29
#define STORE_SUBSCR_DICT 29 #define STORE_SUBSCR_DICT 34
#define CALL_ADAPTIVE 34 #define CALL_ADAPTIVE 36
#define CALL_PY_EXACT_ARGS 36 #define CALL_PY_EXACT_ARGS 37
#define CALL_PY_WITH_DEFAULTS 37 #define CALL_PY_WITH_DEFAULTS 38
#define JUMP_ABSOLUTE_QUICK 38 #define JUMP_ABSOLUTE_QUICK 39
#define LOAD_ATTR_ADAPTIVE 39 #define LOAD_ATTR_ADAPTIVE 40
#define LOAD_ATTR_INSTANCE_VALUE 40 #define LOAD_ATTR_INSTANCE_VALUE 41
#define LOAD_ATTR_WITH_HINT 41 #define LOAD_ATTR_WITH_HINT 42
#define LOAD_ATTR_SLOT 42 #define LOAD_ATTR_SLOT 43
#define LOAD_ATTR_MODULE 43 #define LOAD_ATTR_MODULE 44
#define LOAD_GLOBAL_ADAPTIVE 44 #define LOAD_GLOBAL_ADAPTIVE 45
#define LOAD_GLOBAL_MODULE 45 #define LOAD_GLOBAL_MODULE 46
#define LOAD_GLOBAL_BUILTIN 46 #define LOAD_GLOBAL_BUILTIN 47
#define LOAD_METHOD_ADAPTIVE 47 #define LOAD_METHOD_ADAPTIVE 48
#define LOAD_METHOD_CLASS 48 #define LOAD_METHOD_CLASS 55
#define LOAD_METHOD_MODULE 55 #define LOAD_METHOD_MODULE 56
#define LOAD_METHOD_NO_DICT 56 #define LOAD_METHOD_NO_DICT 57
#define LOAD_METHOD_WITH_DICT 57 #define LOAD_METHOD_WITH_DICT 58
#define LOAD_METHOD_WITH_VALUES 58 #define LOAD_METHOD_WITH_VALUES 59
#define PRECALL_ADAPTIVE 59 #define PRECALL_ADAPTIVE 62
#define PRECALL_BUILTIN_CLASS 62 #define PRECALL_BUILTIN_CLASS 63
#define PRECALL_NO_KW_BUILTIN_O 63 #define PRECALL_NO_KW_BUILTIN_O 64
#define PRECALL_NO_KW_BUILTIN_FAST 64 #define PRECALL_NO_KW_BUILTIN_FAST 65
#define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 65 #define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 66
#define PRECALL_NO_KW_LEN 66 #define PRECALL_NO_KW_LEN 67
#define PRECALL_NO_KW_ISINSTANCE 67 #define PRECALL_NO_KW_ISINSTANCE 72
#define PRECALL_NO_KW_LIST_APPEND 72 #define PRECALL_NO_KW_LIST_APPEND 76
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 76 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 77
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 77 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 78
#define PRECALL_NO_KW_STR_1 78 #define PRECALL_NO_KW_STR_1 79
#define PRECALL_NO_KW_TUPLE_1 79 #define PRECALL_NO_KW_TUPLE_1 80
#define PRECALL_NO_KW_TYPE_1 80 #define PRECALL_NO_KW_TYPE_1 81
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 81 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 131
#define PRECALL_BOUND_METHOD 131 #define PRECALL_BOUND_METHOD 140
#define PRECALL_PYFUNC 140 #define PRECALL_PYFUNC 141
#define RESUME_QUICK 141 #define RESUME_QUICK 143
#define STORE_ATTR_ADAPTIVE 143 #define STORE_ATTR_ADAPTIVE 150
#define STORE_ATTR_INSTANCE_VALUE 150 #define STORE_ATTR_INSTANCE_VALUE 153
#define STORE_ATTR_SLOT 153 #define STORE_ATTR_SLOT 154
#define STORE_ATTR_WITH_HINT 154 #define STORE_ATTR_WITH_HINT 158
#define UNPACK_SEQUENCE_ADAPTIVE 158 #define UNPACK_SEQUENCE_ADAPTIVE 159
#define UNPACK_SEQUENCE_LIST 159 #define UNPACK_SEQUENCE_LIST 161
#define UNPACK_SEQUENCE_TUPLE 161 #define UNPACK_SEQUENCE_TUPLE 167
#define UNPACK_SEQUENCE_TWO_TUPLE 167 #define UNPACK_SEQUENCE_TWO_TUPLE 168
#define LOAD_FAST__LOAD_FAST 168 #define LOAD_FAST__LOAD_FAST 169
#define STORE_FAST__LOAD_FAST 169 #define STORE_FAST__LOAD_FAST 170
#define LOAD_FAST__LOAD_CONST 170 #define LOAD_FAST__LOAD_CONST 173
#define LOAD_CONST__LOAD_FAST 173 #define LOAD_CONST__LOAD_FAST 174
#define STORE_FAST__STORE_FAST 174 #define STORE_FAST__STORE_FAST 175
#define LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE 175 #define LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE 176
#define DO_TRACING 255 #define DO_TRACING 255
#ifdef NEED_OPCODE_JUMP_TABLES #ifdef NEED_OPCODE_JUMP_TABLES
static uint32_t _PyOpcode_RelativeJump[8] = { static uint32_t _PyOpcode_RelativeJump[8] = {
@ -239,6 +240,10 @@ static uint32_t _PyOpcode_Jump[8] = {
#define NB_INPLACE_TRUE_DIVIDE 24 #define NB_INPLACE_TRUE_DIVIDE 24
#define NB_INPLACE_XOR 25 #define NB_INPLACE_XOR 25
static const uint8_t _PyOpcode_InlineCacheEntries[256] = {
[BINARY_OP] = 1,
};
#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) #define HAS_ARG(op) ((op) >= HAVE_ARGUMENT)
/* Reserve some bytecodes for internal use in the compiler. /* Reserve some bytecodes for internal use in the compiler.

View File

@ -30,6 +30,8 @@ MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')
LOAD_CONST = opmap['LOAD_CONST'] LOAD_CONST = opmap['LOAD_CONST']
BINARY_OP = opmap['BINARY_OP'] BINARY_OP = opmap['BINARY_OP']
CACHE = opmap["CACHE"]
def _try_compile(source, name): def _try_compile(source, name):
"""Attempts to compile the given source, first as an expression and """Attempts to compile the given source, first as an expression and
then as a statement if the first approach fails. then as a statement if the first approach fails.
@ -43,7 +45,7 @@ def _try_compile(source, name):
c = compile(source, name, 'exec') c = compile(source, name, 'exec')
return c return c
def dis(x=None, *, file=None, depth=None): def dis(x=None, *, file=None, depth=None, show_caches=False):
"""Disassemble classes, methods, functions, and other compiled objects. """Disassemble classes, methods, functions, and other compiled objects.
With no argument, disassemble the last traceback. With no argument, disassemble the last traceback.
@ -53,7 +55,7 @@ def dis(x=None, *, file=None, depth=None):
in a special attribute. in a special attribute.
""" """
if x is None: if x is None:
distb(file=file) distb(file=file, show_caches=show_caches)
return return
# Extract functions from methods. # Extract functions from methods.
if hasattr(x, '__func__'): if hasattr(x, '__func__'):
@ -74,21 +76,21 @@ def dis(x=None, *, file=None, depth=None):
if isinstance(x1, _have_code): if isinstance(x1, _have_code):
print("Disassembly of %s:" % name, file=file) print("Disassembly of %s:" % name, file=file)
try: try:
dis(x1, file=file, depth=depth) dis(x1, file=file, depth=depth, show_caches=show_caches)
except TypeError as msg: except TypeError as msg:
print("Sorry:", msg, file=file) print("Sorry:", msg, file=file)
print(file=file) print(file=file)
elif hasattr(x, 'co_code'): # Code object elif hasattr(x, 'co_code'): # Code object
_disassemble_recursive(x, file=file, depth=depth) _disassemble_recursive(x, file=file, depth=depth, show_caches=show_caches)
elif isinstance(x, (bytes, bytearray)): # Raw bytecode elif isinstance(x, (bytes, bytearray)): # Raw bytecode
_disassemble_bytes(x, file=file) _disassemble_bytes(x, file=file, show_caches=show_caches)
elif isinstance(x, str): # Source code elif isinstance(x, str): # Source code
_disassemble_str(x, file=file, depth=depth) _disassemble_str(x, file=file, depth=depth, show_caches=show_caches)
else: else:
raise TypeError("don't know how to disassemble %s objects" % raise TypeError("don't know how to disassemble %s objects" %
type(x).__name__) type(x).__name__)
def distb(tb=None, *, file=None): def distb(tb=None, *, file=None, show_caches=False):
"""Disassemble a traceback (default: last traceback).""" """Disassemble a traceback (default: last traceback)."""
if tb is None: if tb is None:
try: try:
@ -96,7 +98,7 @@ def distb(tb=None, *, file=None):
except AttributeError: except AttributeError:
raise RuntimeError("no last traceback to disassemble") from None raise RuntimeError("no last traceback to disassemble") from None
while tb.tb_next: tb = tb.tb_next while tb.tb_next: tb = tb.tb_next
disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file) disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file, show_caches=show_caches)
# The inspect module interrogates this dictionary to build its # The inspect module interrogates this dictionary to build its
# list of CO_* constants. It is also used by pretty_flags to # list of CO_* constants. It is also used by pretty_flags to
@ -298,7 +300,7 @@ class Instruction(_Instruction):
return ' '.join(fields).rstrip() return ' '.join(fields).rstrip()
def get_instructions(x, *, first_line=None): def get_instructions(x, *, first_line=None, show_caches=False):
"""Iterator for the opcodes in methods, functions or code """Iterator for the opcodes in methods, functions or code
Generates a series of Instruction named tuples giving the details of Generates a series of Instruction named tuples giving the details of
@ -318,7 +320,9 @@ def get_instructions(x, *, first_line=None):
return _get_instructions_bytes(co.co_code, return _get_instructions_bytes(co.co_code,
co._varname_from_oparg, co._varname_from_oparg,
co.co_names, co.co_consts, co.co_names, co.co_consts,
linestarts, line_offset, co_positions=co.co_positions()) linestarts, line_offset,
co_positions=co.co_positions(),
show_caches=show_caches)
def _get_const_value(op, arg, co_consts): def _get_const_value(op, arg, co_consts):
"""Helper to get the value of the const in a hasconst op. """Helper to get the value of the const in a hasconst op.
@ -389,7 +393,8 @@ def parse_exception_table(code):
def _get_instructions_bytes(code, varname_from_oparg=None, def _get_instructions_bytes(code, varname_from_oparg=None,
names=None, co_consts=None, names=None, co_consts=None,
linestarts=None, line_offset=0, linestarts=None, line_offset=0,
exception_entries=(), co_positions=None): exception_entries=(), co_positions=None,
show_caches=False):
"""Iterate over the instructions in a bytecode string. """Iterate over the instructions in a bytecode string.
Generates a sequence of Instruction namedtuples giving the details of each Generates a sequence of Instruction namedtuples giving the details of each
@ -406,6 +411,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
labels.add(target) labels.add(target)
starts_line = None starts_line = None
for offset, op, arg in _unpack_opargs(code): for offset, op, arg in _unpack_opargs(code):
if not show_caches and op == CACHE:
continue
if linestarts is not None: if linestarts is not None:
starts_line = linestarts.get(offset, None) starts_line = linestarts.get(offset, None)
if starts_line is not None: if starts_line is not None:
@ -451,17 +458,18 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
arg, argval, argrepr, arg, argval, argrepr,
offset, starts_line, is_jump_target, positions) offset, starts_line, is_jump_target, positions)
def disassemble(co, lasti=-1, *, file=None): def disassemble(co, lasti=-1, *, file=None, show_caches=False):
"""Disassemble a code object.""" """Disassemble a code object."""
linestarts = dict(findlinestarts(co)) linestarts = dict(findlinestarts(co))
exception_entries = parse_exception_table(co) exception_entries = parse_exception_table(co)
_disassemble_bytes(co.co_code, lasti, _disassemble_bytes(co.co_code, lasti,
co._varname_from_oparg, co._varname_from_oparg,
co.co_names, co.co_consts, linestarts, file=file, co.co_names, co.co_consts, linestarts, file=file,
exception_entries=exception_entries, co_positions=co.co_positions()) exception_entries=exception_entries,
co_positions=co.co_positions(), show_caches=show_caches)
def _disassemble_recursive(co, *, file=None, depth=None): def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False):
disassemble(co, file=file) disassemble(co, file=file, show_caches=show_caches)
if depth is None or depth > 0: if depth is None or depth > 0:
if depth is not None: if depth is not None:
depth = depth - 1 depth = depth - 1
@ -469,12 +477,14 @@ def _disassemble_recursive(co, *, file=None, depth=None):
if hasattr(x, 'co_code'): if hasattr(x, 'co_code'):
print(file=file) print(file=file)
print("Disassembly of %r:" % (x,), file=file) print("Disassembly of %r:" % (x,), file=file)
_disassemble_recursive(x, file=file, depth=depth) _disassemble_recursive(
x, file=file, depth=depth, show_caches=show_caches
)
def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
names=None, co_consts=None, linestarts=None, names=None, co_consts=None, linestarts=None,
*, file=None, line_offset=0, exception_entries=(), *, file=None, line_offset=0, exception_entries=(),
co_positions=None): co_positions=None, show_caches=False):
# Omit the line number column entirely if we have no line number info # Omit the line number column entirely if we have no line number info
show_lineno = bool(linestarts) show_lineno = bool(linestarts)
if show_lineno: if show_lineno:
@ -492,8 +502,10 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
offset_width = 4 offset_width = 4
for instr in _get_instructions_bytes(code, varname_from_oparg, names, for instr in _get_instructions_bytes(code, varname_from_oparg, names,
co_consts, linestarts, co_consts, linestarts,
line_offset=line_offset, exception_entries=exception_entries, line_offset=line_offset,
co_positions=co_positions): exception_entries=exception_entries,
co_positions=co_positions,
show_caches=show_caches):
new_source_line = (show_lineno and new_source_line = (show_lineno and
instr.starts_line is not None and instr.starts_line is not None and
instr.offset > 0) instr.offset > 0)
@ -616,7 +628,7 @@ class Bytecode:
Iterating over this yields the bytecode operations as Instruction instances. Iterating over this yields the bytecode operations as Instruction instances.
""" """
def __init__(self, x, *, first_line=None, current_offset=None): def __init__(self, x, *, first_line=None, current_offset=None, show_caches=False):
self.codeobj = co = _get_code_object(x) self.codeobj = co = _get_code_object(x)
if first_line is None: if first_line is None:
self.first_line = co.co_firstlineno self.first_line = co.co_firstlineno
@ -628,6 +640,7 @@ class Bytecode:
self._original_object = x self._original_object = x
self.current_offset = current_offset self.current_offset = current_offset
self.exception_entries = parse_exception_table(co) self.exception_entries = parse_exception_table(co)
self.show_caches = show_caches
def __iter__(self): def __iter__(self):
co = self.codeobj co = self.codeobj
@ -637,18 +650,21 @@ class Bytecode:
self._linestarts, self._linestarts,
line_offset=self._line_offset, line_offset=self._line_offset,
exception_entries=self.exception_entries, exception_entries=self.exception_entries,
co_positions=co.co_positions()) co_positions=co.co_positions(),
show_caches=self.show_caches)
def __repr__(self): def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, return "{}({!r})".format(self.__class__.__name__,
self._original_object) self._original_object)
@classmethod @classmethod
def from_traceback(cls, tb): def from_traceback(cls, tb, *, show_caches=False):
""" Construct a Bytecode from the given traceback """ """ Construct a Bytecode from the given traceback """
while tb.tb_next: while tb.tb_next:
tb = tb.tb_next tb = tb.tb_next
return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti) return cls(
tb.tb_frame.f_code, current_offset=tb.tb_lasti, show_caches=show_caches
)
def info(self): def info(self):
"""Return formatted information about the code object.""" """Return formatted information about the code object."""
@ -670,7 +686,8 @@ class Bytecode:
file=output, file=output,
lasti=offset, lasti=offset,
exception_entries=self.exception_entries, exception_entries=self.exception_entries,
co_positions=co.co_positions()) co_positions=co.co_positions(),
show_caches=self.show_caches)
return output.getvalue() return output.getvalue()

View File

@ -387,9 +387,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.11a5 3478 (New CALL opcodes) # Python 3.11a5 3478 (New CALL opcodes)
# Python 3.11a5 3479 (Add PUSH_NULL opcode) # Python 3.11a5 3479 (Add PUSH_NULL opcode)
# Python 3.11a5 3480 (New CALL opcodes, second iteration) # Python 3.11a5 3480 (New CALL opcodes, second iteration)
# Python 3.11a5 3481 (Use inline CACHE instructions)
# Python 3.12 will start with magic number 3500
# Python 3.12 will start with magic number 3500 # Python 3.12 will start with magic number 3500
@ -404,7 +402,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3480).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3481).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View File

@ -35,20 +35,23 @@ hasnargs = [] # unused
opmap = {} opmap = {}
opname = ['<%r>' % (op,) for op in range(256)] opname = ['<%r>' % (op,) for op in range(256)]
def def_op(name, op): _inline_cache_entries = [0] * 256
def def_op(name, op, entries=0):
opname[op] = name opname[op] = name
opmap[name] = op opmap[name] = op
_inline_cache_entries[op] = entries
def name_op(name, op): def name_op(name, op, entries=0):
def_op(name, op) def_op(name, op, entries)
hasname.append(op) hasname.append(op)
def jrel_op(name, op): def jrel_op(name, op, entries=0):
def_op(name, op) def_op(name, op, entries)
hasjrel.append(op) hasjrel.append(op)
def jabs_op(name, op): def jabs_op(name, op, entries=0):
def_op(name, op) def_op(name, op, entries)
hasjabs.append(op) hasjabs.append(op)
# Instruction opcodes for compiled code # Instruction opcodes for compiled code
@ -56,6 +59,7 @@ def jabs_op(name, op):
def_op('POP_TOP', 1) def_op('POP_TOP', 1)
def_op('PUSH_NULL', 2) def_op('PUSH_NULL', 2)
def_op('CACHE', 3)
def_op('NOP', 9) def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10) def_op('UNARY_POSITIVE', 10)
@ -137,7 +141,7 @@ def_op('CONTAINS_OP', 118)
def_op('RERAISE', 119) def_op('RERAISE', 119)
def_op('COPY', 120) def_op('COPY', 120)
jabs_op('JUMP_IF_NOT_EXC_MATCH', 121) jabs_op('JUMP_IF_NOT_EXC_MATCH', 121)
def_op('BINARY_OP', 122) def_op('BINARY_OP', 122, 1)
jrel_op('SEND', 123) # Number of bytes to skip jrel_op('SEND', 123) # Number of bytes to skip
def_op('LOAD_FAST', 124) # Local variable number def_op('LOAD_FAST', 124) # Local variable number
haslocal.append(124) haslocal.append(124)

View File

@ -357,7 +357,7 @@ class CodeTest(unittest.TestCase):
artificial_instructions = [] artificial_instructions = []
for instr, positions in zip( for instr, positions in zip(
dis.get_instructions(code), dis.get_instructions(code, show_caches=True),
code.co_positions(), code.co_positions(),
strict=True strict=True
): ):

View File

@ -1062,7 +1062,9 @@ class TestSourcePositions(unittest.TestCase):
def assertOpcodeSourcePositionIs(self, code, opcode, def assertOpcodeSourcePositionIs(self, code, opcode,
line, end_line, column, end_column, occurrence=1): line, end_line, column, end_column, occurrence=1):
for instr, position in zip(dis.Bytecode(code), code.co_positions()): for instr, position in zip(
dis.Bytecode(code, show_caches=True), code.co_positions(), strict=True
):
if instr.opname == opcode: if instr.opname == opcode:
occurrence -= 1 occurrence -= 1
if not occurrence: if not occurrence:

View File

@ -375,7 +375,7 @@ dis_traceback = """\
>> PUSH_EXC_INFO >> PUSH_EXC_INFO
%3d LOAD_GLOBAL 0 (Exception) %3d LOAD_GLOBAL 0 (Exception)
JUMP_IF_NOT_EXC_MATCH 25 (to 50) JUMP_IF_NOT_EXC_MATCH 26 (to 52)
STORE_FAST 0 (e) STORE_FAST 0 (e)
%3d LOAD_FAST 0 (e) %3d LOAD_FAST 0 (e)
@ -571,7 +571,7 @@ Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>:
%3d RESUME 0 %3d RESUME 0
BUILD_LIST 0 BUILD_LIST 0
LOAD_FAST 0 (.0) LOAD_FAST 0 (.0)
>> FOR_ITER 6 (to 22) >> FOR_ITER 7 (to 24)
STORE_FAST 1 (z) STORE_FAST 1 (z)
LOAD_DEREF 2 (x) LOAD_DEREF 2 (x)
LOAD_FAST 1 (z) LOAD_FAST 1 (z)
@ -622,8 +622,8 @@ class DisTestBase(unittest.TestCase):
if line.startswith("Exception"): if line.startswith("Exception"):
break break
offset = int(line[start:end]) offset = int(line[start:end])
self.assertEqual(offset, expected_offset, line) self.assertGreaterEqual(offset, expected_offset, line)
expected_offset += delta expected_offset = offset + delta
def strip_offsets(self, text): def strip_offsets(self, text):
lines = text.splitlines(True) lines = text.splitlines(True)
@ -762,20 +762,20 @@ class DisTests(DisTestBase):
%*d LOAD_CONST 1 (1) %*d LOAD_CONST 1 (1)
%*d BINARY_OP 0 (+) %*d BINARY_OP 0 (+)
%*d STORE_FAST 0 (x) %*d STORE_FAST 0 (x)
''' % (w, 8*i + 2, w, 8*i + 4, w, 8*i + 6, w, 8*i + 8) ''' % (w, 10*i + 2, w, 10*i + 4, w, 10*i + 6, w, 10*i + 10)
for i in range(count)] for i in range(count)]
s += ['''\ s += ['''\
3 %*d LOAD_FAST 0 (x) 3 %*d LOAD_FAST 0 (x)
%*d RETURN_VALUE %*d RETURN_VALUE
''' % (w, 8*count + 2, w, 8*count + 4)] ''' % (w, 10*count + 2, w, 10*count + 4)]
s[1] = ' 2' + s[1][3:] s[1] = ' 2' + s[1][3:]
return ''.join(s) return ''.join(s)
for i in range(1, 5): for i in range(1, 5):
self.do_disassembly_test(func(i), expected(i, 4), True) self.do_disassembly_test(func(i), expected(i, 4), True)
self.do_disassembly_test(func(1248), expected(1248, 4), True) self.do_disassembly_test(func(999), expected(999, 4), True)
self.do_disassembly_test(func(1250), expected(1250, 5), True) self.do_disassembly_test(func(1000), expected(1000, 5), True)
def test_disassemble_str(self): def test_disassemble_str(self):
self.do_disassembly_test(expr_str, dis_expr_str) self.do_disassembly_test(expr_str, dis_expr_str)
@ -1250,7 +1250,7 @@ expected_opinfo_jumpy = [
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=11, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=57, argval=114, argrepr='to 114', offset=68, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=58, argval=116, argrepr='to 116', offset=68, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=70, starts_line=12, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=70, starts_line=12, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=72, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=72, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False, positions=None),
@ -1260,102 +1260,102 @@ expected_opinfo_jumpy = [
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=82, starts_line=13, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=82, starts_line=13, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=84, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=84, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=86, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=86, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=88, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=90, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=90, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=92, starts_line=14, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=92, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=94, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=94, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=96, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=50, argval=100, argrepr='to 100', offset=96, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=51, argval=102, argrepr='to 102', offset=98, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=33, argval=66, argrepr='to 66', offset=98, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=33, argval=66, argrepr='to 66', offset=100, starts_line=15, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=100, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=102, starts_line=16, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=102, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=104, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=104, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=106, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=55, argval=110, argrepr='to 110', offset=106, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=56, argval=112, argrepr='to 112', offset=108, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=8, argval=126, argrepr='to 126', offset=108, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=8, argval=128, argrepr='to 128', offset=110, starts_line=17, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=110, starts_line=11, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=112, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=35, argval=70, argrepr='to 70', offset=112, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=35, argval=70, argrepr='to 70', offset=114, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=114, starts_line=19, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=116, starts_line=19, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=116, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=118, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=118, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=120, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=120, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=126, starts_line=20, is_jump_target=True, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=128, starts_line=20, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=128, starts_line=21, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=130, starts_line=21, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=130, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=132, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=132, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=134, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=136, starts_line=25, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=140, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=144, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=142, starts_line=26, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=146, starts_line=26, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=144, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=148, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=146, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=150, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=148, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=160, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=162, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=190, argrepr='to 190', offset=166, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=194, argrepr='to 194', offset=170, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=91, argval=182, argrepr='to 182', offset=172, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=93, argval=186, argrepr='to 186', offset=176, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=174, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=176, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=180, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=180, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=184, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=224, argrepr='to 224', offset=190, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=228, argrepr='to 228', offset=194, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=194, starts_line=22, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=198, starts_line=22, is_jump_target=False, positions=None),
Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=108, argval=216, argrepr='to 216', offset=196, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=110, argval=220, argrepr='to 220', offset=200, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=200, starts_line=23, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=202, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=204, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=214, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=240, argrepr='to 240', offset=214, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=244, argrepr='to 244', offset=218, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=216, starts_line=22, is_jump_target=True, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=220, starts_line=22, is_jump_target=True, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=220, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=224, starts_line=28, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=228, starts_line=28, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=226, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=230, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=228, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=232, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=234, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=236, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=234, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=238, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=236, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=240, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=238, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=242, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=240, starts_line=23, is_jump_target=True, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=244, starts_line=23, is_jump_target=True, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=242, starts_line=28, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=246, starts_line=28, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=244, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=248, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=246, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=250, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=248, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=252, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=254, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=252, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=254, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=258, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=258, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=262, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=264, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=262, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=266, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=264, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=268, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=276, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=276, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=280, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=282, starts_line=None, is_jump_target=False, positions=None),
] ]
# One last piece of inspect fodder to check the default line number handling # One last piece of inspect fodder to check the default line number handling

View File

@ -0,0 +1,2 @@
Store :opcode:`BINARY_OP` caches inline using a new :opcode:`CACHE`
instruction.

View File

@ -327,7 +327,6 @@
<ClInclude Include="..\Python\importdl.h" /> <ClInclude Include="..\Python\importdl.h" />
<ClInclude Include="..\Python\stdlib_module_names.h" /> <ClInclude Include="..\Python\stdlib_module_names.h" />
<ClInclude Include="..\Python\thread_nt.h" /> <ClInclude Include="..\Python\thread_nt.h" />
<ClInclude Include="..\Python\wordcode_helpers.h" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="$(IncludeExternals)"> <ItemGroup Condition="$(IncludeExternals)">
<ClInclude Include="$(zlibDir)\crc32.h" /> <ClInclude Include="$(zlibDir)\crc32.h" />

View File

@ -321,9 +321,6 @@
<ClInclude Include="..\Python\thread_nt.h"> <ClInclude Include="..\Python\thread_nt.h">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Python\wordcode_helpers.h">
<Filter>Python</Filter>
</ClInclude>
<ClInclude Include="..\Python\condvar.h"> <ClInclude Include="..\Python\condvar.h">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClInclude> </ClInclude>

View File

@ -1939,6 +1939,7 @@ handle_eval_breaker:
if (prod == NULL) { if (prod == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -1959,6 +1960,7 @@ handle_eval_breaker:
if (prod == NULL) { if (prod == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -1977,6 +1979,7 @@ handle_eval_breaker:
if (sub == NULL) { if (sub == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -1996,6 +1999,7 @@ handle_eval_breaker:
if (sub == NULL) { if (sub == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -2014,6 +2018,7 @@ handle_eval_breaker:
if (TOP() == NULL) { if (TOP() == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -2043,6 +2048,7 @@ handle_eval_breaker:
if (TOP() == NULL) { if (TOP() == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -2063,6 +2069,7 @@ handle_eval_breaker:
if (sum == NULL) { if (sum == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -2081,6 +2088,7 @@ handle_eval_breaker:
if (sum == NULL) { if (sum == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -5425,23 +5433,23 @@ handle_eval_breaker:
if (res == NULL) { if (res == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_ADAPTIVE) { TARGET(BINARY_OP_ADAPTIVE) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
SpecializedCacheEntry *cache = GET_CACHE(); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
if (cache->adaptive.counter == 0) { if (cache->counter == 0) {
PyObject *lhs = SECOND(); PyObject *lhs = SECOND();
PyObject *rhs = TOP(); PyObject *rhs = TOP();
next_instr--; next_instr--;
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, cache); _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg);
DISPATCH(); DISPATCH();
} }
else { else {
STAT_INC(BINARY_OP, deferred); STAT_INC(BINARY_OP, deferred);
cache->adaptive.counter--; cache->counter--;
oparg = cache->adaptive.original_oparg;
JUMP_TO_INSTRUCTION(BINARY_OP); JUMP_TO_INSTRUCTION(BINARY_OP);
} }
} }
@ -5462,6 +5470,10 @@ handle_eval_breaker:
DISPATCH_GOTO(); DISPATCH_GOTO();
} }
TARGET(CACHE) {
Py_UNREACHABLE();
}
#if USE_COMPUTED_GOTOS #if USE_COMPUTED_GOTOS
TARGET_DO_TRACING: { TARGET_DO_TRACING: {
#else #else
@ -5548,6 +5560,22 @@ opname ## _miss: \
JUMP_TO_INSTRUCTION(opname); \ JUMP_TO_INSTRUCTION(opname); \
} }
#define MISS_WITH_INLINE_CACHE(opname) \
opname ## _miss: \
{ \
STAT_INC(opcode, miss); \
STAT_INC(opname, miss); \
/* The counter is always the first cache entry: */ \
_Py_CODEUNIT *counter = (_Py_CODEUNIT *)next_instr; \
*counter -= 1; \
if (*counter == 0) { \
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, _Py_OPARG(next_instr[-1])); \
STAT_INC(opname, deopt); \
*counter = ADAPTIVE_CACHE_BACKOFF; \
} \
JUMP_TO_INSTRUCTION(opname); \
}
#define MISS_WITH_OPARG_COUNTER(opname) \ #define MISS_WITH_OPARG_COUNTER(opname) \
opname ## _miss: \ opname ## _miss: \
{ \ { \
@ -5569,7 +5597,7 @@ MISS_WITH_CACHE(LOAD_GLOBAL)
MISS_WITH_CACHE(LOAD_METHOD) MISS_WITH_CACHE(LOAD_METHOD)
MISS_WITH_CACHE(PRECALL) MISS_WITH_CACHE(PRECALL)
MISS_WITH_CACHE(CALL) MISS_WITH_CACHE(CALL)
MISS_WITH_CACHE(BINARY_OP) MISS_WITH_INLINE_CACHE(BINARY_OP)
MISS_WITH_CACHE(COMPARE_OP) MISS_WITH_CACHE(COMPARE_OP)
MISS_WITH_CACHE(BINARY_SUBSCR) MISS_WITH_CACHE(BINARY_SUBSCR)
MISS_WITH_CACHE(UNPACK_SEQUENCE) MISS_WITH_CACHE(UNPACK_SEQUENCE)

View File

@ -33,7 +33,6 @@
#define NEED_OPCODE_JUMP_TABLES #define NEED_OPCODE_JUMP_TABLES
#include "opcode.h" // EXTENDED_ARG #include "opcode.h" // EXTENDED_ARG
#include "wordcode_helpers.h" // instrsize()
#define DEFAULT_BLOCK_SIZE 16 #define DEFAULT_BLOCK_SIZE 16
@ -131,6 +130,43 @@ is_jump(struct instr *i)
return i->i_opcode >= SETUP_WITH || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); return i->i_opcode >= SETUP_WITH || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
} }
static int
instr_size(struct instr *instruction)
{
int opcode = instruction->i_opcode;
int oparg = instruction->i_oparg;
int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
int caches = _PyOpcode_InlineCacheEntries[opcode];
return extended_args + 1 + caches;
}
static void
write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen)
{
int opcode = instruction->i_opcode;
int oparg = instruction->i_oparg;
int caches = _PyOpcode_InlineCacheEntries[opcode];
switch (ilen - caches) {
case 4:
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 24) & 0xFF);
/* fall through */
case 3:
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 16) & 0xFF);
/* fall through */
case 2:
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 8) & 0xFF);
/* fall through */
case 1:
*codestr++ = _Py_MAKECODEUNIT(opcode, oparg & 0xFF);
break;
default:
Py_UNREACHABLE();
}
while (caches--) {
*codestr++ = _Py_MAKECODEUNIT(CACHE, 0);
}
}
typedef struct basicblock_ { typedef struct basicblock_ {
/* Each basicblock in a compilation unit is linked via b_list in the /* Each basicblock in a compilation unit is linked via b_list in the
reverse order that the block are allocated. b_list points to the next reverse order that the block are allocated. b_list points to the next
@ -854,6 +890,7 @@ stack_effect(int opcode, int oparg, int jump)
case NOP: case NOP:
case EXTENDED_ARG: case EXTENDED_ARG:
case RESUME: case RESUME:
case CACHE:
return 0; return 0;
/* Stack manipulation */ /* Stack manipulation */
@ -7065,8 +7102,9 @@ blocksize(basicblock *b)
int i; int i;
int size = 0; int size = 0;
for (i = 0; i < b->b_iused; i++) for (i = 0; i < b->b_iused; i++) {
size += instrsize(b->b_instr[i].i_oparg); size += instr_size(&b->b_instr[i]);
}
return size; return size;
} }
@ -7330,7 +7368,7 @@ assemble_exception_table(struct assembler *a)
start = ioffset; start = ioffset;
handler = instr->i_except; handler = instr->i_except;
} }
ioffset += instrsize(instr->i_oparg); ioffset += instr_size(instr);
} }
} }
if (handler != NULL) { if (handler != NULL) {
@ -7459,12 +7497,10 @@ assemble_cnotab(struct assembler* a, struct instr* i, int instr_size)
static int static int
assemble_emit(struct assembler *a, struct instr *i) assemble_emit(struct assembler *a, struct instr *i)
{ {
int size, arg = 0;
Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
_Py_CODEUNIT *code; _Py_CODEUNIT *code;
arg = i->i_oparg; int size = instr_size(i);
size = instrsize(arg);
if (i->i_lineno && !assemble_lnotab(a, i)) { if (i->i_lineno && !assemble_lnotab(a, i)) {
return 0; return 0;
} }
@ -7482,7 +7518,7 @@ assemble_emit(struct assembler *a, struct instr *i)
} }
code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset; code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
a->a_offset += size; a->a_offset += size;
write_op_arg(code, i->i_opcode, arg, size); write_instr(code, i, size);
return 1; return 1;
} }
@ -7532,7 +7568,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
bsize = b->b_offset; bsize = b->b_offset;
for (i = 0; i < b->b_iused; i++) { for (i = 0; i < b->b_iused; i++) {
struct instr *instr = &b->b_instr[i]; struct instr *instr = &b->b_instr[i];
int isize = instrsize(instr->i_oparg); int isize = instr_size(instr);
/* Relative jumps are computed relative to /* Relative jumps are computed relative to
the instruction pointer after fetching the instruction pointer after fetching
the jump instruction. the jump instruction.
@ -7543,7 +7579,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
if (is_relative_jump(instr)) { if (is_relative_jump(instr)) {
instr->i_oparg -= bsize; instr->i_oparg -= bsize;
} }
if (instrsize(instr->i_oparg) != isize) { if (instr_size(instr) != isize) {
extended_arg_recompile = 1; extended_arg_recompile = 1;
} }
} }
@ -7555,7 +7591,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
with a better solution. with a better solution.
The issue is that in the first loop blocksize() is called The issue is that in the first loop blocksize() is called
which calls instrsize() which requires i_oparg be set which calls instr_size() which requires i_oparg be set
appropriately. There is a bootstrap problem because appropriately. There is a bootstrap problem because
i_oparg is calculated in the second loop above. i_oparg is calculated in the second loop above.

View File

@ -2,19 +2,20 @@ static void *opcode_targets[256] = {
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_POP_TOP, &&TARGET_POP_TOP,
&&TARGET_PUSH_NULL, &&TARGET_PUSH_NULL,
&&TARGET_CACHE,
&&TARGET_BINARY_OP_ADAPTIVE, &&TARGET_BINARY_OP_ADAPTIVE,
&&TARGET_BINARY_OP_ADD_INT, &&TARGET_BINARY_OP_ADD_INT,
&&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_FLOAT,
&&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_BINARY_OP_ADD_UNICODE,
&&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE,
&&TARGET_BINARY_OP_MULTIPLY_INT,
&&TARGET_NOP, &&TARGET_NOP,
&&TARGET_UNARY_POSITIVE, &&TARGET_UNARY_POSITIVE,
&&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NEGATIVE,
&&TARGET_UNARY_NOT, &&TARGET_UNARY_NOT,
&&TARGET_BINARY_OP_MULTIPLY_INT,
&&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_BINARY_OP_MULTIPLY_FLOAT,
&&TARGET_BINARY_OP_SUBTRACT_INT,
&&TARGET_UNARY_INVERT, &&TARGET_UNARY_INVERT,
&&TARGET_BINARY_OP_SUBTRACT_INT,
&&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT,
&&TARGET_COMPARE_OP_ADAPTIVE, &&TARGET_COMPARE_OP_ADAPTIVE,
&&TARGET_COMPARE_OP_FLOAT_JUMP, &&TARGET_COMPARE_OP_FLOAT_JUMP,
@ -23,18 +24,18 @@ static void *opcode_targets[256] = {
&&TARGET_BINARY_SUBSCR_ADAPTIVE, &&TARGET_BINARY_SUBSCR_ADAPTIVE,
&&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_GETITEM,
&&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_LIST_INT,
&&TARGET_BINARY_SUBSCR_TUPLE_INT,
&&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SUBSCR,
&&TARGET_BINARY_SUBSCR_TUPLE_INT,
&&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_DICT,
&&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_STORE_SUBSCR_ADAPTIVE,
&&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_STORE_SUBSCR_LIST_INT,
&&TARGET_STORE_SUBSCR_DICT,
&&TARGET_GET_LEN, &&TARGET_GET_LEN,
&&TARGET_MATCH_MAPPING, &&TARGET_MATCH_MAPPING,
&&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_SEQUENCE,
&&TARGET_MATCH_KEYS, &&TARGET_MATCH_KEYS,
&&TARGET_CALL_ADAPTIVE, &&TARGET_STORE_SUBSCR_DICT,
&&TARGET_PUSH_EXC_INFO, &&TARGET_PUSH_EXC_INFO,
&&TARGET_CALL_ADAPTIVE,
&&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_EXACT_ARGS,
&&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_CALL_PY_WITH_DEFAULTS,
&&TARGET_JUMP_ABSOLUTE_QUICK, &&TARGET_JUMP_ABSOLUTE_QUICK,
@ -47,40 +48,39 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_ADAPTIVE,
&&TARGET_LOAD_METHOD_CLASS,
&&TARGET_WITH_EXCEPT_START, &&TARGET_WITH_EXCEPT_START,
&&TARGET_GET_AITER, &&TARGET_GET_AITER,
&&TARGET_GET_ANEXT, &&TARGET_GET_ANEXT,
&&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_ASYNC_WITH,
&&TARGET_BEFORE_WITH, &&TARGET_BEFORE_WITH,
&&TARGET_END_ASYNC_FOR, &&TARGET_END_ASYNC_FOR,
&&TARGET_LOAD_METHOD_CLASS,
&&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_MODULE,
&&TARGET_LOAD_METHOD_NO_DICT, &&TARGET_LOAD_METHOD_NO_DICT,
&&TARGET_LOAD_METHOD_WITH_DICT, &&TARGET_LOAD_METHOD_WITH_DICT,
&&TARGET_LOAD_METHOD_WITH_VALUES, &&TARGET_LOAD_METHOD_WITH_VALUES,
&&TARGET_PRECALL_ADAPTIVE,
&&TARGET_STORE_SUBSCR, &&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR, &&TARGET_DELETE_SUBSCR,
&&TARGET_PRECALL_ADAPTIVE,
&&TARGET_PRECALL_BUILTIN_CLASS, &&TARGET_PRECALL_BUILTIN_CLASS,
&&TARGET_PRECALL_NO_KW_BUILTIN_O, &&TARGET_PRECALL_NO_KW_BUILTIN_O,
&&TARGET_PRECALL_NO_KW_BUILTIN_FAST, &&TARGET_PRECALL_NO_KW_BUILTIN_FAST,
&&TARGET_PRECALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_PRECALL_BUILTIN_FAST_WITH_KEYWORDS,
&&TARGET_PRECALL_NO_KW_LEN, &&TARGET_PRECALL_NO_KW_LEN,
&&TARGET_PRECALL_NO_KW_ISINSTANCE,
&&TARGET_GET_ITER, &&TARGET_GET_ITER,
&&TARGET_GET_YIELD_FROM_ITER, &&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_PRINT_EXPR, &&TARGET_PRINT_EXPR,
&&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_BUILD_CLASS,
&&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_PRECALL_NO_KW_ISINSTANCE,
&&TARGET_GET_AWAITABLE, &&TARGET_GET_AWAITABLE,
&&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_LOAD_ASSERTION_ERROR,
&&TARGET_RETURN_GENERATOR, &&TARGET_RETURN_GENERATOR,
&&TARGET_PRECALL_NO_KW_LIST_APPEND,
&&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O,
&&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
&&TARGET_PRECALL_NO_KW_STR_1, &&TARGET_PRECALL_NO_KW_STR_1,
&&TARGET_PRECALL_NO_KW_TUPLE_1, &&TARGET_PRECALL_NO_KW_TUPLE_1,
&&TARGET_PRECALL_NO_KW_TYPE_1, &&TARGET_PRECALL_NO_KW_TYPE_1,
&&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST,
&&TARGET_LIST_TO_TUPLE, &&TARGET_LIST_TO_TUPLE,
&&TARGET_RETURN_VALUE, &&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR, &&TARGET_IMPORT_STAR,
@ -130,7 +130,7 @@ static void *opcode_targets[256] = {
&&TARGET_POP_JUMP_IF_NOT_NONE, &&TARGET_POP_JUMP_IF_NOT_NONE,
&&TARGET_POP_JUMP_IF_NONE, &&TARGET_POP_JUMP_IF_NONE,
&&TARGET_RAISE_VARARGS, &&TARGET_RAISE_VARARGS,
&&TARGET_PRECALL_BOUND_METHOD, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST,
&&TARGET_MAKE_FUNCTION, &&TARGET_MAKE_FUNCTION,
&&TARGET_BUILD_SLICE, &&TARGET_BUILD_SLICE,
&&TARGET_JUMP_NO_INTERRUPT, &&TARGET_JUMP_NO_INTERRUPT,
@ -139,39 +139,40 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_DEREF, &&TARGET_LOAD_DEREF,
&&TARGET_STORE_DEREF, &&TARGET_STORE_DEREF,
&&TARGET_DELETE_DEREF, &&TARGET_DELETE_DEREF,
&&TARGET_PRECALL_BOUND_METHOD,
&&TARGET_PRECALL_PYFUNC, &&TARGET_PRECALL_PYFUNC,
&&TARGET_RESUME_QUICK,
&&TARGET_CALL_FUNCTION_EX, &&TARGET_CALL_FUNCTION_EX,
&&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_RESUME_QUICK,
&&TARGET_EXTENDED_ARG, &&TARGET_EXTENDED_ARG,
&&TARGET_LIST_APPEND, &&TARGET_LIST_APPEND,
&&TARGET_SET_ADD, &&TARGET_SET_ADD,
&&TARGET_MAP_ADD, &&TARGET_MAP_ADD,
&&TARGET_LOAD_CLASSDEREF, &&TARGET_LOAD_CLASSDEREF,
&&TARGET_COPY_FREE_VARS, &&TARGET_COPY_FREE_VARS,
&&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_ADAPTIVE,
&&TARGET_RESUME, &&TARGET_RESUME,
&&TARGET_MATCH_CLASS, &&TARGET_MATCH_CLASS,
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_FORMAT_VALUE, &&TARGET_FORMAT_VALUE,
&&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_CONST_KEY_MAP,
&&TARGET_BUILD_STRING, &&TARGET_BUILD_STRING,
&&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_UNPACK_SEQUENCE_ADAPTIVE, &&TARGET_UNPACK_SEQUENCE_ADAPTIVE,
&&TARGET_UNPACK_SEQUENCE_LIST,
&&TARGET_LOAD_METHOD, &&TARGET_LOAD_METHOD,
&&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_LIST,
&&TARGET_LIST_EXTEND, &&TARGET_LIST_EXTEND,
&&TARGET_SET_UPDATE, &&TARGET_SET_UPDATE,
&&TARGET_DICT_MERGE, &&TARGET_DICT_MERGE,
&&TARGET_DICT_UPDATE, &&TARGET_DICT_UPDATE,
&&TARGET_PRECALL, &&TARGET_PRECALL,
&&TARGET_UNPACK_SEQUENCE_TUPLE,
&&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
&&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_CALL, &&TARGET_CALL,
&&TARGET_KW_NAMES, &&TARGET_KW_NAMES,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_CONST__LOAD_FAST,
&&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_FAST__STORE_FAST,
&&TARGET_LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE,
@ -253,6 +254,5 @@ static void *opcode_targets[256] = {
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_DO_TRACING &&TARGET_DO_TRACING
}; };

View File

@ -65,7 +65,6 @@ static uint8_t cache_requirements[256] = {
[CALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */ [CALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
[PRECALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */ [PRECALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
[STORE_ATTR] = 1, // _PyAdaptiveEntry [STORE_ATTR] = 1, // _PyAdaptiveEntry
[BINARY_OP] = 1, // _PyAdaptiveEntry
[COMPARE_OP] = 1, /* _PyAdaptiveEntry */ [COMPARE_OP] = 1, /* _PyAdaptiveEntry */
[UNPACK_SEQUENCE] = 1, // _PyAdaptiveEntry [UNPACK_SEQUENCE] = 1, // _PyAdaptiveEntry
}; };
@ -385,29 +384,34 @@ optimize(SpecializedCacheOrInstruction *quickened, int len)
int opcode = _Py_OPCODE(instructions[i]); int opcode = _Py_OPCODE(instructions[i]);
int oparg = _Py_OPARG(instructions[i]); int oparg = _Py_OPARG(instructions[i]);
uint8_t adaptive_opcode = adaptive_opcodes[opcode]; uint8_t adaptive_opcode = adaptive_opcodes[opcode];
if (adaptive_opcode && previous_opcode != EXTENDED_ARG) { if (adaptive_opcode) {
int new_oparg = oparg_from_instruction_and_update_offset( if (_PyOpcode_InlineCacheEntries[opcode]) {
i, opcode, oparg, &cache_offset instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
);
if (new_oparg < 0) {
/* Not possible to allocate a cache for this instruction */
previous_opcode = opcode;
continue;
} }
previous_opcode = adaptive_opcode; else if (previous_opcode != EXTENDED_ARG) {
int entries_needed = cache_requirements[opcode]; int new_oparg = oparg_from_instruction_and_update_offset(
if (entries_needed) { i, opcode, oparg, &cache_offset
/* Initialize the adpative cache entry */ );
int cache0_offset = cache_offset-entries_needed; if (new_oparg < 0) {
SpecializedCacheEntry *cache = /* Not possible to allocate a cache for this instruction */
_GetSpecializedCacheEntry(instructions, cache0_offset); previous_opcode = opcode;
cache->adaptive.original_oparg = oparg; continue;
cache->adaptive.counter = 0; }
} else { previous_opcode = adaptive_opcode;
// oparg is the adaptive cache counter int entries_needed = cache_requirements[opcode];
new_oparg = 0; if (entries_needed) {
/* Initialize the adpative cache entry */
int cache0_offset = cache_offset-entries_needed;
SpecializedCacheEntry *cache =
_GetSpecializedCacheEntry(instructions, cache0_offset);
cache->adaptive.original_oparg = oparg;
cache->adaptive.counter = 0;
} else {
// oparg is the adaptive cache counter
new_oparg = 0;
}
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, new_oparg);
} }
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, new_oparg);
} }
else { else {
/* Super instructions don't use the cache, /* Super instructions don't use the cache,
@ -1922,10 +1926,12 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
void void
_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache) int oparg)
{ {
_PyAdaptiveEntry *adaptive = &cache->adaptive; assert(_PyOpcode_InlineCacheEntries[BINARY_OP] ==
switch (adaptive->original_oparg) { INLINE_CACHE_ENTRIES_BINARY_OP);
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1);
switch (oparg) {
case NB_ADD: case NB_ADD:
case NB_INPLACE_ADD: case NB_INPLACE_ADD:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
@ -1934,20 +1940,18 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
if (PyUnicode_CheckExact(lhs)) { if (PyUnicode_CheckExact(lhs)) {
if (_Py_OPCODE(instr[1]) == STORE_FAST && Py_REFCNT(lhs) == 2) { if (_Py_OPCODE(instr[1]) == STORE_FAST && Py_REFCNT(lhs) == 2) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_INPLACE_ADD_UNICODE, *instr = _Py_MAKECODEUNIT(BINARY_OP_INPLACE_ADD_UNICODE,
_Py_OPARG(*instr)); oparg);
goto success; goto success;
} }
*instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_UNICODE, *instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_UNICODE, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
if (PyLong_CheckExact(lhs)) { if (PyLong_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_INT, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_INT, oparg);
goto success; goto success;
} }
if (PyFloat_CheckExact(lhs)) { if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_FLOAT, *instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_FLOAT, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
break; break;
@ -1957,13 +1961,11 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
break; break;
} }
if (PyLong_CheckExact(lhs)) { if (PyLong_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_INT, *instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_INT, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
if (PyFloat_CheckExact(lhs)) { if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_FLOAT, *instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_FLOAT, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
break; break;
@ -1973,13 +1975,11 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
break; break;
} }
if (PyLong_CheckExact(lhs)) { if (PyLong_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT, *instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
if (PyFloat_CheckExact(lhs)) { if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_FLOAT, *instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_FLOAT, oparg);
_Py_OPARG(*instr));
goto success; goto success;
} }
break; break;
@ -1990,18 +1990,17 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
// back to BINARY_OP (unless we're collecting stats, where it's more // back to BINARY_OP (unless we're collecting stats, where it's more
// important to get accurate hit counts for the unadaptive version // important to get accurate hit counts for the unadaptive version
// and each of the different failure types): // and each of the different failure types):
*instr = _Py_MAKECODEUNIT(BINARY_OP, adaptive->original_oparg); *instr = _Py_MAKECODEUNIT(BINARY_OP, oparg);
return; return;
#endif #endif
} }
SPECIALIZATION_FAIL( SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs));
BINARY_OP, binary_op_fail_kind(adaptive->original_oparg, lhs, rhs));
STAT_INC(BINARY_OP, failure); STAT_INC(BINARY_OP, failure);
cache_backoff(adaptive); cache->counter = ADAPTIVE_CACHE_BACKOFF;
return; return;
success: success:
STAT_INC(BINARY_OP, success); STAT_INC(BINARY_OP, success);
adaptive->counter = initial_counter_value(); cache->counter = initial_counter_value();
} }

View File

@ -1,44 +0,0 @@
/* This file contains code shared by the compiler and the peephole
optimizer.
*/
#ifdef WORDS_BIGENDIAN
# define PACKOPARG(opcode, oparg) ((_Py_CODEUNIT)(((opcode) << 8) | (oparg)))
#else
# define PACKOPARG(opcode, oparg) ((_Py_CODEUNIT)(((oparg) << 8) | (opcode)))
#endif
/* Minimum number of code units necessary to encode instruction with
EXTENDED_ARGs */
static int
instrsize(unsigned int oparg)
{
return oparg <= 0xff ? 1 :
oparg <= 0xffff ? 2 :
oparg <= 0xffffff ? 3 :
4;
}
/* Spits out op/oparg pair using ilen bytes. codestr should be pointed at the
desired location of the first EXTENDED_ARG */
static void
write_op_arg(_Py_CODEUNIT *codestr, unsigned char opcode,
unsigned int oparg, int ilen)
{
switch (ilen) {
case 4:
*codestr++ = PACKOPARG(EXTENDED_ARG, (oparg >> 24) & 0xff);
/* fall through */
case 3:
*codestr++ = PACKOPARG(EXTENDED_ARG, (oparg >> 16) & 0xff);
/* fall through */
case 2:
*codestr++ = PACKOPARG(EXTENDED_ARG, (oparg >> 8) & 0xff);
/* fall through */
case 1:
*codestr++ = PACKOPARG(opcode, oparg & 0xff);
break;
default:
Py_UNREACHABLE();
}
}

View File

@ -53,6 +53,7 @@ def main(opcode_py, outfile='Include/opcode.h'):
code = fp.read() code = fp.read()
exec(code, opcode) exec(code, opcode)
opmap = opcode['opmap'] opmap = opcode['opmap']
opname = opcode['opname']
hasconst = opcode['hasconst'] hasconst = opcode['hasconst']
hasjrel = opcode['hasjrel'] hasjrel = opcode['hasjrel']
hasjabs = opcode['hasjabs'] hasjabs = opcode['hasjabs']
@ -62,7 +63,7 @@ def main(opcode_py, outfile='Include/opcode.h'):
used[op] = True used[op] = True
with open(outfile, 'w') as fobj: with open(outfile, 'w') as fobj:
fobj.write(header) fobj.write(header)
for name in opcode['opname']: for name in opname:
if name in opmap: if name in opmap:
fobj.write(DEFINE.format(name, opmap[name])) fobj.write(DEFINE.format(name, opmap[name]))
if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT
@ -89,6 +90,12 @@ def main(opcode_py, outfile='Include/opcode.h'):
for i, (op, _) in enumerate(opcode["_nb_ops"]): for i, (op, _) in enumerate(opcode["_nb_ops"]):
fobj.write(DEFINE.format(op, i)) fobj.write(DEFINE.format(op, i))
fobj.write("\nstatic const uint8_t _PyOpcode_InlineCacheEntries[256] = {\n")
for i, entries in enumerate(opcode["_inline_cache_entries"]):
if entries:
fobj.write(f" [{opname[i]}] = {entries},\n")
fobj.write("};\n")
fobj.write(footer) fobj.write(footer)