blob: 6fb42ba7467fad503b08516626014bc8a65ebe9e [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/Module.h"
#include "llvm/Support/CommandLine.h"
#include "types.h"
#include "Assembly.h"
#include "CLIJit.h"
#include "CLIString.h"
#include "LockedMap.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() {
N3 *vm= gc_new(N3)();
vm->module = new llvm::Module("Bootstrap N3");
vm->protectModule = mvm::Lock::allocNormal();
vm->functions = FunctionMap::allocate();
vm->TheModuleProvider = new N3ModuleProvider(vm->module, vm->functions);
CLIJit::initialiseBootstrapVM(vm);
vm->bootstrapThread = VMThread::allocate(0, vm);
VMThread::threadKey->set(vm->bootstrapThread);
vm->name = "bootstrapN3";
vm->hashUTF8 = UTF8Map::allocate();
vm->hashStr = StringMap::allocate();
vm->loadedAssemblies = AssemblyMap::allocate();
return vm;
}
N3* N3::allocate(char* name, N3* parent) {
N3 *vm= gc_new(N3)();
vm->module = new llvm::Module("App Domain");
vm->protectModule = mvm::Lock::allocNormal();
vm->functions = FunctionMap::allocate();
vm->TheModuleProvider = new N3ModuleProvider(vm->module, vm->functions);
CLIJit::initialiseAppDomain(vm);
vm->bootstrapThread = VMThread::allocate(0, vm);
VMThread::threadKey->set(vm->bootstrapThread);
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())) {
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;
}
class ClArgumentsInfo {
public:
uint32 appArgumentsPos;
char* assembly;
void readArgs(int argc, char** argv, N3 *vm);
void printInformation();
void nyi();
void printVersion();
};
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::mapInitialThread() {
VMClass* cl = (VMClass*)coreAssembly->loadTypeFromName(
asciizConstructUTF8("Thread"),
asciizConstructUTF8("System.Threading"),
true, true, true, true);
VMObject* th = (*cl)();
std::vector<VMCommonClass*> args;
args.push_back(N3::pVoid);
args.push_back(cl);
args.push_back(N3::pIntPtr);
VMMethod* meth = cl->lookupMethod(asciizConstructUTF8(".ctor"), args,
false, false);
VMThread* myth = VMThread::get();
(*meth)(th, myth);
myth->vmThread = th;
}
void N3::loadBootstrap() {
mapInitialThread();
}
void N3::waitForExit() {
threadSystem->nonDaemonLock->lock();
--(threadSystem->nonDaemonThreads);
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 found 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);
VMMethod* mainMeth = assembly->lookupMethodFromToken(entryPoint);
(*mainMeth)(args);
}
}
}
void N3::runMain(int argc, char** argv) {
ClArgumentsInfo info;
info.readArgs(argc, argv, this);
if (info.assembly) {
int pos = info.appArgumentsPos;
llvm::cl::ParseCommandLineOptions(pos, argv,
"N3 CLI virtual machine\n");
argv = argv + info.appArgumentsPos - 1;
argc = argc - info.appArgumentsPos + 1;
loadBootstrap();
ArrayObject* args = ArrayObject::acons(argc - 2, arrayString);
for (int i = 2; i < argc; ++i) {
args->setAt(i - 2, (VMObject*)asciizToStr(argv[i]));
}
try{
executeAssembly(info.assembly, args);
}catch(...) {
printf("N3 catched it\n");
}
waitForExit();
}
}