Status* InterpreterCodeImpl::execute(std::vector<Var*>& vars) {
    ByteStack stack;
    typedef std::map<uint16_t, ByteStorage> VarMap;
    VarMap var_map;

    for (std::vector<Var*>::iterator it = vars.begin(); it != vars.end(); ++it) {
        if ((*it)->name() == "#__INTERPRETER_TRACING__#") {
            m_trace = true;
        }
    }

    BytecodeFunction* function = (BytecodeFunction*) functionById(0);
    Bytecode* bytecode = function->bytecode();

    for (size_t bci = 0; bci < bytecode->length();) {
        Instruction insn = BC_INVALID;
        size_t length = 1;  // size of the BC_INVALID
        decodeInsn(bytecode, bci, insn, length);
        switch (insn) {
            case BC_INVALID:
                return new Status("BC_INVALID", bci);
                break;

            case BC_DLOAD:
                stack.pushTyped(bytecode->getDouble(bci + 1));
                break;
            case BC_ILOAD:
                stack.pushTyped(bytecode->getInt64(bci + 1));
                break;
            case BC_SLOAD:
                stack.pushTyped(bytecode->getUInt16(bci + 1));
                break;

            case BC_DLOAD0:
                stack.pushTyped(double(0));
                break;
            case BC_ILOAD0:
                stack.pushTyped(int64_t(0));
                break;
            case BC_SLOAD0:
                stack.pushTyped(uint16_t(0));
                break;
            case BC_DLOAD1:
                stack.pushTyped(double(1));
                break;
            case BC_ILOAD1:
                stack.pushTyped(int64_t(1));
                break;

            case BC_DADD:
                stack.pushDouble(stack.popDouble() + stack.popDouble());
                break;
            case BC_IADD:
                stack.pushInt64(stack.popInt64() + stack.popInt64());
                break;
            case BC_DSUB:
                stack.pushDouble(stack.popDouble() - stack.popDouble());
                break;
            case BC_ISUB:
                stack.pushInt64(stack.popInt64() - stack.popInt64());
                break;
            case BC_DMUL:
                stack.pushDouble(stack.popDouble() * stack.popDouble());
                break;
            case BC_IMUL:
                stack.pushInt64(stack.popInt64() * stack.popInt64());
                break;
            case BC_DDIV:
                stack.pushDouble(stack.popDouble() / stack.popDouble());
                break;
            case BC_IDIV:
                stack.pushInt64(stack.popInt64() / stack.popInt64());
                break;
            case BC_IMOD:
                stack.pushInt64(stack.popInt64() % stack.popInt64());
                break;
            case BC_DNEG:
                stack.pushDouble(-stack.popDouble());
                break;
            case BC_INEG:
                stack.pushInt64(-stack.popInt64());
                break;

            case BC_IPRINT:
                std::cout << stack.popInt64();
                break;
            case BC_DPRINT:
                std::cout << stack.popDouble();
                break;
            case BC_SPRINT:
                std::cout << constantById(stack.popUInt16());
                break;
            case BC_POP:
                stack.pop();
                break;

            case BC_LOADDVAR0:
                stack.pushDouble(var_map[0].getDouble());
                break;
            case BC_LOADDVAR1:
                stack.pushDouble(var_map[1].getDouble());
                break;
            case BC_LOADDVAR2:
                stack.pushDouble(var_map[2].getDouble());
                break;
            case BC_LOADDVAR3:
                stack.pushDouble(var_map[3].getDouble());
                break;

            case BC_LOADIVAR0:
                stack.pushInt64(var_map[0].getInt64());
                break;
            case BC_LOADIVAR1:
                stack.pushInt64(var_map[1].getInt64());
                break;
            case BC_LOADIVAR2:
                stack.pushInt64(var_map[2].getInt64());
                break;
            case BC_LOADIVAR3:
                stack.pushInt64(var_map[3].getInt64());
                break;

            case BC_LOADSVAR0:
                stack.pushUInt16(var_map[0].getUInt16());
                break;
            case BC_LOADSVAR1:
                stack.pushUInt16(var_map[1].getUInt16());
                break;
            case BC_LOADSVAR2:
                stack.pushUInt16(var_map[2].getUInt16());
                break;
            case BC_LOADSVAR3:
                stack.pushUInt16(var_map[3].getUInt16());
                break;

            case BC_STOREDVAR0:
                var_map[0].setDouble(stack.popDouble());
                break;
            case BC_STOREIVAR0:
                var_map[0].setInt64(stack.popInt64());
                break;
            case BC_STORESVAR0:
                var_map[0].setUInt16(stack.popUInt16());
                break;

            case BC_LOADDVAR:
                stack.pushDouble(var_map[bytecode->getUInt16(bci + 1)].getDouble());
                break;
            case BC_LOADIVAR:
                stack.pushInt64(var_map[bytecode->getUInt16(bci + 1)].getInt64());
                break;
            case BC_LOADSVAR:
                stack.pushUInt16(var_map[bytecode->getUInt16(bci + 1)].getUInt16());
                break;

            case BC_STOREDVAR:
                var_map[bytecode->getUInt16(bci + 1)].setDouble(stack.popDouble());
                break;
            case BC_STOREIVAR:
                var_map[bytecode->getUInt16(bci + 1)].setInt64(stack.popInt64());
                break;
            case BC_STORESVAR:
            //                  out << name << " @" << getUInt16(bci + 1);
                var_map[bytecode->getUInt16(bci + 1)].setUInt16(stack.popUInt16());
                break;

            //              case BC_LOADCTXDVAR:
            //              case BC_STORECTXDVAR:
            //              case BC_LOADCTXIVAR:
            //              case BC_STORECTXIVAR:
            //              case BC_LOADCTXSVAR:
            //              case BC_STORECTXSVAR:
            ////                  out << name << " @" << getUInt16(bci + 1)
            ////                      << ":" << getUInt16(bci + 3);
            //                  break;
            case BC_IFICMPNE:
                if (stack.popInt64() != stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_IFICMPE:
                if (stack.popInt64() == stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_IFICMPG:
                if (stack.popInt64() > stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_IFICMPGE:
                if (stack.popInt64() >= stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_IFICMPL: 
                if (stack.popInt64() < stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_IFICMPLE:
                if (stack.popInt64() <= stack.popInt64()) {
                    bci += bytecode->getInt16(bci + 1) + 1;
                    continue;
                }
                break;
            case BC_JA:
                bci += bytecode->getInt16(bci + 1) + 1;
                continue;
                break;
            case BC_CALL://{
                stack.pushTyped(bci + length);
                stack.pushTyped(function->id());

//                std::clog << "saving return address: " << function->id() << ":" << bci + length << std::endl;
//                uint16_t f = stack.popUInt16();
//                size_t b = stack.popTyped<size_t>();
//                std::clog << "checking return address: " << f << ":" << b << std::endl;
//                stack.pushTyped(bci + length);
//                stack.pushTyped(function->id());

                function = (BytecodeFunction*) functionById(bytecode->getUInt16(bci + 1));
                if (!function) {
                  return new Status("Unresolved function ID\n", bci);
                }
                bytecode = function->bytecode();
                bci = 0;
                continue;
                break;//}
            case BC_CALLNATIVE:
                return new Status("Native functions are currently not supported\n", bci);
                break;
            case BC_RETURN: {
                uint16_t new_function_id = stack.popUInt16();
//                std::clog << "new func id=" << new_function_id << std::endl;
                function = (BytecodeFunction*) functionById(new_function_id);
                if (!function) {
                  return new Status("Unresolved function ID\n", bci);
                }
                bytecode = function->bytecode();
                size_t new_bci = stack.popTyped<size_t>();
//                std::clog << "new bci=" << new_bci << std::endl;
                bci = new_bci;
                continue;
                break;
            }
            case BC_BREAK:
                return new Status("Breakpoints are currently not supported\n", bci);
                break;
            default:
                return new Status("Unknown or unsupported instruction\n", bci);
        }
        bci += length;
    }
#ifdef ENABLE_TRACING
    std::cout << "Result = " << var_map[0].getInt64() << std::endl;
#endif
    return 0;
}
    void SimpleInterpreter::run(ostream &out) {
        stack.resize(50);
        bytecodes.clear();
        indices.clear();
        vars.clear();
        bytecodes.push_back(bytecode);
        indices.push_back(0);
        contextID.push_back(0);
        callsCounter.push_back(0);
        SP = 0;

        while (!bytecodes.empty()) {
            indexType &currentIndex = indices.back();
            Bytecode &bytecode = *bytecodes.back();
            Instruction instruction = bytecode.getInsn(currentIndex);
            size_t instructionLength = bytecodeLength(instruction);
#ifdef LOG_INTERPRETER
            const char* bcName = bytecodeName(instruction, 0);
            cout << "index: " << currentIndex << ", instruction: " << bcName << endl;
#endif
            switch (instruction) {
                case BC_DLOAD: pushVariable(bytecode.getDouble(currentIndex + 1));
                    break;
                case BC_ILOAD: pushVariable(bytecode.getInt64(currentIndex + 1));
                    break;
                case BC_SLOAD: pushVariable(constantById(bytecode.getUInt16(currentIndex + 1)).c_str());
                    break;
                case BC_DLOAD0: pushVariable(0.0);
                    break;
                case BC_ILOAD0: pushVariable((signedIntType) 0);
                    break;
                case BC_SLOAD0: pushVariable("");
                    break;
                case BC_DLOAD1: pushVariable(1.0);
                    break;
                case BC_ILOAD1: pushVariable((signedIntType) 1);
                    break;
                case BC_DLOADM1: pushVariable(-1.0);
                    break;
                case BC_ILOADM1: pushVariable((signedIntType) - 1);
                    break;
                case BC_DADD: binary_operation(VT_DOUBLE, add<double>);
                    break;
                case BC_IADD: binary_operation(VT_INT, add < signedIntType > );
                    break;
                case BC_DSUB: binary_operation(VT_DOUBLE, sub<double>);
                    break;
                case BC_ISUB: binary_operation(VT_INT, sub < signedIntType > );
                    break;
                case BC_DMUL: binary_operation(VT_DOUBLE, mul<double>);
                    break;
                case BC_IMUL: binary_operation(VT_INT, mul < signedIntType > );
                    break;
                case BC_DDIV: binary_operation(VT_DOUBLE, _div<double>);
                    break;
                case BC_IDIV: binary_operation(VT_INT, _div < signedIntType > );
                    break;
                case BC_IMOD: binary_operation(VT_INT, mod < signedIntType > );
                    break;
                case BC_DNEG: unary_operation(VT_DOUBLE, neg<double>);
                    break;
                case BC_INEG: unary_operation(VT_INT, neg < signedIntType > );
                    break;
                case BC_IAOR: binary_operation(VT_INT, _or < signedIntType > );
                    break;
                case BC_IAAND: binary_operation(VT_INT, _and < signedIntType > );
                    break;
                case BC_IAXOR: binary_operation(VT_INT, _xor < signedIntType > );
                    break;
                case BC_IPRINT: out << popVariable().getIntValue();
                    out.flush();
                    break;
                case BC_DPRINT: out << popVariable().getDoubleValue();
                    out.flush();
                    break;
                case BC_SPRINT: out << popVariable().getStringValue();
                    out.flush();
                    break;
                case BC_SWAP: {
                    auto v1 = popVariable();
                    auto v2 = popVariable();
                    pushVariable(v1);
                    pushVariable(v2);
                    break;
                }
                case BC_STOREDVAR0:
                case BC_STOREIVAR0:
                case BC_STORESVAR0: storeVariable(0);
                    break;
                case BC_STOREDVAR1:
                case BC_STOREIVAR1:
                case BC_STORESVAR1: storeVariable(1);
                    break;
                case BC_STOREDVAR2:
                case BC_STOREIVAR2:
                case BC_STORESVAR2: storeVariable(2);
                    break;
                case BC_STOREDVAR3:
                case BC_STOREIVAR3:
                case BC_STORESVAR3: storeVariable(3);
                    break;
                case BC_LOADDVAR:
                case BC_LOADIVAR:
                case BC_LOADSVAR: pushVariable(loadVariable(bytecode.getUInt16(currentIndex + 1)));
                    break;
                case BC_LOADDVAR0:
                case BC_LOADIVAR0:
                case BC_LOADSVAR0: pushVariable(loadVariable(0));
                    break;
                case BC_LOADDVAR1:
                case BC_LOADIVAR1:
                case BC_LOADSVAR1: pushVariable(loadVariable(1));
                    break;
                case BC_LOADIVAR2:
                case BC_LOADSVAR2:
                case BC_LOADDVAR2: pushVariable(loadVariable(2));
                    break;
                case BC_LOADDVAR3:
                case BC_LOADIVAR3:
                case BC_LOADSVAR3: pushVariable(loadVariable(3));
                    break;
                case BC_STOREDVAR:
                case BC_STOREIVAR:
                case BC_STORESVAR: storeVariable(bytecode.getUInt16(currentIndex + 1));
                    break;
                case BC_LOADCTXDVAR:
                case BC_LOADCTXIVAR:
                case BC_LOADCTXSVAR: pushVariable(loadVariable(bytecode.getUInt16(currentIndex + 1), bytecode.getUInt16(currentIndex + 3)));
                    break;
                case BC_STORECTXDVAR:
                case BC_STORECTXIVAR:
                case BC_STORECTXSVAR: storeVariable(bytecode.getUInt16(currentIndex + 1), bytecode.getUInt16(currentIndex + 3));
                    break;
                case BC_DCMP: binary_operation<double, signedIntType>(VT_DOUBLE, _cmp<double>);
                    break;
                case BC_ICMP: binary_operation(VT_INT, _cmp < signedIntType > );
                    break;
                case BC_JA: {
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPNE: {
                    if (!check_condition(_neq<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPE: {
                    if (!check_condition(_eq<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPG: {
                    if (!check_condition(_g<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPGE: {
                    if (!check_condition(_ge<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPL: {
                    if (!check_condition(_l<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_IFICMPLE: {
                    if (!check_condition(_le<signedIntType>))
                        break;
                    currentIndex += bytecode.getInt16(currentIndex + 1) + 1;
                    continue;
                }
                case BC_STOP: {
                    indices.clear();
                    bytecodes.clear();
                    continue;
                }
                case BC_CALLNATIVE: {
                    callNative(bytecode.getUInt16(currentIndex + 1));
                    break;
                }
                case BC_CALL: {
                    TranslatedFunction *f = functionById(bytecode.getUInt16(currentIndex + 1));
                    bytecodes.push_back(static_cast<BytecodeFunction *>(f)->bytecode());
                    indices.push_back(0);
                    contextID.push_back(f->id());
                    detectCallWithFunctionID(contextID.back());
                    continue;
                }
                case BC_RETURN: {
                    indices.pop_back();
                    bytecodes.pop_back();
                    if (!indices.empty()) {
                        indices.back() += bytecodeLength(BC_CALL);
                    }
                    if (callsCounter[contextID.back()] > 0) {
                        callsCounter[contextID.back()]--;
                    }
                    contextID.pop_back();
                    continue;
                }
                case BC_I2D: pushVariable((double) popVariable().getIntValue());
                    break;
                case BC_D2I: pushVariable((signedIntType) popVariable().getDoubleValue());
                    break;
                case BC_S2I: pushVariable((signedIntType) popVariable().getStringValue());
                    break;
                case BC_BREAK: break;
                case BC_INVALID: throw InterpretationError("BC_Invalid instruction");
                default: throw InterpretationError(string("Unknown interpreting instruction: ") + bytecodeName(instruction, 0));
            }
            currentIndex += instructionLength;
        }
    }
Status *BytecodeInterpreter::execute(vector<Var *> &) try {
    #ifdef BCPRINT
    disassemble();
    return Status::Ok();
    #endif

    #ifdef MATHVM_WITH_SDL
    pre_init_sdl();
    #endif

    processCall(0);
    while (pointer() < bc()->length()) {
        Instruction instruction = next();
        switch (instruction) {
            case BC_INVALID:    throw "Invalid code";
            case BC_DLOAD:      operandStack.push_back(bc_read<double>()); break;
            case BC_ILOAD:      operandStack.push_back(bc_read<int64_t>()); break;
            case BC_SLOAD:      operandStack.push_back(constantById(bc_read<uint16_t>()).c_str()); break;
            case BC_DLOAD0:     operandStack.push_back((double)0); break;
            case BC_ILOAD0:     operandStack.push_back((int64_t)0); break;
            case BC_SLOAD0:     operandStack.push_back(constantById(0).c_str()); break;
            case BC_DLOAD1:     operandStack.push_back((double)1.0); break;
            case BC_ILOAD1:     operandStack.push_back((int64_t)1); break;
            case BC_DLOADM1:    operandStack.push_back((double) - 1.0); break;
            case BC_ILOADM1:    operandStack.push_back((int64_t) - 1); break;
            case BC_DADD:       operandStack.push_back(pop_return().d + pop_return().d); break;
            case BC_IADD:       operandStack.push_back(pop_return().i + pop_return().i); break;
            case BC_DSUB:       operandStack.push_back(pop_return().d - pop_return().d); break;
            case BC_ISUB:       operandStack.push_back(pop_return().i - pop_return().i); break;
            case BC_DMUL:       operandStack.push_back(pop_return().d * pop_return().d); break;
            case BC_IMUL:       operandStack.push_back(pop_return().i * pop_return().i); break;
            case BC_DDIV:       operandStack.push_back(pop_return().d / pop_return().d); break;
            case BC_IDIV:       operandStack.push_back(pop_return().i / pop_return().i); break;
            case BC_IMOD:       operandStack.push_back(pop_return().i % pop_return().i); break;
            case BC_IAOR:       operandStack.push_back(pop_return().i | pop_return().i); break;
            case BC_IAAND:      operandStack.push_back(pop_return().i & pop_return().i); break;
            case BC_IAXOR:      operandStack.push_back(pop_return().i ^ pop_return().i); break;
            case BC_DNEG:       operandStack.back().d = -operandStack.back().d; break;
            case BC_INEG:       operandStack.back().i = -operandStack.back().i; break;
            case BC_DPRINT:     std::cout << pop_return().d << std::flush; break;
            case BC_IPRINT:     std::cout << pop_return().i << std::flush; break;
            case BC_SPRINT:     std::cout << pop_return().c << std::flush; break;
            case BC_I2D:        operandStack.back().d = operandStack.back().i; break;
            case BC_D2I :       operandStack.back().i = operandStack.back().d; break;
            case BC_S2I:        operandStack.back().i = reinterpret_cast<int64_t>(operandStack.back().c); break;
            case BC_SWAP:       std::iter_swap(operandStack.end() - 1, operandStack.end() - 2); break;
            case BC_POP:        operandStack.pop_back(); break;
            case BC_LOADDVAR:
            case BC_LOADIVAR:
            case BC_LOADSVAR:   operandStack.push_back(value(bc_read<uint16_t>())); break;
            case BC_STOREDVAR:
            case BC_STOREIVAR:
            case BC_STORESVAR:  value(bc_read<uint16_t>()) = pop_return(); break;
            case BC_LOADCTXDVAR:
            case BC_LOADCTXIVAR:
            case BC_LOADCTXSVAR: operandStack.push_back(value(bc_read<uint16_t>(), bc_read<uint16_t>())); break;
            case BC_STORECTXDVAR:
            case BC_STORECTXIVAR:
            case BC_STORECTXSVAR: value(bc_read<uint16_t>(), bc_read<uint16_t>()) = pop_return(); break;
            case BC_DCMP:       operandStack.push_back(compare<double>(pop_return().d, pop_return().d)); break;
            case BC_ICMP:       operandStack.push_back(compare<int64_t>(pop_return().i, pop_return().i)); break;
            case BC_JA:         pointer() += bc()->getInt16(pointer()); break;
            case BC_IFICMPE:    pointer() += pop_return().i == pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_IFICMPNE:   pointer() += pop_return().i != pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_IFICMPG:    pointer() += pop_return().i >  pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_IFICMPGE:   pointer() += pop_return().i >= pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_IFICMPL:    pointer() += pop_return().i <  pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_IFICMPLE:   pointer() += pop_return().i <= pop_return().i ? bc()->getInt16(pointer()) : sizeof(int16_t); break;
            case BC_CALL:       processCall(bc_read<uint16_t>()); break;
            case BC_CALLNATIVE: processNativeCall(bc_read<uint16_t>()); break;
            case BC_RETURN:     processReturn(); break;
            case BC_BREAK:      break;
            case BC_DUMP:       std::cout << operandStack.back().i << std::endl; break;
            case BC_STOP:       return Status::Warning("Execution stopped");
            default: throw "Not implemented"; break;
        }
    }
    return Status::Ok();
} catch (const char *msg) {
    return Status::Error(msg);
}
Exemple #4
0
    void Interpreter::funExec(BytecodeFunction* f) {
        size_t bci = 0;
        size_t k = 0;
        while (bci < f->bytecode()->length()) {
            ++k;
            Instruction insn = f->bytecode()->getInsn(bci);
            switch (insn) {
                case BC_INVALID: {
                    std::cerr << "Invalid instruction!\n";
                    return;
                    break;
                }
                case BC_DLOAD: {
                    Var var(VT_DOUBLE, "");
                    var.setDoubleValue(f->bytecode()->getDouble(bci + 1));
                    programStack.push(var);
                    break;
                }
                case BC_ILOAD: {
                    Var var(VT_INT, "");
                    var.setIntValue(f->bytecode()->getInt64(bci + 1));
                    programStack.push(var);
                    break;
                }
                case BC_SLOAD: {
                    Var var(VT_STRING, "");
                    var.setStringValue(constantById(f->bytecode()->getUInt16(bci + 1)).c_str());
                    programStack.push(var);
                    break;
                }
                case BC_DLOAD0: {
                    Var var(VT_DOUBLE, "");
                    var.setDoubleValue(0.0);
                    programStack.push(var);
                    break;
                }
                case BC_ILOAD0: {
                    Var var(VT_INT, "");
                    var.setIntValue(0L);
                    programStack.push(var);
                    break;
                }
                case BC_SLOAD0: {
                    Var var(VT_STRING, "");
                    var.setStringValue("");
                    programStack.push(var);
                    break;
                }
                case BC_DLOAD1: {
                    Var var(VT_DOUBLE, "");
                    var.setDoubleValue(1.0);
                    programStack.push(var);
                    break;
                }
                case BC_ILOAD1: {
                    Var var(VT_INT, "");
                    var.setIntValue(1L);
                    programStack.push(var);
                    break;
                }
                case BC_DLOADM1: {
                    Var var(VT_DOUBLE, "");
                    var.setDoubleValue(-1.0);
                    programStack.push(var);
                    break;
                }
                case BC_ILOADM1: {
                    Var var(VT_INT, "");
                    var.setIntValue(-1L);
                    programStack.push(var);
                    break;
                }
                case BC_DADD: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(leftOperand.getDoubleValue() + rightOperand.getDoubleValue());
                    programStack.push(result);
                    break;
                }
                case BC_IADD: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(leftOperand.getIntValue() + rightOperand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_DSUB: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(leftOperand.getDoubleValue() - rightOperand.getDoubleValue());
                    programStack.push(result);
                    break;
                }
                case BC_ISUB: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(leftOperand.getIntValue() - rightOperand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_DMUL: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(leftOperand.getDoubleValue() * rightOperand.getDoubleValue());
                    programStack.push(result);
                    break;
                }
                case BC_IMUL: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(leftOperand.getIntValue() * rightOperand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_DDIV: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(leftOperand.getDoubleValue() / rightOperand.getDoubleValue());
                    programStack.push(result);
                    break;
                }
                case BC_IDIV: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(leftOperand.getIntValue() / rightOperand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_IMOD: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(leftOperand.getIntValue() % rightOperand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_DNEG: {
                    Var operand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(-operand.getDoubleValue());
                    programStack.push(result);
                    break;
                }
                case BC_INEG: {
                    Var operand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(-operand.getIntValue());
                    programStack.push(result);
                    break;
                }
                case BC_IPRINT: {
                    Var operand = programStack.top();
                    programStack.pop();
                    std::cout << operand.getIntValue();
                    break;
                }
                case BC_DPRINT: {
                    Var operand = programStack.top();
                    programStack.pop();
                    std::cout << operand.getDoubleValue();
                    break;
                }
                case BC_SPRINT: {
                    Var operand = programStack.top();
                    programStack.pop();
                    std::cout << operand.getStringValue();
                    break;
                }
                case BC_I2D: {
                    Var operand = programStack.top();
                    programStack.pop();
                    Var result(VT_DOUBLE, "");
                    result.setDoubleValue(static_cast<double>(operand.getIntValue()));
                    programStack.push(result);
                    break;
                }
                case BC_D2I: {
                    Var operand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(static_cast<int64_t>(operand.getDoubleValue()));
                    programStack.push(result);
                    break;
                }
                case BC_S2I: {
                    Var operand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    result.setIntValue(atoi(operand.getStringValue()));
                    programStack.push(result);
                    break;
                }
                case BC_SWAP: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    programStack.push(leftOperand);
                    programStack.push(rightOperand);
                    break;
                }
                case BC_POP: {
                    programStack.pop();
                    break;
                }
                case BC_LOADSVAR0:
                case BC_LOADIVAR0:
                case BC_LOADDVAR0: {
                    map<uint16_t, Var>::iterator iter = memory.find(0);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        std::cerr << "Can't load variable 0!\n";
                    }
                    break;
                }
                case BC_LOADSVAR1:
                case BC_LOADIVAR1:
                case BC_LOADDVAR1: {
                    map<uint16_t, Var>::iterator iter = memory.find(1);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        std::cerr << "Can't load variable 1!\n";
                    }

                    break;
                }
                case BC_LOADSVAR2:
                case BC_LOADIVAR2:
                case BC_LOADDVAR2: {
                    map<uint16_t, Var>::iterator iter = memory.find(2);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        std::cerr << "Can't load variable 2!\n";
                    }

                    break;
                }
                case BC_LOADSVAR3:
                case BC_LOADIVAR3:
                case BC_LOADDVAR3: {
                    map<uint16_t, Var>::iterator iter = memory.find(3);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        std::cerr << "Can't load variable 3!\n";
                    }

                    break;
                }
                case BC_STORESVAR0:
                case BC_STOREIVAR0:
                case BC_STOREDVAR0: {
                    map<uint16_t, Var>::iterator iter = memory.find(0);
                    if (iter != memory.end()) {
                        iter->second = programStack.top();
                    } else {
                        memory.insert(make_pair(0, programStack.top()));
                    }
                    programStack.pop();
                    break;
                }
                case BC_STORESVAR1:
                case BC_STOREIVAR1:
                case BC_STOREDVAR1: {
                    map<uint16_t, Var>::iterator iter = memory.find(1);
                    if (iter != memory.end()) {
                        iter->second = programStack.top();
                    } else {
                        memory.insert(make_pair(1, programStack.top()));
                    }
                    programStack.pop();
                    break;
                }
                case BC_STORESVAR2:
                case BC_STOREIVAR2:
                case BC_STOREDVAR2: {
                    map<uint16_t, Var>::iterator iter = memory.find(2);
                    if (iter != memory.end()) {
                        iter->second = programStack.top();
                    } else {
                        memory.insert(make_pair(2, programStack.top()));
                    }
                    programStack.pop();
                    break;
                }
                case BC_STORESVAR3:
                case BC_STOREIVAR3:
                case BC_STOREDVAR3: {
                    map<uint16_t, Var>::iterator iter = memory.find(3);
                    if (iter != memory.end()) {
                        iter->second = programStack.top();
                    } else {
                        memory.insert(make_pair(3, programStack.top()));
                    }
                    programStack.pop();
                    break;
                }
                case BC_LOADDVAR: {
                    uint16_t id = f->bytecode()->getUInt16(bci + 1);
                    map<uint16_t, Var>::iterator iter = memory.find(id);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        //std::cerr << "Can't load variable " << id << "!\n";
                        Var var(VT_DOUBLE, "");
                        var.setDoubleValue(0.0);
                        programStack.push(var);
                    }
                    break;
                }
                case BC_LOADIVAR: {
                    uint16_t id = f->bytecode()->getUInt16(bci + 1);
                    map<uint16_t, Var>::iterator iter = memory.find(id);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        //std::cerr << "Can't load variable " << id << "!\n";
                        Var var(VT_INT, "");
                        var.setIntValue(0);
                        programStack.push(var);
                    }
                    break;
                }
                case BC_LOADSVAR: {
                    uint16_t id = f->bytecode()->getUInt16(bci + 1);
                    map<uint16_t, Var>::iterator iter = memory.find(id);
                    if (iter != memory.end()) {
                        programStack.push(iter->second);
                    } else {
                        //std::cerr << "Can't load variable " << id << "!\n";
                        Var var(VT_STRING, "");
                        var.setStringValue("");
                        programStack.push(var);
                    }
                    break;
                }
                case BC_STOREDVAR:
                case BC_STOREIVAR:
                case BC_STORESVAR: {
                    uint16_t id = f->bytecode()->getUInt16(bci + 1);
                    map<uint16_t, Var>::iterator iter = memory.find(id);
                    if (iter != memory.end()) {
                        iter->second = programStack.top();
                    } else {
                        memory.insert(make_pair(id, programStack.top()));
                    }
                    programStack.pop();
                    break;
                }
                case BC_DCMP: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    if (leftOperand.getDoubleValue() > rightOperand.getDoubleValue()) {
                        result.setIntValue(1);
                    } else if (leftOperand.getDoubleValue() == rightOperand.getDoubleValue()) {
                        result.setIntValue(0);
                    } else {
                        result.setIntValue(-1);
                    }
                    programStack.push(result);
                    break;
                }
                case BC_ICMP: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.pop();
                    Var result(VT_INT, "");
                    if (leftOperand.getIntValue() > rightOperand.getIntValue()) {
                        result.setIntValue(1);
                    } else if (leftOperand.getIntValue() == rightOperand.getIntValue()) {
                        result.setIntValue(0);
                    } else {
                        result.setIntValue(-1);
                    }
                    programStack.push(result);
                    break;
                }
                case BC_JA: {
                    bci += (f->bytecode()->getInt16(bci + 1));
                    continue;
                }
                case BC_IFICMPNE: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() != rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_IFICMPE: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() == rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_IFICMPG: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() > rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_IFICMPGE: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() >= rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_IFICMPL: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() < rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_IFICMPLE: {
                    Var leftOperand = programStack.top();
                    programStack.pop();
                    Var rightOperand = programStack.top();
                    programStack.push(leftOperand);
                    if (leftOperand.getIntValue() <= rightOperand.getIntValue()) {
                        bci += (f->bytecode()->getInt16(bci + 1));
                        continue;
                    }
                    break;
                }
                case BC_STOP: {
                    return;
                }
                case BC_CALL: {
                    int id = f->bytecode()->getUInt16(bci + 1);
                    BytecodeFunction* functionToCall = (BytecodeFunction*) functionById(id);
                    
                    returnAddresses.push(bci + commandLen[insn]);
                    returnLocations.push(f);
                    
                    bci = 0;
                    f = functionToCall;
                    continue;
                }
                case BC_RETURN: {
                    f = returnLocations.top();
                    returnLocations.pop();
                    
                    bci = returnAddresses.top();
                    returnAddresses.pop();
                    continue;
                }
                default: {
                    std::cerr << "Unknown instruction!\n";
                    return;
                }
            }
            bci += commandLen[insn];
        }
    }