summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/optimizer.c62
-rw-r--r--Python/optimizer_analysis.c30
-rw-r--r--Python/optimizer_bytecodes.c27
-rw-r--r--Python/optimizer_cases.c.h25
4 files changed, 106 insertions, 38 deletions
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 4a3cd46..177ad34 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -211,7 +211,7 @@ _PyOptimizer_Optimize(
_PyInterpreterFrame *frame, _Py_CODEUNIT *start,
PyObject **stack_pointer, _PyExecutorObject **executor_ptr)
{
- PyCodeObject *code = (PyCodeObject *)frame->f_executable;
+ PyCodeObject *code = _PyFrame_GetCode(frame);
assert(PyCode_Check(code));
PyInterpreterState *interp = _PyInterpreterState_GET();
if (!has_space_for_executor(code, start)) {
@@ -479,8 +479,9 @@ BRANCH_TO_GUARD[4][2] = {
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0); \
goto done; \
} \
- assert(func->func_code == (PyObject *)code); \
+ assert(func == NULL || func->func_code == (PyObject *)code); \
trace_stack[trace_stack_depth].func = func; \
+ trace_stack[trace_stack_depth].code = code; \
trace_stack[trace_stack_depth].instr = instr; \
trace_stack_depth++;
#define TRACE_STACK_POP() \
@@ -489,7 +490,8 @@ BRANCH_TO_GUARD[4][2] = {
} \
trace_stack_depth--; \
func = trace_stack[trace_stack_depth].func; \
- code = (PyCodeObject *)trace_stack[trace_stack_depth].func->func_code; \
+ code = trace_stack[trace_stack_depth].code; \
+ assert(func == NULL || func->func_code == (PyObject *)code); \
instr = trace_stack[trace_stack_depth].instr;
/* Returns 1 on success,
@@ -505,7 +507,7 @@ translate_bytecode_to_trace(
_PyBloomFilter *dependencies)
{
bool progress_needed = true;
- PyCodeObject *code = (PyCodeObject *)frame->f_executable;
+ PyCodeObject *code = _PyFrame_GetCode(frame);
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
assert(PyFunction_Check(func));
PyCodeObject *initial_code = code;
@@ -515,6 +517,7 @@ translate_bytecode_to_trace(
int max_length = buffer_size;
struct {
PyFunctionObject *func;
+ PyCodeObject *code;
_Py_CODEUNIT *instr;
} trace_stack[TRACE_STACK_SIZE];
int trace_stack_depth = 0;
@@ -719,9 +722,19 @@ top: // Jump here after _PUSH_FRAME or likely branches
if (uop == _POP_FRAME) {
TRACE_STACK_POP();
- /* Set the operand to the function object returned to,
- * to assist optimization passes */
- ADD_TO_TRACE(uop, oparg, (uintptr_t)func, target);
+ /* Set the operand to the function or code object returned to,
+ * to assist optimization passes. (See _PUSH_FRAME below.)
+ */
+ if (func != NULL) {
+ operand = (uintptr_t)func;
+ }
+ else if (code != NULL) {
+ operand = (uintptr_t)code | 1;
+ }
+ else {
+ operand = 0;
+ }
+ ADD_TO_TRACE(uop, oparg, operand, target);
DPRINTF(2,
"Returning to %s (%s:%d) at byte offset %d\n",
PyUnicode_AsUTF8(code->co_qualname),
@@ -738,10 +751,12 @@ top: // Jump here after _PUSH_FRAME or likely branches
// Add one to account for the actual opcode/oparg pair:
+ 1;
uint32_t func_version = read_u32(&instr[func_version_offset].cache);
- PyFunctionObject *new_func = _PyFunction_LookupByVersion(func_version);
- DPRINTF(2, "Function: version=%#x; object=%p\n", (int)func_version, new_func);
- if (new_func != NULL) {
- PyCodeObject *new_code = (PyCodeObject *)PyFunction_GET_CODE(new_func);
+ PyCodeObject *new_code = NULL;
+ PyFunctionObject *new_func =
+ _PyFunction_LookupByVersion(func_version, (PyObject **) &new_code);
+ DPRINTF(2, "Function: version=%#x; new_func=%p, new_code=%p\n",
+ (int)func_version, new_func, new_code);
+ if (new_code != NULL) {
if (new_code == code) {
// Recursive call, bail (we could be here forever).
DPRINTF(2, "Bailing on recursive call to %s (%s:%d)\n",
@@ -766,9 +781,22 @@ top: // Jump here after _PUSH_FRAME or likely branches
instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + 1;
TRACE_STACK_PUSH();
_Py_BloomFilter_Add(dependencies, new_code);
- /* Set the operand to the callee's function object,
- * to assist optimization passes */
- ADD_TO_TRACE(uop, oparg, (uintptr_t)new_func, target);
+ /* Set the operand to the callee's function or code object,
+ * to assist optimization passes.
+ * We prefer setting it to the function (for remove_globals())
+ * but if that's not available but the code is available,
+ * use the code, setting the low bit so the optimizer knows.
+ */
+ if (new_func != NULL) {
+ operand = (uintptr_t)new_func;
+ }
+ else if (new_code != NULL) {
+ operand = (uintptr_t)new_code | 1;
+ }
+ else {
+ operand = 0;
+ }
+ ADD_TO_TRACE(uop, oparg, operand, target);
code = new_code;
func = new_func;
instr = _PyCode_CODE(code);
@@ -780,8 +808,8 @@ top: // Jump here after _PUSH_FRAME or likely branches
2 * INSTR_IP(instr, code));
goto top;
}
- DPRINTF(2, "Bail, new_func == NULL\n");
- ADD_TO_TRACE(uop, oparg, operand, target);
+ DPRINTF(2, "Bail, new_code == NULL\n");
+ ADD_TO_TRACE(uop, oparg, 0, target);
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0);
goto done;
}
@@ -1116,7 +1144,7 @@ counter_optimize(
int Py_UNUSED(curr_stackentries)
)
{
- PyCodeObject *code = (PyCodeObject *)frame->f_executable;
+ PyCodeObject *code = _PyFrame_GetCode(frame);
int oparg = instr->op.arg;
while (instr->op.code == EXTENDED_ARG) {
instr++;
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
index 6c460c5..95924a5 100644
--- a/Python/optimizer_analysis.c
+++ b/Python/optimizer_analysis.c
@@ -228,7 +228,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
builtins_watched <<= 1;
globals_watched <<= 1;
function_checked <<= 1;
- PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
+ uint64_t operand = buffer[pc].operand;
+ if (operand == 0 || (operand & 1)) {
+ // It's either a code object or NULL, so bail
+ return 1;
+ }
+ PyFunctionObject *func = (PyFunctionObject *)operand;
if (func == NULL) {
return 1;
}
@@ -251,7 +256,15 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
builtins_watched >>= 1;
globals_watched >>= 1;
function_checked >>= 1;
- PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
+ uint64_t operand = buffer[pc].operand;
+ if (operand == 0 || (operand & 1)) {
+ // It's either a code object or NULL, so bail
+ return 1;
+ }
+ PyFunctionObject *func = (PyFunctionObject *)operand;
+ if (func == NULL) {
+ return 1;
+ }
assert(PyFunction_Check(func));
function_version = func->func_version;
globals = func->func_globals;
@@ -522,7 +535,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
static void
peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_size)
{
- PyCodeObject *co = (PyCodeObject *)frame->f_executable;
+ PyCodeObject *co = _PyFrame_GetCode(frame);
for (int pc = 0; pc < buffer_size; pc++) {
int opcode = buffer[pc].opcode;
switch(opcode) {
@@ -545,11 +558,16 @@ peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_s
case _PUSH_FRAME:
case _POP_FRAME:
{
- PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
- if (func == NULL) {
+ uint64_t operand = buffer[pc].operand;
+ if (operand & 1) {
+ co = (PyCodeObject *)(operand & ~1);
+ assert(PyCode_Check(co));
+ }
+ else if (operand == 0) {
co = NULL;
}
else {
+ PyFunctionObject *func = (PyFunctionObject *)operand;
assert(PyFunction_Check(func));
co = (PyCodeObject *)func->func_code;
}
@@ -587,7 +605,7 @@ _Py_uop_analyze_and_optimize(
peephole_opt(frame, buffer, buffer_size);
err = optimize_uops(
- (PyCodeObject *)frame->f_executable, buffer,
+ _PyFrame_GetCode(frame), buffer,
buffer_size, curr_stacklen, dependencies);
if (err == 0) {
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index a1ef644..e761b1b 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -543,14 +543,25 @@ dummy_func(void) {
(void)callable;
- PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand;
- DPRINTF(3, "func: %p ", func);
- if (func == NULL) {
- DPRINTF(3, "\n");
- DPRINTF(1, "Missing function\n");
- goto done;
- }
- PyCodeObject *co = (PyCodeObject *)func->func_code;
+ PyCodeObject *co = NULL;
+ assert((this_instr + 2)->opcode == _PUSH_FRAME);
+ uintptr_t push_operand = (this_instr + 2)->operand;
+ if (push_operand & 1) {
+ co = (PyCodeObject *)(push_operand & ~1);
+ DPRINTF(3, "code=%p ", co);
+ assert(PyCode_Check(co));
+ }
+ else {
+ PyFunctionObject *func = (PyFunctionObject *)push_operand;
+ DPRINTF(3, "func=%p ", func);
+ if (func == NULL) {
+ DPRINTF(3, "\n");
+ DPRINTF(1, "Missing function\n");
+ goto done;
+ }
+ co = (PyCodeObject *)func->func_code;
+ DPRINTF(3, "code=%p ", co);
+ }
assert(self_or_null != NULL);
assert(args != NULL);
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index a0ecf58..2908a26 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1596,14 +1596,25 @@
callable = stack_pointer[-2 - oparg];
int argcount = oparg;
(void)callable;
- PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand;
- DPRINTF(3, "func: %p ", func);
- if (func == NULL) {
- DPRINTF(3, "\n");
- DPRINTF(1, "Missing function\n");
- goto done;
+ PyCodeObject *co = NULL;
+ assert((this_instr + 2)->opcode == _PUSH_FRAME);
+ uintptr_t push_operand = (this_instr + 2)->operand;
+ if (push_operand & 1) {
+ co = (PyCodeObject *)(push_operand & ~1);
+ DPRINTF(3, "code=%p ", co);
+ assert(PyCode_Check(co));
+ }
+ else {
+ PyFunctionObject *func = (PyFunctionObject *)push_operand;
+ DPRINTF(3, "func=%p ", func);
+ if (func == NULL) {
+ DPRINTF(3, "\n");
+ DPRINTF(1, "Missing function\n");
+ goto done;
+ }
+ co = (PyCodeObject *)func->func_code;
+ DPRINTF(3, "code=%p ", co);
}
- PyCodeObject *co = (PyCodeObject *)func->func_code;
assert(self_or_null != NULL);
assert(args != NULL);
if (sym_is_not_null(self_or_null)) {