| //===--------------- 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 <vector> |
| #include <stdarg.h> |
| |
| #include "llvm/Function.h" |
| #include "llvm/Module.h" |
| #include "llvm/LLVMContext.h" |
| #include "llvm/Support/CommandLine.h" |
| |
| #include "mvm/Object.h" |
| #include "mvm/PrintBuffer.h" |
| #include "mvm/Threads/Cond.h" |
| #include "mvm/Threads/Locks.h" |
| #include "mvm/JIT.h" |
| |
| #include "types.h" |
| |
| #include "Assembly.h" |
| #include "LinkN3Runtime.h" |
| #include "LockedMap.h" |
| #include "MSCorlib.h" |
| #include "N3.h" |
| #include "N3ModuleProvider.h" |
| #include "Reader.h" |
| #include "VMArray.h" |
| #include "VMClass.h" |
| #include "VMObject.h" |
| #include "VMThread.h" |
| #include "CLIJit.h" |
| #include "CLIString.h" |
| |
| |
| using namespace n3; |
| |
| #define DECLARE_EXCEPTION(EXCP) \ |
| const char* N3::EXCP = #EXCP |
| |
| DECLARE_EXCEPTION(SystemException); |
| DECLARE_EXCEPTION(OverFlowException); |
| DECLARE_EXCEPTION(OutOfMemoryException); |
| DECLARE_EXCEPTION(IndexOutOfRangeException); |
| DECLARE_EXCEPTION(NullReferenceException); |
| DECLARE_EXCEPTION(SynchronizationLocException); |
| DECLARE_EXCEPTION(ThreadInterruptedException); |
| DECLARE_EXCEPTION(MissingMethodException); |
| DECLARE_EXCEPTION(MissingFieldException); |
| DECLARE_EXCEPTION(ArrayTypeMismatchException); |
| DECLARE_EXCEPTION(ArgumentException); |
| |
| /* |
| DECLARE_EXCEPTION(ArithmeticException); |
| DECLARE_EXCEPTION(InvocationTargetException); |
| DECLARE_EXCEPTION(ArrayStoreException); |
| DECLARE_EXCEPTION(ClassCastException); |
| DECLARE_EXCEPTION(ArrayIndexOutOfBoundsException); |
| DECLARE_EXCEPTION(SecurityException); |
| DECLARE_EXCEPTION(ClassFormatError); |
| DECLARE_EXCEPTION(ClassCircularityError); |
| DECLARE_EXCEPTION(NoClassDefFoundError); |
| DECLARE_EXCEPTION(UnsupportedClassVersionError); |
| DECLARE_EXCEPTION(NoSuchFieldError); |
| DECLARE_EXCEPTION(NoSuchMethodError); |
| DECLARE_EXCEPTION(InstantiationError); |
| DECLARE_EXCEPTION(IllegalAccessError); |
| DECLARE_EXCEPTION(IllegalAccessException); |
| DECLARE_EXCEPTION(VerifyError); |
| DECLARE_EXCEPTION(ExceptionInInitializerError); |
| DECLARE_EXCEPTION(LinkageError); |
| DECLARE_EXCEPTION(AbstractMethodError); |
| DECLARE_EXCEPTION(UnsatisfiedLinkError); |
| DECLARE_EXCEPTION(InternalError); |
| DECLARE_EXCEPTION(StackOverflowError); |
| DECLARE_EXCEPTION(ClassNotFoundException); |
| */ |
| |
| #undef DECLARE_EXCEPTION |
| |
| void ThreadSystem::print(mvm::PrintBuffer* buf) const { |
| buf->write("ThreadSystem<>"); |
| } |
| |
| ThreadSystem::ThreadSystem() { |
| nonDaemonThreads = 1; |
| nonDaemonLock = new mvm::LockNormal(); |
| nonDaemonVar = new mvm::Cond(); |
| } |
| |
| N3::N3(mvm::BumpPtrAllocator &allocator, const char *name) : mvm::VirtualMachine(allocator) { |
| this->module = 0; |
| this->TheModuleProvider = 0; |
| this->name = name; |
| |
| this->scanner = new mvm::UnpreciseStackScanner(); |
| this->LLVMModule = new llvm::Module(name, llvm::getGlobalContext()); |
| this->module = new mvm::BaseIntrinsics(this->LLVMModule); |
| |
| this->LLVMModule->setDataLayout(mvm::MvmModule::executionEngine->getTargetData()->getStringRepresentation()); |
| this->protectModule = new mvm::LockNormal(); |
| |
| this->functions = new(allocator, "FunctionMap") FunctionMap(); |
| this->loadedAssemblies = new(allocator, "AssemblyMap") AssemblyMap(); |
| |
| this->TheModuleProvider = new N3ModuleProvider(this->LLVMModule, this->functions); |
| } |
| |
| N3::~N3() { |
| delete module; |
| delete TheModuleProvider; |
| } |
| |
| void N3::error(const char* className, const char* fmt, va_list ap) { |
| fprintf(stderr, "Internal exception of type %s during bootstrap: ", className); |
| vfprintf(stderr, fmt, ap); |
| throw 1; |
| } |
| |
| void N3::indexOutOfBounds(const VMObject* obj, sint32 entry) { |
| error(IndexOutOfRangeException, "%d", entry); |
| } |
| |
| void N3::negativeArraySizeException(sint32 size) { |
| error(OverFlowException, "%d", size); |
| } |
| |
| void N3::nullPointerException(const char* fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| error(NullReferenceException, fmt, va_arg(ap, char*)); |
| } |
| |
| |
| void N3::illegalMonitorStateException(const VMObject* obj) { |
| error(SynchronizationLocException, ""); |
| } |
| |
| void N3::interruptedException(const VMObject* obj) { |
| error(ThreadInterruptedException, ""); |
| } |
| |
| void N3::outOfMemoryError(sint32 n) { |
| error(OutOfMemoryException, ""); |
| } |
| |
| void N3::arrayStoreException() { |
| error(ArrayTypeMismatchException, ""); |
| } |
| |
| void N3::illegalArgumentException(const char* name) { |
| error(ArgumentException, name); |
| } |
| |
| void N3::unknownError(const char* fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| error(SystemException, fmt, ap); |
| } |
| |
| void N3::error(const char* fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| error(SystemException, fmt, ap); |
| } |
| |
| void N3::error(const char* name, const char* fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| error(name, fmt, ap); |
| } |
| |
| |
| |
| |
| using namespace n3; |
| |
| void N3::print(mvm::PrintBuffer* buf) const { |
| buf->write("N3 virtual machine<>"); |
| } |
| |
| static Assembly* assemblyDup(const UTF8*& name, N3* vm) { |
| mvm::BumpPtrAllocator *a = new mvm::BumpPtrAllocator(); |
| return new(*a, "Assembly") Assembly(*a, vm, name); |
| } |
| |
| Assembly* N3::constructAssembly(const UTF8* name) { |
| return loadedAssemblies->lookupOrCreate(name, this, assemblyDup); |
| } |
| |
| Assembly* N3::lookupAssembly(const UTF8* name) { |
| return loadedAssemblies->lookup(name); |
| } |
| |
| VMMethod* N3::lookupFunction(Function* F) { |
| return functions->lookup(F); |
| } |
| |
| |
| N3* N3::allocateBootstrap() { |
| mvm::BumpPtrAllocator *a = new mvm::BumpPtrAllocator(); |
| N3 *vm= new(*a, "VM") N3(*a, "bootstrapN3"); |
| |
| vm->hashUTF8 = new(vm->allocator, "UTF8Map") UTF8Map(vm->allocator); |
| |
| CLIJit::initialiseBootstrapVM(vm); |
| |
| return vm; |
| } |
| |
| |
| N3* N3::allocate(const char* name, N3* parent) { |
| mvm::BumpPtrAllocator *a = new mvm::BumpPtrAllocator(); |
| N3 *vm= new(*a, "VM") N3(*a, name); |
| |
| vm->hashUTF8 = parent->hashUTF8; |
| |
| vm->threadSystem = new(*a, "ThreadSystem") ThreadSystem(); |
| |
| vm->assemblyPath = parent->assemblyPath; |
| vm->coreAssembly = parent->coreAssembly; |
| vm->loadedAssemblies->hash(parent->coreAssembly->name, parent->coreAssembly); |
| |
| CLIJit::initialiseAppDomain(vm); |
| |
| return vm; |
| } |
| |
| 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; |
| } |
| |
| void N3::executeAssembly(const char* _name, ArrayObject* args) { |
| const UTF8* name = asciizToUTF8(_name); |
| Assembly* assembly = constructAssembly(name); |
| |
| if(!assembly->resolve(1, 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->compileToNative()->invokeGeneric(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->MyVM = this; |
| bootstrapThread->start((void (*)(mvm::Thread*))mainCLIStart); |
| |
| } else { |
| --(threadSystem->nonDaemonThreads); |
| } |
| } |
| |
| void N3::mainCLIStart(VMThread* th) { |
| N3* vm = (N3*)th->getVM(); |
| MSCorlib::loadBootstrap(vm); |
| |
| ClArgumentsInfo& info = vm->argumentsInfo; |
| declare_gcroot(ArrayObject*, args) = (ArrayObject*)MSCorlib::arrayString->doNew(info.argc-2); |
| for (int i = 2; i < info.argc; ++i) { |
| declare_gcroot(ArrayChar*, arg_array) = vm->asciizToArray(info.argv[i]); |
| declare_gcroot(VMObject*, arg) = vm->arrayToString(arg_array); |
| args->elements[i - 2] = arg; |
| } |
| |
| try{ |
| vm->executeAssembly(info.assembly, args); |
| }catch(...) { |
| declare_gcroot(VMObject*, exc) = th->ooo_pendingException; |
| printf("N3 caught %s\n", mvm::PrintBuffer(exc).cString()); |
| } |
| |
| vm->threadSystem->nonDaemonLock->lock(); |
| --(vm->threadSystem->nonDaemonThreads); |
| if (vm->threadSystem->nonDaemonThreads == 0) |
| vm->threadSystem->nonDaemonVar->signal(); |
| vm->threadSystem->nonDaemonLock->unlock(); |
| } |
| |
| |
| |
| ArrayChar* N3::asciizToArray(const char* asciiz) { |
| uint32 len = strlen(asciiz); |
| declare_gcroot(ArrayChar*, res) = (ArrayChar*)MSCorlib::arrayChar->doNew(len); |
| for(uint32 i=0; i<len; i++) |
| res->elements[i] = asciiz[i]; |
| return res; |
| } |
| |
| ArrayChar* N3::bufToArray(const uint16* buf, uint32 size) { |
| declare_gcroot(ArrayChar*, res) = (ArrayChar*)MSCorlib::arrayChar->doNew(size); |
| memcpy(res->elements, buf, size<<1); |
| return res; |
| } |
| |
| ArrayChar* N3::UTF8ToArray(const UTF8 *utf8) { |
| declare_gcroot(ArrayChar*, res) = bufToArray(utf8->elements, utf8->size); |
| return res; |
| } |
| |
| const UTF8* N3::asciizToUTF8(const char* asciiz) { |
| return hashUTF8->lookupOrCreateAsciiz(asciiz); |
| } |
| |
| const UTF8* N3::bufToUTF8(const uint16* buf, uint32 len) { |
| return hashUTF8->lookupOrCreateReader(buf, len); |
| } |
| |
| const UTF8* N3::arrayToUTF8(const ArrayChar *array) { |
| return bufToUTF8(array->elements, array->size); |
| } |
| |
| CLIString *N3::arrayToString(const ArrayChar *array) { |
| declare_gcroot(CLIString*, res) = (CLIString*)CLIString::stringDup(array, this); |
| return res; |
| } |
| |
| #include "MSCorlib.inc" |