bpo-46841: Use inline caching for calls (GH-31709)

This commit is contained in:
Brandt Bucher 2022-03-07 11:45:00 -08:00 committed by GitHub
parent 105b9ac001
commit f193631387
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 494 additions and 735 deletions

View file

@ -105,7 +105,7 @@ struct PyCodeObject {
/* Quickened instructions and cache, or NULL /* Quickened instructions and cache, or NULL
This should be treated as opaque by all code except the specializer and This should be treated as opaque by all code except the specializer and
interpreter. */ interpreter. */
union _cache_or_instruction *co_quickened; _Py_CODEUNIT *co_quickened;
}; };

View file

@ -8,50 +8,10 @@ extern "C" {
* Specialization and quickening structs and helper functions * Specialization and quickening structs and helper functions
*/ */
typedef struct {
int32_t cache_count;
int32_t _; /* Force 8 byte size */
} _PyEntryZero;
typedef struct { // Inline caches. If you change the number of cache entries for an instruction,
uint8_t original_oparg; // you must *also* update the number of cache entries in Lib/opcode.py and bump
uint8_t counter; // the magic number in Lib/importlib/_bootstrap_external.py!
uint16_t index;
uint32_t version;
} _PyAdaptiveEntry;
typedef struct {
/* Borrowed ref */
PyObject *obj;
} _PyObjectCache;
typedef struct {
uint32_t func_version;
uint16_t min_args;
uint16_t defaults_len;
} _PyCallCache;
/* Add specialized versions of entries to this union.
*
* Do not break the invariant: sizeof(SpecializedCacheEntry) == 8
* Preserving this invariant is necessary because:
- If any one form uses more space, then all must and on 64 bit machines
this is likely to double the memory consumption of caches
- The function for calculating the offset of caches assumes a 4:1
cache:instruction size ratio. Changing that would need careful
analysis to choose a new function.
*/
typedef union {
_PyEntryZero zero;
_PyAdaptiveEntry adaptive;
_PyObjectCache obj;
_PyCallCache call;
} SpecializedCacheEntry;
#define INSTRUCTIONS_PER_ENTRY (sizeof(SpecializedCacheEntry)/sizeof(_Py_CODEUNIT))
/* Inline caches */
#define CACHE_ENTRIES(cache) (sizeof(cache)/sizeof(_Py_CODEUNIT)) #define CACHE_ENTRIES(cache) (sizeof(cache)/sizeof(_Py_CODEUNIT))
@ -112,73 +72,22 @@ typedef struct {
#define INLINE_CACHE_ENTRIES_LOAD_METHOD CACHE_ENTRIES(_PyLoadMethodCache) #define INLINE_CACHE_ENTRIES_LOAD_METHOD CACHE_ENTRIES(_PyLoadMethodCache)
typedef struct {
_Py_CODEUNIT counter;
_Py_CODEUNIT func_version[2];
_Py_CODEUNIT min_args;
} _PyCallCache;
#define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache)
typedef struct {
_Py_CODEUNIT counter;
} _PyPrecallCache;
#define INLINE_CACHE_ENTRIES_PRECALL CACHE_ENTRIES(_PyPrecallCache)
/* 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 10000
typedef union _cache_or_instruction {
_Py_CODEUNIT code[1];
SpecializedCacheEntry entry;
} SpecializedCacheOrInstruction;
/* Get pointer to the nth cache entry, from the first instruction and n.
* Cache entries are indexed backwards, with [count-1] first in memory, and [0] last.
* The zeroth entry immediately precedes the instructions.
*/
static inline SpecializedCacheEntry *
_GetSpecializedCacheEntry(const _Py_CODEUNIT *first_instr, Py_ssize_t n)
{
SpecializedCacheOrInstruction *last_cache_plus_one = (SpecializedCacheOrInstruction *)first_instr;
assert(&last_cache_plus_one->code[0] == first_instr);
return &last_cache_plus_one[-1-n].entry;
}
/* Following two functions form a pair.
*
* oparg_from_offset_and_index() is used to compute the oparg
* when quickening, so that offset_from_oparg_and_nexti()
* can be used at runtime to compute the offset.
*
* The relationship between the three values is currently
* offset == (index>>1) + oparg
* This relation is chosen based on the following observations:
* 1. typically 1 in 4 instructions need a cache
* 2. instructions that need a cache typically use 2 entries
* These observations imply: offset index/2
* We use the oparg to fine tune the relation to avoid wasting space
* and allow consecutive instructions to use caches.
*
* If the number of cache entries < number of instructions/2 we will waste
* some small amoount of space.
* If the number of cache entries > (number of instructions/2) + 255, then
* some instructions will not be able to use a cache.
* In practice, we expect some small amount of wasted space in a shorter functions
* and only functions exceeding a 1000 lines or more not to have enugh cache space.
*
*/
static inline int
oparg_from_offset_and_nexti(int offset, int nexti)
{
return offset-(nexti>>1);
}
static inline int
offset_from_oparg_and_nexti(int oparg, int nexti)
{
return (nexti>>1)+oparg;
}
/* Get pointer to the cache entry associated with an instruction.
* nexti is the index of the instruction plus one.
* nexti is used as it corresponds to the instruction pointer in the interpreter.
* This doesn't check that an entry has been allocated for that instruction. */
static inline SpecializedCacheEntry *
_GetSpecializedCacheEntryForInstruction(const _Py_CODEUNIT *first_instr, int nexti, int oparg)
{
return _GetSpecializedCacheEntry(
first_instr,
offset_from_oparg_and_nexti(oparg, nexti)
);
}
#define QUICKENING_WARMUP_DELAY 8 #define QUICKENING_WARMUP_DELAY 8
@ -205,6 +114,13 @@ _Py_IncrementCountAndMaybeQuicken(PyCodeObject *code)
extern Py_ssize_t _Py_QuickenedCount; extern Py_ssize_t _Py_QuickenedCount;
// Borrowed references to common callables:
struct callable_cache {
PyObject *isinstance;
PyObject *len;
PyObject *list_append;
};
/* "Locals plus" for a code object is the set of locals + cell vars + /* "Locals plus" for a code object is the set of locals + cell vars +
* free vars. This relates to variable names as well as offsets into * free vars. This relates to variable names as well as offsets into
* the "fast locals" storage array of execution frames. The compiler * the "fast locals" storage array of execution frames. The compiler
@ -332,11 +248,6 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
#define ADAPTIVE_CACHE_BACKOFF 64 #define ADAPTIVE_CACHE_BACKOFF 64
static inline void
cache_backoff(_PyAdaptiveEntry *entry) {
entry->counter = ADAPTIVE_CACHE_BACKOFF;
}
/* Specialization functions */ /* Specialization functions */
extern int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, extern int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
@ -348,10 +259,10 @@ extern int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name); PyObject *name);
extern int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr); extern int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr);
extern int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr); extern int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr);
extern int _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, extern int _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr,
PyObject *kwnames, SpecializedCacheEntry *cache); int nargs, PyObject *kwnames);
extern int _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr, int nargs, extern int _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr,
PyObject *kwnames, SpecializedCacheEntry *cache, PyObject *builtins); int nargs, PyObject *kwnames, int oparg);
extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
int oparg); int oparg);
extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,

View file

@ -269,6 +269,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(inf) STRUCT_FOR_ID(inf)
STRUCT_FOR_ID(intersection) STRUCT_FOR_ID(intersection)
STRUCT_FOR_ID(isatty) STRUCT_FOR_ID(isatty)
STRUCT_FOR_ID(isinstance)
STRUCT_FOR_ID(items) STRUCT_FOR_ID(items)
STRUCT_FOR_ID(iter) STRUCT_FOR_ID(iter)
STRUCT_FOR_ID(join) STRUCT_FOR_ID(join)
@ -278,6 +279,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(last_type) STRUCT_FOR_ID(last_type)
STRUCT_FOR_ID(last_value) STRUCT_FOR_ID(last_value)
STRUCT_FOR_ID(latin1) STRUCT_FOR_ID(latin1)
STRUCT_FOR_ID(len)
STRUCT_FOR_ID(line) STRUCT_FOR_ID(line)
STRUCT_FOR_ID(lineno) STRUCT_FOR_ID(lineno)
STRUCT_FOR_ID(listcomp) STRUCT_FOR_ID(listcomp)

View file

@ -12,6 +12,7 @@ extern "C" {
#include "pycore_atomic.h" // _Py_atomic_address #include "pycore_atomic.h" // _Py_atomic_address
#include "pycore_ast_state.h" // struct ast_state #include "pycore_ast_state.h" // struct ast_state
#include "pycore_code.h" // struct callable_cache
#include "pycore_context.h" // struct _Py_context_state #include "pycore_context.h" // struct _Py_context_state
#include "pycore_dict.h" // struct _Py_dict_state #include "pycore_dict.h" // struct _Py_dict_state
#include "pycore_exceptions.h" // struct _Py_exc_state #include "pycore_exceptions.h" // struct _Py_exc_state
@ -176,6 +177,7 @@ struct _is {
struct ast_state ast; struct ast_state ast;
struct type_cache type_cache; struct type_cache type_cache;
struct callable_cache callable_cache;
/* The following fields are here to avoid allocation during init. /* The following fields are here to avoid allocation during init.
The data is exposed through PyInterpreterState pointer fields. The data is exposed through PyInterpreterState pointer fields.

View file

@ -884,6 +884,7 @@ extern "C" {
INIT_ID(inf), \ INIT_ID(inf), \
INIT_ID(intersection), \ INIT_ID(intersection), \
INIT_ID(isatty), \ INIT_ID(isatty), \
INIT_ID(isinstance), \
INIT_ID(items), \ INIT_ID(items), \
INIT_ID(iter), \ INIT_ID(iter), \
INIT_ID(join), \ INIT_ID(join), \
@ -893,6 +894,7 @@ extern "C" {
INIT_ID(last_type), \ INIT_ID(last_type), \
INIT_ID(last_value), \ INIT_ID(last_value), \
INIT_ID(latin1), \ INIT_ID(latin1), \
INIT_ID(len), \
INIT_ID(line), \ INIT_ID(line), \
INIT_ID(lineno), \ INIT_ID(lineno), \
INIT_ID(listcomp), \ INIT_ID(listcomp), \

142
Include/opcode.h generated
View file

@ -7,9 +7,9 @@ extern "C" {
/* Instruction opcodes for compiled code */ /* Instruction opcodes for compiled code */
#define CACHE 0
#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
@ -114,75 +114,75 @@ 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 4 #define BINARY_OP_ADAPTIVE 3
#define BINARY_OP_ADD_INT 5 #define BINARY_OP_ADD_INT 4
#define BINARY_OP_ADD_FLOAT 6 #define BINARY_OP_ADD_FLOAT 5
#define BINARY_OP_ADD_UNICODE 7 #define BINARY_OP_ADD_UNICODE 6
#define BINARY_OP_INPLACE_ADD_UNICODE 8 #define BINARY_OP_INPLACE_ADD_UNICODE 7
#define BINARY_OP_MULTIPLY_INT 13 #define BINARY_OP_MULTIPLY_INT 8
#define BINARY_OP_MULTIPLY_FLOAT 14 #define BINARY_OP_MULTIPLY_FLOAT 13
#define BINARY_OP_SUBTRACT_INT 16 #define BINARY_OP_SUBTRACT_INT 14
#define BINARY_OP_SUBTRACT_FLOAT 17 #define BINARY_OP_SUBTRACT_FLOAT 16
#define COMPARE_OP_ADAPTIVE 18 #define COMPARE_OP_ADAPTIVE 17
#define COMPARE_OP_FLOAT_JUMP 19 #define COMPARE_OP_FLOAT_JUMP 18
#define COMPARE_OP_INT_JUMP 20 #define COMPARE_OP_INT_JUMP 19
#define COMPARE_OP_STR_JUMP 21 #define COMPARE_OP_STR_JUMP 20
#define BINARY_SUBSCR_ADAPTIVE 22 #define BINARY_SUBSCR_ADAPTIVE 21
#define BINARY_SUBSCR_GETITEM 23 #define BINARY_SUBSCR_GETITEM 22
#define BINARY_SUBSCR_LIST_INT 24 #define BINARY_SUBSCR_LIST_INT 23
#define BINARY_SUBSCR_TUPLE_INT 26 #define BINARY_SUBSCR_TUPLE_INT 24
#define BINARY_SUBSCR_DICT 27 #define BINARY_SUBSCR_DICT 26
#define STORE_SUBSCR_ADAPTIVE 28 #define STORE_SUBSCR_ADAPTIVE 27
#define STORE_SUBSCR_LIST_INT 29 #define STORE_SUBSCR_LIST_INT 28
#define STORE_SUBSCR_DICT 34 #define STORE_SUBSCR_DICT 29
#define CALL_ADAPTIVE 36 #define CALL_ADAPTIVE 34
#define CALL_PY_EXACT_ARGS 37 #define CALL_PY_EXACT_ARGS 36
#define CALL_PY_WITH_DEFAULTS 38 #define CALL_PY_WITH_DEFAULTS 37
#define JUMP_ABSOLUTE_QUICK 39 #define JUMP_ABSOLUTE_QUICK 38
#define LOAD_ATTR_ADAPTIVE 40 #define LOAD_ATTR_ADAPTIVE 39
#define LOAD_ATTR_INSTANCE_VALUE 41 #define LOAD_ATTR_INSTANCE_VALUE 40
#define LOAD_ATTR_WITH_HINT 42 #define LOAD_ATTR_WITH_HINT 41
#define LOAD_ATTR_SLOT 43 #define LOAD_ATTR_SLOT 42
#define LOAD_ATTR_MODULE 44 #define LOAD_ATTR_MODULE 43
#define LOAD_GLOBAL_ADAPTIVE 45 #define LOAD_GLOBAL_ADAPTIVE 44
#define LOAD_GLOBAL_MODULE 46 #define LOAD_GLOBAL_MODULE 45
#define LOAD_GLOBAL_BUILTIN 47 #define LOAD_GLOBAL_BUILTIN 46
#define LOAD_METHOD_ADAPTIVE 48 #define LOAD_METHOD_ADAPTIVE 47
#define LOAD_METHOD_CLASS 55 #define LOAD_METHOD_CLASS 48
#define LOAD_METHOD_MODULE 56 #define LOAD_METHOD_MODULE 55
#define LOAD_METHOD_NO_DICT 57 #define LOAD_METHOD_NO_DICT 56
#define LOAD_METHOD_WITH_DICT 58 #define LOAD_METHOD_WITH_DICT 57
#define LOAD_METHOD_WITH_VALUES 59 #define LOAD_METHOD_WITH_VALUES 58
#define PRECALL_ADAPTIVE 62 #define PRECALL_ADAPTIVE 59
#define PRECALL_BUILTIN_CLASS 63 #define PRECALL_BUILTIN_CLASS 62
#define PRECALL_NO_KW_BUILTIN_O 64 #define PRECALL_NO_KW_BUILTIN_O 63
#define PRECALL_NO_KW_BUILTIN_FAST 65 #define PRECALL_NO_KW_BUILTIN_FAST 64
#define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 66 #define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 65
#define PRECALL_NO_KW_LEN 67 #define PRECALL_NO_KW_LEN 66
#define PRECALL_NO_KW_ISINSTANCE 72 #define PRECALL_NO_KW_ISINSTANCE 67
#define PRECALL_NO_KW_LIST_APPEND 73 #define PRECALL_NO_KW_LIST_APPEND 72
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 76 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 73
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 77 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 76
#define PRECALL_NO_KW_STR_1 78 #define PRECALL_NO_KW_STR_1 77
#define PRECALL_NO_KW_TUPLE_1 79 #define PRECALL_NO_KW_TUPLE_1 78
#define PRECALL_NO_KW_TYPE_1 80 #define PRECALL_NO_KW_TYPE_1 79
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 81 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 80
#define PRECALL_BOUND_METHOD 140 #define PRECALL_BOUND_METHOD 81
#define PRECALL_PYFUNC 141 #define PRECALL_PYFUNC 140
#define RESUME_QUICK 143 #define RESUME_QUICK 141
#define STORE_ATTR_ADAPTIVE 150 #define STORE_ATTR_ADAPTIVE 143
#define STORE_ATTR_INSTANCE_VALUE 153 #define STORE_ATTR_INSTANCE_VALUE 150
#define STORE_ATTR_SLOT 154 #define STORE_ATTR_SLOT 153
#define STORE_ATTR_WITH_HINT 158 #define STORE_ATTR_WITH_HINT 154
#define UNPACK_SEQUENCE_ADAPTIVE 159 #define UNPACK_SEQUENCE_ADAPTIVE 158
#define UNPACK_SEQUENCE_LIST 161 #define UNPACK_SEQUENCE_LIST 159
#define UNPACK_SEQUENCE_TUPLE 167 #define UNPACK_SEQUENCE_TUPLE 161
#define UNPACK_SEQUENCE_TWO_TUPLE 168 #define UNPACK_SEQUENCE_TWO_TUPLE 167
#define LOAD_FAST__LOAD_FAST 169 #define LOAD_FAST__LOAD_FAST 168
#define STORE_FAST__LOAD_FAST 170 #define STORE_FAST__LOAD_FAST 169
#define LOAD_FAST__LOAD_CONST 173 #define LOAD_FAST__LOAD_CONST 170
#define LOAD_CONST__LOAD_FAST 174 #define LOAD_CONST__LOAD_FAST 173
#define STORE_FAST__STORE_FAST 175 #define STORE_FAST__STORE_FAST 174
#define DO_TRACING 255 #define DO_TRACING 255
extern const uint8_t _PyOpcode_InlineCacheEntries[256]; extern const uint8_t _PyOpcode_InlineCacheEntries[256];
@ -218,6 +218,8 @@ const uint8_t _PyOpcode_InlineCacheEntries[256] = {
[LOAD_GLOBAL] = 5, [LOAD_GLOBAL] = 5,
[BINARY_OP] = 1, [BINARY_OP] = 1,
[LOAD_METHOD] = 10, [LOAD_METHOD] = 10,
[PRECALL] = 1,
[CALL] = 4,
}; };
#endif /* OPCODE_TABLES */ #endif /* OPCODE_TABLES */

View file

@ -393,6 +393,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.11a5 3484 (Use inline caching for LOAD_ATTR, LOAD_METHOD, and # Python 3.11a5 3484 (Use inline caching for LOAD_ATTR, LOAD_METHOD, and
# STORE_ATTR) # STORE_ATTR)
# Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE) # Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
# Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
# Python 3.12 will start with magic number 3500 # Python 3.12 will start with magic number 3500
@ -407,7 +408,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 = (3485).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3486).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

@ -57,9 +57,9 @@ def jabs_op(name, op, entries=0):
# Instruction opcodes for compiled code # Instruction opcodes for compiled code
# Blank lines correspond to available opcodes # Blank lines correspond to available opcodes
def_op('CACHE', 0)
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)
@ -191,9 +191,9 @@ def_op('LIST_EXTEND', 162)
def_op('SET_UPDATE', 163) def_op('SET_UPDATE', 163)
def_op('DICT_MERGE', 164) def_op('DICT_MERGE', 164)
def_op('DICT_UPDATE', 165) def_op('DICT_UPDATE', 165)
def_op('PRECALL', 166) def_op('PRECALL', 166, 1)
def_op('CALL', 171) def_op('CALL', 171, 4)
def_op('KW_NAMES', 172) def_op('KW_NAMES', 172)
hasconst.append(172) hasconst.append(172)

View file

@ -149,10 +149,10 @@ dis_bug708901 = """\
%3d PRECALL 2 %3d PRECALL 2
CALL 2 CALL 2
GET_ITER GET_ITER
>> FOR_ITER 2 (to 32) >> FOR_ITER 2 (to 42)
STORE_FAST 0 (res) STORE_FAST 0 (res)
%3d JUMP_ABSOLUTE 13 (to 26) %3d JUMP_ABSOLUTE 18 (to 36)
%3d >> LOAD_CONST 0 (None) %3d >> LOAD_CONST 0 (None)
RETURN_VALUE RETURN_VALUE
@ -1164,10 +1164,10 @@ expected_opinfo_outer = [
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=46, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=46, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=54, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=64, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_f = [ expected_opinfo_f = [
@ -1191,10 +1191,10 @@ expected_opinfo_f = [
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=44, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=44, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=46, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=46, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=54, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=64, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_inner = [ expected_opinfo_inner = [
@ -1209,153 +1209,152 @@ expected_opinfo_inner = [
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=26, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=26, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=28, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=28, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=36, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=46, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_jumpy = [ expected_opinfo_jumpy = [
Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None), Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=2, starts_line=3, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=2, starts_line=3, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=4, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=4, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='FOR_ITER', opcode=93, arg=28, argval=82, argrepr='to 82', offset=24, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='FOR_ITER', opcode=93, arg=33, argval=102, argrepr='to 102', offset=34, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=26, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=28, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=38, starts_line=4, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=30, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=40, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=42, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=68, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=50, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=70, starts_line=5, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=52, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=72, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=54, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=74, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=64, argrepr='to 64', offset=60, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=42, argval=84, argrepr='to 84', offset=80, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=12, argval=24, argrepr='to 24', offset=62, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=17, argval=34, argrepr='to 34', offset=82, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=84, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=66, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=86, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=68, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=88, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=40, argval=80, argrepr='to 80', offset=74, 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=94, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=76, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=96, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=104, argrepr='to 104', offset=78, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=17, argval=134, argrepr='to 134', offset=98, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=12, argval=24, argrepr='to 24', offset=80, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=17, argval=34, argrepr='to 34', offset=100, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=82, starts_line=10, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=102, starts_line=10, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=84, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=104, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=116, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=98, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=118, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=100, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=102, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=104, starts_line=11, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=134, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=86, argval=172, argrepr='to 172', offset=106, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=106, argval=212, argrepr='to 212', offset=136, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=108, starts_line=12, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=138, starts_line=12, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=140, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=122, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=128, 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='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=130, starts_line=13, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=170, starts_line=13, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=132, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=172, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=134, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=174, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=138, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=178, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=180, starts_line=14, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=142, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=182, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=144, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=184, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=77, argval=154, argrepr='to 154', offset=150, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=97, argval=194, argrepr='to 194', offset=190, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=52, argval=104, argrepr='to 104', offset=152, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=67, argval=134, argrepr='to 134', offset=192, starts_line=15, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=154, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=194, starts_line=16, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=196, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=158, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=198, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=84, argval=168, argrepr='to 168', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=104, argval=208, argrepr='to 208', offset=204, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=194, argrepr='to 194', offset=166, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=18, argval=244, argrepr='to 244', offset=206, starts_line=17, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=168, starts_line=11, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=208, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=54, argval=108, argrepr='to 108', offset=170, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=69, argval=138, argrepr='to 138', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=172, starts_line=19, is_jump_target=True, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=212, starts_line=19, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=174, 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=186, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=190, 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='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=194, starts_line=20, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=196, starts_line=21, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=198, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=200, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=204, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=206, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=212, starts_line=26, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=214, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=214, 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=226, 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=226, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=230, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=242, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=234, starts_line=25, is_jump_target=False, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=244, starts_line=20, is_jump_target=True, 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=5, argval=1, argrepr='1', offset=246, starts_line=21, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=238, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=248, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=240, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=250, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=242, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=254, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=244, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=256, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=270, argrepr='to 270', offset=246, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BEFORE_WITH', opcode=53, 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=248, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=260, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=262, starts_line=26, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=131, argval=262, argrepr='to 262', offset=252, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=264, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=254, 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=276, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=258, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=282, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=262, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=294, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=264, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=296, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=298, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=300, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=324, argrepr='to 324', offset=270, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=274, starts_line=22, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=340, argrepr='to 340', offset=316, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=158, argval=316, argrepr='to 316', offset=286, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=290, starts_line=23, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=166, argval=332, argrepr='to 332', offset=322, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=292, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=324, 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=304, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=332, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=17, argval=350, argrepr='to 350', offset=314, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=336, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=316, starts_line=22, is_jump_target=True, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=338, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=404, argrepr='to 404', offset=340, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=344, starts_line=22, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=324, starts_line=28, is_jump_target=True, positions=None), Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=198, argval=396, argrepr='to 396', offset=356, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=326, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=358, 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=338, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=360, starts_line=23, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=340, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=362, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=342, 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=374, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=376, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=346, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=350, starts_line=23, is_jump_target=True, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=352, starts_line=28, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=22, argval=440, argrepr='to 440', offset=394, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=354, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=396, starts_line=22, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=366, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=400, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=370, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=404, starts_line=28, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=374, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=406, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=376, 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=418, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=382, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=434, 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=394, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=436, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=438, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=440, starts_line=23, is_jump_target=True, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=400, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=442, starts_line=28, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=444, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=404, 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=456, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=406, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=408, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=472, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=474, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=476, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=478, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_NULL', opcode=2, arg=None, argval=None, argrepr='', offset=480, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=482, 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=494, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=496, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=500, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=510, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=512, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=514, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=516, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=518, 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 @@
Use inline caching for :opcode:`PRECALL` and :opcode:`CALL`, and remove the
internal machinery for managing the (now unused) non-inline caches.

View file

@ -1571,10 +1571,7 @@ code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
} }
if (co->co_quickened != NULL) { if (co->co_quickened != NULL) {
Py_ssize_t count = co->co_quickened[0].entry.zero.cache_count; res += PyBytes_GET_SIZE(co->co_code);
count += (PyBytes_GET_SIZE(co->co_code)+sizeof(SpecializedCacheEntry)-1)/
sizeof(SpecializedCacheEntry);
res += count * sizeof(SpecializedCacheEntry);
} }
return PyLong_FromSsize_t(res); return PyLong_FromSsize_t(res);

View file

@ -1,41 +1,46 @@
// Auto-generated by Programs/freeze_test_frozenmain.py // Auto-generated by Programs/freeze_test_frozenmain.py
unsigned char M_test_frozenmain[] = { unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,
0,0,0,0,0,115,136,0,0,0,151,0,100,0,100,1, 0,0,0,0,0,115,176,0,0,0,151,0,100,0,100,1,
108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2,
100,2,166,1,171,1,1,0,2,0,101,2,100,3,101,0, 100,2,166,1,0,0,171,1,0,0,0,0,0,0,0,0,
106,3,3,0,3,0,3,0,3,0,166,2,171,2,1,0, 1,0,2,0,101,2,100,3,101,0,106,3,0,0,0,0,
2,0,101,1,106,4,3,0,3,0,3,0,3,0,166,0, 0,0,0,0,166,2,0,0,171,2,0,0,0,0,0,0,
171,0,100,4,25,0,3,0,3,0,3,0,3,0,90,5, 0,0,1,0,2,0,101,1,106,4,0,0,0,0,0,0,
100,5,68,0,93,20,90,6,2,0,101,2,100,6,101,6, 0,0,166,0,0,0,171,0,0,0,0,0,0,0,0,0,
155,0,100,7,101,5,101,6,25,0,3,0,3,0,3,0, 100,4,25,0,0,0,0,0,0,0,0,0,90,5,100,5,
3,0,155,0,157,4,166,1,171,1,1,0,113,45,100,1, 68,0,93,25,90,6,2,0,101,2,100,6,101,6,155,0,
83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, 100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0,
101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, 155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0,
115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, 0,0,1,0,113,60,100,1,83,0,41,8,233,0,0,0,
41,5,90,12,112,114,111,103,114,97,109,95,110,97,109,101, 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111,
218,10,101,120,101,99,117,116,97,98,108,101,90,15,117,115, 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118,
101,95,101,110,118,105,114,111,110,109,101,110,116,90,17,99, 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103,
111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, 114,97,109,95,110,97,109,101,218,10,101,120,101,99,117,116,
90,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, 97,98,108,101,90,15,117,115,101,95,101,110,118,105,114,111,
122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, 110,109,101,110,116,90,17,99,111,110,102,105,103,117,114,101,
3,115,121,115,90,17,95,116,101,115,116,105,110,116,101,114, 95,99,95,115,116,100,105,111,90,14,98,117,102,102,101,114,
110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, 101,100,95,115,116,100,105,111,122,7,99,111,110,102,105,103,
97,114,103,118,90,11,103,101,116,95,99,111,110,102,105,103, 32,122,2,58,32,41,7,218,3,115,121,115,90,17,95,116,
115,114,2,0,0,0,218,3,107,101,121,169,0,243,0,0, 101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218,
0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, 5,112,114,105,110,116,218,4,97,114,103,118,90,11,103,101,
97,105,110,46,112,121,250,8,60,109,111,100,117,108,101,62, 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3,
114,11,0,0,0,1,0,0,0,115,18,0,0,0,2,128, 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116,
8,3,8,1,12,2,24,1,32,1,8,1,38,7,4,249, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8,
115,20,0,0,0,2,128,8,3,8,1,12,2,24,1,32, 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0,
1,2,7,4,1,2,249,42,7,115,136,0,0,0,0,0, 0,115,18,0,0,0,2,128,8,3,8,1,22,2,34,1,
1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, 42,1,8,1,48,7,4,249,115,20,0,0,0,2,128,8,
1,6,1,6,7,27,1,28,1,28,1,28,1,6,1,6, 3,8,1,22,2,34,1,42,1,2,7,4,1,2,249,52,
7,17,19,22,19,27,19,27,19,27,19,27,19,27,1,28, 7,115,176,0,0,0,0,0,1,11,1,11,1,11,1,11,
1,28,1,28,10,39,10,27,10,39,10,39,10,39,10,39, 1,25,1,25,1,25,1,25,1,6,1,6,7,27,1,28,
10,39,10,41,10,41,42,50,10,51,10,51,10,51,10,51, 1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,6,
10,51,1,7,12,2,1,42,1,42,5,8,5,10,5,10, 1,6,7,17,19,22,19,27,19,27,19,27,19,27,19,27,
11,41,21,24,11,41,11,41,28,34,35,38,28,39,28,39, 1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,28,
28,39,28,39,28,39,11,41,11,41,5,42,5,42,5,42, 10,39,10,27,10,39,10,39,10,39,10,39,10,39,10,41,
10,41,10,41,10,41,10,41,10,41,10,41,42,50,10,51,
10,51,10,51,10,51,10,51,1,7,12,2,1,42,1,42,
5,8,5,10,5,10,11,41,21,24,11,41,11,41,28,34,
35,38,28,39,28,39,28,39,28,39,28,39,11,41,11,41,
5,42,5,42,5,42,5,42,5,42,5,42,5,42,5,42,
5,42,1,42,1,42,114,9,0,0,0, 5,42,1,42,1,42,114,9,0,0,0,
}; };

View file

@ -1321,6 +1321,10 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define JUMPTO(x) (next_instr = first_instr + (x)) #define JUMPTO(x) (next_instr = first_instr + (x))
#define JUMPBY(x) (next_instr += (x)) #define JUMPBY(x) (next_instr += (x))
// Skip from a PRECALL over a CALL to the next instruction:
#define SKIP_CALL() \
JUMPBY(INLINE_CACHE_ENTRIES_PRECALL + 1 + INLINE_CACHE_ENTRIES_CALL)
/* Get opcode and oparg from original instructions, not quickened form. */ /* Get opcode and oparg from original instructions, not quickened form. */
#define TRACING_NEXTOPARG() do { \ #define TRACING_NEXTOPARG() do { \
_Py_CODEUNIT word = ((_Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code))[INSTR_OFFSET()]; \ _Py_CODEUNIT word = ((_Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code))[INSTR_OFFSET()]; \
@ -1431,9 +1435,6 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define JUMP_TO_INSTRUCTION(op) goto PREDICT_ID(op) #define JUMP_TO_INSTRUCTION(op) goto PREDICT_ID(op)
#define GET_CACHE() \
_GetSpecializedCacheEntryForInstruction(first_instr, INSTR_OFFSET(), oparg)
#define DEOPT_IF(cond, instname) if (cond) { goto instname ## _miss; } #define DEOPT_IF(cond, instname) if (cond) { goto instname ## _miss; }
@ -3003,8 +3004,8 @@ handle_eval_breaker:
TARGET(LOAD_GLOBAL_ADAPTIVE) { TARGET(LOAD_GLOBAL_ADAPTIVE) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
uint16_t counter = *next_instr; _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (counter == 0) { if (cache->counter == 0) {
PyObject *name = GETITEM(names, oparg); PyObject *name = GETITEM(names, oparg);
next_instr--; next_instr--;
if (_Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name) < 0) { if (_Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name) < 0) {
@ -3014,7 +3015,7 @@ handle_eval_breaker:
} }
else { else {
STAT_INC(LOAD_GLOBAL, deferred); STAT_INC(LOAD_GLOBAL, deferred);
*next_instr = counter-1; cache->counter--;
JUMP_TO_INSTRUCTION(LOAD_GLOBAL); JUMP_TO_INSTRUCTION(LOAD_GLOBAL);
} }
} }
@ -4563,20 +4564,12 @@ handle_eval_breaker:
We'll be passing `oparg + 1` to call_function, to We'll be passing `oparg + 1` to call_function, to
make it accept the `self` as a first argument. make it accept the `self` as a first argument.
*/ */
int is_method = (PEEK(oparg + 2) != NULL); int is_meth = is_method(stack_pointer, oparg);
int nargs = oparg + is_method; int nargs = oparg + is_meth;
/* Move ownership of reference from stack to call_shape /* Move ownership of reference from stack to call_shape
* and make sure that NULL is cleared from stack */ * and make sure that NULL is cleared from stack */
PyObject *function = PEEK(nargs + 1); PyObject *function = PEEK(nargs + 1);
#ifdef Py_STATS if (!is_meth && Py_TYPE(function) == &PyMethod_Type) {
extern int _PySpecialization_ClassifyCallable(PyObject *);
SpecializationStats *stats =
&_py_stats.opcode_stats[PRECALL].specialization;
stats->failure++;
int kind = _PySpecialization_ClassifyCallable(function);
stats->failure_kinds[kind]++;
#endif
if (!is_method && Py_TYPE(function) == &PyMethod_Type) {
PyObject *meth = ((PyMethodObject *)function)->im_func; PyObject *meth = ((PyMethodObject *)function)->im_func;
PyObject *self = ((PyMethodObject *)function)->im_self; PyObject *self = ((PyMethodObject *)function)->im_self;
Py_INCREF(meth); Py_INCREF(meth);
@ -4585,35 +4578,32 @@ handle_eval_breaker:
PEEK(oparg+2) = meth; PEEK(oparg+2) = meth;
Py_DECREF(function); Py_DECREF(function);
} }
JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
DISPATCH(); DISPATCH();
} }
TARGET(PRECALL_BOUND_METHOD) { TARGET(PRECALL_BOUND_METHOD) {
SpecializedCacheEntry *cache = GET_CACHE(); DEOPT_IF(is_method(stack_pointer, oparg), PRECALL);
int original_oparg = cache->adaptive.original_oparg; PyObject *function = PEEK(oparg + 1);
int is_method = (PEEK(original_oparg + 2) != NULL);
DEOPT_IF(is_method, PRECALL);
PyObject *function = PEEK(original_oparg + 1);
DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, PRECALL); DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, PRECALL);
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
PyObject *meth = ((PyMethodObject *)function)->im_func; PyObject *meth = ((PyMethodObject *)function)->im_func;
PyObject *self = ((PyMethodObject *)function)->im_self; PyObject *self = ((PyMethodObject *)function)->im_self;
Py_INCREF(meth); Py_INCREF(meth);
Py_INCREF(self); Py_INCREF(self);
PEEK(original_oparg+1) = self; PEEK(oparg + 1) = self;
PEEK(original_oparg+2) = meth; PEEK(oparg + 2) = meth;
Py_DECREF(function); Py_DECREF(function);
JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
DISPATCH(); DISPATCH();
} }
TARGET(PRECALL_PYFUNC) { TARGET(PRECALL_PYFUNC) {
SpecializedCacheEntry *cache = GET_CACHE(); int nargs = oparg + is_method(stack_pointer, oparg);
int original_oparg = cache->adaptive.original_oparg;
int is_method = (PEEK(original_oparg + 2) != NULL);
int nargs = original_oparg + is_method;
PyObject *function = PEEK(nargs + 1); PyObject *function = PEEK(nargs + 1);
DEOPT_IF(Py_TYPE(function) != &PyFunction_Type, PRECALL); DEOPT_IF(Py_TYPE(function) != &PyFunction_Type, PRECALL);
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
DISPATCH(); DISPATCH();
} }
@ -4649,6 +4639,7 @@ handle_eval_breaker:
goto error; goto error;
} }
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame; new_frame->previous = frame;
cframe.current_frame = frame = new_frame; cframe.current_frame = frame = new_frame;
CALL_STAT_INC(inlined_py_calls); CALL_STAT_INC(inlined_py_calls);
@ -4680,21 +4671,20 @@ handle_eval_breaker:
if (res == NULL) { if (res == NULL) {
goto error; goto error;
} }
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
CHECK_EVAL_BREAKER(); CHECK_EVAL_BREAKER();
DISPATCH(); DISPATCH();
} }
TARGET(PRECALL_ADAPTIVE) { TARGET(PRECALL_ADAPTIVE) {
SpecializedCacheEntry *cache = GET_CACHE(); _PyPrecallCache *cache = (_PyPrecallCache *)next_instr;
int original_oparg = cache->adaptive.original_oparg; if (cache->counter == 0) {
if (cache->adaptive.counter == 0) {
next_instr--; next_instr--;
int is_meth = is_method(stack_pointer, original_oparg); int is_meth = is_method(stack_pointer, oparg);
int nargs = original_oparg + is_meth; int nargs = oparg + is_meth;
PyObject *callable = PEEK(nargs + 1); PyObject *callable = PEEK(nargs + 1);
int err = _Py_Specialize_Precall( int err = _Py_Specialize_Precall(callable, next_instr, nargs,
callable, next_instr, nargs, call_shape.kwnames, oparg);
call_shape.kwnames, cache, BUILTINS());
if (err < 0) { if (err < 0) {
goto error; goto error;
} }
@ -4702,23 +4692,20 @@ handle_eval_breaker:
} }
else { else {
STAT_INC(PRECALL, deferred); STAT_INC(PRECALL, deferred);
cache->adaptive.counter--; cache->counter--;
oparg = original_oparg;
JUMP_TO_INSTRUCTION(PRECALL); JUMP_TO_INSTRUCTION(PRECALL);
} }
} }
TARGET(CALL_ADAPTIVE) { TARGET(CALL_ADAPTIVE) {
SpecializedCacheEntry *cache = GET_CACHE(); _PyCallCache *cache = (_PyCallCache *)next_instr;
int original_oparg = cache->adaptive.original_oparg; if (cache->counter == 0) {
if (cache->adaptive.counter == 0) {
next_instr--; next_instr--;
int is_meth = is_method(stack_pointer, original_oparg); int is_meth = is_method(stack_pointer, oparg);
int nargs = original_oparg + is_meth; int nargs = oparg + is_meth;
PyObject *callable = PEEK(nargs + 1); PyObject *callable = PEEK(nargs + 1);
int err = _Py_Specialize_Call( int err = _Py_Specialize_Call(callable, next_instr, nargs,
callable, next_instr, nargs, call_shape.kwnames);
call_shape.kwnames, cache);
if (err < 0) { if (err < 0) {
goto error; goto error;
} }
@ -4726,23 +4713,20 @@ handle_eval_breaker:
} }
else { else {
STAT_INC(CALL, deferred); STAT_INC(CALL, deferred);
cache->adaptive.counter--; cache->counter--;
oparg = original_oparg;
goto call_function; goto call_function;
} }
} }
TARGET(CALL_PY_EXACT_ARGS) { TARGET(CALL_PY_EXACT_ARGS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); _PyCallCache *cache = (_PyCallCache *)next_instr;
int original_oparg = caches->adaptive.original_oparg; int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int argcount = oparg + is_meth;
int argcount = original_oparg + is_meth;
PyObject *callable = PEEK(argcount + 1); PyObject *callable = PEEK(argcount + 1);
DEOPT_IF(!PyFunction_Check(callable), CALL); DEOPT_IF(!PyFunction_Check(callable), CALL);
_PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)callable; PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL); DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(code->co_argcount != argcount, CALL); DEOPT_IF(code->co_argcount != argcount, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
@ -4760,6 +4744,7 @@ handle_eval_breaker:
} }
STACK_SHRINK(2-is_meth); STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_frame; frame = cframe.current_frame = new_frame;
goto start_frame; goto start_frame;
@ -4767,18 +4752,16 @@ handle_eval_breaker:
TARGET(CALL_PY_WITH_DEFAULTS) { TARGET(CALL_PY_WITH_DEFAULTS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); _PyCallCache *cache = (_PyCallCache *)next_instr;
int original_oparg = caches->adaptive.original_oparg; int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int argcount = oparg + is_meth;
int argcount = original_oparg + is_meth;
PyObject *callable = PEEK(argcount + 1); PyObject *callable = PEEK(argcount + 1);
DEOPT_IF(!PyFunction_Check(callable), CALL); DEOPT_IF(!PyFunction_Check(callable), CALL);
_PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)callable; PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL); DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(argcount > code->co_argcount, CALL); DEOPT_IF(argcount > code->co_argcount, CALL);
int minargs = cache1->min_args; int minargs = cache->min_args;
DEOPT_IF(argcount < minargs, CALL); DEOPT_IF(argcount < minargs, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
_PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, func); _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, func);
@ -4790,9 +4773,9 @@ handle_eval_breaker:
for (int i = 0; i < argcount; i++) { for (int i = 0; i < argcount; i++) {
new_frame->localsplus[i] = stack_pointer[i]; new_frame->localsplus[i] = stack_pointer[i];
} }
int def_offset = cache1->defaults_len - code->co_argcount;
for (int i = argcount; i < code->co_argcount; i++) { for (int i = argcount; i < code->co_argcount; i++) {
PyObject *def = PyTuple_GET_ITEM(func->func_defaults, i + def_offset); PyObject *def = PyTuple_GET_ITEM(func->func_defaults,
i - minargs);
Py_INCREF(def); Py_INCREF(def);
new_frame->localsplus[i] = def; new_frame->localsplus[i] = def;
} }
@ -4801,6 +4784,7 @@ handle_eval_breaker:
} }
STACK_SHRINK(2-is_meth); STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_frame; frame = cframe.current_frame = new_frame;
goto start_frame; goto start_frame;
@ -4809,13 +4793,13 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_TYPE_1) { TARGET(PRECALL_NO_KW_TYPE_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(GET_CACHE()->adaptive.original_oparg == 1); assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), PRECALL); DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
PyObject *obj = TOP(); PyObject *obj = TOP();
PyObject *callable = SECOND(); PyObject *callable = SECOND();
DEOPT_IF(callable != (PyObject *)&PyType_Type, PRECALL); DEOPT_IF(callable != (PyObject *)&PyType_Type, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyObject *res = Py_NewRef(Py_TYPE(obj)); PyObject *res = Py_NewRef(Py_TYPE(obj));
Py_DECREF(callable); Py_DECREF(callable);
Py_DECREF(obj); Py_DECREF(obj);
@ -4827,12 +4811,12 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_STR_1) { TARGET(PRECALL_NO_KW_STR_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(GET_CACHE()->adaptive.original_oparg == 1); assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), PRECALL); DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
PyObject *callable = PEEK(2); PyObject *callable = PEEK(2);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, PRECALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyObject *arg = TOP(); PyObject *arg = TOP();
PyObject *res = PyObject_Str(arg); PyObject *res = PyObject_Str(arg);
Py_DECREF(arg); Py_DECREF(arg);
@ -4848,12 +4832,12 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_TUPLE_1) { TARGET(PRECALL_NO_KW_TUPLE_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(GET_CACHE()->adaptive.original_oparg == 1); assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), PRECALL); DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
PyObject *callable = PEEK(2); PyObject *callable = PEEK(2);
DEOPT_IF(callable != (PyObject *)&PyTuple_Type, PRECALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyObject *arg = TOP(); PyObject *arg = TOP();
PyObject *res = PySequence_Tuple(arg); PyObject *res = PySequence_Tuple(arg);
Py_DECREF(arg); Py_DECREF(arg);
@ -4868,16 +4852,15 @@ handle_eval_breaker:
} }
TARGET(PRECALL_BUILTIN_CLASS) { TARGET(PRECALL_BUILTIN_CLASS) {
int original_oparg = GET_CACHE()->adaptive.original_oparg; int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int total_args = oparg + is_meth;
int total_args = original_oparg + is_meth;
int kwnames_len = KWNAMES_LEN(); int kwnames_len = KWNAMES_LEN();
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyType_Check(callable), PRECALL); DEOPT_IF(!PyType_Check(callable), PRECALL);
PyTypeObject *tp = (PyTypeObject *)callable; PyTypeObject *tp = (PyTypeObject *)callable;
DEOPT_IF(tp->tp_vectorcall == NULL, PRECALL); DEOPT_IF(tp->tp_vectorcall == NULL, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
STACK_SHRINK(total_args); STACK_SHRINK(total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
total_args-kwnames_len, call_shape.kwnames); total_args-kwnames_len, call_shape.kwnames);
@ -4900,16 +4883,14 @@ handle_eval_breaker:
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_O functions */ /* Builtin METH_O functions */
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); int is_meth = is_method(stack_pointer, oparg);
int original_oparg = caches->adaptive.original_oparg; int total_args = oparg + is_meth;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
DEOPT_IF(total_args != 1, PRECALL); DEOPT_IF(total_args != 1, PRECALL);
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL); DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, PRECALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
// This is slower but CPython promises to check all non-vectorcall // This is slower but CPython promises to check all non-vectorcall
// function calls. // function calls.
@ -4936,16 +4917,14 @@ handle_eval_breaker:
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL functions, without keywords */ /* Builtin METH_FASTCALL functions, without keywords */
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); int is_meth = is_method(stack_pointer, oparg);
int original_oparg = caches->adaptive.original_oparg; int total_args = oparg + is_meth;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL); DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
PRECALL); PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
STACK_SHRINK(total_args); STACK_SHRINK(total_args);
/* res = func(self, args, nargs) */ /* res = func(self, args, nargs) */
@ -4977,16 +4956,14 @@ handle_eval_breaker:
TARGET(PRECALL_BUILTIN_FAST_WITH_KEYWORDS) { TARGET(PRECALL_BUILTIN_FAST_WITH_KEYWORDS) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */ /* Builtin METH_FASTCALL | METH_KEYWORDS functions */
SpecializedCacheEntry *caches = GET_CACHE(); int is_meth = is_method(stack_pointer, oparg);
int original_oparg = caches->adaptive.original_oparg; int total_args = oparg + is_meth;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL); DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
(METH_FASTCALL | METH_KEYWORDS), PRECALL); (METH_FASTCALL | METH_KEYWORDS), PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
STACK_SHRINK(total_args); STACK_SHRINK(total_args);
/* res = func(self, args, nargs, kwnames) */ /* res = func(self, args, nargs, kwnames) */
_PyCFunctionFastWithKeywords cfunc = _PyCFunctionFastWithKeywords cfunc =
@ -5019,16 +4996,14 @@ handle_eval_breaker:
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
/* len(o) */ /* len(o) */
SpecializedCacheEntry *caches = GET_CACHE(); int is_meth = is_method(stack_pointer, oparg);
int original_oparg = caches->adaptive.original_oparg; int total_args = oparg + is_meth;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
DEOPT_IF(total_args != 1, PRECALL); DEOPT_IF(total_args != 1, PRECALL);
_PyObjectCache *cache1 = &caches[-1].obj;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(callable != cache1->obj, PRECALL); PyInterpreterState *interp = _PyInterpreterState_GET();
next_instr++; // Skip following call DEOPT_IF(callable != interp->callable_cache.len, PRECALL);
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyObject *arg = TOP(); PyObject *arg = TOP();
Py_ssize_t len_i = PyObject_Length(arg); Py_ssize_t len_i = PyObject_Length(arg);
if (len_i < 0) { if (len_i < 0) {
@ -5051,17 +5026,14 @@ handle_eval_breaker:
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
/* isinstance(o, o2) */ /* isinstance(o, o2) */
SpecializedCacheEntry *caches = GET_CACHE(); int is_meth = is_method(stack_pointer, oparg);
int original_oparg = caches->adaptive.original_oparg; int total_args = oparg + is_meth;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 2, PRECALL); DEOPT_IF(total_args != 2, PRECALL);
_PyObjectCache *cache1 = &caches[-1].obj; PyInterpreterState *interp = _PyInterpreterState_GET();
DEOPT_IF(callable != interp->callable_cache.isinstance, PRECALL);
DEOPT_IF(callable != cache1->obj, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyObject *cls = POP(); PyObject *cls = POP();
PyObject *inst = TOP(); PyObject *inst = TOP();
int retval = PyObject_IsInstance(inst, cls); int retval = PyObject_IsInstance(inst, cls);
@ -5086,16 +5058,14 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_LIST_APPEND) { TARGET(PRECALL_NO_KW_LIST_APPEND) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(GET_CACHE()->adaptive.original_oparg == 1); assert(oparg == 1);
SpecializedCacheEntry *caches = GET_CACHE();
_PyObjectCache *cache1 = &caches[-1].obj;
assert(cache1->obj != NULL);
PyObject *callable = PEEK(3); PyObject *callable = PEEK(3);
DEOPT_IF(callable != cache1->obj, PRECALL); PyInterpreterState *interp = _PyInterpreterState_GET();
DEOPT_IF(callable != interp->callable_cache.list_append, PRECALL);
PyObject *list = SECOND(); PyObject *list = SECOND();
DEOPT_IF(!PyList_Check(list), PRECALL); DEOPT_IF(!PyList_Check(list), PRECALL);
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
next_instr++; // Skip following call SKIP_CALL();
PyObject *arg = TOP(); PyObject *arg = TOP();
int err = PyList_Append(list, arg); int err = PyList_Append(list, arg);
if (err) { if (err) {
@ -5112,16 +5082,15 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_O) { TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_O) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
int original_oparg = GET_CACHE()->adaptive.original_oparg; int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int total_args = oparg + is_meth;
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 2, PRECALL); DEOPT_IF(total_args != 2, PRECALL);
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_O, PRECALL); DEOPT_IF(meth->ml_flags != METH_O, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyCFunction cfunc = meth->ml_meth; PyCFunction cfunc = meth->ml_meth;
// This is slower but CPython promises to check all non-vectorcall // This is slower but CPython promises to check all non-vectorcall
// function calls. // function calls.
@ -5135,7 +5104,7 @@ handle_eval_breaker:
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self); Py_DECREF(self);
Py_DECREF(arg); Py_DECREF(arg);
STACK_SHRINK(original_oparg+1); STACK_SHRINK(oparg + 1);
SET_TOP(res); SET_TOP(res);
Py_DECREF(callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
@ -5147,17 +5116,16 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
int original_oparg = GET_CACHE()->adaptive.original_oparg; assert(oparg == 0 || oparg == 1);
assert(original_oparg == 0 || original_oparg == 1); int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int total_args = oparg + is_meth;
int total_args = original_oparg + is_meth;
DEOPT_IF(total_args != 1, PRECALL); DEOPT_IF(total_args != 1, PRECALL);
PyObject *callable = SECOND(); PyObject *callable = SECOND();
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_NOARGS, PRECALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
PyCFunction cfunc = meth->ml_meth; PyCFunction cfunc = meth->ml_meth;
// This is slower but CPython promises to check all non-vectorcall // This is slower but CPython promises to check all non-vectorcall
// function calls. // function calls.
@ -5169,7 +5137,7 @@ handle_eval_breaker:
_Py_LeaveRecursiveCall(tstate); _Py_LeaveRecursiveCall(tstate);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self); Py_DECREF(self);
STACK_SHRINK(original_oparg+1); STACK_SHRINK(oparg + 1);
SET_TOP(res); SET_TOP(res);
Py_DECREF(callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
@ -5181,16 +5149,15 @@ handle_eval_breaker:
TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST) { TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
int original_oparg = GET_CACHE()->adaptive.original_oparg; int is_meth = is_method(stack_pointer, oparg);
int is_meth = is_method(stack_pointer, original_oparg); int total_args = oparg + is_meth;
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1); PyObject *callable = PEEK(total_args + 1);
/* Builtin METH_FASTCALL methods, without keywords */ /* Builtin METH_FASTCALL methods, without keywords */
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, PRECALL); DEOPT_IF(meth->ml_flags != METH_FASTCALL, PRECALL);
next_instr++; // Skip following call
STAT_INC(PRECALL, hit); STAT_INC(PRECALL, hit);
SKIP_CALL();
_PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
int nargs = total_args-1; int nargs = total_args-1;
STACK_SHRINK(nargs); STACK_SHRINK(nargs);
@ -5537,22 +5504,6 @@ handle_eval_breaker:
/* Specialization misses */ /* Specialization misses */
#define MISS_WITH_CACHE(opname) \
opname ## _miss: \
{ \
STAT_INC(opcode, miss); \
STAT_INC(opname, miss); \
_PyAdaptiveEntry *cache = &GET_CACHE()->adaptive; \
cache->counter--; \
if (cache->counter == 0) { \
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, _Py_OPARG(next_instr[-1])); \
STAT_INC(opname, deopt); \
cache_backoff(cache); \
} \
oparg = cache->original_oparg; \
JUMP_TO_INSTRUCTION(opname); \
}
#define MISS_WITH_INLINE_CACHE(opname) \ #define MISS_WITH_INLINE_CACHE(opname) \
opname ## _miss: \ opname ## _miss: \
{ \ { \
@ -5588,8 +5539,8 @@ MISS_WITH_INLINE_CACHE(LOAD_ATTR)
MISS_WITH_INLINE_CACHE(STORE_ATTR) MISS_WITH_INLINE_CACHE(STORE_ATTR)
MISS_WITH_INLINE_CACHE(LOAD_GLOBAL) MISS_WITH_INLINE_CACHE(LOAD_GLOBAL)
MISS_WITH_INLINE_CACHE(LOAD_METHOD) MISS_WITH_INLINE_CACHE(LOAD_METHOD)
MISS_WITH_CACHE(PRECALL) MISS_WITH_INLINE_CACHE(PRECALL)
MISS_WITH_CACHE(CALL) MISS_WITH_INLINE_CACHE(CALL)
MISS_WITH_INLINE_CACHE(BINARY_OP) MISS_WITH_INLINE_CACHE(BINARY_OP)
MISS_WITH_INLINE_CACHE(COMPARE_OP) MISS_WITH_INLINE_CACHE(COMPARE_OP)
MISS_WITH_INLINE_CACHE(BINARY_SUBSCR) MISS_WITH_INLINE_CACHE(BINARY_SUBSCR)

View file

@ -1,21 +1,20 @@
static void *opcode_targets[256] = { static void *opcode_targets[256] = {
&&_unknown_opcode, &&TARGET_CACHE,
&&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_UNARY_INVERT,
&&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_OP_SUBTRACT_INT,
&&TARGET_UNARY_INVERT,
&&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,
@ -24,18 +23,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,
&&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT,
&&TARGET_BINARY_SUBSCR,
&&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_STORE_SUBSCR_DICT,
&&TARGET_PUSH_EXC_INFO,
&&TARGET_CALL_ADAPTIVE, &&TARGET_CALL_ADAPTIVE,
&&TARGET_PUSH_EXC_INFO,
&&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,
@ -48,39 +47,40 @@ 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_ISINSTANCE,
&&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_PRECALL_NO_KW_LIST_APPEND,
&&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O,
&&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_LOAD_ASSERTION_ERROR,
&&TARGET_RETURN_GENERATOR, &&TARGET_RETURN_GENERATOR,
&&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_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST,
&&TARGET_PRECALL_BOUND_METHOD,
&&TARGET_LIST_TO_TUPLE, &&TARGET_LIST_TO_TUPLE,
&&TARGET_RETURN_VALUE, &&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR, &&TARGET_IMPORT_STAR,
@ -139,40 +139,39 @@ 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_CALL_FUNCTION_EX,
&&TARGET_RESUME_QUICK, &&TARGET_RESUME_QUICK,
&&TARGET_CALL_FUNCTION_EX,
&&TARGET_STORE_ATTR_ADAPTIVE,
&&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_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&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_LOAD_METHOD,
&&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_LIST,
&&TARGET_LOAD_METHOD,
&&TARGET_UNPACK_SEQUENCE_TUPLE,
&&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,
&&_unknown_opcode, &&_unknown_opcode,
@ -254,5 +253,6 @@ 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

@ -774,6 +774,16 @@ pycore_init_builtins(PyThreadState *tstate)
Py_INCREF(builtins_dict); Py_INCREF(builtins_dict);
interp->builtins = builtins_dict; interp->builtins = builtins_dict;
PyObject *isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance));
assert(isinstance);
interp->callable_cache.isinstance = isinstance;
PyObject *len = PyDict_GetItem(builtins_dict, &_Py_ID(len));
assert(len);
interp->callable_cache.len = len;
PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append));
assert(list_append);
interp->callable_cache.list_append = list_append;
if (_PyBuiltins_AddExceptions(bimod) < 0) { if (_PyBuiltins_AddExceptions(bimod) < 0) {
return _PyStatus_ERR("failed to add exceptions to builtins"); return _PyStatus_ERR("failed to add exceptions to builtins");
} }

View file

@ -56,13 +56,6 @@ static uint8_t adaptive_opcodes[256] = {
[UNPACK_SEQUENCE] = UNPACK_SEQUENCE_ADAPTIVE, [UNPACK_SEQUENCE] = UNPACK_SEQUENCE_ADAPTIVE,
}; };
/* The number of cache entries required for a "family" of instructions. */
static uint8_t cache_requirements[256] = {
[STORE_SUBSCR] = 0,
[CALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
[PRECALL] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
};
Py_ssize_t _Py_QuickenedCount = 0; Py_ssize_t _Py_QuickenedCount = 0;
#ifdef Py_STATS #ifdef Py_STATS
PyStats _py_stats = { 0 }; PyStats _py_stats = { 0 };
@ -282,137 +275,41 @@ _Py_PrintSpecializationStats(int to_file)
#define SPECIALIZATION_FAIL(opcode, kind) ((void)0) #define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
#endif #endif
static SpecializedCacheOrInstruction * static _Py_CODEUNIT *
allocate(int cache_count, int instruction_count) allocate(int instruction_count)
{ {
assert(sizeof(SpecializedCacheOrInstruction) == 2*sizeof(int32_t));
assert(sizeof(SpecializedCacheEntry) == 2*sizeof(int32_t));
assert(cache_count > 0);
assert(instruction_count > 0); assert(instruction_count > 0);
int count = cache_count + (instruction_count + INSTRUCTIONS_PER_ENTRY -1)/INSTRUCTIONS_PER_ENTRY; void *array = PyMem_Malloc(sizeof(_Py_CODEUNIT) * instruction_count);
SpecializedCacheOrInstruction *array = (SpecializedCacheOrInstruction *)
PyMem_Malloc(sizeof(SpecializedCacheOrInstruction) * count);
if (array == NULL) { if (array == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return NULL;
} }
_Py_QuickenedCount++; _Py_QuickenedCount++;
array[0].entry.zero.cache_count = cache_count; return (_Py_CODEUNIT *)array;
return array;
} }
static int
get_cache_count(SpecializedCacheOrInstruction *quickened) {
return quickened[0].entry.zero.cache_count;
}
/* Return the oparg for the cache_offset and instruction index. // Insert adaptive instructions and superinstructions.
*
* If no cache is needed then return the original oparg.
* If a cache is needed, but cannot be accessed because
* oparg would be too large, then return -1.
*
* Also updates the cache_offset, as it may need to be incremented by
* more than the cache requirements, if many instructions do not need caches.
*
* See pycore_code.h for details of how the cache offset,
* instruction index and oparg are related */
static int
oparg_from_instruction_and_update_offset(int index, int opcode, int original_oparg, int *cache_offset) {
/* The instruction pointer in the interpreter points to the next
* instruction, so we compute the offset using nexti (index + 1) */
int nexti = index + 1;
uint8_t need = cache_requirements[opcode];
if (need == 0) {
return original_oparg;
}
assert(adaptive_opcodes[opcode] != 0);
int oparg = oparg_from_offset_and_nexti(*cache_offset, nexti);
assert(*cache_offset == offset_from_oparg_and_nexti(oparg, nexti));
/* Some cache space is wasted here as the minimum possible offset is (nexti>>1) */
if (oparg < 0) {
oparg = 0;
*cache_offset = offset_from_oparg_and_nexti(oparg, nexti);
}
else if (oparg > 255) {
return -1;
}
*cache_offset += need;
return oparg;
}
static int
entries_needed(const _Py_CODEUNIT *code, int len)
{
int cache_offset = 0;
int previous_opcode = -1;
for (int i = 0; i < len; i++) {
uint8_t opcode = _Py_OPCODE(code[i]);
if (previous_opcode != EXTENDED_ARG) {
oparg_from_instruction_and_update_offset(i, opcode, 0, &cache_offset);
}
previous_opcode = opcode;
}
return cache_offset + 1; // One extra for the count entry
}
static inline _Py_CODEUNIT *
first_instruction(SpecializedCacheOrInstruction *quickened)
{
return &quickened[get_cache_count(quickened)].code[0];
}
/** Insert adaptive instructions and superinstructions.
*
* Skip instruction preceded by EXTENDED_ARG for adaptive
* instructions as those are both very rare and tricky
* to handle.
*/
static void static void
optimize(SpecializedCacheOrInstruction *quickened, int len) optimize(_Py_CODEUNIT *instructions, int len)
{ {
_Py_CODEUNIT *instructions = first_instruction(quickened);
int cache_offset = 0;
int previous_opcode = -1; int previous_opcode = -1;
int previous_oparg = 0; int previous_oparg = -1;
for(int i = 0; i < len; i++) { for(int i = 0; i < len; i++) {
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) { if (adaptive_opcode) {
if (_PyOpcode_InlineCacheEntries[opcode]) { instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg); int caches = _PyOpcode_InlineCacheEntries[opcode];
previous_opcode = -1; // Make sure the adaptive counter is zero:
i += _PyOpcode_InlineCacheEntries[opcode]; assert((caches ? instructions[i + 1] : oparg) == 0);
} previous_opcode = -1;
else if (previous_opcode != EXTENDED_ARG) { previous_oparg = -1;
int new_oparg = oparg_from_instruction_and_update_offset( i += caches;
i, opcode, oparg, &cache_offset
);
if (new_oparg < 0) {
/* Not possible to allocate a cache for this instruction */
previous_opcode = opcode;
continue;
}
previous_opcode = adaptive_opcode;
int entries_needed = cache_requirements[opcode];
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);
}
} }
else { else {
/* Super instructions don't use the cache, assert(!_PyOpcode_InlineCacheEntries[opcode]);
* so no need to update the offset. */
switch (opcode) { switch (opcode) {
case JUMP_ABSOLUTE: case JUMP_ABSOLUTE:
instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg); instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg);
@ -423,23 +320,28 @@ optimize(SpecializedCacheOrInstruction *quickened, int len)
case LOAD_FAST: case LOAD_FAST:
switch(previous_opcode) { switch(previous_opcode) {
case LOAD_FAST: case LOAD_FAST:
assert(0 <= previous_oparg);
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, previous_oparg); instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, previous_oparg);
break; break;
case STORE_FAST: case STORE_FAST:
assert(0 <= previous_oparg);
instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__LOAD_FAST, previous_oparg); instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__LOAD_FAST, previous_oparg);
break; break;
case LOAD_CONST: case LOAD_CONST:
assert(0 <= previous_oparg);
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_CONST__LOAD_FAST, previous_oparg); instructions[i-1] = _Py_MAKECODEUNIT(LOAD_CONST__LOAD_FAST, previous_oparg);
break; break;
} }
break; break;
case STORE_FAST: case STORE_FAST:
if (previous_opcode == STORE_FAST) { if (previous_opcode == STORE_FAST) {
assert(0 <= previous_oparg);
instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__STORE_FAST, previous_oparg); instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__STORE_FAST, previous_oparg);
} }
break; break;
case LOAD_CONST: case LOAD_CONST:
if (previous_opcode == LOAD_FAST) { if (previous_opcode == LOAD_FAST) {
assert(0 <= previous_oparg);
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_CONST, previous_oparg); instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_CONST, previous_oparg);
} }
break; break;
@ -448,7 +350,6 @@ optimize(SpecializedCacheOrInstruction *quickened, int len)
previous_oparg = oparg; previous_oparg = oparg;
} }
} }
assert(cache_offset+1 == get_cache_count(quickened));
} }
int int
@ -462,16 +363,14 @@ _Py_Quicken(PyCodeObject *code) {
code->co_warmup = QUICKENING_WARMUP_COLDEST; code->co_warmup = QUICKENING_WARMUP_COLDEST;
return 0; return 0;
} }
int entry_count = entries_needed(code->co_firstinstr, instr_count); _Py_CODEUNIT *quickened = allocate(instr_count);
SpecializedCacheOrInstruction *quickened = allocate(entry_count, instr_count);
if (quickened == NULL) { if (quickened == NULL) {
return -1; return -1;
} }
_Py_CODEUNIT *new_instructions = first_instruction(quickened); memcpy(quickened, code->co_firstinstr, size);
memcpy(new_instructions, code->co_firstinstr, size);
optimize(quickened, instr_count); optimize(quickened, instr_count);
code->co_quickened = quickened; code->co_quickened = quickened;
code->co_firstinstr = new_instructions; code->co_firstinstr = quickened;
return 0; return 0;
} }
@ -1516,9 +1415,8 @@ success:
} }
static int static int
specialize_class_call( specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *callable, _Py_CODEUNIT *instr, PyObject *kwnames, int oparg)
int nargs, PyObject *kwnames, SpecializedCacheEntry *cache)
{ {
assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE); assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE);
PyTypeObject *tp = _PyType_CAST(callable); PyTypeObject *tp = _PyType_CAST(callable);
@ -1527,7 +1425,7 @@ specialize_class_call(
return -1; return -1;
} }
if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
if (nargs == 1 && kwnames == NULL && cache->adaptive.original_oparg == 1) { if (nargs == 1 && kwnames == NULL && oparg == 1) {
if (tp == &PyUnicode_Type) { if (tp == &PyUnicode_Type) {
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_STR_1, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_STR_1, _Py_OPARG(*instr));
return 0; return 0;
@ -1577,28 +1475,15 @@ builtin_call_fail_kind(int ml_flags)
} }
#endif #endif
static PyMethodDescrObject *_list_append = NULL;
static int static int
specialize_method_descriptor( specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
PyMethodDescrObject *descr, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames, int oparg)
int nargs, PyObject *kwnames, SpecializedCacheEntry *cache)
{ {
assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE); assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE);
if (kwnames) { if (kwnames) {
SPECIALIZATION_FAIL(PRECALL, SPEC_FAIL_CALL_KWNAMES); SPECIALIZATION_FAIL(PRECALL, SPEC_FAIL_CALL_KWNAMES);
return -1; return -1;
} }
if (_list_append == NULL) {
_list_append = (PyMethodDescrObject *)_PyType_Lookup(&PyList_Type,
&_Py_ID(append));
}
assert(_list_append != NULL);
if (nargs == 2 && descr == _list_append && cache->adaptive.original_oparg == 1) {
cache[-1].obj.obj = (PyObject *)_list_append;
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_LIST_APPEND, _Py_OPARG(*instr));
return 0;
}
switch (descr->d_method->ml_flags & switch (descr->d_method->ml_flags &
(METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
@ -1614,9 +1499,16 @@ specialize_method_descriptor(
} }
case METH_O: { case METH_O: {
if (nargs != 2) { if (nargs != 2) {
SPECIALIZATION_FAIL(PRECALL, SPEC_FAIL_OUT_OF_RANGE); SPECIALIZATION_FAIL(PRECALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
return -1; return -1;
} }
PyInterpreterState *interp = _PyInterpreterState_GET();
PyObject *list_append = interp->callable_cache.list_append;
if ((PyObject *)descr == list_append && oparg == 1) {
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_LIST_APPEND,
_Py_OPARG(*instr));
return 0;
}
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_METHOD_DESCRIPTOR_O, *instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_METHOD_DESCRIPTOR_O,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
@ -1632,12 +1524,11 @@ specialize_method_descriptor(
} }
static int static int
specialize_py_call( specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
PyFunctionObject *func, _Py_CODEUNIT *instr, PyObject *kwnames)
int nargs, PyObject *kwnames, SpecializedCacheEntry *cache)
{ {
_PyCallCache *cache = (_PyCallCache *)(instr + 1);
assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE); assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
_PyCallCache *cache1 = &cache[-1].call;
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
int kind = function_kind(code); int kind = function_kind(code);
if (kwnames) { if (kwnames) {
@ -1649,10 +1540,6 @@ specialize_py_call(
return -1; return -1;
} }
int argcount = code->co_argcount; int argcount = code->co_argcount;
if (argcount > 0xffff) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE);
return -1;
}
int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
assert(defcount <= argcount); assert(defcount <= argcount);
int min_args = argcount-defcount; int min_args = argcount-defcount;
@ -1663,7 +1550,7 @@ specialize_py_call(
assert(nargs <= argcount && nargs >= min_args); assert(nargs <= argcount && nargs >= min_args);
assert(min_args >= 0 && defcount >= 0); assert(min_args >= 0 && defcount >= 0);
assert(defcount == 0 || func->func_defaults != NULL); assert(defcount == 0 || func->func_defaults != NULL);
if (min_args > 0xffff || defcount > 0xffff) { if (min_args > 0xffff) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE); SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE);
return -1; return -1;
} }
@ -1672,10 +1559,8 @@ specialize_py_call(
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS);
return -1; return -1;
} }
cache[0].adaptive.index = nargs; write_u32(cache->func_version, version);
cache1->func_version = version; cache->min_args = min_args;
cache1->min_args = min_args;
cache1->defaults_len = defcount;
if (argcount == nargs) { if (argcount == nargs) {
*instr = _Py_MAKECODEUNIT(CALL_PY_EXACT_ARGS, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(CALL_PY_EXACT_ARGS, _Py_OPARG(*instr));
} }
@ -1687,10 +1572,9 @@ specialize_py_call(
static int static int
specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *kwnames, SpecializedCacheEntry *cache, PyObject *builtins) PyObject *kwnames)
{ {
assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE); assert(_Py_OPCODE(*instr) == PRECALL_ADAPTIVE);
_PyObjectCache *cache1 = &cache[-1].obj;
if (PyCFunction_GET_FUNCTION(callable) == NULL) { if (PyCFunction_GET_FUNCTION(callable) == NULL) {
return 1; return 1;
} }
@ -1707,9 +1591,8 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
return 1; return 1;
} }
/* len(o) */ /* len(o) */
PyObject *builtin_len = PyDict_GetItemString(builtins, "len"); PyInterpreterState *interp = _PyInterpreterState_GET();
if (callable == builtin_len) { if (callable == interp->callable_cache.len) {
cache1->obj = builtin_len; // borrowed
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_LEN, *instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_LEN,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
@ -1725,10 +1608,8 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
} }
if (nargs == 2) { if (nargs == 2) {
/* isinstance(o1, o2) */ /* isinstance(o1, o2) */
PyObject *builtin_isinstance = PyDict_GetItemString( PyInterpreterState *interp = _PyInterpreterState_GET();
builtins, "isinstance"); if (callable == interp->callable_cache.isinstance) {
if (callable == builtin_isinstance) {
cache1->obj = builtin_isinstance; // borrowed
*instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_ISINSTANCE, *instr = _Py_MAKECODEUNIT(PRECALL_NO_KW_ISINSTANCE,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
@ -1793,44 +1674,44 @@ call_fail_kind(PyObject *callable)
int int
_Py_Specialize_Precall( _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *callable, _Py_CODEUNIT *instr, PyObject *kwnames, int oparg)
int nargs, PyObject *kwnames,
SpecializedCacheEntry *cache, PyObject *builtins)
{ {
_PyAdaptiveEntry *cache0 = &cache->adaptive; assert(_PyOpcode_InlineCacheEntries[PRECALL] ==
INLINE_CACHE_ENTRIES_PRECALL);
_PyPrecallCache *cache = (_PyPrecallCache *)(instr + 1);
int fail; int fail;
if (PyCFunction_CheckExact(callable)) { if (PyCFunction_CheckExact(callable)) {
fail = specialize_c_call(callable, instr, nargs, kwnames, cache, builtins); fail = specialize_c_call(callable, instr, nargs, kwnames);
} }
else if (PyFunction_Check(callable)) { else if (PyFunction_Check(callable)) {
*instr = _Py_MAKECODEUNIT(PRECALL_PYFUNC, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(PRECALL_PYFUNC, _Py_OPARG(*instr));
fail = 0; fail = 0;
} }
else if (PyType_Check(callable)) { else if (PyType_Check(callable)) {
fail = specialize_class_call(callable, instr, nargs, kwnames, cache); fail = specialize_class_call(callable, instr, nargs, kwnames, oparg);
} }
else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
fail = specialize_method_descriptor( fail = specialize_method_descriptor((PyMethodDescrObject *)callable,
(PyMethodDescrObject *)callable, instr, nargs, kwnames, cache); instr, nargs, kwnames, oparg);
} }
else if (Py_TYPE(callable) == &PyMethod_Type) { else if (Py_TYPE(callable) == &PyMethod_Type) {
*instr = _Py_MAKECODEUNIT(PRECALL_BOUND_METHOD, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(PRECALL_BOUND_METHOD, _Py_OPARG(*instr));
fail = 0; fail = 0;
} }
else { else {
SPECIALIZATION_FAIL(CALL, call_fail_kind(callable)); SPECIALIZATION_FAIL(PRECALL, call_fail_kind(callable));
fail = -1; fail = -1;
} }
if (fail) { if (fail) {
STAT_INC(CALL, failure); STAT_INC(PRECALL, failure);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache_backoff(cache0); cache->counter = ADAPTIVE_CACHE_BACKOFF;
} }
else { else {
STAT_INC(CALL, success); STAT_INC(PRECALL, success);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache0->counter = initial_counter_value(); cache->counter = initial_counter_value();
} }
return 0; return 0;
} }
@ -1840,15 +1721,15 @@ _Py_Specialize_Precall(
- Specialize calling classes. - Specialize calling classes.
*/ */
int int
_Py_Specialize_Call( _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
PyObject *callable, _Py_CODEUNIT *instr, PyObject *kwnames)
int nargs, PyObject *kwnames,
SpecializedCacheEntry *cache)
{ {
_PyAdaptiveEntry *cache0 = &cache->adaptive; assert(_PyOpcode_InlineCacheEntries[CALL] == INLINE_CACHE_ENTRIES_CALL);
_PyCallCache *cache = (_PyCallCache *)(instr + 1);
int fail; int fail;
if (PyFunction_Check(callable)) { if (PyFunction_Check(callable)) {
fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs, kwnames, cache); fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs,
kwnames);
} }
else { else {
SPECIALIZATION_FAIL(CALL, call_fail_kind(callable)); SPECIALIZATION_FAIL(CALL, call_fail_kind(callable));
@ -1857,12 +1738,12 @@ _Py_Specialize_Call(
if (fail) { if (fail) {
STAT_INC(CALL, failure); STAT_INC(CALL, failure);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache_backoff(cache0); cache->counter = ADAPTIVE_CACHE_BACKOFF;
} }
else { else {
STAT_INC(CALL, success); STAT_INC(CALL, success);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache0->counter = initial_counter_value(); cache->counter = initial_counter_value();
} }
return 0; return 0;
} }
@ -2238,10 +2119,4 @@ int
return SPEC_FAIL_OTHER; return SPEC_FAIL_OTHER;
} }
int
_PySpecialization_ClassifyCallable(PyObject *callable)
{
return call_fail_kind(callable);
}
#endif #endif