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::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; } } }
// All accesses to the stack and locals in this function use DataTypeGeneric so // this function should only be used for inspecting state; when the values are // actually used they must be constrained further. Type predictedTypeFromLocation(IRGS& env, const Location& loc) { switch (loc.space) { case Location::Stack: { auto i = loc.bcRelOffset; assertx(i >= 0); if (i < env.irb->evalStack().size()) { return topType(env, i, DataTypeGeneric); } else { auto stackTy = env.irb->stackType( offsetFromIRSP(env, i), DataTypeGeneric ); if (stackTy <= Type::BoxedCell) { return env.irb->stackInnerTypePrediction( offsetFromIRSP(env, i)).box(); } return stackTy; } } break; case Location::Local: return env.irb->predictedLocalType(loc.offset); case Location::Litstr: return Type::cns(curUnit(env)->lookupLitstrId(loc.offset)); case Location::Litint: return Type::cns(loc.offset); case Location::This: // Don't specialize $this for cloned closures which may have been re-bound if (curFunc(env)->hasForeignThis()) return Type::Obj; if (auto const cls = curFunc(env)->cls()) { return Type::SubObj(cls); } return Type::Obj; case Location::Iter: case Location::Invalid: break; } not_reached(); }
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::ensureTopIsNumeric() const { if (topType() != VT_INT && topType() != VT_DOUBLE) ERROR("Expected numeric type"); }
void BytecodeTranslatorVisitor::ensureTopType(VarType expected) const { if (topType() != expected) ERROR(string("Expected ") + typeToName(expected)); }
VarType BytecodeTranslatorVisitor::popType() { VarType type = topType(); typeStack()->pop(); return type; }
void BytecodeTranslatorVisitor::popType(VarType expected) { if (topType() != expected) ERROR(string("Expected: ") + typeToName(expected) + ", got: " + typeToName(topType())); popType(); }
Type publicTopType(const IRGS& env, BCSPOffset idx) { // It's logically const, because we're using DataTypeGeneric. return topType(const_cast<IRGS&>(env), idx, DataTypeGeneric); }
Type publicTopType(const HTS& env, int32_t idx) { // It's logically const, because we're using DataTypeGeneric. return topType(const_cast<HTS&>(env), idx, DataTypeGeneric); }