blob: d0d68e4d6a36ceb4b23d13f37762ae2d910c7f19 [file] [log] [blame]
//===------------- CLIJit.h - CLI just in time compiler -------------------===//
//
// N3
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef N3_CLIJit_H
#define N3_CLIJit_H
#include "mvm/JIT.h"
#include "mvm/Object.h"
#include "mvm/PrintBuffer.h"
#include "mvm/Threads/Locks.h"
#include "llvm/BasicBlock.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/PassManager.h"
#include "llvm/Type.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Target/TargetData.h"
#include "types.h"
namespace n3 {
class CacheNode;
class N3;
class N3ModuleProvider;
class VMClass;
class VMClassArray;
class VMCommonClass;
class VMMethod;
class VMObject;
class VMGenericClass;
class VMGenericMethod;
class N3VirtualTable;
class ExceptionBlockDesc : public mvm::PermanentObject {
public:
uint32 tryOffset;
uint32 tryLength;
uint32 handlerOffset;
uint32 handlerLength;
VMCommonClass* catchClass;
llvm::BasicBlock* test;
llvm::BasicBlock* realTest;
llvm::BasicBlock* handler;
virtual void print(mvm::PrintBuffer* buf) const;
};
class Opinfo {
public:
llvm::BasicBlock* newBlock;
llvm::BasicBlock* exceptionBlock;
bool reqSuppl;
llvm::Value* exception;
virtual void print(mvm::PrintBuffer* buf) const {
buf->write("Opinfo");
}
};
class CLIJit : public mvm::PermanentObject {
public:
mvm::BumpPtrAllocator &allocator;
CLIJit(mvm::BumpPtrAllocator &a) : allocator(a) {}
virtual void print(mvm::PrintBuffer* buf) const {
buf->write("CLIJit");
}
static const char* OpcodeNames[0xE1];
static const char* OpcodeNamesFE[0x23];
static N3VirtualTable* makeVT(VMClass* cl, bool isStatic);
static N3VirtualTable* makeArrayVT(VMClassArray* cl);
static void printExecution(char*, n3::VMMethod*);
void compileOpcodes(uint8*, uint32, VMGenericClass* genClass, VMGenericMethod* genMethod);
void exploreOpcodes(uint8*, uint32);
llvm::Function* llvmFunction;
VMMethod* compilingMethod;
VMClass* compilingClass;
mvm::BaseIntrinsics* module;
std::vector<llvm::Value*> arguments;
std::vector<llvm::Value*> locals;
// end function
llvm::BasicBlock* endBlock;
llvm::PHINode* endNode;
// block manipulation
llvm::BasicBlock* currentBlock;
llvm::BasicBlock* createBasicBlock(const char* name = "");
void setCurrentBlock(llvm::BasicBlock* block);
// branches
void branch(llvm::Value* test, llvm::BasicBlock* ifTrue,
llvm::BasicBlock* ifFalse, llvm::BasicBlock* insert);
void branch(llvm::BasicBlock* where, llvm::BasicBlock* insert);
// stack manipulation
std::vector<llvm::Value*> stack;
void push(llvm::Value*);
llvm::Value* pop();
llvm::Value* top();
// exceptions
llvm::BasicBlock* endExceptionBlock;
llvm::BasicBlock* currentExceptionBlock;
llvm::BasicBlock* unifiedUnreachable;
std::vector<ExceptionBlockDesc*> exceptions;
std::vector<ExceptionBlockDesc*> finallyHandlers;
uint32 readExceptionTable(uint32 offset, bool fat, VMGenericClass* genClass, VMGenericMethod* genMethod);
std::vector<llvm::BasicBlock*> leaves;
llvm::Value* supplLocal;
// calls
void invoke(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod);
void invokeInterfaceOrVirtual(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod);
void invokeNew(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod);
llvm::Value* getVirtualField(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod);
llvm::Value* getStaticField(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod);
void setVirtualField(uint32 value, bool isVolatile, VMGenericClass* genClass, VMGenericMethod* genMethod);
void setStaticField(uint32 value, bool isVolatile, VMGenericClass* genClass, VMGenericMethod* genMethod);
void JITVerifyNull(llvm::Value* obj);
// array manipulation
llvm::Value* verifyAndComputePtr(llvm::Value* obj, llvm::Value* index,
const llvm::Type* arrayType,
bool verif = true);
llvm::Value* arraySize(llvm::Value* obj);
Opinfo* opcodeInfos;
static llvm::Function* printExecutionLLVM;
static llvm::Function* indexOutOfBoundsExceptionLLVM;
static llvm::Function* nullPointerExceptionLLVM;
static llvm::Function* initialiseClassLLVM;
static llvm::Function* throwExceptionLLVM;
static llvm::Function* clearExceptionLLVM;
static llvm::Function* compareExceptionLLVM;
static llvm::Function* classCastExceptionLLVM;
static llvm::Function* newStringLLVM;
static llvm::Function* arrayLengthLLVM;
static llvm::Function* compile(VMClass* cl, VMMethod* meth);
#ifdef WITH_TRACER
static llvm::Function* markAndTraceLLVM;
static const llvm::FunctionType* markAndTraceLLVMType;
#endif
static llvm::Function* vmObjectTracerLLVM;
static llvm::Function* arrayConsLLVM;
static llvm::Function* arrayMultiConsLLVM;
static llvm::Function* objConsLLVM;
static llvm::Function* objInitLLVM;
static llvm::Function* instanceOfLLVM;
static llvm::Function* getCppExceptionLLVM;
static llvm::Function* getCLIExceptionLLVM;
static void initialise();
static void initialiseAppDomain(N3* vm);
static void initialiseBootstrapVM(N3* vm);
llvm::Function* compileNative(VMGenericMethod* genMethod);
llvm::Function* compileFatOrTiny(VMGenericClass* genClass, VMGenericMethod* genMethod);
llvm::Function* compileIntern();
llvm::Function* createDelegate();
llvm::Function* invokeDelegate();
llvm::Value* invoke(llvm::Value *F, std::vector<llvm::Value*> args,
const char* Name,
llvm::BasicBlock *InsertAtEnd, bool structReturn);
// Alternate CallInst ctors w/ two actuals, w/ one actual and no
// actuals, respectively.
llvm::Value* invoke(llvm::Value *F, llvm::Value *Actual1,
llvm::Value *Actual2, const char* Name,
llvm::BasicBlock *InsertAtEnd, bool structReturn);
llvm::Value* invoke(llvm::Value *F, llvm::Value *Actual1,
const char* Name, llvm::BasicBlock *InsertAtEnd,
bool structReturn);
llvm::Value* invoke(llvm::Value *F, const char* Name,
llvm::BasicBlock *InsertAtEnd, bool structReturn);
void makeArgs(const llvm::FunctionType* type,
std::vector<llvm::Value*>& Args, bool structReturn);
llvm::Value* changeType(llvm::Value* val, const llvm::Type* type);
static llvm::Function* virtualLookupLLVM;
llvm::Instruction* lowerMathOps(VMMethod* meth,
std::vector<llvm::Value*>& args);
static llvm::Constant* constantVMObjectNull;
llvm::Instruction* inlineCompile(llvm::Function* parentFunction,
llvm::BasicBlock*& curBB,
llvm::BasicBlock* endExBlock,
std::vector<llvm::Value*>& args, VMGenericClass* genClass, VMGenericMethod* genMethod);
std::map<VMMethod*, bool> inlineMethods;
llvm::Instruction* invokeInline(VMMethod* meth,
std::vector<llvm::Value*>& args, VMGenericClass* genClass, VMGenericMethod* genMethod);
static VMMethod* getMethod(llvm::Function* F);
};
enum Opcode {
NOP = 0x00,
BREAK = 0x01,
LDARG_0 = 0x02,
LDARG_1 = 0x03,
LDARG_2 = 0x04,
LDARG_3 = 0x05,
LDLOC_0 = 0x06,
LDLOC_1 = 0x07,
LDLOC_2 = 0x08,
LDLOC_3 = 0x09,
STLOC_0 = 0x0A,
STLOC_1 = 0x0B,
STLOC_2 = 0x0C,
STLOC_3 = 0x0D,
LDARG_S = 0x0E,
LDARGA_S = 0x0F,
STARG_S = 0x10,
LDLOC_S = 0x11,
LDLOCA_S = 0x12,
STLOC_S = 0x13,
LDNULL = 0x14,
LDC_I4_M1 = 0x15,
LDC_I4_0 = 0x16,
LDC_I4_1 = 0x17,
LDC_I4_2 = 0x18,
LDC_I4_3 = 0x19,
LDC_I4_4 = 0x1A,
LDC_I4_5 = 0x1B,
LDC_I4_6 = 0x1C,
LDC_I4_7 = 0x1D,
LDC_I4_8 = 0x1E,
LDC_I4_S = 0x1F,
LDC_I4 = 0x20,
LDC_I8 = 0x21,
LDC_R4 = 0x22,
LDC_R8 = 0x23,
UNUSED99 = 0x24,
DUP = 0x25,
POP = 0x26,
JMP = 0x27,
CALL = 0x28,
CALLI = 0x29,
RET = 0x2A,
BR_S = 0x2B,
BRFALSE_S = 0x2C,
BRTRUE_S = 0x2D,
BEQ_S = 0x2E,
BGE_S = 0x2F,
BGT_S = 0x30,
BLE_S = 0x31,
BLT_S = 0x32,
BNE_UN_S = 0x33,
BGE_UN_S = 0x34,
BGT_UN_S = 0x35,
BLE_UN_S = 0x36,
BLT_UN_S = 0x37,
BR = 0x38,
BRFALSE = 0x39,
BRTRUE = 0x3A,
BEQ = 0x3B,
BGE = 0x3C,
BGT = 0x3D,
BLE = 0x3E,
BLT = 0x3F,
BNE_UN = 0x40,
BGE_UN = 0x41,
BGT_UN = 0x42,
BLE_UN = 0x43,
BLT_UN = 0x44,
SWITCH = 0x45,
LDIND_I1 = 0x46,
LDIND_U1 = 0x47,
LDIND_I2 = 0x48,
LDIND_U2 = 0x49,
LDIND_I4 = 0x4A,
LDIND_U4 = 0x4B,
LDIND_I8 = 0x4C,
LDIND_I = 0x4D,
LDIND_R4 = 0x4E,
LDIND_R8 = 0x4F,
LDIND_REF = 0x50,
STIND_REF = 0x51,
STIND_I1 = 0x52,
STIND_I2 = 0x53,
STIND_I4 = 0x54,
STIND_I8 = 0x55,
STIND_R4 = 0x56,
STIND_R8 = 0x57,
ADD = 0x58,
SUB = 0x59,
MUL = 0x5A,
DIV = 0x5B,
DIV_UN = 0x5C,
REM = 0x5D,
REM_UN = 0x5E,
AND = 0x5F,
OR = 0x60,
XOR = 0x61,
SHL = 0x62,
SHR = 0x63,
SHR_UN = 0x64,
NEG = 0x65,
NOT = 0x66,
CONV_I1 = 0x67,
CONV_I2 = 0x68,
CONV_I4 = 0x69,
CONV_I8 = 0x6A,
CONV_R4 = 0x6B,
CONV_R8 = 0x6C,
CONV_U4 = 0x6D,
CONV_U8 = 0x6E,
CALLVIRT = 0x6F,
CPOBJ = 0x70,
LDOBJ = 0x71,
LDSTR = 0x72,
NEWOBJ = 0x73,
CASTCLASS = 0x74,
ISINST = 0x75,
CONV_R_UN = 0x76,
UNUSED58 = 0x77,
UNUSED1 = 0x78,
UNBOX = 0x79,
THROW = 0x7A,
LDFLD = 0x7B,
LDFLDA = 0x7C,
STFLD = 0x7D,
LDSFLD = 0x7E,
LDSFLDA = 0x7F,
STSFLD = 0x80,
STOBJ = 0x81,
CONV_OVF_I1_UN = 0x82,
CONV_OVF_I2_UN = 0x83,
CONV_OVF_I4_UN = 0x84,
CONV_OVF_I8_UN = 0x85,
CONV_OVF_U1_UN = 0x86,
CONV_OVF_U2_UN = 0x87,
CONV_OVF_U4_UN = 0x88,
CONV_OVF_U8_UN = 0x89,
CONV_OVF_I_UN = 0x8A,
CONV_OVF_U_UN = 0x8B,
BOX = 0x8C,
NEWARR = 0x8D,
LDLEN = 0x8E,
LDELEMA = 0x8F,
LDELEM_I1 = 0x90,
LDELEM_U1 = 0x91,
LDELEM_I2 = 0x92,
LDELEM_U2 = 0x93,
LDELEM_I4 = 0x94,
LDELEM_U4 = 0x95,
LDELEM_I8 = 0x96,
LDELEM_I = 0x97,
LDELEM_R4 = 0x98,
LDELEM_R8 = 0x99,
LDELEM_REF = 0x9A,
STELEM_I = 0x9B,
STELEM_I1 = 0x9C,
STELEM_I2 = 0x9D,
STELEM_I4 = 0x9E,
STELEM_I8 = 0x9F,
STELEM_R4 = 0xA0,
STELEM_R8 = 0xA1,
STELEM_REF = 0xA2,
LDELEM = 0xA3,
STELEM = 0xA4,
UNBOX_ANY = 0xA5,
UNUSED5 = 0xA6,
UNUSED6 = 0xA7,
UNUSED7 = 0xA8,
UNUSED8 = 0xA9,
UNUSED9 = 0xAA,
UNUSED10 = 0xAB,
UNUSED11 = 0xAC,
UNUSED12 = 0xAD,
UNUSED13 = 0xAE,
UNUSED14 = 0xAF,
UNUSED15 = 0xB0,
UNUSED16 = 0xB1,
UNUSED17 = 0xB2,
CONV_OVF_I1 = 0xB3,
CONV_OVF_U1 = 0xB4,
CONV_OVF_I2 = 0xB5,
CONV_OVF_U2 = 0xB6,
CONV_OVF_I4 = 0xB7,
CONV_OVF_U4 = 0xB8,
CONV_OVF_I8 = 0xB9,
CONV_OVF_U8 = 0xBA,
UNUSED50 = 0xBB,
UNUSED18 = 0xBC,
UNUSED19 = 0xBD,
UNUSED20 = 0xBE,
UNUSED21 = 0xBF,
UNUSED22 = 0xC0,
UNUSED23 = 0xC1,
REFANYVAL = 0xC2,
CKFINITE = 0xC3,
UNUSED24 = 0xC4,
UNUSED25 = 0xC5,
MKREFANY = 0xC6,
UNUSED59 = 0xC7,
UNUSED60 = 0xC8,
UNUSED61 = 0xC9,
UNUSED62 = 0xCA,
UNUSED63 = 0xCB,
UNUSED64 = 0xCC,
UNUSED65 = 0xCD,
UNUSED66 = 0xCE,
UNUSED67 = 0xCF,
LDTOKEN = 0xD0,
CONV_U2 = 0xD1,
CONV_U1 = 0xD2,
CONV_I = 0xD3,
CONV_OVF_I = 0xD4,
CONV_OVF_U = 0xD5,
ADD_OVF = 0xD6,
ADD_OVF_UN = 0xD7,
MUL_OVF = 0xD8,
MUL_OVF_UN = 0xD9,
SUB_OVF = 0xDA,
SUB_OVF_UN = 0xDB,
ENDFINALLY = 0xDC,
LEAVE = 0xDD,
LEAVE_S = 0xDE,
STIND_I = 0xDF,
CONV_U = 0xE0
};
enum OpcodeFE {
ARGLIST = 0x00,
CEQ = 0x01,
CGT = 0x02,
CGT_UN = 0x03,
CLT = 0x04,
CLT_UN = 0x05,
LDFTN = 0x06,
LDVIRTFTN = 0x07,
UNUSED56 = 0x08,
LDARG = 0x09,
LDARGA = 0x0A,
STARG = 0x0B,
LDLOC = 0x0C,
LDLOCA = 0x0D,
STLOC = 0x0E,
LOCALLOC = 0x0F,
UNUSED57 = 0x10,
ENDFILTER = 0x11,
UNALIGNED_ = 0x12,
VOLATILE_ = 0x13,
TAIL_ = 0x14,
INITOBJ = 0x15,
CONSTRAINED_ = 0x16,
CPBLK = 0x17,
INITBLK = 0x18,
NO_ = 0x19,
RETHROW = 0x1A,
UNUSED = 0x1B,
SIZEOF = 0x1C,
REFANYTYPE = 0x1D,
READONLY_ = 0x1E,
UNUSED53 = 0x1F,
UNUSED54 = 0x20,
UNUSED55 = 0x21,
UNUSED70 = 0x22
};
} // end namespace n3
#endif