/* Copyright (c) 2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "machine.h" #include "classpath-common.h" #include "util.h" #ifdef PLATFORM_WINDOWS # include # include # include # include # include # include # include # include # undef interface # define CLOSE _close # define READ _read # define WRITE _write # define FSTAT _fstat # define STAT _stat # define LSEEK _lseek # define S_ISSOCK(x) false # ifdef _MSC_VER # define S_ISREG(x) ((x) | _S_IFREG) # define S_ISDIR(x) ((x) | _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE # else # define OPEN _open # define CREAT _creat # endif # define O_RDONLY _O_RDONLY # ifdef AVIAN_OPENJDK_SRC # define EXPORT(x) x # else # define EXPORT(x) _##x # endif typedef int socklen_t; # define RTLD_DEFAULT 0 #else // not PLATFORM_WINDOWS # include # include # include # include # include # include # include # include # include # define OPEN open # define CLOSE close # define READ read # define WRITE write # define STAT stat # define FSTAT fstat # define LSEEK lseek # define EXPORT(x) x #endif // not PLATFORM_WINDOWS using namespace vm; namespace { #ifdef _MSC_VER inline int OPEN(string_t path, int mask, int mode) { int fd; if (_wsopen_s(&fd, path, mask, _SH_DENYNO, mode) == 0) { return fd; } else { return -1; } } inline int CREAT(string_t path, int mode) { return OPEN(path, _O_CREAT, mode); } #endif namespace local { const unsigned InterfaceVersion = 4; const unsigned PageSize = 4 * 1024; const int VirtualFileBase = 1000000000; Machine* globalMachine; const char* primitiveName(Thread* t, object c) { if (c == primitiveClass(t, 'V')) { return "void"; } else if (c == primitiveClass(t, 'Z')) { return "boolean"; } else if (c == primitiveClass(t, 'B')) { return "byte"; } else if (c == primitiveClass(t, 'C')) { return "char"; } else if (c == primitiveClass(t, 'S')) { return "short"; } else if (c == primitiveClass(t, 'I')) { return "int"; } else if (c == primitiveClass(t, 'F')) { return "float"; } else if (c == primitiveClass(t, 'J')) { return "long"; } else if (c == primitiveClass(t, 'D')) { return "double"; } else { abort(t); } } object getClassName(Thread* t, object c) { if (className(t, c) == 0) { if (classVmFlags(t, c) & PrimitiveFlag) { PROTECT(t, c); object name = makeByteArray(t, primitiveName(t, c)); set(t, c, ClassName, name); } else { abort(t); } } return className(t, c); } object makeClassNameString(Thread* t, object name) { THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, name)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, name, 0))); return makeString(t, "%s", s); } void interceptFileOperations(Thread*); class MyClasspath : public Classpath { public: static const unsigned BufferSize = 1024; MyClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix): allocator(allocator), ranNetOnLoad(0) { class StringBuilder { public: StringBuilder(System* s, char* pointer, unsigned remaining): s(s), pointer(pointer), remaining(remaining) { } void append(const char* append) { unsigned length = strlen(append); expect(s, remaining > length); strncpy(pointer, append, remaining); remaining -= length; pointer += length; } void append(char c) { assert(s, remaining > 1); pointer[0] = c; pointer[1] = 0; -- remaining; ++ pointer; } System* s; char* pointer; unsigned remaining; } sb(s, buffer, BufferSize); this->javaHome = sb.pointer; sb.append(javaHome); sb.append('\0'); this->classpath = sb.pointer; sb.append(AVIAN_CLASSPATH); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/rt.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/jsse.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/jce.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/resources.jar"); sb.append('\0'); this->libraryPath = sb.pointer; sb.append(javaHome); #ifdef PLATFORM_WINDOWS sb.append("/bin"); #elif defined ARCH_x86_64 sb.append("/lib/amd64"); #else // todo: handle other architectures sb.append("/lib/i386"); #endif sb.append('\0'); this->tzMappings = sb.pointer; sb.append(javaHome); sb.append("/lib/tzmappings"); this->tzMappingsLength = sb.pointer - tzMappings; sb.append('\0'); this->embedPrefix = sb.pointer; sb.append(embedPrefix); this->embedPrefixLength = sb.pointer - this->embedPrefix; } virtual object makeJclass(Thread* t, object class_) { PROTECT(t, class_); object name = makeClassNameString(t, getClassName(t, class_)); return vm::makeJclass (t, 0, 0, name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, class_); } virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) { if (objectClass(t, array) == type(t, Machine::ByteArrayType)) { PROTECT(t, array); object charArray = makeCharArray(t, length); for (int i = 0; i < length; ++i) { charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); } array = charArray; } return vm::makeString(t, array, offset, length, 0); } virtual object makeThread(Thread* t, Thread* parent) { const unsigned MaxPriority = 10; const unsigned NormalPriority = 5; object group; if (parent) { group = threadGroup(t, parent->javaThread); } else { group = allocate(t, FixedSizeOfThreadGroup, true); setObjectClass(t, group, type(t, Machine::ThreadGroupType)); threadGroupMaxPriority(t, group) = MaxPriority; } PROTECT(t, group); object thread = allocate(t, FixedSizeOfThread, true); setObjectClass(t, thread, type(t, Machine::ThreadType)); threadPriority(t, thread) = NormalPriority; threadGroup(t, thread) = group; threadContextClassLoader(t, thread) = root(t, Machine::BootLoader); PROTECT(t, thread); const unsigned BufferSize = 256; char buffer[BufferSize]; unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); object name = makeCharArray(t, length); for (unsigned i = 0; i < length; ++i) { charArrayBody(t, name, i) = buffer[i]; } set(t, thread, ThreadName, name); return thread; } virtual void runThread(Thread* t) { object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); t->m->processor->invoke(t, method, t->javaThread); acquire(t, t->javaThread); t->flags &= ~Thread::ActiveFlag; notifyAll(t, t->javaThread); release(t, t->javaThread); } virtual void boot(Thread* t) { globalMachine = t->m; resolveSystemClass(t, root(t, Machine::BootLoader), className(t, type(t, Machine::ClassLoaderType))); #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t); #else // not AVIAN_OPENJDK_SRC if (loadLibrary(t, libraryPath, "verify", true, true) == 0 or loadLibrary(t, libraryPath, "java", true, true) == 0) { abort(t); } #endif // not AVIAN_OPENJDK_SRC object constructor = resolveMethod (t, type(t, Machine::ClassLoaderType), "", "(Ljava/lang/ClassLoader;)V"); PROTECT(t, constructor); t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); t->m->processor->invoke (t, constructor, root(t, Machine::AppLoader), root(t, Machine::BootLoader)); object scl = resolveField (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); PROTECT(t, scl); object sclSet = resolveField (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, scl), root(t, Machine::AppLoader)); cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, sclSet)) = true; t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", "initializeSystemClass", "()V", 0); } virtual const char* bootClasspath() { return classpath; } virtual void dispose() { allocator->free(this, sizeof(*this)); } Allocator* allocator; const char* javaHome; const char* classpath; const char* libraryPath; const char* tzMappings; const char* embedPrefix; unsigned tzMappingsLength; unsigned embedPrefixLength; unsigned filePathField; unsigned fileDescriptorFdField; unsigned fileInputStreamFdField; bool ranNetOnLoad; char buffer[BufferSize]; }; struct JVM_ExceptionTableEntryType { jint start_pc; jint end_pc; jint handler_pc; jint catchType; }; struct jvm_version_info { unsigned jvm_version; unsigned update_version: 8; unsigned special_update_version: 8; unsigned reserved1: 16; unsigned reserved2; unsigned is_attach_supported: 1; unsigned is_kernel_jvm: 1; unsigned: 30; unsigned: 32; unsigned: 32; }; Finder* getFinder(Thread* t, const char* name, unsigned nameLength) { ACQUIRE(t, t->m->referenceLock); for (object p = root(t, Machine::VirtualFileFinders); p; p = finderNext(t, p)) { if (byteArrayLength(t, finderName(t, p)) == nameLength and strncmp(reinterpret_cast (&byteArrayBody(t, finderName(t, p), 0)), name, nameLength)) { return static_cast(finderFinder(t, p)); } } object n = makeByteArray(t, nameLength + 1); memcpy(&byteArrayBody(t, n, 0), name, nameLength); void* p = t->m->libraries->resolve (reinterpret_cast(&byteArrayBody(t, n, 0))); if (p) { uint8_t* (*function)(unsigned*); memcpy(&function, &p, BytesPerWord); unsigned size; uint8_t* data = function(&size); if (data) { Finder* f = makeFinder(t->m->system, t->m->heap, data, size); object finder = makeFinder (t, f, n, root(t, Machine::VirtualFileFinders)); setRoot(t, Machine::VirtualFileFinders, finder); return f; } } return 0; } bool pathEqual(const char* a, const char* b, unsigned length) { #ifdef PLATFORM_WINDOWS return strncasecmp(a, b, length) == 0; #else return strncmp(a, b, length) == 0; #endif } bool pathEqual(const char* a, const char* b) { #ifdef PLATFORM_WINDOWS return strcasecmp(a, b) == 0; #else return strcmp(a, b) == 0; #endif } class EmbeddedFile { public: EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) { if (pathEqual(cp->embedPrefix, path, cp->embedPrefixLength)) { const char* p = path + cp->embedPrefixLength; while (*p == '/') ++ p; this->jar = p; if (*p == 0) { this->jarLength = 0; this->path = 0; this->pathLength = 0; return; } while (*p and *p != '/') ++p; this->jarLength = p - this->jar; while (*p == '/') ++p; this->path = p; this->pathLength = pathLength - (p - path); } else { this->jar = 0; this->jarLength =0; this->path = 0; this->pathLength = 0; } } const char* jar; const char* path; unsigned jarLength; unsigned pathLength; }; int64_t JNICALL getFileAttributes (Thread* t, object method, uintptr_t* arguments) { const unsigned Exists = 1; const unsigned Regular = 2; const unsigned Directory = 4; MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); object path = cast(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return Exists | Directory; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return Exists | Directory; } unsigned length; System::FileType type = finder->stat(ef.path, &length, true); switch (type) { case System::TypeUnknown: return Exists; case System::TypeDoesNotExist: return 0; case System::TypeFile: return Exists | Regular; case System::TypeDirectory: return Exists | Directory; default: abort(t); } } else { return 0; } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file)); } } int64_t JNICALL checkFileAccess (Thread* t, object method, uintptr_t* arguments) { const unsigned Read = 4; MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); unsigned mask = arguments[2]; object path = cast(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return mask == Read; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return mask == Read; } unsigned length; System::FileType type = finder->stat(ef.path, &length, true); switch (type) { case System::TypeDoesNotExist: return false; case System::TypeUnknown: case System::TypeFile: case System::TypeDirectory: return mask == Read; default: abort(t); } } else { return 0; } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file, mask)) != 0; } } int64_t JNICALL getFileLength (Thread* t, object method, uintptr_t* arguments) { MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); object path = cast(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return 0; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return 0; } unsigned fileLength; finder->stat(ef.path, &fileLength); return fileLength; } return 0; } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file)); } } void JNICALL openFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object path = reinterpret_cast(arguments[1]); MyClasspath* cp = static_cast(t->m->classpath); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } System::Region* r = finder->find(ef.path); if (r == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } PROTECT(t, this_); ACQUIRE(t, t->m->referenceLock); int index = -1; unsigned oldLength = root(t, Machine::VirtualFiles) ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; for (unsigned i = 0; i < oldLength; ++i) { if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { index = i; break; } } if (index == -1) { object newArray = growArray(t, root(t, Machine::VirtualFiles)); setRoot(t, Machine::VirtualFiles, newArray); index = oldLength; } object region = makeRegion(t, r, 0); set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), region); cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField) = index + VirtualFileBase; } else { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, path); } } int64_t JNICALL readByteFromFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); if (r->length() > regionPosition(t, region)) { return r->start()[regionPosition(t, region)++]; } else { return -1; } } else { throwNew(t, Machine::IoExceptionType); } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_)); } } int64_t JNICALL readBytesFromFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object dst = reinterpret_cast(arguments[1]); int32_t offset = arguments[2]; int32_t length = arguments[3]; MyClasspath* cp = static_cast(t->m->classpath); int fd = cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); int available = r->length() - regionPosition(t, region); if (available == 0) { return -1; } if (length > available) { length = available; } memcpy(&byteArrayBody(t, dst, offset), r->start() + regionPosition(t, region), length); regionPosition(t, region) += length; return length; } else { throwNew(t, Machine::IoExceptionType); } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, dst, offset, length)); } } int64_t JNICALL skipBytesInFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); int64_t count; memcpy(&count, arguments + 1, 8); MyClasspath* cp = static_cast(t->m->classpath); int fd = cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); int available = r->length() - regionPosition(t, region); if (count > available) { count = available; } regionPosition(t, region) += count; return count; } else { throwNew(t, Machine::IoExceptionType); } } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, count)); } } int64_t JNICALL availableBytesInFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { return static_cast(regionRegion(t, region))->length() - regionPosition(t, region); } else { throwNew(t, Machine::IoExceptionType); } } else { object r = t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_); return r ? intValue(t, r) : 0; } } void JNICALL closeFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); int index = fd - VirtualFileBase; object region = arrayBody(t, root(t, Machine::VirtualFiles), index); if (region) { static_cast(regionRegion(t, region))->dispose(); } set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), 0); } else { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_); } } int64_t JNICALL getBootstrapResource(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); object m = findMethodOrNull (t, type(t, Machine::SystemClassLoaderType), "findResource", "(Ljava/lang/String;)Ljava/net/URL;"); if (m) { return reinterpret_cast (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); } else { return 0; } } int64_t JNICALL getBootstrapResources(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); object m = findMethodOrNull (t, type(t, Machine::SystemClassLoaderType), "findResources", "(Ljava/lang/String;)Ljava/util/Enumeration;"); if (m) { return reinterpret_cast (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); } else { return 0; } } extern "C" JNIEXPORT jint JNICALL net_JNI_OnLoad(JavaVM*, void*); void JNICALL loadLibrary(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); bool absolute = arguments[2]; #ifdef AVIAN_OPENJDK_SRC if (not absolute) { if (strcmp(n, "net") == 0) { bool ran; { ACQUIRE(t, t->m->classLock); local::MyClasspath* c = static_cast (t->m->classpath); ran = c->ranNetOnLoad; c->ranNetOnLoad = true; } if (not ran) { net_JNI_OnLoad(t->m, 0); } return; } else if (strcmp(n, "zip") == 0 or strcmp(n, "nio") == 0) { return; } } #endif // AVIAN_OPENJDK_SRC loadLibrary (t, static_cast(t->m->classpath)->libraryPath, RUNTIME_ARRAY_BODY(n), not absolute, false); } // only safe to call during bootstrap when there's only one thread // running: void intercept(Thread* t, object c, const char* name, const char* spec, void* function) { object m = findMethodOrNull(t, c, name, spec); if (m) { PROTECT(t, m); object clone = methodClone(t, m); // make clone private to prevent vtable updates at compilation // time. Otherwise, our interception might be bypassed by calls // through the vtable. methodFlags(t, clone) |= ACC_PRIVATE; methodFlags(t, m) |= ACC_NATIVE; object native = makeNativeIntercept(t, function, true, clone); PROTECT(t, native); object runtimeData = getMethodRuntimeData(t, m); set(t, runtimeData, MethodRuntimeDataNative, native); } } void interceptFileOperations(Thread* t) { MyClasspath* cp = static_cast(t->m->classpath); { object fileClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/File"); if (fileClass == 0) return; object filePathField = findFieldInClass2 (t, fileClass, "path", "Ljava/lang/String;"); if (filePathField == 0) return; cp->filePathField = fieldOffset(t, filePathField); } { object fileDescriptorClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/FileDescriptor"); if (fileDescriptorClass == 0) return; object fileDescriptorFdField = findFieldInClass2 (t, fileDescriptorClass, "fd", "I"); if (fileDescriptorFdField == 0) return; cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); } { object fileInputStreamClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/FileInputStream"); if (fileInputStreamClass == 0) return; PROTECT(t, fileInputStreamClass); object fileInputStreamFdField = findFieldInClass2 (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); if (fileInputStreamFdField == 0) return; cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", voidPointer(openFile)); intercept(t, fileInputStreamClass, "read", "()I", voidPointer(readByteFromFile)); intercept(t, fileInputStreamClass, "readBytes", "([BII)I", voidPointer(readBytesFromFile)); intercept(t, fileInputStreamClass, "skip", "(J)J", voidPointer(skipBytesInFile)); intercept(t, fileInputStreamClass, "available", "()I", voidPointer(availableBytesInFile)); intercept(t, fileInputStreamClass, "close0", "()V", voidPointer(closeFile)); } { #ifdef PLATFORM_WINDOWS const char* const fsClassName = "java/io/WinNTFileSystem"; const char* const gbaMethodName = "getBooleanAttributes"; #else const char* const fsClassName = "java/io/UnixFileSystem"; const char* const gbaMethodName = "getBooleanAttributes0"; #endif object fsClass = resolveClass (t, root(t, Machine::BootLoader), fsClassName, false); if (fsClass == 0) return; PROTECT(t, fsClass); intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", voidPointer(getFileAttributes)); intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", voidPointer(checkFileAccess)); intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", voidPointer(getFileLength)); } intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary", "(Ljava/lang/Class;Ljava/lang/String;Z)V", voidPointer(loadLibrary)); intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource", "(Ljava/lang/String;)Ljava/net/URL;", voidPointer(getBootstrapResource)); intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResources", "(Ljava/lang/String;)Ljava/util/Enumeration;", voidPointer(getBootstrapResources)); } unsigned countMethods(Thread* t, object c, bool publicOnly) { object table = classMethodTable(t, c); unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') { ++ count; } } return count; } unsigned countFields(Thread* t, object c, bool publicOnly) { object table = classFieldTable(t, c); if (publicOnly) { unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmField = arrayBody(t, table, i); if (fieldFlags(t, vmField) & ACC_PUBLIC) { ++ count; } } return count; } else { return objectArrayLength(t, table); } } unsigned countConstructors(Thread* t, object c, bool publicOnly) { object table = classMethodTable(t, c); unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and strcmp(reinterpret_cast (&byteArrayBody(t, methodName(t, vmMethod), 0)), "") == 0) { ++ count; } } return count; } object resolveClassBySpec(Thread* t, object loader, const char* spec, unsigned specLength) { switch (*spec) { case 'L': { THREAD_RUNTIME_ARRAY(t, char, s, specLength - 1); memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2); RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0; return resolveClass(t, loader, s); } case '[': { THREAD_RUNTIME_ARRAY(t, char, s, specLength + 1); memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength); RUNTIME_ARRAY_BODY(s)[specLength] = 0; return resolveClass(t, loader, s); } default: return primitiveClass(t, *spec); } } object resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) { return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); } object resolveParameterTypes(Thread* t, object loader, object spec, unsigned* parameterCount, unsigned* returnTypeSpec) { PROTECT(t, loader); PROTECT(t, spec); object list = 0; PROTECT(t, list); unsigned offset = 1; unsigned count = 0; while (byteArrayBody(t, spec, offset) != ')') { switch (byteArrayBody(t, spec, offset)) { case 'L': { unsigned start = offset; ++ offset; while (byteArrayBody(t, spec, offset) != ';') ++ offset; ++ offset; object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); list = makePair(t, type, list); ++ count; } break; case '[': { unsigned start = offset; while (byteArrayBody(t, spec, offset) == '[') ++ offset; switch (byteArrayBody(t, spec, offset)) { case 'L': ++ offset; while (byteArrayBody(t, spec, offset) != ';') ++ offset; ++ offset; break; default: ++ offset; break; } object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); list = makePair(t, type, list); ++ count; } break; default: list = makePair (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); ++ offset; ++ count; break; } } *parameterCount = count; *returnTypeSpec = offset + 1; return list; } object resolveParameterJTypes(Thread* t, object loader, object spec, unsigned* parameterCount, unsigned* returnTypeSpec) { object list = resolveParameterTypes (t, loader, spec, parameterCount, returnTypeSpec); PROTECT(t, list); object array = makeObjectArray (t, type(t, Machine::JclassType), *parameterCount); PROTECT(t, array); for (int i = *parameterCount - 1; i >= 0; --i) { object c = getJClass(t, pairFirst(t, list)); set(t, array, ArrayBody + (i * BytesPerWord), c); list = pairSecond(t, list); } return array; } object resolveExceptionJTypes(Thread* t, object loader, object addendum) { if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { return makeObjectArray(t, type(t, Machine::JclassType), 0); } PROTECT(t, loader); PROTECT(t, addendum); object array = makeObjectArray (t, type(t, Machine::JclassType), shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); PROTECT(t, array); for (unsigned i = 0; i < shortArrayLength (t, methodAddendumExceptionTable(t, addendum)); ++i) { uint16_t index = shortArrayBody (t, methodAddendumExceptionTable(t, addendum), i) - 1; object o = singletonObject(t, addendumPool(t, addendum), index); if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass(t, loader, referenceName(t, o)); set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), o); } o = getJClass(t, o); set(t, array, ArrayBody + (i * BytesPerWord), o); } return array; } void setProperty(Thread* t, object method, object properties, const char* name, const void* value, const char* format = "%s") { PROTECT(t, method); PROTECT(t, properties); object n = makeString(t, "%s", name); PROTECT(t, n); object v = makeString(t, format, value); t->m->processor->invoke(t, method, properties, n, v); } object interruptLock(Thread* t, object thread) { if (threadInterruptLock(t, thread) == 0) { PROTECT(t, thread); ACQUIRE(t, t->m->referenceLock); if (threadInterruptLock(t, thread) == 0) { object head = makeMonitorNode(t, 0, 0); object lock = makeMonitor(t, 0, 0, 0, head, head, 0); set(t, thread, ThreadInterruptLock, lock); } } return threadInterruptLock(t, thread); } bool pipeAvailable(int fd, int* available) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); if (h == INVALID_HANDLE_VALUE) { return false; } DWORD n; if (PeekNamedPipe(h, 0,0, 0, &n, 0)) { *available = n; } else { if (GetLastError() != ERROR_BROKEN_PIPE) { return false; } *available = 0; } return true; #else return ioctl(fd, FIONREAD, available) >= 0; #endif } } // namespace local } // namespace namespace vm { Classpath* makeClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(s, allocator, javaHome, embedPrefix); } } // namespace vm extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_getSuperclass (Thread* t, object, uintptr_t* arguments) { object super = classSuper (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); return super ? reinterpret_cast(getJClass(t, super)) : 0; } extern "C" JNIEXPORT void Avian_sun_misc_Unsafe_registerNatives (Thread*, object, uintptr_t*) { // ignore } extern "C" JNIEXPORT int64_t Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2 (Thread* t, object, uintptr_t* arguments) { //object name = reinterpret_cast(arguments[1]); object data = reinterpret_cast(arguments[2]); int32_t offset = arguments[3]; int32_t length = arguments[4]; object loader = reinterpret_cast(arguments[5]); //object domain = reinterpret_cast(arguments[6]); uint8_t* buffer = static_cast(t->m->heap->allocate(length)); THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, t->m->heap->free(buffer, length)); memcpy(buffer, &byteArrayBody(t, data, offset), length); return reinterpret_cast (getJClass(t, defineClass(t, loader, buffer, length))); } extern "C" JNIEXPORT int64_t Avian_sun_misc_Unsafe_allocateInstance (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[1])); PROTECT(t, c); initClass(t, c); return reinterpret_cast(make(t, c)); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldOffset (Thread* t, object, uintptr_t* arguments) { object jfield = reinterpret_cast(arguments[1]); return fieldOffset (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_arrayBaseOffset (Thread*, object, uintptr_t*) { return BytesPerWord * 2; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_arrayIndexScale (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[1])); if (classVmFlags(t, c) & PrimitiveFlag) { const char* name = reinterpret_cast (&byteArrayBody(t, local::getClassName(t, c), 0)); switch (*name) { case 'b': return 1; case 's': case 'c': return 2; case 'l': case 'd': return 8; case 'i': case 'f': return 4; default: abort(t); } } else { return BytesPerWord; } } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldBase (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (classStaticTable (t, jclassVmClass (t, jfieldClazz(t, reinterpret_cast(arguments[1]))))); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_objectFieldOffset (Thread* t, object, uintptr_t* arguments) { object jfield = reinterpret_cast(arguments[1]); return fieldOffset (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getObject (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return cast(o, offset); } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putObject (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t value = arguments[4]; set(t, o, offset, reinterpret_cast(value)); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return cast(o, offset); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getIntVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t result = cast(o, offset); loadMemoryBarrier(); return result; } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t value = arguments[4]; cast(o, offset) = value; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getBoolean (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return cast(o, offset); } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putBoolean (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint8_t value = arguments[4]; cast(o, offset) = value; } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__Ljava_lang_Object_2JJ (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int64_t value; memcpy(&value, arguments + 4, 8); cast(o, offset) = value; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getObjectVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t value = cast(o, offset); loadMemoryBarrier(); return value; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapInt (Thread*, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint32_t expect = arguments[4]; uint32_t update = arguments[5]; return atomicCompareAndSwap32 (&cast(target, offset), expect, update); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapObject (Thread* t, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t expect = arguments[4]; uintptr_t update = arguments[5]; bool success = atomicCompareAndSwap (&cast(target, offset), expect, update); if (success) { mark(t, target, offset); } return success; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapLong (Thread*, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint64_t expect; memcpy(&expect, arguments + 4, 8); uint64_t update; memcpy(&update, arguments + 6, 8); return atomicCompareAndSwap64 (&cast(target, offset), expect, update); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_allocateMemory (Thread* t, object, uintptr_t* arguments) { void* p = malloc(arguments[1]); if (p) { return reinterpret_cast(p); } else { throwNew(t, Machine::OutOfMemoryErrorType); } } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_freeMemory (Thread*, object, uintptr_t* arguments) { void* p = reinterpret_cast(arguments[1]); if (p) { free(p); } } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_setMemory (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int64_t count; memcpy(&count, arguments + 3, 8); int8_t v = arguments[5]; memset(reinterpret_cast(p), v, count); } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__JJ (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int64_t v; memcpy(&v, arguments + 3, 8); *reinterpret_cast(p) = v; } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__JI (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int32_t v = arguments[3]; *reinterpret_cast(p) = v; } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getByte__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getInt__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_pageSize (Thread*, object, uintptr_t*) { return local::PageSize; } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_ensureClassInitialized (Thread* t, object, uintptr_t* arguments) { initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_unpark (Thread* t, object, uintptr_t* arguments) { object thread = reinterpret_cast(arguments[1]); monitorAcquire(t, local::interruptLock(t, thread)); threadUnparked(t, thread) = true; monitorNotify(t, local::interruptLock(t, thread)); monitorRelease(t, local::interruptLock(t, thread)); } extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_park (Thread* t, object, uintptr_t* arguments) { bool absolute = arguments[1]; int64_t time; memcpy(&time, arguments + 2, 8); if (absolute) { time -= t->m->system->now(); if (time <= 0) { return; } } monitorAcquire(t, local::interruptLock(t, t->javaThread)); while (not (threadUnparked(t, t->javaThread) or monitorWait(t, local::interruptLock(t, t->javaThread), time))) { } threadUnparked(t, t->javaThread) = false; monitorRelease(t, local::interruptLock(t, t->javaThread)); } namespace { namespace local { extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetInterfaceVersion)() { return local::InterfaceVersion; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_IHashCode)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); return objectHash(t, *o); } uint64_t jvmWait(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); vm::wait(t, *o, milliseconds); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorWait)(Thread* t, jobject o, jlong milliseconds) { uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(o); memcpy(arguments + 1, &milliseconds, sizeof(jlong)); run(t, jvmWait, arguments); } uint64_t jvmNotify(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); notify(t, *o); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorNotify)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; run(t, jvmNotify, arguments); } uint64_t jvmNotifyAll(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); notifyAll(t, *o); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; run(t, jvmNotifyAll, arguments); } uint64_t jvmClone(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); return reinterpret_cast(makeLocalReference(t, clone(t, *o))); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_Clone)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; return reinterpret_cast(run(t, jvmClone, arguments)); } uint64_t jvmInternString(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); return reinterpret_cast(makeLocalReference(t, intern(t, *o))); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_InternString)(Thread* t, jstring s) { uintptr_t arguments[] = { reinterpret_cast(s) }; return reinterpret_cast(run(t, jvmInternString, arguments)); } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_CurrentTimeMillis)(Thread* t, jclass) { return t->m->system->now(); } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_NanoTime)(Thread* t, jclass) { return t->m->system->now() * 1000 * 1000; } uint64_t jvmArrayCopy(Thread* t, uintptr_t* arguments) { jobject src = reinterpret_cast(arguments[0]); jint srcOffset = arguments[1]; jobject dst = reinterpret_cast(arguments[2]); jint dstOffset = arguments[3]; jint length = arguments[4]; arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ArrayCopy)(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, jint dstOffset, jint length) { uintptr_t arguments[] = { reinterpret_cast(src), srcOffset, reinterpret_cast(dst), dstOffset, length }; run(t, jvmArrayCopy, arguments); } uint64_t jvmInitProperties(Thread* t, uintptr_t* arguments) { jobject properties = reinterpret_cast(arguments[0]); object method = resolveMethod (t, root(t, Machine::BootLoader), "java/util/Properties", "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); PROTECT(t, method); #ifdef PLATFORM_WINDOWS local::setProperty(t, method, *properties, "line.separator", "\r\n"); local::setProperty(t, method, *properties, "file.separator", "\\"); local::setProperty(t, method, *properties, "path.separator", ";"); local::setProperty(t, method, *properties, "os.name", "Windows"); TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); local::setProperty(t, method, *properties, "java.io.tmpdir", buffer); local::setProperty(t, method, *properties, "java.home", buffer); local::setProperty(t, method, *properties, "user.home", _wgetenv(L"USERPROFILE"), "%ls"); GetCurrentDirectory(MAX_PATH, buffer); local::setProperty(t, method, *properties, "user.dir", buffer); #else local::setProperty(t, method, *properties, "line.separator", "\n"); local::setProperty(t, method, *properties, "file.separator", "/"); local::setProperty(t, method, *properties, "path.separator", ":"); # ifdef __APPLE__ local::setProperty(t, method, *properties, "os.name", "Mac OS X"); # else local::setProperty(t, method, *properties, "os.name", "Linux"); # endif local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); #endif local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); local::setProperty (t, method, *properties, "sun.boot.library.path", static_cast(t->m->classpath)->libraryPath); local::setProperty(t, method, *properties, "file.encoding", "ASCII"); #ifdef ARCH_x86_32 local::setProperty(t, method, *properties, "os.arch", "x86"); #elif defined ARCH_x86_64 local::setProperty(t, method, *properties, "os.arch", "x86_64"); #elif defined ARCH_powerpc local::setProperty(t, method, *properties, "os.arch", "ppc"); #elif defined ARCH_arm local::setProperty(t, method, *properties, "os.arch", "arm"); #else local::setProperty(t, method, *properties, "os.arch", "unknown"); #endif for (unsigned i = 0; i < t->m->propertyCount; ++i) { const char* start = t->m->properties[i]; const char* p = start; while (*p and *p != '=') ++p; if (*p == '=') { THREAD_RUNTIME_ARRAY(t, char, name, (p - start) + 1); memcpy(name, start, p - start); name[p - start] = 0; local::setProperty (t, method, *properties, RUNTIME_ARRAY_BODY(name), p + 1); } } return reinterpret_cast(properties); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_InitProperties)(Thread* t, jobject properties) { uintptr_t arguments[] = { reinterpret_cast(properties) }; return reinterpret_cast(run(t, jvmInitProperties, arguments)); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_OnExit)(void (*)(void)) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_Exit)(jint code) { exit(code); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_Halt)(jint code) { exit(code); } uint64_t jvmGC(Thread* t, uintptr_t*) { collect(t, Heap::MajorCollection); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GC)() { Thread* t = static_cast(local::globalMachine->localThread->get()); run(t, jvmGC, 0); } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_MaxObjectInspectionAge)(void) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_TraceInstructions)(jboolean) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_TraceMethodCalls)(jboolean) { abort(); } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_TotalMemory)() { return 0; } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_FreeMemory)() { return 0; } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_MaxMemory)() { return 0; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ActiveProcessorCount)() { return 1; } uint64_t jvmLoadLibrary(Thread* t, uintptr_t* arguments) { const char* path = reinterpret_cast(arguments[0]); THREAD_RUNTIME_ARRAY(t, char, p, strlen(path) + 1); replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); return reinterpret_cast (loadLibrary (t, static_cast(t->m->classpath)->libraryPath, RUNTIME_ARRAY_BODY(p), false, false)); } extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_LoadLibrary)(const char* path) { Thread* t = static_cast(local::globalMachine->localThread->get()); uintptr_t arguments[] = { reinterpret_cast(path) }; return reinterpret_cast(run(t, jvmLoadLibrary, arguments)); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_UnloadLibrary)(void*) { abort(); } extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) { Thread* t = static_cast(local::globalMachine->localThread->get()); ENTER(t, Thread::ActiveState); if (library == RTLD_DEFAULT) { library = t->m->libraries; } return static_cast(library)->resolve(name); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsSupportedJNIVersion)(jint version) { return version <= JNI_VERSION_1_4; } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsNaN)(jdouble) { abort(); } uint64_t jvmFillInStackTrace(Thread* t, uintptr_t* arguments) { jobject throwable = reinterpret_cast(arguments[0]); object trace = getTrace(t, 1); set(t, *throwable, ThrowableTrace, trace); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) { uintptr_t arguments[] = { reinterpret_cast(throwable) }; run(t, jvmFillInStackTrace, arguments); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_PrintStackTrace)(Thread*, jobject, jobject) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetStackTraceDepth)(Thread* t, jobject throwable) { ENTER(t, Thread::ActiveState); return objectArrayLength(t, throwableTrace(t, *throwable)); } uint64_t jvmGetStackTraceElement(Thread* t, uintptr_t* arguments) { jobject throwable = reinterpret_cast(arguments[0]); jint index = arguments[1]; return reinterpret_cast (makeLocalReference (t, makeStackTraceElement (t, objectArrayBody(t, throwableTrace(t, *throwable), index)))); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetStackTraceElement)(Thread* t, jobject throwable, jint index) { uintptr_t arguments[] = { reinterpret_cast(throwable), index }; return reinterpret_cast(run(t, jvmGetStackTraceElement, arguments)); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_InitializeCompiler) (Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsSilentCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_EnableCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_DisableCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_StartThread)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); startThread(t, *thread); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_StopThread)(Thread*, jobject, jobject) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsThreadAlive)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); Thread* p = reinterpret_cast(threadPeer(t, *thread)); return p and (p->flags & Thread::ActiveFlag) != 0; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SuspendThread)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ResumeThread)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetThreadPriority)(Thread*, jobject, jint) { // ignore } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_Yield)(Thread* t, jclass) { t->m->system->yield(); } uint64_t jvmSleep(Thread* t, uintptr_t* arguments) { jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong)); if (threadSleepLock(t, t->javaThread) == 0) { object lock = makeJobject(t); set(t, t->javaThread, ThreadSleepLock, lock); } acquire(t, threadSleepLock(t, t->javaThread)); vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); release(t, threadSleepLock(t, t->javaThread)); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) { uintptr_t arguments[sizeof(jlong) / BytesPerWord]; memcpy(arguments, &milliseconds, sizeof(jlong)); run(t, jvmSleep, arguments); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CurrentThread)(Thread* t, jclass) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, t->javaThread); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_CountStackFrames)(Thread*, jobject) { abort(); } uint64_t jvmInterrupt(Thread* t, uintptr_t* arguments) { jobject thread = reinterpret_cast(arguments[0]); monitorAcquire(t, local::interruptLock(t, *thread)); Thread* p = reinterpret_cast(threadPeer(t, *thread)); if (p) { interrupt(t, p); } else { threadInterrupted(t, *thread) = true; } monitorRelease(t, local::interruptLock(t, *thread)); return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_Interrupt)(Thread* t, jobject thread) { uintptr_t arguments[] = { reinterpret_cast(thread) }; run(t, jvmInterrupt, arguments); } uint64_t jvmIsInterrupted(Thread* t, uintptr_t* arguments) { jobject thread = reinterpret_cast(arguments[0]); jboolean clear = arguments[1]; monitorAcquire(t, local::interruptLock(t, *thread)); bool v = threadInterrupted(t, *thread); if (clear) { threadInterrupted(t, *thread) = false; } monitorRelease(t, local::interruptLock(t, *thread)); return v; } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) { uintptr_t arguments[] = { reinterpret_cast(thread), clear }; return run(t, jvmIsInterrupted, arguments); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } uint64_t jvmDumpThreads(Thread* t, uintptr_t* arguments) { jobjectArray threads = reinterpret_cast(arguments[0]); unsigned threadsLength = objectArrayLength(t, *threads); object arrayClass = resolveObjectArrayClass (t, classLoader(t, type(t, Machine::StackTraceElementType)), type(t, Machine::StackTraceElementType)); object result = makeObjectArray(t, arrayClass, threadsLength); PROTECT(t, result); for (unsigned threadsIndex = 0; threadsIndex < threadsLength; ++ threadsIndex) { Thread* peer = reinterpret_cast (threadPeer(t, objectArrayBody(t, *threads, threadsIndex))); if (peer) { object trace = t->m->processor->getStackTrace(t, peer); PROTECT(t, trace); unsigned traceLength = objectArrayLength(t, trace); object array = makeObjectArray (t, type(t, Machine::StackTraceElementType), traceLength); PROTECT(t, array); for (unsigned traceIndex = 0; traceIndex < traceLength; ++ traceIndex) { object ste = makeStackTraceElement (t, objectArrayBody(t, trace, traceIndex)); set(t, array, ArrayBody + (traceIndex * BytesPerWord), ste); } set(t, result, ArrayBody + (threadsIndex * BytesPerWord), array); } } return reinterpret_cast(makeLocalReference(t, result)); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) { uintptr_t arguments[] = { reinterpret_cast(threads) }; return reinterpret_cast(run(t, jvmDumpThreads, arguments)); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CurrentClassLoader)(Thread*) { abort(); } uint64_t jvmGetClassContext(Thread* t, uintptr_t*) { object trace = getTrace(t, 1); PROTECT(t, trace); object context = makeObjectArray (t, type(t, Machine::JclassType), objectArrayLength(t, trace)); PROTECT(t, context); for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { object c = getJClass (t, methodClass(t, traceElementMethod(t, objectArrayBody(t, trace, i)))); set(t, context, ArrayBody + (i * BytesPerWord), c); } return reinterpret_cast(makeLocalReference(t, context)); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassContext)(Thread* t) { return reinterpret_cast(run(t, jvmGetClassContext, 0)); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_GetSystemPackage)(Thread*, jstring) { return 0; } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetSystemPackages)(Thread*) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_AllocateNewObject)(Thread*, jobject, jclass, jclass) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_AllocateNewArray)(Thread*, jobject, jclass, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_LatestUserDefinedLoader)(Thread*) { abort(); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_LoadClass0)(Thread*, jobject, jclass, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetArrayLength)(Thread* t, jobject array) { ENTER(t, Thread::ActiveState); return cast(*array, BytesPerWord); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetArrayElement)(Thread* t, jobject array, jint index) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, objectArrayBody(t, *array, index)); } extern "C" JNIEXPORT jvalue JNICALL EXPORT(JVM_GetPrimitiveArrayElement)(Thread*, jobject, jint, jint) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetArrayElement)(Thread* t, jobject array, jint index, jobject value) { ENTER(t, Thread::ActiveState); set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, unsigned char) { abort(); } uint64_t jvmNewArray(Thread* t, uintptr_t* arguments) { jclass elementClass = reinterpret_cast(arguments[0]); jint length = arguments[1]; object c = jclassVmClass(t, *elementClass); if (classVmFlags(t, c) & PrimitiveFlag) { const char* name = reinterpret_cast (&byteArrayBody(t, local::getClassName(t, c), 0)); switch (*name) { case 'b': if (name[1] == 'o') { return reinterpret_cast (makeLocalReference(t, makeBooleanArray(t, length))); } else { return reinterpret_cast (makeLocalReference(t, makeByteArray(t, length))); } case 'c': return reinterpret_cast (makeLocalReference(t, makeCharArray(t, length))); case 'd': return reinterpret_cast (makeLocalReference(t, makeDoubleArray(t, length))); case 'f': return reinterpret_cast (makeLocalReference(t, makeFloatArray(t, length))); case 'i': return reinterpret_cast (makeLocalReference(t, makeIntArray(t, length))); case 'l': return reinterpret_cast (makeLocalReference(t, makeLongArray(t, length))); case 's': return reinterpret_cast (makeLocalReference(t, makeShortArray(t, length))); default: abort(t); } } else { return reinterpret_cast (makeLocalReference(t, makeObjectArray(t, c, length))); } } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) { uintptr_t arguments[] = { reinterpret_cast(elementClass), length }; return reinterpret_cast(run(t, jvmNewArray, arguments)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_NewMultiArray)(Thread*, jclass, jintArray) { abort(); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_GetCallerClass)(Thread* t, int target) { ENTER(t, Thread::ActiveState); return makeLocalReference (t, getJClass(t, methodClass(t, getCaller(t, target)))); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) { ENTER(t, Thread::ActiveState); switch (*name) { case 'b': if (name[1] == 'o') { return makeLocalReference (t, getJClass(t, type(t, Machine::JbooleanType))); } else { return makeLocalReference (t, getJClass(t, type(t, Machine::JbyteType))); } case 'c': return makeLocalReference (t, getJClass(t, type(t, Machine::JcharType))); case 'd': return makeLocalReference (t, getJClass(t, type(t, Machine::JdoubleType))); case 'f': return makeLocalReference (t, getJClass(t, type(t, Machine::JfloatType))); case 'i': return makeLocalReference (t, getJClass(t, type(t, Machine::JintType))); case 'l': return makeLocalReference (t, getJClass(t, type(t, Machine::JlongType))); case 's': return makeLocalReference (t, getJClass(t, type(t, Machine::JshortType))); case 'v': return makeLocalReference (t, getJClass(t, type(t, Machine::JvoidType))); default: throwNew(t, Machine::IllegalArgumentExceptionType); } } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ResolveClass)(Thread*, jclass) { abort(); } uint64_t jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) { const char* name = reinterpret_cast(arguments[0]); jboolean init = arguments[1]; jobject loader = reinterpret_cast(arguments[2]); jboolean throwError = arguments[3]; THREAD_RESOURCE(t, jboolean, throwError, { if (t->exception and throwError) { object exception = t->exception; t->exception = 0; t->exception = makeThrowable (t, Machine::NoClassDefFoundErrorType, throwableMessage(t, exception), throwableTrace(t, exception), throwableCause(t, exception)); } }); object c = resolveClass (t, loader ? *loader : root(t, Machine::BootLoader), name); if (init) { PROTECT(t, c); initClass(t, c); } return reinterpret_cast(makeLocalReference(t, getJClass(t, c))); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, jboolean init, jobject loader, jboolean throwError) { uintptr_t arguments[] = { reinterpret_cast(name), init, reinterpret_cast(loader), throwError }; return reinterpret_cast (run(t, jvmFindClassFromClassLoader, arguments)); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_FindClassFromBootLoader)(Thread* t, const char* name, jboolean throwError) { return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, throwError); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, jclass) { abort(); } uint64_t jvmFindLoadedClass(Thread* t, uintptr_t* arguments) { jobject loader = reinterpret_cast(arguments[0]); jstring name = reinterpret_cast(arguments[1]); object spec = makeByteArray(t, stringLength(t, *name) + 1); { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); stringChars(t, *name, s); replace('.', '/', s); } object c = findLoadedClass(t, *loader, spec); return reinterpret_cast (c ? makeLocalReference(t, getJClass(t, c)) : 0); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(name) }; return reinterpret_cast(run(t, jvmFindLoadedClass, arguments)); } uint64_t jvmDefineClass(Thread* t, uintptr_t* arguments) { jobject loader = reinterpret_cast(arguments[0]); const uint8_t* data = reinterpret_cast(arguments[1]); jsize length = arguments[2]; return reinterpret_cast (makeLocalReference (t, getJClass(t, defineClass(t, *loader, data, length)))); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_DefineClass)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(data), length }; return reinterpret_cast(run(t, jvmDefineClass, arguments)); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject, const char*) { return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_GetClassName)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, jclassName(t, *c)); } uint64_t jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object table = classInterfaceTable(t, jclassVmClass(t, *c)); if (table) { unsigned stride = (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; object array = makeObjectArray (t, type(t, Machine::JclassType), arrayLength(t, table) / stride); PROTECT(t, array); for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { object interface = getJClass(t, arrayBody(t, table, i * stride)); set(t, array, ArrayBody + (i * BytesPerWord), interface); } return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetClassInterfaces, arguments)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetClassLoader)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object loader = classLoader(t, jclassVmClass(t, *c)); if (loader == root(t, Machine::BootLoader)) { // sun.misc.Unsafe.getUnsafe expects a null result if the class // loader is the boot classloader and will throw a // SecurityException otherwise. object caller = getCaller(t, 2); if (caller and strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, caller)), 0)), "sun/misc/Unsafe") == 0) { return 0; } else { return makeLocalReference(t, root(t, Machine::BootLoader)); } } else { return makeLocalReference(t, loader); } } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsInterface)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) != 0; } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassSigners)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object runtimeData = getClassRuntimeDataIfExists(t, jclassVmClass(t, *c)); return runtimeData ? makeLocalReference (t, classRuntimeDataSigners(t, runtimeData)) : 0; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) { ENTER(t, Thread::ActiveState); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataSigners, *signers); } uint64_t jvmGetProtectionDomain(Thread* t, uintptr_t*) { object openJDK = resolveClass (t, root(t, Machine::BootLoader), "avian/OpenJDK"); object method = resolveMethod (t, openJDK, "getProtectionDomain", "()Ljava/security/ProtectionDomain;"); return reinterpret_cast (makeLocalReference(t, t->m->processor->invoke(t, method, 0))); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) { return reinterpret_cast(run(t, jvmGetProtectionDomain, 0)); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetProtectionDomain)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsArrayClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return classArrayDimensions(t, jclassVmClass(t, *c)) != 0; } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsPrimitiveClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_GetComponentType)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); if (n != 'L' and n != '[') { return makeLocalReference(t, getJClass(t, primitiveClass(t, n))); } else { return makeLocalReference (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c)))); } } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return classFlags(t, jclassVmClass(t, *c)); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetDeclaredClasses)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_GetClassSignature)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jbyteArray JNICALL EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object addendum = classAddendum(t, jclassVmClass(t, *c)); return addendum ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; } uint64_t jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JmethodType), local::countMethods(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); PROTECT(t, vmMethod); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') { object name = intern (t, t->m->classpath->makeString (t, methodName(t, vmMethod), 0, byteArrayLength (t, methodName(t, vmMethod)) - 1)); PROTECT(t, name); unsigned parameterCount; unsigned returnTypeSpec; object parameterTypes = local::resolveParameterJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); object returnType = local::resolveJType (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); PROTECT(t, returnType); object exceptionTypes = local::resolveExceptionJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); object signature = t->m->classpath->makeString (t, methodSpec(t, vmMethod), 0, byteArrayLength (t, methodSpec(t, vmMethod)) - 1); object annotationTable = methodAddendum(t, vmMethod) == 0 ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { PROTECT(t, signature); PROTECT(t, annotationTable); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } object method = makeJmethod (t, true, *c, i, name, returnType, parameterTypes, exceptionTypes, methodFlags(t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); } } return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JmethodType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredMethods, arguments)); } uint64_t jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classFieldTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JfieldType), local::countFields(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmField = arrayBody(t, table, i); PROTECT(t, vmField); if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { object name = intern (t, t->m->classpath->makeString (t, fieldName(t, vmField), 0, byteArrayLength (t, fieldName(t, vmField)) - 1)); PROTECT(t, name); object type = local::resolveClassBySpec (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast (&byteArrayBody(t, fieldSpec(t, vmField), 0)), byteArrayLength(t, fieldSpec(t, vmField)) - 1); PROTECT(t, type); type = getJClass(t, type); object signature = t->m->classpath->makeString (t, fieldSpec(t, vmField), 0, byteArrayLength (t, fieldSpec(t, vmField)) - 1); object annotationTable = fieldAddendum(t, vmField) == 0 ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); if (annotationTable) { PROTECT(t, signature); PROTECT(t, annotationTable); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, fieldAddendum(t, vmField))); } object field = makeJfield (t, true, *c, i, name, type, fieldFlags (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), field); } } assert(t, ai == objectArrayLength(t, array)); return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JfieldType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredFields, arguments)); } uint64_t jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JconstructorType), local::countConstructors(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); PROTECT(t, vmMethod); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and strcmp(reinterpret_cast (&byteArrayBody(t, methodName(t, vmMethod), 0)), "") == 0) { unsigned parameterCount; unsigned returnTypeSpec; object parameterTypes = local::resolveParameterJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); object exceptionTypes = local::resolveExceptionJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); object signature = t->m->classpath->makeString (t, methodSpec(t, vmMethod), 0, byteArrayLength (t, methodSpec(t, vmMethod)) - 1); object annotationTable = methodAddendum(t, vmMethod) == 0 ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { PROTECT(t, signature); PROTECT(t, annotationTable); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } object method = makeJconstructor (t, true, *c, i, parameterTypes, exceptionTypes, methodFlags (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); } } return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredConstructors, arguments)); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c) { return EXPORT(JVM_GetClassModifiers)(t, c); } uint64_t jvmInvokeMethod(Thread* t, uintptr_t* arguments) { jobject method = reinterpret_cast(arguments[0]); jobject instance = reinterpret_cast(arguments[1]); jobjectArray args = reinterpret_cast(arguments[2]); object vmMethod = arrayBody (t, classMethodTable (t, jclassVmClass(t, jmethodClazz(t, *method))), jmethodSlot(t, *method)); if (methodFlags(t, vmMethod) & ACC_STATIC) { instance = 0; } object result; if (args) { result = t->m->processor->invokeArray (t, vmMethod, instance ? *instance : 0, *args); } else { result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); } return reinterpret_cast(makeLocalReference(t, result)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, jobjectArray args) { uintptr_t arguments[] = { reinterpret_cast(method), reinterpret_cast(instance), reinterpret_cast(args) }; return reinterpret_cast(run(t, jvmInvokeMethod, arguments)); } uint64_t jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments) { jobject constructor = reinterpret_cast(arguments[0]); jobjectArray args = reinterpret_cast(arguments[1]); object instance = make (t, jclassVmClass(t, jconstructorClazz(t, *constructor))); PROTECT(t, instance); object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), jconstructorSlot(t, *constructor)); if (args) { t->m->processor->invokeArray(t, method, instance, *args); } else { t->m->processor->invoke(t, method, instance); } return reinterpret_cast(makeLocalReference(t, instance)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, jobjectArray args) { uintptr_t arguments[] = { reinterpret_cast(constructor), reinterpret_cast(args) }; return reinterpret_cast (run(t, jvmNewInstanceFromConstructor, arguments)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object vmClass = jclassVmClass(t, *c); object addendum = classAddendum(t, vmClass); object pool; if (addendum) { pool = addendumPool(t, addendum); } else { pool = 0; } if (pool == 0) { pool = classRuntimeDataPool(t, getClassRuntimeData(t, vmClass)); } return makeLocalReference(t, makeConstantPool(t, pool)); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ConstantPoolGetSize)(Thread* t, jobject, jobject pool) { if (pool == 0) return 0; ENTER(t, Thread::ActiveState); return singletonCount(t, *pool); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_ConstantPoolGetClassAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_ConstantPoolGetClassAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetMethodAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetMethodAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetFieldAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetFieldAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_ConstantPoolGetMemberRefInfoAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ConstantPoolGetIntAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); return singletonValue(t, *pool, index - 1); } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_ConstantPoolGetLongAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jfloat JNICALL EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jdouble JNICALL EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) { abort(); } uint64_t jvmConstantPoolGetUTF8At(Thread* t, uintptr_t* arguments) { jobject pool = reinterpret_cast(arguments[0]); jint index = arguments[1]; object array = singletonObject(t, *pool, index - 1); return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, cast(array, BytesPerWord) - 1))); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) { uintptr_t arguments[] = { reinterpret_cast(pool), index }; return reinterpret_cast (run(t, jvmConstantPoolGetUTF8At, arguments)); } void maybeWrap(Thread* t, bool wrapException) { if (t->exception and wrapException and not (instanceOf(t, type(t, Machine::ErrorType), t->exception) or instanceOf (t, type(t, Machine::RuntimeExceptionType), t->exception))) { object exception = t->exception; t->exception = 0; PROTECT(t, exception); object paeClass = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedActionException"); PROTECT(t, paeClass); object paeConstructor = resolveMethod (t, paeClass, "", "(Ljava/lang/Exception;)V"); PROTECT(t, paeConstructor); object result = make(t, paeClass); PROTECT(t, result); t->m->processor->invoke(t, paeConstructor, result, exception); t->exception = result; } } uint64_t jvmDoPrivileged(Thread* t, uintptr_t* arguments) { jobject action = reinterpret_cast(arguments[0]); jboolean wrapException = arguments[1]; // todo: cache these class and method lookups in the t->m->classpath // object: object privilegedAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedAction"); object method; if (instanceOf(t, privilegedAction, *action)) { method = resolveMethod (t, privilegedAction, "run", "()Ljava/lang/Object;"); } else { object privilegedExceptionAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedExceptionAction"); method = resolveMethod (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); } THREAD_RESOURCE(t, jboolean, wrapException, maybeWrap(t, wrapException)); return reinterpret_cast (makeLocalReference(t, t->m->processor->invoke(t, method, *action))); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_DoPrivileged) (Thread* t, jclass, jobject action, jobject, jboolean wrapException) { uintptr_t arguments[] = { reinterpret_cast(action), wrapException }; return reinterpret_cast(run(t, jvmDoPrivileged, arguments)); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetInheritedAccessControlContext)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetStackAccessControlContext)(Thread*, jclass) { return 0; } extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_RegisterSignal)(jint, void*) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_RaiseSignal)(jint) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_FindSignal)(const char*) { return -1; } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_DesiredAssertionStatus)(Thread*, jclass, jclass) { return false; } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_AssertionStatusDirectives)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_SupportsCX8)() { return true; } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetClassNameUTF)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GetClassCPTypes)(Thread*, jclass, unsigned char*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassCPEntriesCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassFieldsCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassMethodsCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GetMethodIxExceptionIndexes)(Thread*, jclass, jint, unsigned short*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxExceptionsCount)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GetMethodIxByteCode)(Thread*, jclass, jint, unsigned char*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxByteCodeLength)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GetMethodIxExceptionTableEntry)(Thread*, jclass, jint, jint, local::JVM_ExceptionTableEntryType*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxExceptionTableLength)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetFieldIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxLocalsCount)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxArgsSize)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetMethodIxMaxStack)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetMethodIxSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPFieldNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPMethodNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPMethodSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPFieldSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPFieldClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL EXPORT(JVM_GetCPMethodClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetCPFieldModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetCPMethodModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ReleaseUTF)(const char*) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsSameClassPackage)(Thread*, jclass, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetLastErrorString)(char* dst, int length) { strncpy(dst, strerror(errno), length); return strlen(dst); } extern "C" JNIEXPORT char* JNICALL EXPORT(JVM_NativePath)(char* path) { return path; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Open)(const char* path, jint flags, jint mode) { return OPEN(path, flags, mode); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Close)(jint fd) { return CLOSE(fd); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Read)(jint fd, char* dst, jint length) { return READ(fd, dst, length); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Write)(jint fd, char* src, jint length) { return WRITE(fd, src, length); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Available)(jint fd, jlong* result) { struct STAT buffer; int n; if (FSTAT(fd, &buffer) >= 0 and (S_ISCHR(buffer.st_mode) or S_ISFIFO(buffer.st_mode) or S_ISSOCK(buffer.st_mode)) and local::pipeAvailable(fd, &n)) { *result = n; return 1; } int current = LSEEK(fd, 0, SEEK_CUR); if (current == -1) return 0; int end = LSEEK(fd, 0, SEEK_END); if (end == -1) return 0; if (LSEEK(fd, current, SEEK_SET) == -1) return 0; *result = end - current; return 1; } extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_Lseek)(jint fd, jlong offset, jint seek) { return LSEEK(fd, offset, seek); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SetLength)(jint, jlong) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Sync)(jint fd) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (FlushFileBuffers(h)) { return 0; } else { errno = EIO; return -1; } #else return fsync(fd); #endif } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_InitializeSocketLibrary)() { #ifdef PLATFORM_WINDOWS static bool wsaInitialized = false; if (not wsaInitialized) { WSADATA data; int r = WSAStartup(MAKEWORD(2, 2), &data); if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { return -1; } else { wsaInitialized = true; } } #endif return 0; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Socket)(jint domain, jint type, jint protocol) { return socket(domain, type, protocol); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SocketClose)(jint socket) { #ifdef PLATFORM_WINDOWS return closesocket(socket); #else return close(socket); #endif } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SocketShutdown)(jint socket, jint how) { return shutdown(socket, how); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Recv)(jint socket, char* dst, jint count, jint flags) { return recv(socket, dst, count, flags); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Send)(jint socket, char* src, jint count, jint flags) { return send(socket, src, count, flags); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Timeout)(int, long) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Listen)(jint socket, jint count) { return listen(socket, count); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Connect)(jint socket, sockaddr* address, jint addressLength) { return connect(socket, address, addressLength); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Bind)(jint, struct sockaddr*, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Accept)(jint socket, struct sockaddr* address, jint* addressLength) { socklen_t length = *addressLength; int r = accept(socket, address, &length); *addressLength = length; return r; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_RecvFrom)(jint, char*, int, int, struct sockaddr*, int*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SendTo)(jint, char*, int, int, struct sockaddr*, int) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SocketAvailable)(jint, jint*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, int* addressLength) { socklen_t length = *addressLength; int r = getsockname(socket, address, &length); *addressLength = length; return r; } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetSockOpt)(jint, int, int, char*, int*) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SetSockOpt)(jint, int, int, const char*, int) { abort(); } extern "C" JNIEXPORT struct protoent* JNICALL EXPORT(JVM_GetProtoByName)(char*) { abort(); } extern "C" JNIEXPORT struct hostent* JNICALL EXPORT(JVM_GetHostByAddr)(const char*, int, int) { abort(); } extern "C" JNIEXPORT struct hostent* JNICALL EXPORT(JVM_GetHostByName)(char*) { abort(); } extern "C" JNIEXPORT int JNICALL EXPORT(JVM_GetHostName)(char* name, int length) { return gethostname(name, length); } extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_RawMonitorCreate)(void) { System* s = local::globalMachine->system; System::Monitor* lock; if (s->success(s->make(&lock))) { return lock; } else { return 0; } } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_RawMonitorDestroy)(void* lock) { static_cast(lock)->dispose(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_RawMonitorEnter)(void* lock) { static_cast(lock)->acquire (static_cast (local::globalMachine->localThread->get())->systemThread); return 0; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_RawMonitorExit)(void* lock) { static_cast(lock)->release (static_cast (local::globalMachine->localThread->get())->systemThread); } extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_GetManagement)(jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetEnclosingMethodInfo)(JNIEnv*, jclass) { abort(); } extern "C" JNIEXPORT jintArray JNICALL EXPORT(JVM_GetThreadStateValues)(JNIEnv*, jint) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetThreadStateNames)(JNIEnv*, jint, jintArray) { abort(); } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info*, size_t) { abort(); } extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) { abort(); } } // namespace local } // namespace extern "C" JNIEXPORT int jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) { return vm::vsnprintf(dst, size, format, a); } extern "C" JNIEXPORT int jio_vfprintf(FILE* stream, const char* format, va_list a) { return vfprintf(stream, format, a); } #ifdef PLATFORM_WINDOWS extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_GetThreadInterruptEvent)() { abort(); } namespace { HMODULE jvmHandle = 0; } extern "C" int JDK_InitJvmHandle() { jvmHandle = GetModuleHandle(0); return jvmHandle != 0; } extern "C" void* JDK_FindJvmEntry(const char* name) { return voidPointer(GetProcAddress(jvmHandle, name)); } # ifdef AVIAN_OPENJDK_SRC extern "C" char* findJavaTZ_md(const char*, const char*); extern "C" JNIEXPORT int64_t JNICALL Avian_java_util_TimeZone_getSystemTimeZoneID (Thread* t, object, uintptr_t* arguments) { // On Windows, findJavaTZ_md loads tzmappings from the filesystem // using fopen, so we have no opportunity to make it read straight // from the embedded JAR file as with files read from Java code. // Therefore, we must extract tzmappings to a temporary location // before calling findJavaTZ_md. We could avoid this by // implementing findJavaTZ_md ourselves from scratch, but that would // be a lot of code to implement and maintain. object country = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, char, countryChars, stringLength(t, country) + 1); stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars)); local::MyClasspath* cp = static_cast(t->m->classpath); local::EmbeddedFile ef(cp, cp->tzMappings, cp->tzMappingsLength); if (ef.jar == 0 or ef.jarLength == 0 or ef.pathLength == 0) { return 0; } Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { return 0; } System::Region* r = finder->find(ef.path); if (r == 0) { return 0; } THREAD_RESOURCE(t, System::Region*, r, r->dispose()); char tmpPath[MAX_PATH + 1]; GetTempPathA(MAX_PATH, tmpPath); char tmpDir[MAX_PATH + 1]; vm::snprintf(tmpDir, MAX_PATH, "%s/avian-tmp", tmpPath); if (_mkdir(tmpDir) != 0 and errno != EEXIST) { return 0; } THREAD_RESOURCE(t, char*, tmpDir, rmdir(tmpDir)); char libDir[MAX_PATH + 1]; vm::snprintf(libDir, MAX_PATH, "%s/lib", tmpDir); if (mkdir(libDir) != 0 and errno != EEXIST) { return 0; } THREAD_RESOURCE(t, char*, libDir, rmdir(libDir)); char file[MAX_PATH + 1]; vm::snprintf(file, MAX_PATH, "%s/tzmappings", libDir); FILE* out = vm::fopen(file, "wb"); if (out == 0) { return 0; } THREAD_RESOURCE(t, char*, file, unlink(file)); THREAD_RESOURCE(t, FILE*, out, fclose(out)); if (fwrite(r->start(), 1, r->length(), out) != r->length() or fflush(out) != 0) { return 0; } char* javaTZ = findJavaTZ_md(tmpDir, RUNTIME_ARRAY_BODY(countryChars)); if (javaTZ) { THREAD_RESOURCE(t, char*, javaTZ, free(javaTZ)); return reinterpret_cast(makeString(t, "%s", javaTZ)); } else { return 0; } } # else // not AVIAN_OPENJDK_SRC extern "C" JNIEXPORT int jio_snprintf(char* dst, size_t size, const char* format, ...) { va_list a; va_start(a, format); int r = jio_vsnprintf(dst, size, format, a); va_end(a); return r; } extern "C" JNIEXPORT int jio_fprintf(FILE* stream, const char* format, ...) { va_list a; va_start(a, format); int r = jio_vfprintf(stream, format, a); va_end(a); return r; } # endif // not AVIAN_OPENJDK_SRC #endif // PLATFORM_WINDOWS