mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
6e19f4dcca
These methods can all throw exceptions, so they must be run using vmRun to avoid unwinding past the JVM entry points.
3950 lines
104 KiB
C++
3950 lines
104 KiB
C++
/* 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 <windows.h>
|
|
# include <io.h>
|
|
# include <direct.h>
|
|
# include <share.h>
|
|
# include <errno.h>
|
|
# include <fcntl.h>
|
|
# include <sys/stat.h>
|
|
# include <sys/types.h>
|
|
|
|
# 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 <unistd.h>
|
|
# include <sys/types.h>
|
|
# include <sys/stat.h>
|
|
# include <sys/socket.h>
|
|
# include <sys/ioctl.h>
|
|
# include <fcntl.h>
|
|
# include <errno.h>
|
|
# include <sched.h>
|
|
# include <dlfcn.h>
|
|
|
|
# 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<char*>(&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), "<init>",
|
|
"(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<uint8_t>(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<const char*>
|
|
(&byteArrayBody(t, finderName(t, p), 0)),
|
|
name, nameLength))
|
|
{
|
|
return static_cast<Finder*>(finderFinder(t, p));
|
|
}
|
|
}
|
|
|
|
object n = makeByteArray(t, nameLength + 1);
|
|
memcpy(&byteArrayBody(t, n, 0), name, nameLength);
|
|
|
|
void* p = t->m->libraries->resolve
|
|
(reinterpret_cast<const char*>(&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<MyClasspath*>(t->m->classpath);
|
|
|
|
object file = reinterpret_cast<object>(arguments[1]);
|
|
object path = cast<object>(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<object>(arguments[0]), file));
|
|
}
|
|
}
|
|
|
|
int64_t JNICALL
|
|
checkFileAccess
|
|
(Thread* t, object method, uintptr_t* arguments)
|
|
{
|
|
const unsigned Read = 4;
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
object file = reinterpret_cast<object>(arguments[1]);
|
|
unsigned mask = arguments[2];
|
|
object path = cast<object>(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<object>(arguments[0]), file, mask)) != 0;
|
|
}
|
|
}
|
|
|
|
int64_t JNICALL
|
|
getFileLength
|
|
(Thread* t, object method, uintptr_t* arguments)
|
|
{
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
object file = reinterpret_cast<object>(arguments[1]);
|
|
object path = cast<object>(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<object>(arguments[0]), file));
|
|
}
|
|
}
|
|
|
|
void JNICALL
|
|
openFile(Thread* t, object method, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
object path = reinterpret_cast<object>(arguments[1]);
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(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<int32_t>
|
|
(cast<object>
|
|
(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<object>(arguments[0]);
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
int fd = cast<int32_t>
|
|
(cast<object>
|
|
(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<System::Region*>
|
|
(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<object>(arguments[0]);
|
|
object dst = reinterpret_cast<object>(arguments[1]);
|
|
int32_t offset = arguments[2];
|
|
int32_t length = arguments[3];
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
int fd = cast<int32_t>
|
|
(cast<object>
|
|
(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<System::Region*>
|
|
(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<object>(arguments[0]);
|
|
int64_t count; memcpy(&count, arguments + 1, 8);
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
int fd = cast<int32_t>
|
|
(cast<object>
|
|
(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<System::Region*>
|
|
(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<object>(arguments[0]);
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
int fd = cast<int32_t>
|
|
(cast<object>
|
|
(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<System::Region*>(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<object>(arguments[0]);
|
|
|
|
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
|
|
|
int fd = cast<int32_t>
|
|
(cast<object>
|
|
(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<System::Region*>(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<object>(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<int64_t>
|
|
(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<object>(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<int64_t>
|
|
(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<object>(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<local::MyClasspath*>
|
|
(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<local::MyClasspath*>(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<MyClasspath*>(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<char*>
|
|
(&byteArrayBody(t, methodName(t, vmMethod), 0)),
|
|
"<init>") == 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<char*>(&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<char*>(&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<HANDLE>(_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<object>(arguments[0])));
|
|
|
|
return super ? reinterpret_cast<int64_t>(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<object>(arguments[1]);
|
|
object data = reinterpret_cast<object>(arguments[2]);
|
|
int32_t offset = arguments[3];
|
|
int32_t length = arguments[4];
|
|
object loader = reinterpret_cast<object>(arguments[5]);
|
|
//object domain = reinterpret_cast<object>(arguments[6]);
|
|
|
|
uint8_t* buffer = static_cast<uint8_t*>(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<int64_t>
|
|
(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<object>(arguments[1]));
|
|
PROTECT(t, c);
|
|
|
|
initClass(t, c);
|
|
|
|
return reinterpret_cast<int64_t>(make(t, c));
|
|
}
|
|
|
|
extern "C" JNIEXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_staticFieldOffset
|
|
(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object jfield = reinterpret_cast<object>(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<object>(arguments[1]));
|
|
|
|
if (classVmFlags(t, c) & PrimitiveFlag) {
|
|
const char* name = reinterpret_cast<char*>
|
|
(&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<int64_t>
|
|
(classStaticTable
|
|
(t, jclassVmClass
|
|
(t, jfieldClazz(t, reinterpret_cast<object>(arguments[1])))));
|
|
}
|
|
|
|
extern "C" JNIEXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_objectFieldOffset
|
|
(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object jfield = reinterpret_cast<object>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
|
|
return cast<uintptr_t>(o, offset);
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
Avian_sun_misc_Unsafe_putObject
|
|
(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
uintptr_t value = arguments[4];
|
|
|
|
set(t, o, offset, reinterpret_cast<object>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
|
|
return cast<int32_t>(o, offset);
|
|
}
|
|
|
|
extern "C" JNIEXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_getIntVolatile
|
|
(Thread*, object, uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
|
|
int32_t result = cast<int32_t>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
int32_t value = arguments[4];
|
|
|
|
cast<int32_t>(o, offset) = value;
|
|
}
|
|
|
|
extern "C" JNIEXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_getBoolean
|
|
(Thread*, object, uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
|
|
return cast<uint8_t>(o, offset);
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
Avian_sun_misc_Unsafe_putBoolean
|
|
(Thread*, object, uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
uint8_t value = arguments[4];
|
|
|
|
cast<uint8_t>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
int64_t value; memcpy(&value, arguments + 4, 8);
|
|
|
|
cast<int64_t>(o, offset) = value;
|
|
}
|
|
|
|
extern "C" JNIEXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_getObjectVolatile
|
|
(Thread*, object, uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
|
|
uintptr_t value = cast<uintptr_t>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
uint32_t expect = arguments[4];
|
|
uint32_t update = arguments[5];
|
|
|
|
return atomicCompareAndSwap32
|
|
(&cast<uint32_t>(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<object>(arguments[1]);
|
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
|
uintptr_t expect = arguments[4];
|
|
uintptr_t update = arguments[5];
|
|
|
|
bool success = atomicCompareAndSwap
|
|
(&cast<uintptr_t>(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<object>(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<uint64_t>(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<int64_t>(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<void*>(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<int8_t*>(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<int64_t*>(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<int32_t*>(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<int8_t*>(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<int32_t*>(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<object>(arguments[1])));
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
Avian_sun_misc_Unsafe_unpark
|
|
(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object thread = reinterpret_cast<object>(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<jobject>(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<uintptr_t>(o);
|
|
memcpy(arguments + 1, &milliseconds, sizeof(jlong));
|
|
|
|
run(t, jvmWait, arguments);
|
|
}
|
|
|
|
uint64_t
|
|
jvmNotify(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
notify(t, *o);
|
|
|
|
return 1;
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
EXPORT(JVM_MonitorNotify)(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o) };
|
|
|
|
run(t, jvmNotify, arguments);
|
|
}
|
|
|
|
uint64_t
|
|
jvmNotifyAll(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
notifyAll(t, *o);
|
|
|
|
return 1;
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o) };
|
|
|
|
run(t, jvmNotifyAll, arguments);
|
|
}
|
|
|
|
uint64_t
|
|
jvmClone(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, clone(t, *o)));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobject JNICALL
|
|
EXPORT(JVM_Clone)(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o) };
|
|
|
|
return reinterpret_cast<jobject>(run(t, jvmClone, arguments));
|
|
}
|
|
|
|
uint64_t
|
|
jvmInternString(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, intern(t, *o)));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jstring JNICALL
|
|
EXPORT(JVM_InternString)(Thread* t, jstring s)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(s) };
|
|
|
|
return reinterpret_cast<jobject>(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<jobject>(arguments[0]);
|
|
jint srcOffset = arguments[1];
|
|
jobject dst = reinterpret_cast<jobject>(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<uintptr_t>(src),
|
|
srcOffset,
|
|
reinterpret_cast<uintptr_t>(dst),
|
|
dstOffset,
|
|
length };
|
|
|
|
run(t, jvmArrayCopy, arguments);
|
|
}
|
|
|
|
uint64_t
|
|
jvmInitProperties(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject properties = reinterpret_cast<jobject>(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<local::MyClasspath*>(t->m->classpath)->javaHome);
|
|
|
|
local::setProperty
|
|
(t, method, *properties, "sun.boot.library.path",
|
|
static_cast<local::MyClasspath*>(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<uint64_t>(properties);
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobject JNICALL
|
|
EXPORT(JVM_InitProperties)(Thread* t, jobject properties)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(properties) };
|
|
|
|
return reinterpret_cast<jobject>(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<Thread*>(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<const char*>(arguments[0]);
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, p, strlen(path) + 1);
|
|
replace('\\', '/', RUNTIME_ARRAY_BODY(p), path);
|
|
|
|
return reinterpret_cast<uint64_t>
|
|
(loadLibrary
|
|
(t, static_cast<local::MyClasspath*>(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<Thread*>(local::globalMachine->localThread->get());
|
|
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(path) };
|
|
|
|
return reinterpret_cast<void*>(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<Thread*>(local::globalMachine->localThread->get());
|
|
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (library == RTLD_DEFAULT) {
|
|
library = t->m->libraries;
|
|
}
|
|
|
|
return static_cast<System::Library*>(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<jobject>(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<uintptr_t>(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<jobject>(arguments[0]);
|
|
jint index = arguments[1];
|
|
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(throwable), index };
|
|
|
|
return reinterpret_cast<jobject>(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<Thread*>(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<jobject>(arguments[0]);
|
|
|
|
monitorAcquire(t, local::interruptLock(t, *thread));
|
|
Thread* p = reinterpret_cast<Thread*>(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<uintptr_t>(thread) };
|
|
|
|
run(t, jvmInterrupt, arguments);
|
|
}
|
|
|
|
uint64_t
|
|
jvmIsInterrupted(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject thread = reinterpret_cast<jobject>(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<uintptr_t>(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<jobjectArray>(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<Thread*>
|
|
(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<uint64_t>(makeLocalReference(t, result));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobjectArray JNICALL
|
|
EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(threads) };
|
|
|
|
return reinterpret_cast<jobjectArray>(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<uint64_t>(makeLocalReference(t, context));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobjectArray JNICALL
|
|
EXPORT(JVM_GetClassContext)(Thread* t)
|
|
{
|
|
return reinterpret_cast<jobjectArray>(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<uintptr_t>(*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<jclass>(arguments[0]);
|
|
jint length = arguments[1];
|
|
|
|
object c = jclassVmClass(t, *elementClass);
|
|
|
|
if (classVmFlags(t, c) & PrimitiveFlag) {
|
|
const char* name = reinterpret_cast<char*>
|
|
(&byteArrayBody(t, local::getClassName(t, c), 0));
|
|
|
|
switch (*name) {
|
|
case 'b':
|
|
if (name[1] == 'o') {
|
|
return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeBooleanArray(t, length)));
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeByteArray(t, length)));
|
|
}
|
|
case 'c': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeCharArray(t, length)));
|
|
case 'd': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeDoubleArray(t, length)));
|
|
case 'f': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeFloatArray(t, length)));
|
|
case 'i': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeIntArray(t, length)));
|
|
case 'l': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeLongArray(t, length)));
|
|
case 's': return reinterpret_cast<uint64_t>
|
|
(makeLocalReference(t, makeShortArray(t, length)));
|
|
default: abort(t);
|
|
}
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(elementClass),
|
|
length };
|
|
|
|
return reinterpret_cast<jobject>(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<const char*>(arguments[0]);
|
|
jboolean init = arguments[1];
|
|
jobject loader = reinterpret_cast<jobject>(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<uint64_t>(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<uintptr_t>(name),
|
|
init,
|
|
reinterpret_cast<uintptr_t>(loader),
|
|
throwError };
|
|
|
|
return reinterpret_cast<jclass>
|
|
(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<jobject>(arguments[0]);
|
|
jstring name = reinterpret_cast<jstring>(arguments[1]);
|
|
|
|
object spec = makeByteArray(t, stringLength(t, *name) + 1);
|
|
|
|
{ char* s = reinterpret_cast<char*>(&byteArrayBody(t, spec, 0));
|
|
stringChars(t, *name, s);
|
|
replace('.', '/', s);
|
|
}
|
|
|
|
object c = findLoadedClass(t, *loader, spec);
|
|
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(loader),
|
|
reinterpret_cast<uintptr_t>(name) };
|
|
|
|
return reinterpret_cast<jclass>(run(t, jvmFindLoadedClass, arguments));
|
|
}
|
|
|
|
uint64_t
|
|
jvmDefineClass(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject loader = reinterpret_cast<jobject>(arguments[0]);
|
|
const uint8_t* data = reinterpret_cast<const uint8_t*>(arguments[1]);
|
|
jsize length = arguments[2];
|
|
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(loader),
|
|
reinterpret_cast<uintptr_t>(data),
|
|
length };
|
|
|
|
return reinterpret_cast<jclass>(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<jclass>(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<uint64_t>(makeLocalReference(t, array));
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(c) };
|
|
|
|
return reinterpret_cast<jclass>(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<const char*>
|
|
(&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<uint64_t>
|
|
(makeLocalReference(t, t->m->processor->invoke(t, method, 0)));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobject JNICALL
|
|
EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass)
|
|
{
|
|
return reinterpret_cast<jobject>(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<jclass>(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<char*>
|
|
(&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<uint64_t>(makeLocalReference(t, array));
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(c), publicOnly };
|
|
|
|
return reinterpret_cast<jobjectArray>
|
|
(run(t, jvmGetClassDeclaredMethods, arguments));
|
|
}
|
|
|
|
uint64_t
|
|
jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(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<char*>
|
|
(&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<uint64_t>(makeLocalReference(t, array));
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(c), publicOnly };
|
|
|
|
return reinterpret_cast<jobjectArray>
|
|
(run(t, jvmGetClassDeclaredFields, arguments));
|
|
}
|
|
|
|
uint64_t
|
|
jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(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<char*>
|
|
(&byteArrayBody(t, methodName(t, vmMethod), 0)),
|
|
"<init>") == 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<uint64_t>(makeLocalReference(t, array));
|
|
} else {
|
|
return reinterpret_cast<uint64_t>
|
|
(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<uintptr_t>(c), publicOnly };
|
|
|
|
return reinterpret_cast<jobjectArray>
|
|
(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<jobject>(arguments[0]);
|
|
jobject instance = reinterpret_cast<jobject>(arguments[1]);
|
|
jobjectArray args = reinterpret_cast<jobjectArray>(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<uint64_t>(makeLocalReference(t, result));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobject JNICALL
|
|
EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance,
|
|
jobjectArray args)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(method),
|
|
reinterpret_cast<uintptr_t>(instance),
|
|
reinterpret_cast<uintptr_t>(args) };
|
|
|
|
return reinterpret_cast<jobject>(run(t, jvmInvokeMethod, arguments));
|
|
}
|
|
|
|
uint64_t
|
|
jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject constructor = reinterpret_cast<jobject>(arguments[0]);
|
|
jobjectArray args = reinterpret_cast<jobjectArray>(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<uint64_t>(makeLocalReference(t, instance));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jobject JNICALL
|
|
EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor,
|
|
jobjectArray args)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(constructor),
|
|
reinterpret_cast<uintptr_t>(args) };
|
|
|
|
return reinterpret_cast<jobject>
|
|
(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<jobject>(arguments[0]);
|
|
jint index = arguments[1];
|
|
|
|
object array = singletonObject(t, *pool, index - 1);
|
|
|
|
return reinterpret_cast<uint64_t>
|
|
(makeLocalReference
|
|
(t, t->m->classpath->makeString
|
|
(t, array, 0, cast<uintptr_t>(array, BytesPerWord) - 1)));
|
|
}
|
|
|
|
extern "C" JNIEXPORT jstring JNICALL
|
|
EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index)
|
|
{
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(pool), index };
|
|
|
|
return reinterpret_cast<jstring>
|
|
(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, "<init>", "(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<jobject>(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<uint64_t>
|
|
(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<uintptr_t>(action),
|
|
wrapException };
|
|
|
|
return reinterpret_cast<jobject>(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<HANDLE>(_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<System::Monitor*>(lock)->dispose();
|
|
}
|
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
EXPORT(JVM_RawMonitorEnter)(void* lock)
|
|
{
|
|
static_cast<System::Monitor*>(lock)->acquire
|
|
(static_cast<Thread*>
|
|
(local::globalMachine->localThread->get())->systemThread);
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
EXPORT(JVM_RawMonitorExit)(void* lock)
|
|
{
|
|
static_cast<System::Monitor*>(lock)->release
|
|
(static_cast<Thread*>
|
|
(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<object>(arguments[1]);
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, countryChars, stringLength(t, country) + 1);
|
|
stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars));
|
|
|
|
local::MyClasspath* cp = static_cast<local::MyClasspath*>(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<int64_t>(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
|