hotpy_2 / Include / ceval_macros.h

Full commit

    #define USE_COMPUTED_GOTOS 1
    #error "Computed gotos are not supported on this compiler."
    #define USE_COMPUTED_GOTOS 0

/* Tuple access macros */

#ifndef Py_DEBUG
#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))
#define GETITEM(v, i) PyTuple_GetItem((v), (i))

/* Code access macros */

#define INSTR_OFFSET()  ((int)(next_instr - first_instr))
#define NEXTOP()        (*next_instr++)
#define NEXTARG()       (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
#define PEEKARG()       ((next_instr[2]<<8) + next_instr[1])
#define JUMPTO(x)       (next_instr = first_instr + (x))
#define JUMPBY(x)       (next_instr += (x))

/* OpCode prediction macros
    Some opcodes tend to come in pairs thus making it possible to
    predict the second code when the first is run.  For example,
    COMPARE_OP is often followed by JUMP_IF_FALSE or JUMP_IF_TRUE.  And,
    those opcodes are often followed by a POP_TOP.

    Verifying the prediction costs a single high-speed test of a register
    variable against a constant.  If the pairing was good, then the
    processor's own internal branch predication has a high likelihood of
    success, resulting in a nearly zero-overhead transition to the
    next opcode.  A successful prediction saves a trip through the eval-loop
    including its two unpredictable branches, the HAS_ARG test and the
    switch-case.  Combined with the processor's internal branch prediction,
    a successful PREDICT has the effect of making the two opcodes run as if
    they were a single new opcode with the bodies combined.

    If collecting opcode statistics, your choices are to either keep the
    predictions turned-on and interpret the results as if some opcodes
    had been combined or turn-off predictions so that the opcode frequency
    counter updates for both opcodes.

    Opcode prediction is disabled with threaded code, since the latter allows
    the CPU to record separate branch prediction information for each


#define PREDICT(op)             if (0) goto PRED_##op
#define PREDICTED(op)           PRED_##op:
#define PREDICTED_WITH_ARG(op)  PRED_##op:
#define PREDICT(op)             if (*next_instr == op) goto PRED_##op
#define PREDICTED(op)           PRED_##op: next_instr++
#define PREDICTED_WITH_ARG(op)  PRED_##op: oparg = PEEKARG(); next_instr += 3

/* Stack manipulation macros */

/* The stack can grow at most MAXINT deep, as co_nlocals and
   co_stacksize are ints. */
#define STACK_LEVEL()     ((int)(f->f_stacktop - f->f_valuestack))
#define EMPTY()           (STACK_LEVEL() == 0)
#define TOP()             (f->f_stacktop[-1])
#define SECOND()          (f->f_stacktop[-2])
#define THIRD()           (f->f_stacktop[-3])
#define FOURTH()          (f->f_stacktop[-4])
#define PEEK(n)           (f->f_stacktop[-(n)])
#define SET_TOP(v)        (f->f_stacktop[-1] = (v))
#define SET_SECOND(v)     (f->f_stacktop[-2] = (v))
#define SET_THIRD(v)      (f->f_stacktop[-3] = (v))
#define SET_FOURTH(v)     (f->f_stacktop[-4] = (v))
#define SET_VALUE(n, v)   (f->f_stacktop[-(n)] = (v))
#define BASIC_STACKADJ(n) (f->f_stacktop += n)
#define BASIC_PUSH(v)     (*(f->f_stacktop)++ = (v))
#define BASIC_POP()       (*--(f->f_stacktop))

#ifdef LLTRACE
#define PUSH(v)         { (void)(BASIC_PUSH(v), \
                          lltrace && prtrace(TOP(), "push")); \
                          assert(STACK_LEVEL() <= co->co_stacksize+HOTPY_STACK_OVERHEAD); }
#define POP()           ((void)(lltrace && prtrace(TOP(), "pop")), \
                         assert(STACK_LEVEL() >= 1), BASIC_POP())

#define EXT_POP(STACK_POINTER) ((void)(lltrace && \
                                prtrace((STACK_POINTER)[-1], "ext_pop")), \
#define PUSH(v)                BASIC_PUSH(v)
#define POP()                  BASIC_POP()
#define STACKADJ(n)            BASIC_STACKADJ(n)

/* Local variable macros */

#define GETLOCAL(i)     (fastlocals[i])

/* The SETLOCAL() macro must not DECREF the local variable in-place and
   then store the new value; it must copy the old value to a temporary
   value, then store the new value, and then DECREF the temporary value.
   This is because it is possible that during the DECREF the frame is
   accessed by other code (e.g. a __del__ method or gc.collect()) and the
   variable would be pointing to already-freed memory. */
#define SETLOCAL(i, value)      do { PyObject *tmp = GETLOCAL(i); \
                                     GETLOCAL(i) = value; \
                                     Py_XDECREF(tmp); } while (0)

#define UNWIND_BLOCK(b) \
do { \
    assert(STACK_LEVEL() >= (b)->b_level); \
    while (STACK_LEVEL() > (b)->b_level) { \
        PyObject *v = POP(); \
        Py_XDECREF(v); \
    } \
} while (0)

    { \
        PyObject *type, *value, *traceback; \
        assert(STACK_LEVEL() >= (b)->b_level + 3); \
        while (STACK_LEVEL() > (b)->b_level + 3) { \
            value = POP(); \
            Py_XDECREF(value); \
        } \
        type = tstate->exc_type; \
        value = tstate->exc_value; \
        traceback = tstate->exc_traceback; \
        tstate->exc_type = POP(); \
        tstate->exc_value = POP(); \
        tstate->exc_traceback = POP(); \
        Py_XDECREF(type); \
        Py_XDECREF(value); \
        Py_XDECREF(traceback); \

#define NAME_ERROR_MSG \
    "name '%.200s' is not defined"
    "global name '%.200s' is not defined"
    "local variable '%.200s' referenced before assignment"
    "free variable '%.200s' referenced before assignment" \
    " in enclosing scope"

#ifdef Py_DEBUG

static char* small_rep(PyObject *obj, char *buf) {
    if (obj == NULL)
        return " null";
    if (obj == Py_True)
        return " True";
    if (obj == Py_False)
        return " False";
    if (PyType_Check(obj))
        snprintf(buf, 9, " T.%s", ((PyTypeObject *)obj)->tp_name);
    else if (PyLong_Check(obj)) {
        int oflow;
        long l = PyLong_AsLongAndOverflow(obj, &oflow);
        if (oflow)
            snprintf(buf, 9, "");
            snprintf(buf, 9, " %ld", l);
        snprintf(buf, 9, " O.%s", obj->ob_type->tp_name);
    return &buf[0];

static void _print_log(char *name, PyThreadState *tstate, int depth, PyObject **sp, int op)
    static char buf1[12];
    static char buf2[12];
    int rec_depth = tstate->recursion_depth;
    if (tstate->_InstructionLog == NULL) {
        char filename[100];
        int pid = getpid();
        sprintf(filename, "/tmp/hotpy.%lx.%x.log", tstate->thread_id, pid);
        tstate->_InstructionLog = fopen(filename, "w+");
        if (tstate->_InstructionLog == NULL)
            _HotPy_Options.lltrace = 0;
    fprintf(tstate->_InstructionLog, "%s: [%d, %d%s%s] %s",
            name, rec_depth, depth,
            depth > 1 ? small_rep(sp[-2], buf1) : "",
            depth ? small_rep(sp[-1], buf2) : "",

static void
_log_op(char *name, PyThreadState *tstate, int depth, PyObject **sp, int op)
    if (sp == NULL)
        depth = 0;
    _print_log(name, tstate, depth, sp, op);
    fprintf(tstate->_InstructionLog, "\n");

static void
_log_op_with_arg(char *name, PyThreadState *tstate, int depth, PyObject **sp, int op, int oparg)
    _print_log(name, tstate, depth, sp, op);
    fprintf(tstate->_InstructionLog, " %d\n", oparg);

#define LOG_OP(op) INC_ON_TRACE \
    if (_HotPy_Options.lltrace) \
        _log_op(interpreter_name, tstate, \
                STACK_LEVEL(), f->f_stacktop, op);
#define LOG_OP_ARG(op, oparg) INC_ON_TRACE \
    if (_HotPy_Options.lltrace) \
        _log_op_with_arg(interpreter_name, tstate, \
                         STACK_LEVEL(), f->f_stacktop, op, oparg);

#define LOG(txt) \
    if (_HotPy_Options.lltrace && tstate->_InstructionLog) \
        fprintf(tstate->_InstructionLog, "%s\n", txt)
#define LOG_FMT(fmt, what) \
    if (_HotPy_Options.lltrace && tstate->_InstructionLog) \
        fprintf(tstate->_InstructionLog, fmt, what)
#define FLUSH_LOG() \
    if (_HotPy_Options.lltrace && tstate->_InstructionLog) \


#define LOG_OP(op)
#define LOG_OP_ARG(op, oparg)
#define LOG(txt) ((void)0)
#define LOG_FMT(fmt, what) ((void)0)
#define FLUSH_LOG() ((void)0)