JitOptRef *n_consumed;
JitOptRef *limit;
JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
+ _PyUOpInstruction *out_buffer;
+ int out_len;
} JitOptContext;
_PyJitTracerTranslatorState translator_state;
JitOptContext opt_context;
_PyUOpInstruction code_buffer[UOP_MAX_TRACE_LENGTH];
+ _PyUOpInstruction out_buffer[UOP_MAX_TRACE_LENGTH];
} _PyJitTracerState;
#endif
if (length <= 0) {
return length;
}
+ buffer = _tstate->jit_tracer_state->out_buffer;
}
assert(length < UOP_MAX_TRACE_LENGTH/2);
assert(length >= 1);
#define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack))
#define STACK_SIZE() ((int)(ctx->frame->stack_len))
+static inline int
+is_terminator_uop(const _PyUOpInstruction *uop)
+{
+ int opcode = uop->opcode;
+ return (
+ opcode == _EXIT_TRACE ||
+ opcode == _JUMP_TO_TOP ||
+ opcode == _DYNAMIC_EXIT ||
+ opcode == _DEOPT
+ );
+}
+
#define CURRENT_FRAME_IS_INIT_SHIM() (ctx->frame->code == ((PyCodeObject *)&_Py_InitCleanup))
#define GETLOCAL(idx) ((ctx->frame->locals[idx]))
(INST)->oparg = ARG; \
(INST)->operand0 = OPERAND;
+#define ADD_OP(OP, ARG, OPERAND) add_op(ctx, this_instr, (OP), (ARG), (OPERAND))
+
+static inline void
+add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
+ uint16_t opcode, uint16_t oparg, uintptr_t operand0)
+{
+ _PyUOpInstruction *out = &ctx->out_buffer[ctx->out_len];
+ out->opcode = (opcode);
+ out->format = this_instr->format;
+ out->oparg = (oparg);
+ out->target = this_instr->target;
+ out->operand0 = (operand0);
+ out->operand1 = this_instr->operand1;
+ ctx->out_len++;
+}
+
/* Shortened forms for convenience, used in optimizer_bytecodes.c */
#define sym_is_not_null _Py_uop_sym_is_not_null
#define sym_is_const _Py_uop_sym_is_const
bool insert_mode)
{
if (sym_matches_type(value, &PyBool_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
*result_ptr = value;
return 1;
}
int opcode = insert_mode ?
_INSERT_1_LOAD_CONST_INLINE_BORROW :
_POP_TOP_LOAD_CONST_INLINE_BORROW;
- REPLACE_OP(this_instr, opcode, 0, (uintptr_t)load);
+ ADD_OP(opcode, 0, (uintptr_t)load);
*result_ptr = sym_new_const(ctx, load);
return 1;
}
}
static void
-eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
+eliminate_pop_guard(_PyUOpInstruction *this_instr, JitOptContext *ctx, bool exit)
{
- REPLACE_OP(this_instr, _POP_TOP, 0, 0);
+ ADD_OP(_POP_TOP, 0, 0);
if (exit) {
REPLACE_OP((this_instr+1), _EXIT_TRACE, 0, 0);
this_instr[1].target = this_instr->target;
PyObject *lookup = _PyType_Lookup(type, name);
if (lookup) {
int opcode = _Py_IsImmortal(lookup) ? immortal : mortal;
- REPLACE_OP(this_instr, opcode, 0, (uintptr_t)lookup);
+ ADD_OP(opcode, 0, (uintptr_t)lookup);
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type);
_Py_BloomFilter_Add(dependencies, type);
return sym_new_const(ctx, lookup);
JitOptContext *ctx = &tstate->jit_tracer_state->opt_context;
uint32_t opcode = UINT16_MAX;
+ ctx->out_buffer = tstate->jit_tracer_state->out_buffer;
+
// Make sure that watchers are set up
PyInterpreterState *interp = _PyInterpreterState_GET();
if (interp->dict_state.watchers[GLOBALS_WATCHER_ID] == NULL) {
ctx->curr_frame_depth++;
ctx->frame = frame;
+ ctx->out_len = 0;
+
_PyUOpInstruction *this_instr = NULL;
JitOptRef *stack_pointer = ctx->frame->stack_pointer;
DPRINTF(1, "\nUnknown opcode in abstract interpreter\n");
Py_UNREACHABLE();
}
+ // If no ADD_OP was called during this iteration, copy the original instruction
+ if (ctx->out_len == i) {
+ ctx->out_buffer[ctx->out_len++] = *this_instr;
+ }
assert(ctx->frame != NULL);
if (!CURRENT_FRAME_IS_INIT_SHIM()) {
DPRINTF(3, " stack_level %d\n", STACK_LEVEL());
/* Either reached the end or cannot optimize further, but there
* would be no benefit in retrying later */
_Py_uop_abstractcontext_fini(ctx);
- return trace_len;
+ // Check that the trace ends with a proper terminator
+ if (ctx->out_len > 0) {
+ _PyUOpInstruction *last_uop = &ctx->out_buffer[ctx->out_len - 1];
+ if (!is_terminator_uop(last_uop)) {
+ // Copy remaining uops from original trace until we find a terminator
+ for (int i = ctx->out_len; i < trace_len; i++) {
+ ctx->out_buffer[ctx->out_len++] = trace[i];
+ if (is_terminator_uop(&trace[i])) {
+ break;
+ }
+ }
+ }
+ }
+
+ return ctx->out_len;
error:
DPRINTF(3, "\n");
assert(length > 0);
- length = remove_unneeded_uops(buffer, length);
+ length = remove_unneeded_uops(tstate->jit_tracer_state->out_buffer, length);
assert(length > 0);
OPT_STAT_INC(optimizer_successes);
bool insert_mode);
extern void
-eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit);
+eliminate_pop_guard(_PyUOpInstruction *this_instr, JitOptContext *ctx, bool exit);
extern PyCodeObject *get_code(_PyUOpInstruction *op);
op(_GUARD_TOS_INT, (value -- value)) {
if (sym_is_compact_int(value)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
if (sym_get_type(value) == &PyLong_Type) {
- REPLACE_OP(this_instr, _GUARD_TOS_OVERFLOWED, 0, 0);
+ ADD_OP(_GUARD_TOS_OVERFLOWED, 0, 0);
}
sym_set_compact_int(value);
}
op(_GUARD_NOS_INT, (left, unused -- left, unused)) {
if (sym_is_compact_int(left)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
if (sym_get_type(left) == &PyLong_Type) {
- REPLACE_OP(this_instr, _GUARD_NOS_OVERFLOWED, 0, 0);
+ ADD_OP(_GUARD_NOS_OVERFLOWED, 0, 0);
}
sym_set_compact_int(left);
}
PyObject *type = (PyObject *)_PyType_LookupByVersion(type_version);
if (type) {
if (type == sym_get_const(ctx, owner)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
sym_set_const(owner, type);
op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) {
assert(type_version);
if (sym_matches_type_version(owner, type_version)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
} else {
// add watcher so that whenever the type changes we invalidate this
PyTypeObject *type = _PyType_LookupByVersion(type_version);
op(_GUARD_TOS_FLOAT, (value -- value)) {
if (sym_matches_type(value, &PyFloat_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(value, &PyFloat_Type);
}
op(_GUARD_NOS_FLOAT, (left, unused -- left, unused)) {
if (sym_matches_type(left, &PyFloat_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(left, &PyFloat_Type);
}
assert(index >= 0);
int tuple_length = sym_tuple_length(tuple_st);
if (tuple_length != -1 && index < tuple_length) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
}
op(_GUARD_NOS_UNICODE, (nos, unused -- nos, unused)) {
if (sym_matches_type(nos, &PyUnicode_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyUnicode_Type);
}
op(_GUARD_TOS_UNICODE, (value -- value)) {
if (sym_matches_type(value, &PyUnicode_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(value, &PyUnicode_Type);
}
op(_LOAD_CONST, (-- value)) {
PyCodeObject *co = get_current_code_object(ctx);
PyObject *val = PyTuple_GET_ITEM(co->co_consts, oparg);
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
}
PyObject *val = PyLong_FromLong(oparg);
assert(val);
assert(_Py_IsImmortal(val));
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
}
if (PyJitRef_IsBorrowed(value) ||
sym_is_immortal(PyJitRef_Unwrap(value)) ||
sym_is_null(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
else if (typ == &PyLong_Type) {
- REPLACE_OP(this_instr, _POP_TOP_INT, 0, 0);
+ ADD_OP(_POP_TOP_INT, 0, 0);
}
else if (typ == &PyFloat_Type) {
- REPLACE_OP(this_instr, _POP_TOP_FLOAT, 0, 0);
+ ADD_OP(_POP_TOP_FLOAT, 0, 0);
}
else if (typ == &PyUnicode_Type) {
- REPLACE_OP(this_instr, _POP_TOP_UNICODE, 0, 0);
+ ADD_OP(_POP_TOP_UNICODE, 0, 0);
}
}
op(_POP_TOP_INT, (value --)) {
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
}
op(_POP_TOP_FLOAT, (value --)) {
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
}
op(_POP_TOP_UNICODE, (value --)) {
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
}
op (_PUSH_NULL_CONDITIONAL, ( -- null[oparg & 1])) {
if (oparg & 1) {
- REPLACE_OP(this_instr, _PUSH_NULL, 0, 0);
+ ADD_OP(_PUSH_NULL, 0, 0);
null[0] = sym_new_null(ctx);
}
else {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
assert(PyFunction_Check(sym_get_const(ctx, callable)));
- REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
- this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
+ ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
+ ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)sym_get_const(ctx, callable);
}
sym_set_type(callable, &PyFunction_Type);
}
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyMethod_Type)) {
PyMethodObject *method = (PyMethodObject *)sym_get_const(ctx, callable);
assert(PyMethod_Check(method));
- REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
- this_instr->operand1 = (uintptr_t)method->im_func;
+ ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
+ ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)method->im_func;
}
sym_set_type(callable, &PyMethod_Type);
}
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(ctx, callable);
PyCodeObject *co = (PyCodeObject *)func->func_code;
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
- REPLACE_OP(this_instr, _NOP, 0 ,0);
+ ADD_OP(_NOP, 0 ,0);
}
}
}
op(_ITER_CHECK_TUPLE, (iter, null_or_index -- iter, null_or_index)) {
if (sym_matches_type(iter, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(iter, &PyTuple_Type);
}
PyObject* type = (PyObject *)sym_get_type(arg);
if (type) {
res = sym_new_const(ctx, type);
- REPLACE_OP(this_instr, _SHUFFLE_2_LOAD_CONST_INLINE_BORROW, 0,
+ ADD_OP(_SHUFFLE_2_LOAD_CONST_INLINE_BORROW, 0,
(uintptr_t)type);
}
else {
out = Py_True;
}
sym_set_const(res, out);
- REPLACE_OP(this_instr, _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)out);
+ ADD_OP(_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)out);
}
}
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
- eliminate_pop_guard(this_instr, value != Py_True);
+ eliminate_pop_guard(this_instr, ctx, value != Py_True);
}
sym_set_const(flag, Py_True);
}
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
- eliminate_pop_guard(this_instr, value != Py_False);
+ eliminate_pop_guard(this_instr, ctx, value != Py_False);
}
sym_set_const(flag, Py_False);
}
if (sym_is_const(ctx, val)) {
PyObject *value = sym_get_const(ctx, val);
assert(value != NULL);
- eliminate_pop_guard(this_instr, !Py_IsNone(value));
+ eliminate_pop_guard(this_instr, ctx, !Py_IsNone(value));
}
else if (sym_has_type(val)) {
assert(!sym_matches_type(val, &_PyNone_Type));
- eliminate_pop_guard(this_instr, true);
+ eliminate_pop_guard(this_instr, ctx, true);
}
sym_set_const(val, Py_None);
}
if (sym_is_const(ctx, val)) {
PyObject *value = sym_get_const(ctx, val);
assert(value != NULL);
- eliminate_pop_guard(this_instr, Py_IsNone(value));
+ eliminate_pop_guard(this_instr, ctx, Py_IsNone(value));
}
else if (sym_has_type(val)) {
assert(!sym_matches_type(val, &_PyNone_Type));
- eliminate_pop_guard(this_instr, false);
+ eliminate_pop_guard(this_instr, ctx, false);
}
}
/* Setting the eval frame function invalidates
* all executors, so no need to check dynamically */
if (_PyInterpreterState_GET()->eval_frame == NULL) {
- REPLACE_OP(this_instr, _NOP, 0 ,0);
+ ADD_OP(_NOP, 0 ,0);
}
}
}
op(_REPLACE_WITH_TRUE, (value -- res, v)) {
- REPLACE_OP(this_instr, _INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True);
+ ADD_OP(_INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True);
res = sym_new_const(ctx, Py_True);
v = value;
}
op(_GUARD_TOS_LIST, (tos -- tos)) {
if (sym_matches_type(tos, &PyList_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyList_Type);
}
op(_GUARD_NOS_LIST, (nos, unused -- nos, unused)) {
if (sym_matches_type(nos, &PyList_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyList_Type);
}
op(_GUARD_TOS_TUPLE, (tos -- tos)) {
if (sym_matches_type(tos, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyTuple_Type);
}
op(_GUARD_NOS_TUPLE, (nos, unused -- nos, unused)) {
if (sym_matches_type(nos, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyTuple_Type);
}
op(_GUARD_TOS_DICT, (tos -- tos)) {
if (sym_matches_type(tos, &PyDict_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyDict_Type);
}
op(_GUARD_NOS_DICT, (nos, unused -- nos, unused)) {
if (sym_matches_type(nos, &PyDict_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyDict_Type);
}
if (sym_matches_type(tos, &PySet_Type) ||
sym_matches_type(tos, &PyFrozenSet_Type))
{
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
op(_GUARD_NOS_NULL, (null, unused -- null, unused)) {
if (sym_is_null(null)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_null(null);
}
op(_GUARD_NOS_NOT_NULL, (nos, unused -- nos, unused)) {
if (sym_is_not_null(nos)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_non_null(nos);
}
op(_GUARD_THIRD_NULL, (null, unused, unused -- null, unused, unused)) {
if (sym_is_null(null)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_null(null);
}
op(_GUARD_CALLABLE_TYPE_1, (callable, unused, unused -- callable, unused, unused)) {
if (sym_get_const(ctx, callable) == (PyObject *)&PyType_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyType_Type);
}
op(_GUARD_CALLABLE_TUPLE_1, (callable, unused, unused -- callable, unused, unused)) {
if (sym_get_const(ctx, callable) == (PyObject *)&PyTuple_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyTuple_Type);
}
op(_GUARD_CALLABLE_STR_1, (callable, unused, unused -- callable, unused, unused)) {
if (sym_get_const(ctx, callable) == (PyObject *)&PyUnicode_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyUnicode_Type);
}
goto error;
}
if (_Py_IsImmortal(temp)) {
- REPLACE_OP(this_instr, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW,
+ ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW,
0, (uintptr_t)temp);
}
res = sym_new_const(ctx, temp);
goto error;
}
if (_Py_IsImmortal(temp)) {
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp);
}
len = sym_new_const(ctx, temp);
Py_DECREF(temp);
op(_GUARD_CALLABLE_LEN, (callable, unused, unused -- callable, unused, unused)) {
PyObject *len = _PyInterpreterState_GET()->callable_cache.len;
if (sym_get_const(ctx, callable) == len) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, len);
}
op(_GUARD_CALLABLE_ISINSTANCE, (callable, unused, unused, unused -- callable, unused, unused, unused)) {
PyObject *isinstance = _PyInterpreterState_GET()->callable_cache.isinstance;
if (sym_get_const(ctx, callable) == isinstance) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, isinstance);
}
op(_GUARD_CALLABLE_LIST_APPEND, (callable, unused, unused -- callable, unused, unused)) {
PyObject *list_append = _PyInterpreterState_GET()->callable_cache.list_append;
if (sym_get_const(ctx, callable) == list_append) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, list_append);
}
ctx->frame->globals_watched = true;
}
if (ctx->frame->globals_checked_version == version) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
}
ctx->frame->globals_watched = true;
}
if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) {
- REPLACE_OP(this_instr-1, _GUARD_GLOBALS_VERSION, 0, version);
+ REPLACE_OP(&ctx->out_buffer[ctx->out_len - 1], _GUARD_GLOBALS_VERSION, 0, version);
ctx->frame->globals_checked_version = version;
}
if (ctx->frame->globals_checked_version == version) {
JitOptRef value;
PyCodeObject *co = get_current_code_object(ctx);
PyObject *val = PyTuple_GET_ITEM(co->co_consts, oparg);
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = value;
PyObject *val = PyLong_FromLong(oparg);
assert(val);
assert(_Py_IsImmortal(val));
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = value;
if (PyJitRef_IsBorrowed(value) ||
sym_is_immortal(PyJitRef_Unwrap(value)) ||
sym_is_null(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
else if (typ == &PyLong_Type) {
- REPLACE_OP(this_instr, _POP_TOP_INT, 0, 0);
+ ADD_OP(_POP_TOP_INT, 0, 0);
}
else if (typ == &PyFloat_Type) {
- REPLACE_OP(this_instr, _POP_TOP_FLOAT, 0, 0);
+ ADD_OP(_POP_TOP_FLOAT, 0, 0);
}
else if (typ == &PyUnicode_Type) {
- REPLACE_OP(this_instr, _POP_TOP_UNICODE, 0, 0);
+ ADD_OP(_POP_TOP_UNICODE, 0, 0);
}
CHECK_STACK_BOUNDS(-1);
stack_pointer += -1;
JitOptRef value;
value = stack_pointer[-1];
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
CHECK_STACK_BOUNDS(-1);
stack_pointer += -1;
JitOptRef value;
value = stack_pointer[-1];
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
CHECK_STACK_BOUNDS(-1);
stack_pointer += -1;
JitOptRef value;
value = stack_pointer[-1];
if (PyJitRef_IsBorrowed(value)) {
- REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0);
+ ADD_OP(_POP_TOP_NOP, 0, 0);
}
CHECK_STACK_BOUNDS(-1);
stack_pointer += -1;
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_1_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
- REPLACE_OP(this_instr, _INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
- REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
stack_pointer[-1] = res;
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_matches_type(nos, &PyList_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyList_Type);
break;
JitOptRef tos;
tos = stack_pointer[-1];
if (sym_matches_type(tos, &PyList_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyList_Type);
break;
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_matches_type(nos, &PyUnicode_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyUnicode_Type);
break;
JitOptRef value;
value = stack_pointer[-1];
if (sym_matches_type(value, &PyUnicode_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(value, &PyUnicode_Type);
break;
JitOptRef res;
JitOptRef v;
value = stack_pointer[-1];
- REPLACE_OP(this_instr, _INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True);
+ ADD_OP(_INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True);
res = sym_new_const(ctx, Py_True);
v = value;
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_1_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
- REPLACE_OP(this_instr, _INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_1_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
JitOptRef left;
left = stack_pointer[-2];
if (sym_is_compact_int(left)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
if (sym_get_type(left) == &PyLong_Type) {
- REPLACE_OP(this_instr, _GUARD_NOS_OVERFLOWED, 0, 0);
+ ADD_OP(_GUARD_NOS_OVERFLOWED, 0, 0);
}
sym_set_compact_int(left);
}
JitOptRef value;
value = stack_pointer[-1];
if (sym_is_compact_int(value)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
if (sym_get_type(value) == &PyLong_Type) {
- REPLACE_OP(this_instr, _GUARD_TOS_OVERFLOWED, 0, 0);
+ ADD_OP(_GUARD_TOS_OVERFLOWED, 0, 0);
}
sym_set_compact_int(value);
}
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
JitOptRef left;
left = stack_pointer[-2];
if (sym_matches_type(left, &PyFloat_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(left, &PyFloat_Type);
break;
JitOptRef value;
value = stack_pointer[-1];
if (sym_matches_type(value, &PyFloat_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(value, &PyFloat_Type);
break;
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_matches_type(nos, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyTuple_Type);
break;
JitOptRef tos;
tos = stack_pointer[-1];
if (sym_matches_type(tos, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyTuple_Type);
break;
assert(index >= 0);
int tuple_length = sym_tuple_length(tuple_st);
if (tuple_length != -1 && index < tuple_length) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
break;
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_matches_type(nos, &PyDict_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(nos, &PyDict_Type);
break;
JitOptRef tos;
tos = stack_pointer[-1];
if (sym_matches_type(tos, &PyDict_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(tos, &PyDict_Type);
break;
JitOptRef *null;
null = &stack_pointer[0];
if (oparg & 1) {
- REPLACE_OP(this_instr, _PUSH_NULL, 0, 0);
+ ADD_OP(_PUSH_NULL, 0, 0);
null[0] = sym_new_null(ctx);
}
else {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
CHECK_STACK_BOUNDS((oparg & 1));
stack_pointer += (oparg & 1);
ctx->frame->globals_watched = true;
}
if (ctx->frame->globals_checked_version == version) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
}
}
ctx->frame->globals_watched = true;
}
if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) {
- REPLACE_OP(this_instr-1, _GUARD_GLOBALS_VERSION, 0, version);
+ REPLACE_OP(&ctx->out_buffer[ctx->out_len - 1], _GUARD_GLOBALS_VERSION, 0, version);
ctx->frame->globals_checked_version = version;
}
if (ctx->frame->globals_checked_version == version) {
uint32_t type_version = (uint32_t)this_instr->operand0;
assert(type_version);
if (sym_matches_type_version(owner, type_version)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
} else {
PyTypeObject *type = _PyType_LookupByVersion(type_version);
if (type) {
PyObject *type = (PyObject *)_PyType_LookupByVersion(type_version);
if (type) {
if (type == sym_get_const(ctx, owner)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
else {
sym_set_const(owner, type);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(-1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
PyObject *result = sym_get_const(ctx, b);
if (_Py_IsImmortal(result)) {
// Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(1);
if (sym_matches_type(tos, &PySet_Type) ||
sym_matches_type(tos, &PyFrozenSet_Type))
{
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
break;
}
goto error;
}
if (_Py_IsImmortal(temp)) {
- REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp);
+ ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp);
}
len = sym_new_const(ctx, temp);
CHECK_STACK_BOUNDS(1);
JitOptRef iter;
iter = stack_pointer[-2];
if (sym_matches_type(iter, &PyTuple_Type)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_type(iter, &PyTuple_Type);
break;
uint32_t func_version = (uint32_t)this_instr->operand0;
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
assert(PyFunction_Check(sym_get_const(ctx, callable)));
- REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
- this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
+ ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
+ ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)sym_get_const(ctx, callable);
}
sym_set_type(callable, &PyFunction_Type);
break;
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyMethod_Type)) {
PyMethodObject *method = (PyMethodObject *)sym_get_const(ctx, callable);
assert(PyMethod_Check(method));
- REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
- this_instr->operand1 = (uintptr_t)method->im_func;
+ ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
+ ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)method->im_func;
}
sym_set_type(callable, &PyMethod_Type);
break;
case _CHECK_PEP_523: {
if (_PyInterpreterState_GET()->eval_frame == NULL) {
- REPLACE_OP(this_instr, _NOP, 0 ,0);
+ ADD_OP(_NOP, 0 ,0);
}
break;
}
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(ctx, callable);
PyCodeObject *co = (PyCodeObject *)func->func_code;
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
- REPLACE_OP(this_instr, _NOP, 0 ,0);
+ ADD_OP(_NOP, 0 ,0);
}
}
}
JitOptRef null;
null = stack_pointer[-2];
if (sym_is_null(null)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_null(null);
break;
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_is_not_null(nos)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_non_null(nos);
break;
JitOptRef null;
null = stack_pointer[-3];
if (sym_is_null(null)) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_null(null);
break;
JitOptRef callable;
callable = stack_pointer[-3];
if (sym_get_const(ctx, callable) == (PyObject *)&PyType_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyType_Type);
break;
PyObject* type = (PyObject *)sym_get_type(arg);
if (type) {
res = sym_new_const(ctx, type);
- REPLACE_OP(this_instr, _SHUFFLE_2_LOAD_CONST_INLINE_BORROW, 0,
- (uintptr_t)type);
+ ADD_OP(_SHUFFLE_2_LOAD_CONST_INLINE_BORROW, 0,
+ (uintptr_t)type);
}
else {
res = sym_new_not_null(ctx);
JitOptRef callable;
callable = stack_pointer[-3];
if (sym_get_const(ctx, callable) == (PyObject *)&PyUnicode_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyUnicode_Type);
break;
JitOptRef callable;
callable = stack_pointer[-3];
if (sym_get_const(ctx, callable) == (PyObject *)&PyTuple_Type) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, (PyObject *)&PyTuple_Type);
break;
callable = stack_pointer[-3];
PyObject *len = _PyInterpreterState_GET()->callable_cache.len;
if (sym_get_const(ctx, callable) == len) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, len);
break;
goto error;
}
if (_Py_IsImmortal(temp)) {
- REPLACE_OP(this_instr, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW,
- 0, (uintptr_t)temp);
+ ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW,
+ 0, (uintptr_t)temp);
}
res = sym_new_const(ctx, temp);
CHECK_STACK_BOUNDS(-2);
callable = stack_pointer[-4];
PyObject *isinstance = _PyInterpreterState_GET()->callable_cache.isinstance;
if (sym_get_const(ctx, callable) == isinstance) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, isinstance);
break;
out = Py_True;
}
sym_set_const(res, out);
- REPLACE_OP(this_instr, _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)out);
+ ADD_OP(_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)out);
}
CHECK_STACK_BOUNDS(-3);
stack_pointer[-4] = res;
callable = stack_pointer[-3];
PyObject *list_append = _PyInterpreterState_GET()->callable_cache.list_append;
if (sym_get_const(ctx, callable) == list_append) {
- REPLACE_OP(this_instr, _NOP, 0, 0);
+ ADD_OP(_NOP, 0, 0);
}
sym_set_const(callable, list_append);
break;
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
// Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
- REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ ADD_OP(_POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
}
}
CHECK_STACK_BOUNDS(-1);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
- eliminate_pop_guard(this_instr, value != Py_True);
+ eliminate_pop_guard(this_instr, ctx, value != Py_True);
}
sym_set_const(flag, Py_True);
CHECK_STACK_BOUNDS(-1);
if (sym_is_const(ctx, flag)) {
PyObject *value = sym_get_const(ctx, flag);
assert(value != NULL);
- eliminate_pop_guard(this_instr, value != Py_False);
+ eliminate_pop_guard(this_instr, ctx, value != Py_False);
}
sym_set_const(flag, Py_False);
CHECK_STACK_BOUNDS(-1);
if (sym_is_const(ctx, val)) {
PyObject *value = sym_get_const(ctx, val);
assert(value != NULL);
- eliminate_pop_guard(this_instr, !Py_IsNone(value));
+ eliminate_pop_guard(this_instr, ctx, !Py_IsNone(value));
}
else if (sym_has_type(val)) {
assert(!sym_matches_type(val, &_PyNone_Type));
- eliminate_pop_guard(this_instr, true);
+ eliminate_pop_guard(this_instr, ctx, true);
}
sym_set_const(val, Py_None);
CHECK_STACK_BOUNDS(-1);
if (sym_is_const(ctx, val)) {
PyObject *value = sym_get_const(ctx, val);
assert(value != NULL);
- eliminate_pop_guard(this_instr, Py_IsNone(value));
+ eliminate_pop_guard(this_instr, ctx, Py_IsNone(value));
}
else if (sym_has_type(val)) {
assert(!sym_matches_type(val, &_PyNone_Type));
- eliminate_pop_guard(this_instr, false);
+ eliminate_pop_guard(this_instr, ctx, false);
}
CHECK_STACK_BOUNDS(-1);
stack_pointer += -1;
emitter.emit(f"PyObject *result = sym_get_const(ctx, {output_identifier.text});\n")
emitter.emit(f"if (_Py_IsImmortal(result)) {{\n")
emitter.emit(f"// Replace with {replacement_uop} since we have {input_desc} and an immortal result\n")
- emitter.emit(f"REPLACE_OP(this_instr, {replacement_uop}, 0, (uintptr_t)result);\n")
+ emitter.emit(f"ADD_OP({replacement_uop}, 0, (uintptr_t)result);\n")
emitter.emit("}\n")
emitter.emit("}\n")