corda/src/gnu.cpp
2009-09-03 09:06:04 -06:00

500 lines
14 KiB
C++

/* Copyright (c) 2009, 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 "constants.h"
#include "processor.h"
#include "util.h"
using namespace vm;
namespace {
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);
}
} // namespace
namespace vm {
jobject JNICALL
NewDirectByteBuffer(Thread* t, void* address, jlong capacity)
{
const char* pointerClassName;
const char* initSpec;
if (BytesPerWord == 8) {
pointerClassName = "gnu/classpath/Pointer64";
initSpec = "(J)V";
} else {
pointerClassName = "gnu/classpath/Pointer32";
initSpec = "(I)V";
}
object pointerClass = resolveClass(t, t->m->loader, pointerClassName);
if (UNLIKELY(pointerClass == 0)) return 0;
PROTECT(t, pointerClass);
object pointerConstructor = resolveMethod
(t, pointerClass, "<init>", initSpec);
if (UNLIKELY(pointerConstructor == 0)) return 0;
object pointer = make(t, pointerClass);
PROTECT(t, pointer);
t->m->processor->invoke(t, pointerConstructor, pointer, address);
if (UNLIKELY(t->exception)) return 0;
object bufferClass = resolveClass
(t, t->m->loader, "java/nio/DirectByteBufferImpl$ReadWrite");
if (UNLIKELY(bufferClass == 0)) return 0;
PROTECT(t, bufferClass);
object bufferConstructor = resolveMethod
(t, bufferClass, "<init>", "(Lgnu/classpath/Pointer;int)V");
if (UNLIKELY(bufferConstructor == 0)) return 0;
object buffer = make(t, bufferClass);
PROTECT(t, buffer);
t->m->processor->invoke
(t, bufferConstructor, buffer, &pointer, static_cast<jint>(capacity));
if (UNLIKELY(t->exception)) return 0;
return makeLocalReference(t, buffer);
}
void* JNICALL
GetDirectBufferAddress(Thread* t, jobject buffer)
{
object addressField = resolveField
(t, objectClass(t, *buffer), "address", "Lgnu/classpath/Pointer;");
if (UNLIKELY(addressField == 0)) return 0;
object address = cast<object>(*buffer, fieldOffset(t, addressField));
if (address == 0) return 0;
const char* dataSpec;
if (BytesPerWord == 8) {
dataSpec = "J";
} else {
dataSpec = "I";
}
object dataField = resolveField
(t, objectClass(t, address), "data", dataSpec);
if (UNLIKELY(dataField == 0)) return 0;
return cast<void*>(address, fieldOffset(t, dataField));
}
jlong JNICALL
GetDirectBufferCapacity(Thread* t, jobject buffer)
{
object capField = resolveField(t, objectClass(t, *buffer), "cap", "I");
if (UNLIKELY(capField == 0)) return 0;
return cast<jint>(*buffer, fieldOffset(t, capField));
}
} // namespace vm
extern "C" JNIEXPORT void JNICALL
Avian_gnu_classpath_VMSystemProperties_preInit
(Thread* t, object, uintptr_t* arguments)
{
object properties = reinterpret_cast<object>(arguments[0]);
PROTECT(t, properties);
object method = resolveMethod
(t, t->m->loader, "java/util/Properties", "setProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
if (UNLIKELY(t->exception)) {
return;
}
PROTECT(t, method);
setProperty(t, method, properties, "java.version", "1.5");
setProperty(t, method, properties, "java.specification.version", "1.5");
setProperty(t, method, properties, "java.vm.name", "Avian");
setProperty(t, method, properties, "java.protocol.handler.pkgs", "avian");
setProperty(t, method, properties, "file.encoding", "ASCII");
// specify a bogus library path so we can do our own search in
// VMRuntime.nativeLoad:
#define LIBRARY_PATH_SENTINAL "*"
setProperty(t, method, properties, "java.library.path",
LIBRARY_PATH_SENTINAL);
#ifdef PLATFORM_WINDOWS
# define FILE_SEPARATOR "\\"
setProperty(t, method, properties, "line.separator", "\r\n");
setProperty(t, method, properties, "file.separator", FILE_SEPARATOR);
setProperty(t, method, properties, "path.separator", ";");
setProperty(t, method, properties, "os.name", "Windows");
TCHAR buffer[MAX_PATH];
GetTempPath(MAX_PATH, buffer);
setProperty(t, method, properties, "java.io.tmpdir", buffer);
setProperty(t, method, properties, "user.home",
_wgetenv(L"USERPROFILE"), "%ls");
GetCurrentDirectory(MAX_PATH, buffer);
setProperty(t, method, properties, "user.dir", buffer);
#else
# define FILE_SEPARATOR "/"
setProperty(t, method, properties, "line.separator", "\n");
setProperty(t, method, properties, "file.separator", FILE_SEPARATOR);
setProperty(t, method, properties, "path.separator", ":");
# ifdef __APPLE__
setProperty(t, method, properties, "os.name", "Mac OS X");
# else
setProperty(t, method, properties, "os.name", "Linux");
# endif
setProperty(t, method, properties, "java.io.tmpdir", "/tmp");
setProperty(t, method, properties, "user.home", getenv("HOME"));
setProperty(t, method, properties, "user.dir", getenv("PWD"));
#endif
#ifdef ARCH_x86_32
setProperty(t, method, properties, "gnu.cpu.endian", "little");
setProperty(t, method, properties, "os.arch", "x86");
#elif defined ARCH_x86_64
setProperty(t, method, properties, "gnu.cpu.endian", "little");
setProperty(t, method, properties, "os.arch", "x86_64");
#elif defined ARCH_powerpc
setProperty(t, method, properties, "gnu.cpu.endian", "big");
setProperty(t, method, properties, "os.arch", "ppc");
#elif defined ARCH_arm
setProperty(t, method, properties, "os.arch", "arm");
#else
setProperty(t, method, properties, "os.arch", "unknown");
#endif
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassContext
(Thread* t, object, uintptr_t*)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t):
t(t), skipCount(1), trace(0), index(0), protector(t, &trace)
{ }
virtual bool visit(Processor::StackWalker* walker) {
if (skipCount == 0) {
if (trace == 0) {
trace = makeObjectArray
(t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType),
walker->count());
}
assert(t, index < objectArrayLength(t, trace));
set(t, trace, ArrayBody + (index * BytesPerWord),
methodClass(t, walker->method()));
++ index;
return true;
} else {
-- skipCount;
return true;
}
}
Thread* t;
unsigned skipCount;
object trace;
unsigned index;
Thread::SingleProtector protector;
} v(t);
t->m->processor->walkStack(t, &v);
if (v.trace == 0) {
v.trace = makeObjectArray
(t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), 0);
}
return reinterpret_cast<int64_t>(v.trace);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassLoader
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<int64_t>
(classLoader(t, reinterpret_cast<object>(arguments[0])));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_mapLibraryName
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
PROTECT(t, name);
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned nameLength = stringLength(t, name);
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned total = soPrefixLength + nameLength + soSuffixLength;
object s = makeByteArray(t, total + 1);
char* p = reinterpret_cast<char*>(&byteArrayBody(t, s, 0));
memcpy(p, SO_PREFIX, soPrefixLength);
stringChars(t, name, p + soPrefixLength);
memcpy(p + soPrefixLength + nameLength, SO_SUFFIX, soSuffixLength);
p[total] = 0;
return reinterpret_cast<int64_t>(makeString(t, s, 0, total, 0));
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_System_arraycopy
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMSystem_arraycopy
(Thread* t, object, uintptr_t* arguments)
{
Avian_java_lang_System_arraycopy(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_load
(Thread* t, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_nativeLoad
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
// given that we set java.library.path to LIBRARY_PATH_SENTINAL, we
// can determine which names are filenames and which are library
// names by looking for the prefix LIBRARY_PATH_SENTINAL
// FILE_SEPARATOR
unsigned length = stringLength(t, name);
char n[length + 1];
stringChars(t, name, n);
const unsigned pathPrefixLength
= sizeof(LIBRARY_PATH_SENTINAL) - 1
+ sizeof(FILE_SEPARATOR) - 1;
bool mapName = (strncmp(n, LIBRARY_PATH_SENTINAL FILE_SEPARATOR,
pathPrefixLength) == 0);
if (mapName) {
// strip the path prefix, SO prefix, and SO suffix before passing
// the name to Runtime.load
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned newOffset
= stringOffset(t, name) + pathPrefixLength + soPrefixLength;
const unsigned newLength
= length - pathPrefixLength - soPrefixLength - soSuffixLength;
name = makeString(t, stringData(t, name), newOffset, newLength, 0);
}
uintptr_t args[] = { reinterpret_cast<uintptr_t>(name), mapName };
Avian_java_lang_Runtime_load(t, 0, args);
if (t->exception) {
t->exception = 0;
return 0;
} else {
return 1;
}
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Class_primitiveClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_getPrimitiveClass
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_Class_primitiveClass(t, 0, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_ClassLoader_defineClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_defineClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[]
= { arguments[0], arguments[2], arguments[3], arguments[4] };
// object name = reinterpret_cast<object>(arguments[1]);
// char n[stringLength(t, name) + 1];
// stringChars(t, name, n);
// fprintf(stderr, "define class %s in %p\n", n,
// reinterpret_cast<void*>(arguments[0]));
return Avian_java_lang_ClassLoader_defineClass(t, 0, args);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_System_identityHashCode
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMSystem_identityHashCode
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_System_identityHashCode(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_gc
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_gc
(Thread* t, object, uintptr_t*)
{
Avian_java_lang_Runtime_gc(t, 0, 0);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_runFinalizationForExit
(Thread*, object, uintptr_t*)
{
// ignore
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_exit
(Thread*, object, uintptr_t* arguments)
{
exit(arguments[0]);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_loadClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[] = { 0, arguments[0] };
// object name = reinterpret_cast<object>(arguments[0]);
// char n[stringLength(t, name) + 1];
// stringChars(t, name, n);
// fprintf(stderr, "load bootstrap class %s in %p\n", n, t->m->loader);
return Avian_avian_SystemClassLoader_findClass(t, 0, args);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMClassLoader_resolveClass
(Thread*, object, uintptr_t*)
{
// ignore
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_findLoadedClass
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
object map = getClassLoaderMap(t, loader);
if (map) {
PROTECT(t, loader);
object name = reinterpret_cast<object>(arguments[1]);
PROTECT(t, name);
object n = makeByteArray(t, stringLength(t, name) + 1);
char* s = reinterpret_cast<char*>(&byteArrayBody(t, n, 0));
stringChars(t, name, s);
replace('.', '/', s);
return reinterpret_cast<int64_t>
(hashMapFind
(t, getClassLoaderMap(t, loader), n, byteArrayHash, byteArrayEqual));
} else {
return 0;
}
}
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);
int32_t expect = arguments[4];
int32_t update = arguments[5];
return __sync_bool_compare_and_swap
(&cast<int32_t>(target, offset), expect, update);
}
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);
int64_t expect; memcpy(&expect, arguments + 4, 8);
int64_t update; memcpy(&update, arguments + 6, 8);
return __sync_bool_compare_and_swap
(&cast<int64_t>(target, offset), expect, update);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_objectFieldOffset
(Thread* t, object, uintptr_t* arguments)
{
return fieldOffset(t, reinterpret_cast<object>(arguments[1]));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8
(Thread*, object, uintptr_t*)
{
return 0;
}