/** * Print the main method. */ void JVMWriter::printMainMethod() { const Function *f = module->getFunction("main"); if(!f || f->isDeclaration()) return; out << ".method public static main([Ljava/lang/String;)V\n"; printSimpleInstruction(".limit stack 4"); if(f->arg_size() == 0) { printSimpleInstruction("invokestatic", classname + "/main()I"); } else if(f->arg_size() == 2) { Function::const_arg_iterator arg1, arg2; arg1 = arg2 = f->arg_begin(); arg2++; if(!arg1->getType()->isIntegerTy() || arg2->getType()->getTypeID() != Type::PointerTyID) llvm_unreachable("main function has invalid type signature"); printSimpleInstruction("aload_0"); printSimpleInstruction("arraylength"); printSimpleInstruction("aload_0"); printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/storeStack([Ljava/lang/String;)I"); printSimpleInstruction("invokestatic", classname + "/main(" + getTypeDescriptor(arg1->getType()) + getTypeDescriptor(arg2->getType()) + ")I"); } else { llvm_unreachable("main function has invalid number of arguments"); } printSimpleInstruction("invokestatic", "lljvm/lib/c/exit(I)V"); printSimpleInstruction("return"); out << ".end method\n"; }
std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const { //This additional if is needed because getTypeDescriptor might fail if type is not registered // (and if casting is not needed, then registereing should no be required) if(!strcmp(from->name(), to->name())) return std::vector<CTypeList::TypeInfoPtr>(); return castSequence(getTypeDescriptor(from), getTypeDescriptor(to)); }
/** * Print the main method. */ void JVMWriter::printMainMethod() { const Function *f = module->getFunction("main"); if(!f || f->isDeclaration()) return; out << ".method public static main([Ljava/lang/String;)V\n"; printSimpleInstruction(".limit stack 6"); printSimpleInstruction(".limit locals 2"); printSimpleInstruction("new","lljvm/runtime/DefaultContext"); printSimpleInstruction("dup"); printSimpleInstruction("invokespecial","lljvm/runtime/DefaultContext/<init>()V"); printSimpleInstruction("dup"); printSimpleInstruction("astore_1"); printSimpleInstruction("ldc",classname); printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); printSimpleInstruction("checkcast",classname); if(f->arg_size() == 0) { printSimpleInstruction("invokevirtual",classname + "/main()I"); } else if(f->arg_size() == 2) { Function::const_arg_iterator arg1, arg2; arg1 = arg2 = f->arg_begin(); arg2++; if(!arg1->getType()->isIntegerTy() || arg2->getType()->getTypeID() != Type::PointerTyID) llvm_unreachable("main function has invalid type signature"); printSimpleInstruction("aload_0"); printSimpleInstruction("arraylength"); printSimpleInstruction("aload_1"); printSimpleInstruction("ldc","lljvm/runtime/Memory"); printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); printSimpleInstruction("checkcast","lljvm/runtime/Memory"); printSimpleInstruction("aload_0"); printSimpleInstruction("invokevirtual", "lljvm/runtime/Memory/storeStack([Ljava/lang/String;)I"); printSimpleInstruction("invokevirtual", classname + "/main(" + getTypeDescriptor(arg1->getType()) + getTypeDescriptor(arg2->getType()) + ")I"); } else { llvm_unreachable("main function has invalid number of arguments"); } printSimpleInstruction("aload_1"); printSimpleInstruction("ldc","lljvm/lib/c"); printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); printSimpleInstruction("checkcast","lljvm/lib/c"); printSimpleInstruction("swap"); printSimpleInstruction("invokevirtual", "lljvm/lib/c/exit(I)V"); printSimpleInstruction("return"); out << ".end method\n"; }
/** * Print a memory intrinsic function. * * @param inst the instruction */ void JVMWriter::printMemIntrinsic(const MemIntrinsic *inst) { printValueLoad(inst->getDest()); if(const MemTransferInst *minst = dyn_cast<MemTransferInst>(inst)) printValueLoad(minst->getSource()); else if(const MemSetInst *minst = dyn_cast<MemSetInst>(inst)) printValueLoad(minst->getValue()); printValueLoad(inst->getLength()); printConstLoad(inst->getAlignmentCst()); std::string lenDescriptor = getTypeDescriptor( inst->getLength()->getType(), true); switch(inst->getIntrinsicID()) { case Intrinsic::memcpy: printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/memcpy(II" + lenDescriptor + "I)V"); break; case Intrinsic::memmove: printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/memmove(II" + lenDescriptor + "I)V"); break; case Intrinsic::memset: printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/memset(IB" + lenDescriptor + "I)V"); break; } }
/** * Print an arithmetic instruction. * * @param op the opcode for the instruction * @param left the first operand of the instruction * @param right the second operand of the instruction */ void JVMWriter::printArithmeticInstruction(unsigned int op, const Value *left, const Value *right) { printValueLoad(left); printValueLoad(right); std::string typePrefix = getTypePrefix(left->getType(), true); std::string typeDescriptor = getTypeDescriptor(left->getType()); switch(op) { case Instruction::Add: case Instruction::FAdd: printSimpleInstruction(typePrefix + "add"); break; case Instruction::Sub: case Instruction::FSub: printSimpleInstruction(typePrefix + "sub"); break; case Instruction::Mul: case Instruction::FMul: printSimpleInstruction(typePrefix + "mul"); break; case Instruction::SDiv: case Instruction::FDiv: printSimpleInstruction(typePrefix + "div"); break; case Instruction::SRem: case Instruction::FRem: printSimpleInstruction(typePrefix + "rem"); break; case Instruction::And: printSimpleInstruction(typePrefix + "and"); break; case Instruction::Or: printSimpleInstruction(typePrefix + "or"); break; case Instruction::Xor: printSimpleInstruction(typePrefix + "xor"); break; case Instruction::Shl: if(getBitWidth(right->getType()) == 64) printSimpleInstruction("l2i"); printSimpleInstruction(typePrefix + "shl"); break; case Instruction::LShr: if(getBitWidth(right->getType()) == 64) printSimpleInstruction("l2i"); printSimpleInstruction(typePrefix + "ushr"); break; case Instruction::AShr: if(getBitWidth(right->getType()) == 64) printSimpleInstruction("l2i"); printSimpleInstruction(typePrefix + "shr"); break; case Instruction::UDiv: printVirtualInstruction( "udiv(" + typeDescriptor + typeDescriptor + ")" + typeDescriptor); break; case Instruction::URem: printVirtualInstruction( "urem(" + typeDescriptor + typeDescriptor + ")" + typeDescriptor); break; } }
ui16 CTypeList::getTypeID(const std::type_info *type, bool throws) const { auto descriptor = getTypeDescriptor(type, throws); if (descriptor == nullptr) { return 0; } return descriptor->typeID; }
/** * Print a bit manipulation intrinsic function. * * @param inst the instruction */ void JVMWriter::printBitIntrinsic(const IntrinsicInst *inst) { // TODO: ctpop, ctlz, cttz const Value *value = inst->getOperand(1); const std::string typeDescriptor = getTypeDescriptor(value->getType()); switch(inst->getIntrinsicID()) { case Intrinsic::bswap: printVirtualInstruction( "bswap(" + typeDescriptor + ")" + typeDescriptor, value); break; } }
CTypeList::TypeInfoPtr CTypeList::registerType(const std::type_info *type) { if(auto typeDescr = getTypeDescriptor(type, false)) return typeDescr; //type found, return ptr to structure //type not found - add it to the list and return given ID auto newType = std::make_shared<TypeDescriptor>(); newType->typeID = typeInfos.size() + 1; newType->name = type->name(); typeInfos[type] = newType; return newType; }
/** * Print the field declarations. */ void JVMWriter::printFields() { out << "; Fields\n"; for(Module::global_iterator i = module->global_begin(), e = module->global_end(); i != e; i++) { if(i->isDeclaration()) { out << ".extern field "; externRefs.insert(i); } else out << ".field " << (i->hasLocalLinkage() ? "private " : "public ") << "static final "; out << getValueName(i) << ' ' << getTypeDescriptor(i->getType()); if(debug >= 3) out << " ; " << *i; else out << '\n'; } out << '\n'; }
/** * Print a cast instruction. * * @param op the opcode for the instruction * @param v the value to be casted * @param ty the destination type * @param srcTy the source type */ void JVMWriter::printCastInstruction(unsigned int op, const Value *v, const Type *ty, const Type *srcTy) { printValueLoad(v); switch(op) { case Instruction::SIToFP: case Instruction::FPToSI: case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::SExt: if(getBitWidth(srcTy) < 32) printCastInstruction(getTypePrefix(srcTy), "i"); printCastInstruction(getTypePrefix(ty, true), getTypePrefix(srcTy, true)); break; case Instruction::Trunc: if(getBitWidth(srcTy) == 64 && getBitWidth(ty) < 32) { printSimpleInstruction("l2i"); printCastInstruction(getTypePrefix(ty), "i"); } else printCastInstruction(getTypePrefix(ty), getTypePrefix(srcTy, true)); break; case Instruction::IntToPtr: printCastInstruction("i", getTypePrefix(srcTy, true)); break; case Instruction::PtrToInt: printCastInstruction(getTypePrefix(ty), "i"); break; case Instruction::ZExt: printVirtualInstruction("zext_" + getTypePostfix(ty, true) + "(" + getTypeDescriptor(srcTy) + ")" + getTypeDescriptor(ty, true)); break; case Instruction::UIToFP: printVirtualInstruction("uitofp_" + getTypePostfix(ty) + "(" + getTypeDescriptor(srcTy) + ")" + getTypeDescriptor(ty)); break; case Instruction::FPToUI: printVirtualInstruction("fptoui_" + getTypePostfix(ty) + "(" + getTypeDescriptor(srcTy) + ")" + getTypeDescriptor(ty)); break; case Instruction::BitCast: printBitCastInstruction(ty, srcTy); break; default: errs() << "Opcode = " << op << '\n'; llvm_unreachable("Invalid cast instruction"); } }
/** * Print an icmp/fcmp instruction. * * @param predicate the predicate for the instruction * @param left the first operand of the instruction * @param right the second operand of the instruction */ void JVMWriter::printCmpInstruction(unsigned int predicate, const Value *left, const Value *right) { std::string inst; switch(predicate) { case ICmpInst::ICMP_EQ: inst = "icmp_eq"; break; case ICmpInst::ICMP_NE: inst = "icmp_ne"; break; case ICmpInst::ICMP_ULE: inst = "icmp_ule"; break; case ICmpInst::ICMP_SLE: inst = "icmp_sle"; break; case ICmpInst::ICMP_UGE: inst = "icmp_uge"; break; case ICmpInst::ICMP_SGE: inst = "icmp_sge"; break; case ICmpInst::ICMP_ULT: inst = "icmp_ult"; break; case ICmpInst::ICMP_SLT: inst = "icmp_slt"; break; case ICmpInst::ICMP_UGT: inst = "icmp_ugt"; break; case ICmpInst::ICMP_SGT: inst = "icmp_sgt"; break; case FCmpInst::FCMP_UGT: inst = "fcmp_ugt"; break; case FCmpInst::FCMP_OGT: inst = "fcmp_ogt"; break; case FCmpInst::FCMP_UGE: inst = "fcmp_uge"; break; case FCmpInst::FCMP_OGE: inst = "fcmp_oge"; break; case FCmpInst::FCMP_ULT: inst = "fcmp_ult"; break; case FCmpInst::FCMP_OLT: inst = "fcmp_olt"; break; case FCmpInst::FCMP_ULE: inst = "fcmp_ule"; break; case FCmpInst::FCMP_OLE: inst = "fcmp_ole"; break; case FCmpInst::FCMP_UEQ: inst = "fcmp_ueq"; break; case FCmpInst::FCMP_OEQ: inst = "fcmp_oeq"; break; case FCmpInst::FCMP_UNE: inst = "fcmp_une"; break; case FCmpInst::FCMP_ONE: inst = "fcmp_one"; break; case FCmpInst::FCMP_ORD: inst = "fcmp_ord"; break; case FCmpInst::FCMP_UNO: inst = "fcmp_uno"; break; default: errs() << "Predicate = " << predicate << '\n'; llvm_unreachable("Invalid cmp predicate"); } printVirtualInstruction( inst + "(" + getTypeDescriptor(left->getType(), true) + getTypeDescriptor(right->getType(), true) + ")Z", left, right); }
/** * Indirectly store a value of the given type. * * @param ty the type of the value */ void JVMWriter::printIndirectStore(const Type *ty) { printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/store(I" + getTypeDescriptor(ty) + ")V"); }
/** * Load a value of the given type from the address curently on top of the * stack. * * @param ty the type of the value */ void JVMWriter::printIndirectLoad(const Type *ty) { printSimpleInstruction("invokestatic", "lljvm/runtime/Memory/load_" + getTypePostfix(ty) + "(I)" + getTypeDescriptor(ty)); }
/** * Print the main method. */ void JVMWriter::printMainMethod() { const Function *f = module->getFunction("main"); if(!f || f->isDeclaration()) return; out << ".method public main_([Ljava/lang/String;)I\n"; printSimpleInstruction(".limit stack 5"); printSimpleInstruction(".limit locals 2"); printSimpleInstruction("aload_0"); // this if(f->arg_size() == 0) { printSimpleInstruction("invokevirtual", classname + "/main()I"); // stack: inst } else if(f->arg_size() == 2) { Function::const_arg_iterator arg1, arg2; arg1 = arg2 = f->arg_begin(); arg2++; if(!arg1->getType()->isIntegerTy() || arg2->getType()->getTypeID() != Type::PointerTyID) llvm_unreachable("main function has invalid type signature"); printSimpleInstruction("aload_1"); // args printSimpleInstruction("arraylength"); // stack: inst inst argc printSimpleInstruction("swap"); printSimpleInstruction("dup_x1"); // stack: inst inst argc inst // load memory onto stack printSimpleInstruction("getfield", classname+"/__env Llljvm/runtime/Environment;"); // stack: inst inst argc env printSimpleInstruction("getfield", "lljvm/runtime/Environment/memory Llljvm/runtime/Memory;"); // stack: inst inst argc memory printSimpleInstruction("aload_1"); printSimpleInstruction("invokevirtual", "lljvm/runtime/Memory/storeStack([Ljava/lang/String;)I"); // stack: inst inst argc argv printSimpleInstruction("invokevirtual", classname + "/main(" + getTypeDescriptor(arg1->getType()) + getTypeDescriptor(arg2->getType()) + ")I"); } else { llvm_unreachable("main function has invalid number of arguments"); } printSimpleInstruction("ireturn"); out << ".end method\n"; out << ".method public static main([Ljava/lang/String;)V\n"; printSimpleInstruction(".limit stack 5"); out << "\n\t; create an instance of our class, leaving it as TOS\n"; printSimpleInstruction("new", classname); printSimpleInstruction("dup"); printSimpleInstruction("invokespecial", classname+"/<init>()V"); // stack: inst printSimpleInstruction("dup"); // stack: inst inst // create our environment out << "\n\t; create our environment\n"; printSimpleInstruction("new", "lljvm/runtime/Environment"); printSimpleInstruction("dup"); printSimpleInstruction("invokespecial", "lljvm/runtime/Environment/<init>()V"); // stack: inst inst env printSimpleInstruction("swap"); // stack: inst env inst printSimpleInstruction("invokevirtual", "lljvm/runtime/Environment/loadCustomLibrary(" "Llljvm/runtime/CustomLibrary;" ")V"); // stack: inst printSimpleInstruction("dup"); // stack: inst inst // invoke the instance main function printSimpleInstruction("aload_0"); printSimpleInstruction("invokevirtual", classname + "/main_([Ljava/lang/String;)I"); // stack: inst ret printSimpleInstruction("swap"); // stack: ret inst printSimpleInstruction("getfield", classname+"/__env Llljvm/runtime/Environment;"); // stack: ret env printSimpleInstruction("ldc", "\"lljvm/lib/c\""); printSimpleInstruction("invokevirtual", "lljvm/runtime/Environment/getInstanceByName(Ljava.lang.String;)Llljvm.runtime.CustomLibrary;"); // stack: ret libc printSimpleInstruction("checkcast", "lljvm/lib/c"); printSimpleInstruction("swap"); // put the return value ahead // stack: libc ret printSimpleInstruction("invokevirtual", "lljvm/lib/c/exit(I)V"); printSimpleInstruction("return"); out << ".end method\n"; }