gh-98831: rewrite PUSH_EXC_INFO and conditional jumps in the instruction definition DSL (#101481)

This commit is contained in:
Irit Katriel 2023-02-01 19:38:06 +00:00 committed by GitHub
parent 7840ff3cdb
commit b91b42d236
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 99 deletions

View file

@ -1898,9 +1898,7 @@ dummy_func(
CHECK_EVAL_BREAKER(); CHECK_EVAL_BREAKER();
} }
// stack effect: (__0 -- ) inst(POP_JUMP_IF_FALSE, (cond -- )) {
inst(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
if (Py_IsTrue(cond)) { if (Py_IsTrue(cond)) {
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
@ -1911,19 +1909,16 @@ dummy_func(
else { else {
int err = PyObject_IsTrue(cond); int err = PyObject_IsTrue(cond);
Py_DECREF(cond); Py_DECREF(cond);
if (err > 0) if (err == 0) {
;
else if (err == 0) {
JUMPBY(oparg); JUMPBY(oparg);
} }
else else {
goto error; ERROR_IF(err < 0, error);
}
} }
} }
// stack effect: (__0 -- ) inst(POP_JUMP_IF_TRUE, (cond -- )) {
inst(POP_JUMP_IF_TRUE) {
PyObject *cond = POP();
if (Py_IsFalse(cond)) { if (Py_IsFalse(cond)) {
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
@ -1937,25 +1932,23 @@ dummy_func(
if (err > 0) { if (err > 0) {
JUMPBY(oparg); JUMPBY(oparg);
} }
else if (err == 0) else {
; ERROR_IF(err < 0, error);
else }
goto error;
} }
} }
// stack effect: (__0 -- ) inst(POP_JUMP_IF_NOT_NONE, (value -- )) {
inst(POP_JUMP_IF_NOT_NONE) {
PyObject *value = POP();
if (!Py_IsNone(value)) { if (!Py_IsNone(value)) {
Py_DECREF(value);
JUMPBY(oparg); JUMPBY(oparg);
} }
Py_DECREF(value); else {
_Py_DECREF_NO_DEALLOC(value);
}
} }
// stack effect: (__0 -- ) inst(POP_JUMP_IF_NONE, (value -- )) {
inst(POP_JUMP_IF_NONE) {
PyObject *value = POP();
if (Py_IsNone(value)) { if (Py_IsNone(value)) {
_Py_DECREF_NO_DEALLOC(value); _Py_DECREF_NO_DEALLOC(value);
JUMPBY(oparg); JUMPBY(oparg);
@ -1965,25 +1958,24 @@ dummy_func(
} }
} }
// error: JUMP_IF_FALSE_OR_POP stack effect depends on jump flag inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) {
inst(JUMP_IF_FALSE_OR_POP) { bool jump = false;
PyObject *cond = TOP();
int err; int err;
if (Py_IsTrue(cond)) { if (Py_IsTrue(cond)) {
STACK_SHRINK(1);
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
else if (Py_IsFalse(cond)) { else if (Py_IsFalse(cond)) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
err = PyObject_IsTrue(cond); err = PyObject_IsTrue(cond);
if (err > 0) { if (err > 0) {
STACK_SHRINK(1);
Py_DECREF(cond); Py_DECREF(cond);
} }
else if (err == 0) { else if (err == 0) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
goto error; goto error;
@ -1991,24 +1983,23 @@ dummy_func(
} }
} }
// error: JUMP_IF_TRUE_OR_POP stack effect depends on jump flag inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) {
inst(JUMP_IF_TRUE_OR_POP) { bool jump = false;
PyObject *cond = TOP();
int err; int err;
if (Py_IsFalse(cond)) { if (Py_IsFalse(cond)) {
STACK_SHRINK(1);
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
else if (Py_IsTrue(cond)) { else if (Py_IsTrue(cond)) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
err = PyObject_IsTrue(cond); err = PyObject_IsTrue(cond);
if (err > 0) { if (err > 0) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else if (err == 0) { else if (err == 0) {
STACK_SHRINK(1);
Py_DECREF(cond); Py_DECREF(cond);
} }
else { else {
@ -2321,22 +2312,16 @@ dummy_func(
ERROR_IF(res == NULL, error); ERROR_IF(res == NULL, error);
} }
// stack effect: ( -- __0) inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) {
inst(PUSH_EXC_INFO) {
PyObject *value = TOP();
_PyErr_StackItem *exc_info = tstate->exc_info; _PyErr_StackItem *exc_info = tstate->exc_info;
if (exc_info->exc_value != NULL) { if (exc_info->exc_value != NULL) {
SET_TOP(exc_info->exc_value); prev_exc = exc_info->exc_value;
} }
else { else {
SET_TOP(Py_NewRef(Py_None)); prev_exc = Py_NewRef(Py_None);
} }
assert(PyExceptionInstance_Check(new_exc));
PUSH(Py_NewRef(value)); exc_info->exc_value = Py_NewRef(new_exc);
assert(PyExceptionInstance_Check(value));
exc_info->exc_value = value;
} }
inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) { inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) {

View file

@ -8630,17 +8630,19 @@ opcode_metadata_is_sane(cfg_builder *g) {
int opcode = instr->i_opcode; int opcode = instr->i_opcode;
int oparg = instr->i_oparg; int oparg = instr->i_oparg;
assert(opcode <= MAX_REAL_OPCODE); assert(opcode <= MAX_REAL_OPCODE);
int popped = _PyOpcode_num_popped(opcode, oparg); for (int jump = 0; jump <= 1; jump++) {
int pushed = _PyOpcode_num_pushed(opcode, oparg); int popped = _PyOpcode_num_popped(opcode, oparg, jump ? true : false);
assert((pushed < 0) == (popped < 0)); int pushed = _PyOpcode_num_pushed(opcode, oparg, jump ? true : false);
if (pushed >= 0) { assert((pushed < 0) == (popped < 0));
assert(_PyOpcode_opcode_metadata[opcode].valid_entry); if (pushed >= 0) {
int effect = stack_effect(opcode, instr->i_oparg, -1); assert(_PyOpcode_opcode_metadata[opcode].valid_entry);
if (effect != pushed - popped) { int effect = stack_effect(opcode, instr->i_oparg, jump);
fprintf(stderr, if (effect != pushed - popped) {
"op=%d: stack_effect (%d) != pushed (%d) - popped (%d)\n", fprintf(stderr,
opcode, effect, pushed, popped); "op=%d arg=%d jump=%d: stack_effect (%d) != pushed (%d) - popped (%d)\n",
result = false; opcode, oparg, jump, effect, pushed, popped);
result = false;
}
} }
} }
} }

View file

@ -2348,7 +2348,7 @@
TARGET(POP_JUMP_IF_FALSE) { TARGET(POP_JUMP_IF_FALSE) {
PREDICTED(POP_JUMP_IF_FALSE); PREDICTED(POP_JUMP_IF_FALSE);
PyObject *cond = POP(); PyObject *cond = PEEK(1);
if (Py_IsTrue(cond)) { if (Py_IsTrue(cond)) {
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
@ -2359,19 +2359,19 @@
else { else {
int err = PyObject_IsTrue(cond); int err = PyObject_IsTrue(cond);
Py_DECREF(cond); Py_DECREF(cond);
if (err > 0) if (err == 0) {
;
else if (err == 0) {
JUMPBY(oparg); JUMPBY(oparg);
} }
else else {
goto error; if (err < 0) goto pop_1_error;
}
} }
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
TARGET(POP_JUMP_IF_TRUE) { TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = POP(); PyObject *cond = PEEK(1);
if (Py_IsFalse(cond)) { if (Py_IsFalse(cond)) {
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
@ -2385,25 +2385,29 @@
if (err > 0) { if (err > 0) {
JUMPBY(oparg); JUMPBY(oparg);
} }
else if (err == 0) else {
; if (err < 0) goto pop_1_error;
else }
goto error;
} }
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
TARGET(POP_JUMP_IF_NOT_NONE) { TARGET(POP_JUMP_IF_NOT_NONE) {
PyObject *value = POP(); PyObject *value = PEEK(1);
if (!Py_IsNone(value)) { if (!Py_IsNone(value)) {
Py_DECREF(value);
JUMPBY(oparg); JUMPBY(oparg);
} }
Py_DECREF(value); else {
_Py_DECREF_NO_DEALLOC(value);
}
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
TARGET(POP_JUMP_IF_NONE) { TARGET(POP_JUMP_IF_NONE) {
PyObject *value = POP(); PyObject *value = PEEK(1);
if (Py_IsNone(value)) { if (Py_IsNone(value)) {
_Py_DECREF_NO_DEALLOC(value); _Py_DECREF_NO_DEALLOC(value);
JUMPBY(oparg); JUMPBY(oparg);
@ -2411,58 +2415,65 @@
else { else {
Py_DECREF(value); Py_DECREF(value);
} }
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
TARGET(JUMP_IF_FALSE_OR_POP) { TARGET(JUMP_IF_FALSE_OR_POP) {
PyObject *cond = TOP(); PyObject *cond = PEEK(1);
bool jump = false;
int err; int err;
if (Py_IsTrue(cond)) { if (Py_IsTrue(cond)) {
STACK_SHRINK(1);
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
else if (Py_IsFalse(cond)) { else if (Py_IsFalse(cond)) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
err = PyObject_IsTrue(cond); err = PyObject_IsTrue(cond);
if (err > 0) { if (err > 0) {
STACK_SHRINK(1);
Py_DECREF(cond); Py_DECREF(cond);
} }
else if (err == 0) { else if (err == 0) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
goto error; goto error;
} }
} }
STACK_SHRINK(1);
STACK_GROW((jump ? 1 : 0));
DISPATCH(); DISPATCH();
} }
TARGET(JUMP_IF_TRUE_OR_POP) { TARGET(JUMP_IF_TRUE_OR_POP) {
PyObject *cond = TOP(); PyObject *cond = PEEK(1);
bool jump = false;
int err; int err;
if (Py_IsFalse(cond)) { if (Py_IsFalse(cond)) {
STACK_SHRINK(1);
_Py_DECREF_NO_DEALLOC(cond); _Py_DECREF_NO_DEALLOC(cond);
} }
else if (Py_IsTrue(cond)) { else if (Py_IsTrue(cond)) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else { else {
err = PyObject_IsTrue(cond); err = PyObject_IsTrue(cond);
if (err > 0) { if (err > 0) {
JUMPBY(oparg); JUMPBY(oparg);
jump = true;
} }
else if (err == 0) { else if (err == 0) {
STACK_SHRINK(1);
Py_DECREF(cond); Py_DECREF(cond);
} }
else { else {
goto error; goto error;
} }
} }
STACK_SHRINK(1);
STACK_GROW((jump ? 1 : 0));
DISPATCH(); DISPATCH();
} }
@ -2828,19 +2839,20 @@
} }
TARGET(PUSH_EXC_INFO) { TARGET(PUSH_EXC_INFO) {
PyObject *value = TOP(); PyObject *new_exc = PEEK(1);
PyObject *prev_exc;
_PyErr_StackItem *exc_info = tstate->exc_info; _PyErr_StackItem *exc_info = tstate->exc_info;
if (exc_info->exc_value != NULL) { if (exc_info->exc_value != NULL) {
SET_TOP(exc_info->exc_value); prev_exc = exc_info->exc_value;
} }
else { else {
SET_TOP(Py_NewRef(Py_None)); prev_exc = Py_NewRef(Py_None);
} }
assert(PyExceptionInstance_Check(new_exc));
PUSH(Py_NewRef(value)); exc_info->exc_value = Py_NewRef(new_exc);
assert(PyExceptionInstance_Check(value)); STACK_GROW(1);
exc_info->exc_value = value; POKE(1, new_exc);
POKE(2, prev_exc);
DISPATCH(); DISPATCH();
} }

View file

@ -4,7 +4,7 @@
#ifndef NDEBUG #ifndef NDEBUG
static int static int
_PyOpcode_num_popped(int opcode, int oparg) { _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
switch(opcode) { switch(opcode) {
case NOP: case NOP:
return 0; return 0;
@ -233,17 +233,17 @@ _PyOpcode_num_popped(int opcode, int oparg) {
case JUMP_BACKWARD: case JUMP_BACKWARD:
return 0; return 0;
case POP_JUMP_IF_FALSE: case POP_JUMP_IF_FALSE:
return -1; return 1;
case POP_JUMP_IF_TRUE: case POP_JUMP_IF_TRUE:
return -1; return 1;
case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NOT_NONE:
return -1; return 1;
case POP_JUMP_IF_NONE: case POP_JUMP_IF_NONE:
return -1; return 1;
case JUMP_IF_FALSE_OR_POP: case JUMP_IF_FALSE_OR_POP:
return -1; return 1;
case JUMP_IF_TRUE_OR_POP: case JUMP_IF_TRUE_OR_POP:
return -1; return 1;
case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD_NO_INTERRUPT:
return 0; return 0;
case GET_LEN: case GET_LEN:
@ -277,7 +277,7 @@ _PyOpcode_num_popped(int opcode, int oparg) {
case WITH_EXCEPT_START: case WITH_EXCEPT_START:
return 4; return 4;
case PUSH_EXC_INFO: case PUSH_EXC_INFO:
return -1; return 1;
case LOAD_ATTR_METHOD_WITH_VALUES: case LOAD_ATTR_METHOD_WITH_VALUES:
return 1; return 1;
case LOAD_ATTR_METHOD_NO_DICT: case LOAD_ATTR_METHOD_NO_DICT:
@ -350,7 +350,7 @@ _PyOpcode_num_popped(int opcode, int oparg) {
#ifndef NDEBUG #ifndef NDEBUG
static int static int
_PyOpcode_num_pushed(int opcode, int oparg) { _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
switch(opcode) { switch(opcode) {
case NOP: case NOP:
return 0; return 0;
@ -579,17 +579,17 @@ _PyOpcode_num_pushed(int opcode, int oparg) {
case JUMP_BACKWARD: case JUMP_BACKWARD:
return 0; return 0;
case POP_JUMP_IF_FALSE: case POP_JUMP_IF_FALSE:
return -1; return 0;
case POP_JUMP_IF_TRUE: case POP_JUMP_IF_TRUE:
return -1; return 0;
case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NOT_NONE:
return -1; return 0;
case POP_JUMP_IF_NONE: case POP_JUMP_IF_NONE:
return -1; return 0;
case JUMP_IF_FALSE_OR_POP: case JUMP_IF_FALSE_OR_POP:
return -1; return (jump ? 1 : 0);
case JUMP_IF_TRUE_OR_POP: case JUMP_IF_TRUE_OR_POP:
return -1; return (jump ? 1 : 0);
case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD_NO_INTERRUPT:
return 0; return 0;
case GET_LEN: case GET_LEN:
@ -623,7 +623,7 @@ _PyOpcode_num_pushed(int opcode, int oparg) {
case WITH_EXCEPT_START: case WITH_EXCEPT_START:
return 5; return 5;
case PUSH_EXC_INFO: case PUSH_EXC_INFO:
return -1; return 2;
case LOAD_ATTR_METHOD_WITH_VALUES: case LOAD_ATTR_METHOD_WITH_VALUES:
return ((oparg & 1) ? 1 : 0) + 1; return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_METHOD_NO_DICT: case LOAD_ATTR_METHOD_NO_DICT:

View file

@ -868,7 +868,7 @@ class Analyzer:
) -> None: ) -> None:
self.out.emit("\n#ifndef NDEBUG") self.out.emit("\n#ifndef NDEBUG")
self.out.emit("static int") self.out.emit("static int")
self.out.emit(f"_PyOpcode_num_{direction}(int opcode, int oparg) {{") self.out.emit(f"_PyOpcode_num_{direction}(int opcode, int oparg, bool jump) {{")
self.out.emit(" switch(opcode) {") self.out.emit(" switch(opcode) {")
for instr, effect in data: for instr, effect in data:
self.out.emit(f" case {instr.name}:") self.out.emit(f" case {instr.name}:")