void BytecodeTranslatorVisitor::visitForNode(ForNode* node) { onVisitNode(node); const AstVar* i = node->var(); if (i->type() != VT_INT) ERROR("Non-iterable type in for loop"); const BinaryOpNode* expr = node->inExpr()->asBinaryOpNode(); if (expr == NULL || expr->kind() != tRANGE) ERROR("Invalid range in for loop"); CONTEXT(function(), locals(), node->body()->scope(), typeStack()); beforeProcessBlock(); bool needTempVar = !expr->right()->isIntLiteralNode(); AstVar* temp = NULL; if (needTempVar) { if (!scope()->declareVariable("<tempForEnd>", VT_INT)) ERROR("internal error: temp name is unavailable"); temp = scope()->lookupVariable("<tempForEnd>", false); } Label L_Begin(bytecode()); Label L_End(bytecode()); VISIT(expr->left()); EMIT_STORE(i); if (needTempVar) { VISIT(expr->right()); EMIT_STORE(temp); popType(VT_INT); } popType(VT_INT); EMIT_BIND(L_Begin); if (needTempVar) EMIT_LOAD(temp); else VISIT(expr->right()); EMIT_LOAD(i); EMIT_BRANCH(BC_IFICMPG, L_End); processBlockNode(node->body()); afterProcessBlock(); /* i += 1 */ EMIT_LOAD(i); EMIT(BC_ILOAD1); EMIT(BC_IADD); EMIT_STORE(i); EMIT_BRANCH(BC_JA, L_Begin); EMIT_BIND(L_End); pushType(VT_VOID); }
void BytecodeTranslatorVisitor::visitBinaryOpNode(BinaryOpNode * node) { onVisitNode(node); TokenKind op = node->kind(); if (op == tOR || op == tAND) { processLazyLogic(node); return; } VISIT(node->right()); ensureTopIsNumeric(); VISIT(node->left()); ensureTopIsNumeric(); if (tEQ <= op && op <= tLE) processComparison(node->kind()); else if (tADD <= op && op <= tDIV) processNumericOperation(node->kind()); else if (op == tMOD || op == tAXOR || op == tAOR || op == tAAND) { popType(VT_INT); ensureTopType(VT_INT); EMIT(op == tAXOR ? BC_IAXOR : op == tMOD ? BC_IMOD : op == tAOR ? BC_IAOR : BC_IAAND); } else ERROR("Unknown binary op"); }
void BytecodeTranslatorVisitor::castTopsToCommonType() { VarType hi = popType(); VarType lo = popType(); if (hi != lo) { if (hi == VT_DOUBLE) { EMIT(BC_SWAP); EMIT(BC_I2D); EMIT(BC_SWAP); } else { EMIT(BC_I2D); } hi = VT_DOUBLE; } pushType(hi); pushType(hi); }
void BytecodeTranslatorVisitor::processNumericOperation(TokenKind op) { castTopsToCommonType(); switch (op) { case tADD: EMIT(TYPED(ADD)); break; case tSUB: EMIT(TYPED(SUB)); break; case tMUL: EMIT(TYPED(MUL)); break; default : EMIT(TYPED(DIV)); break; } popType(); ensureTopIsNumeric(); }
void BytecodeTranslatorVisitor::falseJump(AstNode* node, Label& label) { bool isComparison = false; if (node->isBinaryOpNode()) { TokenKind kind = node->asBinaryOpNode()->kind(); if (tEQ <= kind && kind <= tLE) isComparison = true; } if (!isComparison) { visitTyped(node, VT_INT); EMIT(BC_ILOAD0); EMIT_BRANCH(BC_IFICMPE, label); } else { /* Premature optimization is the root of all evil */ VISIT(node->asBinaryOpNode()->right()); ensureTopIsNumeric(); VISIT(node->asBinaryOpNode()->left()); ensureTopIsNumeric(); TokenKind kind = node->asBinaryOpNode()->kind(); castTopsToCommonType(); Instruction cmp = TYPED(CMP); bool hack = topType() == VT_INT; popType(); popType(); if (!hack) { EMIT(cmp); EMIT(BC_ILOAD0); } switch (kind) { case tEQ: EMIT_BRANCH(BC_IFICMPNE, label); break; case tNEQ: EMIT_BRANCH(BC_IFICMPE, label); break; case tGT: EMIT_BRANCH(hack ? BC_IFICMPLE : BC_IFICMPGE, label); break; case tGE: EMIT_BRANCH(hack ? BC_IFICMPL : BC_IFICMPG, label); break; case tLT: EMIT_BRANCH(hack ? BC_IFICMPGE : BC_IFICMPLE, label); break; default: EMIT_BRANCH(hack ? BC_IFICMPG : BC_IFICMPL, label); break; } } }
void BytecodeTranslatorVisitor::processBlockNode(BlockNode* node) { for (uint32_t i = 0; i < node->nodes(); i++) { AstNode* ith = node->nodeAt(i); warningIf(isUnused(ith), "unused result of statement"); VISIT(ith); VarType result = popType(); if (result != VT_VOID && !ith->isReturnNode()) EMIT(BC_POP); } }
void BytecodeTranslatorVisitor::processComparison(TokenKind kind) { castTopsToCommonType(); Instruction cmp = TYPED(CMP); int hack = topType() == VT_INT ? 3 : 0; popType(); popType(); pushType(VT_INT); if (kind == tNEQ) { EMIT(cmp); return; } if (!hack) { EMIT(cmp); EMIT(BC_ILOAD0); } Label L_Fail(bytecode()); Label L_End(bytecode()); switch (kind) { case tEQ: EMIT_BRANCH(BC_IFICMPE, L_Fail); break; case tGT: EMIT_BRANCH(BC_IFICMPG, L_Fail); break; case tGE: EMIT_BRANCH(BC_IFICMPGE, L_Fail); break; case tLT: EMIT_BRANCH(BC_IFICMPL, L_Fail); break; default : EMIT_BRANCH(BC_IFICMPLE, L_Fail); break; } EMIT(BC_ILOAD1 - hack); EMIT_BRANCH(BC_JA, L_End); EMIT_BIND(L_Fail); EMIT(BC_ILOAD0 + hack); EMIT_BIND(L_End); }
void BytecodeTranslatorVisitor::visitPrintNode(PrintNode * node) { onVisitNode(node); for (uint32_t i = 0; i < node->operands(); ++i) { VISIT(node->operandAt(i)); switch (topType()) { case VT_INT: EMIT(BC_IPRINT); break; case VT_DOUBLE: EMIT(BC_DPRINT); break; case VT_STRING: EMIT(BC_SPRINT); break; default: ERROR("Unprintable parameter"); } popType(); } pushType(VT_VOID); }
void BytecodeTranslatorVisitor::tryCast(VarType to) { static Instruction castTable[VAR_TYPES_NUMBER][VAR_TYPES_NUMBER] = {BC_INVALID}; castTable[VT_INT][VT_DOUBLE] = BC_I2D; castTable[VT_DOUBLE][VT_INT] = BC_D2I; VarType from = topType(); if (from == to) return; Instruction cast = castTable[from][to]; if (!cast) ERROR(string("Cast error from ") + typeToName(from) + " to " + typeToName(to)); warningIf(cast == BC_D2I, "Casting double to int. I warned you!"); EMIT(cast); popType(); pushType(to); }
void BytecodeTranslatorVisitor::processLazyLogic(BinaryOpNode* node) { Label L_Lazy(bytecode()); Label L_End(bytecode()); bool isOr = node->kind() == tOR; VISIT(node->left()); popType(VT_INT); EMIT(BC_ILOAD0); EMIT_BRANCH(isOr ? BC_IFICMPNE : BC_IFICMPE, L_Lazy); VISIT(node->right()); ensureTopType(VT_INT); EMIT_BRANCH(BC_JA, L_End); EMIT_BIND(L_Lazy); EMIT(isOr ? BC_ILOAD1 : BC_ILOAD0); EMIT_BIND(L_End); }
void BytecodeTranslatorVisitor::visitStoreNode(StoreNode* node) { onVisitNode(node); visitTyped(node->value(), node->var()->type()); pushType(node->var()->type()); if (node->op() == tINCRSET || node->op() == tDECRSET) { ensureTopIsNumeric(); EMIT_LOAD(node->var()); if (node->op() == tINCRSET) EMIT(TYPED(ADD)); else EMIT(TYPED(SUB)); } else if (node->op() != tASSIGN) ERROR("Invalid store operation"); EMIT_STORE(node->var()); popType(); pushType(VT_VOID); /* a = b = c is forbidden */ }
bool popInt64() { return popType(OperandType::Int64); }
bool popPointer() { return popType(OperandType::Pointer); }
void BytecodeTranslatorVisitor::popType(VarType expected) { if (topType() != expected) ERROR(string("Expected: ") + typeToName(expected) + ", got: " + typeToName(topType())); popType(); }
bool popInt32() { return popType(OperandType::Int32); }
bool popFloat32() { return popType(OperandType::Float32); }
bool popFloat64() { return popType(OperandType::Float64); }
void BytecodeTranslatorVisitor::visitTyped(AstNode* node, VarType type) { VISIT(node); tryCast(type); popType(type); }
bool popOop() { return popType(OperandType::Oop); }