| //===-- 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/Compiler.h> |
| #include "BasicBlockBuilder.h" |
| #include "Locals.h" |
| #include "OperandStack.h" |
| #include "Resolver.h" |
| #include <llvm/Java/Bytecode.h> |
| #include <llvm/Java/BytecodeParser.h> |
| #include <llvm/Java/ClassFile.h> |
| #include <llvm/Constants.h> |
| #include <llvm/DerivedTypes.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/CFG.h> |
| #include <llvm/Support/Debug.h> |
| #include <iostream> |
| #include <list> |
| #include <vector> |
| |
| using namespace llvm; |
| using namespace llvm::Java; |
| |
| namespace llvm { namespace Java { namespace { |
| |
| const std::string TMP("tmp"); |
| |
| llvm::Constant* ONE = ConstantSInt::get(Type::IntTy, 1); |
| llvm::Constant* ZERO = ConstantSInt::get(Type::IntTy, 0); |
| llvm::Constant* MINUS_ONE = ConstantSInt::get(Type::IntTy, -1); |
| |
| llvm::Constant* INT_SHIFT_MASK = ConstantUInt::get(Type::UByteTy, 0x1f); |
| llvm::Constant* LONG_SHIFT_MASK = ConstantUInt::get(Type::UByteTy, 0x3f); |
| |
| class Compiler : public BytecodeParser<Compiler> { |
| Module* module_; |
| std::auto_ptr<Resolver> resolver_; |
| GlobalVariable* JNIEnvPtr_; |
| const VMClass* class_; |
| std::auto_ptr<BasicBlockBuilder> bbBuilder_; |
| std::list<BasicBlock*> bbWorkList_; |
| typedef std::map<BasicBlock*, unsigned> OpStackDepthMap; |
| OpStackDepthMap opStackDepthMap_; |
| typedef std::map<std::string, GlobalVariable*> StringMap; |
| StringMap stringMap_; |
| BasicBlock* currentBB_; |
| Locals locals_; |
| OperandStack opStack_; |
| Function *getClassRecord_, *setClassRecord_, *throw_, *isInstanceOf_, |
| *memcpy_, *memset_; |
| std::vector<llvm::Constant*> classInitializers_; |
| |
| SetVector<const VMMethod*> toCompileMethods_; |
| |
| public: |
| Compiler(Module* m) |
| : module_(m), |
| resolver_(new Resolver(module_)), |
| locals_(resolver_.get(), 0), |
| opStack_(resolver_.get(), 0) { |
| Type* JNIEnvTy = OpaqueType::get(); |
| module_->addTypeName("JNIEnv", JNIEnvTy); |
| JNIEnvPtr_ = new GlobalVariable(JNIEnvTy, |
| true, |
| GlobalVariable::ExternalLinkage, |
| NULL, |
| "llvm_java_JNIEnv", |
| module_); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| const Type* objectBaseType = resolver_->getObjectBaseType(); |
| |
| getClassRecord_ = module_->getOrInsertFunction( |
| "llvm_java_get_class_record", classRecordPtrType, |
| objectBaseType, NULL); |
| setClassRecord_ = module_->getOrInsertFunction( |
| "llvm_java_set_class_record", Type::VoidTy, |
| objectBaseType, classRecordPtrType, NULL); |
| throw_ = module_->getOrInsertFunction( |
| "llvm_java_throw", Type::IntTy, |
| objectBaseType, NULL); |
| isInstanceOf_ = module_->getOrInsertFunction( |
| "llvm_java_is_instance_of", Type::IntTy, |
| objectBaseType, classRecordPtrType, NULL); |
| memcpy_ = module_->getOrInsertFunction( |
| "llvm.memcpy", Type::VoidTy, |
| PointerType::get(Type::SByteTy), |
| PointerType::get(Type::SByteTy), |
| Type::ULongTy, Type::UIntTy, NULL); |
| memset_ = module_->getOrInsertFunction( |
| "llvm.memset", Type::VoidTy, |
| PointerType::get(Type::SByteTy), |
| Type::UByteTy, Type::ULongTy, Type::UIntTy, NULL); |
| } |
| |
| private: |
| void push(Value* value) { |
| opStack_.push(value, currentBB_); |
| } |
| |
| Value* pop(const Type* type) { |
| return opStack_.pop(type, currentBB_); |
| } |
| |
| /// Schedule a method for compilation. Returns true if this is the |
| /// first time this function was scheduled. |
| bool scheduleMethod(const VMMethod* method) { |
| if (toCompileMethods_.insert(method)) { |
| DEBUG(std::cerr << "Scheduling function: " |
| << method->getFunction()->getName() << " for compilation\n"); |
| return true; |
| } |
| return false; |
| } |
| |
| template <typename InsertionPointTy> |
| void initializeString(Value* globalString, |
| const std::string& str, |
| InsertionPointTy* ip) { |
| // Create a new byte[] object and initialize it with the |
| // contents of this string constant. |
| Value* count = ConstantUInt::get(Type::UIntTy, str.size()); |
| Value* arrayRef = allocateArray(resolver_->getClass("[B"), count, ip); |
| // Copy string data. |
| std::vector<Value*> indices; |
| indices.reserve(3); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 2)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| Value* arrayData = new GetElementPtrInst(arrayRef, indices, TMP, ip); |
| llvm::Constant* init = ConstantArray::get(str); |
| GlobalVariable* chars = new GlobalVariable( |
| init->getType(), |
| true, |
| GlobalVariable::InternalLinkage, |
| init, |
| str + ".str", |
| module_); |
| |
| std::vector<Value*> params; |
| params.reserve(4); |
| params.clear(); |
| params.push_back(arrayData); |
| params.push_back(ConstantExpr::getPtrPtrFromArrayPtr(chars)); |
| params.push_back(new CastInst(count, Type::ULongTy, TMP, ip)); |
| params.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| new CallInst(memcpy_, params, "", ip); |
| |
| // Get class information for java/lang/String. |
| const VMClass* clazz = resolver_->getClass("java/lang/String"); |
| emitClassInitializers(clazz); |
| |
| // Install the class record. |
| Value* objBase = |
| new CastInst(globalString, resolver_->getObjectBaseType(), TMP, ip); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| Value* classRecord = |
| new CastInst(clazz->getClassRecord(), classRecordPtrType, TMP, ip); |
| new CallInst(setClassRecord_, objBase, classRecord, "", ip); |
| |
| // Initialize it: call java/lang/String/<init>(byte[],int) |
| const VMMethod* method = clazz->getMethod("<init>([BI)V"); |
| |
| params.reserve(3); |
| params.clear(); |
| params.push_back(objBase); |
| params.push_back( |
| new CastInst(arrayRef, resolver_->getObjectBaseType(), TMP, ip)); |
| params.push_back(ConstantSInt::get(Type::IntTy, 0)); |
| new CallInst(method->getFunction(), params, "", ip); |
| } |
| |
| /// Returns the type of the Java string descriptor for JNI. |
| const Type* getJNIType(const std::string& descr) { |
| unsigned i = 0; |
| return getJNITypeHelper(descr, i); |
| } |
| |
| const Type* getJNITypeHelper(const std::string& descr, unsigned& i) { |
| 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; |
| // Both array and object types are pointers to llvm_object_base |
| case 'L': { |
| unsigned e = descr.find(';', i); |
| i = e + 1; |
| return resolver_->getObjectBaseType(); |
| } |
| case '[': |
| // Skip '['s. |
| if (descr[i] == '[') |
| do { ++i; } while (descr[i] == '['); |
| // Consume the element type |
| getJNITypeHelper(descr, i); |
| return resolver_->getObjectBaseType(); |
| case '(': { |
| std::vector<const Type*> params; |
| // JNIEnv* |
| params.push_back(JNIEnvPtr_->getType()); |
| params.push_back(resolver_->getObjectBaseType()); |
| while (descr[i] != ')') |
| params.push_back(getJNITypeHelper(descr, i)); |
| return FunctionType::get(getJNITypeHelper(descr, ++i), params, false); |
| } |
| // FIXME: Throw something |
| default: assert(0 && "Cannot parse type descriptor!"); |
| } |
| return 0; // not reached |
| } |
| |
| std::string getMangledString(const std::string& str) { |
| std::string mangledStr; |
| |
| for (unsigned i = 0, e = str.size(); i != e; ++i) { |
| if (str[i] == '/') |
| mangledStr += '_'; |
| else if (str[i] == '_') |
| mangledStr += "_1"; |
| else if (str[i] == ';') |
| mangledStr += "_2"; |
| else if (str[i] == '[') |
| mangledStr += "_3"; |
| else |
| mangledStr += str[i]; |
| } |
| return mangledStr; |
| } |
| |
| /// Compiles the passed method only (it does not compile any |
| /// callers or methods of objects it creates). |
| void compileMethodOnly(const VMMethod* method) { |
| class_ = method->getParent(); |
| |
| Function* function = method->getFunction(); |
| if (!function->empty()) { |
| DEBUG(std::cerr << "Function: " << function->getName() |
| << " is already compiled!\n"); |
| return; |
| } |
| |
| if (method->isNative()) { |
| DEBUG(std::cerr << "Adding stub for natively implemented method: " |
| << function->getName() << '\n'); |
| const FunctionType* jniFuncTy = |
| cast<FunctionType>(getJNIType(method->getDescriptor())); |
| |
| std::string funcName = |
| "Java_" + |
| getMangledString(class_->getName()) + '_' + |
| getMangledString(method->getName()); |
| if (class_->getClassFile()->isNativeMethodOverloaded(*method->getMethod())) { |
| // We need to add two underscores and a mangled argument signature |
| funcName += "__"; |
| const std::string descr = method->getDescriptor(); |
| funcName += getMangledString( |
| std::string(descr.begin() + descr.find('(') + 1, |
| descr.begin() + descr.find(')'))); |
| } |
| |
| Function* jniFunction = |
| module_->getOrInsertFunction(funcName, jniFuncTy); |
| |
| BasicBlock* bb = new BasicBlock("entry", function); |
| std::vector<Value*> params; |
| params.push_back(JNIEnvPtr_); |
| if (method->isStatic()) |
| params.push_back( |
| new CastInst(method->getParent()->getClassRecord(), |
| resolver_->getObjectBaseType(), TMP, bb)); |
| for (Function::arg_iterator A = function->arg_begin(), |
| E = function->arg_end(); A != E; ++A) { |
| params.push_back( |
| new CastInst(A, jniFuncTy->getParamType(params.size()), TMP, bb)); |
| } |
| Value* result = new CallInst(jniFunction, params, "", bb); |
| if (result->getType() != Type::VoidTy) |
| result = new CastInst(result, function->getReturnType(), TMP,bb); |
| new ReturnInst(result, bb); |
| |
| return; |
| } |
| |
| assert (!method->isAbstract() && "Trying to compile an abstract method!"); |
| |
| // HACK: skip most of the class libraries. |
| const std::string& funcName = function->getName(); |
| if ((funcName.find("java/") == 0 && |
| funcName.find("java/lang/Object") != 0 && |
| (funcName.find("java/lang/Throwable") != 0 || |
| funcName.find("java/lang/Throwable$StaticData/<cl") == 0) && |
| funcName.find("java/lang/Exception") != 0 && |
| funcName.find("java/lang/IllegalArgumentException") != 0 && |
| funcName.find("java/lang/IllegalStateException") != 0 && |
| funcName.find("java/lang/IndexOutOfBoundsException") != 0 && |
| funcName.find("java/lang/RuntimeException") != 0 && |
| (funcName.find("java/lang/Math") != 0 || |
| funcName.find("java/lang/Math/<cl") == 0) && |
| funcName.find("java/lang/Number") != 0 && |
| funcName.find("java/lang/Byte") != 0 && |
| funcName.find("java/lang/Float") != 0 && |
| funcName.find("java/lang/Integer") != 0 && |
| funcName.find("java/lang/Long") != 0 && |
| funcName.find("java/lang/Short") != 0 && |
| (funcName.find("java/lang/String") != 0 || |
| funcName.find("java/lang/String/<cl") == 0) && |
| funcName.find("java/lang/StringBuffer") != 0 && |
| (funcName.find("java/lang/System") != 0 || |
| funcName.find("java/lang/System/loadLibrary") == 0) && |
| funcName.find("java/lang/VMSystem") != 0 && |
| (funcName.find("java/util/") != 0 || |
| funcName.find("java/util/Locale/<cl") == 0 || |
| funcName.find("java/util/ResourceBundle/<cl") == 0 || |
| funcName.find("java/util/Calendar/<cl") == 0) || |
| funcName.find("java/util/PropertyPermission/<cl") == 0) || |
| (funcName.find("gnu/") == 0)) { |
| DEBUG(std::cerr << "Skipping compilation of method: " |
| << funcName << '\n'); |
| return; |
| } |
| |
| DEBUG(std::cerr << "Compiling method: " << funcName << '\n'); |
| |
| Java::CodeAttribute* codeAttr = method->getMethod()->getCodeAttribute(); |
| |
| opStackDepthMap_.clear(); |
| bbBuilder_.reset(new BasicBlockBuilder(function, codeAttr)); |
| |
| // Put arguments into locals. |
| locals_ = Locals(resolver_.get(), codeAttr->getMaxLocals()); |
| |
| unsigned index = 0; |
| for (Function::arg_iterator a = function->arg_begin(), |
| ae = function->arg_end(); a != ae; ++a) { |
| locals_.store(index, a, &function->getEntryBlock()); |
| index += resolver_->isTwoSlotType(a->getType()) ? 2 : 1; |
| } |
| |
| BasicBlock* bb0 = bbBuilder_->getBasicBlock(0); |
| |
| // For bb0 the operand stack is empty and the locals contain the |
| // arguments to the function. |
| // |
| // NOTE: We create an operand stack one size too big because we |
| // push extra values on the stack to simplify code generation |
| // (see implementation of ifne). |
| opStack_ = OperandStack(resolver_.get(), codeAttr->getMaxStack()+2); |
| opStackDepthMap_.insert(std::make_pair(bb0, 0)); |
| |
| // Insert bb0 in the work list. |
| bbWorkList_.push_back(bb0); |
| |
| // Process the work list until we compile the whole function. |
| while (!bbWorkList_.empty()) { |
| currentBB_ = bbWorkList_.front(); |
| bbWorkList_.pop_front(); |
| |
| OpStackDepthMap::iterator opStackDepth = |
| opStackDepthMap_.find(currentBB_); |
| assert(opStackDepth != opStackDepthMap_.end() && |
| "Unknown operand stack depth for basic block in work list!"); |
| |
| opStack_.setDepth(opStackDepth->second); |
| |
| unsigned start, end; |
| tie(start, end) = bbBuilder_->getBytecodeIndices(currentBB_); |
| |
| // Compile this basic block. |
| parse(codeAttr->getCode(), start, end); |
| |
| // If this basic block does not have a terminator, it should |
| // have an unconditional branch to the next basic block |
| // (fallthrough). |
| if (!currentBB_->getTerminator()) |
| new BranchInst(bbBuilder_->getBasicBlock(end), currentBB_); |
| |
| // For each successor of this basic block we can compute its |
| // entry operand stack depth. We do so, and add it to the work |
| // list. If a successor already has an entry operand stack and |
| // locals we assume the computation was correct and do not add |
| // it to the work list. |
| for (succ_iterator |
| SI = succ_begin(currentBB_), SE = succ_end(currentBB_); |
| SI != SE; ++SI) { |
| BasicBlock* Succ = *SI; |
| OpStackDepthMap::iterator succOpStackDepth = |
| opStackDepthMap_.lower_bound(Succ); |
| if (succOpStackDepth == opStackDepthMap_.end() || |
| succOpStackDepth->first != Succ) { |
| opStackDepthMap_.insert(succOpStackDepth, |
| std::make_pair(Succ, opStack_.getDepth())); |
| bbWorkList_.push_back(Succ); |
| } |
| } |
| } |
| |
| // Add an unconditional branch from the entry block to bb0. |
| new BranchInst(bb0, &function->getEntryBlock()); |
| |
| // FIXME: remove empty basic blocks (we have empty basic blocks |
| // because of our lack of exception support). |
| for (Function::iterator bb = function->begin(), be = function->end(); |
| bb != be; ) |
| if (bb->empty()) |
| bb = function->getBasicBlockList().erase(bb); |
| else |
| ++bb; |
| |
| DEBUG(std::cerr << "Finished compilation of method: "<< funcName << '\n'); |
| // DEBUG(function->dump()); |
| } |
| |
| /// Emits static initializers for this class if not done already. |
| void emitClassInitializers(const VMClass* clazz) { |
| static SetVector<const VMClass*> toInitClasses; |
| |
| // If this is a primitive class we are done. |
| if (clazz->isPrimitive()) |
| return; |
| |
| // If this class is already initialized, we are done. |
| if (!toInitClasses.insert(clazz)) |
| return; |
| |
| // If this class has a super class, initialize that first. |
| if (const VMClass* superClass = clazz->getSuperClass()) |
| emitClassInitializers(superClass); |
| |
| // If this class is an array, initialize its component class now. |
| if (const VMClass* componentClass = clazz->getComponentClass()) |
| emitClassInitializers(componentClass); |
| |
| // Schedule all its dynamically bound non abstract methods for |
| // compilation. |
| for (unsigned i = 0, e = clazz->getNumDynamicMethods(); i != e; ++i) { |
| const VMMethod* method = clazz->getDynamicMethod(i); |
| if (!method->isAbstract()) |
| scheduleMethod(method); |
| } |
| |
| // Schedule all its statically bound non abstract methods for |
| // compilation. |
| for (unsigned i = 0, e = clazz->getNumStaticMethods(); i != e; ++i) { |
| const VMMethod* method = clazz->getStaticMethod(i); |
| if (!method->isAbstract()) |
| scheduleMethod(method); |
| } |
| |
| // If this class has a constant pool (was loaded from a |
| // classfile), create constant strings for it. |
| if (const ClassFile* classfile = clazz->getClassFile()) { |
| Function* stringConstructors = module_->getOrInsertFunction( |
| clazz->getName() + "<strinit>", |
| FunctionType::get(Type::VoidTy, std::vector<const Type*>(), false)); |
| Instruction* I = |
| new ReturnInst(NULL, new BasicBlock("entry", stringConstructors)); |
| for (unsigned i = 0, e = classfile->getNumConstants(); i != e; ++i) |
| if (ConstantString* s = dynamic_cast<ConstantString*>(classfile->getConstant(i))) |
| initializeString(clazz->getConstant(i), s->getValue()->str(), I); |
| |
| // Insert string constructors method in class initializers array. |
| classInitializers_.push_back(stringConstructors); |
| |
| // Call its class initialization method if it exists. |
| if (const VMMethod* method = clazz->getMethod("<clinit>()V")) |
| classInitializers_.push_back(method->getFunction()); |
| } |
| } |
| |
| public: |
| /// Compiles the specified method given a <class,method> |
| /// descriptor and the transitive closure of all methods |
| /// (possibly) called by it. |
| const VMMethod* compileMethod(const std::string& className, |
| const std::string& methodDesc) { |
| // Load the class. |
| const VMClass* clazz = resolver_->getClass(className); |
| emitClassInitializers(clazz); |
| |
| // Find the method. |
| const VMMethod* method = clazz->getMethod(methodDesc); |
| // Compile the transitive closure of methods called by this method. |
| for (unsigned i = 0; i != toCompileMethods_.size(); ++i) { |
| const VMMethod* m = toCompileMethods_[i]; |
| compileMethodOnly(m); |
| DEBUG(std::cerr << i+1 << '/' << toCompileMethods_.size() |
| << " functions compiled\n"); |
| } |
| |
| // Null terminate the static initializers array and add the |
| // global to the module. |
| Type* classInitializerType = PointerType::get( |
| FunctionType::get(Type::VoidTy, std::vector<const Type*>(), false)); |
| classInitializers_.push_back( |
| llvm::Constant::getNullValue(classInitializerType)); |
| |
| ArrayType* classInitializersType = |
| ArrayType::get(classInitializerType, classInitializers_.size()); |
| new GlobalVariable(classInitializersType, |
| true, |
| GlobalVariable::ExternalLinkage, |
| ConstantArray::get(classInitializersType, |
| classInitializers_), |
| "llvm_java_class_initializers", |
| module_); |
| |
| // Emit the array of all class records. |
| resolver_->emitClassRecordsArray(); |
| |
| return method; |
| } |
| |
| void do_aconst_null() { |
| push(llvm::Constant::getNullValue(resolver_->getObjectBaseType())); |
| } |
| |
| void do_iconst(int value) { |
| push(ConstantSInt::get(Type::IntTy, value)); |
| } |
| |
| void do_lconst(long long value) { |
| push(ConstantSInt::get(Type::LongTy, value)); |
| } |
| |
| void do_fconst(float value) { |
| push(ConstantFP::get(Type::FloatTy, value)); |
| } |
| |
| void do_dconst(double value) { |
| push(ConstantFP::get(Type::DoubleTy, value)); |
| } |
| |
| void do_ldc(unsigned index) { |
| llvm::Constant* c = class_->getConstant(index); |
| assert(c && "Java constant not handled!"); |
| push(c); |
| } |
| |
| void do_ldc2(unsigned index) { |
| do_ldc(index); |
| } |
| |
| void do_iload(unsigned index) { do_load_common(index, Type::IntTy); } |
| void do_lload(unsigned index) { do_load_common(index, Type::LongTy); } |
| void do_fload(unsigned index) { do_load_common(index, Type::FloatTy); } |
| void do_dload(unsigned index) { do_load_common(index, Type::DoubleTy); } |
| void do_aload(unsigned index) { do_load_common(index, resolver_->getObjectBaseType()); } |
| |
| void do_load_common(unsigned index, const Type* type) { |
| Value* val = locals_.load(index, type, currentBB_); |
| push(val); |
| } |
| |
| void do_iaload() { do_aload_common("[I"); } |
| void do_laload() { do_aload_common("[J"); } |
| void do_faload() { do_aload_common("[F"); } |
| void do_daload() { do_aload_common("[D"); } |
| void do_aaload() { do_aload_common("[Ljava/lang/Object;"); } |
| void do_baload() { do_aload_common("[B"); } |
| void do_caload() { do_aload_common("[C"); } |
| void do_saload() { do_aload_common("[S"); } |
| |
| void do_aload_common(const std::string& className) { |
| const VMClass* arrayClass = resolver_->getClass(className); |
| assert(arrayClass->isArray() && "Not an array class!"); |
| Value* index = pop(Type::IntTy); |
| Value* arrayRef = pop(arrayClass->getType()); |
| |
| std::vector<Value*> indices; |
| indices.reserve(3); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 2)); |
| indices.push_back(index); |
| Value* elementPtr = |
| new GetElementPtrInst(arrayRef, indices, TMP, currentBB_); |
| Value* result = new LoadInst(elementPtr, TMP, currentBB_); |
| push(result); |
| } |
| |
| void do_istore(unsigned index) { do_store_common(index, Type::IntTy); } |
| void do_lstore(unsigned index) { do_store_common(index, Type::LongTy); } |
| void do_fstore(unsigned index) { do_store_common(index, Type::FloatTy); } |
| void do_dstore(unsigned index) { do_store_common(index, Type::DoubleTy); } |
| void do_astore(unsigned index) { do_store_common(index, resolver_->getObjectBaseType()); } |
| |
| void do_store_common(unsigned index, const Type* type) { |
| Value* val = pop(type); |
| locals_.store(index, val, currentBB_); |
| } |
| |
| void do_iastore() { do_astore_common("[I"); } |
| void do_lastore() { do_astore_common("[J"); } |
| void do_fastore() { do_astore_common("[F"); } |
| void do_dastore() { do_astore_common("[D"); } |
| void do_aastore() { do_astore_common("[Ljava/lang/Object;"); } |
| void do_bastore() { do_astore_common("[B"); } |
| void do_castore() { do_astore_common("[C"); } |
| void do_sastore() { do_astore_common("[S"); } |
| |
| void do_astore_common(const std::string& className) { |
| const VMClass* arrayClass = resolver_->getClass(className); |
| assert(arrayClass->isArray() && "Not an array class!"); |
| const VMClass* componentClass = arrayClass->getComponentClass(); |
| Value* value = pop(componentClass->getType()); |
| Value* index = pop(Type::IntTy); |
| Value* arrayRef = pop(arrayClass->getType()); |
| |
| std::vector<Value*> indices; |
| indices.reserve(3); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 2)); |
| indices.push_back(index); |
| Value* elementPtr = |
| new GetElementPtrInst(arrayRef, indices, TMP, currentBB_); |
| |
| new StoreInst(value, elementPtr, currentBB_); |
| } |
| |
| void do_pop() { |
| opStack_.do_pop(currentBB_); |
| } |
| |
| void do_pop2() { |
| opStack_.do_pop2(currentBB_); |
| } |
| |
| void do_dup() { |
| opStack_.do_dup(currentBB_); |
| } |
| |
| void do_dup_x1() { |
| opStack_.do_dup_x1(currentBB_); |
| } |
| |
| void do_dup_x2() { |
| opStack_.do_dup_x2(currentBB_); |
| } |
| |
| void do_dup2() { |
| opStack_.do_dup2(currentBB_); |
| } |
| |
| void do_dup2_x1() { |
| opStack_.do_dup2_x1(currentBB_); |
| } |
| |
| void do_dup2_x2() { |
| opStack_.do_dup2_x2(currentBB_); |
| } |
| |
| void do_swap() { |
| opStack_.do_swap(currentBB_); |
| } |
| |
| void do_iadd() { do_binary_op_common(Instruction::Add, Type::IntTy); } |
| void do_ladd() { do_binary_op_common(Instruction::Add, Type::LongTy); } |
| void do_fadd() { do_binary_op_common(Instruction::Add, Type::FloatTy); } |
| void do_dadd() { do_binary_op_common(Instruction::Add, Type::DoubleTy); } |
| |
| void do_isub() { do_binary_op_common(Instruction::Sub, Type::IntTy); } |
| void do_lsub() { do_binary_op_common(Instruction::Sub, Type::LongTy); } |
| void do_fsub() { do_binary_op_common(Instruction::Sub, Type::FloatTy); } |
| void do_dsub() { do_binary_op_common(Instruction::Sub, Type::DoubleTy); } |
| |
| void do_imul() { do_binary_op_common(Instruction::Mul, Type::IntTy); } |
| void do_lmul() { do_binary_op_common(Instruction::Mul, Type::LongTy); } |
| void do_fmul() { do_binary_op_common(Instruction::Mul, Type::FloatTy); } |
| void do_dmul() { do_binary_op_common(Instruction::Mul, Type::DoubleTy); } |
| |
| void do_idiv() { do_binary_op_common(Instruction::Div, Type::IntTy); } |
| void do_ldiv() { do_binary_op_common(Instruction::Div, Type::LongTy); } |
| void do_fdiv() { do_binary_op_common(Instruction::Div, Type::FloatTy); } |
| void do_ddiv() { do_binary_op_common(Instruction::Div, Type::DoubleTy); } |
| |
| void do_irem() { do_binary_op_common(Instruction::Rem, Type::IntTy); } |
| void do_lrem() { do_binary_op_common(Instruction::Rem, Type::LongTy); } |
| void do_frem() { do_binary_op_common(Instruction::Rem, Type::FloatTy); } |
| void do_drem() { do_binary_op_common(Instruction::Rem, Type::DoubleTy); } |
| |
| void do_ineg() { do_neg_common(Type::IntTy); } |
| void do_lneg() { do_neg_common(Type::LongTy); } |
| void do_fneg() { do_neg_common(Type::FloatTy); } |
| void do_dneg() { do_neg_common(Type::DoubleTy); } |
| |
| void do_neg_common(const Type* type) { |
| Value* v1 = pop(type); |
| Value* r = BinaryOperator::createNeg(v1, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_ishl() { do_shift_common(Instruction::Shl, Type::IntTy); } |
| void do_lshl() { do_shift_common(Instruction::Shl, Type::LongTy); } |
| void do_ishr() { do_shift_common(Instruction::Shr, Type::IntTy); } |
| void do_lshr() { do_shift_common(Instruction::Shr, Type::LongTy); } |
| |
| void do_iushr() { do_shift_common(Instruction::Shr, Type::UIntTy); } |
| void do_lushr() { do_shift_common(Instruction::Shr, Type::ULongTy); } |
| |
| void do_shift_common(Instruction::OtherOps op, const Type* type) { |
| llvm::Constant* mask = |
| type == Type::IntTy ? INT_SHIFT_MASK : LONG_SHIFT_MASK; |
| Value* a = pop(Type::UByteTy); |
| a = BinaryOperator::create(Instruction::And, a, mask, TMP, currentBB_); |
| Value* v = pop(type); |
| Value* r = new ShiftInst(op, v, a, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_iand() { do_binary_op_common(Instruction::And, Type::IntTy); } |
| void do_land() { do_binary_op_common(Instruction::And, Type::LongTy); } |
| void do_ior() { do_binary_op_common(Instruction::Or, Type::IntTy); } |
| void do_lor() { do_binary_op_common(Instruction::Or, Type::LongTy); } |
| void do_ixor() { do_binary_op_common(Instruction::Xor, Type::IntTy); } |
| void do_lxor() { do_binary_op_common(Instruction::Xor, Type::LongTy); } |
| |
| void do_binary_op_common(Instruction::BinaryOps op, const Type* type) { |
| Value* v2 = pop(type); |
| Value* v1 = pop(type); |
| Value* r = BinaryOperator::create(op, v1, v2, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_iinc(unsigned index, int amount) { |
| Value* v = locals_.load(index, Type::IntTy, currentBB_); |
| Value* a = ConstantSInt::get(Type::IntTy, amount); |
| v = BinaryOperator::createAdd(v, a, TMP, currentBB_); |
| locals_.store(index, v, currentBB_); |
| } |
| |
| void do_i2l() { do_cast_common(Type::IntTy, Type::LongTy); } |
| void do_i2f() { do_cast_common(Type::IntTy, Type::FloatTy); } |
| void do_i2d() { do_cast_common(Type::IntTy, Type::DoubleTy); } |
| void do_l2i() { do_cast_common(Type::LongTy, Type::IntTy); } |
| void do_l2f() { do_cast_common(Type::LongTy, Type::FloatTy); } |
| void do_l2d() { do_cast_common(Type::LongTy, Type::DoubleTy); } |
| void do_f2i() { do_cast_common(Type::FloatTy, Type::IntTy); } |
| void do_f2l() { do_cast_common(Type::FloatTy, Type::LongTy); } |
| void do_f2d() { do_cast_common(Type::FloatTy, Type::DoubleTy); } |
| void do_d2i() { do_cast_common(Type::DoubleTy, Type::IntTy); } |
| void do_d2l() { do_cast_common(Type::DoubleTy, Type::LongTy); } |
| void do_d2f() { do_cast_common(Type::DoubleTy, Type::FloatTy); } |
| void do_i2b() { do_cast_common(Type::IntTy, Type::SByteTy); } |
| void do_i2c() { do_cast_common(Type::IntTy, Type::UShortTy); } |
| void do_i2s() { do_cast_common(Type::IntTy, Type::ShortTy); } |
| |
| void do_cast_common(const Type* from, const Type* to) { |
| Value* v1 = pop(from); |
| push(new CastInst(v1, to, TMP, currentBB_)); |
| } |
| |
| void do_lcmp() { |
| Value* v2 = pop(Type::LongTy); |
| Value* v1 = pop(Type::LongTy); |
| Value* c = BinaryOperator::createSetGT(v1, v2, TMP, currentBB_); |
| Value* r = new SelectInst(c, ONE, ZERO, TMP, currentBB_); |
| c = BinaryOperator::createSetLT(v1, v2, TMP, currentBB_); |
| r = new SelectInst(c, MINUS_ONE, r, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_fcmpl() { do_cmp_common(Type::FloatTy, false); } |
| void do_dcmpl() { do_cmp_common(Type::DoubleTy, false); } |
| void do_fcmpg() { do_cmp_common(Type::FloatTy, true); } |
| void do_dcmpg() { do_cmp_common(Type::DoubleTy, true); } |
| |
| void do_cmp_common(const Type* type, bool pushOne) { |
| Value* v2 = pop(type); |
| Value* v1 = pop(type); |
| Value* c = BinaryOperator::createSetGT(v1, v2, TMP, currentBB_); |
| Value* r = new SelectInst(c, ONE, ZERO, TMP, currentBB_); |
| c = BinaryOperator::createSetLT(v1, v2, TMP, currentBB_); |
| r = new SelectInst(c, MINUS_ONE, r, TMP, currentBB_); |
| c = new CallInst(module_->getOrInsertFunction |
| ("llvm.isunordered", |
| Type::BoolTy, v1->getType(), v2->getType(), NULL), |
| v1, v2, TMP, currentBB_); |
| r = new SelectInst(c, pushOne ? ONE : MINUS_ONE, r, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_ifeq(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetEQ, Type::IntTy, t, f); |
| } |
| void do_ifne(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetNE, Type::IntTy, t, f); |
| } |
| void do_iflt(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetLT, Type::IntTy, t, f); |
| } |
| void do_ifge(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetGE, Type::IntTy, t, f); |
| } |
| void do_ifgt(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetGT, Type::IntTy, t, f); |
| } |
| void do_ifle(unsigned t, unsigned f) { |
| do_iconst(0); |
| do_if_common(Instruction::SetLE, Type::IntTy, t, f); |
| } |
| void do_if_icmpeq(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetEQ, Type::IntTy, t, f); |
| } |
| void do_if_icmpne(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetNE, Type::IntTy, t, f); |
| } |
| void do_if_icmplt(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetLT, Type::IntTy, t, f); |
| } |
| void do_if_icmpge(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetGE, Type::IntTy, t, f); |
| } |
| void do_if_icmpgt(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetGT, Type::IntTy, t, f); |
| } |
| void do_if_icmple(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetLE, Type::IntTy, t, f); |
| } |
| void do_if_acmpeq(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetEQ, resolver_->getObjectBaseType(), t, f); |
| } |
| void do_if_acmpne(unsigned t, unsigned f) { |
| do_if_common(Instruction::SetNE, resolver_->getObjectBaseType(), t, f); |
| } |
| void do_ifnull(unsigned t, unsigned f) { |
| do_aconst_null(); |
| do_if_common(Instruction::SetEQ, resolver_->getObjectBaseType(), t, f); |
| } |
| void do_ifnonnull(unsigned t, unsigned f) { |
| do_aconst_null(); |
| do_if_common(Instruction::SetNE, resolver_->getObjectBaseType(), t, f); |
| } |
| |
| void do_if_common(Instruction::BinaryOps cc, const Type* type, |
| unsigned t, unsigned f) { |
| Value* v2 = pop(type); |
| Value* v1 = pop(type); |
| Value* c = new SetCondInst(cc, v1, v2, TMP, currentBB_); |
| new BranchInst(bbBuilder_->getBasicBlock(t), |
| bbBuilder_->getBasicBlock(f), |
| c, currentBB_); |
| } |
| |
| void do_goto(unsigned target) { |
| new BranchInst(bbBuilder_->getBasicBlock(target), currentBB_); |
| } |
| |
| void do_ireturn() { do_return_common(Type::IntTy); } |
| void do_lreturn() { do_return_common(Type::LongTy); } |
| void do_freturn() { do_return_common(Type::FloatTy); } |
| void do_dreturn() { do_return_common(Type::DoubleTy); } |
| void do_areturn() { do_return_common(resolver_->getObjectBaseType()); } |
| |
| void do_return_common(const Type* type) { |
| Value* r = pop(type); |
| const Type* retTy = currentBB_->getParent()->getReturnType(); |
| if (retTy != r->getType()) |
| r = new CastInst(r, retTy, TMP, currentBB_); |
| new ReturnInst(r, currentBB_); |
| } |
| |
| void do_return() { |
| new ReturnInst(NULL, currentBB_); |
| } |
| |
| void do_jsr(unsigned target, unsigned retAddress) { |
| // FIXME: this is currently a noop. |
| push(llvm::Constant::getNullValue(Type::IntTy)); |
| } |
| |
| void do_ret(unsigned index) { |
| // FIXME: this is currently a noop. |
| } |
| |
| void do_tableswitch(unsigned defTarget, const SwitchCases& sw) { |
| do_switch_common(defTarget, sw); |
| } |
| |
| void do_lookupswitch(unsigned defTarget, const SwitchCases& sw) { |
| do_switch_common(defTarget, sw); |
| } |
| |
| void do_switch_common(unsigned defTarget, const SwitchCases& sw) { |
| Value* v = pop(Type::IntTy); |
| SwitchInst* in = |
| new SwitchInst(v, bbBuilder_->getBasicBlock(defTarget), sw.size(), |
| currentBB_); |
| for (unsigned i = 0, e = sw.size(); i != e; ++i) |
| in->addCase(ConstantSInt::get(Type::IntTy, sw[i].first), |
| bbBuilder_->getBasicBlock(sw[i].second)); |
| } |
| |
| void do_getstatic(unsigned index) { |
| const VMField* field = class_->getField(index); |
| emitClassInitializers(field->getParent()); |
| |
| Value* v = new LoadInst(field->getGlobal(), TMP, currentBB_); |
| push(v); |
| } |
| |
| void do_putstatic(unsigned index) { |
| const VMField* field = class_->getField(index); |
| emitClassInitializers(field->getParent()); |
| |
| Value* v = pop(field->getClass()->getType()); |
| new StoreInst(v, field->getGlobal(), currentBB_); |
| } |
| |
| void do_getfield(unsigned index) { |
| const VMField* field = class_->getField(index); |
| |
| Value* p = pop(field->getParent()->getType()); |
| std::vector<Value*> indices(2); |
| indices[0] = ConstantUInt::get(Type::UIntTy, 0); |
| indices[1] = ConstantUInt::get(Type::UIntTy, field->getMemberIndex()); |
| Value* fieldPtr = |
| new GetElementPtrInst(p, indices, field->getName()+'*', currentBB_); |
| Value* v = new LoadInst(fieldPtr, field->getName(), currentBB_); |
| push(v); |
| } |
| |
| void do_putfield(unsigned index) { |
| const VMField* field = class_->getField(index); |
| |
| Value* v = pop(field->getClass()->getType()); |
| Value* p = pop(field->getParent()->getType()); |
| std::vector<Value*> indices(2); |
| indices[0] = ConstantUInt::get(Type::UIntTy, 0); |
| indices[1] = ConstantUInt::get(Type::UIntTy, field->getMemberIndex()); |
| Value* fieldPtr = |
| new GetElementPtrInst(p, indices, field->getName()+'*', currentBB_); |
| new StoreInst(v, fieldPtr, currentBB_); |
| } |
| |
| void makeCall(Value* fun, const std::vector<Value*> params) { |
| const PointerType* funPtrTy = cast<PointerType>(fun->getType()); |
| const FunctionType* funTy = |
| cast<FunctionType>(funPtrTy->getElementType()); |
| |
| if (funTy->getReturnType() == Type::VoidTy) |
| new CallInst(fun, params, "", currentBB_); |
| else { |
| Value* r = new CallInst(fun, params, TMP, currentBB_); |
| push(r); |
| } |
| } |
| |
| std::vector<Value*> getParams(const FunctionType* funTy) { |
| unsigned numParams = funTy->getNumParams(); |
| std::vector<Value*> params(numParams); |
| while (numParams--) |
| params[numParams] = pop(funTy->getParamType(numParams)); |
| |
| return params; |
| } |
| |
| void do_invokevirtual(unsigned index) { |
| const VMMethod* method = class_->getMethod(index); |
| const VMClass* clazz = method->getParent(); |
| |
| Function* function = method->getFunction(); |
| std::vector<Value*> params(getParams(function->getFunctionType())); |
| |
| Value* objRef = params.front(); |
| objRef = new CastInst(objRef, clazz->getType(), "this", currentBB_); |
| Value* objBase = |
| new CastInst(objRef, resolver_->getObjectBaseType(), TMP, currentBB_); |
| Value* classRecord = |
| new CallInst(getClassRecord_, objBase, TMP, currentBB_); |
| classRecord = new CastInst(classRecord, |
| clazz->getClassRecord()->getType(), |
| clazz->getName() + ".classRecord", currentBB_); |
| std::vector<Value*> indices(1, ConstantUInt::get(Type::UIntTy, 0)); |
| assert(method->getMethodIndex() != -1 && |
| "Method index not found for dynamically bound method!"); |
| indices.push_back( |
| ConstantUInt::get(Type::UIntTy, method->getMethodIndex()+1)); |
| Value* funPtr = |
| new GetElementPtrInst(classRecord, indices, TMP, currentBB_); |
| Value* fun = new LoadInst(funPtr, function->getName(), currentBB_); |
| |
| makeCall(fun, params); |
| } |
| |
| void do_invokespecial(unsigned index) { |
| const VMMethod* method = class_->getMethod(index); |
| Function* function = method->getFunction(); |
| makeCall(function, getParams(function->getFunctionType())); |
| } |
| |
| void do_invokestatic(unsigned index) { |
| const VMMethod* method = class_->getMethod(index); |
| emitClassInitializers(method->getParent()); |
| Function* function = method->getFunction(); |
| makeCall(function, getParams(function->getFunctionType())); |
| } |
| |
| void do_invokeinterface(unsigned index) { |
| const VMMethod* method = class_->getMethod(index); |
| const VMClass* clazz = method->getParent(); |
| assert(clazz->isInterface() && "Class must be an interface!"); |
| |
| Function* function = method->getFunction(); |
| std::vector<Value*> params(getParams(function->getFunctionType())); |
| |
| Value* objRef = params.front(); |
| objRef = new CastInst(objRef, clazz->getType(), "this", currentBB_); |
| Value* objBase = |
| new CastInst(objRef, resolver_->getObjectBaseType(), TMP, currentBB_); |
| Value* classRecord = |
| new CallInst(getClassRecord_, objBase, TMP, currentBB_); |
| classRecord = new CastInst(classRecord, |
| resolver_->getClassRecordPtrType(), |
| TMP, currentBB_); |
| // get the interfaces array of class records |
| std::vector<Value*> indices(2, ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 4)); |
| Value* interfaceClassRecords = |
| new GetElementPtrInst(classRecord, indices, TMP, currentBB_); |
| interfaceClassRecords = |
| new LoadInst(interfaceClassRecords, TMP, currentBB_); |
| // Get the actual interface class record. |
| indices.clear(); |
| indices.push_back( |
| ConstantUInt::get(Type::UIntTy, clazz->getInterfaceIndex())); |
| Value* interfaceClassRecord = |
| new GetElementPtrInst(interfaceClassRecords, indices, TMP, currentBB_); |
| interfaceClassRecord = |
| new LoadInst(interfaceClassRecord, |
| clazz->getName() + ".classRecord", currentBB_); |
| interfaceClassRecord = |
| new CastInst(interfaceClassRecord, |
| clazz->getClassRecord()->getType(), TMP, currentBB_); |
| // Get the function pointer. |
| assert(method->getMethodIndex() != -1 && |
| "Method index not found for dynamically bound method!"); |
| indices.resize(2); |
| indices[0] = ConstantUInt::get(Type::UIntTy, 0); |
| indices[1] = ConstantUInt::get(Type::UIntTy, method->getMethodIndex()+1); |
| Value* funPtr = |
| new GetElementPtrInst(interfaceClassRecord, indices, TMP, currentBB_); |
| Value* fun = new LoadInst(funPtr, function->getName(), currentBB_); |
| |
| makeCall(fun, params); |
| } |
| |
| template<typename InsertionPointTy> |
| Value* allocateObject(const VMClass& clazz, InsertionPointTy* ip) { |
| static std::vector<Value*> params(4); |
| |
| Value* objRef = new MallocInst(clazz.getLayoutType(), NULL, TMP, ip); |
| params[0] = |
| new CastInst(objRef, PointerType::get(Type::SByteTy), TMP, ip); // dest |
| params[1] = ConstantUInt::get(Type::UByteTy, 0); // value |
| params[2] = ConstantExpr::getSizeOf(clazz.getLayoutType()); // size |
| params[3] = ConstantUInt::get(Type::UIntTy, 0); // alignment |
| new CallInst(memset_, params, "", ip); |
| |
| // Install the class record. |
| Value* objBase = |
| new CastInst(objRef, resolver_->getObjectBaseType(), TMP, ip); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| Value* classRecord = |
| new CastInst(clazz.getClassRecord(), classRecordPtrType, TMP, ip); |
| new CallInst(setClassRecord_, objBase, classRecord, "", ip); |
| |
| return objRef; |
| } |
| |
| void do_new(unsigned index) { |
| const VMClass* clazz = class_->getClass(index); |
| emitClassInitializers(clazz); |
| push(allocateObject(*clazz, currentBB_)); |
| } |
| |
| template <typename InsertionPointTy> |
| Value* getArrayLengthPtr(Value* arrayRef, InsertionPointTy* ip) const { |
| std::vector<Value*> indices; |
| indices.reserve(2); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 1)); |
| |
| return new GetElementPtrInst(arrayRef, indices, TMP, ip); |
| } |
| |
| template <typename InsertionPointTy> |
| Value* getArrayObjectBasePtr(Value* arrayRef, InsertionPointTy* ip) const { |
| std::vector<Value*> indices; |
| indices.reserve(2); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| indices.push_back(ConstantUInt::get(Type::UIntTy, 0)); |
| |
| return new GetElementPtrInst(arrayRef, indices, TMP, ip); |
| } |
| |
| template<typename InsertionPointTy> |
| Value* allocateArray(const VMClass* clazz, |
| Value* count, |
| InsertionPointTy* ip) { |
| static std::vector<Value*> params(4); |
| |
| assert(clazz->isArray() && "Not an array class!"); |
| const VMClass* componentClass = clazz->getComponentClass(); |
| const Type* elementTy = componentClass->getType(); |
| |
| // The size of the element. |
| llvm::Constant* elementSize = |
| ConstantExpr::getCast(ConstantExpr::getSizeOf(elementTy), Type::UIntTy); |
| |
| // The size of the array part of the struct. |
| Value* size = BinaryOperator::create( |
| Instruction::Mul, count, elementSize, TMP, ip); |
| // The size of the rest of the array object. |
| llvm::Constant* arrayObjectSize = |
| ConstantExpr::getCast(ConstantExpr::getSizeOf(clazz->getLayoutType()), |
| Type::UIntTy); |
| |
| // Add the array part plus the object part together. |
| size = BinaryOperator::create( |
| Instruction::Add, size, arrayObjectSize, TMP, ip); |
| // Allocate memory for the object. |
| Value* objRef = new MallocInst(Type::SByteTy, size, TMP, ip); |
| params[0] = objRef; // dest |
| params[1] = ConstantUInt::get(Type::UByteTy, 0); // value |
| params[2] = new CastInst(size, Type::ULongTy, TMP, ip); // size |
| params[3] = ConstantUInt::get(Type::UIntTy, 0); // alignment |
| new CallInst(memset_, params, "", ip); |
| |
| // Cast back to array type. |
| objRef = new CastInst(objRef, clazz->getType(), TMP, ip); |
| |
| // Store the size. |
| Value* lengthPtr = getArrayLengthPtr(objRef, ip); |
| new StoreInst(count, lengthPtr, ip); |
| |
| // Install the class record. |
| Value* objBase = new CastInst(objRef, resolver_->getObjectBaseType(), TMP, ip); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| Value* classRecord = |
| new CastInst(clazz->getClassRecord(), classRecordPtrType, TMP, ip); |
| new CallInst(setClassRecord_, objBase, classRecord, "", ip); |
| |
| return objRef; |
| } |
| |
| void do_newarray(JType type) { |
| Value* count = pop(Type::UIntTy); |
| |
| const VMClass* clazz = resolver_->getClass(type); |
| const VMClass* arrayClass = resolver_->getArrayClass(clazz); |
| emitClassInitializers(arrayClass); |
| |
| push(allocateArray(arrayClass, count, currentBB_)); |
| } |
| |
| void do_anewarray(unsigned index) { |
| Value* count = pop(Type::UIntTy); |
| |
| const VMClass* clazz = class_->getClass(index); |
| const VMClass* arrayClass = resolver_->getArrayClass(clazz); |
| emitClassInitializers(arrayClass); |
| |
| push(allocateArray(arrayClass, count, currentBB_)); |
| } |
| |
| void do_arraylength() { |
| const VMClass* clazz = resolver_->getClass("[Ljava/lang/Object;"); |
| Value* arrayRef = pop(clazz->getType()); |
| Value* lengthPtr = getArrayLengthPtr(arrayRef, currentBB_); |
| Value* length = new LoadInst(lengthPtr, TMP, currentBB_); |
| push(length); |
| } |
| |
| void do_athrow() { |
| Value* objRef = pop(resolver_->getObjectBaseType()); |
| new CallInst(throw_, objRef, "", currentBB_); |
| new UnreachableInst(currentBB_); |
| } |
| |
| void do_checkcast(unsigned index) { |
| const VMClass* clazz = class_->getClass(index); |
| |
| Value* objRef = pop(resolver_->getObjectBaseType()); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| Value* classRecord = new CastInst(clazz->getClassRecord(), |
| classRecordPtrType, TMP, currentBB_); |
| Value* r = |
| new CallInst(isInstanceOf_, objRef, classRecord, TMP, currentBB_); |
| |
| Value* b = new SetCondInst(Instruction::SetEQ, |
| r, ConstantSInt::get(Type::IntTy, 1), |
| TMP, currentBB_); |
| // FIXME: if b is false we must throw a ClassCast exception |
| push(objRef); |
| } |
| |
| void do_instanceof(unsigned index) { |
| const VMClass* clazz = class_->getClass(index); |
| |
| Value* objRef = pop(resolver_->getObjectBaseType()); |
| const Type* classRecordPtrType = resolver_->getClassRecordPtrType(); |
| Value* classRecord = new CastInst(clazz->getClassRecord(), |
| classRecordPtrType, TMP, currentBB_); |
| Value* r = |
| new CallInst(isInstanceOf_, objRef, classRecord, TMP, currentBB_); |
| push(r); |
| } |
| |
| void do_monitorenter() { |
| // FIXME: This is currently a noop. |
| pop(resolver_->getObjectBaseType()); |
| } |
| |
| void do_monitorexit() { |
| // FIXME: This is currently a noop. |
| pop(resolver_->getObjectBaseType()); |
| } |
| |
| void do_multianewarray(unsigned index, unsigned dims) { |
| assert(0 && "not implemented"); |
| } |
| }; |
| |
| } } } // namespace llvm::Java:: |
| |
| std::auto_ptr<Module> llvm::Java::compile(const std::string& className) |
| { |
| DEBUG(std::cerr << "Compiling class: " << className << '\n'); |
| |
| std::auto_ptr<Module> m(new Module(className)); |
| // Require the Java runtime. |
| m->addLibrary("jrt"); |
| |
| Compiler c(m.get()); |
| const VMMethod* main = |
| c.compileMethod(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->getFunction()->getFunctionType(); |
| new CallInst(main->getFunction(), |
| // FIXME: Forward correct params from llvm_java_main |
| llvm::Constant::getNullValue(mainTy->getParamType(0)), |
| "", |
| bb); |
| new ReturnInst(NULL, bb); |
| |
| return m; |
| } |