blob: aa9820f002e1af25018a3f323b4e4f1cca64903c [file] [log] [blame]
//===------- VMCache.cpp - Inline cache for virtual calls -----------------===//
//
// N3
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/LLVMContext.h"
#include "mvm/JIT.h"
#include "mvm/Object.h"
#include "mvm/PrintBuffer.h"
#include "mvm/Threads/Locks.h"
#include "Assembly.h"
#include "CLIJit.h"
#include "MSCorlib.h"
#include "N3.h"
#include "VMArray.h"
#include "VMCache.h"
#include "VMClass.h"
#include "VMThread.h"
#include "types.h"
using namespace n3;
using namespace llvm;
void CacheNode::print(mvm::PrintBuffer* buf) const {
buf->write("CacheNode<");
if (lastCible) {
lastCible->print(buf);
buf->write(" -- ");
buf->writePtr(methPtr);
}
buf->write(" in ");
enveloppe->print(buf);
buf->write(">");
}
void Enveloppe::print(mvm::PrintBuffer* buf) const {
buf->write("Enveloppe<>");
}
CacheNode* CacheNode::allocate(mvm::BumpPtrAllocator &allocator) {
CacheNode* cache = new(allocator, "CacheNode") CacheNode();
cache->lastCible = 0;
cache->methPtr = 0;
cache->next = 0;
return cache;
}
Enveloppe* Enveloppe::allocate(mvm::BumpPtrAllocator &allocator, VMMethod* meth) {
Enveloppe* enveloppe = new(allocator, "Enveloppe") Enveloppe();
enveloppe->firstCache = CacheNode::allocate(allocator);
enveloppe->firstCache->enveloppe = enveloppe;
enveloppe->cacheLock = new mvm::LockNormal();
enveloppe->originalMethod = meth;
return enveloppe;
}
void CLIJit::invokeInterfaceOrVirtual(uint32 value, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMMethod* origMeth = compilingClass->assembly->getMethodFromToken(value, genClass, genMethod);
const llvm::FunctionType* funcType = origMeth->getSignature(genMethod);
std::vector<Value*> args;
makeArgs(funcType, args, origMeth->structReturn);
BasicBlock* callBlock = createBasicBlock("call virtual invoke");
PHINode* node = PHINode::Create(CacheNode::llvmType, "", callBlock);
Value* argObj = args[0];
if (argObj->getType() != VMObject::llvmType) {
argObj = new BitCastInst(argObj, VMObject::llvmType, "", currentBlock);
}
JITVerifyNull(argObj);
// ok now the cache
Enveloppe* enveloppe = Enveloppe::allocate(origMeth->classDef->assembly->allocator, origMeth);
compilingMethod->caches.push_back(enveloppe);
Value* zero = module->constantZero;
Value* one = module->constantOne;
Value* two = module->constantTwo;
Value* five = module->constantFive;
Value* llvmEnv =
ConstantExpr::getIntToPtr(ConstantInt::get(Type::getInt64Ty(getGlobalContext()), uint64_t (enveloppe)),
Enveloppe::llvmType);
std::vector<Value*> args1;
args1.push_back(zero);
args1.push_back(one);
Value* cachePtr = GetElementPtrInst::Create(llvmEnv, args1.begin(), args1.end(),
"", currentBlock);
Value* cache = new LoadInst(cachePtr, "", currentBlock);
std::vector<Value*> args2;
args2.push_back(zero);
args2.push_back(VMObject::classOffset());
Value* classPtr = GetElementPtrInst::Create(argObj, args2.begin(),
args2.end(), "",
currentBlock);
Value* cl = new LoadInst(classPtr, "", currentBlock);
std::vector<Value*> args3;
args3.push_back(zero);
args3.push_back(two);
Value* lastCiblePtr = GetElementPtrInst::Create(cache, args3.begin(), args3.end(),
"", currentBlock);
Value* lastCible = new LoadInst(lastCiblePtr, "", currentBlock);
Value* cmp = new ICmpInst(*currentBlock, ICmpInst::ICMP_EQ, cl, lastCible, "");
BasicBlock* ifFalse = createBasicBlock("cache not ok");
BranchInst::Create(callBlock, ifFalse, cmp, currentBlock);
node->addIncoming(cache, currentBlock);
currentBlock = ifFalse;
Value* newCache = invoke(virtualLookupLLVM, cache, argObj, "", ifFalse, false);
node->addIncoming(newCache, currentBlock);
BranchInst::Create(callBlock, currentBlock);
currentBlock = callBlock;
Value* methPtr = GetElementPtrInst::Create(node, args1.begin(), args1.end(),
"", currentBlock);
Value* _meth = new LoadInst(methPtr, "", currentBlock);
Value* meth = new BitCastInst(_meth, PointerType::getUnqual(funcType), "", currentBlock);
std::vector<Value*> args4;
args4.push_back(zero);
args4.push_back(five);
Value* boxedptr = GetElementPtrInst::Create(node, args4.begin(), args4.end(), "", currentBlock);
Value* boxed = new LoadInst(boxedptr, "", currentBlock);
/* I put VMArray::llvmType here, but in should be something else... */
Value* unboxed = new BitCastInst(args[0], VMArray::llvmType, "", currentBlock);
Value* unboxedptr = GetElementPtrInst::Create(unboxed, args1.begin(), args1.end(), "", currentBlock);
Value* fakeunboxedptr = new BitCastInst(unboxedptr, args[0]->getType(), "", currentBlock);
args[0] = SelectInst::Create(boxed, fakeunboxedptr, args[0], "", currentBlock);
Value* ret = invoke(meth, args, "", currentBlock, origMeth->structReturn);
if (ret->getType() != Type::getVoidTy(getGlobalContext())) {
push(ret);
}
}