blob: 27865e714403c3b453ff9b172b6a1968938fdaf2 [file] [log] [blame]
//===--------------- N3.cpp - The N3 virtual machine ----------------------===//
//
// N3
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "mvm/JIT.h"
#include "types.h"
#include "Assembly.h"
#include "CLIJit.h"
#include "CLIString.h"
#include "LinkN3Runtime.h"
#include "LockedMap.h"
#include "MSCorlib.h"
#include "N3.h"
#include "N3ModuleProvider.h"
#include "Reader.h"
#include "VirtualMachine.h"
#include "VMClass.h"
#include "VMObject.h"
#include "VMThread.h"
using namespace n3;
void N3::print(mvm::PrintBuffer* buf) const {
buf->write("N3 virtual machine<>");
}
VMObject* N3::asciizToStr(const char* asciiz) {
const UTF8* var = asciizConstructUTF8(asciiz);
return UTF8ToStr(var);
}
VMObject* N3::UTF8ToStr(const UTF8* utf8) {
VMObject* res = CLIString::stringDup(utf8, this);
//VMObject* res = hashStr->lookupOrCreate(utf8, this, CLIString::stringDup);
return res;
}
static Assembly* assemblyDup(const UTF8*& name, N3* vm) {
Assembly* res = Assembly::allocate(name);
return res;
}
Assembly* N3::constructAssembly(const UTF8* name) {
return loadedAssemblies->lookupOrCreate(name, this, assemblyDup);
}
Assembly* N3::lookupAssembly(const UTF8* name) {
return loadedAssemblies->lookup(name);
}
N3* N3::allocateBootstrap() {
mvm::BumpPtrAllocator * A = new mvm::BumpPtrAllocator();
N3 *vm= new(*A, "VM") N3();
std::string str =
mvm::MvmModule::executionEngine->getTargetData()->getStringRepresentation();
vm->LLVMModule = new llvm::Module("Bootstrap N3", llvm::getGlobalContext());
vm->module = new mvm::MvmModule(vm->LLVMModule);
vm->getLLVMModule()->setDataLayout(str);
vm->protectModule = new mvm::LockNormal();
vm->functions = FunctionMap::allocate();
vm->TheModuleProvider = new N3ModuleProvider(vm->LLVMModule, vm->functions);
CLIJit::initialiseBootstrapVM(vm);
vm->name = "bootstrapN3";
vm->hashUTF8 = UTF8Map::allocate();
vm->hashStr = StringMap::allocate();
vm->loadedAssemblies = AssemblyMap::allocate();
return vm;
}
N3* N3::allocate(const char* name, N3* parent) {
mvm::BumpPtrAllocator * A = new mvm::BumpPtrAllocator();
N3 *vm= new(*A, "VM") N3();
std::string str =
mvm::MvmModule::executionEngine->getTargetData()->getStringRepresentation();
vm->LLVMModule = new llvm::Module("Bootstrap N3", llvm::getGlobalContext());
vm->module = new mvm::MvmModule(vm->LLVMModule);
vm->LLVMModule->setDataLayout(str);
vm->protectModule = new mvm::LockNormal();
vm->functions = FunctionMap::allocate();
vm->TheModuleProvider = new N3ModuleProvider(vm->LLVMModule, vm->functions);
CLIJit::initialiseAppDomain(vm);
vm->threadSystem = ThreadSystem::allocateThreadSystem();
vm->name = name;
vm->hashUTF8 = parent->hashUTF8;
vm->hashStr = StringMap::allocate();
vm->loadedAssemblies = AssemblyMap::allocate();
vm->assemblyPath = parent->assemblyPath;
vm->coreAssembly = parent->coreAssembly;
vm->loadedAssemblies->hash(parent->coreAssembly->name, parent->coreAssembly);
return vm;
}
ArrayUInt8* N3::openAssembly(const UTF8* name, const char* ext) {
char* asciiz = name->UTF8ToAsciiz();
uint32 alen = strlen(asciiz);
ArrayUInt8* res = 0;
uint32 idx = 0;
while ((res == 0) && (idx < assemblyPath.size())) {
const char* cur = assemblyPath[idx];
uint32 strLen = strlen(cur);
char* buf = (char*)alloca(strLen + alen + 16);
if (ext != 0) {
sprintf(buf, "%s%s.%s", cur, asciiz, ext);
} else {
sprintf(buf, "%s%s", cur, asciiz);
}
res = Reader::openFile(buf);
++idx;
}
return res;
}
void ClArgumentsInfo::nyi() {
fprintf(stdout, "Not yet implemented\n");
}
void ClArgumentsInfo::printVersion() {
fprintf(stdout, "N3 -- a VVM implementation of the Common Language Infrastructure\n");
}
void ClArgumentsInfo::printInformation() {
fprintf(stdout,
"Usage: n3 [-options] assembly [args...] \n"
"No option is available\n");
}
void ClArgumentsInfo::readArgs(int argc, char** argv, N3* n3) {
assembly = 0;
appArgumentsPos = 0;
sint32 i = 1;
if (i == argc) printInformation();
while (i < argc) {
char* cur = argv[i];
if (cur[0] == '-') {
} else {
assembly = cur;
appArgumentsPos = i;
return;
}
++i;
}
}
void N3::waitForExit() {
threadSystem->nonDaemonLock->lock();
while (threadSystem->nonDaemonThreads) {
threadSystem->nonDaemonVar->wait(threadSystem->nonDaemonLock);
}
threadSystem->nonDaemonLock->unlock();
return;
}
Assembly* N3::loadAssembly(const UTF8* name, const char* ext) {
Assembly* ass = lookupAssembly(name);
if (ass == 0 || !ass->isRead) {
ArrayUInt8* bytes = openAssembly(name, ext);
if (bytes != 0) {
if (ass == 0) ass = constructAssembly(name);
ass->bytes = bytes;
ass->vm = this;
ass->read();
ass->isRead = true;
}
}
return ass;
}
void N3::executeAssembly(const char* _name, ArrayObject* args) {
const UTF8* name = asciizConstructUTF8(_name);
Assembly* assembly = loadAssembly(name, 0);
if (assembly == 0) {
error("Can not find assembly %s", _name);
} else {
uint32 entryPoint = assembly->entryPoint;
uint32 table = entryPoint >> 24;
if (table != CONSTANT_MethodDef) {
error("Entry point does not point to a method");
} else {
uint32 typeToken = assembly->getTypeDefTokenFromMethod(entryPoint);
assembly->loadType(this, typeToken, true, true, true ,true, NULL, NULL);
VMMethod* mainMeth = assembly->lookupMethodFromToken(entryPoint);
(*mainMeth)(args);
}
}
}
void N3::runMain(int argc, char** argv) {
ClArgumentsInfo& info = argumentsInfo;
info.readArgs(argc, argv, this);
if (info.assembly) {
info.argv = argv + info.appArgumentsPos - 1;
info.argc = argc - info.appArgumentsPos + 1;
bootstrapThread = VMThread::TheThread;
bootstrapThread->vm = this;
bootstrapThread->start((void (*)(mvm::Thread*))mainCLIStart);
} else {
--(threadSystem->nonDaemonThreads);
}
}
void N3::mainCLIStart(VMThread* th) {
N3* vm = (N3*)th->vm;
MSCorlib::loadBootstrap(vm);
ClArgumentsInfo& info = vm->argumentsInfo;
ArrayObject* args = ArrayObject::acons(info.argc - 2, MSCorlib::arrayString);
for (int i = 2; i < info.argc; ++i) {
args->setAt(i - 2, (VMObject*)vm->asciizToStr(info.argv[i]));
}
try{
vm->executeAssembly(info.assembly, args);
}catch(...) {
VMObject* exc = th->pendingException;
printf("N3 caught %s\n", exc->printString());
}
vm->threadSystem->nonDaemonLock->lock();
--(vm->threadSystem->nonDaemonThreads);
if (vm->threadSystem->nonDaemonThreads == 0)
vm->threadSystem->nonDaemonVar->signal();
vm->threadSystem->nonDaemonLock->unlock();
}
#include "MSCorlib.inc"