Source

arana-main / arana / eval.c

/*
 * eval.c
 *
 * (c) Copyright 2009 by Armin Ronacher, Georg Brandl.
 */

#include "arana.h"

#define TOP()           (stack_ptr[-1])
#define SET_TOP(v)      (stack_ptr[-1] = (v))
#define POP()           (*--stack_ptr)
#define PUSH(v)         (*stack_ptr++ = (v))
#define CONST(i)        AR_TUPLE_GET(frame->code->consts, i)
#define CURINSTR()      (op - frame->code->ops)
#define OPNAME(op)      AR_OPMAP[op]

/* include the automatically generated opcode reverse map */
#include "_opmap.h"


void
arana_debug_code(AR_SIG, ArCode *code)
{
    ArOp *op = code->ops;
    printf("Code %s (%p):\n", code->filename, code);
    while (1) {
        int index = (int)(op - code->ops);
        printf(" %- 8d%-20s", index, OPNAME(op->op));
        switch (op->op) {
        case AR_OP_LOAD_CONST: {
            AR val = AR_TUPLE_GET(code->consts, op->arg);
            printf("(%s)", AR_AS_CHARP(AR_REPR(val)));
            break;
        }
        case AR_OP_LOAD_FAST:
        case AR_OP_STORE_FAST: {
            AR name = AR_TUPLE_GET(code->vars, op->arg);
            printf("(%s)", AR_AS_CHARP(name));
            break;
        }
        case AR_OP_SETUP_LOOP:
            printf("(loop ends at %u)", op->arg);
            break;
        case AR_OP_JUMP_IF_FALSE:
        case AR_OP_JUMP_ALWAYS:
            printf("(jumps %s to %u)",
                   op->arg > index ? "forward" : "back", op->arg);
            break;
        case AR_OP_MAKE_STRING:
        case AR_OP_MAKE_TUPLE:
        case AR_OP_MAKE_LIST:
            printf("(%d item%s)", op->arg, op->arg == 1 ? "" : "s");
            break;
        }
        printf("\n");
        if ((op++)->op == AR_OP_STOP)
            break;
    }
}

AR
arana_evaluate(AR_SIG, ArFrame *frame)
{

/* Computed GOTOs, or so-called "threaded code"; see <doc/eval.txt>. */
#ifdef USE_COMPUTED_GOTOS
#include "_opcode_targets.h"
#define DISPATCH(op)                            \
    TARGET_##op:                                \
case AR_OP_##op
#define NEXT()                                  \
    { goto *AR_OPTARGETS[(++op)->op]; }
#define JUMP_TO(p)                                              \
    { op = frame->code->ops + p; goto *AR_OPTARGETS[op->op]; }
#else
#define DISPATCH(op)    case AR_OP_##op
#define NEXT()          { op++; continue; }
#define JUMP_TO(p)      { op = frame->code->ops + p; continue; }
#endif /* defined(USE_COMPUTED_GOTOS) */

    AR rv = AR_NULL;
    ArOp *op = frame->code->ops;
    register AR arg0;
    register AR arg1;
    register AR arg2;
    register AR arg3;

    register AR *stack_ptr = frame->stack;

    /* if you change the effect an opcode has on the stack size here
       make sure to also update the arana_compiler_get_stack_size
       function in the compiler (compile.c) */
    while (1) {
        switch (op->op) {
        /* loading */
        DISPATCH(LOAD_CONST):
            arg0 = CONST(op->arg);
            PUSH(arg0);
            NEXT();
        DISPATCH(LOAD_FAST):
            arg0 = frame->fastlocals[op->arg];
            /* fastlocal not yet loaded */
            if (arg0 == AR_NULL) {
                const char *name = AR_AS_CHARP(
                    AR_TUPLE_GET(frame->code->vars, op->arg));
                arg0 = AR_STRINGMAP_GET(frame->locals, name);
                if (!arg0)
                    AR_RAISE(AR_NAME_ERROR(name));
                frame->fastlocals[op->arg] = arg0;
            }
            PUSH(arg0);
            NEXT();
        DISPATCH(STORE_FAST):
            arg1 = arg0 = POP();
            frame->fastlocals[op->arg] = arg0;
            PUSH(arg0);
            NEXT();
        /* binary expressions */
        DISPATCH(CONCAT):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":concat", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(ADD):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":add", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(SUB):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":sub", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(MUL):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":mul", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(DIV):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":div", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(MOD):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":mod", arg2);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(POW):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":pow", arg2);
            SET_TOP(arg0);
            NEXT();
        /* unary expressions */
        DISPATCH(POS):
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":pos", 0);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(NEG):
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":neg", 0);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(NOT):
            arg1 = TOP();
            if (AR_TEST(arg1)) SET_TOP(AR_FALSE);
            else SET_TOP(AR_TRUE);
            NEXT();
        /* string interpolation */
        DISPATCH(MAKE_STRING): {
            arg1 = AR_STRINGBUILDER();
            for (int i = 0; i < op->arg; i++) {
                arg2 = POP();
                if (!AR_IS_STRING(arg2))
                    arg2 = AR_CALL_METHOD(arg2, "to_string", 0);
                AR_STRINGBUILDER_APPEND_STRING(arg1, arg2);
            }
            arg0 = AR_STRINGBUILDER_TO_STRING(arg1);
            PUSH(arg0);
            NEXT();
        }
        /* list/tuple displays */
        DISPATCH(MAKE_LIST):
            arg0 = AR_LIST2(op->arg);
            for (int i = 0; i < op->arg; i++) {
                arg2 = POP();
                AR_LIST_APPEND(arg0, arg2);
            }
            PUSH(arg0);
            NEXT();
        DISPATCH(MAKE_TUPLE):
            arg0 = AR_TUPLE(op->arg);
            for (int i = 0; i < op->arg; i++) {
                arg2 = POP();
                AR_TUPLE_PUT(arg0, i, arg2);
            }
            PUSH(arg0);
            NEXT();
        /* method calling */
        DISPATCH(CALL_METHOD): {
            const char *message;
            arg3 = POP();
            arg2 = POP();
            arg1 = TOP();
            if (!AR_IS_STRING(arg2))
                AR_RAISE(AR_TYPE_ERROR("messages have to be strings."));
            if (!AR_IS_TUPLE(arg3))
                AR_RAISE(AR_TYPE_ERROR("arguments have to be tuples."));
            message = AR_AS_CHARP(arg2);
            arg0 = AR_CALL_METHODA(arg1, message, arg3);
            SET_TOP(arg0);
            NEXT();
        }
        DISPATCH(CALL):
            arg1 = POP();
            arg2 = TOP();
            arg0 = AR_CALL(arg1, arg2);
            SET_TOP(arg0);
            NEXT();
        /* attribute getting */
        DISPATCH(GET_ATTRIBUTE):
            arg2 = POP();
            arg1 = TOP();
            arg0 = arana_get_member(AR_ISIG, arg1, arg2);
            SET_TOP(arg0);
            NEXT();
        /* subscription */
        DISPATCH(GET_SUBSCRIPT):
            arg2 = POP();
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, ":getitem", arg2);
            SET_TOP(arg0);
            NEXT();
        /* for loops */
        DISPATCH(GET_ITERATOR):
            arg1 = TOP();
            arg0 = AR_GET_ITERATOR(arg1);
            SET_TOP(arg0);
            NEXT();
        DISPATCH(ITER_NEXT):
            arg1 = TOP();
            arg0 = AR_CALL_METHOD(arg1, "next", 0);
            PUSH(arg0);
            NEXT();
        DISPATCH(SETUP_LOOP):
            NEXT();
        /* jumps */
        DISPATCH(JUMP_IF_FALSE):
            arg1 = POP();
            if (AR_TEST(arg1))
                NEXT();
            /* fallthrough */
        DISPATCH(JUMP_ALWAYS):
            JUMP_TO(op->arg);
        /* general purpose opcodes */
        DISPATCH(POP_TOP):
            arg0 = POP();
            NEXT();
        /* last opcode that closes the loop */
        DISPATCH(STOP):
            goto outside;
#ifdef USE_COMPUTED_GOTOS
        TARGET_UNSET:
        TARGET_UNKNOWN:
#endif
        default:
            AR_FATAL("arana_evaluate: unhandled opcode %s\n", OPNAME(op->op));
        }
        /* should never reach this point */
        AR_FATAL("arana_evaluate: reached unreachable point\n");
    }
  outside:

    GC_gcollect();
    return rv;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.