| #include <map> |
| #include <dlfcn.h> |
| |
| #include "llvm/IR/Module.h" |
| #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| |
| #include "vmkit/allocator.h" |
| #include "vmkit/system.h" |
| |
| #include "j3/j3classloader.h" |
| #include "j3/j3.h" |
| #include "j3/j3reader.h" |
| #include "j3/j3zip.h" |
| #include "j3/j3class.h" |
| #include "j3/j3constants.h" |
| #include "j3/j3method.h" |
| #include "j3/j3lib.h" |
| #include "j3/j3mangler.h" |
| #include "j3/j3thread.h" |
| |
| using namespace j3; |
| |
| J3ClassLoader::J3InterfaceMethodLess J3ClassLoader::j3InterfaceMethodLess; |
| |
| J3ClassLoader::J3ClassLoader(J3ObjectHandle* javaClassLoader, vmkit::BumpAllocator* allocator) |
| : CompilationUnit(allocator, "class-loader", J3Thread::get()->vm()->options()->enableInlining, J3Thread::get()->vm()->options()->isAOT), |
| _globalReferences(allocator), |
| _staticObjectHandles(allocator), |
| _staticObjects(allocator), |
| classes(vmkit::Name::less, allocator), |
| types(vmkit::Name::less, allocator), |
| interfaces(j3InterfaceMethodLess, allocator), |
| methodTypes(vmkit::Name::less, allocator), |
| nativeLibraries(allocator) { |
| pthread_mutex_init(&_mutexClasses, 0); |
| pthread_mutex_init(&_mutexTypes, 0); |
| pthread_mutex_init(&_mutexInterfaces, 0); |
| pthread_mutex_init(&_mutexMethodTypes, 0); |
| pthread_mutex_init(&_mutexNativeLibraries, 0); |
| |
| _javaClassLoader = globalReferences()->add(javaClassLoader); |
| |
| J3* vm = J3Thread::get()->vm(); |
| #define _x(name, id, forceInline) \ |
| { \ |
| llvm::Function* function = vm->introspectFunction(0, id); \ |
| void* addr = dlsym(SELF_HANDLE, function->getName().data()); \ |
| addSymbol(function->getName().data(), new(allocator) vmkit::NativeSymbol(function, addr)); \ |
| } |
| #include "j3/j3meta.def" |
| #undef _x |
| } |
| |
| J3StringSymbol* J3ClassLoader::newStringSymbol(J3ObjectHandle* handle) { |
| size_t num = __sync_fetch_and_add(&_stringSymbolCounter, 1); |
| char buf[256]; |
| snprintf(buf, 256, "jstr%lu", num); |
| size_t len = strlen(buf); |
| char* id = (char*)allocator()->allocate(len+1); |
| memcpy(id, buf, len+1); |
| return new(allocator()) J3StringSymbol(id, handle); |
| } |
| |
| void J3ClassLoader::addNativeLibrary(void* handle) { |
| pthread_mutex_lock(&_mutexNativeLibraries); |
| nativeLibraries.push_back(handle); |
| pthread_mutex_unlock(&_mutexNativeLibraries); |
| } |
| |
| J3ObjectHandle* J3ClassLoader::javaClassLoader(bool doPush) { |
| return (_javaClassLoader && doPush) ? J3Thread::get()->push(_javaClassLoader) : _javaClassLoader; |
| } |
| |
| J3ClassLoader* J3ClassLoader::nativeClassLoader(J3ObjectHandle* jloader) { |
| J3ClassLoader* res = (J3ClassLoader*)jloader->getLong(J3Thread::get()->vm()->classLoaderClassVMData); |
| |
| if(!res) { |
| vmkit::BumpAllocator* allocator = vmkit::BumpAllocator::create(); |
| res = new(allocator) J3ClassLoader(jloader, allocator); |
| jloader->setLong(J3Thread::get()->vm()->classLoaderClassVMData, (uint64_t)(uintptr_t)res); |
| } |
| |
| return res; |
| } |
| |
| uint32_t J3ClassLoader::interfaceIndex(J3Method* method) { |
| pthread_mutex_lock(&_mutexInterfaces); |
| InterfaceMethodRefMap::iterator it = interfaces.find(method); |
| uint32_t res; |
| |
| if(it == interfaces.end()) { |
| res = interfaces.size(); |
| // fprintf(stderr, " new interface: %s::%s%s ---> %d\n", method->cl()->name()->cStr(), method->name()->cStr(), method->signature()->name()->cStr(), res); |
| interfaces[method] = res; |
| } else { |
| res = it->second; |
| } |
| |
| pthread_mutex_unlock(&_mutexInterfaces); |
| |
| return res; |
| } |
| |
| void* J3ClassLoader::lookupNativeFunctionPointer(J3Method* method, const char* symbol) { |
| pthread_mutex_lock(&_mutexNativeLibraries); |
| for(std::vector<void*>::size_type i=0; i!=nativeLibraries.size(); i++) { |
| void* fnPtr = dlsym(nativeLibraries[i], symbol); |
| if(fnPtr) { |
| pthread_mutex_unlock(&_mutexNativeLibraries); |
| return fnPtr; |
| } |
| } |
| pthread_mutex_unlock(&_mutexNativeLibraries); |
| |
| return 0; |
| } |
| |
| J3Class* J3ClassLoader::findLoadedClass(const vmkit::Name* name) { |
| pthread_mutex_lock(&_mutexClasses); |
| std::map<const vmkit::Name*, J3Class*>::iterator it = classes.find(name); |
| J3Class* res = it == classes.end() ? 0 : it->second; |
| pthread_mutex_unlock(&_mutexClasses); |
| return res; |
| } |
| |
| J3Class* J3ClassLoader::defineClass(const vmkit::Name* name, J3ClassBytes* bytes, J3ObjectHandle* protectionDomain, const char* source) { |
| pthread_mutex_lock(&_mutexClasses); |
| J3Class* res = classes[name]; |
| if(!res) |
| classes[name] = res = new(allocator()) J3Class(this, name, bytes, protectionDomain, source); |
| pthread_mutex_unlock(&_mutexClasses); |
| return res; |
| } |
| |
| void J3ClassLoader::aotSnapshot(llvm::Linker* linker) { |
| pthread_mutex_lock(&_mutexClasses); |
| for(vmkit::NameMap<J3Class*>::map::iterator it=classes.begin(); it!=classes.end(); it++) { |
| it->second->aotSnapshot(linker); |
| } |
| pthread_mutex_unlock(&_mutexClasses); |
| } |
| |
| J3Class* J3ClassLoader::loadClass(const vmkit::Name* name) { |
| J3* vm = J3Thread::get()->vm(); |
| return J3Class::nativeClass(vm->classLoaderClassLoadClass->invokeVirtual(_javaClassLoader, vm->nameToString(name)).valObject)->asClass(); |
| } |
| |
| void J3ClassLoader::wrongType(J3ObjectType* from, const char* type, size_t length) { |
| J3::classFormatError(from, "wrong type: %s", J3Thread::get()->vm()->names()->get(type, 0, length)); |
| } |
| |
| J3Type* J3ClassLoader::getTypeInternal(J3ObjectType* from, const char* type, |
| size_t start, size_t len, size_t* pend, bool unify) { |
| J3* vm = J3Thread::get()->vm(); |
| J3Type* res = 0; |
| uint32_t pos = start; |
| uint32_t prof = 0; |
| |
| while(!res) { |
| if(pos >= len) |
| wrongType(from, type, len); |
| |
| switch(type[pos]) { |
| case J3Cst::ID_Array: prof++; pos++; break; |
| #define doIt(id, ctype, llvmType, scale) \ |
| case J3Cst::ID_##id: res = vm->type##id; pos++; break; |
| onJavaTypes(doIt) |
| #undef doIt |
| case J3Cst::ID_Classname: |
| if(unify) { |
| size_t start = ++pos; |
| for(; pos < len && type[pos] != J3Cst::ID_End; pos++); |
| |
| if(type[pos] != J3Cst::ID_End) |
| wrongType(from, type, len); |
| |
| pos++; |
| res = vm->objectClass; |
| } else { |
| size_t start = ++pos; |
| char buf[len + 1 - start], c; |
| |
| memset(buf, 0, len + 1 - pos); |
| |
| for(; pos < len && (c = type[pos]) != J3Cst::ID_End; pos++) |
| buf[pos - start] = c == '/' ? '.' : c; |
| |
| if(type[pos] != J3Cst::ID_End) |
| wrongType(from, type, len); |
| |
| buf[pos++ - start] = 0; |
| |
| res = loadClass(vm->names()->get(buf)); |
| } |
| break; |
| case J3Cst::ID_Left: |
| case J3Cst::ID_Right: |
| default: |
| wrongType(from, type, len); |
| } |
| } |
| |
| *pend = pos; |
| |
| if(prof) { |
| if(unify) |
| res = vm->objectClass; |
| else |
| res = res->getArray(prof); |
| } |
| |
| return res; |
| } |
| |
| J3Type* J3ClassLoader::getTypeFromDescriptor(J3ObjectType* from, const vmkit::Name* typeName) { |
| pthread_mutex_lock(&_mutexTypes); |
| J3Type* res = types[typeName]; |
| pthread_mutex_unlock(&_mutexTypes); |
| |
| if(!res) { |
| const char* type = typeName->cStr(); |
| size_t length = typeName->length(); |
| size_t end; |
| res = getTypeInternal(from, type, 0, length, &end, 0); |
| |
| if(end != length) |
| wrongType(from, type, length); |
| |
| //printf("Analyse %s => %ls\n", type->cStr(), res->name()->cStr()); |
| |
| pthread_mutex_lock(&_mutexTypes); |
| types[typeName] = res; |
| pthread_mutex_unlock(&_mutexTypes); |
| } |
| |
| return res; |
| } |
| |
| J3ObjectType* J3ClassLoader::getTypeFromQualified(J3ObjectType* from, const char* type, size_t length) { |
| if(length == -1) |
| length = strlen(type); |
| |
| J3* vm = J3Thread::get()->vm(); |
| |
| if(type[0] == J3Cst::ID_Array) |
| return getTypeFromDescriptor(from, vm->names()->get(type, 0, length))->asObjectType(); |
| else |
| return loadClass(vm->qualifiedToBinaryName(type, length)); |
| } |
| |
| J3Signature* J3ClassLoader::getSignature(J3ObjectType* from, const vmkit::Name* signature) { |
| pthread_mutex_lock(&_mutexMethodTypes); |
| |
| J3Signature* res = methodTypes[signature]; |
| if(!res) |
| methodTypes[signature] = res = new(allocator()) J3Signature(this, signature); |
| |
| pthread_mutex_unlock(&_mutexMethodTypes); |
| |
| return res; |
| } |
| |
| bool J3ClassLoader::J3InterfaceMethodLess::operator()(j3::J3Method const* lhs, j3::J3Method const* rhs) const { |
| return lhs->name() < rhs->name() |
| || (lhs->name() == rhs->name() |
| && (lhs->signature() < rhs->signature())); |
| } |
| |
| J3InitialClassLoader::J3InitialClassLoader(vmkit::BumpAllocator* _alloc) |
| : J3ClassLoader(0, _alloc) { |
| const char* archives = J3Thread::get()->vm()->options()->bootClasspath; |
| J3ClassBytes* bytes = J3Reader::openFile(allocator(), archives); |
| |
| if (bytes) { |
| archive = new(allocator()) J3ZipArchive(bytes, allocator()); |
| if(!archive) { |
| J3::internalError("unable to find system archive"); |
| } |
| } else |
| J3::internalError("unable to find system archive"); |
| |
| J3Lib::loadSystemLibraries(this); |
| } |
| |
| J3Class* J3InitialClassLoader::loadClass(const vmkit::Name* name) { |
| J3Class* res = findLoadedClass(name); |
| |
| if(res) |
| return res; |
| |
| char tmp[name->length()+16]; |
| |
| //printf("L: %s\n", name->cStr()); |
| for(int i=0; i<name->length(); i++) { |
| char c = name->cStr()[i] & 0xff; |
| tmp[i] = c == '.' ? '/' : c; |
| } |
| strcpy(tmp + name->length(), ".class"); |
| J3ZipFile* file = archive->getFile(tmp); |
| |
| if(file) { |
| J3ClassBytes* bytes = new(allocator(), file->ucsize) J3ClassBytes(file->ucsize); |
| |
| if(archive->readFile(bytes, file)) |
| return defineClass(name, bytes, 0, 0); |
| } |
| |
| return 0; |
| } |
| |
| void J3InitialClassLoader::registerCMangling(const char* mangled, const char* demangled) { |
| _cmangled[demangled] = mangled; |
| } |
| |
| |
| |