| //===-- Compiler.cpp - Java bytecode compiler -------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains Java bytecode to LLVM bytecode compiler. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "javacompiler" |
| |
| #include <llvm/Java/Bytecode.h> |
| #include <llvm/Java/BytecodeParser.h> |
| #include <llvm/Java/ClassFile.h> |
| #include <llvm/Java/Compiler.h> |
| #include <llvm/Constants.h> |
| #include <llvm/DerivedTypes.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/Value.h> |
| #include <llvm/Type.h> |
| #include <llvm/ADT/STLExtras.h> |
| #include <llvm/ADT/SetVector.h> |
| #include <llvm/ADT/StringExtras.h> |
| #include <llvm/Support/Debug.h> |
| #include <iostream> |
| #include <stack> |
| #include <vector> |
| |
| #define LLVM_JAVA_OBJECT_BASE "struct.llvm_java_object_base" |
| #define LLVM_JAVA_OBJECT_HEADER "struct.llvm_java_object_header" |
| #define LLVM_JAVA_OBJECT_TYPEINFO "struct.llvm_java_object_typeinfo" |
| #define LLVM_JAVA_OBJECT_VTABLE "struct.llvm_java_object_vtable" |
| |
| #define LLVM_JAVA_STATIC_INIT "llvm_java_static_init" |
| |
| #define LLVM_JAVA_ISINSTANCEOF "llvm_java_IsInstanceOf" |
| #define LLVM_JAVA_GETOBJECTCLASS "llvm_java_GetObjectClass" |
| |
| using namespace llvm; |
| using namespace llvm::Java; |
| |
| namespace llvm { namespace Java { namespace { |
| |
| const std::string TMP("tmp"); |
| |
| typedef std::vector<BasicBlock*> BC2BBMap; |
| typedef std::stack<Value*, std::vector<Value*> > OperandStack; |
| typedef std::vector<Value*> Locals; |
| |
| inline bool isTwoSlotValue(const Value* v) { |
| return v->getType() == Type::LongTy | v->getType() == Type::DoubleTy; |
| } |
| |
| inline bool isOneSlotValue(const Value* v) { |
| return !isTwoSlotValue(v); |
| } |
| |
| class Bytecode2BasicBlockMapper |
| : public BytecodeParser<Bytecode2BasicBlockMapper> { |
| Function& function_; |
| BC2BBMap& bc2bbMap_; |
| typedef std::map<BasicBlock*, BasicBlock*> FallThroughMap; |
| FallThroughMap ftMap_; |
| const CodeAttribute& codeAttr_; |
| |
| public: |
| Bytecode2BasicBlockMapper(Function& f, |
| BC2BBMap& m, |
| CodeAttribute& c) |
| : function_(f), bc2bbMap_(m), codeAttr_(c) { } |
| |
| void compute() { |
| bc2bbMap_.clear(); |
| bc2bbMap_.assign(codeAttr_.getCodeSize(), NULL); |
| |
| BasicBlock* bb = new BasicBlock("entry", &function_); |
| |
| parse(codeAttr_.getCode(), codeAttr_.getCodeSize()); |
| |
| for (unsigned i = 0, e = bc2bbMap_.size(); i != e; ++i) |
| if (BasicBlock* next = bc2bbMap_[i]) { |
| ftMap_.insert(std::make_pair(bb, next)); |
| bb = next; |
| } |
| else |
| bc2bbMap_[i] = bb; |
| |
| assert(function_.getEntryBlock().getName() == "entry"); |
| } |
| |
| void insertFallThroughBranches() { |
| for (FallThroughMap::const_iterator i = ftMap_.begin(), e = ftMap_.end(); |
| i != e; ++i) |
| if (!i->first->getTerminator()) |
| new BranchInst(i->second, i->first); |
| } |
| |
| void do_if(unsigned bcI, JSetCC cc, JType type, |
| unsigned t, unsigned f) { |
| if (!bc2bbMap_[t]) |
| bc2bbMap_[t] = new BasicBlock("bc" + utostr(t), &function_); |
| if (!bc2bbMap_[f]) |
| bc2bbMap_[f] = new BasicBlock("bc" + utostr(f), &function_); |
| } |
| |
| void do_ifcmp(unsigned bcI, JSetCC cc, |
| unsigned t, unsigned f) { |
| if (!bc2bbMap_[t]) |
| bc2bbMap_[t] = new BasicBlock("bc" + utostr(t), &function_); |
| if (!bc2bbMap_[f]) |
| bc2bbMap_[f] = new BasicBlock("bc" + utostr(f), &function_); |
| } |
| |
| void do_switch(unsigned bcI, |
| unsigned defTarget, |
| const SwitchCases& sw) { |
| for (unsigned i = 0; i < sw.size(); ++i) { |
| unsigned target = sw[i].second; |
| if (!bc2bbMap_[target]) |
| bc2bbMap_[target] = new BasicBlock("bc" + utostr(target), &function_); |
| } |
| if (!bc2bbMap_[defTarget]) |
| bc2bbMap_[defTarget] = |
| new BasicBlock("bc" + utostr(defTarget), &function_); |
| } |
| }; |
| |
| struct CompilerImpl : |
| public BytecodeParser<CompilerImpl> { |
| private: |
| Module* module_; |
| ClassFile* cf_; |
| OperandStack opStack_; |
| Locals locals_; |
| BC2BBMap bc2bbMap_; |
| BasicBlock* prologue_; |
| |
| typedef SetVector<Function*> FunctionSet; |
| FunctionSet toCompileFunctions_; |
| |
| struct ClassInfo { |
| ClassInfo() : type(NULL), interfaceIdx(0) { } |
| Type* type; |
| unsigned interfaceIdx; |
| typedef std::map<std::string, unsigned> Field2IndexMap; |
| Field2IndexMap f2iMap; |
| |
| static unsigned InterfaceCount; |
| }; |
| typedef std::map<ClassFile*, ClassInfo> Class2ClassInfoMap; |
| Class2ClassInfoMap c2ciMap_; |
| |
| struct VTableInfo { |
| VTableInfo() : vtable(NULL) { } |
| GlobalVariable* vtable; |
| std::vector<llvm::Constant*> superVtables; |
| typedef std::map<std::string, unsigned> Method2IndexMap; |
| Method2IndexMap m2iMap; |
| |
| static StructType* VTableTy; |
| static StructType* TypeInfoTy; |
| }; |
| typedef std::map<ClassFile*, VTableInfo> Class2VTableInfoMap; |
| Class2VTableInfoMap c2viMap_; |
| |
| private: |
| BasicBlock* getBBAt(unsigned bcI) { return bc2bbMap_[bcI]; } |
| |
| private: |
| llvm::Constant* getConstant(Constant* c) { |
| if (dynamic_cast<ConstantString*>(c)) |
| // FIXME: should return a String object represeting this ConstantString |
| return ConstantPointerNull::get( |
| PointerType::get( |
| getClassInfo(ClassFile::get("java/lang/String")).type)); |
| else if (ConstantInteger* i = dynamic_cast<ConstantInteger*>(c)) |
| return ConstantSInt::get(Type::IntTy, i->getValue()); |
| else if (ConstantFloat* f = dynamic_cast<ConstantFloat*>(c)) |
| return ConstantFP::get(Type::FloatTy, f->getValue()); |
| else if (ConstantLong* l = dynamic_cast<ConstantLong*>(c)) |
| return ConstantSInt::get(Type::LongTy, l->getValue()); |
| else if (ConstantDouble* d = dynamic_cast<ConstantDouble*>(c)) |
| return ConstantFP::get(Type::DoubleTy, d->getValue()); |
| else |
| assert(0 && "Unknown llvm::Java::Constant!"); |
| } |
| |
| Type* getType(JType type) { |
| switch (type) { |
| case REFERENCE: |
| return PointerType::get( |
| getClassInfo(ClassFile::get("java/lang/Object")).type); |
| case BOOLEAN: return Type::BoolTy; |
| case CHAR: return Type::UShortTy; |
| case FLOAT: return Type::FloatTy; |
| case DOUBLE: return Type::DoubleTy; |
| case BYTE: return Type::SByteTy; |
| case SHORT: return Type::ShortTy; |
| case INT: return Type::IntTy; |
| case LONG: return Type::LongTy; |
| default: assert(0 && "Invalid JType to Type conversion!"); |
| } |
| |
| return NULL; |
| } |
| |
| Instruction::BinaryOps getSetCC(JSetCC cc) { |
| switch (cc) { |
| case EQ: return Instruction::SetEQ; |
| case NE: return Instruction::SetNE; |
| case LT: return Instruction::SetLT; |
| case GE: return Instruction::SetGE; |
| case GT: return Instruction::SetGT; |
| case LE: return Instruction::SetLE; |
| default: assert(0 && "Invalid JSetCC to BinaryOps conversion!"); |
| } |
| return static_cast<Instruction::BinaryOps>(-1); |
| } |
| |
| /// Returns the type of the Java string descriptor. If the |
| /// Type* self is not NULL then that type is used as the first |
| /// type in function types |
| Type* getType(ConstantUtf8* descr, Type* self = NULL) { |
| unsigned i = 0; |
| return getTypeHelper(descr->str(), i, self); |
| } |
| |
| Type* getTypeHelper(const std::string& descr, unsigned& i, Type* self) { |
| assert(i < descr.size()); |
| switch (descr[i++]) { |
| case 'B': return Type::SByteTy; |
| case 'C': return Type::UShortTy; |
| case 'D': return Type::DoubleTy; |
| case 'F': return Type::FloatTy; |
| case 'I': return Type::IntTy; |
| case 'J': return Type::LongTy; |
| case 'S': return Type::ShortTy; |
| case 'Z': return Type::BoolTy; |
| case 'V': return Type::VoidTy; |
| case 'L': { |
| unsigned e = descr.find(';', i); |
| std::string className = descr.substr(i, e - i); |
| i = e + 1; |
| return PointerType::get(getClassInfo(ClassFile::get(className)).type); |
| } |
| case '[': |
| // FIXME: this should really be a new class |
| // represeting the array of the following type |
| return PointerType::get( |
| ArrayType::get(getTypeHelper(descr, i, NULL), 0)); |
| case '(': { |
| std::vector<const Type*> params; |
| if (self) |
| params.push_back(PointerType::get(self)); |
| while (descr[i] != ')') |
| params.push_back(getTypeHelper(descr, i, NULL)); |
| return FunctionType::get(getTypeHelper(descr, ++i, NULL),params, false); |
| } |
| // FIXME: Throw something |
| default: return NULL; |
| } |
| } |
| |
| void initializeClassInfoMap() { |
| DEBUG(std::cerr << "Building ClassInfo for: java/lang/Object\n"); |
| ClassFile* cf = ClassFile::get("java/lang/Object"); |
| ClassInfo& ci = c2ciMap_[cf]; |
| |
| assert(!ci.type && ci.f2iMap.empty() && |
| "java/lang/Object ClassInfo should not be initialized!"); |
| ci.type = OpaqueType::get(); |
| |
| std::vector<const Type*> elements; |
| |
| // because this is java/lang/Object, we add the opaque |
| // llvm_java_object_base type first |
| Type* base = OpaqueType::get(); |
| module_->addTypeName(LLVM_JAVA_OBJECT_BASE, base); |
| ci.f2iMap.insert(std::make_pair(LLVM_JAVA_OBJECT_BASE, elements.size())); |
| elements.push_back(base); |
| |
| const Fields& fields = cf->getFields(); |
| for (unsigned i = 0, e = fields.size(); i != e; ++i) { |
| Field* field = fields[i]; |
| if (!field->isStatic()) { |
| ci.f2iMap.insert( |
| std::make_pair(field->getName()->str(), elements.size())); |
| elements.push_back(getType(field->getDescriptor())); |
| } |
| } |
| PATypeHolder holder = ci.type; |
| cast<OpaqueType>(ci.type)->refineAbstractTypeTo(StructType::get(elements)); |
| ci.type = holder.get(); |
| DEBUG(std::cerr << "Adding java/lang/Object = " |
| << *ci.type << " to type map\n"); |
| module_->addTypeName("java/lang/Object", ci.type); |
| |
| assert(ci.type && "ClassInfo not initialized properly!"); |
| emitStaticInitializers(cf); |
| DEBUG(std::cerr << "Built ClassInfo for: java/lang/Object\n"); |
| } |
| |
| void initializeVTableInfoMap() { |
| DEBUG(std::cerr << "Building VTableInfo for: java/lang/Object\n"); |
| ClassFile* cf = ClassFile::get("java/lang/Object"); |
| VTableInfo& vi = c2viMap_[cf]; |
| |
| assert(!vi.vtable && vi.m2iMap.empty() && |
| "java/lang/Object VTableInfo should not be initialized!"); |
| |
| Type* VTtype = OpaqueType::get(); |
| |
| std::vector<const Type*> elements; |
| std::vector<llvm::Constant*> init; |
| |
| // this is java/lang/Object so we must add a |
| // llvm_java_object_typeinfo struct first |
| |
| // depth |
| elements.push_back(Type::UIntTy); |
| init.push_back(llvm::ConstantUInt::get(elements[0], 0)); |
| // superclasses vtable pointers |
| elements.push_back(PointerType::get(PointerType::get(VTtype))); |
| init.push_back(llvm::Constant::getNullValue(elements[1])); |
| // last interface index |
| elements.push_back(Type::IntTy); |
| init.push_back(llvm::ConstantSInt::get(elements[2], -1)); |
| // interfaces vtable pointers |
| elements.push_back(PointerType::get(PointerType::get(VTtype))); |
| init.push_back(llvm::Constant::getNullValue(elements[3])); |
| |
| // this is a static variable |
| VTableInfo::TypeInfoTy = StructType::get(elements); |
| module_->addTypeName(LLVM_JAVA_OBJECT_TYPEINFO, VTableInfo::TypeInfoTy); |
| llvm::Constant* typeInfoInit = |
| ConstantStruct::get(VTableInfo::TypeInfoTy, init); |
| |
| // now that we have both the type and initializer for the |
| // llvm_java_object_typeinfo struct we can start adding the |
| // function pointers |
| elements.clear(); |
| init.clear(); |
| |
| /// first add the typeinfo struct itself |
| elements.push_back(typeInfoInit->getType()); |
| // add the typeinfo block for this class |
| init.push_back(typeInfoInit); |
| |
| const Methods& methods = cf->getMethods(); |
| |
| const ClassInfo& ci = getClassInfo(cf); |
| |
| // add member functions to the vtable |
| for (unsigned i = 0, e = methods.size(); i != e; ++i) { |
| Method* method = methods[i]; |
| // the contructor is the only non-static method that is not |
| // dynamically dispatched so we skip it |
| if (!method->isStatic() && method->getName()->str() != "<init>") { |
| std::string methodDescr = |
| method->getName()->str() + |
| method->getDescriptor()->str(); |
| |
| std::string funcName = "java/lang/Object/" + methodDescr; |
| const FunctionType* funcTy = cast<FunctionType>( |
| getType(method->getDescriptor(), ci.type)); |
| |
| Function* vfun = module_->getOrInsertFunction(funcName, funcTy); |
| toCompileFunctions_.insert(vfun); |
| |
| unsigned& index = vi.m2iMap[methodDescr]; |
| if (!index) { |
| index = elements.size(); |
| elements.resize(index + 1, NULL); |
| init.resize(index + 1, NULL); |
| } |
| elements[index] = vfun->getType(); |
| init[index] = vfun; |
| } |
| } |
| |
| PATypeHolder holder = VTtype; |
| cast<OpaqueType>(VTtype)->refineAbstractTypeTo(StructType::get(elements)); |
| |
| VTableInfo::VTableTy = cast<StructType>(holder.get()); |
| module_->addTypeName("java/lang/Object<vtable>", VTableInfo::VTableTy); |
| |
| vi.vtable = new GlobalVariable(VTableInfo::VTableTy, |
| true, GlobalVariable::ExternalLinkage, |
| ConstantStruct::get(init), |
| "java/lang/Object<vtable>", |
| module_); |
| DEBUG(std::cerr << "Built VTableInfo for: java/lang/Object\n"); |
| } |
| |
| void initializeTypeMaps() { |
| initializeClassInfoMap(); |
| initializeVTableInfoMap(); |
| } |
| |
| const ClassInfo& getClassInfo(ClassFile* cf) { |
| Class2ClassInfoMap::iterator it = c2ciMap_.lower_bound(cf); |
| if (it != c2ciMap_.end() && it->first == cf) |
| return it->second; |
| |
| const std::string& className = cf->getThisClass()->getName()->str(); |
| DEBUG(std::cerr << "Building ClassInfo for: " << className << '\n'); |
| ClassInfo& ci = c2ciMap_[cf]; |
| |
| assert(!ci.type && ci.f2iMap.empty() && |
| "got already initialized ClassInfo!"); |
| |
| // get the interface id |
| if (cf->isInterface()) |
| ci.interfaceIdx = ClassInfo::InterfaceCount++; |
| |
| ci.type = OpaqueType::get(); |
| |
| std::vector<const Type*> elements; |
| ConstantClass* super = cf->getSuperClass(); |
| assert(super && "Class does not have superclass!"); |
| const ClassInfo& superCI = |
| getClassInfo(ClassFile::get(super->getName()->str())); |
| elements.push_back(superCI.type); |
| |
| const Fields& fields = cf->getFields(); |
| for (unsigned i = 0, e = fields.size(); i != e; ++i) { |
| Field* field = fields[i]; |
| if (!field->isStatic()) { |
| ci.f2iMap.insert( |
| std::make_pair(field->getName()->str(), elements.size())); |
| elements.push_back(getType(field->getDescriptor())); |
| } |
| } |
| PATypeHolder holder = ci.type; |
| cast<OpaqueType>(ci.type)->refineAbstractTypeTo(StructType::get(elements)); |
| ci.type = holder.get(); |
| |
| assert(ci.type && "ClassInfo not initialized properly!"); |
| DEBUG(std::cerr << "Adding " << className << " = " |
| << *ci.type << " to type map\n"); |
| module_->addTypeName(className, ci.type); |
| emitStaticInitializers(cf); |
| DEBUG(std::cerr << "Built ClassInfo for: " << className << '\n'); |
| return ci; |
| } |
| |
| std::pair<unsigned,llvm::Constant*> |
| buildSuperClassesVTables(ClassFile* cf, const VTableInfo& vi) const { |
| ArrayType* vtablesArrayTy = |
| ArrayType::get(PointerType::get(VTableInfo::VTableTy), |
| vi.superVtables.size()); |
| |
| GlobalVariable* vtablesArray = new GlobalVariable( |
| vtablesArrayTy, |
| true, |
| GlobalVariable::ExternalLinkage, |
| ConstantArray::get(vtablesArrayTy, vi.superVtables), |
| cf->getThisClass()->getName()->str() + "<superclassesvtables>", |
| module_); |
| |
| return std::make_pair( |
| vi.superVtables.size(), |
| ConstantExpr::getGetElementPtr( |
| vtablesArray, |
| std::vector<llvm::Constant*>(2, ConstantUInt::get(Type::UIntTy, 0)))); |
| } |
| |
| llvm::Constant* buildInterfaceVTable(ClassFile* cf, ClassFile* interface) { |
| |
| const VTableInfo& classVI = getVTableInfo(cf); |
| const VTableInfo& interfaceVI = getVTableInfo(interface); |
| const Methods& methods = interface->getMethods(); |
| |
| // the size of the initializer will be 1 greater than the number |
| // of methods for this interface (the first slot is the typeinfo |
| // struct |
| std::vector<llvm::Constant*> init(interfaceVI.m2iMap.size()+1, NULL); |
| init[0] = llvm::Constant::getNullValue(VTableInfo::TypeInfoTy); |
| |
| for (VTableInfo::Method2IndexMap::const_iterator |
| i = interfaceVI.m2iMap.begin(), e = interfaceVI.m2iMap.end(); |
| i != e; ++i) { |
| std::vector<llvm::Constant*> indices; |
| indices.reserve(2); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| assert(classVI.m2iMap.find(i->first) != classVI.m2iMap.end() && |
| "Interface method not found in class definition!"); |
| unsigned classMethodIdx = classVI.m2iMap.find(i->first)->second; |
| indices.push_back(ConstantUInt::get(Type::UIntTy, classMethodIdx)); |
| init[i->second] = |
| ConstantExpr::getGetElementPtr(classVI.vtable, indices); |
| } |
| |
| llvm::Constant* vtable = ConstantStruct::get(init); |
| const std::string& globalName = |
| cf->getThisClass()->getName()->str() + '+' + |
| interface->getThisClass()->getName()->str() + "<vtable>"; |
| module_->addTypeName(globalName, vtable->getType()); |
| |
| return new GlobalVariable( |
| vtable->getType(), |
| true, |
| GlobalVariable::ExternalLinkage, |
| vtable, |
| globalName, |
| module_); |
| } |
| |
| std::pair<int, llvm::Constant*> |
| buildInterfacesVTables(ClassFile* cf, const VTableInfo& vi) { |
| |
| std::vector<llvm::Constant*> vtables; |
| const Classes& interfaces = cf->getInterfaces(); |
| llvm::Constant* nullVTable = |
| llvm::Constant::getNullValue(PointerType::get(VTableInfo::VTableTy)); |
| |
| for (unsigned i = 0, e = interfaces.size(); i != e; ++i) { |
| ClassFile* interface = ClassFile::get(interfaces[i]->getName()->str()); |
| assert(interface->isInterface() && |
| "Class in interfaces list is not an interface!"); |
| const ClassInfo& interfaceCI = getClassInfo(interface); |
| if (interfaceCI.interfaceIdx >= vtables.size()) |
| vtables.resize(interfaceCI.interfaceIdx+1, nullVTable); |
| vtables[interfaceCI.interfaceIdx] = buildInterfaceVTable(cf, interface); |
| } |
| |
| ArrayType* interfacesArrayTy = |
| ArrayType::get(PointerType::get(VTableInfo::VTableTy), vtables.size()); |
| |
| const std::string& globalName = |
| cf->getThisClass()->getName()->str() + "<interfacesvtables>"; |
| module_->addTypeName(globalName, interfacesArrayTy); |
| |
| GlobalVariable* interfacesArray = new GlobalVariable( |
| interfacesArrayTy, |
| true, |
| GlobalVariable::ExternalLinkage, |
| ConstantArray::get(interfacesArrayTy, vtables), |
| globalName, |
| module_); |
| |
| return std::make_pair( |
| int(vtables.size())-1, |
| ConstantExpr::getGetElementPtr( |
| interfacesArray, |
| std::vector<llvm::Constant*>(2, ConstantUInt::get(Type::UIntTy, 0)))); |
| } |
| |
| llvm::Constant* buildClassTypeInfo(ClassFile* cf, const VTableInfo& vi) { |
| std::vector<llvm::Constant*> typeInfoInit; |
| |
| unsigned depth; |
| llvm::Constant* superClassesVTables; |
| tie(depth, superClassesVTables) = buildSuperClassesVTables(cf, vi); |
| |
| // the depth (java/lang/Object has depth 0) |
| typeInfoInit.push_back(ConstantUInt::get(Type::UIntTy, depth)); |
| // the super classes' vtables |
| typeInfoInit.push_back(superClassesVTables); |
| |
| int lastInterface; |
| llvm::Constant* interfacesVTables; |
| tie(lastInterface, interfacesVTables) = buildInterfacesVTables(cf, vi); |
| |
| // the last interface index or the interface index if this is an |
| // interface |
| typeInfoInit.push_back(ConstantSInt::get(Type::IntTy, lastInterface)); |
| // the interfaces' vtables |
| typeInfoInit.push_back(interfacesVTables); |
| |
| return ConstantStruct::get(VTableInfo::TypeInfoTy, typeInfoInit); |
| } |
| |
| const VTableInfo& getVTableInfo(ClassFile* cf) { |
| Class2VTableInfoMap::iterator it = c2viMap_.lower_bound(cf); |
| if (it != c2viMap_.end() && it->first == cf) |
| return it->second; |
| |
| const std::string& className = cf->getThisClass()->getName()->str(); |
| DEBUG(std::cerr << "Building VTableInfo for: " << className << '\n'); |
| VTableInfo& vi = c2viMap_[cf]; |
| |
| assert(!vi.vtable && vi.m2iMap.empty() && |
| "got already initialized VTableInfo!"); |
| |
| ConstantClass* super = cf->getSuperClass(); |
| assert(super && "Class does not have superclass!"); |
| const VTableInfo& superVI = |
| getVTableInfo(ClassFile::get(super->getName()->str())); |
| |
| // copy the super vtables array |
| vi.superVtables.push_back(superVI.vtable); |
| vi.superVtables.reserve(superVI.superVtables.size() + 1); |
| std::copy(superVI.superVtables.begin(), superVI.superVtables.end(), |
| std::back_inserter(vi.superVtables)); |
| |
| // copy all the constants from the super class' vtable |
| assert(superVI.vtable && "No vtable found for super class!"); |
| ConstantStruct* superInit = |
| cast<ConstantStruct>(superVI.vtable->getInitializer()); |
| std::vector<llvm::Constant*> init(superInit->getNumOperands()); |
| // use a null typeinfo struct for now |
| init[0] = llvm::Constant::getNullValue(VTableInfo::TypeInfoTy); |
| // fill in the function pointers as they are in the super |
| // class. overriden methods will be replaced later |
| for (unsigned i = 0, e = superInit->getNumOperands(); i != e; ++i) |
| init[i] = superInit->getOperand(i); |
| vi.m2iMap = superVI.m2iMap; |
| |
| // add member functions to the vtable |
| const Methods& methods = cf->getMethods(); |
| |
| for (unsigned i = 0, e = methods.size(); i != e; ++i) { |
| Method* method = methods[i]; |
| // the contructor is the only non-static method that is not |
| // dynamically dispatched so we skip it |
| if (!method->isStatic() && method->getName()->str() != "<init>") { |
| const std::string& methodDescr = |
| method->getName()->str() + method->getDescriptor()->str(); |
| |
| std::string funcName = className + '/' + methodDescr; |
| |
| // if this is not an interface we will need to build up the |
| const FunctionType* funcTy = cast<FunctionType>( |
| getType(method->getDescriptor(), getClassInfo(cf).type)); |
| Function* vfun = module_->getOrInsertFunction(funcName, funcTy); |
| toCompileFunctions_.insert(vfun); |
| |
| unsigned& index = vi.m2iMap[methodDescr]; |
| if (!index) { |
| index = init.size(); |
| init.resize(index + 1); |
| } |
| init[index] = vfun; |
| } |
| } |
| |
| #ifndef NDEBUG |
| for (unsigned i = 0, e = init.size(); i != e; ++i) |
| assert(init[i] && "No elements in the initializer should be NULL!"); |
| #endif |
| |
| const std::string& globalName = className + "<vtable>"; |
| |
| llvm::Constant* vtable = ConstantStruct::get(init); |
| module_->addTypeName(globalName, vtable->getType()); |
| vi.vtable = new GlobalVariable(vtable->getType(), |
| true, |
| GlobalVariable::ExternalLinkage, |
| vtable, |
| globalName, |
| module_); |
| |
| // Now the vtable is complete, install the new typeinfo block |
| // for this class: we install it last because we need the vtable |
| // to exist in order to build it |
| init[0] = buildClassTypeInfo(cf, vi); |
| vi.vtable->setInitializer(ConstantStruct::get(init)); |
| |
| DEBUG(std::cerr << "Built VTableInfo for: " << className << '\n'); |
| return vi; |
| } |
| |
| Value* getOrCreateLocal(unsigned index, Type* type) { |
| if (!locals_[index] || |
| cast<PointerType>(locals_[index]->getType())->getElementType() != type) { |
| locals_[index] = |
| new AllocaInst(type, NULL, "local" + utostr(index), prologue_); |
| } |
| |
| return locals_[index]; |
| } |
| |
| GlobalVariable* getStaticField(unsigned index) { |
| ConstantFieldRef* fieldRef = cf_->getConstantFieldRef(index); |
| ConstantNameAndType* nameAndType = fieldRef->getNameAndType(); |
| |
| // get ClassInfo for class owning the field - this will force |
| // the globals to be initialized |
| getClassInfo(ClassFile::get(fieldRef->getClass()->getName()->str())); |
| |
| std::string globalName = |
| fieldRef->getClass()->getName()->str() + '/' + |
| nameAndType->getName()->str(); |
| |
| DEBUG(std::cerr << "Looking up global: " << globalName << '\n'); |
| GlobalVariable* global = module_->getGlobalVariable |
| (globalName, getType(nameAndType->getDescriptor())); |
| assert(global && "Got NULL global variable!"); |
| |
| return global; |
| } |
| |
| Value* getField(unsigned bcI, unsigned index, Value* ptr) { |
| ConstantFieldRef* fieldRef = cf_->getConstantFieldRef(index); |
| ConstantNameAndType* nameAndType = fieldRef->getNameAndType(); |
| ClassFile* cf = ClassFile::get(fieldRef->getClass()->getName()->str()); |
| return getField(bcI, |
| cf, |
| nameAndType->getName()->str(), |
| ptr); |
| } |
| |
| Value* getField(unsigned bcI, |
| ClassFile* cf, |
| const std::string& fieldName, |
| Value* ptr) { |
| // Cast ptr to correct type |
| ptr = new CastInst(ptr, PointerType::get(getClassInfo(cf).type), |
| TMP, getBBAt(bcI)); |
| |
| // deref pointer |
| std::vector<Value*> indices(1, ConstantUInt::get(Type::UIntTy, 0)); |
| while (true) { |
| const ClassInfo& info = getClassInfo(cf); |
| ClassInfo::Field2IndexMap::const_iterator it = |
| info.f2iMap.find(fieldName); |
| if (it == info.f2iMap.end()) { |
| cf = ClassFile::get(cf->getSuperClass()->getName()->str()); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| } |
| else { |
| indices.push_back(ConstantUInt::get(Type::UIntTy, it->second)); |
| break; |
| } |
| } |
| |
| return new GetElementPtrInst(ptr, indices, TMP, getBBAt(bcI)); |
| } |
| |
| Function* compileMethodOnly(const std::string& classMethodDesc) { |
| Method* method; |
| tie(cf_, method) = findClassAndMethod(classMethodDesc); |
| const ClassInfo& ci = getClassInfo(cf_); |
| |
| std::string name = cf_->getThisClass()->getName()->str(); |
| name += '/'; |
| name += method->getName()->str(); |
| name += method->getDescriptor()->str(); |
| |
| FunctionType* funcTy = cast<FunctionType>( |
| getType(method->getDescriptor(), method->isStatic() ? NULL : ci.type)); |
| |
| Function* function = module_->getOrInsertFunction(name, funcTy); |
| function->setLinkage(method->isPrivate() ? |
| Function::InternalLinkage : |
| Function::ExternalLinkage); |
| |
| if (method->isNative()) { |
| DEBUG(std::cerr << "Ignoring native method: "; |
| std::cerr << classMethodDesc << '\n'); |
| return function; |
| } |
| |
| DEBUG(std::cerr << "Compiling method: " << classMethodDesc << '\n'); |
| |
| Java::CodeAttribute* codeAttr = method->getCodeAttribute(); |
| |
| while (!opStack_.empty()) |
| opStack_.pop(); |
| |
| locals_.clear(); |
| locals_.assign(codeAttr->getMaxLocals(), NULL); |
| |
| Bytecode2BasicBlockMapper mapper(*function, bc2bbMap_, *codeAttr); |
| mapper.compute(); |
| |
| prologue_ = new BasicBlock("prologue"); |
| |
| parse(codeAttr->getCode(), codeAttr->getCodeSize()); |
| |
| // if the prologue is not empty, make it the entry block |
| // of the function with entry as its only successor |
| if (prologue_->empty()) |
| delete prologue_; |
| else { |
| function->getBasicBlockList().push_front(prologue_); |
| new BranchInst(prologue_->getNext(), prologue_); |
| } |
| |
| // now insert fall through branches to all basic blocks that |
| // don't have a terminator |
| mapper.insertFallThroughBranches(); |
| |
| return function; |
| } |
| |
| void emitStaticInitializers(const ClassFile* classfile) { |
| const Method* method = classfile->getMethod("<clinit>()V"); |
| if (!method) |
| return; |
| |
| std::string name = classfile->getThisClass()->getName()->str(); |
| name += '/'; |
| name += method->getName()->str(); |
| name += method->getDescriptor()->str(); |
| |
| Function* hook = module_->getOrInsertFunction(LLVM_JAVA_STATIC_INIT, |
| Type::VoidTy, 0); |
| Function* init = module_->getOrInsertFunction(name, Type::VoidTy, 0); |
| |
| // if this is the first time we scheduled this function |
| // for compilation insert a call to it right before the |
| // terminator of the only basic block in |
| // llvm_java_static_init |
| if (toCompileFunctions_.insert(init)) { |
| assert(hook->front().getTerminator() && |
| LLVM_JAVA_STATIC_INIT " should have a terminator!"); |
| new CallInst(init, "", hook->front().getTerminator()); |
| // we also create the global variables of this class |
| const Fields& fields = classfile->getFields(); |
| for (unsigned i = 0, e = fields.size(); i != e; ++i) { |
| Field* field = fields[i]; |
| if (field->isStatic()) { |
| llvm::Constant* init = NULL; |
| if (ConstantValueAttribute* cv = field->getConstantValueAttribute()) |
| init = getConstant(cv->getValue()); |
| |
| std::string globalName = |
| classfile->getThisClass()->getName()->str() + '/' + |
| field->getName()->str(); |
| DEBUG(std::cerr << "Adding global: " << globalName << '\n'); |
| new GlobalVariable(getType(field->getDescriptor()), |
| field->isFinal(), |
| (field->isPrivate() & bool(init) ? |
| GlobalVariable::InternalLinkage : |
| GlobalVariable::ExternalLinkage), |
| init, |
| globalName, |
| module_); |
| } |
| } |
| } |
| } |
| |
| std::pair<ClassFile*, Method*> |
| findClassAndMethod(const std::string& classMethodDesc) { |
| unsigned slash = classMethodDesc.rfind('/', classMethodDesc.find('(')); |
| std::string className = classMethodDesc.substr(0, slash); |
| std::string methodNameAndDescr = classMethodDesc.substr(slash+1); |
| |
| ClassFile* classfile = ClassFile::get(className); |
| emitStaticInitializers(classfile); |
| Method* method = classfile->getMethod(methodNameAndDescr); |
| |
| if (!method) |
| throw InvocationTargetException("Method " + methodNameAndDescr + |
| " not found in class " + className); |
| |
| return std::make_pair(classfile, method); |
| } |
| |
| public: |
| Function* compileMethod(Module& module, |
| const std::string& classMethodDesc) { |
| module_ = &module; |
| |
| // initialize the static initializer function |
| Function* staticInit = |
| module_->getOrInsertFunction(LLVM_JAVA_STATIC_INIT, |
| Type::VoidTy, 0); |
| BasicBlock* staticInitBB = new BasicBlock("entry", staticInit); |
| new ReturnInst(NULL, staticInitBB); |
| |
| // initialize type maps and globals (vtables) |
| initializeTypeMaps(); |
| |
| // compile the method requested |
| Function* function = compileMethodOnly(classMethodDesc); |
| // compile all other methods called by this method recursively |
| for (unsigned i = 0; i != toCompileFunctions_.size(); ++i) { |
| Function* f = toCompileFunctions_[i]; |
| compileMethodOnly(f->getName()); |
| } |
| |
| return function; |
| } |
| |
| void do_aconst_null(unsigned bcI) { |
| opStack_.push(llvm::Constant::getNullValue(getType(REFERENCE))); |
| } |
| |
| void do_iconst(unsigned bcI, int value) { |
| opStack_.push(ConstantSInt::get(Type::IntTy, value)); |
| } |
| |
| void do_lconst(unsigned bcI, long long value) { |
| opStack_.push(ConstantSInt::get(Type::LongTy, value)); |
| } |
| |
| void do_fconst(unsigned bcI, float value) { |
| opStack_.push(ConstantFP::get(Type::FloatTy, value)); |
| } |
| |
| void do_dconst(unsigned bcI, double value) { |
| opStack_.push(ConstantFP::get(Type::DoubleTy, value)); |
| } |
| |
| void do_ldc(unsigned bcI, unsigned index) { |
| Constant* c = cf_->getConstant(index); |
| assert(getConstant(c) && "Java constant not handled!"); |
| opStack_.push(getConstant(c)); |
| } |
| |
| void do_load(unsigned bcI, JType type, unsigned index) { |
| opStack_.push(new LoadInst(getOrCreateLocal(index, getType(type)), |
| TMP, getBBAt(bcI))); |
| } |
| |
| void do_aload(unsigned bcI, JType type) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_store(unsigned bcI, JType type, unsigned index) { |
| Value* val = opStack_.top(); opStack_.pop(); |
| const Type* valTy = val->getType(); |
| Value* ptr = getOrCreateLocal(index, getType(type)); |
| if (!valTy->isPrimitiveType() && |
| valTy != cast<PointerType>(ptr->getType())->getElementType()) |
| ptr = new CastInst(ptr, PointerType::get(valTy), TMP, getBBAt(bcI)); |
| opStack_.push(new StoreInst(val, ptr, getBBAt(bcI))); |
| } |
| |
| void do_astore(unsigned bcI, JType type) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_pop(unsigned bcI) { |
| opStack_.pop(); |
| } |
| |
| void do_pop2(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v1)) |
| opStack_.pop(); |
| } |
| |
| void do_dup(unsigned bcI) { |
| opStack_.push(opStack_.top()); |
| } |
| |
| void do_dup_x1(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v1); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| |
| void do_dup_x2(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v2)) { |
| Value* v3 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v1); |
| opStack_.push(v3); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| else { |
| opStack_.push(v1); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| } |
| |
| void do_dup2(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v1)) { |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| else { |
| opStack_.push(v1); |
| opStack_.push(v1); |
| } |
| } |
| |
| void do_dup2_x1(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v1)) { |
| Value* v3 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| opStack_.push(v3); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| else { |
| opStack_.push(v1); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| } |
| |
| void do_dup2_x2(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v1)) { |
| Value* v3 = opStack_.top(); opStack_.pop(); |
| if (isOneSlotValue(v3)) { |
| Value* v4 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| opStack_.push(v4); |
| opStack_.push(v3); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| else { |
| opStack_.push(v2); |
| opStack_.push(v1); |
| opStack_.push(v3); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| } |
| else { |
| if (isOneSlotValue(v2)) { |
| Value* v3 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v1); |
| opStack_.push(v3); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| else { |
| opStack_.push(v1); |
| opStack_.push(v2); |
| opStack_.push(v1); |
| } |
| } |
| } |
| |
| void do_swap(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| opStack_.push(v1); |
| opStack_.push(v2); |
| } |
| |
| void do_add(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Add); |
| } |
| |
| void do_sub(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Sub); |
| } |
| |
| void do_mul(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Mul); |
| } |
| |
| void do_div(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Div); |
| } |
| |
| void do_rem(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Rem); |
| } |
| |
| void do_neg(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| opStack_.push(BinaryOperator::createNeg(v1, TMP, getBBAt(bcI))); |
| } |
| |
| void do_shl(unsigned bcI) { |
| do_shift_common(bcI, Instruction::Shl); |
| } |
| |
| void do_shr(unsigned bcI) { |
| do_shift_common(bcI, Instruction::Shr); |
| } |
| |
| void do_ushr(unsigned bcI) { |
| // cast value to be shifted into its unsigned version |
| do_swap(bcI); |
| Value* value = opStack_.top(); opStack_.pop(); |
| value = new CastInst(value, value->getType()->getUnsignedVersion(), |
| TMP, getBBAt(bcI)); |
| opStack_.push(value); |
| do_swap(bcI); |
| |
| do_shift_common(bcI, Instruction::Shr); |
| |
| value = opStack_.top(); opStack_.pop(); |
| // cast shifted value back to its original signed version |
| opStack_.push(new CastInst(value, value->getType()->getSignedVersion(), |
| TMP, getBBAt(bcI))); |
| } |
| |
| void do_shift_common(unsigned bcI, Instruction::OtherOps op) { |
| Value* amount = opStack_.top(); opStack_.pop(); |
| Value* value = opStack_.top(); opStack_.pop(); |
| amount = new CastInst(amount, Type::UByteTy, TMP, getBBAt(bcI)); |
| opStack_.push(new ShiftInst(op, value, amount, TMP, getBBAt(bcI))); |
| } |
| |
| void do_and(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::And); |
| } |
| |
| void do_or(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Or); |
| } |
| |
| void do_xor(unsigned bcI) { |
| do_binary_op_common(bcI, Instruction::Xor); |
| } |
| |
| void do_binary_op_common(unsigned bcI, Instruction::BinaryOps op) { |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| opStack_.push(BinaryOperator::create(op, v1, v2, TMP,getBBAt(bcI))); |
| } |
| |
| |
| void do_iinc(unsigned bcI, unsigned index, int amount) { |
| Value* v = new LoadInst(getOrCreateLocal(index, Type::IntTy), |
| TMP, getBBAt(bcI)); |
| BinaryOperator::createAdd(v, ConstantSInt::get(Type::IntTy, amount), |
| TMP, getBBAt(bcI)); |
| new StoreInst(v, getOrCreateLocal(index, Type::IntTy), getBBAt(bcI)); |
| } |
| |
| void do_convert(unsigned bcI, JType to) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| opStack_.push(new CastInst(v1, getType(to), TMP, getBBAt(bcI))); |
| } |
| |
| void do_lcmp(unsigned bcI) { |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* c = BinaryOperator::createSetGT(v1, v2, TMP, getBBAt(bcI)); |
| Value* r = new SelectInst(c, ConstantSInt::get(Type::IntTy, 1), |
| ConstantSInt::get(Type::IntTy, 0), TMP, |
| getBBAt(bcI)); |
| c = BinaryOperator::createSetLT(v1, v2, TMP, getBBAt(bcI)); |
| r = new SelectInst(c, ConstantSInt::get(Type::IntTy, -1), r, TMP, |
| getBBAt(bcI)); |
| opStack_.push(r); |
| } |
| |
| void do_cmpl(unsigned bcI) { |
| do_cmp_common(bcI, -1); |
| } |
| |
| void do_cmpg(unsigned bcI) { |
| do_cmp_common(bcI, 1); |
| } |
| |
| void do_cmp_common(unsigned bcI, int valueIfUnordered) { |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* c = BinaryOperator::createSetGT(v1, v2, TMP, getBBAt(bcI)); |
| Value* r = new SelectInst(c, ConstantSInt::get(Type::IntTy, 1), |
| ConstantSInt::get(Type::IntTy, 0), TMP, |
| getBBAt(bcI)); |
| c = BinaryOperator::createSetLT(v1, v2, TMP, getBBAt(bcI)); |
| r = new SelectInst(c, ConstantSInt::get(Type::IntTy, -1), r, TMP, |
| getBBAt(bcI)); |
| c = new CallInst(module_->getOrInsertFunction |
| ("llvm.isunordered", |
| Type::BoolTy, v1->getType(), v2->getType(), 0), |
| v1, v2, TMP, getBBAt(bcI)); |
| r = new SelectInst(c, ConstantSInt::get(Type::IntTy, valueIfUnordered), |
| r, TMP, getBBAt(bcI)); |
| opStack_.push(r); |
| } |
| |
| void do_if(unsigned bcI, JSetCC cc, JType type, |
| unsigned t, unsigned f) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* v2 = llvm::Constant::getNullValue(v1->getType()); |
| Value* c = new SetCondInst(getSetCC(cc), v1, v2, TMP, getBBAt(bcI)); |
| new BranchInst(getBBAt(t), getBBAt(f), c, getBBAt(bcI)); |
| } |
| |
| void do_ifcmp(unsigned bcI, JSetCC cc, |
| unsigned t, unsigned f) { |
| Value* v2 = opStack_.top(); opStack_.pop(); |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| Value* c = new SetCondInst(getSetCC(cc), v1, v2, TMP, getBBAt(bcI)); |
| new BranchInst(getBBAt(t), getBBAt(f), c, getBBAt(bcI)); |
| } |
| |
| void do_goto(unsigned bcI, unsigned target) { |
| new BranchInst(getBBAt(target), getBBAt(bcI)); |
| } |
| |
| void do_jsr(unsigned bcI, unsigned target) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_ret(unsigned bcI, unsigned index) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_switch(unsigned bcI, |
| unsigned defTarget, |
| const SwitchCases& sw) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| SwitchInst* in = new SwitchInst(v1, getBBAt(defTarget), getBBAt(bcI)); |
| for (unsigned i = 0; i < sw.size(); ++i) |
| in->addCase(ConstantSInt::get(Type::IntTy, sw[i].first), |
| getBBAt(sw[i].second)); |
| } |
| |
| void do_return(unsigned bcI) { |
| Value* v1 = opStack_.top(); opStack_.pop(); |
| new ReturnInst(v1, getBBAt(bcI)); |
| } |
| |
| void do_return_void(unsigned bcI) { |
| new ReturnInst(NULL, getBBAt(bcI)); |
| } |
| |
| void do_getstatic(unsigned bcI, unsigned index) { |
| Value* v = new LoadInst(getStaticField(index), TMP, getBBAt(bcI)); |
| opStack_.push(v); |
| } |
| |
| void do_putstatic(unsigned bcI, unsigned index) { |
| Value* v = opStack_.top(); opStack_.pop(); |
| Value* ptr = getStaticField(index); |
| const Type* fieldTy = cast<PointerType>(ptr->getType())->getElementType(); |
| if (v->getType() != fieldTy) |
| v = new CastInst(v, fieldTy, TMP, getBBAt(bcI)); |
| new StoreInst(v, ptr, getBBAt(bcI)); |
| } |
| |
| void do_getfield(unsigned bcI, unsigned index) { |
| Value* p = opStack_.top(); opStack_.pop(); |
| Value* v = new LoadInst(getField(bcI, index, p), TMP, getBBAt(bcI)); |
| opStack_.push(v); |
| } |
| |
| void do_putfield(unsigned bcI, unsigned index) { |
| Value* v = opStack_.top(); opStack_.pop(); |
| Value* p = opStack_.top(); opStack_.pop(); |
| new StoreInst(v, getField(bcI, index, p), getBBAt(bcI)); |
| } |
| |
| void makeCall(Value* fun, |
| const std::vector<Value*> params, |
| BasicBlock* bb) { |
| const PointerType* funPtrTy = cast<PointerType>(fun->getType()); |
| const FunctionType* funTy = |
| cast<FunctionType>(funPtrTy->getElementType()); |
| |
| if (funTy->getReturnType() == Type::VoidTy) |
| new CallInst(fun, params, "", bb); |
| else { |
| Value* r = new CallInst(fun, params, TMP, bb); |
| opStack_.push(r); |
| } |
| } |
| |
| std::vector<Value*> getParams(FunctionType* funTy, BasicBlock* bb) { |
| unsigned numParams = funTy->getNumParams(); |
| std::vector<Value*> params(numParams); |
| while (numParams--) { |
| Value* p = opStack_.top(); opStack_.pop(); |
| params[numParams] = |
| p->getType() == funTy->getParamType(numParams) ? |
| p : |
| new CastInst(p, funTy->getParamType(numParams), TMP, bb); |
| } |
| |
| return params; |
| } |
| |
| void do_invokevirtual(unsigned bcI, unsigned index) { |
| ConstantMethodRef* methodRef = cf_->getConstantMethodRef(index); |
| ConstantNameAndType* nameAndType = methodRef->getNameAndType(); |
| |
| ClassFile* cf = ClassFile::get(methodRef->getClass()->getName()->str()); |
| const ClassInfo& ci = getClassInfo(cf); |
| const VTableInfo& vi = getVTableInfo(cf); |
| |
| const std::string& className = cf->getThisClass()->getName()->str(); |
| const std::string& methodDescr = |
| nameAndType->getName()->str() + |
| nameAndType->getDescriptor()->str(); |
| |
| FunctionType* funTy = |
| cast<FunctionType>(getType(nameAndType->getDescriptor(), ci.type)); |
| |
| BasicBlock* BB = getBBAt(bcI); |
| std::vector<Value*> params(getParams(funTy, BB)); |
| |
| Value* objRef = params.front(); |
| objRef = new CastInst(objRef, PointerType::get(ci.type), |
| "this", BB); |
| Value* objBase = getField(bcI, cf, LLVM_JAVA_OBJECT_BASE, objRef); |
| Function* f = module_->getOrInsertFunction( |
| LLVM_JAVA_GETOBJECTCLASS, PointerType::get(VTableInfo::VTableTy), |
| objBase->getType(), NULL); |
| Value* vtable = new CallInst(f, objBase, TMP, BB); |
| vtable = new CastInst(vtable, PointerType::get(vi.vtable->getType()), |
| TMP, BB); |
| vtable = new LoadInst(vtable, className + "<vtable>", BB); |
| std::vector<Value*> indices(1, ConstantUInt::get(Type::UIntTy, 0)); |
| assert(vi.m2iMap.find(methodDescr) != vi.m2iMap.end() && |
| "could not find slot for virtual function!"); |
| unsigned vSlot = vi.m2iMap.find(methodDescr)->second; |
| indices.push_back(ConstantUInt::get(Type::UIntTy, vSlot)); |
| Value* vfunPtr = |
| new GetElementPtrInst(vtable, indices, TMP, BB); |
| Value* vfun = new LoadInst(vfunPtr, methodDescr, BB); |
| |
| makeCall(vfun, params, BB); |
| } |
| |
| void do_invokespecial(unsigned bcI, unsigned index) { |
| ConstantMethodRef* methodRef = cf_->getConstantMethodRef(index); |
| ConstantNameAndType* nameAndType = methodRef->getNameAndType(); |
| |
| const std::string& className = methodRef->getClass()->getName()->str(); |
| const std::string& methodName = nameAndType->getName()->str(); |
| const std::string& methodDescr = |
| methodName + nameAndType->getDescriptor()->str(); |
| std::string funcName = className + '/' + methodDescr; |
| const ClassInfo& ci = getClassInfo(ClassFile::get(className)); |
| |
| // constructor calls are statically bound |
| BasicBlock* BB = getBBAt(bcI); |
| if (methodName == "<init>") { |
| FunctionType* funcTy = |
| cast<FunctionType>(getType(nameAndType->getDescriptor(), ci.type)); |
| Function* function = module_->getOrInsertFunction(funcName, funcTy); |
| toCompileFunctions_.insert(function); |
| makeCall(function, getParams(funcTy, BB), BB); |
| } |
| // otherwise we call the superclass' implementation of the method |
| else { |
| assert(0 && "not implemented"); |
| } |
| } |
| |
| void do_invokestatic(unsigned bcI, unsigned index) { |
| ConstantMethodRef* methodRef = cf_->getConstantMethodRef(index); |
| ConstantNameAndType* nameAndType = methodRef->getNameAndType(); |
| |
| std::string funcName = |
| methodRef->getClass()->getName()->str() + '/' + |
| nameAndType->getName()->str() + |
| nameAndType->getDescriptor()->str(); |
| |
| FunctionType* funcTy = |
| cast<FunctionType>(getType(nameAndType->getDescriptor())); |
| Function* function = module_->getOrInsertFunction(funcName, funcTy); |
| toCompileFunctions_.insert(function); |
| BasicBlock* BB = getBBAt(bcI); |
| makeCall(function, getParams(funcTy, BB), BB); |
| } |
| |
| void do_invokeinterface(unsigned bcI, unsigned index) { |
| ConstantInterfaceMethodRef* methodRef = |
| cf_->getConstantInterfaceMethodRef(index); |
| ConstantNameAndType* nameAndType = methodRef->getNameAndType(); |
| |
| ClassFile* cf = ClassFile::get(methodRef->getClass()->getName()->str()); |
| const ClassInfo& ci = getClassInfo(cf); |
| const VTableInfo& vi = getVTableInfo(cf); |
| |
| const std::string& className = cf->getThisClass()->getName()->str(); |
| const std::string& methodDescr = |
| nameAndType->getName()->str() + |
| nameAndType->getDescriptor()->str(); |
| |
| FunctionType* funTy = |
| cast<FunctionType>(getType(nameAndType->getDescriptor(), ci.type)); |
| |
| BasicBlock* BB = getBBAt(bcI); |
| std::vector<Value*> params(getParams(funTy, BB)); |
| |
| Value* objRef = params.front(); |
| objRef = new CastInst(objRef, PointerType::get(ci.type), |
| "this", BB); |
| Value* objBase = getField(bcI, cf, LLVM_JAVA_OBJECT_BASE, objRef); |
| Function* f = module_->getOrInsertFunction( |
| LLVM_JAVA_GETOBJECTCLASS, PointerType::get(VTableInfo::VTableTy), |
| objBase->getType(), NULL); |
| Value* vtable = new CallInst(f, objBase, TMP, BB); |
| // get the interfaces array of vtables |
| std::vector<Value*> indices(2, ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 3)); |
| Value* interfaceVTables = |
| new GetElementPtrInst(vtable, indices, TMP, BB); |
| interfaceVTables = new LoadInst(interfaceVTables, TMP, BB); |
| // get the actual interface vtable |
| indices.clear(); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, ci.interfaceIdx)); |
| Value* interfaceVTable = |
| new GetElementPtrInst(interfaceVTables, indices, TMP, BB); |
| interfaceVTable = |
| new LoadInst(interfaceVTable, className + "<vtable>", BB); |
| interfaceVTable = |
| new CastInst(interfaceVTable, vi.vtable->getType(), TMP, BB); |
| // get the function pointer |
| indices.resize(1); |
| assert(vi.m2iMap.find(methodDescr) != vi.m2iMap.end() && |
| "could not find slot for virtual function!"); |
| unsigned vSlot = vi.m2iMap.find(methodDescr)->second; |
| indices.push_back(ConstantUInt::get(Type::UIntTy, vSlot)); |
| Value* vfunPtr = |
| new GetElementPtrInst(interfaceVTable, indices, TMP, BB); |
| Value* vfun = new LoadInst(vfunPtr, methodDescr, BB); |
| |
| makeCall(vfun, params, BB); |
| } |
| |
| void do_new(unsigned bcI, unsigned index) { |
| ConstantClass* classRef = cf_->getConstantClass(index); |
| ClassFile* cf = ClassFile::get(classRef->getName()->str()); |
| const ClassInfo& ci = getClassInfo(cf); |
| const VTableInfo& vi = getVTableInfo(cf); |
| |
| Value* objRef = new MallocInst(ci.type, |
| ConstantUInt::get(Type::UIntTy, 0), |
| TMP, getBBAt(bcI)); |
| Value* vtable = getField(bcI, cf, LLVM_JAVA_OBJECT_BASE, objRef); |
| vtable = new CastInst(vtable, PointerType::get(vi.vtable->getType()), |
| TMP, getBBAt(bcI)); |
| vtable = new StoreInst(vi.vtable, vtable, getBBAt(bcI)); |
| opStack_.push(objRef); |
| } |
| |
| void do_newarray(unsigned bcI, JType type) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_anewarray(unsigned bcI, unsigned index) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_arraylength(unsigned bcI) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_athrow(unsigned bcI) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_checkcast(unsigned bcI, unsigned index) { |
| do_dup(bcI); |
| do_instanceof(bcI, index); |
| Value* r = opStack_.top(); opStack_.pop(); |
| Value* b = new SetCondInst(Instruction::SetEQ, |
| r, ConstantSInt::get(Type::IntTy, 1), |
| TMP, getBBAt(bcI)); |
| // FIXME: if b is false we must throw a ClassCast exception |
| } |
| |
| void do_instanceof(unsigned bcI, unsigned index) { |
| ConstantClass* classRef = cf_->getConstantClass(index); |
| ClassFile* cf = ClassFile::get(classRef->getName()->str()); |
| const VTableInfo& vi = getVTableInfo(cf); |
| |
| Value* objRef = opStack_.top(); opStack_.pop(); |
| Value* objBase = getField(bcI, cf, LLVM_JAVA_OBJECT_BASE, objRef); |
| Function* f = module_->getOrInsertFunction( |
| LLVM_JAVA_ISINSTANCEOF, Type::IntTy, |
| objBase->getType(), PointerType::get(VTableInfo::VTableTy), NULL); |
| Value* vtable = new CastInst(vi.vtable, PointerType::get(VTableInfo::VTableTy), TMP, getBBAt(bcI)); |
| Value* r = new CallInst(f, objBase, vtable, TMP, getBBAt(bcI)); |
| opStack_.push(r); |
| } |
| |
| void do_monitorenter(unsigned bcI) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_monitorexit(unsigned bcI) { |
| assert(0 && "not implemented"); |
| } |
| |
| void do_multianewarray(unsigned bcI, |
| unsigned index, |
| unsigned dims) { |
| assert(0 && "not implemented"); |
| } |
| }; |
| |
| unsigned CompilerImpl::ClassInfo::InterfaceCount = 0; |
| StructType* CompilerImpl::VTableInfo::VTableTy; |
| StructType* CompilerImpl::VTableInfo::TypeInfoTy; |
| |
| } } } // namespace llvm::Java:: |
| |
| Compiler::Compiler() |
| : compilerImpl_(new CompilerImpl()) |
| { |
| |
| } |
| |
| Compiler::~Compiler() |
| { |
| delete compilerImpl_; |
| } |
| |
| void Compiler::compile(Module& m, const std::string& className) |
| { |
| DEBUG(std::cerr << "Compiling class: " << className << '\n'); |
| |
| Function* main = |
| compilerImpl_->compileMethod(m, className + "/main([Ljava/lang/String;)V"); |
| Function* javaMain = m.getOrInsertFunction |
| ("llvm_java_main", Type::VoidTy, |
| Type::IntTy, PointerType::get(PointerType::get(Type::SByteTy)), NULL); |
| |
| BasicBlock* bb = new BasicBlock("entry", javaMain); |
| const FunctionType* mainTy = main->getFunctionType(); |
| new CallInst(main, |
| // FIXME: Forward correct params from llvm_java_main |
| llvm::Constant::getNullValue(mainTy->getParamType(0)), |
| "", |
| bb); |
| new ReturnInst(NULL, bb); |
| } |