mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
2a43e68c16
So there I was, planning to just fix one little bug: Thread.holdsLock and Thread.yield were missing for the Android class library. Easy enough, right? So, I added a test, got it passing, and figured I'd go ahead and run ci.sh with all three class libraries. Big mistake. Here's the stuff I found: * minor inconsistency in README.md about OpenSSL version * untested, broken Class.getEnclosingMethod (reported by Josh) * JNI test failed for tails=true Android build * Runtime.nativeExit missing for Android build * obsolete assertion in CallEvent broke tails=true Android build * obsolete superclass field offset padding broke bootimage=true Android build * runtime annotation parsing broke bootimage=true Android build (because we couldn't modify Addendum.annotationTable for classes in the heap image) * ci.sh tried building with both android=... and openjdk=..., which the makefile rightfully balked at Sorry this is all in a single commit; I didn't expect so many unrelated issues, and I'm too lazy to break them apart.
847 lines
24 KiB
C++
847 lines
24 KiB
C++
/* Copyright (c) 2008-2014, 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 "avian/machine.h"
|
|
#include "avian/classpath-common.h"
|
|
#include "avian/process.h"
|
|
|
|
#include <avian/util/runtime-array.h>
|
|
|
|
using namespace vm;
|
|
|
|
namespace {
|
|
|
|
namespace local {
|
|
|
|
class MyClasspath : public Classpath {
|
|
public:
|
|
MyClasspath(Allocator* allocator) : allocator(allocator)
|
|
{
|
|
}
|
|
|
|
virtual GcJclass* makeJclass(Thread* t, GcClass* class_)
|
|
{
|
|
return vm::makeJclass(t, class_);
|
|
}
|
|
|
|
virtual GcString* makeString(Thread* t,
|
|
object array,
|
|
int32_t offset,
|
|
int32_t length)
|
|
{
|
|
return vm::makeString(t, array, offset, length, 0);
|
|
}
|
|
|
|
virtual GcThread* makeThread(Thread* t, Thread* parent)
|
|
{
|
|
GcThreadGroup* group;
|
|
if (parent) {
|
|
group = parent->javaThread->group();
|
|
} else {
|
|
group = makeThreadGroup(t, 0, 0, 0);
|
|
}
|
|
|
|
const unsigned NewState = 0;
|
|
const unsigned NormalPriority = 5;
|
|
|
|
return vm::makeThread(t,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
NewState,
|
|
NormalPriority,
|
|
0,
|
|
0,
|
|
0,
|
|
roots(t)->appLoader(),
|
|
0,
|
|
0,
|
|
group,
|
|
0);
|
|
}
|
|
|
|
virtual object makeJMethod(Thread* t, GcMethod* vmMethod)
|
|
{
|
|
PROTECT(t, vmMethod);
|
|
|
|
GcJmethod* jmethod = makeJmethod(t, vmMethod, false);
|
|
|
|
return vmMethod->name()->body()[0] == '<'
|
|
? (object)makeJconstructor(t, jmethod)
|
|
: (object)jmethod;
|
|
}
|
|
|
|
virtual GcMethod* getVMMethod(Thread* t, object jmethod)
|
|
{
|
|
return objectClass(t, jmethod) == type(t, GcJmethod::Type)
|
|
? cast<GcJmethod>(t, jmethod)->vmMethod()
|
|
: cast<GcJconstructor>(t, jmethod)->method()->vmMethod();
|
|
}
|
|
|
|
virtual object makeJField(Thread* t, GcField* vmField)
|
|
{
|
|
return makeJfield(t, vmField, false);
|
|
}
|
|
|
|
virtual GcField* getVMField(Thread* t UNUSED, GcJfield* jfield)
|
|
{
|
|
return jfield->vmField();
|
|
}
|
|
|
|
virtual void clearInterrupted(Thread*)
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
virtual void runThread(Thread* t)
|
|
{
|
|
GcMethod* method = resolveMethod(t,
|
|
roots(t)->bootLoader(),
|
|
"java/lang/Thread",
|
|
"run",
|
|
"(Ljava/lang/Thread;)V");
|
|
|
|
t->m->processor->invoke(t, method, 0, t->javaThread);
|
|
}
|
|
|
|
virtual void resolveNative(Thread* t, GcMethod* method)
|
|
{
|
|
vm::resolveNative(t, method);
|
|
}
|
|
|
|
virtual void interceptMethods(Thread*)
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
virtual void preBoot(Thread*)
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
virtual bool mayInitClasses()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
virtual void boot(Thread*)
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
virtual const char* bootClasspath()
|
|
{
|
|
return AVIAN_CLASSPATH;
|
|
}
|
|
|
|
virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
|
{
|
|
GcClass* c
|
|
= resolveClass(t, roots(t)->bootLoader(), "java/nio/DirectByteBuffer");
|
|
PROTECT(t, c);
|
|
|
|
object instance = makeNew(t, c);
|
|
PROTECT(t, instance);
|
|
|
|
GcMethod* constructor = resolveMethod(t, c, "<init>", "(JI)V");
|
|
|
|
t->m->processor->invoke(t,
|
|
constructor,
|
|
instance,
|
|
reinterpret_cast<int64_t>(p),
|
|
static_cast<int32_t>(capacity));
|
|
|
|
return instance;
|
|
}
|
|
|
|
virtual void* getDirectBufferAddress(Thread* t, object b)
|
|
{
|
|
PROTECT(t, b);
|
|
|
|
GcField* field = resolveField(t, objectClass(t, b), "address", "J");
|
|
|
|
return reinterpret_cast<void*>(fieldAtOffset<int64_t>(b, field->offset()));
|
|
}
|
|
|
|
virtual int64_t getDirectBufferCapacity(Thread* t, object b)
|
|
{
|
|
PROTECT(t, b);
|
|
|
|
GcField* field = resolveField(t, objectClass(t, b), "capacity", "I");
|
|
|
|
return fieldAtOffset<int32_t>(b, field->offset());
|
|
}
|
|
|
|
virtual bool canTailCall(Thread* t UNUSED,
|
|
GcMethod*,
|
|
GcByteArray* calleeClassName,
|
|
GcByteArray* calleeMethodName,
|
|
GcByteArray*)
|
|
{
|
|
// we can't tail call System.load[Library] or
|
|
// Runtime.load[Library] due to their use of
|
|
// ClassLoader.getCaller, which gets confused if we elide stack
|
|
// frames.
|
|
|
|
return (
|
|
(strcmp("loadLibrary",
|
|
reinterpret_cast<char*>(calleeMethodName->body().begin()))
|
|
and strcmp("load",
|
|
reinterpret_cast<char*>(calleeMethodName->body().begin())))
|
|
or (strcmp("java/lang/System",
|
|
reinterpret_cast<char*>(calleeClassName->body().begin()))
|
|
and strcmp(
|
|
"java/lang/Runtime",
|
|
reinterpret_cast<char*>(calleeClassName->body().begin()))));
|
|
}
|
|
|
|
virtual GcClassLoader* libraryClassLoader(Thread* t, GcMethod* caller)
|
|
{
|
|
return (caller->class_() == type(t, Gc::ClassLoaderType)
|
|
and t->libraryLoadStack)
|
|
? t->libraryLoadStack->classLoader
|
|
: caller->class_()->loader();
|
|
}
|
|
|
|
virtual void shutDown(Thread*)
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
virtual void dispose()
|
|
{
|
|
allocator->free(this, sizeof(*this));
|
|
}
|
|
|
|
Allocator* allocator;
|
|
};
|
|
|
|
void enumerateThreads(Thread* t,
|
|
Thread* x,
|
|
GcArray* array,
|
|
unsigned* index,
|
|
unsigned limit)
|
|
{
|
|
if (*index < limit) {
|
|
array->setBodyElement(t, *index, x->javaThread);
|
|
++(*index);
|
|
|
|
if (x->peer)
|
|
enumerateThreads(t, x->peer, array, index, limit);
|
|
|
|
if (x->child)
|
|
enumerateThreads(t, x->child, array, index, limit);
|
|
}
|
|
}
|
|
|
|
} // namespace local
|
|
|
|
} // namespace
|
|
|
|
namespace vm {
|
|
|
|
Classpath* makeClasspath(System*,
|
|
Allocator* allocator,
|
|
const char*,
|
|
const char*)
|
|
{
|
|
return new (allocator->allocate(sizeof(local::MyClasspath)))
|
|
local::MyClasspath(allocator);
|
|
}
|
|
|
|
} // namespace vm
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Object_toString(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
|
|
unsigned hash = objectHash(t, this_);
|
|
GcString* s = makeString(
|
|
t, "%s@0x%x", objectClass(t, this_)->name()->body().begin(), hash);
|
|
|
|
return reinterpret_cast<int64_t>(s);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Object_getVMClass(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<int64_t>(
|
|
objectClass(t, reinterpret_cast<object>(arguments[0])));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Object_wait(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
int64_t milliseconds;
|
|
memcpy(&milliseconds, arguments + 1, 8);
|
|
|
|
vm::wait(t, this_, milliseconds);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Object_notify(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
|
|
notify(t, this_);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Object_notifyAll(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
|
|
notifyAll(t, this_);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Object_hashCode(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
|
|
return objectHash(t, this_);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Object_clone(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<int64_t>(
|
|
clone(t, reinterpret_cast<object>(arguments[0])));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_io_ObjectInputStream_makeInstance(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
GcClass* c = cast<GcClass>(t, reinterpret_cast<object>(arguments[0]));
|
|
|
|
return reinterpret_cast<int64_t>(make(t, c));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_LegacyObjectInputStream_makeInstance(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
return Avian_java_io_ObjectInputStream_makeInstance(t, NULL, arguments);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Field_getPrimitive(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object instance = reinterpret_cast<object>(arguments[0]);
|
|
int code = arguments[1];
|
|
int offset = arguments[2];
|
|
|
|
switch (code) {
|
|
case ByteField:
|
|
return fieldAtOffset<int8_t>(instance, offset);
|
|
case BooleanField:
|
|
return fieldAtOffset<uint8_t>(instance, offset);
|
|
case CharField:
|
|
return fieldAtOffset<uint16_t>(instance, offset);
|
|
case ShortField:
|
|
return fieldAtOffset<int16_t>(instance, offset);
|
|
case IntField:
|
|
return fieldAtOffset<int32_t>(instance, offset);
|
|
case LongField:
|
|
return fieldAtOffset<int64_t>(instance, offset);
|
|
case FloatField:
|
|
return fieldAtOffset<uint32_t>(instance, offset);
|
|
case DoubleField:
|
|
return fieldAtOffset<uint64_t>(instance, offset);
|
|
default:
|
|
abort(t);
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Field_getObject(Thread*,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object instance = reinterpret_cast<object>(arguments[0]);
|
|
int offset = arguments[1];
|
|
|
|
return reinterpret_cast<int64_t>(fieldAtOffset<object>(instance, offset));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_reflect_Field_setPrimitive(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object instance = reinterpret_cast<object>(arguments[0]);
|
|
int code = arguments[1];
|
|
int offset = arguments[2];
|
|
int64_t value;
|
|
memcpy(&value, arguments + 3, 8);
|
|
|
|
switch (code) {
|
|
case ByteField:
|
|
fieldAtOffset<int8_t>(instance, offset) = static_cast<int8_t>(value);
|
|
break;
|
|
case BooleanField:
|
|
fieldAtOffset<uint8_t>(instance, offset) = static_cast<uint8_t>(value);
|
|
break;
|
|
case CharField:
|
|
fieldAtOffset<uint16_t>(instance, offset) = static_cast<uint16_t>(value);
|
|
break;
|
|
case ShortField:
|
|
fieldAtOffset<int16_t>(instance, offset) = static_cast<int16_t>(value);
|
|
break;
|
|
case IntField:
|
|
fieldAtOffset<int32_t>(instance, offset) = static_cast<int32_t>(value);
|
|
break;
|
|
case LongField:
|
|
fieldAtOffset<int64_t>(instance, offset) = static_cast<int64_t>(value);
|
|
break;
|
|
case FloatField:
|
|
fieldAtOffset<uint32_t>(instance, offset) = static_cast<uint32_t>(value);
|
|
break;
|
|
case DoubleField:
|
|
fieldAtOffset<uint64_t>(instance, offset) = static_cast<uint64_t>(value);
|
|
break;
|
|
default:
|
|
abort(t);
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_reflect_Field_setObject(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object instance = reinterpret_cast<object>(arguments[0]);
|
|
int offset = arguments[1];
|
|
object value = reinterpret_cast<object>(arguments[2]);
|
|
|
|
setField(t, instance, offset, value);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Constructor_make(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
GcClass* c = cast<GcClass>(t, reinterpret_cast<object>(arguments[0]));
|
|
|
|
return reinterpret_cast<int64_t>(make(t, c));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Method_getCaller(Thread* t, object, uintptr_t*)
|
|
{
|
|
return reinterpret_cast<int64_t>(getCaller(t, 2));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Method_invoke(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
GcMethod* method = cast<GcMethod>(t, reinterpret_cast<object>(arguments[0]));
|
|
object instance = reinterpret_cast<object>(arguments[1]);
|
|
object args = reinterpret_cast<object>(arguments[2]);
|
|
|
|
THREAD_RESOURCE0(t, {
|
|
if (t->exception) {
|
|
GcThrowable* exception = t->exception;
|
|
t->exception = makeThrowable(
|
|
t, GcInvocationTargetException::Type, 0, 0, exception);
|
|
}
|
|
});
|
|
|
|
unsigned returnCode = method->returnCode();
|
|
|
|
return reinterpret_cast<int64_t>(translateInvokeResult(
|
|
t, returnCode, t->m->processor->invokeArray(t, method, instance, args)));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Array_getLength(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object array = reinterpret_cast<object>(arguments[0]);
|
|
|
|
if (LIKELY(array)) {
|
|
unsigned elementSize = objectClass(t, array)->arrayElementSize();
|
|
|
|
if (LIKELY(elementSize)) {
|
|
return fieldAtOffset<uintptr_t>(array, BytesPerWord);
|
|
} else {
|
|
throwNew(t, GcIllegalArgumentException::Type);
|
|
}
|
|
} else {
|
|
throwNew(t, GcNullPointerException::Type);
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_reflect_Array_makeObjectArray(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
GcJclass* elementType
|
|
= cast<GcJclass>(t, reinterpret_cast<object>(arguments[0]));
|
|
int length = arguments[1];
|
|
|
|
return reinterpret_cast<int64_t>(
|
|
makeObjectArray(t, elementType->vmClass(), length));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Float_floatToRawIntBits(Thread*,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
return static_cast<int32_t>(*arguments);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Float_intBitsToFloat(Thread*, object, uintptr_t* arguments)
|
|
{
|
|
return static_cast<int32_t>(*arguments);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Double_doubleToRawLongBits(Thread*,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
int64_t v;
|
|
memcpy(&v, arguments, 8);
|
|
return v;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Double_longBitsToDouble(Thread*,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
int64_t v;
|
|
memcpy(&v, arguments, 8);
|
|
return v;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_String_intern(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
object this_ = reinterpret_cast<object>(arguments[0]);
|
|
|
|
return reinterpret_cast<int64_t>(intern(t, this_));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_System_getVMProperties(Thread* t, object, uintptr_t*)
|
|
{
|
|
object array
|
|
= makeObjectArray(t, type(t, GcString::Type), t->m->propertyCount);
|
|
PROTECT(t, array);
|
|
|
|
for (unsigned i = 0; i < t->m->propertyCount; ++i) {
|
|
GcString* s = makeString(t, "%s", t->m->properties[i]);
|
|
reinterpret_cast<GcArray*>(array)->setBodyElement(t, i, s);
|
|
}
|
|
|
|
return reinterpret_cast<int64_t>(array);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_System_arraycopy(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
arrayCopy(t,
|
|
reinterpret_cast<object>(arguments[0]),
|
|
arguments[1],
|
|
reinterpret_cast<object>(arguments[2]),
|
|
arguments[3],
|
|
arguments[4]);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_System_identityHashCode(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object o = reinterpret_cast<object>(arguments[0]);
|
|
|
|
if (LIKELY(o)) {
|
|
return objectHash(t, o);
|
|
} else {
|
|
throwNew(t, GcNullPointerException::Type);
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_ClassLoader_getCaller(Thread* t, object, uintptr_t*)
|
|
{
|
|
return reinterpret_cast<int64_t>(getJClass(t, getCaller(t, 2)->class_()));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_ClassLoader_load(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
GcString* name = cast<GcString>(t, reinterpret_cast<object>(arguments[0]));
|
|
|
|
Thread::LibraryLoadStack stack(
|
|
t,
|
|
cast<GcJclass>(t, reinterpret_cast<object>(arguments[1]))
|
|
->vmClass()
|
|
->loader());
|
|
|
|
bool mapName = arguments[2];
|
|
|
|
unsigned length = name->length(t);
|
|
THREAD_RUNTIME_ARRAY(t, char, n, length + 1);
|
|
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
|
|
|
loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Runtime_gc(Thread* t, object, uintptr_t*)
|
|
{
|
|
collect(t, Heap::MajorCollection);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Runtime_addShutdownHook(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object hook = reinterpret_cast<object>(arguments[1]);
|
|
PROTECT(t, hook);
|
|
|
|
ACQUIRE(t, t->m->shutdownLock);
|
|
|
|
GcPair* p = makePair(t, hook, roots(t)->shutdownHooks());
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setShutdownHooks(t, p);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Throwable_trace(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<int64_t>(getTrace(t, arguments[0]));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Throwable_resolveTrace(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object trace = reinterpret_cast<object>(*arguments);
|
|
PROTECT(t, trace);
|
|
|
|
unsigned length = objectArrayLength(t, trace);
|
|
GcClass* elementType = type(t, GcStackTraceElement::Type);
|
|
object array = makeObjectArray(t, elementType, length);
|
|
PROTECT(t, array);
|
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
|
GcStackTraceElement* ste = makeStackTraceElement(
|
|
t, cast<GcTraceElement>(t, objectArrayBody(t, trace, i)));
|
|
reinterpret_cast<GcArray*>(array)->setBodyElement(t, i, ste);
|
|
}
|
|
|
|
return reinterpret_cast<int64_t>(array);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_currentThread(Thread* t, object, uintptr_t*)
|
|
{
|
|
return reinterpret_cast<int64_t>(t->javaThread);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_doStart(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<int64_t>(
|
|
startThread(t, cast<GcThread>(t, reinterpret_cast<object>(*arguments))));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Thread_interrupt(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
int64_t peer;
|
|
memcpy(&peer, arguments, 8);
|
|
|
|
threadInterrupt(t, reinterpret_cast<Thread*>(peer)->javaThread);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_interrupted(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
int64_t peer;
|
|
memcpy(&peer, arguments, 8);
|
|
|
|
return threadIsInterrupted(
|
|
t, reinterpret_cast<Thread*>(peer)->javaThread, true);
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_getStackTrace(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
int64_t peer;
|
|
memcpy(&peer, arguments, 8);
|
|
|
|
if (reinterpret_cast<Thread*>(peer) == t) {
|
|
return reinterpret_cast<int64_t>(makeTrace(t));
|
|
} else {
|
|
return reinterpret_cast<int64_t>(
|
|
t->m->processor->getStackTrace(t, reinterpret_cast<Thread*>(peer)));
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_activeCount(Thread* t, object, uintptr_t*)
|
|
{
|
|
return t->m->liveCount;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_enumerate(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
GcArray* array = cast<GcArray>(t, reinterpret_cast<object>(*arguments));
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
unsigned count = min(t->m->liveCount,
|
|
objectArrayLength(t, reinterpret_cast<object>(array)));
|
|
unsigned index = 0;
|
|
local::enumerateThreads(t, t->m->rootThread, array, &index, count);
|
|
return count;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_java_lang_Thread_holdsLock(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
GcMonitor* m
|
|
= objectMonitor(t, reinterpret_cast<object>(arguments[0]), false);
|
|
|
|
return m and m->owner() == t;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT void JNICALL
|
|
Avian_java_lang_Thread_yield(Thread* t, object, uintptr_t*)
|
|
{
|
|
t->m->system->yield();
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_Atomic_getOffset(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return cast<GcJfield>(t, reinterpret_cast<object>(arguments[0]))
|
|
->vmField()
|
|
->offset();
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_sun_misc_Unsafe_objectFieldOffset(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
return cast<GcJfield>(t, reinterpret_cast<object>(arguments[1]))
|
|
->vmField()
|
|
->offset();
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_Atomic_compareAndSwapObject(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
object target = reinterpret_cast<object>(arguments[0]);
|
|
int64_t offset;
|
|
memcpy(&offset, arguments + 1, 8);
|
|
uintptr_t expect = arguments[3];
|
|
uintptr_t update = arguments[4];
|
|
|
|
bool success = atomicCompareAndSwap(
|
|
&fieldAtOffset<uintptr_t>(target, offset), expect, update);
|
|
|
|
if (success) {
|
|
mark(t, target, offset);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_Classes_isAssignableFrom(Thread* t,
|
|
object,
|
|
uintptr_t* arguments)
|
|
{
|
|
GcClass* this_ = cast<GcClass>(t, reinterpret_cast<object>(arguments[0]));
|
|
GcClass* that = cast<GcClass>(t, reinterpret_cast<object>(arguments[1]));
|
|
|
|
if (LIKELY(that)) {
|
|
return vm::isAssignableFrom(t, this_, that);
|
|
} else {
|
|
throwNew(t, GcNullPointerException::Type);
|
|
}
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_Classes_getVMClass(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<int64_t>(
|
|
objectClass(t, reinterpret_cast<object>(arguments[0])));
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
Avian_avian_Classes_makeMethod(Thread* t, object, uintptr_t* arguments)
|
|
{
|
|
GcMethod* method = cast<GcMethod>(
|
|
t,
|
|
cast<GcArray>(t,
|
|
cast<GcJclass>(t, reinterpret_cast<object>(arguments[0]))
|
|
->vmClass()
|
|
->methodTable())->body()[arguments[1]]);
|
|
PROTECT(t, method);
|
|
|
|
GcClass* c
|
|
= resolveClass(t, roots(t)->bootLoader(), "java/lang/reflect/Method");
|
|
PROTECT(t, c);
|
|
|
|
object instance = makeNew(t, c);
|
|
PROTECT(t, instance);
|
|
|
|
GcMethod* constructor = resolveMethod(t, c, "<init>", "(Lavian/VMMethod;)V");
|
|
|
|
t->m->processor->invoke(t, constructor, instance, method);
|
|
|
|
if (method->name()->body()[0] == '<') {
|
|
object oldInstance = instance;
|
|
|
|
c = resolveClass(
|
|
t, roots(t)->bootLoader(), "java/lang/reflect/Constructor");
|
|
|
|
object instance = makeNew(t, c);
|
|
|
|
GcMethod* constructor
|
|
= resolveMethod(t, c, "<init>", "(Ljava/lang/Method;)V");
|
|
|
|
t->m->processor->invoke(t, constructor, instance, oldInstance);
|
|
}
|
|
|
|
return reinterpret_cast<uintptr_t>(instance);
|
|
}
|