GH-98831: Simple input-output stack effects for bytecodes.c (#99120)

This commit is contained in:
Guido van Rossum 2022-11-08 08:22:56 -08:00 committed by GitHub
parent c7065ce019
commit f1a654648b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 384 additions and 406 deletions

View file

@ -43,6 +43,7 @@ void _PyUnicode_ExactDealloc(PyObject *);
#define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_TOP(v) (stack_pointer[-1] = (v))
#define SET_SECOND(v) (stack_pointer[-2] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v))
#define PEEK(n) (stack_pointer[-(n)]) #define PEEK(n) (stack_pointer[-(n)])
#define POKE(n, v) (stack_pointer[-(n)] = (v))
#define PUSH(val) (*(stack_pointer++) = (val)) #define PUSH(val) (*(stack_pointer++) = (val))
#define POP() (*(--stack_pointer)) #define POP() (*(--stack_pointer))
#define TOP() PEEK(1) #define TOP() PEEK(1)
@ -63,12 +64,13 @@ do { \
/* Flow control macros */ /* Flow control macros */
#define DEOPT_IF(cond, instname) ((void)0) #define DEOPT_IF(cond, instname) ((void)0)
#define ERROR_IF(cond, labelname) ((void)0)
#define JUMPBY(offset) ((void)0) #define JUMPBY(offset) ((void)0)
#define GO_TO_INSTRUCTION(instname) ((void)0) #define GO_TO_INSTRUCTION(instname) ((void)0)
#define DISPATCH_SAME_OPARG() ((void)0) #define DISPATCH_SAME_OPARG() ((void)0)
#define DISPATCH() ((void)0) #define DISPATCH() ((void)0)
#define inst(name) case name: #define inst(name, ...) case name:
#define super(name) static int SUPER_##name #define super(name) static int SUPER_##name
#define family(name) static int family_##name #define family(name) static int family_##name
@ -79,6 +81,10 @@ typedef struct {
PyObject *kwnames; PyObject *kwnames;
} CallShape; } CallShape;
// Dummy variables for stack effects.
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
static PyObject *container, *start, *stop, *v;
static PyObject * static PyObject *
dummy_func( dummy_func(
PyThreadState *tstate, PyThreadState *tstate,
@ -104,12 +110,10 @@ dummy_func(
and that all operation that succeed call DISPATCH() ! */ and that all operation that succeed call DISPATCH() ! */
// BEGIN BYTECODES // // BEGIN BYTECODES //
// stack effect: ( -- ) inst(NOP, (--)) {
inst(NOP) {
} }
// stack effect: ( -- ) inst(RESUME, (--)) {
inst(RESUME) {
assert(tstate->cframe == &cframe); assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame); assert(frame == cframe.current_frame);
if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
@ -117,45 +121,31 @@ dummy_func(
} }
} }
// stack effect: ( -- __0) inst(LOAD_CLOSURE, (-- value)) {
inst(LOAD_CLOSURE) {
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
PyObject *value = GETLOCAL(oparg); value = GETLOCAL(oparg);
if (value == NULL) { ERROR_IF(value == NULL, unbound_local_error);
goto unbound_local_error;
}
Py_INCREF(value); Py_INCREF(value);
PUSH(value);
} }
// stack effect: ( -- __0) inst(LOAD_FAST_CHECK, (-- value)) {
inst(LOAD_FAST_CHECK) { value = GETLOCAL(oparg);
PyObject *value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error);
if (value == NULL) {
goto unbound_local_error;
}
Py_INCREF(value); Py_INCREF(value);
PUSH(value);
} }
// stack effect: ( -- __0) inst(LOAD_FAST, (-- value)) {
inst(LOAD_FAST) { value = GETLOCAL(oparg);
PyObject *value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value);
} }
// stack effect: ( -- __0) inst(LOAD_CONST, (-- value)) {
inst(LOAD_CONST) { value = GETITEM(consts, oparg);
PyObject *value = GETITEM(consts, oparg);
Py_INCREF(value); Py_INCREF(value);
PUSH(value);
} }
// stack effect: (__0 -- ) inst(STORE_FAST, (value --)) {
inst(STORE_FAST) {
PyObject *value = POP();
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
} }
@ -165,9 +155,7 @@ dummy_func(
super(STORE_FAST__STORE_FAST) = STORE_FAST + STORE_FAST; super(STORE_FAST__STORE_FAST) = STORE_FAST + STORE_FAST;
super (LOAD_CONST__LOAD_FAST) = LOAD_CONST + LOAD_FAST; super (LOAD_CONST__LOAD_FAST) = LOAD_CONST + LOAD_FAST;
// stack effect: (__0 -- ) inst(POP_TOP, (value --)) {
inst(POP_TOP) {
PyObject *value = POP();
Py_DECREF(value); Py_DECREF(value);
} }
@ -177,166 +165,113 @@ dummy_func(
BASIC_PUSH(NULL); BASIC_PUSH(NULL);
} }
// stack effect: (__0, __1 -- ) inst(END_FOR, (value1, value2 --)) {
inst(END_FOR) { Py_DECREF(value1);
PyObject *value = POP(); Py_DECREF(value2);
Py_DECREF(value);
value = POP();
Py_DECREF(value);
} }
// stack effect: ( -- ) inst(UNARY_POSITIVE, (value -- res)) {
inst(UNARY_POSITIVE) { res = PyNumber_Positive(value);
PyObject *value = TOP();
PyObject *res = PyNumber_Positive(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); ERROR_IF(res == NULL, error);
if (res == NULL)
goto error;
} }
// stack effect: ( -- ) inst(UNARY_NEGATIVE, (value -- res)) {
inst(UNARY_NEGATIVE) { res = PyNumber_Negative(value);
PyObject *value = TOP();
PyObject *res = PyNumber_Negative(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); ERROR_IF(res == NULL, error);
if (res == NULL)
goto error;
} }
// stack effect: ( -- ) inst(UNARY_NOT, (value -- res)) {
inst(UNARY_NOT) {
PyObject *value = TOP();
int err = PyObject_IsTrue(value); int err = PyObject_IsTrue(value);
Py_DECREF(value); Py_DECREF(value);
ERROR_IF(err < 0, error);
if (err == 0) { if (err == 0) {
Py_INCREF(Py_True); res = Py_True;
SET_TOP(Py_True);
DISPATCH();
} }
else if (err > 0) { else {
Py_INCREF(Py_False); res = Py_False;
SET_TOP(Py_False);
DISPATCH();
} }
STACK_SHRINK(1); Py_INCREF(res);
goto error;
} }
// stack effect: ( -- ) inst(UNARY_INVERT, (value -- res)) {
inst(UNARY_INVERT) { res = PyNumber_Invert(value);
PyObject *value = TOP();
PyObject *res = PyNumber_Invert(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); ERROR_IF(res == NULL, error);
if (res == NULL)
goto error;
} }
// stack effect: (__0 -- ) inst(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) {
inst(BINARY_OP_MULTIPLY_INT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(prod);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); ERROR_IF(prod == NULL, error);
if (prod == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_MULTIPLY_FLOAT, (left, right -- prod)) {
inst(BINARY_OP_MULTIPLY_FLOAT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dprod = ((PyFloatObject *)left)->ob_fval * double dprod = ((PyFloatObject *)left)->ob_fval *
((PyFloatObject *)right)->ob_fval; ((PyFloatObject *)right)->ob_fval;
PyObject *prod = PyFloat_FromDouble(dprod); prod = PyFloat_FromDouble(dprod);
SET_SECOND(prod);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); ERROR_IF(prod == NULL, error);
if (prod == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_SUBTRACT_INT, (left, right -- sub)) {
inst(BINARY_OP_SUBTRACT_INT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(sub);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); ERROR_IF(sub == NULL, error);
if (sub == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_SUBTRACT_FLOAT, (left, right -- sub)) {
inst(BINARY_OP_SUBTRACT_FLOAT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
PyObject *sub = PyFloat_FromDouble(dsub); sub = PyFloat_FromDouble(dsub);
SET_SECOND(sub);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); ERROR_IF(sub == NULL, error);
if (sub == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_ADD_UNICODE, (left, right -- res)) {
inst(BINARY_OP_ADD_UNICODE) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *res = PyUnicode_Concat(left, right); res = PyUnicode_Concat(left, right);
STACK_SHRINK(1);
SET_TOP(res);
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
if (TOP() == NULL) { ERROR_IF(res == NULL, error);
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) // This is a subtle one. It's a super-instruction for
inst(BINARY_OP_INPLACE_ADD_UNICODE) { // BINARY_OP_ADD_UNICODE followed by STORE_FAST
// where the store goes into the left argument.
// So the inputs are the same as for all BINARY_OP
// specializations, but there is no output.
// At the end we just skip over the STORE_FAST.
inst(BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
@ -358,107 +293,75 @@ dummy_func(
*/ */
assert(Py_REFCNT(left) >= 2); assert(Py_REFCNT(left) >= 2);
_Py_DECREF_NO_DEALLOC(left); _Py_DECREF_NO_DEALLOC(left);
STACK_SHRINK(2);
PyUnicode_Append(target_local, right); PyUnicode_Append(target_local, right);
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
if (*target_local == NULL) { ERROR_IF(*target_local == NULL, error);
goto error;
}
// The STORE_FAST is already done. // The STORE_FAST is already done.
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_ADD_FLOAT, (left, right -- sum)) {
inst(BINARY_OP_ADD_FLOAT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dsum = ((PyFloatObject *)left)->ob_fval + double dsum = ((PyFloatObject *)left)->ob_fval +
((PyFloatObject *)right)->ob_fval; ((PyFloatObject *)right)->ob_fval;
PyObject *sum = PyFloat_FromDouble(dsum); sum = PyFloat_FromDouble(dsum);
SET_SECOND(sum);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); ERROR_IF(sum == NULL, error);
if (sum == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_OP_ADD_INT, (left, right -- sum)) {
inst(BINARY_OP_ADD_INT) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(sum);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); ERROR_IF(sum == NULL, error);
if (sum == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
} }
// stack effect: (__0 -- ) inst(BINARY_SUBSCR, (container, sub -- res)) {
inst(BINARY_SUBSCR) { res = PyObject_GetItem(container, sub);
PyObject *sub = POP();
PyObject *container = TOP();
PyObject *res = PyObject_GetItem(container, sub);
Py_DECREF(container); Py_DECREF(container);
Py_DECREF(sub); Py_DECREF(sub);
SET_TOP(res); ERROR_IF(res == NULL, error);
if (res == NULL)
goto error;
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
} }
// stack effect: (__0, __1 -- ) inst(BINARY_SLICE, (container, start, stop -- res)) {
inst(BINARY_SLICE) {
PyObject *stop = POP();
PyObject *start = POP();
PyObject *container = TOP();
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
// Can't use ERROR_IF() here, because we haven't
// DECREF'ed container yet, and we still own slice.
if (slice == NULL) { if (slice == NULL) {
goto error; res = NULL;
} }
PyObject *res = PyObject_GetItem(container, slice); else {
Py_DECREF(slice); res = PyObject_GetItem(container, slice);
if (res == NULL) { Py_DECREF(slice);
goto error;
} }
SET_TOP(res);
Py_DECREF(container); Py_DECREF(container);
ERROR_IF(res == NULL, error);
} }
// stack effect: (__0, __1, __2, __3 -- ) inst(STORE_SLICE, (v, container, start, stop -- )) {
inst(STORE_SLICE) {
PyObject *stop = POP();
PyObject *start = POP();
PyObject *container = TOP();
PyObject *v = SECOND();
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
int err;
if (slice == NULL) { if (slice == NULL) {
goto error; err = 1;
} }
int err = PyObject_SetItem(container, slice, v); else {
Py_DECREF(slice); err = PyObject_SetItem(container, slice, v);
if (err) { Py_DECREF(slice);
goto error;
} }
STACK_SHRINK(2);
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(container); Py_DECREF(container);
ERROR_IF(err, error);
} }
// stack effect: (__0 -- ) // stack effect: (__0 -- )
@ -607,21 +510,14 @@ dummy_func(
PREDICT(JUMP_BACKWARD); PREDICT(JUMP_BACKWARD);
} }
// stack effect: (__0, __1, __2 -- ) inst(STORE_SUBSCR, (v, container, sub -- )) {
inst(STORE_SUBSCR) {
PyObject *sub = TOP();
PyObject *container = SECOND();
PyObject *v = THIRD();
int err; int err;
STACK_SHRINK(3);
/* container[sub] = v */ /* container[sub] = v */
err = PyObject_SetItem(container, sub, v); err = PyObject_SetItem(container, sub, v);
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(container); Py_DECREF(container);
Py_DECREF(sub); Py_DECREF(sub);
if (err != 0) { ERROR_IF(err != 0, error);
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR); JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
} }

View file

@ -806,6 +806,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define THIRD() (stack_pointer[-3]) #define THIRD() (stack_pointer[-3])
#define FOURTH() (stack_pointer[-4]) #define FOURTH() (stack_pointer[-4])
#define PEEK(n) (stack_pointer[-(n)]) #define PEEK(n) (stack_pointer[-(n)])
#define POKE(n, v) (stack_pointer[-(n)] = (v))
#define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_TOP(v) (stack_pointer[-1] = (v))
#define SET_SECOND(v) (stack_pointer[-2] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v))
#define BASIC_STACKADJ(n) (stack_pointer += n) #define BASIC_STACKADJ(n) (stack_pointer += n)
@ -1274,6 +1275,14 @@ unbound_local_error:
goto error; goto error;
} }
pop_4_error:
STACK_SHRINK(1);
pop_3_error:
STACK_SHRINK(1);
pop_2_error:
STACK_SHRINK(1);
pop_1_error:
STACK_SHRINK(1);
error: error:
call_shape.kwnames = NULL; call_shape.kwnames = NULL;
/* Double-check exception status. */ /* Double-check exception status. */

View file

@ -15,51 +15,57 @@
} }
TARGET(LOAD_CLOSURE) { TARGET(LOAD_CLOSURE) {
PyObject *value;
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
PyObject *value = GETLOCAL(oparg); value = GETLOCAL(oparg);
if (value == NULL) { if (value == NULL) goto unbound_local_error;
goto unbound_local_error;
}
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
DISPATCH(); DISPATCH();
} }
TARGET(LOAD_FAST_CHECK) { TARGET(LOAD_FAST_CHECK) {
PyObject *value = GETLOCAL(oparg); PyObject *value;
if (value == NULL) { value = GETLOCAL(oparg);
goto unbound_local_error; if (value == NULL) goto unbound_local_error;
}
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
DISPATCH(); DISPATCH();
} }
TARGET(LOAD_FAST) { TARGET(LOAD_FAST) {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
DISPATCH(); DISPATCH();
} }
TARGET(LOAD_CONST) { TARGET(LOAD_CONST) {
PREDICTED(LOAD_CONST); PREDICTED(LOAD_CONST);
PyObject *value = GETITEM(consts, oparg); PyObject *value;
value = GETITEM(consts, oparg);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
DISPATCH(); DISPATCH();
} }
TARGET(STORE_FAST) { TARGET(STORE_FAST) {
PyObject *value = POP(); PyObject *value = PEEK(1);
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
TARGET(POP_TOP) { TARGET(POP_TOP) {
PyObject *value = POP(); PyObject *value = PEEK(1);
Py_DECREF(value); Py_DECREF(value);
STACK_SHRINK(1);
DISPATCH(); DISPATCH();
} }
@ -70,163 +76,158 @@
} }
TARGET(END_FOR) { TARGET(END_FOR) {
PyObject *value = POP(); PyObject *value2 = PEEK(1);
Py_DECREF(value); PyObject *value1 = PEEK(2);
value = POP(); Py_DECREF(value1);
Py_DECREF(value); Py_DECREF(value2);
STACK_SHRINK(2);
DISPATCH(); DISPATCH();
} }
TARGET(UNARY_POSITIVE) { TARGET(UNARY_POSITIVE) {
PyObject *value = TOP(); PyObject *value = PEEK(1);
PyObject *res = PyNumber_Positive(value); PyObject *res;
res = PyNumber_Positive(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); if (res == NULL) goto pop_1_error;
if (res == NULL) POKE(1, res);
goto error;
DISPATCH(); DISPATCH();
} }
TARGET(UNARY_NEGATIVE) { TARGET(UNARY_NEGATIVE) {
PyObject *value = TOP(); PyObject *value = PEEK(1);
PyObject *res = PyNumber_Negative(value); PyObject *res;
res = PyNumber_Negative(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); if (res == NULL) goto pop_1_error;
if (res == NULL) POKE(1, res);
goto error;
DISPATCH(); DISPATCH();
} }
TARGET(UNARY_NOT) { TARGET(UNARY_NOT) {
PyObject *value = TOP(); PyObject *value = PEEK(1);
PyObject *res;
int err = PyObject_IsTrue(value); int err = PyObject_IsTrue(value);
Py_DECREF(value); Py_DECREF(value);
if (err < 0) goto pop_1_error;
if (err == 0) { if (err == 0) {
Py_INCREF(Py_True); res = Py_True;
SET_TOP(Py_True);
DISPATCH();
} }
else if (err > 0) { else {
Py_INCREF(Py_False); res = Py_False;
SET_TOP(Py_False);
DISPATCH();
} }
STACK_SHRINK(1); Py_INCREF(res);
goto error; POKE(1, res);
DISPATCH();
} }
TARGET(UNARY_INVERT) { TARGET(UNARY_INVERT) {
PyObject *value = TOP(); PyObject *value = PEEK(1);
PyObject *res = PyNumber_Invert(value); PyObject *res;
res = PyNumber_Invert(value);
Py_DECREF(value); Py_DECREF(value);
SET_TOP(res); if (res == NULL) goto pop_1_error;
if (res == NULL) POKE(1, res);
goto error;
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_MULTIPLY_INT) { TARGET(BINARY_OP_MULTIPLY_INT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *prod;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(prod);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); if (prod == NULL) goto pop_2_error;
if (prod == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, prod);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_MULTIPLY_FLOAT) { TARGET(BINARY_OP_MULTIPLY_FLOAT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *prod;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dprod = ((PyFloatObject *)left)->ob_fval * double dprod = ((PyFloatObject *)left)->ob_fval *
((PyFloatObject *)right)->ob_fval; ((PyFloatObject *)right)->ob_fval;
PyObject *prod = PyFloat_FromDouble(dprod); prod = PyFloat_FromDouble(dprod);
SET_SECOND(prod);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); if (prod == NULL) goto pop_2_error;
if (prod == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, prod);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_SUBTRACT_INT) { TARGET(BINARY_OP_SUBTRACT_INT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *sub;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(sub);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); if (sub == NULL) goto pop_2_error;
if (sub == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, sub);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_SUBTRACT_FLOAT) { TARGET(BINARY_OP_SUBTRACT_FLOAT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *sub;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
PyObject *sub = PyFloat_FromDouble(dsub); sub = PyFloat_FromDouble(dsub);
SET_SECOND(sub);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); if (sub == NULL) goto pop_2_error;
if (sub == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, sub);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_ADD_UNICODE) { TARGET(BINARY_OP_ADD_UNICODE) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *res;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *res = PyUnicode_Concat(left, right); res = PyUnicode_Concat(left, right);
STACK_SHRINK(1);
SET_TOP(res);
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
if (TOP() == NULL) { if (res == NULL) goto pop_2_error;
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, res);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { TARGET(BINARY_OP_INPLACE_ADD_UNICODE) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
@ -248,108 +249,108 @@
*/ */
assert(Py_REFCNT(left) >= 2); assert(Py_REFCNT(left) >= 2);
_Py_DECREF_NO_DEALLOC(left); _Py_DECREF_NO_DEALLOC(left);
STACK_SHRINK(2);
PyUnicode_Append(target_local, right); PyUnicode_Append(target_local, right);
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
if (*target_local == NULL) { if (*target_local == NULL) goto pop_2_error;
goto error;
}
// The STORE_FAST is already done. // The STORE_FAST is already done.
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
STACK_SHRINK(2);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_ADD_FLOAT) { TARGET(BINARY_OP_ADD_FLOAT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *sum;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dsum = ((PyFloatObject *)left)->ob_fval + double dsum = ((PyFloatObject *)left)->ob_fval +
((PyFloatObject *)right)->ob_fval; ((PyFloatObject *)right)->ob_fval;
PyObject *sum = PyFloat_FromDouble(dsum); sum = PyFloat_FromDouble(dsum);
SET_SECOND(sum);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
STACK_SHRINK(1); if (sum == NULL) goto pop_2_error;
if (sum == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, sum);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_OP_ADD_INT) { TARGET(BINARY_OP_ADD_INT) {
PyObject *right = PEEK(1);
PyObject *left = PEEK(2);
PyObject *sum;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyObject *left = SECOND();
PyObject *right = TOP();
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
SET_SECOND(sum);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
STACK_SHRINK(1); if (sum == NULL) goto pop_2_error;
if (sum == NULL) {
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
STACK_SHRINK(1);
POKE(1, sum);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_SUBSCR) { TARGET(BINARY_SUBSCR) {
PREDICTED(BINARY_SUBSCR); PREDICTED(BINARY_SUBSCR);
PyObject *sub = POP(); PyObject *sub = PEEK(1);
PyObject *container = TOP(); PyObject *container = PEEK(2);
PyObject *res = PyObject_GetItem(container, sub); PyObject *res;
res = PyObject_GetItem(container, sub);
Py_DECREF(container); Py_DECREF(container);
Py_DECREF(sub); Py_DECREF(sub);
SET_TOP(res); if (res == NULL) goto pop_2_error;
if (res == NULL)
goto error;
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
STACK_SHRINK(1);
POKE(1, res);
DISPATCH(); DISPATCH();
} }
TARGET(BINARY_SLICE) { TARGET(BINARY_SLICE) {
PyObject *stop = POP(); PyObject *stop = PEEK(1);
PyObject *start = POP(); PyObject *start = PEEK(2);
PyObject *container = TOP(); PyObject *container = PEEK(3);
PyObject *res;
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
// Can't use ERROR_IF() here, because we haven't
// DECREF'ed container yet, and we still own slice.
if (slice == NULL) { if (slice == NULL) {
goto error; res = NULL;
} }
PyObject *res = PyObject_GetItem(container, slice); else {
Py_DECREF(slice); res = PyObject_GetItem(container, slice);
if (res == NULL) { Py_DECREF(slice);
goto error;
} }
SET_TOP(res);
Py_DECREF(container); Py_DECREF(container);
if (res == NULL) goto pop_3_error;
STACK_SHRINK(2);
POKE(1, res);
DISPATCH(); DISPATCH();
} }
TARGET(STORE_SLICE) { TARGET(STORE_SLICE) {
PyObject *stop = POP(); PyObject *stop = PEEK(1);
PyObject *start = POP(); PyObject *start = PEEK(2);
PyObject *container = TOP(); PyObject *container = PEEK(3);
PyObject *v = SECOND(); PyObject *v = PEEK(4);
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
int err;
if (slice == NULL) { if (slice == NULL) {
goto error; err = 1;
} }
int err = PyObject_SetItem(container, slice, v); else {
Py_DECREF(slice); err = PyObject_SetItem(container, slice, v);
if (err) { Py_DECREF(slice);
goto error;
} }
STACK_SHRINK(2);
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(container); Py_DECREF(container);
if (err) goto pop_4_error;
STACK_SHRINK(4);
DISPATCH(); DISPATCH();
} }
@ -500,20 +501,18 @@
TARGET(STORE_SUBSCR) { TARGET(STORE_SUBSCR) {
PREDICTED(STORE_SUBSCR); PREDICTED(STORE_SUBSCR);
PyObject *sub = TOP(); PyObject *sub = PEEK(1);
PyObject *container = SECOND(); PyObject *container = PEEK(2);
PyObject *v = THIRD(); PyObject *v = PEEK(3);
int err; int err;
STACK_SHRINK(3);
/* container[sub] = v */ /* container[sub] = v */
err = PyObject_SetItem(container, sub, v); err = PyObject_SetItem(container, sub, v);
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(container); Py_DECREF(container);
Py_DECREF(sub); Py_DECREF(sub);
if (err != 0) { if (err != 0) goto pop_3_error;
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR); JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
STACK_SHRINK(3);
DISPATCH(); DISPATCH();
} }
@ -3876,82 +3875,99 @@
TARGET(LOAD_FAST__LOAD_FAST) { TARGET(LOAD_FAST__LOAD_FAST) {
{ {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
NEXTOPARG(); NEXTOPARG();
next_instr++; next_instr++;
{ {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
DISPATCH(); DISPATCH();
} }
TARGET(LOAD_FAST__LOAD_CONST) { TARGET(LOAD_FAST__LOAD_CONST) {
{ {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
NEXTOPARG(); NEXTOPARG();
next_instr++; next_instr++;
{ {
PyObject *value = GETITEM(consts, oparg); PyObject *value;
value = GETITEM(consts, oparg);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
DISPATCH(); DISPATCH();
} }
TARGET(STORE_FAST__LOAD_FAST) { TARGET(STORE_FAST__LOAD_FAST) {
{ {
PyObject *value = POP(); PyObject *value = PEEK(1);
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
STACK_SHRINK(1);
} }
NEXTOPARG(); NEXTOPARG();
next_instr++; next_instr++;
{ {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
DISPATCH(); DISPATCH();
} }
TARGET(STORE_FAST__STORE_FAST) { TARGET(STORE_FAST__STORE_FAST) {
{ {
PyObject *value = POP(); PyObject *value = PEEK(1);
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
STACK_SHRINK(1);
} }
NEXTOPARG(); NEXTOPARG();
next_instr++; next_instr++;
{ {
PyObject *value = POP(); PyObject *value = PEEK(1);
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
STACK_SHRINK(1);
} }
DISPATCH(); DISPATCH();
} }
TARGET(LOAD_CONST__LOAD_FAST) { TARGET(LOAD_CONST__LOAD_FAST) {
{ {
PyObject *value = GETITEM(consts, oparg); PyObject *value;
value = GETITEM(consts, oparg);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
NEXTOPARG(); NEXTOPARG();
next_instr++; next_instr++;
{ {
PyObject *value = GETLOCAL(oparg); PyObject *value;
value = GETLOCAL(oparg);
assert(value != NULL); assert(value != NULL);
Py_INCREF(value); Py_INCREF(value);
PUSH(value); STACK_GROW(1);
POKE(1, value);
} }
DISPATCH(); DISPATCH();
} }

View file

@ -5,10 +5,10 @@
# TODO: Reuse C generation framework from deepfreeze.py? # TODO: Reuse C generation framework from deepfreeze.py?
import argparse import argparse
import io
import os import os
import re import re
import sys import sys
from typing import TextIO, cast
import parser import parser
from parser import InstDef # TODO: Use parser.InstDef from parser import InstDef # TODO: Use parser.InstDef
@ -20,13 +20,13 @@ arg_parser.add_argument("-c", "--compare", action="store_true")
arg_parser.add_argument("-q", "--quiet", action="store_true") arg_parser.add_argument("-q", "--quiet", action="store_true")
def eopen(filename: str, mode: str = "r"): def eopen(filename: str, mode: str = "r") -> TextIO:
if filename == "-": if filename == "-":
if "r" in mode: if "r" in mode:
return sys.stdin return sys.stdin
else: else:
return sys.stdout return sys.stdout
return open(filename, mode) return cast(TextIO, open(filename, mode))
def parse_cases( def parse_cases(
@ -67,42 +67,72 @@ def always_exits(block: parser.Block) -> bool:
return line.startswith(("goto ", "return ", "DISPATCH", "GO_TO_", "Py_UNREACHABLE()")) return line.startswith(("goto ", "return ", "DISPATCH", "GO_TO_", "Py_UNREACHABLE()"))
def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Super]): def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, dedent: int = 0):
predictions = set() assert instr.block
for inst in instrs: if dedent < 0:
for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", inst.block.text): indent += " " * -dedent
# TODO: Is it better to count forward or backward?
for i, input in enumerate(reversed(instr.inputs), 1):
f.write(f"{indent} PyObject *{input} = PEEK({i});\n")
for output in instr.outputs:
if output not in instr.inputs:
f.write(f"{indent} PyObject *{output};\n")
assert instr.block is not None
blocklines = instr.block.to_text(dedent=dedent).splitlines(True)
# Remove blank lines from ends
while blocklines and not blocklines[0].strip():
blocklines.pop(0)
while blocklines and not blocklines[-1].strip():
blocklines.pop()
# Remove leading '{' and trailing '}'
assert blocklines and blocklines[0].strip() == "{"
assert blocklines and blocklines[-1].strip() == "}"
blocklines.pop()
blocklines.pop(0)
# Remove trailing blank lines
while blocklines and not blocklines[-1].strip():
blocklines.pop()
# Write the body
ninputs = len(instr.inputs or ())
for line in blocklines:
if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*$", line):
space, cond, label = m.groups()
# ERROR_IF() must remove the inputs from the stack.
# The code block is responsible for DECREF()ing them.
if ninputs:
f.write(f"{space}if ({cond}) goto pop_{ninputs}_{label};\n")
else:
f.write(f"{space}if ({cond}) goto {label};\n")
else:
f.write(line)
noutputs = len(instr.outputs or ())
diff = noutputs - ninputs
if diff > 0:
f.write(f"{indent} STACK_GROW({diff});\n")
elif diff < 0:
f.write(f"{indent} STACK_SHRINK({-diff});\n")
for i, output in enumerate(reversed(instr.outputs or ()), 1):
if output not in (instr.inputs or ()):
f.write(f"{indent} POKE({i}, {output});\n")
assert instr.block
def write_cases(f: TextIO, instrs: list[InstDef], supers: list[parser.Super]):
predictions: set[str] = set()
for instr in instrs:
assert isinstance(instr, InstDef)
assert instr.block is not None
for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", instr.block.text):
predictions.add(target) predictions.add(target)
indent = " " indent = " "
f.write(f"// This file is generated by {os.path.relpath(__file__)}\n") f.write(f"// This file is generated by {os.path.relpath(__file__)}\n")
f.write("// Do not edit!\n") f.write(f"// Do not edit!\n")
instr_index: dict[str, InstDef] = {} instr_index: dict[str, InstDef] = {}
for instr in instrs: for instr in instrs:
assert isinstance(instr, InstDef)
instr_index[instr.name] = instr instr_index[instr.name] = instr
f.write(f"\n{indent}TARGET({instr.name}) {{\n") f.write(f"\n{indent}TARGET({instr.name}) {{\n")
if instr.name in predictions: if instr.name in predictions:
f.write(f"{indent} PREDICTED({instr.name});\n") f.write(f"{indent} PREDICTED({instr.name});\n")
# input = ", ".join(instr.inputs) write_instr(instr, predictions, indent, f)
# output = ", ".join(instr.outputs)
# f.write(f"{indent} // {input} -- {output}\n")
assert instr.block
blocklines = instr.block.text.splitlines(True)
# Remove blank lines from ends
while blocklines and not blocklines[0].strip():
blocklines.pop(0)
while blocklines and not blocklines[-1].strip():
blocklines.pop()
# Remove leading '{' and trailing '}'
assert blocklines and blocklines[0].strip() == "{"
assert blocklines and blocklines[-1].strip() == "}"
blocklines.pop()
blocklines.pop(0)
# Remove trailing blank lines
while blocklines and not blocklines[-1].strip():
blocklines.pop()
# Write the body
for line in blocklines:
f.write(line)
assert instr.block assert instr.block
if not always_exits(instr.block): if not always_exits(instr.block):
f.write(f"{indent} DISPATCH();\n") f.write(f"{indent} DISPATCH();\n")
@ -114,14 +144,13 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Sup
components = [instr_index[name] for name in sup.ops] components = [instr_index[name] for name in sup.ops]
f.write(f"\n{indent}TARGET({sup.name}) {{\n") f.write(f"\n{indent}TARGET({sup.name}) {{\n")
for i, instr in enumerate(components): for i, instr in enumerate(components):
assert instr.block
if i > 0: if i > 0:
f.write(f"{indent} NEXTOPARG();\n") f.write(f"{indent} NEXTOPARG();\n")
f.write(f"{indent} next_instr++;\n") f.write(f"{indent} next_instr++;\n")
text = instr.block.to_text(-4) f.write(f"{indent} {{\n")
textlines = text.splitlines(True) write_instr(instr, predictions, indent, f, dedent=-4)
textlines = [line for line in textlines if not line.strip().startswith("PREDICTED(")] f.write(f" {indent}}}\n")
text = "".join(textlines)
f.write(f"{indent} {text.strip()}\n")
f.write(f"{indent} DISPATCH();\n") f.write(f"{indent} DISPATCH();\n")
f.write(f"{indent}}}\n") f.write(f"{indent}}}\n")

View file

@ -57,11 +57,28 @@ class Block(Node):
@dataclass @dataclass
class InstDef(Node): class InstHeader(Node):
name: str name: str
inputs: list[str] | None inputs: list[str]
outputs: list[str] | None outputs: list[str]
block: Block | None
@dataclass
class InstDef(Node):
header: InstHeader
block: Block
@property
def name(self):
return self.header.name
@property
def inputs(self):
return self.header.inputs
@property
def outputs(self):
return self.header.outputs
@dataclass @dataclass
@ -82,30 +99,42 @@ class Parser(PLexer):
def inst_def(self) -> InstDef | None: def inst_def(self) -> InstDef | None:
if header := self.inst_header(): if header := self.inst_header():
if block := self.block(): if block := self.block():
header.block = block return InstDef(header, block)
return header
raise self.make_syntax_error("Expected block") raise self.make_syntax_error("Expected block")
return None return None
@contextual @contextual
def inst_header(self): def inst_header(self) -> InstHeader | None:
# inst(NAME) | inst(NAME, (inputs -- outputs)) # inst(NAME) | inst(NAME, (inputs -- outputs))
# TODO: Error out when there is something unexpected. # TODO: Error out when there is something unexpected.
# TODO: Make INST a keyword in the lexer. # TODO: Make INST a keyword in the lexer.``
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst": if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst":
if (self.expect(lx.LPAREN) if (self.expect(lx.LPAREN)
and (tkn := self.expect(lx.IDENTIFIER))): and (tkn := self.expect(lx.IDENTIFIER))):
name = tkn.text name = tkn.text
if self.expect(lx.COMMA): if self.expect(lx.COMMA):
inp, outp = self.stack_effect() inp, outp = self.stack_effect()
if (self.expect(lx.RPAREN) if self.expect(lx.RPAREN):
and self.peek().kind == lx.LBRACE): if ((tkn := self.peek())
return InstDef(name, inp, outp, []) and tkn.kind == lx.LBRACE):
self.check_overlaps(inp, outp)
return InstHeader(name, inp, outp)
elif self.expect(lx.RPAREN): elif self.expect(lx.RPAREN):
return InstDef(name, None, None, []) return InstHeader(name, [], [])
return None return None
def stack_effect(self): def check_overlaps(self, inp: list[str], outp: list[str]):
for i, name in enumerate(inp):
try:
j = outp.index(name)
except ValueError:
continue
else:
if i != j:
raise self.make_syntax_error(
f"Input {name!r} at pos {i} repeated in output at different pos {j}")
def stack_effect(self) -> tuple[list[str], list[str]]:
# '(' [inputs] '--' [outputs] ')' # '(' [inputs] '--' [outputs] ')'
if self.expect(lx.LPAREN): if self.expect(lx.LPAREN):
inp = self.inputs() or [] inp = self.inputs() or []
@ -115,7 +144,7 @@ class Parser(PLexer):
return inp, outp return inp, outp
raise self.make_syntax_error("Expected stack effect") raise self.make_syntax_error("Expected stack effect")
def inputs(self): def inputs(self) -> list[str] | None:
# input (, input)* # input (, input)*
here = self.getpos() here = self.getpos()
if inp := self.input(): if inp := self.input():
@ -128,7 +157,7 @@ class Parser(PLexer):
self.setpos(here) self.setpos(here)
return None return None
def input(self): def input(self) -> str | None:
# IDENTIFIER # IDENTIFIER
if (tkn := self.expect(lx.IDENTIFIER)): if (tkn := self.expect(lx.IDENTIFIER)):
if self.expect(lx.LBRACKET): if self.expect(lx.LBRACKET):
@ -148,7 +177,7 @@ class Parser(PLexer):
return "??" return "??"
return None return None
def outputs(self): def outputs(self) -> list[str] | None:
# output (, output)* # output (, output)*
here = self.getpos() here = self.getpos()
if outp := self.output(): if outp := self.output():
@ -161,7 +190,7 @@ class Parser(PLexer):
self.setpos(here) self.setpos(here)
return None return None
def output(self): def output(self) -> str | None:
return self.input() # TODO: They're not quite the same. return self.input() # TODO: They're not quite the same.
@contextual @contextual
@ -176,7 +205,6 @@ class Parser(PLexer):
return res return res
def ops(self) -> list[str] | None: def ops(self) -> list[str] | None:
here = self.getpos()
if tkn := self.expect(lx.IDENTIFIER): if tkn := self.expect(lx.IDENTIFIER):
ops = [tkn.text] ops = [tkn.text]
while self.expect(lx.PLUS): while self.expect(lx.PLUS):
@ -197,7 +225,7 @@ class Parser(PLexer):
return Family(tkn.text, members) return Family(tkn.text, members)
return None return None
def members(self): def members(self) -> list[str] | None:
here = self.getpos() here = self.getpos()
if tkn := self.expect(lx.IDENTIFIER): if tkn := self.expect(lx.IDENTIFIER):
near = self.getpos() near = self.getpos()
@ -214,8 +242,8 @@ class Parser(PLexer):
tokens = self.c_blob() tokens = self.c_blob()
return Block(tokens) return Block(tokens)
def c_blob(self): def c_blob(self) -> list[lx.Token]:
tokens = [] tokens: list[lx.Token] = []
level = 0 level = 0
while tkn := self.next(raw=True): while tkn := self.next(raw=True):
if tkn.kind in (lx.LBRACE, lx.LPAREN, lx.LBRACKET): if tkn.kind in (lx.LBRACE, lx.LPAREN, lx.LBRACKET):