R runner(SimpleInterpreter *p, void *func, size_t paramsCount) { switch (paramsCount) { case 0: return nativeCaller<R>(func); case 1: return Collector<0, 1, R, decltype(make_tuple())>::run(p, func, make_tuple()); case 2: return Collector<0, 2, R, decltype(make_tuple())>::run(p, func, make_tuple()); case 3: return Collector<0, 3, R, decltype(make_tuple())>::run(p, func, make_tuple()); case 4: return Collector<0, 4, R, decltype(make_tuple())>::run(p, func, make_tuple()); default: throw InterpretationError("Non-jit native caller can't process " + to_string(paramsCount) + " function parameters. Call AmJit insted"); } }
static R run(SimpleInterpreter *inter, void* f, T a) { auto p = inter->loadVariable(index); switch (p._type) { case VT_DOUBLE: return Collector<index + 1, size, R, decltype(tuple_cat(a, make_tuple(p.getDoubleValue())))>:: run(inter, f, tuple_cat(a, make_tuple(p.getDoubleValue()))); case VT_INT: return Collector<index + 1, size, R, decltype(tuple_cat(a, make_tuple(p.getIntValue())))>:: run(inter, f, tuple_cat(a, make_tuple(p.getIntValue()))); case VT_STRING: return Collector<index + 1, size, R, decltype(tuple_cat(a, make_tuple(p.getStringValue())))>:: run(inter, f, tuple_cat(a, make_tuple(p.getStringValue()))); default: throw InterpretationError("Unknown type of " + to_string(index) + " function parameter"); } }
void callNative(uint16_t id) { const Signature *signature; const std::string *name; void *nativeFunctionAddress = (void *) nativeById(id, &signature, &name); if (!nativeFunctionAddress) { throw InterpretationError("Native function not found"); } size_t paramsCount = signature->size() - 1; VarType returnType = signature->at(0).first; if (paramsCount <= 4) { callNativeFunctionViaTemplateMagic(nativeFunctionAddress, paramsCount, returnType); } else { callNativeFunctionViaAsmJit(nativeFunctionAddress, signature, returnType); } }
void Pattern::apply(Tree *pTree) const { // do interpretation text::TokenSequence &text = *pTree->refText(); Interpreter &interp = const_cast<Pattern *>(this)->interp; interp.setCutoffValue(cutoffValue * (long long)text.size()); interp.swapVariable(varName, &text); boost::int32_t errorPc = interp.interpret(0); if (errorPc > 0) { interp.swapVariable(varName, &text); throw InterpretationError((boost::format("PC = %d, ErrorCode = %d") % errorPc % (100 + interp.getError().code)).str()); } else { interp.swapVariable(varName, &text); } }
void SimpleInterpreter::callNativeFunctionViaTemplateMagic(void* f, size_t params, VarType returnType) { switch (returnType) { case VT_VOID: runner<void>(this, f, params); break; case VT_DOUBLE: pushVariable(runner<double>(this, f, params)); break; case VT_INT: pushVariable(runner<signedIntType>(this, f, params)); break; case VT_STRING: pushVariable(runner<char const*>(this, f, params)); break; default: throw InterpretationError("Wrong native function return type"); } }
void storeVariable(unsignedIntType contextID, unsignedIntType id) { while (vars.size() <= contextID){ vars.push_back(vector<Variables>()); } while(callsCounter.size() <= contextID) { callsCounter.push_back(0); } vector<Variables> ¤tRecursiveScope = vars[contextID]; while (currentRecursiveScope.size() <= callsCounter[contextID]) { currentRecursiveScope.push_back(Variables()); } Variables &local_vars = currentRecursiveScope[callsCounter[contextID]]; while (local_vars.size() <= id) { local_vars.push_back(TypedVariable(VT_INT)); } if (local_vars.size() > MAX_VARS_COUNT) { throw InterpretationError("Too many variables"); } local_vars[id] = popVariable(); }
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 ¤tIndex = 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; } }