// This value is arbitrary and was not optimized.
#define JIT_CLEANUP_THRESHOLD 1000
-#define TRACE_STACK_SIZE 5
-
int _Py_uop_analyze_and_optimize(
PyFunctionObject *func,
_PyUOpInstruction *trace, int trace_len, int curr_stackentries,
#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5)
// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH())
-#define MAX_ABSTRACT_FRAME_DEPTH (TRACE_STACK_SIZE + 2)
+#define MAX_ABSTRACT_FRAME_DEPTH (16)
// The maximum number of side exits that we can take before requiring forward
// progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this
bool needs_guard_ip = OPCODE_HAS_NEEDS_GUARD_IP(opcode);
if (has_dynamic_jump_taken && !needs_guard_ip) {
- DPRINTF(2, "Unsupported: dynamic jump taken\n");
+ DPRINTF(2, "Unsupported: dynamic jump taken %s\n", _PyOpcode_OpName[opcode]);
goto unsupported;
}
DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level);
if ((next_instr != _tstate->jit_state.initial_state.close_loop_instr) &&
(next_instr != _tstate->jit_state.initial_state.start_instr) &&
_tstate->jit_state.prev_state.code_curr_size > 5 &&
+ // For side exits, we don't want to terminate them early.
+ _tstate->jit_state.initial_state.exit == NULL &&
// These are coroutines, and we want to unroll those usually.
opcode != JUMP_BACKWARD_NO_INTERRUPT) {
// We encountered a JUMP_BACKWARD but not to the top of our own loop.
if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
// Don't add nested code objects to the dependency.
// It causes endless re-traces.
- if (new_func != NULL && !(new_code->co_flags & CO_NESTED)) {
+ if (new_func != NULL && !Py_IsNone((PyObject*)new_func) && !(new_code->co_flags & CO_NESTED)) {
operand = (uintptr_t)new_func;
DPRINTF(2, "Adding %p func to op\n", (void *)operand);
_Py_BloomFilter_Add(dependencies, new_func);
}
op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame)) {
- _Py_UOpsAbstractFrame *old_frame = ctx->frame;
+ ctx->frame->stack_pointer = stack_pointer - oparg - 2;
_Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0);
if (shim == NULL) {
break;
}
_Py_BloomFilter_Add(dependencies, returning_code);
int returning_stacklevel = this_instr->operand1;
+ if (ctx->curr_frame_depth >= 2) {
+ PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code;
+ if (expected_code == returning_code) {
+ assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE);
+ REPLACE_OP((this_instr + 1), _NOP, 0, 0);
+ }
+ }
if (frame_pop(ctx, returning_code, returning_stacklevel)) {
break;
}
_Py_BloomFilter_Add(dependencies, co);
ctx->frame->func = func;
}
+ // Fixed calls don't need IP guards.
+ if ((this_instr-1)->opcode == _SAVE_RETURN_OFFSET ||
+ (this_instr-1)->opcode == _CREATE_INIT_FRAME) {
+ assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME);
+ REPLACE_OP(this_instr+1, _NOP, 0, 0);
+ }
}
op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) {
}
_Py_BloomFilter_Add(dependencies, returning_code);
int returning_stacklevel = this_instr->operand1;
+ if (ctx->curr_frame_depth >= 2) {
+ PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code;
+ if (expected_code == returning_code) {
+ assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE);
+ REPLACE_OP((this_instr + 1), _NOP, 0, 0);
+ }
+ }
if (frame_pop(ctx, returning_code, returning_stacklevel)) {
break;
}
_Py_BloomFilter_Add(dependencies, co);
ctx->frame->func = func;
}
+ if ((this_instr-1)->opcode == _SAVE_RETURN_OFFSET ||
+ (this_instr-1)->opcode == _CREATE_INIT_FRAME) {
+ assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME);
+ REPLACE_OP(this_instr+1, _NOP, 0, 0);
+ }
break;
}
JitOptRef init_frame;
args = &stack_pointer[-oparg];
self = stack_pointer[-1 - oparg];
- _Py_UOpsAbstractFrame *old_frame = ctx->frame;
+ ctx->frame->stack_pointer = stack_pointer - oparg - 2;
_Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0);
if (shim == NULL) {
break;