| //===------------ CLIJit.cpp - CLI just in time compiler ------------------===// |
| // |
| // N3 |
| // |
| // This file is distributed under the University Of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG 0 |
| #define N3_COMPILE 0 |
| #define N3_EXECUTE 0 |
| |
| #include "debug.h" |
| #include "types.h" |
| |
| #include <llvm/Type.h> |
| #include <llvm/Support/CFG.h> |
| #include <llvm/Module.h> |
| #include <llvm/Constants.h> |
| #include <llvm/Type.h> |
| #include <llvm/DerivedTypes.h> |
| #include <llvm/Function.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/ModuleProvider.h> |
| #include <llvm/ExecutionEngine/JIT.h> |
| #include <llvm/ExecutionEngine/GenericValue.h> |
| #include <llvm/PassManager.h> |
| #include <llvm/Analysis/Verifier.h> |
| #include <llvm/Transforms/Scalar.h> |
| #include <llvm/Target/TargetData.h> |
| #include <llvm/Assembly/PrintModulePass.h> |
| #include <llvm/Target/TargetOptions.h> |
| #include <llvm/CodeGen/MachineCodeEmitter.h> |
| #include <llvm/CodeGen/MachineBasicBlock.h> |
| #include "llvm/Constants.h" |
| #include "llvm/DerivedTypes.h" |
| #include "llvm/Module.h" |
| #include "llvm/ModuleProvider.h" |
| #include "llvm/PassManager.h" |
| #include "llvm/ValueSymbolTable.h" |
| #include "llvm/Analysis/LoadValueNumbering.h" |
| #include "llvm/Analysis/LoopPass.h" |
| #include "llvm/Analysis/Verifier.h" |
| #include "llvm/Assembly/Writer.h" |
| #include "llvm/Assembly/PrintModulePass.h" |
| #include "llvm/Bitcode/ReaderWriter.h" |
| #include "llvm/CodeGen/RegAllocRegistry.h" |
| #include "llvm/CodeGen/SchedulerRegistry.h" |
| #include "llvm/CodeGen/ScheduleDAG.h" |
| #include "llvm/Target/SubtargetFeature.h" |
| #include "llvm/Target/TargetData.h" |
| #include "llvm/Target/TargetLowering.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Target/TargetMachineRegistry.h" |
| #include "llvm/Transforms/Scalar.h" |
| #include "llvm/Transforms/IPO.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Support/Streams.h" |
| #include "llvm/Support/ManagedStatic.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/MutexGuard.h" |
| |
| #include <llvm/Transforms/IPO.h> |
| |
| #include "mvm/JIT.h" |
| #include "mvm/Method.h" |
| #include "mvm/VMLet.h" |
| |
| #include "Assembly.h" |
| #include "CLIAccess.h" |
| #include "CLIJit.h" |
| #include "CLIString.h" |
| #include "NativeUtil.h" |
| #include "N3.h" |
| #include "N3ModuleProvider.h" |
| #include "Reader.h" |
| #include "VirtualMachine.h" |
| #include "VMArray.h" |
| #include "VMCache.h" |
| #include "VMClass.h" |
| #include "VMThread.h" |
| |
| using namespace llvm; |
| using namespace n3; |
| |
| #include <iostream> |
| |
| void Exception::print(mvm::PrintBuffer* buf) const { |
| buf->write("Exception<>"); |
| } |
| |
| // for structs |
| static void traceStruct(VMCommonClass* cl, BasicBlock* block, Value* arg) { |
| for (std::vector<VMField*>::iterator i = cl->virtualFields.begin(), |
| e = cl->virtualFields.end(); i!= e; ++i) { |
| VMField* field = *i; |
| if (field->signature->super == N3::pValue) { |
| if (!field->signature->isPrimitive) { |
| Value* ptr = new GetElementPtrInst(arg, field->offset, "", |
| block); |
| traceStruct(field->signature, block, ptr); |
| } else if (field->signature == N3::pIntPtr || field->signature == N3::pUIntPtr) { |
| Value* valCast = new BitCastInst(arg, VMObject::llvmType, "", block); |
| new CallInst(CLIJit::markAndTraceLLVM, valCast, "", block); |
| } |
| } else if (field->signature->super != N3::pEnum) { |
| Value* valCast = new BitCastInst(arg, VMObject::llvmType, "", block); |
| new CallInst(CLIJit::markAndTraceLLVM, valCast, "", block); |
| } |
| } |
| } |
| |
| |
| // Always classes |
| static void traceClass(VMCommonClass* cl, BasicBlock* block, Value* arg, |
| std::vector<VMField*>& fields, bool boxed = false) { |
| |
| Constant* zero = mvm::jit::constantZero; |
| for (std::vector<VMField*>::iterator i = fields.begin(), |
| e = fields.end(); i!= e; ++i) { |
| VMField* field = *i; |
| if (field->signature->super == N3::pValue) { |
| std::vector<Value*> args; //size = 2 |
| args.push_back(zero); |
| if (boxed) { |
| mvm::jit::protectConstants(); |
| args.push_back(ConstantInt::get(field->offset->getValue() + 1)); |
| mvm::jit::unprotectConstants(); |
| } else { |
| args.push_back(field->offset); |
| } |
| Value* ptr = new GetElementPtrInst(arg, args.begin(), args.end(), "", |
| block); |
| traceStruct(field->signature, block, ptr); |
| } else if (field->signature->super != N3::pEnum) { |
| std::vector<Value*> args; //size = 2 |
| args.push_back(zero); |
| if (boxed) { |
| mvm::jit::protectConstants(); |
| args.push_back(ConstantInt::get(field->offset->getValue() + 1)); |
| mvm::jit::unprotectConstants(); |
| } else { |
| args.push_back(field->offset); |
| } |
| Value* ptr = new GetElementPtrInst(arg, args.begin(), args.end(), "", |
| block); |
| Value* val = new LoadInst(ptr, "", block); |
| Value* valCast = new BitCastInst(val, VMObject::llvmType, "", block); |
| new CallInst(CLIJit::markAndTraceLLVM, valCast, "", block); |
| } |
| } |
| } |
| |
| VirtualTable* CLIJit::makeArrayVT(VMClassArray* cl) { |
| Function* func = new Function(markAndTraceLLVMType, |
| GlobalValue::ExternalLinkage, |
| "markAndTraceObject", |
| cl->vm->module); |
| Argument* arg = func->arg_begin(); |
| |
| // Constant Definitions |
| Constant* const_int32_8 = mvm::jit::constantZero; |
| ConstantInt* const_int32_9 = mvm::jit::constantOne; |
| ConstantInt* const_int32_10 = mvm::jit::constantTwo; |
| |
| |
| // Function Definitions |
| |
| { |
| BasicBlock* label_entry = new BasicBlock("entry",func,0); |
| BasicBlock* label_bb = new BasicBlock("bb",func,0); |
| BasicBlock* label_return = new BasicBlock("return",func,0); |
| |
| Value* ptr_v = new BitCastInst(arg, cl->naturalType, "", label_entry); |
| |
| // Block entry (label_entry) |
| std::vector<Value*> ptr_tmp918_indices; |
| ptr_tmp918_indices.push_back(const_int32_8); |
| ptr_tmp918_indices.push_back(const_int32_9); |
| Instruction* ptr_tmp918 = new GetElementPtrInst(ptr_v, ptr_tmp918_indices.begin(), ptr_tmp918_indices.end(), "tmp918", label_entry); |
| LoadInst* int32_tmp1019 = new LoadInst(ptr_tmp918, "tmp1019", false, label_entry); |
| ICmpInst* int1_tmp1221 = new ICmpInst(ICmpInst::ICMP_SGT, int32_tmp1019, const_int32_8, "tmp1221", label_entry); |
| new BranchInst(label_bb, label_return, int1_tmp1221, label_entry); |
| |
| // Block bb (label_bb) |
| Argument* fwdref_12 = new Argument(IntegerType::get(32)); |
| PHINode* int32_i_015_0 = new PHINode(IntegerType::get(32), "i.015.0", label_bb); |
| int32_i_015_0->reserveOperandSpace(2); |
| int32_i_015_0->addIncoming(fwdref_12, label_bb); |
| int32_i_015_0->addIncoming(const_int32_8, label_entry); |
| |
| std::vector<Value*> ptr_tmp3_indices; |
| ptr_tmp3_indices.push_back(const_int32_8); |
| ptr_tmp3_indices.push_back(const_int32_10); |
| ptr_tmp3_indices.push_back(int32_i_015_0); |
| Instruction* ptr_tmp3 = new GetElementPtrInst(ptr_v, ptr_tmp3_indices.begin(), ptr_tmp3_indices.end(), "tmp3", label_bb); |
| if (cl->baseClass->super == N3::pValue) { |
| traceStruct(cl->baseClass, label_bb, ptr_tmp3); |
| } else if (cl->baseClass->super != N3::pEnum) { |
| LoadInst* ptr_tmp4 = new LoadInst(ptr_tmp3, "tmp4", false, label_bb); |
| Value* arg = new BitCastInst(ptr_tmp4, VMObject::llvmType, "", label_bb); |
| new CallInst(markAndTraceLLVM, arg, "", label_bb); |
| } |
| BinaryOperator* int32_tmp6 = BinaryOperator::create(Instruction::Add, int32_i_015_0, const_int32_9, "tmp6", label_bb); |
| LoadInst* int32_tmp10 = new LoadInst(ptr_tmp918, "tmp10", false, label_bb); |
| ICmpInst* int1_tmp12 = new ICmpInst(ICmpInst::ICMP_SGT, int32_tmp10, int32_tmp6, "tmp12", label_bb); |
| new BranchInst(label_bb, label_return, int1_tmp12, label_bb); |
| |
| // Block return (label_return) |
| new ReturnInst(label_return); |
| |
| // Resolve Forward References |
| fwdref_12->replaceAllUsesWith(int32_tmp6); delete fwdref_12; |
| |
| } |
| |
| VirtualTable * res = malloc(VT_SIZE); |
| memcpy(res, VMObject::VT, VT_SIZE); |
| void* tracer = mvm::jit::executionEngine->getPointerToGlobal(func); |
| ((void**)res)[VT_TRACER_OFFSET] = tracer; |
| cl->virtualTracer = func; |
| cl->codeVirtualTracer = (mvm::Code*)((intptr_t)tracer - sizeof(intptr_t)); |
| |
| return res; |
| } |
| |
| VirtualTable* CLIJit::makeVT(VMClass* cl, bool stat) { |
| const Type* type = stat ? cl->staticType : cl->virtualType; |
| std::vector<VMField*> &fields = stat ? cl->staticFields : cl->virtualFields; |
| |
| Function* func = new Function(markAndTraceLLVMType, |
| GlobalValue::ExternalLinkage, |
| "markAndTraceObject", |
| cl->vm->module); |
| |
| Argument* arg = func->arg_begin(); |
| BasicBlock* block = new BasicBlock("", func); |
| llvm::Value* realArg = new BitCastInst(arg, type, "", block); |
| |
| if (stat || cl->super == 0) { |
| new CallInst(vmObjectTracerLLVM, arg, "", block); |
| } else { |
| new CallInst(((VMClass*)cl->super)->virtualTracer, arg, "", block); |
| } |
| |
| traceClass(cl, block, realArg, fields, (cl->super == N3::pValue && !stat)); |
| new ReturnInst(block); |
| |
| VirtualTable * res = malloc(VT_SIZE); |
| memcpy(res, VMObject::VT, VT_SIZE); |
| void* tracer = mvm::jit::executionEngine->getPointerToGlobal(func); |
| ((void**)res)[VT_TRACER_OFFSET] = tracer; |
| |
| if (!stat) { |
| cl->virtualTracer = func; |
| cl->codeVirtualTracer = (mvm::Code*)((intptr_t)tracer - sizeof(intptr_t)); |
| } else { |
| cl->staticTracer = func; |
| cl->codeStaticTracer = (mvm::Code*)((intptr_t)tracer - sizeof(intptr_t)); |
| } |
| return res; |
| |
| } |
| |
| BasicBlock* CLIJit::createBasicBlock(const char* name) { |
| return new BasicBlock(name, llvmFunction); |
| } |
| |
| void CLIJit::setCurrentBlock(BasicBlock* newBlock) { |
| |
| std::vector<Value*> newStack; |
| uint32 index = 0; |
| for (BasicBlock::iterator i = newBlock->begin(), e = newBlock->end(); i != e; |
| ++i, ++index) { |
| if (!(isa<PHINode>(i))) { |
| break; |
| } else { |
| newStack.push_back(i); |
| } |
| } |
| |
| stack = newStack; |
| currentBlock = newBlock; |
| } |
| |
| extern void convertValue(Value*& val, const Type* t1, BasicBlock* currentBlock); |
| |
| static void testPHINodes(BasicBlock* dest, BasicBlock* insert, CLIJit* jit) { |
| if(dest->empty()) { |
| for (std::vector<Value*>::iterator i = jit->stack.begin(), |
| e = jit->stack.end(); i!= e; ++i) { |
| Value* cur = (*i); |
| PHINode* node = new PHINode(cur->getType(), "", dest); |
| node->addIncoming(cur, insert); |
| } |
| } else { |
| std::vector<Value*>::iterator stackit = jit->stack.begin(); |
| for (BasicBlock::iterator i = dest->begin(), e = dest->end(); i != e; |
| ++i) { |
| if (!(isa<PHINode>(i))) { |
| break; |
| } else { |
| Instruction* ins = i; |
| Value* cur = (*stackit); |
| convertValue(cur, ins->getType(), insert); |
| ((PHINode*)ins)->addIncoming(cur, insert); |
| ++stackit; |
| } |
| } |
| } |
| } |
| |
| void CLIJit::branch(llvm::BasicBlock* dest, llvm::BasicBlock* insert) { |
| testPHINodes(dest, insert, this); |
| new BranchInst(dest, insert); |
| } |
| |
| void CLIJit::branch(llvm::Value* test, llvm::BasicBlock* ifTrue, |
| llvm::BasicBlock* ifFalse, llvm::BasicBlock* insert) { |
| testPHINodes(ifTrue, insert, this); |
| testPHINodes(ifFalse, insert, this); |
| new BranchInst(ifTrue, ifFalse, test, insert); |
| } |
| |
| Value* CLIJit::pop() { |
| assert(stack.size()); |
| Value* ret = top(); |
| stack.pop_back(); |
| return ret; |
| } |
| |
| Value* CLIJit::top() { |
| return stack.back(); |
| } |
| |
| void CLIJit::push(Value* val) { |
| assert(val); |
| stack.push_back(val); |
| } |
| |
| Value* CLIJit::changeType(Value* val, const Type* type) { |
| const Type* valType = val->getType(); |
| if (type->isInteger()) { |
| if (valType == PointerType::getUnqual(type)) { |
| // in cast it's a struct |
| val = new LoadInst(val, "", currentBlock); |
| } |
| else if (type->getPrimitiveSizeInBits() < valType->getPrimitiveSizeInBits()) { |
| val = new TruncInst(val, type, "", currentBlock); |
| } else { |
| val = new SExtInst(val, type, "", currentBlock); |
| } |
| } else if (type == Type::FloatTy) { |
| val = new FPTruncInst(val, type, "", currentBlock); |
| } else if (type == Type::DoubleTy) { |
| val = new FPExtInst(val, type, "", currentBlock); |
| } else { |
| val = new BitCastInst(val, type, "", currentBlock); |
| } |
| return val; |
| } |
| |
| void CLIJit::makeArgs(const FunctionType* type, std::vector<Value*>& Args, |
| bool structReturn) { |
| uint32 size = type->getNumParams(); |
| Value* args[size]; |
| sint32 index = size - 1; |
| FunctionType::param_iterator e = type->param_end(); |
| e--; |
| if (structReturn) { e--; index--; size--; } |
| for (; index >= 0; --e, --index) { |
| const Type* argType = (*e); |
| Value* val = pop(); |
| if (val->getType() != argType) { |
| val = changeType(val, argType); |
| } |
| args[index] = val; |
| } |
| |
| for (uint32 i = 0; i < size; ++i) { |
| Args.push_back(args[i]); |
| } |
| } |
| |
| Instruction* CLIJit::lowerMathOps(VMMethod* meth, |
| std::vector<Value*>& args) { |
| |
| if (meth->name == N3::sqrt) { |
| return new CallInst(mvm::jit::func_llvm_sqrt_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::sin) { |
| return new CallInst(mvm::jit::func_llvm_sin_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::cos) { |
| return new CallInst(mvm::jit::func_llvm_cos_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::exp) { |
| return new CallInst(mvm::jit::func_llvm_exp_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::log) { |
| return new CallInst(mvm::jit::func_llvm_log_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::floor) { |
| return new CallInst(mvm::jit::func_llvm_floor_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::log10) { |
| return new CallInst(mvm::jit::func_llvm_log10_f64, args[0], "tmp1", currentBlock); |
| } else if (meth->name == N3::pow) { |
| Instruction* val = new CallInst(mvm::jit::func_llvm_pow_f64, args.begin(), args.end(), "tmp1", currentBlock); |
| return val; |
| } |
| return 0; |
| |
| } |
| |
| Instruction* CLIJit::invokeInline(VMMethod* meth, |
| std::vector<Value*>& args) { |
| |
| CLIJit* jit = gc_new(CLIJit)(); |
| jit->compilingClass = meth->classDef; |
| jit->compilingMethod = meth; |
| jit->unifiedUnreachable = unifiedUnreachable; |
| jit->inlineMethods = inlineMethods; |
| jit->inlineMethods[meth] = true; |
| Instruction* ret = jit->inlineCompile(llvmFunction, currentBlock, |
| currentExceptionBlock, args); |
| inlineMethods[meth] = false; |
| return ret; |
| } |
| |
| |
| void CLIJit::invoke(uint32 value) { |
| VMMethod* meth = compilingClass->assembly->getMethodFromToken(value); |
| |
| if (meth->classDef->isArray) { |
| uint8 func = 0; |
| if (meth->name == VMThread::get()->vm->asciizConstructUTF8("Set")) { |
| func = 0; |
| } else if (meth->name == VMThread::get()->vm->asciizConstructUTF8("Get")) { |
| func = 1; |
| } else if (meth->name == VMThread::get()->vm->asciizConstructUTF8("Address")) { |
| func = 2; |
| } else { |
| VMThread::get()->vm->error("implement me %s", meth->name->printString()); |
| } |
| |
| VMClassArray* type = (VMClassArray*)meth->classDef; |
| uint32 dims = type->dims; |
| Value* args[dims]; |
| Value* val = 0; |
| if (func == 0) { |
| val = pop(); |
| } |
| for (sint32 i = dims - 1; i >= 0 ; --i) { |
| args[i] = pop(); |
| } |
| Value* obj = pop(); |
| VMClassArray* base = type; |
| for (uint32 v = 0; v < dims; ++v) { |
| std::vector<Value*> Args; |
| Args.push_back(mvm::jit::constantZero); |
| Args.push_back(mvm::jit::constantTwo); |
| Args.push_back(args[v]); |
| obj = verifyAndComputePtr(obj, args[v], base->naturalType, true); |
| if (v != dims - 1) { |
| base = (VMClassArray*)base->baseClass; |
| obj = new LoadInst(obj, "", currentBlock); |
| } |
| } |
| |
| if (func == 0) { |
| new StoreInst(val, obj, false, currentBlock); |
| } else if (func == 1) { |
| push(new LoadInst(obj, "", currentBlock)); |
| } else { |
| push(obj); |
| } |
| return; |
| } |
| |
| std::vector<Value*> Args; |
| const llvm::FunctionType* type = meth->getSignature(); |
| makeArgs(type, Args, meth->structReturn); |
| |
| if (meth->classDef->nameSpace == N3::system && meth->classDef->name == N3::math) { |
| Value* val = lowerMathOps(meth, Args); |
| if (val) { |
| push(val); |
| return; |
| } |
| } else if (meth->classDef->nameSpace == N3::system && meth->classDef->name == N3::doubleName) { |
| if (meth->name == N3::isNan) { |
| push(new FCmpInst(FCmpInst::FCMP_UNO, Args[0], mvm::jit::constantDoubleZero, "tmp1", currentBlock)); |
| return; |
| } else if (meth->name == N3::testInfinity) { |
| BasicBlock* endBlock = createBasicBlock("end test infinity"); |
| BasicBlock* minusInfinity = createBasicBlock("- infinity"); |
| BasicBlock* noInfinity = createBasicBlock("no infinity"); |
| PHINode* node = new PHINode(Type::Int32Ty, "", endBlock); |
| node->addIncoming(mvm::jit::constantOne, currentBlock); |
| node->addIncoming(mvm::jit::constantMinusOne, minusInfinity); |
| node->addIncoming(mvm::jit::constantZero, noInfinity); |
| Value* val1 = new FCmpInst(FCmpInst::FCMP_OEQ, Args[0], mvm::jit::constantDoubleInfinity, "tmp1", currentBlock); |
| new BranchInst(endBlock, minusInfinity, val1, currentBlock); |
| Value* val2 = new FCmpInst(FCmpInst::FCMP_OEQ, Args[0], mvm::jit::constantDoubleMinusInfinity, "tmp1", minusInfinity); |
| new BranchInst(endBlock, noInfinity, val2, minusInfinity); |
| new BranchInst(endBlock, noInfinity); |
| currentBlock = endBlock; |
| push(node); |
| return; |
| } |
| } else if (meth->classDef->nameSpace == N3::system && meth->classDef->name == N3::floatName) { |
| if (meth->name == N3::isNan) { |
| push(new FCmpInst(FCmpInst::FCMP_UNO, Args[0], mvm::jit::constantFloatZero, "tmp1", currentBlock)); |
| return; |
| } else if (meth->name == N3::testInfinity) { |
| BasicBlock* endBlock = createBasicBlock("end test infinity"); |
| BasicBlock* minusInfinity = createBasicBlock("- infinity"); |
| BasicBlock* noInfinity = createBasicBlock("no infinity"); |
| PHINode* node = new PHINode(Type::Int32Ty, "", endBlock); |
| node->addIncoming(mvm::jit::constantOne, currentBlock); |
| node->addIncoming(mvm::jit::constantMinusOne, minusInfinity); |
| node->addIncoming(mvm::jit::constantZero, noInfinity); |
| Value* val1 = new FCmpInst(FCmpInst::FCMP_OEQ, Args[0], mvm::jit::constantFloatInfinity, "tmp1", currentBlock); |
| new BranchInst(endBlock, minusInfinity, val1, currentBlock); |
| Value* val2 = new FCmpInst(FCmpInst::FCMP_OEQ, Args[0], mvm::jit::constantFloatMinusInfinity, "tmp1", minusInfinity); |
| new BranchInst(endBlock, noInfinity, val2, minusInfinity); |
| new BranchInst(endBlock, noInfinity); |
| currentBlock = endBlock; |
| push(node); |
| return; |
| } |
| } |
| |
| Value* res = 0; |
| if (meth && meth->canBeInlined && meth != compilingMethod && |
| inlineMethods[meth] == 0) { |
| res = invokeInline(meth, Args); |
| } else { |
| Function* func = meth->compiledPtr(); |
| |
| res = invoke(func, Args, "", currentBlock, meth->structReturn); |
| } |
| if (meth->parameters[0] != N3::pVoid) { |
| push(res); |
| } |
| } |
| |
| void CLIJit::invokeNew(uint32 value) { |
| Assembly* ass = compilingClass->assembly; |
| VMMethod* meth = ass->getMethodFromToken(value); |
| VMClass* type = meth->classDef; |
| const FunctionType* funcType = meth->getSignature(); |
| |
| Value* obj = 0; |
| if (type->isPointer) { |
| VMThread::get()->vm->error("implement me %s", type->printString()); |
| } else if (type->isArray) { |
| VMClassArray* arrayType = (VMClassArray*)type; |
| Value* valCl = new LoadInst(arrayType->llvmVar(), "", currentBlock); |
| Value* args[arrayType->dims + 1]; |
| args[0] = valCl; |
| |
| for (int cur = arrayType->dims; cur > 0; --cur) |
| args[cur] = pop(); |
| |
| std::vector<Value*> Args; |
| for (uint32 v = 0; v < arrayType->dims + 1; ++v) { |
| Args.push_back(args[v]); |
| } |
| push(invoke(arrayMultiConsLLVM, Args, "", currentBlock, false)); |
| return; |
| |
| } else if (type->super == N3::pValue || type->super == N3::pEnum) { |
| obj = new AllocaInst(type->naturalType, "", currentBlock); |
| uint64 size = mvm::jit::getTypeSize(type->naturalType); |
| |
| std::vector<Value*> params; |
| params.push_back(new BitCastInst(obj, mvm::jit::ptrType, "", currentBlock)); |
| params.push_back(mvm::jit::constantInt8Zero); |
| mvm::jit::protectConstants(); |
| params.push_back(ConstantInt::get(Type::Int32Ty, size)); |
| mvm::jit::unprotectConstants(); |
| params.push_back(mvm::jit::constantZero); |
| new CallInst(mvm::jit::llvm_memset_i32, params.begin(), params.end(), "", currentBlock); |
| } else { |
| Value* var = new LoadInst(type->llvmVar(), "", currentBlock); |
| Value* val = new CallInst(objConsLLVM, var, "", currentBlock); |
| obj = new BitCastInst(val, type->naturalType, "", currentBlock); |
| } |
| |
| std::vector<Value*>::iterator i = stack.end(); |
| uint32 nbParams = funcType->getNumParams(); |
| while (--nbParams) --i; |
| stack.insert(i, obj); |
| |
| std::vector<Value*> Args; |
| makeArgs(funcType, Args, meth->structReturn); |
| if (meth && meth->canBeInlined && meth != compilingMethod && |
| inlineMethods[meth] == 0) { |
| invokeInline(meth, Args); |
| } else { |
| Function* func = meth->compiledPtr(); |
| |
| invoke(func, Args, "", currentBlock, meth->structReturn); |
| } |
| |
| if ((type->super == N3::pValue || type->super == N3::pEnum) && type->virtualFields.size() == 1) { |
| push(new LoadInst(obj, "", currentBlock)); |
| } else { |
| push(obj); |
| } |
| } |
| |
| llvm::Value* CLIJit::getVirtualField(uint32 value) { |
| VMField* field = compilingClass->assembly->getFieldFromToken(value, false); |
| Value* obj = pop(); |
| if ((field->classDef->super == N3::pValue || |
| field->classDef->super == N3::pEnum) && |
| field->classDef->virtualFields.size() == 1){ |
| // struct! |
| return obj; |
| } else { |
| if (field->classDef->super != N3::pValue && field->classDef->super != N3::pEnum) { |
| obj = new BitCastInst(obj, field->classDef->naturalType, "", currentBlock); |
| } |
| std::vector<Value*> args; |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(field->offset); |
| Value* ptr = new GetElementPtrInst(obj, args.begin(), args.end(), "", |
| currentBlock); |
| return ptr; |
| } |
| } |
| |
| llvm::Value* CLIJit::getStaticField(uint32 value) { |
| VMField* field = compilingClass->assembly->getFieldFromToken(value, true); |
| VMCommonClass* cl = field->classDef; |
| cl->resolveType(true, false); |
| Value* arg = new LoadInst(cl->llvmVar(), "", currentBlock); |
| Value* call = invoke(initialiseClassLLVM, arg, "", currentBlock, false); |
| Value* staticCl = new BitCastInst(call, cl->staticType, "", currentBlock); |
| |
| std::vector<Value*> args; |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(field->offset); |
| Value* ptr = new GetElementPtrInst(staticCl, args.begin(), args.end(), "", |
| currentBlock); |
| |
| return ptr; |
| |
| } |
| |
| void CLIJit::setVirtualField(uint32 value) { |
| VMField* field = compilingClass->assembly->getFieldFromToken(value, false); |
| Value* val = pop(); |
| Value* obj = pop(); |
| const Type* valType = val->getType(); |
| |
| Value* ptr = 0; |
| const Type* type = obj->getType(); |
| if ((field->classDef->super == N3::pValue || |
| field->classDef->super == N3::pEnum) && |
| field->classDef->virtualFields.size() == 1){ |
| // struct! |
| ptr = obj; |
| } else { |
| if (field->classDef->super != N3::pValue && field->classDef->super != N3::pEnum) { |
| obj = new BitCastInst(obj, field->classDef->naturalType, "", currentBlock); |
| } |
| std::vector<Value*> args; |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(field->offset); |
| ptr = new GetElementPtrInst(obj, args.begin(), args.end(), "", |
| currentBlock); |
| } |
| |
| type = field->signature->naturalType; |
| if (val == constantVMObjectNull) { |
| mvm::jit::protectConstants(); |
| val = Constant::getNullValue(type); |
| mvm::jit::unprotectConstants(); |
| } else if (type != valType) { |
| val = changeType(val, type); |
| } |
| |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void CLIJit::setStaticField(uint32 value) { |
| VMField* field = compilingClass->assembly->getFieldFromToken(value, true); |
| |
| VMCommonClass* cl = field->classDef; |
| Value* arg = new LoadInst(cl->llvmVar(), "", currentBlock); |
| Value* call = invoke(initialiseClassLLVM, arg, "", currentBlock, false); |
| Value* staticCl = new BitCastInst(call, cl->staticType, "", currentBlock); |
| |
| std::vector<Value*> args; |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(field->offset); |
| Value* ptr = new GetElementPtrInst(staticCl, args.begin(), args.end(), "", |
| currentBlock); |
| Value* val = pop(); |
| const Type* type = field->signature->naturalType; |
| const Type* valType = val->getType(); |
| if (val == constantVMObjectNull) { |
| mvm::jit::protectConstants(); |
| val = Constant::getNullValue(type); |
| mvm::jit::unprotectConstants(); |
| } else if (type != valType) { |
| val = changeType(val, type); |
| } |
| new StoreInst(val, ptr, false, currentBlock); |
| } |
| |
| void CLIJit::JITVerifyNull(Value* obj) { |
| CLIJit* jit = this; |
| mvm::jit::protectConstants(); |
| Constant* zero = Constant::getNullValue(obj->getType()); |
| mvm::jit::unprotectConstants(); |
| Value* test = new ICmpInst(ICmpInst::ICMP_EQ, obj, zero, "", |
| jit->currentBlock); |
| |
| BasicBlock* exit = jit->createBasicBlock("verifyNullExit"); |
| BasicBlock* cont = jit->createBasicBlock("verifyNullCont"); |
| |
| new BranchInst(exit, cont, test, jit->currentBlock); |
| |
| std::vector<Value*> args; |
| if (currentExceptionBlock != endExceptionBlock) { |
| new InvokeInst(CLIJit::nullPointerExceptionLLVM, unifiedUnreachable, |
| currentExceptionBlock, args.begin(), |
| args.end(), "", exit); |
| } else { |
| new CallInst(CLIJit::nullPointerExceptionLLVM, args.begin(), |
| args.end(), "", exit); |
| new UnreachableInst(exit); |
| } |
| |
| |
| jit->currentBlock = cont; |
| } |
| |
| llvm::Value* CLIJit::verifyAndComputePtr(llvm::Value* obj, llvm::Value* index, |
| const llvm::Type* arrayType, |
| bool verif) { |
| JITVerifyNull(obj); |
| |
| if (index->getType() != Type::Int32Ty) { |
| index = changeType(index, Type::Int32Ty); |
| } |
| |
| if (true) { |
| Value* size = arraySize(obj); |
| |
| Value* cmp = new ICmpInst(ICmpInst::ICMP_SLT, index, size, "", currentBlock); |
| |
| BasicBlock* ifTrue = createBasicBlock("true verifyAndComputePtr"); |
| BasicBlock* ifFalse = createBasicBlock("false verifyAndComputePtr"); |
| |
| branch(cmp, ifTrue, ifFalse, currentBlock); |
| |
| std::vector<Value*>args; |
| args.push_back(new BitCastInst(obj, VMObject::llvmType, "", ifFalse)); |
| args.push_back(index); |
| if (currentExceptionBlock != endExceptionBlock) { |
| new InvokeInst(CLIJit::indexOutOfBoundsExceptionLLVM, unifiedUnreachable, |
| currentExceptionBlock, args.begin(), |
| args.end(), "", ifFalse); |
| } else { |
| new CallInst(CLIJit::indexOutOfBoundsExceptionLLVM, args.begin(), |
| args.end(), "", ifFalse); |
| new UnreachableInst(ifFalse); |
| } |
| |
| currentBlock = ifTrue; |
| } |
| |
| Constant* zero = mvm::jit::constantZero; |
| Value* val = new BitCastInst(obj, arrayType, "", currentBlock); |
| |
| std::vector<Value*> indexes; //[3]; |
| indexes.push_back(zero); |
| indexes.push_back(VMArray::elementsOffset()); |
| indexes.push_back(index); |
| Value* ptr = new GetElementPtrInst(val, indexes.begin(), indexes.end(), |
| "", currentBlock); |
| |
| return ptr; |
| |
| } |
| |
| ConstantInt* VMArray::sizeOffset() { |
| return mvm::jit::constantOne; |
| } |
| |
| ConstantInt* VMArray::elementsOffset() { |
| return mvm::jit::constantTwo; |
| } |
| |
| Value* CLIJit::arraySize(Value* array) { |
| if (array->getType() != VMArray::llvmType) { |
| array = new BitCastInst(array, VMArray::llvmType, "", currentBlock); |
| } |
| return new CallInst(arrayLengthLLVM, array, "", currentBlock); |
| /* |
| std::vector<Value*> args; //size= 2 |
| args.push_back(mvm::jit::constantZero); |
| args.push_back(VMArray::sizeOffset()); |
| Value* ptr = new GetElementPtrInst(array, args.begin(), args.end(), |
| "", currentBlock); |
| return new LoadInst(ptr, "", currentBlock);*/ |
| } |
| |
| Function* CLIJit::createDelegate() { |
| Function* func = llvmFunction = compilingMethod->methPtr; |
| Function::arg_iterator i = func->arg_begin()++, e = func->arg_end(); |
| Value* obj = i++; |
| Value* target = i++; |
| Value* handle = i++; |
| assert(i == e); |
| |
| BasicBlock* entry = createBasicBlock("entry"); |
| obj = new BitCastInst(obj, N3::pDelegate->virtualType, "", entry); |
| std::vector<Value*> elts; |
| elts.push_back(mvm::jit::constantZero); |
| elts.push_back(mvm::jit::constantOne); |
| Value* targetPtr = new GetElementPtrInst(obj, elts.begin(), elts.end(), "", |
| entry); |
| |
| elts.pop_back(); |
| elts.push_back(mvm::jit::constantTwo); |
| Value* handlePtr = new GetElementPtrInst(obj, elts.begin(), elts.end(), "", |
| entry); |
| new StoreInst(target, targetPtr, false, entry); |
| new StoreInst(handle, handlePtr, false, entry); |
| new ReturnInst(entry); |
| |
| return func; |
| } |
| Function* CLIJit::invokeDelegate() { |
| VMThread::get()->vm->error("implement me"); |
| return 0; |
| } |
| |
| Function* CLIJit::compileIntern() { |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "intern compile %s\n", |
| compilingMethod->printString()); |
| |
| if (compilingClass->subclassOf(N3::pDelegate)) { |
| const UTF8* name = compilingMethod->name; |
| if (name == N3::ctorName) return createDelegate(); |
| else if (name == N3::invokeName) return invokeDelegate(); |
| else VMThread::get()->vm->error("implement me"); |
| } else { |
| VMThread::get()->vm->error("implement me %s", compilingClass->printString()); |
| } |
| return 0; |
| } |
| |
| Function* CLIJit::compileNative() { |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "native compile %s\n", |
| compilingMethod->printString()); |
| |
| const FunctionType *funcType = compilingMethod->getSignature(); |
| |
| Function* func = llvmFunction = compilingMethod->methPtr; |
| currentBlock = createBasicBlock("start"); |
| // TODO |
| /*endExceptionBlock = createBasicBlock("exceptionBlock"); |
| endBlock = createBasicBlock("end"); |
| new UnwindInst(endExceptionBlock);*/ |
| |
| uint32 nargs = func->arg_size(); |
| std::vector<Value*> nativeArgs; |
| |
| uint32 index = 0; |
| for (Function::arg_iterator i = func->arg_begin(); |
| index < nargs; ++i, ++index) { |
| nativeArgs.push_back(i); |
| } |
| |
| void* natPtr = NativeUtil::nativeLookup(compilingClass, compilingMethod); |
| |
| mvm::jit::protectConstants(); |
| Value* valPtr = |
| ConstantExpr::getIntToPtr(ConstantInt::get(Type::Int64Ty, (uint64)natPtr), |
| PointerType::getUnqual(funcType)); |
| mvm::jit::unprotectConstants(); |
| |
| Value* result = new CallInst(valPtr, nativeArgs.begin(), nativeArgs.end(), "", currentBlock); |
| |
| |
| if (result->getType() != Type::VoidTy) |
| new ReturnInst(result, currentBlock); |
| else |
| new ReturnInst(currentBlock); |
| |
| |
| return llvmFunction; |
| } |
| |
| uint32 CLIJit::readExceptionTable(uint32 offset, bool fat) { |
| Assembly* ass = compilingClass->assembly; |
| ArrayUInt8* bytes = ass->bytes; |
| uint32 nbe = 0; |
| if (fat) { |
| nbe = (READ_U3(bytes, offset) - 4) / 24; |
| } else { |
| nbe = (READ_U1(bytes, offset) - 4) / 12; |
| READ_U2(bytes, offset); |
| } |
| |
| if (nbe) { |
| supplLocal = new AllocaInst(VMObject::llvmType, "exceptionVar", |
| currentBlock); |
| } |
| |
| BasicBlock* realEndExceptionBlock = endExceptionBlock; |
| // TODO synchronized |
| |
| for (uint32 i = 0; i < nbe; ++i) { |
| Exception* ex = gc_new(Exception)(); |
| uint32 flags = 0; |
| uint32 classToken = 0; |
| if (fat) { |
| flags = READ_U4(bytes, offset); |
| ex->tryOffset = READ_U4(bytes, offset); |
| ex->tryLength = READ_U4(bytes, offset); |
| ex->handlerOffset = READ_U4(bytes, offset); |
| ex->handlerLength = READ_U4(bytes, offset); |
| classToken = READ_U4(bytes, offset); |
| } else { |
| flags = READ_U2(bytes, offset); |
| ex->tryOffset = READ_U2(bytes, offset); |
| ex->tryLength = READ_U1(bytes, offset); |
| ex->handlerOffset = READ_U2(bytes, offset); |
| ex->handlerLength = READ_U1(bytes, offset); |
| classToken = READ_U4(bytes, offset); |
| } |
| |
| if (!(opcodeInfos[ex->handlerOffset].newBlock)) { |
| opcodeInfos[ex->handlerOffset].newBlock = createBasicBlock("handlerException"); |
| } |
| |
| ex->handler = opcodeInfos[ex->handlerOffset].newBlock; |
| |
| if (flags == CONSTANT_COR_ILEXCEPTION_CLAUSE_EXCEPTION) { |
| ex->test = createBasicBlock("testException"); |
| if (classToken) { |
| ex->catchClass = ass->loadType((N3*)VMThread::get()->vm, classToken, |
| true, false, false, true); |
| } else { |
| ex->catchClass = N3::pException; |
| } |
| opcodeInfos[ex->handlerOffset].reqSuppl = true; |
| exceptions.push_back(ex); |
| |
| for (uint16 i = ex->tryOffset; i < ex->tryOffset + ex->tryLength; ++i) { |
| if (opcodeInfos[i].exceptionBlock == endExceptionBlock) { |
| opcodeInfos[i].exceptionBlock = ex->test; |
| } |
| } |
| |
| } else if (flags == CONSTANT_COR_ILEXCEPTION_CLAUSE_FINALLY) { |
| ex->catchClass = 0; |
| finallyHandlers.push_back(ex); |
| } else { |
| VMThread::get()->vm->error("implement me"); |
| } |
| } |
| |
| bool first = true; |
| for (std::vector<Exception*>::iterator i = exceptions.begin(), |
| e = exceptions.end(); i!= e; ++i) { |
| |
| Exception* cur = *i; |
| Exception* next = 0; |
| if (i + 1 != e) { |
| next = *(i + 1); |
| } |
| |
| if (first) { |
| cur->realTest = createBasicBlock("realTestException"); |
| } else { |
| cur->realTest = cur->test; |
| } |
| |
| if (next && cur->tryOffset == next->tryOffset && |
| cur->tryOffset + cur->tryLength == next->tryOffset + next->tryLength) |
| first = false; |
| else |
| first = true; |
| |
| } |
| |
| for (std::vector<Exception*>::iterator i = exceptions.begin(), |
| e = exceptions.end(); i!= e; ++i) { |
| |
| Exception* cur = *i; |
| Exception* next = 0; |
| BasicBlock* bbNext = 0; |
| if (i + 1 != e) { |
| next = *(i + 1); |
| if (cur->tryOffset >= next->tryOffset && |
| cur->tryOffset + cur->tryLength <= next->tryOffset + next->tryLength) { |
| bbNext = realEndExceptionBlock; |
| } else { |
| bbNext = next->realTest; |
| } |
| } else { |
| bbNext = realEndExceptionBlock; |
| } |
| |
| if (cur->realTest != cur->test) { |
| const PointerType* PointerTy_0 = mvm::jit::ptrType; |
| std::vector<Value*> int32_eh_select_params; |
| Instruction* ptr_eh_ptr = new CallInst(mvm::jit::llvmGetException, "eh_ptr", cur->test); |
| int32_eh_select_params.push_back(ptr_eh_ptr); |
| mvm::jit::protectConstants(); |
| int32_eh_select_params.push_back(ConstantExpr::getCast(Instruction::BitCast, mvm::jit::personality, PointerTy_0)); |
| mvm::jit::unprotectConstants(); |
| int32_eh_select_params.push_back(mvm::jit::constantPtrNull); |
| new CallInst(mvm::jit::exceptionSelector, int32_eh_select_params.begin(), int32_eh_select_params.end(), "eh_select", cur->test); |
| new BranchInst(cur->realTest, cur->test); |
| } |
| |
| Value* cl = new LoadInst(cur->catchClass->llvmVar(), "", cur->realTest); |
| Value* cmp = new CallInst(compareExceptionLLVM, cl, "", cur->realTest); |
| new BranchInst(cur->handler, bbNext, cmp, cur->realTest); |
| |
| if (cur->handler->empty()) { |
| Value* cpp = new CallInst(getCppExceptionLLVM, "", cur->handler); |
| Value* exc = new CallInst(getCLIExceptionLLVM, "", cur->handler); |
| new CallInst(clearExceptionLLVM, "", cur->handler); |
| new CallInst(mvm::jit::exceptionBeginCatch, cpp, "tmp8", cur->handler); |
| std::vector<Value*> void_28_params; |
| new CallInst(mvm::jit::exceptionEndCatch, void_28_params.begin(), void_28_params.end(), "", cur->handler); |
| new StoreInst(exc, supplLocal, false, cur->handler); |
| |
| for (uint16 i = cur->tryOffset; i < cur->tryOffset + cur->tryLength; ++i) { |
| opcodeInfos[i].exception = exc; |
| } |
| } |
| |
| } |
| |
| return nbe; |
| |
| } |
| |
| #include <iostream> |
| Function* CLIJit::compileFatOrTiny() { |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "tiny or fat compile %s\n", |
| compilingMethod->printString()); |
| uint32 offset = compilingMethod->offset; |
| ArrayUInt8* bytes = compilingClass->assembly->bytes; |
| uint8 header = READ_U1(bytes, offset); |
| bool tiny = false; |
| uint32 localVarSig = 0; |
| uint32 maxStack = 0; |
| uint32 codeLen = 0; |
| uint32 nbe = 0; |
| |
| if ((header & 3) == CONSTANT_CorILMethod_TinyFormat) { |
| tiny = true; |
| codeLen = (header & 0xfffc) >> 2; |
| } else if ((header & 3) != CONSTANT_CorILMethod_FatFormat) { |
| VMThread::get()->vm->error("unknown Method Format"); |
| } else { |
| header += (READ_U1(bytes, offset) << 8); //header |
| maxStack = READ_U2(bytes, offset); |
| codeLen = READ_U4(bytes, offset); |
| localVarSig = READ_U4(bytes, offset); |
| } |
| |
| |
| /* TODO Synchronize |
| bool synchro = isSynchro(compilingMethod->flags); |
| */ |
| |
| const FunctionType *funcType = compilingMethod->getSignature(); |
| |
| Function* func = llvmFunction = compilingMethod->methPtr; |
| currentBlock = createBasicBlock("start"); |
| endExceptionBlock = createBasicBlock("exceptionBlock"); |
| unifiedUnreachable = createBasicBlock("unifiedUnreachable"); |
| |
| |
| opcodeInfos = (Opinfo*)alloca(codeLen * sizeof(Opinfo)); |
| memset(opcodeInfos, 0, codeLen * sizeof(Opinfo)); |
| for (uint32 i = 0; i < codeLen; ++i) { |
| opcodeInfos[i].exceptionBlock = endExceptionBlock; |
| } |
| |
| if (!tiny) { |
| if (header & CONSTANT_CorILMethod_MoreSects) { |
| uint32 excpOffset = 0; |
| if ((codeLen % 4) == 0) { |
| excpOffset = offset + codeLen; |
| } else { |
| excpOffset = offset + codeLen + (4 - (codeLen % 4)); |
| } |
| |
| uint8 flags = READ_U1(bytes, excpOffset); |
| nbe = readExceptionTable(excpOffset, |
| flags & CONSTANT_CorILMethod_Sect_FatFormat); |
| } |
| } |
| |
| for (Function::arg_iterator i = func->arg_begin(), e = func->arg_end(); |
| i != e; ++i) { |
| |
| const Type* cur = i->getType(); |
| |
| AllocaInst* alloc = new AllocaInst(cur, "", currentBlock); |
| new StoreInst(i, alloc, false, currentBlock); |
| arguments.push_back(alloc); |
| } |
| |
| if (localVarSig) { |
| std::vector<VMCommonClass*> temp; |
| compilingClass->assembly->readSignature(localVarSig, temp); |
| |
| for (std::vector<VMCommonClass*>::iterator i = temp.begin(), |
| e = temp.end(); i!= e; ++i) { |
| VMCommonClass* cl = *i; |
| cl->resolveType(false, false); |
| AllocaInst* alloc = new AllocaInst(cl->naturalType, "", currentBlock); |
| if (cl->naturalType->isFirstClassType()) { |
| mvm::jit::protectConstants(); |
| new StoreInst(Constant::getNullValue(cl->naturalType), alloc, false, |
| currentBlock); |
| mvm::jit::unprotectConstants(); |
| } else { |
| uint64 size = mvm::jit::getTypeSize(cl->naturalType); |
| |
| std::vector<Value*> params; |
| params.push_back(new BitCastInst(alloc, PointerType::getUnqual(Type::Int8Ty), "", currentBlock)); |
| params.push_back(mvm::jit::constantInt8Zero); |
| mvm::jit::protectConstants(); |
| params.push_back(ConstantInt::get(Type::Int32Ty, size)); |
| mvm::jit::unprotectConstants(); |
| params.push_back(mvm::jit::constantZero); |
| new CallInst(mvm::jit::llvm_memset_i32, params.begin(), params.end(), "", currentBlock); |
| |
| } |
| locals.push_back(alloc); |
| } |
| } |
| |
| exploreOpcodes(&compilingClass->assembly->bytes->elements[offset], codeLen); |
| |
| endBlock = createBasicBlock("end"); |
| |
| const Type* endType = funcType->getReturnType(); |
| if (endType != Type::VoidTy) { |
| endNode = new PHINode(endType, "", endBlock); |
| } else if (compilingMethod->structReturn) { |
| const Type* lastType = |
| funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| endNode = new PHINode(lastType, "", endBlock); |
| } |
| |
| compileOpcodes(&compilingClass->assembly->bytes->elements[offset], codeLen); |
| |
| currentBlock = endBlock; |
| pred_iterator PI = pred_begin(endBlock); |
| pred_iterator PE = pred_end(endBlock); |
| if (PI == PE) { |
| endBlock->eraseFromParent(); |
| } else { |
| if (endType != Type::VoidTy) { |
| new ReturnInst(endNode, endBlock); |
| } else if (compilingMethod->structReturn) { |
| const Type* lastType = |
| funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| uint64 size = mvm::jit::getTypeSize(lastType->getContainedType(0)); |
| Value* obj = --llvmFunction->arg_end(); |
| std::vector<Value*> params; |
| params.push_back(new BitCastInst(obj, PointerType::getUnqual(Type::Int8Ty), "", currentBlock)); |
| params.push_back(new BitCastInst(endNode, PointerType::getUnqual(Type::Int8Ty), "", currentBlock)); |
| mvm::jit::protectConstants(); |
| params.push_back(ConstantInt::get(Type::Int32Ty, size)); |
| mvm::jit::unprotectConstants(); |
| params.push_back(mvm::jit::constantFour); |
| new CallInst(mvm::jit::llvm_memcpy_i32, params.begin(), params.end(), "", currentBlock); |
| new ReturnInst(currentBlock); |
| } else { |
| new ReturnInst(endBlock); |
| } |
| } |
| |
| PI = pred_begin(endExceptionBlock); |
| PE = pred_end(endExceptionBlock); |
| if (PI == PE) { |
| endExceptionBlock->eraseFromParent(); |
| } else { |
| CallInst* ptr_eh_ptr = new CallInst(getCppExceptionLLVM, "eh_ptr", |
| endExceptionBlock); |
| new CallInst(mvm::jit::unwindResume, ptr_eh_ptr, "", endExceptionBlock); |
| new UnreachableInst(endExceptionBlock); |
| } |
| |
| PI = pred_begin(unifiedUnreachable); |
| PE = pred_end(unifiedUnreachable); |
| if (PI == PE) { |
| unifiedUnreachable->eraseFromParent(); |
| } else { |
| new UnreachableInst(unifiedUnreachable); |
| } |
| |
| mvm::jit::runPasses(llvmFunction, VMThread::get()->perFunctionPasses); |
| |
| if (nbe == 0 && codeLen < 50) { |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "%s can be inlined\n", |
| compilingMethod->printString()); |
| compilingMethod->canBeInlined = true; |
| } |
| |
| return llvmFunction; |
| } |
| |
| Instruction* CLIJit::inlineCompile(Function* parentFunction, BasicBlock*& curBB, |
| BasicBlock* endExBlock, |
| std::vector<Value*>& args) { |
| |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "tiny or fat inline compile %s\n", |
| compilingMethod->printString()); |
| uint32 offset = compilingMethod->offset; |
| ArrayUInt8* bytes = compilingClass->assembly->bytes; |
| uint8 header = READ_U1(bytes, offset); |
| bool tiny = false; |
| uint32 localVarSig = 0; |
| uint32 maxStack = 0; |
| uint32 codeLen = 0; |
| |
| if ((header & 3) == CONSTANT_CorILMethod_TinyFormat) { |
| tiny = true; |
| codeLen = (header & 0xfffc) >> 2; |
| } else if ((header & 3) != CONSTANT_CorILMethod_FatFormat) { |
| VMThread::get()->vm->error("unknown Method Format"); |
| } else { |
| header += (READ_U1(bytes, offset) << 8); //header |
| maxStack = READ_U2(bytes, offset); |
| codeLen = READ_U4(bytes, offset); |
| localVarSig = READ_U4(bytes, offset); |
| } |
| |
| |
| /* TODO Synchronize |
| bool synchro = isSynchro(compilingMethod->flags); |
| */ |
| |
| const FunctionType *funcType = compilingMethod->getSignature(); |
| |
| llvmFunction = parentFunction; |
| currentBlock = curBB; |
| endExceptionBlock = 0; |
| |
| |
| opcodeInfos = (Opinfo*)alloca(codeLen * sizeof(Opinfo)); |
| memset(opcodeInfos, 0, codeLen * sizeof(Opinfo)); |
| for (uint32 i = 0; i < codeLen; ++i) { |
| opcodeInfos[i].exceptionBlock = endExBlock; |
| } |
| |
| if (!tiny) { |
| if (header & CONSTANT_CorILMethod_MoreSects) { |
| assert(0 && "inlining a function with exceptions!"); |
| uint32 excpOffset = 0; |
| if ((codeLen % 4) == 0) { |
| excpOffset = offset + codeLen; |
| } else { |
| excpOffset = offset + codeLen + (4 - (codeLen % 4)); |
| } |
| |
| uint8 flags = READ_U1(bytes, excpOffset); |
| readExceptionTable(excpOffset, |
| flags & CONSTANT_CorILMethod_Sect_FatFormat); |
| } |
| } |
| |
| for (std::vector<Value*>::iterator i = args.begin(), e = args.end(); |
| i != e; ++i) { |
| |
| const Type* cur = (*i)->getType(); |
| |
| AllocaInst* alloc = new AllocaInst(cur, "", currentBlock); |
| new StoreInst(*i, alloc, false, currentBlock); |
| arguments.push_back(alloc); |
| } |
| |
| if (localVarSig) { |
| std::vector<VMCommonClass*> temp; |
| compilingClass->assembly->readSignature(localVarSig, temp); |
| |
| for (std::vector<VMCommonClass*>::iterator i = temp.begin(), |
| e = temp.end(); i!= e; ++i) { |
| VMCommonClass* cl = *i; |
| cl->resolveType(false, false); |
| AllocaInst* alloc = new AllocaInst(cl->naturalType, "", currentBlock); |
| if (cl->naturalType->isFirstClassType()) { |
| mvm::jit::protectConstants(); |
| new StoreInst(Constant::getNullValue(cl->naturalType), alloc, false, |
| currentBlock); |
| mvm::jit::unprotectConstants(); |
| } else { |
| uint64 size = mvm::jit::getTypeSize(cl->naturalType); |
| |
| std::vector<Value*> params; |
| params.push_back(new BitCastInst(alloc, PointerType::getUnqual(Type::Int8Ty), "", currentBlock)); |
| params.push_back(mvm::jit::constantInt8Zero); |
| mvm::jit::protectConstants(); |
| params.push_back(ConstantInt::get(Type::Int32Ty, size)); |
| mvm::jit::unprotectConstants(); |
| params.push_back(mvm::jit::constantZero); |
| new CallInst(mvm::jit::llvm_memset_i32, params.begin(), params.end(), "", currentBlock); |
| |
| } |
| locals.push_back(alloc); |
| } |
| } |
| |
| exploreOpcodes(&compilingClass->assembly->bytes->elements[offset], codeLen); |
| |
| endBlock = createBasicBlock("end"); |
| |
| const Type* endType = funcType->getReturnType(); |
| if (endType != Type::VoidTy) { |
| endNode = new PHINode(endType, "", endBlock); |
| } else if (compilingMethod->structReturn) { |
| const Type* lastType = |
| funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| endNode = new PHINode(lastType, "", endBlock); |
| } |
| |
| compileOpcodes(&compilingClass->assembly->bytes->elements[offset], codeLen); |
| |
| curBB = endBlock; |
| |
| PRINT_DEBUG(N3_COMPILE, 1, COLOR_NORMAL, "end tiny or fat inline compile %s\n", |
| compilingMethod->printString()); |
| |
| return endNode; |
| } |
| |
| |
| Function* CLIJit::compile(VMClass* cl, VMMethod* meth) { |
| CLIJit* jit = gc_new(CLIJit)(); |
| jit->compilingClass = cl; |
| jit->compilingMethod = meth; |
| |
| meth->getSignature(); |
| if (isInternal(meth->implFlags)) { |
| return jit->compileNative(); |
| } else if (meth->offset == 0) { |
| return jit->compileIntern(); |
| } else { |
| return jit->compileFatOrTiny(); |
| } |
| } |
| |
| llvm::Function *VMMethod::compiledPtr() { |
| if (methPtr != 0) return methPtr; |
| else { |
| classDef->aquire(); |
| if (methPtr == 0) { |
| methPtr = new llvm::Function(getSignature(), GlobalValue::GhostLinkage, |
| printString(), classDef->vm->module); |
| classDef->vm->functions->hash(methPtr, this); |
| } |
| classDef->release(); |
| return methPtr; |
| } |
| } |
| |
| void VMField::initField(VMObject* obj) { |
| VMField* field = this; |
| ConstantInt* offset = field->offset; |
| const TargetData* targetData = mvm::jit::executionEngine->getTargetData(); |
| bool stat = isStatic(field->flags); |
| const Type* clType = stat ? field->classDef->staticType : |
| field->classDef->virtualType; |
| |
| const StructLayout* sl = |
| targetData->getStructLayout((StructType*)(clType->getContainedType(0))); |
| uint64 ptrOffset = sl->getElementOffset(offset->getZExtValue()); |
| |
| field->ptrOffset = ptrOffset; |
| |
| } |
| |
| extern "C" VMObject* initialiseClass(VMClass* cl) { |
| cl->clinitClass(); |
| return cl->staticInstance; |
| } |
| |
| extern "C" void classCastException() { |
| fflush(stdout); |
| assert(0 && "implement class cast exception"); |
| } |
| |
| extern "C" void nullPointerException() { |
| fflush(stdout); |
| assert(0 && "implement null pointer exception"); |
| } |
| |
| extern "C" void indexOutOfBounds() { |
| fflush(stdout); |
| assert(0 && "implement index out of bounds exception"); |
| } |
| |
| |
| extern "C" bool isInCode(void* value) { |
| mvm::Object* obj = (mvm::Object*)gc::begOf(value); |
| if (obj && obj->getVirtualTable() == mvm::Code::VT) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| extern "C" VMObject* newString(const UTF8* utf8) { |
| CLIString * str = |
| (CLIString*)(((N3*)VMThread::get()->vm)->UTF8ToStr(utf8)); |
| return str; |
| } |
| |
| void CLIJit::initialise() { |
| } |
| |
| void CLIJit::initialiseAppDomain(N3* vm) { |
| mvm::jit::protectEngine->lock(); |
| mvm::jit::executionEngine->addModuleProvider(vm->TheModuleProvider); |
| mvm::jit::protectEngine->unlock(); |
| } |
| |
| void CLIJit::initialiseBootstrapVM(N3* vm) { |
| Module* module = vm->module; |
| mvm::jit::protectEngine->lock(); |
| mvm::jit::executionEngine->addModuleProvider(vm->TheModuleProvider); |
| mvm::jit::protectEngine->unlock(); |
| |
| |
| |
| { |
| std::vector<const llvm::Type *> arg_types; |
| arg_types.insert (arg_types.begin (), llvm::PointerType::getUnqual(llvm::PointerType::getUnqual(llvm::Type::Int8Ty))); |
| |
| llvm::FunctionType *mtype = llvm::FunctionType::get (llvm::Type::VoidTy, arg_types, false); |
| new llvm::Function(mtype, llvm::GlobalValue::ExternalLinkage, "llvm.va_start", module); |
| } |
| |
| { |
| std::vector<const llvm::Type *> arg_types; |
| arg_types.insert (arg_types.begin (), llvm::Type::Int32Ty); |
| |
| llvm::FunctionType *mtype = llvm::FunctionType::get (llvm::PointerType::getUnqual(llvm::Type::Int8Ty), arg_types, false); |
| new llvm::Function(mtype, llvm::GlobalValue::ExternalLinkage, "llvm.frameaddress", module); |
| } |
| |
| |
| { |
| const llvm::Type *BPTy = PointerType::getUnqual(llvm::Type::Int8Ty); |
| // Prototype malloc as "char* malloc(...)", because we don't know in |
| // doInitialization whether size_t is int or long. |
| FunctionType *FT = FunctionType::get(BPTy, std::vector<const llvm::Type*>(), true); |
| new llvm::Function(FT, llvm::GlobalValue::ExternalLinkage, "_ZN2gcnwEjP5gc_vt", module); |
| } |
| |
| |
| // Create VMObject::llvmType |
| const llvm::Type* Pty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); |
| |
| std::vector<const llvm::Type*> objectFields; |
| objectFields.push_back(Pty); // VT |
| objectFields.push_back(Pty); // Class |
| objectFields.push_back(Pty); // Lock |
| VMObject::llvmType = |
| llvm::PointerType::getUnqual(llvm::StructType::get(objectFields, false)); |
| |
| // Create VMArray::llvmType |
| { |
| std::vector<const llvm::Type*> arrayFields; |
| arrayFields.push_back(VMObject::llvmType->getContainedType(0)); |
| arrayFields.push_back(llvm::Type::Int32Ty); |
| VMArray::llvmType = |
| llvm::PointerType::getUnqual(llvm::StructType::get(arrayFields, false)); |
| } |
| |
| #define ARRAY_TYPE(name, type) \ |
| { \ |
| std::vector<const Type*> arrayFields; \ |
| arrayFields.push_back(VMObject::llvmType->getContainedType(0)); \ |
| arrayFields.push_back(Type::Int32Ty); \ |
| arrayFields.push_back(ArrayType::get(type, 0)); \ |
| name::llvmType = PointerType::getUnqual(StructType::get(arrayFields, false)); \ |
| } |
| |
| ARRAY_TYPE(ArrayUInt8, Type::Int8Ty); |
| ARRAY_TYPE(ArraySInt8, Type::Int8Ty); |
| ARRAY_TYPE(ArrayUInt16, Type::Int16Ty); |
| ARRAY_TYPE(ArraySInt16, Type::Int16Ty); |
| ARRAY_TYPE(ArrayUInt32, Type::Int32Ty); |
| ARRAY_TYPE(ArraySInt32, Type::Int32Ty); |
| ARRAY_TYPE(ArrayLong, Type::Int64Ty); |
| ARRAY_TYPE(ArrayDouble, Type::DoubleTy); |
| ARRAY_TYPE(ArrayFloat, Type::FloatTy); |
| ARRAY_TYPE(ArrayObject, VMObject::llvmType); |
| |
| #undef ARRAY_TYPE |
| |
| // Create UTF8::llvmType |
| { |
| std::vector<const llvm::Type*> arrayFields; |
| arrayFields.push_back(VMObject::llvmType->getContainedType(0)); |
| arrayFields.push_back(llvm::Type::Int32Ty); |
| arrayFields.push_back(llvm::ArrayType::get(llvm::Type::Int16Ty, 0)); |
| UTF8::llvmType = |
| llvm::PointerType::getUnqual(llvm::StructType::get(arrayFields, false)); |
| } |
| |
| // Create CacheNode::llvmType |
| { |
| std::vector<const llvm::Type*> arrayFields; |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // VT |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // methPtr |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // lastCible |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // next |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // enveloppe |
| arrayFields.push_back(Type::Int1Ty); // box |
| CacheNode::llvmType = |
| PointerType::getUnqual(StructType::get(arrayFields, false)); |
| } |
| |
| // Create Enveloppe::llvmType |
| { |
| std::vector<const llvm::Type*> arrayFields; |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // VT |
| arrayFields.push_back(CacheNode::llvmType); // firstCache |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // cacheLock |
| arrayFields.push_back(PointerType::getUnqual(Type::Int8Ty)); // originalMethod |
| Enveloppe::llvmType = |
| PointerType::getUnqual(StructType::get(arrayFields, false)); |
| } |
| |
| // Create markAndTraceLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| markAndTraceLLVMType = FunctionType::get(llvm::Type::VoidTy, args, false); |
| markAndTraceLLVM = new Function(markAndTraceLLVMType, |
| GlobalValue::ExternalLinkage, |
| "_ZNK2gc12markAndTraceEv", |
| module); |
| } |
| |
| // Create vmObjectTracerLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| vmObjectTracerLLVM = new Function(type, |
| GlobalValue::ExternalLinkage, |
| "_ZN2n38VMObject6tracerEj", |
| module); |
| } |
| |
| // Create intialiseClassLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, false); |
| initialiseClassLLVM = new Function(type, |
| GlobalValue::ExternalLinkage, |
| "initialiseClass", |
| module); |
| } |
| |
| |
| // Create resolveStringLLVM |
| /*{ |
| std::vector<const Type*> args; |
| args.push_back(UTF8::llvmType); |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| args.push_back(llvm::Type::Int32Ty); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| stringLookupLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n37CLIJit12stringLookupEPKNS_4UTF8EPNS_5ClassEj", |
| module); |
| }*/ |
| |
| // Create staticLookupLLVM |
| /*{ |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| args.push_back(llvm::Type::Int32Ty); |
| const FunctionType* type = |
| FunctionType::get(llvm::PointerType::getUnqual(llvm::Type::Int8Ty), args, |
| false); |
| |
| staticLookupLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n37CLIJit12staticLookupEPNS_5ClassEj", |
| module); |
| }*/ |
| |
| // Create virtualLookupLLVM |
| { |
| std::vector<const Type*> args; |
| //args.push_back(VMObject::llvmType); |
| //args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| //args.push_back(llvm::Type::Int32Ty); |
| args.push_back(CacheNode::llvmType); |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = |
| FunctionType::get(CacheNode::llvmType, args, false); |
| |
| virtualLookupLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "virtualLookup", module); |
| |
| /* |
| virtualLookupLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n37CLIJit13virtualLookupEPNS_10VMObjectEPNS_5ClassEj", |
| module); |
| */ |
| } |
| |
| // Create newLookupLLVM |
| /*{ |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| args.push_back(llvm::Type::Int32Ty); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| |
| newLookupLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n37CLIJit9newLookupEPNS_5ClassEj", |
| module); |
| }*/ |
| |
| // Create arrayConsLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| args.push_back(Type::Int32Ty); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| |
| arrayConsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n312VMClassArray5doNewEj", |
| module); |
| } |
| |
| // Create objConsLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| |
| objConsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n37VMClass5doNewEv", |
| module); |
| } |
| |
| // Create objInitLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| |
| objInitLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n37VMClass16initialiseObjectEPNS_8VMObjectE", |
| module); |
| PAListPtr func_toto_PAL; |
| SmallVector<ParamAttrsWithIndex, 4> Attrs; |
| ParamAttrsWithIndex PAWI; |
| PAWI.Index = 0; PAWI.Attrs = 0 | ParamAttr::ReadNone; |
| Attrs.push_back(PAWI); |
| func_toto_PAL = PAListPtr::get(Attrs.begin(), Attrs.end()); |
| objInitLLVM->setParamAttrs(func_toto_PAL); |
| } |
| |
| // Create arrayLengthLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMArray::llvmType); |
| const FunctionType* type = FunctionType::get(Type::Int32Ty, args, false); |
| |
| arrayLengthLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "arrayLength", |
| module); |
| PAListPtr func_toto_PAL; |
| SmallVector<ParamAttrsWithIndex, 4> Attrs; |
| ParamAttrsWithIndex PAWI; |
| PAWI.Index = 0; PAWI.Attrs = 0 | ParamAttr::ReadNone; |
| Attrs.push_back(PAWI); |
| func_toto_PAL = PAListPtr::get(Attrs.begin(), Attrs.end()); |
| arrayLengthLLVM->setParamAttrs(func_toto_PAL); |
| } |
| |
| |
| // Create nullPointerExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| nullPointerExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "nullPointerException", |
| module); |
| } |
| |
| // Create classCastExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| classCastExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "classCastException", |
| module); |
| } |
| |
| // Create indexOutOfBoundsExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| args.push_back(Type::Int32Ty); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| indexOutOfBoundsExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "indexOutOfBounds", |
| module); |
| } |
| |
| // Create proceedPendingExceptionLLVM |
| /*{ |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| jniProceedPendingExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n37CLIJit26jniProceedPendingExceptionEv", |
| module); |
| }*/ |
| |
| // Create printExecutionLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(Type::Int32Ty); |
| args.push_back(Type::Int32Ty); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| printExecutionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n36CLIJit14printExecutionEPcPNS_8VMMethodE", |
| module); |
| } |
| |
| // Create throwExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| throwExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMThread14throwExceptionEPNS_8VMObjectE", |
| module); |
| } |
| |
| // Create clearExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| clearExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMThread14clearExceptionEv", |
| module); |
| } |
| |
| |
| // Create compareExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(Type::Int1Ty, args, false); |
| |
| compareExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMThread16compareExceptionEPNS_7VMClassE", |
| module); |
| } |
| |
| // Create instanceOfLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(Type::Int32Ty, args, false); |
| |
| instanceOfLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMObject10instanceOfEPNS_13VMCommonClassE", |
| module); |
| } |
| |
| // Create isInCodeLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(Type::Int1Ty, args, false); |
| |
| isInCodeLLVM = new Function(type, GlobalValue::ExternalLinkage, "isInCode", |
| module); |
| } |
| |
| // Create arrayMultiConsLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| true); |
| |
| arrayMultiConsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "doMultiNew", |
| module); |
| } |
| |
| /* |
| // Create aquireObjectLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| aquireObjectLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n310VMObject6aquireEv", |
| module); |
| } |
| |
| // Create releaseObjectLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(VMObject::llvmType); |
| const FunctionType* type = FunctionType::get(Type::VoidTy, args, false); |
| |
| releaseObjectLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n310VMObject6unlockEv", |
| module); |
| } |
| |
| */ |
| |
| |
| // Create *AconsLLVM |
| /*{ |
| std::vector<const Type*> args; |
| args.push_back(Type::Int32Ty); |
| args.push_back(PointerType::getUnqual(Type::Int8Ty)); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, args, |
| false); |
| |
| FloatAconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n310ArrayFloat5aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| Int8AconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n310ArraySInt85aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| DoubleAconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n311ArrayDouble5aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| Int16AconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n311ArraySInt165aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| Int32AconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n311ArraySInt325aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| UTF8AconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n34UTF85aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| LongAconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n39ArrayLong5aconsEiPNS_10VMClassArrayE", |
| module); |
| |
| ObjectAconsLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN5n311ArrayObject5aconsEiPNS_10VMClassArrayE", |
| module); |
| }*/ |
| |
| // Create getCppExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(mvm::jit::ptrType, |
| args, false); |
| |
| getCppExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMThread15getCppExceptionEv", |
| module); |
| } |
| |
| // Create getCLIExceptionLLVM |
| { |
| std::vector<const Type*> args; |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, |
| args, false); |
| |
| getCLIExceptionLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "_ZN2n38VMThread15getCLIExceptionEv", |
| module); |
| } |
| |
| // Create newStringLLVM |
| { |
| std::vector<const Type*> args; |
| args.push_back(mvm::jit::ptrType); |
| const FunctionType* type = FunctionType::get(VMObject::llvmType, |
| args, false); |
| |
| newStringLLVM = new Function(type, GlobalValue::ExternalLinkage, |
| "newString", |
| module); |
| } |
| |
| |
| constantVMObjectNull = Constant::getNullValue(VMObject::llvmType); |
| } |
| |
| Constant* CLIJit::constantVMObjectNull; |
| |
| |
| static void printArgs(std::vector<llvm::Value*> args, BasicBlock* insertAt) { |
| for (std::vector<llvm::Value*>::iterator i = args.begin(), |
| e = args.end(); i!= e; ++i) { |
| llvm::Value* arg = *i; |
| const llvm::Type* type = arg->getType(); |
| if (type == Type::Int8Ty || type == Type::Int16Ty || type == Type::Int1Ty) { |
| new CallInst(mvm::jit::printIntLLVM, new ZExtInst(arg, Type::Int32Ty, "", insertAt), "", insertAt); |
| } else if (type == Type::Int32Ty) { |
| new CallInst(mvm::jit::printIntLLVM, arg, "", insertAt); |
| } else if (type == Type::Int64Ty) { |
| new CallInst(mvm::jit::printLongLLVM, arg, "", insertAt); |
| } else if (type == Type::FloatTy) { |
| new CallInst(mvm::jit::printFloatLLVM, arg, "", insertAt); |
| } else if (type == Type::DoubleTy) { |
| new CallInst(mvm::jit::printDoubleLLVM, arg, "", insertAt); |
| } else { |
| new CallInst(mvm::jit::printObjectLLVM, new BitCastInst(arg, VMObject::llvmType, "", insertAt), "", insertAt); |
| } |
| } |
| |
| } |
| |
| Value* CLIJit::invoke(Value *F, std::vector<llvm::Value*> args, |
| const char* Name, |
| BasicBlock *InsertAtEnd, bool structReturn) { |
| #if N3_EXECUTE > 1 |
| printArgs(args, InsertAtEnd); |
| #endif |
| |
| Value* ret = 0; |
| if (structReturn) { |
| const Type* funcType = F->getType(); |
| if (isa<PointerType>(funcType)) { |
| funcType = funcType->getContainedType(0); |
| } |
| const Type* lastType = funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| ret = new AllocaInst(lastType->getContainedType(0), "", InsertAtEnd); |
| args.push_back(ret); |
| } |
| Value* val = 0; |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| val = new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| val = new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| if (ret) return ret; |
| else return val; |
| } |
| |
| Value* CLIJit::invoke(Value *F, Value* arg1, const char* Name, |
| BasicBlock *InsertAtEnd, bool structReturn) { |
| |
| std::vector<Value*> args; |
| args.push_back(arg1); |
| #if N3_EXECUTE > 1 |
| printArgs(args, InsertAtEnd); |
| #endif |
| Value* ret = 0; |
| if (structReturn) { |
| const Type* funcType = F->getType(); |
| if (isa<PointerType>(funcType)) { |
| funcType = funcType->getContainedType(0); |
| } |
| const Type* lastType = funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| ret = new AllocaInst(lastType->getContainedType(0), "", InsertAtEnd); |
| args.push_back(ret); |
| } |
| |
| Value* val = 0; |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| val = new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| val = new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| |
| if (ret) return ret; |
| else return val; |
| } |
| |
| Value* CLIJit::invoke(Value *F, Value* arg1, Value* arg2, |
| const char* Name, BasicBlock *InsertAtEnd, |
| bool structReturn) { |
| |
| std::vector<Value*> args; |
| args.push_back(arg1); |
| args.push_back(arg2); |
| #if N3_EXECUTE > 1 |
| printArgs(args, InsertAtEnd); |
| #endif |
| |
| Value* ret = 0; |
| if (structReturn) { |
| const Type* funcType = F->getType(); |
| if (isa<PointerType>(funcType)) { |
| funcType = funcType->getContainedType(0); |
| } |
| const Type* lastType = funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| ret = new AllocaInst(lastType->getContainedType(0), "", InsertAtEnd); |
| args.push_back(ret); |
| } |
| |
| Value* val = 0; |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| val = new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| val = new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| if (ret) return ret; |
| else return val; |
| } |
| |
| Value* CLIJit::invoke(Value *F, const char* Name, |
| BasicBlock *InsertAtEnd, bool structReturn) { |
| |
| std::vector<Value*> args; |
| Value* ret = 0; |
| if (structReturn) { |
| const Type* funcType = F->getType(); |
| if (isa<PointerType>(funcType)) { |
| funcType = funcType->getContainedType(0); |
| } |
| const Type* lastType = funcType->getContainedType(funcType->getNumContainedTypes() - 1); |
| ret = new AllocaInst(lastType->getContainedType(0), "", InsertAtEnd); |
| args.push_back(ret); |
| } |
| |
| Value* val = 0; |
| // means: is there a handler for me? |
| if (currentExceptionBlock != endExceptionBlock) { |
| BasicBlock* ifNormal = createBasicBlock("no exception block"); |
| currentBlock = ifNormal; |
| val = new InvokeInst(F, ifNormal, currentExceptionBlock, args.begin(), |
| args.end(), Name, InsertAtEnd); |
| } else { |
| val = new CallInst(F, args.begin(), args.end(), Name, InsertAtEnd); |
| } |
| if (ret) return ret; |
| else return val; |
| } |
| |
| |
| |
| |
| namespace mvm { |
| llvm::FunctionPass* createEscapeAnalysisPass(llvm::Function*, llvm::Function*); |
| } |
| |
| namespace n3 { |
| llvm::FunctionPass* createLowerArrayLengthPass(); |
| //llvm::FunctionPass* createArrayChecksPass(); |
| } |
| |
| static void addPass(FunctionPassManager *PM, Pass *P) { |
| // Add the pass to the pass manager... |
| PM->add(P); |
| } |
| |
| void AddStandardCompilePasses(FunctionPassManager *PM) { |
| llvm::MutexGuard locked(mvm::jit::executionEngine->lock); |
| // LLVM does not allow calling functions from other modules in verifier |
| //PM->add(llvm::createVerifierPass()); // Verify that input is correct |
| |
| addPass(PM, mvm::createEscapeAnalysisPass(CLIJit::objConsLLVM, CLIJit::objInitLLVM)); |
| addPass(PM, llvm::createCFGSimplificationPass()); // Clean up disgusting code |
| addPass(PM, llvm::createScalarReplAggregatesPass());// Kill useless allocas |
| addPass(PM, llvm::createInstructionCombiningPass()); // Clean up after IPCP & DAE |
| addPass(PM, llvm::createCFGSimplificationPass()); // Clean up after IPCP & DAE |
| addPass(PM, llvm::createPromoteMemoryToRegisterPass());// Kill useless allocas |
| addPass(PM, llvm::createInstructionCombiningPass()); // Clean up after IPCP & DAE |
| addPass(PM, llvm::createCFGSimplificationPass()); // Clean up after IPCP & DAE |
| |
| addPass(PM, llvm::createTailDuplicationPass()); // Simplify cfg by copying code |
| addPass(PM, llvm::createInstructionCombiningPass()); // Cleanup for scalarrepl. |
| addPass(PM, llvm::createCFGSimplificationPass()); // Merge & remove BBs |
| addPass(PM, llvm::createScalarReplAggregatesPass()); // Break up aggregate allocas |
| addPass(PM, llvm::createInstructionCombiningPass()); // Combine silly seq's |
| addPass(PM, llvm::createCondPropagationPass()); // Propagate conditionals |
| |
| |
| addPass(PM, llvm::createTailCallEliminationPass()); // Eliminate tail calls |
| addPass(PM, llvm::createCFGSimplificationPass()); // Merge & remove BBs |
| addPass(PM, llvm::createReassociatePass()); // Reassociate expressions |
| addPass(PM, llvm::createLoopRotatePass()); |
| addPass(PM, llvm::createLICMPass()); // Hoist loop invariants |
| addPass(PM, llvm::createLoopUnswitchPass()); // Unswitch loops. |
| addPass(PM, llvm::createInstructionCombiningPass()); // Clean up after LICM/reassoc |
| addPass(PM, llvm::createIndVarSimplifyPass()); // Canonicalize indvars |
| addPass(PM, llvm::createLoopUnrollPass()); // Unroll small loops |
| addPass(PM, llvm::createInstructionCombiningPass()); // Clean up after the unroller |
| //addPass(PM, mvm::createArrayChecksPass()); |
| addPass(PM, llvm::createGVNPass()); // GVN for load instructions |
| addPass(PM, llvm::createGCSEPass()); // Remove common subexprs |
| addPass(PM, llvm::createSCCPPass()); // Constant prop with SCCP |
| addPass(PM, llvm::createPredicateSimplifierPass()); |
| |
| |
| // Run instcombine after redundancy elimination to exploit opportunities |
| // opened up by them. |
| addPass(PM, llvm::createInstructionCombiningPass()); |
| addPass(PM, llvm::createCondPropagationPass()); // Propagate conditionals |
| |
| addPass(PM, llvm::createDeadStoreEliminationPass()); // Delete dead stores |
| addPass(PM, llvm::createAggressiveDCEPass()); // SSA based 'Aggressive DCE' |
| addPass(PM, llvm::createCFGSimplificationPass()); // Merge & remove BBs |
| addPass(PM, n3::createLowerArrayLengthPass()); |
| } |