mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +00:00
rework VM exception handling; throw OOMEs when appropriate
This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling.
This commit is contained in:
@ -92,8 +92,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
(t, root(t, Machine::BootLoader),
|
(t, root(t, Machine::BootLoader),
|
||||||
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
||||||
|
|
||||||
if (t->exception) return 0;
|
|
||||||
|
|
||||||
PROTECT(t, c);
|
PROTECT(t, c);
|
||||||
|
|
||||||
if (classMethodTable(t, c)) {
|
if (classMethodTable(t, c)) {
|
||||||
@ -139,8 +137,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
o = resolveClass
|
o = resolveClass
|
||||||
(t, root(t, Machine::BootLoader), referenceName(t, o));
|
(t, root(t, Machine::BootLoader), referenceName(t, o));
|
||||||
|
|
||||||
if (t->exception) return 0;
|
|
||||||
|
|
||||||
set(t, addendumPool(t, addendum),
|
set(t, addendumPool(t, addendum),
|
||||||
SingletonBody + (index * BytesPerWord), o);
|
SingletonBody + (index * BytesPerWord), o);
|
||||||
}
|
}
|
||||||
@ -360,7 +356,7 @@ offset(object a, uintptr_t* b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
|
writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
|
||||||
unsigned codeCapacity, const char* className,
|
unsigned codeCapacity, const char* className,
|
||||||
const char* methodName, const char* methodSpec)
|
const char* methodName, const char* methodSpec)
|
||||||
{
|
{
|
||||||
@ -373,8 +369,6 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
|
|||||||
object constants = makeCodeImage
|
object constants = makeCodeImage
|
||||||
(t, &zone, image, code, codeMap, className, methodName, methodSpec);
|
(t, &zone, image, code, codeMap, className, methodName, methodSpec);
|
||||||
|
|
||||||
if (t->exception) return;
|
|
||||||
|
|
||||||
PROTECT(t, constants);
|
PROTECT(t, constants);
|
||||||
|
|
||||||
// this map will not be used when the bootimage is loaded, so
|
// this map will not be used when the bootimage is loaded, so
|
||||||
@ -505,6 +499,23 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
writeBootImage(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
FILE* out = reinterpret_cast<FILE*>(arguments[0]);
|
||||||
|
BootImage* image = reinterpret_cast<BootImage*>(arguments[1]);
|
||||||
|
uint8_t* code = reinterpret_cast<uint8_t*>(arguments[2]);
|
||||||
|
unsigned codeCapacity = arguments[3];
|
||||||
|
const char* className = reinterpret_cast<const char*>(arguments[4]);
|
||||||
|
const char* methodName = reinterpret_cast<const char*>(arguments[5]);
|
||||||
|
const char* methodSpec = reinterpret_cast<const char*>(arguments[6]);
|
||||||
|
|
||||||
|
writeBootImage2
|
||||||
|
(t, out, image, code, codeCapacity, className, methodName, methodSpec);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -540,15 +551,22 @@ main(int ac, const char** av)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBootImage
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(output),
|
||||||
(t, output, &image, code, CodeCapacity,
|
reinterpret_cast<uintptr_t>(&image),
|
||||||
(ac > 3 ? av[3] : 0), (ac > 4 ? av[4] : 0), (ac > 5 ? av[5] : 0));
|
reinterpret_cast<uintptr_t>(code),
|
||||||
|
CodeCapacity,
|
||||||
|
reinterpret_cast<uintptr_t>(ac > 3 ? av[3] : 0),
|
||||||
|
reinterpret_cast<uintptr_t>(ac > 4 ? av[4] : 0),
|
||||||
|
reinterpret_cast<uintptr_t>(ac > 5 ? av[5] : 0) };
|
||||||
|
|
||||||
|
run(t, writeBootImage, arguments);
|
||||||
|
|
||||||
fclose(output);
|
fclose(output);
|
||||||
|
|
||||||
if (t->exception) {
|
if (t->exception) {
|
||||||
printTrace(t, t->exception);
|
printTrace(t, t->exception);
|
||||||
}
|
return -1;
|
||||||
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,9 @@ search(Thread* t, object loader, object name,
|
|||||||
replace('.', '/', s);
|
replace('.', '/', s);
|
||||||
}
|
}
|
||||||
|
|
||||||
object r = op(t, loader, n);
|
return reinterpret_cast<int64_t>(op(t, loader, n));
|
||||||
if (t->exception) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<int64_t>(r);
|
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +75,7 @@ Avian_avian_SystemClassLoader_resourceExists
|
|||||||
object name = reinterpret_cast<object>(arguments[1]);
|
object name = reinterpret_cast<object>(arguments[1]);
|
||||||
|
|
||||||
if (LIKELY(name)) {
|
if (LIKELY(name)) {
|
||||||
RUNTIME_ARRAY(char, n, stringLength(t, name) + 1);
|
THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1);
|
||||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||||
|
|
||||||
unsigned length;
|
unsigned length;
|
||||||
@ -92,8 +86,7 @@ Avian_avian_SystemClassLoader_resourceExists
|
|||||||
|
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,17 +107,16 @@ Avian_avian_Machine_dumpHeap
|
|||||||
object outputFile = reinterpret_cast<object>(*arguments);
|
object outputFile = reinterpret_cast<object>(*arguments);
|
||||||
|
|
||||||
unsigned length = stringLength(t, outputFile);
|
unsigned length = stringLength(t, outputFile);
|
||||||
char n[length + 1];
|
THREAD_RUNTIME_ARRAY(t, char, n, length + 1);
|
||||||
stringChars(t, outputFile, n);
|
stringChars(t, outputFile, RUNTIME_ARRAY_BODY(n));
|
||||||
FILE* out = vm::fopen(n, "wb");
|
FILE* out = vm::fopen(RUNTIME_ARRAY_BODY(n), "wb");
|
||||||
if (out) {
|
if (out) {
|
||||||
{ ENTER(t, Thread::ExclusiveState);
|
{ ENTER(t, Thread::ExclusiveState);
|
||||||
dumpHeap(t, out);
|
dumpHeap(t, out);
|
||||||
}
|
}
|
||||||
fclose(out);
|
fclose(out);
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "file not found: %s", n);
|
throwNew(t, Machine::RuntimeExceptionType, "file not found: %s", n);
|
||||||
t->exception = makeThrowable(t, Machine::RuntimeExceptionType, message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +138,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
|
|||||||
object path = reinterpret_cast<object>(*arguments);
|
object path = reinterpret_cast<object>(*arguments);
|
||||||
|
|
||||||
if (LIKELY(path)) {
|
if (LIKELY(path)) {
|
||||||
RUNTIME_ARRAY(char, p, stringLength(t, path) + 1);
|
THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1);
|
||||||
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
|
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
|
||||||
|
|
||||||
System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p));
|
System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p));
|
||||||
@ -170,7 +162,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open
|
|||||||
object path = reinterpret_cast<object>(*arguments);
|
object path = reinterpret_cast<object>(*arguments);
|
||||||
|
|
||||||
if (LIKELY(path)) {
|
if (LIKELY(path)) {
|
||||||
RUNTIME_ARRAY(char, p, stringLength(t, path) + 1);
|
THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1);
|
||||||
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
|
stringChars(t, path, RUNTIME_ARRAY_BODY(p));
|
||||||
|
|
||||||
System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p));
|
System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p));
|
||||||
@ -180,8 +172,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open
|
|||||||
|
|
||||||
return reinterpret_cast<int64_t>(r);
|
return reinterpret_cast<int64_t>(r);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +60,8 @@ class MyClasspath : public Classpath {
|
|||||||
(t, root(t, Machine::BootLoader), "java/lang/Thread", "run",
|
(t, root(t, Machine::BootLoader), "java/lang/Thread", "run",
|
||||||
"(Ljava/lang/Thread;)V");
|
"(Ljava/lang/Thread;)V");
|
||||||
|
|
||||||
if (t->exception == 0) {
|
|
||||||
t->m->processor->invoke(t, method, 0, t->javaThread);
|
t->m->processor->invoke(t, method, 0, t->javaThread);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
boot(Thread*)
|
boot(Thread*)
|
||||||
@ -134,9 +132,8 @@ extern "C" JNIEXPORT int64_t JNICALL
|
|||||||
Avian_java_lang_Object_getVMClass
|
Avian_java_lang_Object_getVMClass
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
object o = reinterpret_cast<object>(arguments[0]);
|
return reinterpret_cast<int64_t>
|
||||||
|
(objectClass(t, reinterpret_cast<object>(arguments[0])));
|
||||||
return reinterpret_cast<int64_t>(objectClass(t, o));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
@ -307,12 +304,16 @@ Avian_java_lang_reflect_Method_invoke
|
|||||||
object instance = reinterpret_cast<object>(arguments[1]);
|
object instance = reinterpret_cast<object>(arguments[1]);
|
||||||
object args = reinterpret_cast<object>(arguments[2]);
|
object args = reinterpret_cast<object>(arguments[2]);
|
||||||
|
|
||||||
object v = t->m->processor->invokeArray(t, method, instance, args);
|
THREAD_RESOURCE0(t, {
|
||||||
if (t->exception) {
|
if (t->exception) {
|
||||||
|
object exception = t->exception;
|
||||||
t->exception = makeThrowable
|
t->exception = makeThrowable
|
||||||
(t, Machine::InvocationTargetExceptionType, 0, 0, t->exception);
|
(t, Machine::InvocationTargetExceptionType, 0, 0, exception);
|
||||||
}
|
}
|
||||||
return reinterpret_cast<int64_t>(v);
|
});
|
||||||
|
|
||||||
|
return reinterpret_cast<int64_t>
|
||||||
|
(t->m->processor->invokeArray(t, method, instance, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
@ -327,12 +328,11 @@ Avian_java_lang_reflect_Array_getLength
|
|||||||
if (LIKELY(elementSize)) {
|
if (LIKELY(elementSize)) {
|
||||||
return cast<uintptr_t>(array, BytesPerWord);
|
return cast<uintptr_t>(array, BytesPerWord);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType);
|
throwNew(t, Machine::IllegalArgumentExceptionType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
@ -394,7 +394,7 @@ Avian_java_lang_System_getVMProperty
|
|||||||
PROTECT(t, found);
|
PROTECT(t, found);
|
||||||
|
|
||||||
unsigned length = stringLength(t, name);
|
unsigned length = stringLength(t, name);
|
||||||
RUNTIME_ARRAY(char, n, length + 1);
|
THREAD_RUNTIME_ARRAY(t, char, n, length + 1);
|
||||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||||
|
|
||||||
int64_t r = 0;
|
int64_t r = 0;
|
||||||
@ -439,8 +439,7 @@ Avian_java_lang_System_identityHashCode
|
|||||||
if (LIKELY(o)) {
|
if (LIKELY(o)) {
|
||||||
return objectHash(t, o);
|
return objectHash(t, o);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +451,7 @@ Avian_java_lang_Runtime_load
|
|||||||
bool mapName = arguments[1];
|
bool mapName = arguments[1];
|
||||||
|
|
||||||
unsigned length = stringLength(t, name);
|
unsigned length = stringLength(t, name);
|
||||||
RUNTIME_ARRAY(char, n, length + 1);
|
THREAD_RUNTIME_ARRAY(t, char, n, length + 1);
|
||||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||||
|
|
||||||
loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true);
|
loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true);
|
||||||
@ -622,11 +621,13 @@ Avian_avian_Classes_defineVMClass
|
|||||||
|
|
||||||
uint8_t* buffer = static_cast<uint8_t*>
|
uint8_t* buffer = static_cast<uint8_t*>
|
||||||
(t->m->heap->allocate(length));
|
(t->m->heap->allocate(length));
|
||||||
memcpy(buffer, &byteArrayBody(t, b, offset), length);
|
|
||||||
object c = defineClass(t, loader, buffer, length);
|
|
||||||
t->m->heap->free(buffer, length);
|
|
||||||
|
|
||||||
return reinterpret_cast<int64_t>(c);
|
THREAD_RESOURCE2(t, uint8_t*, buffer, int, length,
|
||||||
|
t->m->heap->free(buffer, length));
|
||||||
|
|
||||||
|
memcpy(buffer, &byteArrayBody(t, b, offset), length);
|
||||||
|
|
||||||
|
return reinterpret_cast<int64_t>(defineClass(t, loader, buffer, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
@ -648,8 +649,7 @@ Avian_avian_Classes_isAssignableFrom
|
|||||||
if (LIKELY(that)) {
|
if (LIKELY(that)) {
|
||||||
return vm::isAssignableFrom(t, this_, that);
|
return vm::isAssignableFrom(t, this_, that);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +101,7 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable
|
throwNew(t, Machine::IndexOutOfBoundsExceptionType);
|
||||||
(t, Machine::IndexOutOfBoundsExceptionType);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -111,11 +109,11 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
throwNew(t, Machine::NullPointerExceptionType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->exception = makeThrowable(t, Machine::ArrayStoreExceptionType);
|
throwNew(t, Machine::ArrayStoreExceptionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -158,6 +156,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
|
|||||||
{
|
{
|
||||||
ACQUIRE(t, t->m->classLock);
|
ACQUIRE(t, t->m->classLock);
|
||||||
|
|
||||||
|
char* mappedName;
|
||||||
unsigned nameLength = strlen(name);
|
unsigned nameLength = strlen(name);
|
||||||
if (mapName) {
|
if (mapName) {
|
||||||
const char* builtins = findProperty(t, "avian.builtins");
|
const char* builtins = findProperty(t, "avian.builtins");
|
||||||
@ -186,15 +185,22 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
|
|||||||
const char* suffix = t->m->system->librarySuffix();
|
const char* suffix = t->m->system->librarySuffix();
|
||||||
unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix);
|
unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix);
|
||||||
|
|
||||||
char* mappedName = static_cast<char*>
|
mappedName = static_cast<char*>
|
||||||
(t->m->heap->allocate(mappedNameLength + 1));
|
(t->m->heap->allocate(mappedNameLength + 1));
|
||||||
|
|
||||||
snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix);
|
snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix);
|
||||||
|
|
||||||
name = mappedName;
|
name = mappedName;
|
||||||
nameLength = mappedNameLength;
|
nameLength = mappedNameLength;
|
||||||
|
} else {
|
||||||
|
mappedName = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THREAD_RESOURCE2
|
||||||
|
(t, char*, mappedName, unsigned, nameLength, if (mappedName) {
|
||||||
|
t->m->heap->free(mappedName, nameLength + 1);
|
||||||
|
});
|
||||||
|
|
||||||
System::Library* lib = 0;
|
System::Library* lib = 0;
|
||||||
for (Tokenizer tokenizer(path, t->m->system->pathSeparator());
|
for (Tokenizer tokenizer(path, t->m->system->pathSeparator());
|
||||||
tokenizer.hasMore();)
|
tokenizer.hasMore();)
|
||||||
@ -202,7 +208,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
|
|||||||
Tokenizer::Token token(tokenizer.next());
|
Tokenizer::Token token(tokenizer.next());
|
||||||
|
|
||||||
unsigned fullNameLength = token.length + 1 + nameLength;
|
unsigned fullNameLength = token.length + 1 + nameLength;
|
||||||
RUNTIME_ARRAY(char, fullName, fullNameLength + 1);
|
THREAD_RUNTIME_ARRAY(t, char, fullName, fullNameLength + 1);
|
||||||
|
|
||||||
snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1,
|
snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1,
|
||||||
"%*s/%s", token.length, token.s, name);
|
"%*s/%s", token.length, token.s, name);
|
||||||
@ -220,13 +226,8 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
|
|||||||
runOnLoadIfFound(t, lib);
|
runOnLoadIfFound(t, lib);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "library not found: %s", name);
|
throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s",
|
||||||
t->exception = makeThrowable
|
name);
|
||||||
(t, Machine::UnsatisfiedLinkErrorType, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapName) {
|
|
||||||
t->m->heap->free(name, nameLength + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lib;
|
return lib;
|
||||||
@ -264,7 +265,7 @@ makeStackTraceElement(Thread* t, object e)
|
|||||||
object class_ = className(t, methodClass(t, traceElementMethod(t, e)));
|
object class_ = className(t, methodClass(t, traceElementMethod(t, e)));
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
RUNTIME_ARRAY(char, s, byteArrayLength(t, class_));
|
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_));
|
||||||
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
||||||
reinterpret_cast<char*>(&byteArrayBody(t, class_, 0)));
|
reinterpret_cast<char*>(&byteArrayBody(t, class_, 0)));
|
||||||
class_ = makeString(t, "%s", s);
|
class_ = makeString(t, "%s", s);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
#define THREAD_STACK 2216
|
#define THREAD_STACK 2232
|
||||||
|
|
||||||
#if defined __MINGW32__ || defined __CYGWIN32__
|
#if defined __MINGW32__ || defined __CYGWIN32__
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ LOCAL(vmJumpAndInvoke_argumentTest):
|
|||||||
|
|
||||||
#elif defined __i386__
|
#elif defined __i386__
|
||||||
|
|
||||||
#define THREAD_STACK 2144
|
#define THREAD_STACK 2152
|
||||||
|
|
||||||
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16
|
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16
|
||||||
|
|
||||||
|
360
src/compile.cpp
360
src/compile.cpp
File diff suppressed because it is too large
Load Diff
@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
#define THREAD_CONTINUATION 2224
|
#define THREAD_CONTINUATION 2240
|
||||||
#define THREAD_EXCEPTION 80
|
#define THREAD_EXCEPTION 80
|
||||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232
|
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2248
|
||||||
#define THREAD_EXCEPTION_OFFSET 2240
|
#define THREAD_EXCEPTION_OFFSET 2256
|
||||||
#define THREAD_EXCEPTION_HANDLER 2248
|
#define THREAD_EXCEPTION_HANDLER 2264
|
||||||
|
|
||||||
#define CONTINUATION_NEXT 8
|
#define CONTINUATION_NEXT 8
|
||||||
#define CONTINUATION_ADDRESS 32
|
#define CONTINUATION_ADDRESS 32
|
||||||
@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit):
|
|||||||
|
|
||||||
#elif defined __i386__
|
#elif defined __i386__
|
||||||
|
|
||||||
#define THREAD_CONTINUATION 2148
|
#define THREAD_CONTINUATION 2156
|
||||||
#define THREAD_EXCEPTION 44
|
#define THREAD_EXCEPTION 44
|
||||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152
|
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160
|
||||||
#define THREAD_EXCEPTION_OFFSET 2156
|
#define THREAD_EXCEPTION_OFFSET 2164
|
||||||
#define THREAD_EXCEPTION_HANDLER 2160
|
#define THREAD_EXCEPTION_HANDLER 2168
|
||||||
|
|
||||||
#define CONTINUATION_NEXT 4
|
#define CONTINUATION_NEXT 4
|
||||||
#define CONTINUATION_ADDRESS 16
|
#define CONTINUATION_ADDRESS 16
|
||||||
|
31
src/heap.cpp
31
src/heap.cpp
@ -68,6 +68,7 @@ void assert(Context*, bool);
|
|||||||
|
|
||||||
System* system(Context*);
|
System* system(Context*);
|
||||||
void* tryAllocate(Context* c, unsigned size);
|
void* tryAllocate(Context* c, unsigned size);
|
||||||
|
void* allocate(Context* c, unsigned size);
|
||||||
void free(Context* c, const void* p, unsigned size);
|
void free(Context* c, const void* p, unsigned size);
|
||||||
void outOfMemory(Context*);
|
void outOfMemory(Context*);
|
||||||
|
|
||||||
@ -360,7 +361,9 @@ class Segment {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outOfMemory(context);
|
data = static_cast<uintptr_t*>
|
||||||
|
(local::allocate
|
||||||
|
(context, (footprint(capacity_)) * BytesPerWord));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1710,7 +1713,7 @@ collect(Context* c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
tryAllocate(Context* c, unsigned size)
|
allocate(Context* c, unsigned size, bool limit)
|
||||||
{
|
{
|
||||||
ACQUIRE(c->lock);
|
ACQUIRE(c->lock);
|
||||||
|
|
||||||
@ -1718,7 +1721,7 @@ tryAllocate(Context* c, unsigned size)
|
|||||||
size = pad(size) + 2 * BytesPerWord;
|
size = pad(size) + 2 * BytesPerWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size + c->count < c->limit) {
|
if ((not limit) or size + c->count < c->limit) {
|
||||||
void* p = c->system->tryAllocate(size);
|
void* p = c->system->tryAllocate(size);
|
||||||
if (p) {
|
if (p) {
|
||||||
c->count += size;
|
c->count += size;
|
||||||
@ -1735,6 +1738,18 @@ tryAllocate(Context* c, unsigned size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
tryAllocate(Context* c, unsigned size)
|
||||||
|
{
|
||||||
|
return allocate(c, size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(Context* c, unsigned size)
|
||||||
|
{
|
||||||
|
return allocate(c, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
free(Context* c, const void* p, unsigned size)
|
free(Context* c, const void* p, unsigned size)
|
||||||
{
|
{
|
||||||
@ -1787,16 +1802,16 @@ class MyHeap: public Heap {
|
|||||||
c.immortalHeapEnd = start + sizeInWords;
|
c.immortalHeapEnd = start + sizeInWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool limitExceeded() {
|
||||||
|
return c.count > c.limit;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
return local::tryAllocate(&c, size);
|
return local::tryAllocate(&c, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocate(unsigned size) {
|
virtual void* allocate(unsigned size) {
|
||||||
void* p = local::tryAllocate(&c, size);
|
return local::allocate(&c, size);
|
||||||
if (p == 0) {
|
|
||||||
c.client->outOfMemory();
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size) {
|
virtual void free(const void* p, unsigned size) {
|
||||||
|
@ -54,6 +54,7 @@ class Heap: public Allocator {
|
|||||||
|
|
||||||
virtual void setClient(Client* client) = 0;
|
virtual void setClient(Client* client) = 0;
|
||||||
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
|
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
|
||||||
|
virtual bool limitExceeded() = 0;
|
||||||
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
bool objectMask, unsigned* totalInBytes) = 0;
|
||||||
|
@ -435,7 +435,7 @@ checkStack(Thread* t, object method)
|
|||||||
+ codeMaxStack(t, methodCode(t, method))
|
+ codeMaxStack(t, methodCode(t, method))
|
||||||
> StackSizeInWords / 2))
|
> StackSizeInWords / 2))
|
||||||
{
|
{
|
||||||
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
|
throwNew(t, Machine::StackOverflowErrorType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,9 +570,9 @@ invokeNativeSlow(Thread* t, object method, void* function)
|
|||||||
}
|
}
|
||||||
unsigned count = methodParameterCount(t, method) + 2;
|
unsigned count = methodParameterCount(t, method) + 2;
|
||||||
|
|
||||||
RUNTIME_ARRAY(uintptr_t, args, footprint);
|
THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint);
|
||||||
unsigned argOffset = 0;
|
unsigned argOffset = 0;
|
||||||
RUNTIME_ARRAY(uint8_t, types, count);
|
THREAD_RUNTIME_ARRAY(t, uint8_t, types, count);
|
||||||
unsigned typeOffset = 0;
|
unsigned typeOffset = 0;
|
||||||
|
|
||||||
RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast<uintptr_t>(t);
|
RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast<uintptr_t>(t);
|
||||||
@ -613,6 +613,10 @@ invokeNativeSlow(Thread* t, object method, void* function)
|
|||||||
|
|
||||||
{ ENTER(t, Thread::IdleState);
|
{ ENTER(t, Thread::IdleState);
|
||||||
|
|
||||||
|
bool noThrow = t->checkpoint->noThrow;
|
||||||
|
t->checkpoint->noThrow = true;
|
||||||
|
THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow);
|
||||||
|
|
||||||
result = t->m->system->call
|
result = t->m->system->call
|
||||||
(function,
|
(function,
|
||||||
RUNTIME_ARRAY_BODY(args),
|
RUNTIME_ARRAY_BODY(args),
|
||||||
@ -633,7 +637,9 @@ invokeNativeSlow(Thread* t, object method, void* function)
|
|||||||
popFrame(t);
|
popFrame(t);
|
||||||
|
|
||||||
if (UNLIKELY(t->exception)) {
|
if (UNLIKELY(t->exception)) {
|
||||||
return VoidField;
|
object exception = t->exception;
|
||||||
|
t->exception = 0;
|
||||||
|
throw_(t, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
pushResult(t, returnCode, result, true);
|
pushResult(t, returnCode, result, true);
|
||||||
@ -648,10 +654,6 @@ invokeNative(Thread* t, object method)
|
|||||||
|
|
||||||
resolveNative(t, method);
|
resolveNative(t, method);
|
||||||
|
|
||||||
if (UNLIKELY(t->exception)) {
|
|
||||||
return VoidField;
|
|
||||||
}
|
|
||||||
|
|
||||||
object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method));
|
object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method));
|
||||||
if (nativeFast(t, native)) {
|
if (nativeFast(t, native)) {
|
||||||
pushFrame(t, method);
|
pushFrame(t, method);
|
||||||
@ -673,10 +675,6 @@ invokeNative(Thread* t, object method)
|
|||||||
|
|
||||||
popFrame(t);
|
popFrame(t);
|
||||||
|
|
||||||
if (UNLIKELY(t->exception)) {
|
|
||||||
return VoidField;
|
|
||||||
}
|
|
||||||
|
|
||||||
pushResult(t, methodReturnCode(t, method), result, false);
|
pushResult(t, methodReturnCode(t, method), result, false);
|
||||||
|
|
||||||
return methodReturnCode(t, method);
|
return methodReturnCode(t, method);
|
||||||
@ -802,10 +800,8 @@ pushField(Thread* t, object target, object field)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
interpret(Thread* t)
|
interpret3(Thread* t, const int base)
|
||||||
{
|
{
|
||||||
const int base = t->frame;
|
|
||||||
|
|
||||||
unsigned instruction = nop;
|
unsigned instruction = nop;
|
||||||
unsigned& ip = t->ip;
|
unsigned& ip = t->ip;
|
||||||
unsigned& sp = t->sp;
|
unsigned& sp = t->sp;
|
||||||
@ -858,10 +854,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushObject(t, objectArrayBody(t, array, index));
|
pushObject(t, objectArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString
|
|
||||||
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, objectArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -881,10 +876,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
set(t, array, ArrayBody + (index * BytesPerWord), value);
|
set(t, array, ArrayBody + (index * BytesPerWord), value);
|
||||||
} else {
|
} else {
|
||||||
object message = makeString
|
|
||||||
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, objectArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -924,13 +918,11 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
pushObject(t, makeObjectArray(t, class_, count));
|
pushObject(t, makeObjectArray(t, class_, count));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d", count);
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
(t, Machine::NegativeArraySizeExceptionType, "%d", count);
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} goto loop;
|
} goto loop;
|
||||||
@ -995,10 +987,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, booleanArrayBody(t, array, index));
|
pushInt(t, booleanArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
booleanArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
|
||||||
|
"%d not in [0,%d)", index, booleanArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1008,11 +999,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, byteArrayBody(t, array, index));
|
pushInt(t, byteArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
byteArrayLength(t, array));
|
|
||||||
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
|
||||||
|
"%d not in [0,%d)", index, byteArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1035,10 +1024,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
booleanArrayBody(t, array, index) = value;
|
booleanArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
booleanArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
|
||||||
|
"%d not in [0,%d)", index, booleanArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1047,10 +1035,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
byteArrayBody(t, array, index) = value;
|
byteArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
byteArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
|
||||||
|
"%d not in [0,%d)", index, byteArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1074,10 +1061,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, charArrayBody(t, array, index));
|
pushInt(t, charArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
charArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, charArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1097,10 +1083,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
charArrayBody(t, array, index) = value;
|
charArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
charArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, charArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1117,13 +1102,11 @@ interpret(Thread* t)
|
|||||||
if (UNLIKELY(exception)) goto throw_;
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
|
|
||||||
if (not instanceOf(t, class_, peekObject(t, sp - 1))) {
|
if (not instanceOf(t, class_, peekObject(t, sp - 1))) {
|
||||||
object message = makeString
|
exception = makeThrowable
|
||||||
(t, "%s as %s",
|
(t, Machine::ClassCastExceptionType, "%s as %s",
|
||||||
&byteArrayBody
|
&byteArrayBody
|
||||||
(t, className(t, objectClass(t, peekObject(t, sp - 1))), 0),
|
(t, className(t, objectClass(t, peekObject(t, sp - 1))), 0),
|
||||||
&byteArrayBody(t, className(t, class_), 0));
|
&byteArrayBody(t, className(t, class_), 0));
|
||||||
exception = makeThrowable
|
|
||||||
(t, Machine::ClassCastExceptionType, message);
|
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1158,10 +1141,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushLong(t, doubleArrayBody(t, array, index));
|
pushLong(t, doubleArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
doubleArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, doubleArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1181,10 +1163,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t));
|
memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
doubleArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, doubleArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1360,10 +1341,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, floatArrayBody(t, array, index));
|
pushInt(t, floatArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
floatArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, floatArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1383,10 +1363,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t));
|
memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
floatArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, floatArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1476,7 +1455,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
||||||
|
|
||||||
@ -1511,7 +1489,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
||||||
|
|
||||||
@ -1592,10 +1569,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, intArrayBody(t, array, index));
|
pushInt(t, intArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
intArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, intArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1622,10 +1598,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
intArrayBody(t, array, index) = value;
|
intArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
intArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, intArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1874,7 +1849,6 @@ interpret(Thread* t)
|
|||||||
|
|
||||||
if (peekObject(t, sp - 1)) {
|
if (peekObject(t, sp - 1)) {
|
||||||
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
if (instanceOf(t, class_, popObject(t))) {
|
if (instanceOf(t, class_, popObject(t))) {
|
||||||
pushInt(t, 1);
|
pushInt(t, 1);
|
||||||
@ -1893,7 +1867,6 @@ interpret(Thread* t)
|
|||||||
ip += 2;
|
ip += 2;
|
||||||
|
|
||||||
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||||
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
||||||
@ -1910,7 +1883,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||||
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
||||||
@ -1935,7 +1907,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
|
||||||
if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke;
|
if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke;
|
||||||
@ -1947,7 +1918,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||||
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
||||||
@ -2096,10 +2066,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushLong(t, longArrayBody(t, array, index));
|
pushLong(t, longArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
longArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, longArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2126,10 +2095,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
longArrayBody(t, array, index) = value;
|
longArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
longArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, longArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2170,7 +2138,6 @@ interpret(Thread* t)
|
|||||||
if (objectClass(t, v) == type(t, Machine::ReferenceType)) {
|
if (objectClass(t, v) == type(t, Machine::ReferenceType)) {
|
||||||
object class_ = resolveClassInPool
|
object class_ = resolveClassInPool
|
||||||
(t, frameMethod(t, frame), index - 1);
|
(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
pushObject(t, getJClass(t, class_));
|
pushObject(t, getJClass(t, class_));
|
||||||
} else if (objectClass(t, v) == type(t, Machine::ClassType)) {
|
} else if (objectClass(t, v) == type(t, Machine::ClassType)) {
|
||||||
@ -2389,16 +2356,14 @@ interpret(Thread* t)
|
|||||||
uint8_t dimensions = codeBody(t, code, ip++);
|
uint8_t dimensions = codeBody(t, code, ip++);
|
||||||
|
|
||||||
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
int32_t counts[dimensions];
|
int32_t counts[dimensions];
|
||||||
for (int i = dimensions - 1; i >= 0; --i) {
|
for (int i = dimensions - 1; i >= 0; --i) {
|
||||||
counts[i] = popInt(t);
|
counts[i] = popInt(t);
|
||||||
if (UNLIKELY(counts[i] < 0)) {
|
if (UNLIKELY(counts[i] < 0)) {
|
||||||
object message = makeString(t, "%d", counts[i]);
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
(t, Machine::NegativeArraySizeExceptionType, "%d", counts[i]);
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2416,7 +2381,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
|
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
|
||||||
@ -2470,9 +2434,8 @@ interpret(Thread* t)
|
|||||||
|
|
||||||
pushObject(t, array);
|
pushObject(t, array);
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d", count);
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
(t, Machine::NegativeArraySizeExceptionType, "%d", count);
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} goto loop;
|
} goto loop;
|
||||||
@ -2491,7 +2454,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
||||||
PROTECT(t, field);
|
PROTECT(t, field);
|
||||||
@ -2582,7 +2544,6 @@ interpret(Thread* t)
|
|||||||
uint16_t index = codeReadInt16(t, code, ip);
|
uint16_t index = codeReadInt16(t, code, ip);
|
||||||
|
|
||||||
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
object field = resolveField(t, frameMethod(t, frame), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
||||||
|
|
||||||
@ -2683,10 +2644,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
pushInt(t, shortArrayBody(t, array, index));
|
pushInt(t, shortArrayBody(t, array, index));
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
shortArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, shortArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2706,10 +2666,9 @@ interpret(Thread* t)
|
|||||||
{
|
{
|
||||||
shortArrayBody(t, array, index) = value;
|
shortArrayBody(t, array, index) = value;
|
||||||
} else {
|
} else {
|
||||||
object message = makeString(t, "%d not in [0,%d)", index,
|
|
||||||
shortArrayLength(t, array));
|
|
||||||
exception = makeThrowable
|
exception = makeThrowable
|
||||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
|
||||||
|
index, shortArrayLength(t, array));
|
||||||
goto throw_;
|
goto throw_;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2771,7 +2730,6 @@ interpret(Thread* t)
|
|||||||
|
|
||||||
resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))),
|
resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))),
|
||||||
className(t, class_));
|
className(t, class_));
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
ip -= 3;
|
ip -= 3;
|
||||||
} goto loop;
|
} goto loop;
|
||||||
@ -2822,11 +2780,8 @@ interpret(Thread* t)
|
|||||||
invoke: {
|
invoke: {
|
||||||
if (methodFlags(t, code) & ACC_NATIVE) {
|
if (methodFlags(t, code) & ACC_NATIVE) {
|
||||||
invokeNative(t, code);
|
invokeNative(t, code);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
} else {
|
} else {
|
||||||
checkStack(t, code);
|
checkStack(t, code);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
pushFrame(t, code);
|
pushFrame(t, code);
|
||||||
}
|
}
|
||||||
} goto loop;
|
} goto loop;
|
||||||
@ -2851,6 +2806,39 @@ interpret(Thread* t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
interpret2(vm::Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
int base = arguments[0];
|
||||||
|
bool* success = reinterpret_cast<bool*>(arguments[1]);
|
||||||
|
|
||||||
|
object r = interpret3(static_cast<Thread*>(t), base);
|
||||||
|
*success = true;
|
||||||
|
return reinterpret_cast<uint64_t>(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
interpret(Thread* t)
|
||||||
|
{
|
||||||
|
const int base = t->frame;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
bool success = false;
|
||||||
|
uintptr_t arguments[] = { base, reinterpret_cast<uintptr_t>(&success) };
|
||||||
|
|
||||||
|
uint64_t r = run(t, interpret2, arguments);
|
||||||
|
if (success) {
|
||||||
|
if (t->exception) {
|
||||||
|
object exception = t->exception;
|
||||||
|
t->exception = 0;
|
||||||
|
throw_(t, exception);
|
||||||
|
} else {
|
||||||
|
return reinterpret_cast<object>(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects,
|
pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects,
|
||||||
va_list a)
|
va_list a)
|
||||||
@ -2957,7 +2945,6 @@ invoke(Thread* t, object method)
|
|||||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||||
unsigned returnCode = invokeNative(t, method);
|
unsigned returnCode = invokeNative(t, method);
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
switch (returnCode) {
|
switch (returnCode) {
|
||||||
case ByteField:
|
case ByteField:
|
||||||
case BooleanField:
|
case BooleanField:
|
||||||
@ -2984,21 +2971,20 @@ invoke(Thread* t, object method)
|
|||||||
default:
|
default:
|
||||||
abort(t);
|
abort(t);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
checkStack(t, method);
|
checkStack(t, method);
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
pushFrame(t, method);
|
pushFrame(t, method);
|
||||||
|
|
||||||
result = interpret(t);
|
result = interpret(t);
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
if (LIKELY(t->exception == 0)) {
|
||||||
popFrame(t);
|
popFrame(t);
|
||||||
|
} else {
|
||||||
|
object exception = t->exception;
|
||||||
|
t->exception = 0;
|
||||||
|
throw_(t, exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (UNLIKELY(t->exception)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -3155,8 +3141,7 @@ class MyProcessor: public Processor {
|
|||||||
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
||||||
> StackSizeInWords / 2))
|
> StackSizeInWords / 2))
|
||||||
{
|
{
|
||||||
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
|
throwNew(t, Machine::StackOverflowErrorType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* spec = reinterpret_cast<char*>
|
const char* spec = reinterpret_cast<char*>
|
||||||
@ -3180,8 +3165,7 @@ class MyProcessor: public Processor {
|
|||||||
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
||||||
> StackSizeInWords / 2))
|
> StackSizeInWords / 2))
|
||||||
{
|
{
|
||||||
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
|
throwNew(t, Machine::StackOverflowErrorType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* spec = reinterpret_cast<char*>
|
const char* spec = reinterpret_cast<char*>
|
||||||
@ -3204,8 +3188,7 @@ class MyProcessor: public Processor {
|
|||||||
if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false)
|
if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false)
|
||||||
> StackSizeInWords / 2))
|
> StackSizeInWords / 2))
|
||||||
{
|
{
|
||||||
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
|
throwNew(t, Machine::StackOverflowErrorType);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pushArguments(t, this_, methodSpec, false, arguments);
|
pushArguments(t, this_, methodSpec, false, arguments);
|
||||||
@ -3213,13 +3196,9 @@ class MyProcessor: public Processor {
|
|||||||
object method = resolveMethod
|
object method = resolveMethod
|
||||||
(t, loader, className, methodName, methodSpec);
|
(t, loader, className, methodName, methodSpec);
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
|
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
|
||||||
|
|
||||||
return ::invoke(t, method);
|
return ::invoke(t, method);
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual object getStackTrace(vm::Thread*, vm::Thread*) {
|
virtual object getStackTrace(vm::Thread*, vm::Thread*) {
|
||||||
|
605
src/jnienv.cpp
605
src/jnienv.cpp
@ -71,11 +71,9 @@ DetachCurrentThread(Machine* m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
uint64_t
|
||||||
DestroyJavaVM(Machine* m)
|
destroyJavaVM(Thread* t, uintptr_t*)
|
||||||
{
|
{
|
||||||
Thread* t; AttachCurrentThread(m, &t, 0);
|
|
||||||
|
|
||||||
// wait for other non-daemon threads to exit
|
// wait for other non-daemon threads to exit
|
||||||
{ ACQUIRE(t, t->m->stateLock);
|
{ ACQUIRE(t, t->m->stateLock);
|
||||||
while (t->m->liveCount - t->m->daemonCount > 1) {
|
while (t->m->liveCount - t->m->daemonCount > 1) {
|
||||||
@ -83,16 +81,22 @@ DestroyJavaVM(Machine* m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ ENTER(t, Thread::ActiveState);
|
|
||||||
|
|
||||||
shutDown(t);
|
shutDown(t);
|
||||||
}
|
|
||||||
|
|
||||||
int exitCode = (t->exception ? -1 : 0);
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint JNICALL
|
||||||
|
DestroyJavaVM(Machine* m)
|
||||||
|
{
|
||||||
|
Thread* t; AttachCurrentThread(m, &t, 0);
|
||||||
|
|
||||||
|
if (run(t, destroyJavaVM, 0)) {
|
||||||
t->exit();
|
t->exit();
|
||||||
|
return 0;
|
||||||
return exitCode;
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -233,12 +237,11 @@ GetArrayLength(Thread* t, jarray array)
|
|||||||
return cast<uintptr_t>(*array, BytesPerWord);
|
return cast<uintptr_t>(*array, BytesPerWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring JNICALL
|
uint64_t
|
||||||
NewString(Thread* t, const jchar* chars, jsize size)
|
newString(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
if (chars == 0) return 0;
|
const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
|
||||||
|
jsize size = arguments[1];
|
||||||
ENTER(t, Thread::ActiveState);
|
|
||||||
|
|
||||||
object a = 0;
|
object a = 0;
|
||||||
if (size) {
|
if (size) {
|
||||||
@ -246,7 +249,31 @@ NewString(Thread* t, const jchar* chars, jsize size)
|
|||||||
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
|
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size));
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring JNICALL
|
||||||
|
NewString(Thread* t, const jchar* chars, jsize size)
|
||||||
|
{
|
||||||
|
if (chars == 0) return 0;
|
||||||
|
|
||||||
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(chars), size };
|
||||||
|
|
||||||
|
return reinterpret_cast<jstring>(run(t, newString, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
newStringUTF(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
const char* chars = reinterpret_cast<const char*>(arguments[0]);
|
||||||
|
|
||||||
|
object array = parseUtf8(t, chars, strlen(chars));
|
||||||
|
|
||||||
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference
|
||||||
|
(t, t->m->classpath->makeString
|
||||||
|
(t, array, 0, cast<uintptr_t>(array, BytesPerWord) - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring JNICALL
|
jstring JNICALL
|
||||||
@ -254,13 +281,9 @@ NewStringUTF(Thread* t, const char* chars)
|
|||||||
{
|
{
|
||||||
if (chars == 0) return 0;
|
if (chars == 0) return 0;
|
||||||
|
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(chars) };
|
||||||
|
|
||||||
object array = parseUtf8(t, chars, strlen(chars));
|
return reinterpret_cast<jstring>(run(t, newStringUTF, arguments));
|
||||||
|
|
||||||
return makeLocalReference
|
|
||||||
(t, t->m->classpath->makeString
|
|
||||||
(t, array, 0, cast<uintptr_t>(array, BytesPerWord) - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -274,44 +297,62 @@ replace(int a, int b, const char* in, int8_t* out)
|
|||||||
*out = 0;
|
*out = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
defineClass(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jobject loader = reinterpret_cast<jobject>(arguments[0]);
|
||||||
|
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(arguments[1]);
|
||||||
|
jsize length = arguments[2];
|
||||||
|
|
||||||
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference
|
||||||
|
(t, getJClass
|
||||||
|
(t, defineClass
|
||||||
|
(t, loader ? *loader : root(t, Machine::BootLoader), buffer, length))));
|
||||||
|
}
|
||||||
|
|
||||||
jclass JNICALL
|
jclass JNICALL
|
||||||
DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer,
|
DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer,
|
||||||
jsize length)
|
jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(loader),
|
||||||
|
reinterpret_cast<uintptr_t>(buffer),
|
||||||
|
length };
|
||||||
|
|
||||||
object c = defineClass
|
return reinterpret_cast<jclass>(run(t, defineClass, arguments));
|
||||||
(t, loader ? *loader : root(t, Machine::BootLoader),
|
|
||||||
reinterpret_cast<const uint8_t*>(buffer), length);
|
|
||||||
|
|
||||||
return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass JNICALL
|
uint64_t
|
||||||
FindClass(Thread* t, const char* name)
|
findClass(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
const char* name = reinterpret_cast<const char*>(arguments[0]);
|
||||||
|
|
||||||
object n = makeByteArray(t, strlen(name) + 1);
|
object n = makeByteArray(t, strlen(name) + 1);
|
||||||
replace('.', '/', name, &byteArrayBody(t, n, 0));
|
replace('.', '/', name, &byteArrayBody(t, n, 0));
|
||||||
|
|
||||||
object caller = getCaller(t, 0);
|
object caller = getCaller(t, 0);
|
||||||
|
|
||||||
object c = resolveClass
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference
|
||||||
|
(t, getJClass
|
||||||
|
(t, resolveClass
|
||||||
(t, caller ? classLoader(t, methodClass(t, caller))
|
(t, caller ? classLoader(t, methodClass(t, caller))
|
||||||
: root(t, Machine::AppLoader), n);
|
: root(t, Machine::AppLoader), n))));
|
||||||
|
|
||||||
return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jclass JNICALL
|
||||||
ThrowNew(Thread* t, jclass c, const char* message)
|
FindClass(Thread* t, const char* name)
|
||||||
{
|
{
|
||||||
if (t->exception) {
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(name) };
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENTER(t, Thread::ActiveState);
|
return reinterpret_cast<jclass>(run(t, findClass, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
throwNew(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
const char* message = reinterpret_cast<const char*>(arguments[1]);
|
||||||
|
|
||||||
object m = 0;
|
object m = 0;
|
||||||
PROTECT(t, m);
|
PROTECT(t, m);
|
||||||
@ -327,7 +368,20 @@ ThrowNew(Thread* t, jclass c, const char* message)
|
|||||||
set(t, t->exception, ThrowableMessage, m);
|
set(t, t->exception, ThrowableMessage, m);
|
||||||
set(t, t->exception, ThrowableTrace, trace);
|
set(t, t->exception, ThrowableTrace, trace);
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint JNICALL
|
||||||
|
ThrowNew(Thread* t, jclass c, const char* message)
|
||||||
|
{
|
||||||
|
if (t->exception) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(message) };
|
||||||
|
|
||||||
|
return run(t, throwNew, arguments) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -429,13 +483,14 @@ methodID(Thread* t, object method)
|
|||||||
return methodNativeID(t, method);
|
return methodNativeID(t, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID JNICALL
|
uint64_t
|
||||||
GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
getMethodID(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
||||||
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
||||||
|
|
||||||
object method = findMethod(t, c, name, spec);
|
object method = findMethod(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
assert(t, (methodFlags(t, method) & ACC_STATIC) == 0);
|
assert(t, (methodFlags(t, method) & ACC_STATIC) == 0);
|
||||||
|
|
||||||
@ -443,18 +498,39 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
jmethodID JNICALL
|
jmethodID JNICALL
|
||||||
GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(name),
|
||||||
|
reinterpret_cast<uintptr_t>(spec) };
|
||||||
|
|
||||||
|
return run(t, getMethodID, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
getStaticMethodID(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
||||||
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
||||||
|
|
||||||
object method = findMethod(t, c, name, spec);
|
object method = findMethod(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
assert(t, methodFlags(t, method) & ACC_STATIC);
|
assert(t, methodFlags(t, method) & ACC_STATIC);
|
||||||
|
|
||||||
return methodID(t, method);
|
return methodID(t, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jmethodID JNICALL
|
||||||
|
GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
|
{
|
||||||
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(name),
|
||||||
|
reinterpret_cast<uintptr_t>(spec) };
|
||||||
|
|
||||||
|
return run(t, getStaticMethodID, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
getMethod(Thread* t, jmethodID m)
|
getMethod(Thread* t, jmethodID m)
|
||||||
{
|
{
|
||||||
@ -465,17 +541,29 @@ getMethod(Thread* t, jmethodID m)
|
|||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
uint64_t
|
||||||
NewObjectV(Thread* t, jclass c, jmethodID m, va_list a)
|
newObjectV(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
jmethodID m = arguments[1];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
||||||
|
|
||||||
object o = make(t, jclassVmClass(t, *c));
|
object o = make(t, jclassVmClass(t, *c));
|
||||||
PROTECT(t, o);
|
PROTECT(t, o);
|
||||||
|
|
||||||
t->m->processor->invokeList(t, getMethod(t, m), o, true, a);
|
t->m->processor->invokeList(t, getMethod(t, m), o, true, *a);
|
||||||
|
|
||||||
return makeLocalReference(t, o);
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, o));
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject JNICALL
|
||||||
|
NewObjectV(Thread* t, jclass c, jmethodID m, va_list a)
|
||||||
|
{
|
||||||
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
|
return reinterpret_cast<jobject>(run(t, newObjectV, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -491,14 +579,27 @@ NewObject(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callObjectMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jobject o = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
jmethodID m = arguments[1];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
||||||
|
|
||||||
|
object method = getMethod(t, m);
|
||||||
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference
|
||||||
|
(t, t->m->processor->invokeList(t, method, *o, true, *a)));
|
||||||
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return reinterpret_cast<jobject>(run(t, callObjectMethodV, arguments));
|
||||||
return makeLocalReference
|
|
||||||
(t, t->m->processor->invokeList(t, method, *o, true, a));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -514,14 +615,25 @@ CallObjectMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callIntMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jobject o = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
jmethodID m = arguments[1];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
||||||
|
|
||||||
|
object method = getMethod(t, m);
|
||||||
|
return intValue(t, t->m->processor->invokeList(t, method, *o, true, *a));
|
||||||
|
}
|
||||||
|
|
||||||
jboolean JNICALL
|
jboolean JNICALL
|
||||||
CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callIntMethodV, arguments) != 0;
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? (intValue(t, r) != 0) : false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean JNICALL
|
jboolean JNICALL
|
||||||
@ -540,11 +652,11 @@ CallBooleanMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jbyte JNICALL
|
jbyte JNICALL
|
||||||
CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callIntMethodV, arguments);
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyte JNICALL
|
jbyte JNICALL
|
||||||
@ -563,11 +675,11 @@ CallByteMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jchar JNICALL
|
jchar JNICALL
|
||||||
CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callIntMethodV, arguments);
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jchar JNICALL
|
jchar JNICALL
|
||||||
@ -586,11 +698,11 @@ CallCharMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jshort JNICALL
|
jshort JNICALL
|
||||||
CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callIntMethodV, arguments);
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jshort JNICALL
|
jshort JNICALL
|
||||||
@ -609,11 +721,11 @@ CallShortMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jint JNICALL
|
jint JNICALL
|
||||||
CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callIntMethodV, arguments);
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -629,14 +741,25 @@ CallIntMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callLongMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jobject o = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
jmethodID m = arguments[1];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
||||||
|
|
||||||
|
object method = getMethod(t, m);
|
||||||
|
return longValue(t, t->m->processor->invokeList(t, method, *o, true, *a));
|
||||||
|
}
|
||||||
|
|
||||||
jlong JNICALL
|
jlong JNICALL
|
||||||
CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return run(t, callLongMethodV, arguments);
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? longValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jlong JNICALL
|
jlong JNICALL
|
||||||
@ -655,11 +778,11 @@ CallLongMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jfloat JNICALL
|
jfloat JNICALL
|
||||||
CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return bitsToFloat(run(t, callIntMethodV, arguments));
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? bitsToFloat(intValue(t, r)) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jfloat JNICALL
|
jfloat JNICALL
|
||||||
@ -678,11 +801,11 @@ CallFloatMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
jdouble JNICALL
|
jdouble JNICALL
|
||||||
CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
return bitsToDouble(run(t, callLongMethodV, arguments));
|
||||||
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
return (r ? bitsToDouble(longValue(t, r)) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jdouble JNICALL
|
jdouble JNICALL
|
||||||
@ -698,13 +821,27 @@ CallDoubleMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callVoidMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jobject o = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
jmethodID m = arguments[1];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
||||||
|
|
||||||
|
object method = getMethod(t, m);
|
||||||
|
t->m->processor->invokeList(t, method, *o, true, *a);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void JNICALL
|
void JNICALL
|
||||||
CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o),
|
||||||
|
m,
|
||||||
|
reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object method = getMethod(t, m);
|
run(t, callVoidMethodV, arguments);
|
||||||
t->m->processor->invokeList(t, method, *o, true, a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNICALL
|
void JNICALL
|
||||||
@ -728,13 +865,23 @@ getStaticMethod(Thread* t, jmethodID m)
|
|||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callStaticObjectMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jmethodID m = arguments[0];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
||||||
|
|
||||||
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference
|
||||||
|
(t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)));
|
||||||
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
return makeLocalReference(t, t->m->processor->invokeList
|
return reinterpret_cast<jobject>(run(t, callStaticObjectMethodV, arguments));
|
||||||
(t, getStaticMethod(t, m), 0, true, a));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -750,13 +897,22 @@ CallStaticObjectMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callStaticIntMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jmethodID m = arguments[0];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
||||||
|
|
||||||
|
return intValue
|
||||||
|
(t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a));
|
||||||
|
}
|
||||||
|
|
||||||
jboolean JNICALL
|
jboolean JNICALL
|
||||||
CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticIntMethodV, arguments) != 0;
|
||||||
return (r ? (intValue(t, r) != 0) : false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean JNICALL
|
jboolean JNICALL
|
||||||
@ -775,10 +931,9 @@ CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jbyte JNICALL
|
jbyte JNICALL
|
||||||
CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticIntMethodV, arguments);
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyte JNICALL
|
jbyte JNICALL
|
||||||
@ -797,10 +952,9 @@ CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jchar JNICALL
|
jchar JNICALL
|
||||||
CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticIntMethodV, arguments);
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jchar JNICALL
|
jchar JNICALL
|
||||||
@ -819,10 +973,9 @@ CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jshort JNICALL
|
jshort JNICALL
|
||||||
CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticIntMethodV, arguments);
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jshort JNICALL
|
jshort JNICALL
|
||||||
@ -841,10 +994,9 @@ CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jint JNICALL
|
jint JNICALL
|
||||||
CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticIntMethodV, arguments);
|
||||||
return (r ? intValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -860,13 +1012,22 @@ CallStaticIntMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callStaticLongMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jmethodID m = arguments[0];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
||||||
|
|
||||||
|
return longValue
|
||||||
|
(t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a));
|
||||||
|
}
|
||||||
|
|
||||||
jlong JNICALL
|
jlong JNICALL
|
||||||
CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return run(t, callStaticLongMethodV, arguments);
|
||||||
return (r ? longValue(t, r) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jlong JNICALL
|
jlong JNICALL
|
||||||
@ -885,10 +1046,9 @@ CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jfloat JNICALL
|
jfloat JNICALL
|
||||||
CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return bitsToFloat(run(t, callStaticIntMethodV, arguments));
|
||||||
return (r ? bitsToFloat(intValue(t, r)) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jfloat JNICALL
|
jfloat JNICALL
|
||||||
@ -907,10 +1067,9 @@ CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
jdouble JNICALL
|
jdouble JNICALL
|
||||||
CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
return bitsToDouble(run(t, callStaticLongMethodV, arguments));
|
||||||
return (r ? bitsToDouble(longValue(t, r)) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jdouble JNICALL
|
jdouble JNICALL
|
||||||
@ -926,12 +1085,23 @@ CallStaticDoubleMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
callStaticVoidMethodV(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jmethodID m = arguments[0];
|
||||||
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
||||||
|
|
||||||
|
t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void JNICALL
|
void JNICALL
|
||||||
CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { m, reinterpret_cast<uintptr_t>(a) };
|
||||||
|
|
||||||
t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a);
|
run(t, callStaticVoidMethodV, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNICALL
|
void JNICALL
|
||||||
@ -945,26 +1115,34 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
va_end(a);
|
va_end(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
getFieldID(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
||||||
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
||||||
|
|
||||||
|
return fieldOffset(t, resolveField(t, jclassVmClass(t, *c), name, spec));
|
||||||
|
}
|
||||||
|
|
||||||
jfieldID JNICALL
|
jfieldID JNICALL
|
||||||
GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(name),
|
||||||
|
reinterpret_cast<uintptr_t>(spec) };
|
||||||
|
|
||||||
object field = resolveField(t, jclassVmClass(t, *c), name, spec);
|
return run(t, getFieldID, arguments);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
return fieldOffset(t, field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID JNICALL
|
jfieldID JNICALL
|
||||||
GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(name),
|
||||||
|
reinterpret_cast<uintptr_t>(spec) };
|
||||||
|
|
||||||
object field = resolveField(t, jclassVmClass(t, *c), name, spec);
|
return run(t, getFieldID, arguments);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
return fieldOffset(t, field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -1325,17 +1503,29 @@ ExceptionClear(Thread* t)
|
|||||||
t->exception = 0;
|
t->exception = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobjectArray JNICALL
|
uint64_t
|
||||||
NewObjectArray(Thread* t, jsize length, jclass class_, jobject init)
|
newObjectArray(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
jsize length = arguments[0];
|
||||||
|
jclass class_ = reinterpret_cast<jclass>(arguments[1]);
|
||||||
|
jobject init = reinterpret_cast<jobject>(arguments[2]);
|
||||||
|
|
||||||
object a = makeObjectArray(t, jclassVmClass(t, *class_), length);
|
object a = makeObjectArray(t, jclassVmClass(t, *class_), length);
|
||||||
object value = (init ? *init : 0);
|
object value = (init ? *init : 0);
|
||||||
for (jsize i = 0; i < length; ++i) {
|
for (jsize i = 0; i < length; ++i) {
|
||||||
set(t, a, ArrayBody + (i * BytesPerWord), value);
|
set(t, a, ArrayBody + (i * BytesPerWord), value);
|
||||||
}
|
}
|
||||||
return makeLocalReference(t, a);
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
jobjectArray JNICALL
|
||||||
|
NewObjectArray(Thread* t, jsize length, jclass class_, jobject init)
|
||||||
|
{
|
||||||
|
uintptr_t arguments[] = { length,
|
||||||
|
reinterpret_cast<uintptr_t>(class_),
|
||||||
|
reinterpret_cast<uintptr_t>(init) };
|
||||||
|
|
||||||
|
return reinterpret_cast<jobjectArray>(run(t, newObjectArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -1355,68 +1545,102 @@ SetObjectArrayElement(Thread* t, jobjectArray array, jsize index,
|
|||||||
set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0));
|
set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
newArray(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
object (*constructor)(Thread*, unsigned)
|
||||||
|
= reinterpret_cast<object (*)(Thread*, unsigned)>(arguments[0]);
|
||||||
|
|
||||||
|
jsize length = arguments[1];
|
||||||
|
|
||||||
|
return reinterpret_cast<uint64_t>
|
||||||
|
(makeLocalReference(t, constructor(t, length)));
|
||||||
|
}
|
||||||
|
|
||||||
jbooleanArray JNICALL
|
jbooleanArray JNICALL
|
||||||
NewBooleanArray(Thread* t, jsize length)
|
NewBooleanArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeBooleanArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeBooleanArray(t, length));
|
return reinterpret_cast<jbooleanArray>(run(t, newArray, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
makeByteArray0(Thread* t, unsigned length)
|
||||||
|
{
|
||||||
|
return makeByteArray(t, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyteArray JNICALL
|
jbyteArray JNICALL
|
||||||
NewByteArray(Thread* t, jsize length)
|
NewByteArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeByteArray0)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeByteArray(t, length));
|
return reinterpret_cast<jbyteArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jcharArray JNICALL
|
jcharArray JNICALL
|
||||||
NewCharArray(Thread* t, jsize length)
|
NewCharArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeCharArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeCharArray(t, length));
|
return reinterpret_cast<jcharArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jshortArray JNICALL
|
jshortArray JNICALL
|
||||||
NewShortArray(Thread* t, jsize length)
|
NewShortArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeShortArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeShortArray(t, length));
|
return reinterpret_cast<jshortArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jintArray JNICALL
|
jintArray JNICALL
|
||||||
NewIntArray(Thread* t, jsize length)
|
NewIntArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeIntArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeIntArray(t, length));
|
return reinterpret_cast<jintArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jlongArray JNICALL
|
jlongArray JNICALL
|
||||||
NewLongArray(Thread* t, jsize length)
|
NewLongArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeLongArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeLongArray(t, length));
|
return reinterpret_cast<jlongArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jfloatArray JNICALL
|
jfloatArray JNICALL
|
||||||
NewFloatArray(Thread* t, jsize length)
|
NewFloatArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeFloatArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeFloatArray(t, length));
|
return reinterpret_cast<jfloatArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jdoubleArray JNICALL
|
jdoubleArray JNICALL
|
||||||
NewDoubleArray(Thread* t, jsize length)
|
NewDoubleArray(Thread* t, jsize length)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(makeDoubleArray)),
|
||||||
|
length };
|
||||||
|
|
||||||
return makeLocalReference(t, makeDoubleArray(t, length));
|
return reinterpret_cast<jdoubleArray>(run(t, newArray, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean* JNICALL
|
jboolean* JNICALL
|
||||||
@ -1909,11 +2133,13 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
uint64_t
|
||||||
RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods,
|
registerNatives(Thread* t, uintptr_t* arguments)
|
||||||
jint methodCount)
|
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
||||||
|
const JNINativeMethod* methods
|
||||||
|
= reinterpret_cast<const JNINativeMethod*>(arguments[1]);
|
||||||
|
jint methodCount = arguments[2];
|
||||||
|
|
||||||
for (int i = 0; i < methodCount; ++i) {
|
for (int i = 0; i < methodCount; ++i) {
|
||||||
if (methods[i].function) {
|
if (methods[i].function) {
|
||||||
@ -1930,7 +2156,18 @@ RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint JNICALL
|
||||||
|
RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods,
|
||||||
|
jint methodCount)
|
||||||
|
{
|
||||||
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(c),
|
||||||
|
reinterpret_cast<uintptr_t>(methods),
|
||||||
|
methodCount };
|
||||||
|
|
||||||
|
return run(t, registerNatives, arguments) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -1943,24 +2180,49 @@ UnregisterNatives(Thread* t, jclass c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
monitorOp(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
void (*op)(Thread*, object)
|
||||||
|
= reinterpret_cast<void (*)(Thread*, object)>(arguments[0]);
|
||||||
|
|
||||||
|
jobject o = reinterpret_cast<jobject>(arguments[1]);
|
||||||
|
|
||||||
|
op(t, *o);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
acquire0(Thread* t, object o)
|
||||||
|
{
|
||||||
|
return acquire(t, o);
|
||||||
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
MonitorEnter(Thread* t, jobject o)
|
MonitorEnter(Thread* t, jobject o)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(acquire0)),
|
||||||
|
reinterpret_cast<uintptr_t>(o) };
|
||||||
|
|
||||||
acquire(t, *o);
|
return run(t, monitorOp, arguments) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
void
|
||||||
|
release0(Thread* t, object o)
|
||||||
|
{
|
||||||
|
return acquire(t, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
MonitorExit(Thread* t, jobject o)
|
MonitorExit(Thread* t, jobject o)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
uintptr_t arguments[]
|
||||||
|
= { reinterpret_cast<uintptr_t>(voidPointer(release0)),
|
||||||
|
reinterpret_cast<uintptr_t>(o) };
|
||||||
|
|
||||||
release(t, *o);
|
return run(t, monitorOp, arguments) ? 0 : -1;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
@ -2030,20 +2292,23 @@ boot(Thread* t)
|
|||||||
{
|
{
|
||||||
enter(t, Thread::ActiveState);
|
enter(t, Thread::ActiveState);
|
||||||
|
|
||||||
if (t->exception == 0) {
|
t->javaThread = t->m->classpath->makeThread(t, 0);
|
||||||
|
|
||||||
setRoot(t, Machine::NullPointerException, makeThrowable
|
setRoot(t, Machine::NullPointerException, makeThrowable
|
||||||
(t, Machine::NullPointerExceptionType));
|
(t, Machine::NullPointerExceptionType));
|
||||||
|
|
||||||
if (t->exception == 0) {
|
|
||||||
setRoot(t, Machine::ArithmeticException,
|
setRoot(t, Machine::ArithmeticException,
|
||||||
makeThrowable(t, Machine::ArithmeticExceptionType));
|
makeThrowable(t, Machine::ArithmeticExceptionType));
|
||||||
|
|
||||||
if (t->exception == 0) {
|
|
||||||
setRoot(t, Machine::ArrayIndexOutOfBoundsException,
|
setRoot(t, Machine::ArrayIndexOutOfBoundsException,
|
||||||
makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType));
|
makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType));
|
||||||
}
|
|
||||||
}
|
setRoot(t, Machine::OutOfMemoryError,
|
||||||
}
|
makeThrowable(t, Machine::OutOfMemoryErrorType));
|
||||||
|
|
||||||
|
setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t));
|
||||||
|
|
||||||
|
threadDaemon(t, root(t, Machine::FinalizerThread)) = true;
|
||||||
|
|
||||||
t->m->classpath->boot(t);
|
t->m->classpath->boot(t);
|
||||||
|
|
||||||
|
321
src/machine.cpp
321
src/machine.cpp
@ -83,7 +83,7 @@ dispose(Thread* t, Thread* o, bool remove)
|
|||||||
expect(t, find(t->m->rootThread, o));
|
expect(t, find(t->m->rootThread, o));
|
||||||
|
|
||||||
unsigned c = count(t->m->rootThread, o);
|
unsigned c = count(t->m->rootThread, o);
|
||||||
RUNTIME_ARRAY(Thread*, threads, c);
|
THREAD_RUNTIME_ARRAY(t, Thread*, threads, c);
|
||||||
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
|
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -578,7 +578,14 @@ postCollect(Thread* t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t->heapOffset = 0;
|
t->heapOffset = 0;
|
||||||
|
|
||||||
|
if (t->m->heap->limitExceeded()) {
|
||||||
|
// if we're out of memory, pretend the thread-local heap is
|
||||||
|
// already full so we don't make things worse:
|
||||||
|
t->heapIndex = ThreadHeapSizeInWords;
|
||||||
|
} else {
|
||||||
t->heapIndex = 0;
|
t->heapIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (t->flags & Thread::UseBackupHeapFlag) {
|
if (t->flags & Thread::UseBackupHeapFlag) {
|
||||||
memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes);
|
memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes);
|
||||||
@ -592,6 +599,17 @@ postCollect(Thread* t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
invoke(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
object m = reinterpret_cast<object>(arguments[0]);
|
||||||
|
object o = reinterpret_cast<object>(arguments[1]);
|
||||||
|
|
||||||
|
t->m->processor->invoke(t, m, o);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
finalizeObject(Thread* t, object o)
|
finalizeObject(Thread* t, object o)
|
||||||
{
|
{
|
||||||
@ -604,7 +622,11 @@ finalizeObject(Thread* t, object o)
|
|||||||
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
|
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
|
||||||
&byteArrayBody(t, methodSpec(t, m), 0)) == 0)
|
&byteArrayBody(t, methodSpec(t, m), 0)) == 0)
|
||||||
{
|
{
|
||||||
t->m->processor->invoke(t, m, o);
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(m),
|
||||||
|
reinterpret_cast<uintptr_t>(o) };
|
||||||
|
|
||||||
|
run(t, invoke, arguments);
|
||||||
|
|
||||||
t->exception = 0;
|
t->exception = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -613,21 +635,6 @@ finalizeObject(Thread* t, object o)
|
|||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
|
||||||
makeByteArray(Thread* t, const char* format, va_list a)
|
|
||||||
{
|
|
||||||
const int Size = 256;
|
|
||||||
char buffer[Size];
|
|
||||||
|
|
||||||
int r = vm::vsnprintf(buffer, Size - 1, format, a);
|
|
||||||
expect(t, r >= 0 and r < Size - 1);
|
|
||||||
|
|
||||||
object s = makeByteArray(t, strlen(buffer) + 1);
|
|
||||||
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
readByte(Stream& s, unsigned* value)
|
readByte(Stream& s, unsigned* value)
|
||||||
{
|
{
|
||||||
@ -858,6 +865,9 @@ parsePool(Thread* t, Stream& s)
|
|||||||
if (count) {
|
if (count) {
|
||||||
uint32_t* index = static_cast<uint32_t*>(t->m->heap->allocate(count * 4));
|
uint32_t* index = static_cast<uint32_t*>(t->m->heap->allocate(count * 4));
|
||||||
|
|
||||||
|
THREAD_RESOURCE2(t, uint32_t*, index, unsigned, count,
|
||||||
|
t->m->heap->free(index, count * 4));
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
index[i] = s.position();
|
index[i] = s.position();
|
||||||
|
|
||||||
@ -889,6 +899,7 @@ parsePool(Thread* t, Stream& s)
|
|||||||
s.skip(8);
|
s.skip(8);
|
||||||
++ i;
|
++ i;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONSTANT_Double:
|
case CONSTANT_Double:
|
||||||
singletonSetBit(t, pool, count, i);
|
singletonSetBit(t, pool, count, i);
|
||||||
singletonSetBit(t, pool, count, i + 1);
|
singletonSetBit(t, pool, count, i + 1);
|
||||||
@ -911,8 +922,6 @@ parsePool(Thread* t, Stream& s)
|
|||||||
i += parsePoolEntry(t, s, index, pool, i);
|
i += parsePoolEntry(t, s, index, pool, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
t->m->heap->free(index, count * 4);
|
|
||||||
|
|
||||||
s.setPosition(end);
|
s.setPosition(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -960,7 +969,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
PROTECT(t, name);
|
PROTECT(t, name);
|
||||||
|
|
||||||
object interface = resolveClass(t, classLoader(t, class_), name);
|
object interface = resolveClass(t, classLoader(t, class_), name);
|
||||||
if (UNLIKELY(t->exception)) return;
|
|
||||||
|
|
||||||
PROTECT(t, interface);
|
PROTECT(t, interface);
|
||||||
|
|
||||||
@ -981,7 +989,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (HashMapIterator it(t, map); it.hasMore();) {
|
for (HashMapIterator it(t, map); it.hasMore();) {
|
||||||
object interface = tripleSecond(t, it.next());
|
object interface = tripleSecond(t, it.next());
|
||||||
if (UNLIKELY(t->exception)) return;
|
|
||||||
|
|
||||||
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
|
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
|
||||||
++ i;
|
++ i;
|
||||||
@ -1028,7 +1035,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
object addendum = 0;
|
object addendum = 0;
|
||||||
PROTECT(t, addendum);
|
PROTECT(t, addendum);
|
||||||
|
|
||||||
RUNTIME_ARRAY(uint8_t, staticTypes, count);
|
THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
unsigned flags = s.read2();
|
unsigned flags = s.read2();
|
||||||
@ -2046,6 +2053,7 @@ boot(Thread* t)
|
|||||||
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
|
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
|
||||||
|
|
||||||
setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0));
|
setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0));
|
||||||
|
|
||||||
m->processor->boot(t, 0);
|
m->processor->boot(t, 0);
|
||||||
|
|
||||||
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1);
|
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1);
|
||||||
@ -2162,6 +2170,67 @@ class HeapClient: public Heap::Client {
|
|||||||
Machine* m;
|
Machine* m;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
doCollect(Thread* t, Heap::CollectionType type)
|
||||||
|
{
|
||||||
|
#ifdef VM_STRESS
|
||||||
|
bool stress = (t->flags |= Thread::StressFlag);
|
||||||
|
if (not stress) atomicOr(&(t->flags), Thread::StressFlag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Machine* m = t->m;
|
||||||
|
|
||||||
|
m->unsafe = true;
|
||||||
|
m->heap->collect(type, footprint(m->rootThread));
|
||||||
|
m->unsafe = false;
|
||||||
|
|
||||||
|
postCollect(m->rootThread);
|
||||||
|
|
||||||
|
killZombies(t, m->rootThread);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
||||||
|
m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes);
|
||||||
|
}
|
||||||
|
m->heapPoolIndex = 0;
|
||||||
|
|
||||||
|
if (m->heap->limitExceeded()) {
|
||||||
|
// if we're out of memory, disallow further allocations of fixed
|
||||||
|
// objects:
|
||||||
|
m->fixedFootprint = FixedFootprintThresholdInBytes;
|
||||||
|
} else {
|
||||||
|
m->fixedFootprint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VM_STRESS
|
||||||
|
if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
object f = t->m->finalizeQueue;
|
||||||
|
t->m->finalizeQueue = 0;
|
||||||
|
for (; f; f = finalizerNext(t, f)) {
|
||||||
|
void (*function)(Thread*, object);
|
||||||
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
||||||
|
if (function) {
|
||||||
|
function(t, finalizerTarget(t, f));
|
||||||
|
} else {
|
||||||
|
setRoot(t, Machine::ObjectsToFinalize, makePair
|
||||||
|
(t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) {
|
||||||
|
m->finalizeThread = m->processor->makeThread
|
||||||
|
(m, root(t, Machine::FinalizerThread), m->rootThread);
|
||||||
|
|
||||||
|
addThread(t, m->finalizeThread);
|
||||||
|
|
||||||
|
if (not startThread(t, m->finalizeThread)) {
|
||||||
|
removeThread(t, m->finalizeThread);
|
||||||
|
m->finalizeThread = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
@ -2663,7 +2732,9 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
> ThreadHeapSizeInWords)
|
> ThreadHeapSizeInWords)
|
||||||
{
|
{
|
||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
if (t->m->heapPoolIndex < ThreadHeapPoolSize) {
|
if ((not t->m->heap->limitExceeded())
|
||||||
|
and t->m->heapPoolIndex < ThreadHeapPoolSize)
|
||||||
|
{
|
||||||
t->heap = static_cast<uintptr_t*>
|
t->heap = static_cast<uintptr_t*>
|
||||||
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
|
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
|
||||||
|
|
||||||
@ -2694,6 +2765,10 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
// vmPrintTrace(t);
|
// vmPrintTrace(t);
|
||||||
collect(t, Heap::MinorCollection);
|
collect(t, Heap::MinorCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t->m->heap->limitExceeded()) {
|
||||||
|
throw_(t, root(t, Machine::OutOfMemoryError));
|
||||||
|
}
|
||||||
} while (type == Machine::MovableAllocation
|
} while (type == Machine::MovableAllocation
|
||||||
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
> ThreadHeapSizeInWords);
|
> ThreadHeapSizeInWords);
|
||||||
@ -2759,12 +2834,51 @@ makeNewGeneral(Thread* t, object class_)
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NO_RETURN
|
||||||
|
throw_(Thread* t, object e)
|
||||||
|
{
|
||||||
|
assert(t, t->exception == 0);
|
||||||
|
|
||||||
|
Thread::Checkpoint* checkpoint = t->checkpoint;
|
||||||
|
|
||||||
|
expect(t, not checkpoint->noThrow);
|
||||||
|
|
||||||
|
t->exception = e;
|
||||||
|
|
||||||
|
while (t->resource != checkpoint->resource) {
|
||||||
|
Thread::Resource* r = t->resource;
|
||||||
|
t->resource = r->next;
|
||||||
|
r->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
t->protector = checkpoint->protector;
|
||||||
|
|
||||||
|
checkpoint->unwind();
|
||||||
|
|
||||||
|
abort(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
makeByteArray(Thread* t, const char* format, va_list a)
|
||||||
|
{
|
||||||
|
const int Size = 256;
|
||||||
|
char buffer[Size];
|
||||||
|
|
||||||
|
int r = vm::vsnprintf(buffer, Size - 1, format, a);
|
||||||
|
expect(t, r >= 0 and r < Size - 1);
|
||||||
|
|
||||||
|
object s = makeByteArray(t, strlen(buffer) + 1);
|
||||||
|
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
makeByteArray(Thread* t, const char* format, ...)
|
makeByteArray(Thread* t, const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list a;
|
va_list a;
|
||||||
va_start(a, format);
|
va_start(a, format);
|
||||||
object s = ::makeByteArray(t, format, a);
|
object s = makeByteArray(t, format, a);
|
||||||
va_end(a);
|
va_end(a);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@ -2775,7 +2889,7 @@ makeString(Thread* t, const char* format, ...)
|
|||||||
{
|
{
|
||||||
va_list a;
|
va_list a;
|
||||||
va_start(a, format);
|
va_start(a, format);
|
||||||
object s = ::makeByteArray(t, format, a);
|
object s = makeByteArray(t, format, a);
|
||||||
va_end(a);
|
va_end(a);
|
||||||
|
|
||||||
return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1);
|
return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1);
|
||||||
@ -2880,6 +2994,16 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
resolveBootstrap(Thread* t, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
object name = reinterpret_cast<object>(arguments[0]);
|
||||||
|
|
||||||
|
resolveSystemClass(t, root(t, Machine::BootLoader), name);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isAssignableFrom(Thread* t, object a, object b)
|
isAssignableFrom(Thread* t, object a, object b)
|
||||||
{
|
{
|
||||||
@ -2890,8 +3014,9 @@ isAssignableFrom(Thread* t, object a, object b)
|
|||||||
|
|
||||||
if (classFlags(t, a) & ACC_INTERFACE) {
|
if (classFlags(t, a) & ACC_INTERFACE) {
|
||||||
if (classVmFlags(t, b) & BootstrapFlag) {
|
if (classVmFlags(t, b) & BootstrapFlag) {
|
||||||
resolveSystemClass(t, root(t, Machine::BootLoader), className(t, b));
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(className(t, b)) };
|
||||||
if (UNLIKELY(t->exception)) {
|
|
||||||
|
if (run(t, resolveBootstrap, arguments) == 0) {
|
||||||
t->exception = 0;
|
t->exception = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3084,7 +3209,6 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
|||||||
if (super) {
|
if (super) {
|
||||||
object sc = resolveClass
|
object sc = resolveClass
|
||||||
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)));
|
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)));
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
set(t, class_, ClassSuper, sc);
|
set(t, class_, ClassSuper, sc);
|
||||||
|
|
||||||
@ -3094,16 +3218,12 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseInterfaceTable(t, s, class_, pool);
|
parseInterfaceTable(t, s, class_, pool);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
parseFieldTable(t, s, class_, pool);
|
parseFieldTable(t, s, class_, pool);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
parseMethodTable(t, s, class_, pool);
|
parseMethodTable(t, s, class_, pool);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
parseAttributeTable(t, s, class_, pool);
|
parseAttributeTable(t, s, class_, pool);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
object vtable = classVirtualTable(t, class_);
|
object vtable = classVirtualTable(t, class_);
|
||||||
unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0);
|
unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0);
|
||||||
@ -3160,7 +3280,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
|
|||||||
if (byteArrayBody(t, spec, 0) == '[') {
|
if (byteArrayBody(t, spec, 0) == '[') {
|
||||||
class_ = resolveArrayClass(t, loader, spec, throw_);
|
class_ = resolveArrayClass(t, loader, spec, throw_);
|
||||||
} else {
|
} else {
|
||||||
RUNTIME_ARRAY(char, file, byteArrayLength(t, spec) + 6);
|
THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6);
|
||||||
memcpy(RUNTIME_ARRAY_BODY(file),
|
memcpy(RUNTIME_ARRAY_BODY(file),
|
||||||
&byteArrayBody(t, spec, 0),
|
&byteArrayBody(t, spec, 0),
|
||||||
byteArrayLength(t, spec) - 1);
|
byteArrayLength(t, spec) - 1);
|
||||||
@ -3177,11 +3297,12 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
|
|||||||
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
|
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
|
||||||
|
|
||||||
// parse class file
|
// parse class file
|
||||||
class_ = parseClass(t, loader, region->start(), region->length());
|
class_ = parseClass(t, loader, region->start(), region->length());
|
||||||
region->dispose();
|
}
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
fprintf(stderr, "done parsing %s: %p\n",
|
fprintf(stderr, "done parsing %s: %p\n",
|
||||||
&byteArrayBody(t, spec, 0),
|
&byteArrayBody(t, spec, 0),
|
||||||
@ -3200,16 +3321,14 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (class_) {
|
if (class_) {
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
||||||
} else if (throw_ and t->exception == 0) {
|
} else if (throw_) {
|
||||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
|
||||||
t->exception = makeThrowable
|
&byteArrayBody(t, spec, 0));
|
||||||
(t, Machine::ClassNotFoundExceptionType, message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3265,28 +3384,24 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
object method = findVirtualMethod
|
object method = findVirtualMethod
|
||||||
(t, root(t, Machine::LoadClassMethod), objectClass(t, loader));
|
(t, root(t, Machine::LoadClassMethod), objectClass(t, loader));
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
|
||||||
RUNTIME_ARRAY(char, s, byteArrayLength(t, spec));
|
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec));
|
||||||
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
|
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
|
||||||
(&byteArrayBody(t, spec, 0)));
|
(&byteArrayBody(t, spec, 0)));
|
||||||
|
|
||||||
object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
|
object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
|
||||||
|
|
||||||
object jc = t->m->processor->invoke(t, method, loader, specString);
|
object jc = t->m->processor->invoke(t, method, loader, specString);
|
||||||
if (LIKELY(jc and t->exception == 0)) {
|
if (LIKELY(jc)) {
|
||||||
c = jclassVmClass(t, jc);
|
c = jclassVmClass(t, jc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LIKELY(c and t->exception == 0)) {
|
if (LIKELY(c)) {
|
||||||
PROTECT(t, c);
|
PROTECT(t, c);
|
||||||
|
|
||||||
ACQUIRE(t, t->m->classLock);
|
ACQUIRE(t, t->m->classLock);
|
||||||
@ -3301,13 +3416,8 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
|
|||||||
|
|
||||||
return c;
|
return c;
|
||||||
} else {
|
} else {
|
||||||
if (t->exception == 0) {
|
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
|
||||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
&byteArrayBody(t, spec, 0));
|
||||||
t->exception = makeThrowable
|
|
||||||
(t, Machine::ClassNotFoundExceptionType, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3325,13 +3435,10 @@ resolveMethod(Thread* t, object class_, const char* methodName,
|
|||||||
|
|
||||||
object method = findMethodInClass(t, class_, name, spec);
|
object method = findMethodInClass(t, class_, name, spec);
|
||||||
|
|
||||||
if (t->exception == 0 and method == 0) {
|
if (method == 0) {
|
||||||
object message = makeString
|
throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s",
|
||||||
(t, "%s %s not found in %s", methodName, methodSpec,
|
methodName, methodSpec, &byteArrayBody
|
||||||
&byteArrayBody(t, className(t, class_), 0));
|
(t, className(t, class_), 0));
|
||||||
|
|
||||||
t->exception = makeThrowable(t, Machine::NoSuchMethodErrorType, message);
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
@ -3358,13 +3465,9 @@ resolveField(Thread* t, object class_, const char* fieldName,
|
|||||||
field = findFieldInClass(t, c, name, spec);
|
field = findFieldInClass(t, c, name, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->exception == 0 and field == 0) {
|
if (field == 0) {
|
||||||
object message = makeString
|
throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s",
|
||||||
(t, "%s %s not found in %s", fieldName, fieldSpec,
|
fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0));
|
||||||
&byteArrayBody(t, className(t, class_), 0));
|
|
||||||
|
|
||||||
t->exception = makeThrowable(t, Machine::NoSuchFieldErrorType, message);
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
@ -3413,11 +3516,8 @@ preInitClass(Thread* t, object c)
|
|||||||
t->m->classLock->wait(t->systemThread, 0);
|
t->m->classLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
} else if (classVmFlags(t, c) & InitErrorFlag) {
|
} else if (classVmFlags(t, c) & InitErrorFlag) {
|
||||||
object message = makeString
|
throwNew(t, Machine::NoClassDefFoundErrorType, "%s",
|
||||||
(t, "%s", &byteArrayBody(t, className(t, c), 0));
|
&byteArrayBody(t, className(t, c), 0));
|
||||||
|
|
||||||
t->exception = makeThrowable
|
|
||||||
(t, Machine::NoClassDefFoundErrorType, message);
|
|
||||||
} else {
|
} else {
|
||||||
classVmFlags(t, c) |= InitFlag;
|
classVmFlags(t, c) |= InitFlag;
|
||||||
return true;
|
return true;
|
||||||
@ -3434,13 +3534,13 @@ postInitClass(Thread* t, object c)
|
|||||||
ACQUIRE(t, t->m->classLock);
|
ACQUIRE(t, t->m->classLock);
|
||||||
|
|
||||||
if (t->exception) {
|
if (t->exception) {
|
||||||
object exception = t->exception;
|
|
||||||
t->exception = 0;
|
|
||||||
t->exception = makeThrowable
|
|
||||||
(t, Machine::ExceptionInInitializerErrorType, 0, 0, exception);
|
|
||||||
|
|
||||||
classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag;
|
classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag;
|
||||||
classVmFlags(t, c) &= ~InitFlag;
|
classVmFlags(t, c) &= ~InitFlag;
|
||||||
|
|
||||||
|
object exception = t->exception;
|
||||||
|
t->exception = 0;
|
||||||
|
|
||||||
|
throwNew(t, Machine::ExceptionInInitializerErrorType, 0, 0, exception);
|
||||||
} else {
|
} else {
|
||||||
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
|
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
|
||||||
}
|
}
|
||||||
@ -3453,11 +3553,11 @@ initClass(Thread* t, object c)
|
|||||||
PROTECT(t, c);
|
PROTECT(t, c);
|
||||||
|
|
||||||
if (preInitClass(t, c)) {
|
if (preInitClass(t, c)) {
|
||||||
|
OBJECT_RESOURCE(t, c, postInitClass(t, c));
|
||||||
|
|
||||||
Thread::ClassInitStack stack(t, c);
|
Thread::ClassInitStack stack(t, c);
|
||||||
|
|
||||||
t->m->processor->invoke(t, classInitializer(t, c), 0);
|
t->m->processor->invoke(t, classInitializer(t, c), 0);
|
||||||
|
|
||||||
postInitClass(t, c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3496,7 +3596,6 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object arrayClass = resolveClass(t, loader, spec);
|
object arrayClass = resolveClass(t, loader, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass,
|
set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass,
|
||||||
arrayClass);
|
arrayClass);
|
||||||
@ -3509,7 +3608,6 @@ makeObjectArray(Thread* t, object elementClass, unsigned count)
|
|||||||
{
|
{
|
||||||
object arrayClass = resolveObjectArrayClass
|
object arrayClass = resolveObjectArrayClass
|
||||||
(t, classLoader(t, elementClass), elementClass);
|
(t, classLoader(t, elementClass), elementClass);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
PROTECT(t, arrayClass);
|
PROTECT(t, arrayClass);
|
||||||
|
|
||||||
@ -3692,57 +3790,16 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ExclusiveState);
|
ENTER(t, Thread::ExclusiveState);
|
||||||
|
|
||||||
#ifdef VM_STRESS
|
if (t->m->heap->limitExceeded()) {
|
||||||
bool stress = (t->flags |= Thread::StressFlag);
|
type = Heap::MajorCollection;
|
||||||
if (not stress) atomicOr(&(t->flags), Thread::StressFlag);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Machine* m = t->m;
|
|
||||||
|
|
||||||
m->unsafe = true;
|
|
||||||
m->heap->collect(type, footprint(m->rootThread));
|
|
||||||
m->unsafe = false;
|
|
||||||
|
|
||||||
postCollect(m->rootThread);
|
|
||||||
|
|
||||||
killZombies(t, m->rootThread);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
|
||||||
m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes);
|
|
||||||
}
|
|
||||||
m->heapPoolIndex = 0;
|
|
||||||
|
|
||||||
m->fixedFootprint = 0;
|
|
||||||
|
|
||||||
#ifdef VM_STRESS
|
|
||||||
if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
object f = t->m->finalizeQueue;
|
|
||||||
t->m->finalizeQueue = 0;
|
|
||||||
for (; f; f = finalizerNext(t, f)) {
|
|
||||||
void (*function)(Thread*, object);
|
|
||||||
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
||||||
if (function) {
|
|
||||||
function(t, finalizerTarget(t, f));
|
|
||||||
} else {
|
|
||||||
setRoot(t, Machine::ObjectsToFinalize, makePair
|
|
||||||
(t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) {
|
doCollect(t, type);
|
||||||
object javaThread = t->m->classpath->makeThread(t, m->rootThread);
|
|
||||||
threadDaemon(t, javaThread) = true;
|
|
||||||
|
|
||||||
m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread);
|
if (t->m->heap->limitExceeded()) {
|
||||||
|
// try once more, giving the heap a chance to squeeze everything
|
||||||
addThread(t, m->finalizeThread);
|
// into the smallest possible space:
|
||||||
|
doCollect(t, Heap::MajorCollection);
|
||||||
if (not startThread(t, m->finalizeThread)) {
|
|
||||||
removeThread(t, m->finalizeThread);
|
|
||||||
m->finalizeThread = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3762,7 +3819,7 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start)
|
|||||||
= (arrayElementSize ?
|
= (arrayElementSize ?
|
||||||
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
|
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
|
||||||
|
|
||||||
RUNTIME_ARRAY(uint32_t, mask, intArrayLength(t, objectMask));
|
THREAD_RUNTIME_ARRAY(t, uint32_t, mask, intArrayLength(t, objectMask));
|
||||||
memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0),
|
memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0),
|
||||||
intArrayLength(t, objectMask) * 4);
|
intArrayLength(t, objectMask) * 4);
|
||||||
|
|
||||||
@ -3836,7 +3893,7 @@ printTrace(Thread* t, object exception)
|
|||||||
|
|
||||||
if (throwableMessage(t, e)) {
|
if (throwableMessage(t, e)) {
|
||||||
object m = throwableMessage(t, e);
|
object m = throwableMessage(t, e);
|
||||||
RUNTIME_ARRAY(char, message, stringLength(t, m) + 1);
|
THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1);
|
||||||
stringChars(t, m, RUNTIME_ARRAY_BODY(message));
|
stringChars(t, m, RUNTIME_ARRAY_BODY(message));
|
||||||
fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message));
|
fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message));
|
||||||
} else {
|
} else {
|
||||||
|
378
src/machine.h
378
src/machine.h
@ -37,6 +37,56 @@
|
|||||||
|
|
||||||
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
|
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
|
||||||
|
|
||||||
|
#define THREAD_RESOURCE0(t, releaseBody) \
|
||||||
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
||||||
|
public: \
|
||||||
|
MAKE_NAME(Resource_)(Thread* t): Resource(t) { } \
|
||||||
|
~MAKE_NAME(Resource_)() { releaseBody; } \
|
||||||
|
virtual void release() \
|
||||||
|
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
|
||||||
|
} MAKE_NAME(resource_)(t);
|
||||||
|
|
||||||
|
#define OBJECT_RESOURCE(t, name, releaseBody) \
|
||||||
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
||||||
|
public: \
|
||||||
|
MAKE_NAME(Resource_)(Thread* t, object name): \
|
||||||
|
Resource(t), name(name), protector(t, &(this->name)) { } \
|
||||||
|
~MAKE_NAME(Resource_)() { releaseBody; } \
|
||||||
|
virtual void release() \
|
||||||
|
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
object name; \
|
||||||
|
Thread::SingleProtector protector; \
|
||||||
|
} MAKE_NAME(resource_)(t, name);
|
||||||
|
|
||||||
|
#define THREAD_RESOURCE(t, type, name, releaseBody) \
|
||||||
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
||||||
|
public: \
|
||||||
|
MAKE_NAME(Resource_)(Thread* t, type name): \
|
||||||
|
Resource(t), name(name) { } \
|
||||||
|
~MAKE_NAME(Resource_)() { releaseBody; } \
|
||||||
|
virtual void release() \
|
||||||
|
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
type name; \
|
||||||
|
} MAKE_NAME(resource_)(t, name);
|
||||||
|
|
||||||
|
#define THREAD_RESOURCE2(t, type1, name1, type2, name2, releaseBody) \
|
||||||
|
class MAKE_NAME(Resource_): public Thread::Resource { \
|
||||||
|
public: \
|
||||||
|
MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \
|
||||||
|
Resource(t), name1(name1), name2(name2) { } \
|
||||||
|
~MAKE_NAME(Resource_)() { releaseBody; } \
|
||||||
|
virtual void release() \
|
||||||
|
{ this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
type1 name1; \
|
||||||
|
type2 name2; \
|
||||||
|
} MAKE_NAME(resource_)(t, name1, name2);
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
@ -1201,10 +1251,12 @@ class Machine {
|
|||||||
MethodRuntimeDataTable,
|
MethodRuntimeDataTable,
|
||||||
JNIMethodTable,
|
JNIMethodTable,
|
||||||
ShutdownHooks,
|
ShutdownHooks,
|
||||||
|
FinalizerThread,
|
||||||
ObjectsToFinalize,
|
ObjectsToFinalize,
|
||||||
NullPointerException,
|
NullPointerException,
|
||||||
ArithmeticException,
|
ArithmeticException,
|
||||||
ArrayIndexOutOfBoundsException,
|
ArrayIndexOutOfBoundsException,
|
||||||
|
OutOfMemoryError,
|
||||||
VirtualFileFinders,
|
VirtualFileFinders,
|
||||||
VirtualFiles
|
VirtualFiles
|
||||||
};
|
};
|
||||||
@ -1280,15 +1332,23 @@ inline void stress(Thread* t);
|
|||||||
|
|
||||||
#endif // not VM_STRESS
|
#endif // not VM_STRESS
|
||||||
|
|
||||||
void
|
uint64_t
|
||||||
runJavaThread(Thread* t);
|
runThread(Thread*, uintptr_t*);
|
||||||
|
|
||||||
void
|
uint64_t
|
||||||
runFinalizeThread(Thread* t);
|
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
|
||||||
|
uintptr_t* arguments);
|
||||||
|
|
||||||
void
|
void
|
||||||
checkDaemon(Thread* t);
|
checkDaemon(Thread* t);
|
||||||
|
|
||||||
|
extern "C" uint64_t
|
||||||
|
vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments,
|
||||||
|
void* checkpoint);
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
vmRun_returnAddress();
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
@ -1336,9 +1396,26 @@ class Thread {
|
|||||||
object* p;
|
object* p;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClassInitStack {
|
class Resource {
|
||||||
|
public:
|
||||||
|
Resource(Thread* t): t(t), next(t->resource) {
|
||||||
|
t->resource = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Resource() {
|
||||||
|
t->resource = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() = 0;
|
||||||
|
|
||||||
|
Thread* t;
|
||||||
|
Resource* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClassInitStack: public Resource {
|
||||||
public:
|
public:
|
||||||
ClassInitStack(Thread* t, object class_):
|
ClassInitStack(Thread* t, object class_):
|
||||||
|
Resource(t),
|
||||||
next(t->classInitStack),
|
next(t->classInitStack),
|
||||||
class_(class_),
|
class_(class_),
|
||||||
protector(t, &(this->class_))
|
protector(t, &(this->class_))
|
||||||
@ -1347,7 +1424,11 @@ class Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~ClassInitStack() {
|
~ClassInitStack() {
|
||||||
protector.t->classInitStack = next;
|
t->classInitStack = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
this->ClassInitStack::~ClassInitStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassInitStack* next;
|
ClassInitStack* next;
|
||||||
@ -1355,6 +1436,50 @@ class Thread {
|
|||||||
SingleProtector protector;
|
SingleProtector protector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Checkpoint {
|
||||||
|
public:
|
||||||
|
Checkpoint(Thread* t):
|
||||||
|
t(t),
|
||||||
|
next(t->checkpoint),
|
||||||
|
resource(t->resource),
|
||||||
|
protector(t->protector),
|
||||||
|
noThrow(false)
|
||||||
|
{
|
||||||
|
t->checkpoint = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Checkpoint() {
|
||||||
|
t->checkpoint = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void NO_RETURN unwind() = 0;
|
||||||
|
|
||||||
|
Thread* t;
|
||||||
|
Checkpoint* next;
|
||||||
|
Resource* resource;
|
||||||
|
Protector* protector;
|
||||||
|
bool noThrow;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RunCheckpoint: public Checkpoint {
|
||||||
|
public:
|
||||||
|
RunCheckpoint(Thread* t):
|
||||||
|
Checkpoint(t),
|
||||||
|
stack(0),
|
||||||
|
base(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void unwind() {
|
||||||
|
void* stack = this->stack;
|
||||||
|
this->stack = 0;
|
||||||
|
expect(t->m->system, stack);
|
||||||
|
vmJump(voidPointer(vmRun_returnAddress), base, stack, t, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* stack;
|
||||||
|
void* base;
|
||||||
|
};
|
||||||
|
|
||||||
class Runnable: public System::Runnable {
|
class Runnable: public System::Runnable {
|
||||||
public:
|
public:
|
||||||
Runnable(Thread* t): t(t) { }
|
Runnable(Thread* t): t(t) { }
|
||||||
@ -1366,19 +1491,11 @@ class Thread {
|
|||||||
virtual void run() {
|
virtual void run() {
|
||||||
enterActiveState(t);
|
enterActiveState(t);
|
||||||
|
|
||||||
t->m->localThread->set(t);
|
vm::run(t, runThread, 0);
|
||||||
|
|
||||||
checkDaemon(t);
|
|
||||||
|
|
||||||
if (t == t->m->finalizeThread) {
|
|
||||||
runFinalizeThread(t);
|
|
||||||
} else if (t->javaThread) {
|
|
||||||
runJavaThread(t);
|
|
||||||
|
|
||||||
if (t->exception) {
|
if (t->exception) {
|
||||||
printTrace(t, t->exception);
|
printTrace(t, t->exception);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
t->exit();
|
t->exit();
|
||||||
}
|
}
|
||||||
@ -1416,6 +1533,8 @@ class Thread {
|
|||||||
unsigned heapOffset;
|
unsigned heapOffset;
|
||||||
Protector* protector;
|
Protector* protector;
|
||||||
ClassInitStack* classInitStack;
|
ClassInitStack* classInitStack;
|
||||||
|
Resource* resource;
|
||||||
|
Checkpoint* checkpoint;
|
||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
uintptr_t* defaultHeap;
|
uintptr_t* defaultHeap;
|
||||||
uintptr_t* heap;
|
uintptr_t* heap;
|
||||||
@ -1448,6 +1567,38 @@ class Classpath {
|
|||||||
dispose() = 0;
|
dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class RuntimeArray: public Thread::Resource {
|
||||||
|
public:
|
||||||
|
RuntimeArray(Thread* t, unsigned size):
|
||||||
|
Resource(t),
|
||||||
|
body(static_cast<T*>(t->m->heap->allocate(size * sizeof(T)))),
|
||||||
|
size(size)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~RuntimeArray() {
|
||||||
|
t->m->heap->free(body, size * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
RuntimeArray::~RuntimeArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* body;
|
||||||
|
unsigned size;
|
||||||
|
};
|
||||||
|
|
||||||
|
# define THREAD_RUNTIME_ARRAY(thread, type, name, size) \
|
||||||
|
RuntimeArray<type> name(thread, size);
|
||||||
|
|
||||||
|
#else // not _MSC_VER
|
||||||
|
|
||||||
|
# define THREAD_RUNTIME_ARRAY(thread, type, name, size) type name[size];
|
||||||
|
|
||||||
|
#endif // not _MSC_VER
|
||||||
|
|
||||||
Classpath*
|
Classpath*
|
||||||
makeClasspath(System* system, Allocator* allocator, const char* javaHome,
|
makeClasspath(System* system, Allocator* allocator, const char* javaHome,
|
||||||
const char* embedPrefix);
|
const char* embedPrefix);
|
||||||
@ -1469,16 +1620,21 @@ enterActiveState(Thread* t)
|
|||||||
enter(t, Thread::ActiveState);
|
enter(t, Thread::ActiveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
class StateResource {
|
class StateResource: public Thread::Resource {
|
||||||
public:
|
public:
|
||||||
StateResource(Thread* t, Thread::State state): t(t), oldState(t->state) {
|
StateResource(Thread* t, Thread::State state):
|
||||||
|
Resource(t), oldState(t->state)
|
||||||
|
{
|
||||||
enter(t, state);
|
enter(t, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
~StateResource() { enter(t, oldState); }
|
~StateResource() { enter(t, oldState); }
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
this->StateResource::~StateResource();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* t;
|
|
||||||
Thread::State oldState;
|
Thread::State oldState;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1553,33 +1709,43 @@ release(Thread* t, System::Monitor* m)
|
|||||||
m->release(t->systemThread);
|
m->release(t->systemThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MonitorResource {
|
class MonitorResource: public Thread::Resource {
|
||||||
public:
|
public:
|
||||||
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
MonitorResource(Thread* t, System::Monitor* m):
|
||||||
|
Resource(t), m(m)
|
||||||
|
{
|
||||||
acquire(t, m);
|
acquire(t, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
~MonitorResource() {
|
~MonitorResource() {
|
||||||
release(t, m);
|
vm::release(t, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
this->MonitorResource::~MonitorResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* t;
|
|
||||||
System::Monitor* m;
|
System::Monitor* m;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RawMonitorResource {
|
class RawMonitorResource: public Thread::Resource {
|
||||||
public:
|
public:
|
||||||
RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
RawMonitorResource(Thread* t, System::Monitor* m):
|
||||||
|
Resource(t), m(m)
|
||||||
|
{
|
||||||
m->acquire(t->systemThread);
|
m->acquire(t->systemThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RawMonitorResource() {
|
~RawMonitorResource() {
|
||||||
release(t, m);
|
vm::release(t, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
this->RawMonitorResource::~RawMonitorResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* t;
|
|
||||||
System::Monitor* m;
|
System::Monitor* m;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1622,9 +1788,13 @@ class FixedAllocator: public Allocator {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void*, unsigned) {
|
virtual void free(const void* p, unsigned size) {
|
||||||
|
if (p >= base and static_cast<const uint8_t*>(p) + size == base + offset) {
|
||||||
|
offset -= size;
|
||||||
|
} else {
|
||||||
abort(s);
|
abort(s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
uint8_t* base;
|
uint8_t* base;
|
||||||
@ -1667,7 +1837,6 @@ allocateSmall(Thread* t, unsigned sizeInBytes)
|
|||||||
|
|
||||||
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
|
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
|
||||||
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
|
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
|
||||||
cast<object>(o, 0) = 0;
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1745,12 +1914,39 @@ instanceOf(Thread* t, object class_, object o);
|
|||||||
|
|
||||||
#include "type-declarations.cpp"
|
#include "type-declarations.cpp"
|
||||||
|
|
||||||
|
inline uint64_t
|
||||||
|
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
Thread::RunCheckpoint checkpoint(t);
|
||||||
|
return vmRun(function, arguments, &checkpoint);
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
runJavaThread(Thread* t)
|
runJavaThread(Thread* t)
|
||||||
{
|
{
|
||||||
t->m->classpath->runThread(t);
|
t->m->classpath->runThread(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runFinalizeThread(Thread* t);
|
||||||
|
|
||||||
|
inline uint64_t
|
||||||
|
runThread(Thread* t, uintptr_t*)
|
||||||
|
{
|
||||||
|
t->m->localThread->set(t);
|
||||||
|
|
||||||
|
checkDaemon(t);
|
||||||
|
|
||||||
|
if (t == t->m->finalizeThread) {
|
||||||
|
runFinalizeThread(t);
|
||||||
|
} else if (t->javaThread) {
|
||||||
|
runJavaThread(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
startThread(Thread* t, Thread* p)
|
startThread(Thread* t, Thread* p)
|
||||||
{
|
{
|
||||||
@ -1820,17 +2016,12 @@ checkDaemon(Thread* t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Thread*
|
inline uint64_t
|
||||||
attachThread(Machine* m, bool daemon)
|
initAttachedThread(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
Thread* t = m->processor->makeThread(m, 0, m->rootThread);
|
bool daemon = arguments[0];
|
||||||
m->system->attach(&(t->runnable));
|
|
||||||
|
|
||||||
addThread(t, t);
|
t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread);
|
||||||
|
|
||||||
enter(t, Thread::ActiveState);
|
|
||||||
|
|
||||||
t->javaThread = m->classpath->makeThread(t, m->rootThread);
|
|
||||||
|
|
||||||
threadPeer(t, t->javaThread) = reinterpret_cast<jlong>(t);
|
threadPeer(t, t->javaThread) = reinterpret_cast<jlong>(t);
|
||||||
|
|
||||||
@ -1840,11 +2031,30 @@ attachThread(Machine* m, bool daemon)
|
|||||||
registerDaemon(t);
|
registerDaemon(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t->m->localThread->set(t);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Thread*
|
||||||
|
attachThread(Machine* m, bool daemon)
|
||||||
|
{
|
||||||
|
Thread* t = m->processor->makeThread(m, 0, m->rootThread);
|
||||||
|
m->system->attach(&(t->runnable));
|
||||||
|
|
||||||
|
addThread(t, t);
|
||||||
|
|
||||||
|
uintptr_t arguments[] = { daemon };
|
||||||
|
|
||||||
|
enter(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
if (run(t, initAttachedThread, arguments)) {
|
||||||
enter(t, Thread::IdleState);
|
enter(t, Thread::IdleState);
|
||||||
|
|
||||||
m->localThread->set(t);
|
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
|
} else {
|
||||||
|
t->exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object&
|
inline object&
|
||||||
@ -1939,6 +2149,9 @@ make(Thread* t, object class_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
makeByteArray(Thread* t, const char* format, va_list a);
|
||||||
|
|
||||||
object
|
object
|
||||||
makeByteArray(Thread* t, const char* format, ...);
|
makeByteArray(Thread* t, const char* format, ...);
|
||||||
|
|
||||||
@ -2248,12 +2461,8 @@ inline object
|
|||||||
resolveMethod(Thread* t, object loader, const char* className,
|
resolveMethod(Thread* t, object loader, const char* className,
|
||||||
const char* methodName, const char* methodSpec)
|
const char* methodName, const char* methodSpec)
|
||||||
{
|
{
|
||||||
object class_ = resolveClass(t, loader, className);
|
return resolveMethod
|
||||||
if (LIKELY(t->exception == 0)) {
|
(t, resolveClass(t, loader, className), methodName, methodSpec);
|
||||||
return resolveMethod(t, class_, methodName, methodSpec);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -2264,12 +2473,8 @@ inline object
|
|||||||
resolveField(Thread* t, object loader, const char* className,
|
resolveField(Thread* t, object loader, const char* className,
|
||||||
const char* fieldName, const char* fieldSpec)
|
const char* fieldName, const char* fieldSpec)
|
||||||
{
|
{
|
||||||
object class_ = resolveClass(t, loader, className);
|
return resolveField
|
||||||
if (LIKELY(t->exception == 0)) {
|
(t, resolveClass(t, loader, className), fieldName, fieldSpec);
|
||||||
return resolveField(t, class_, fieldName, fieldSpec);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -2347,6 +2552,48 @@ makeThrowable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline object
|
||||||
|
makeThrowable(Thread* t, Machine::Type type, const char* format, va_list a)
|
||||||
|
{
|
||||||
|
object s = makeByteArray(t, format, a);
|
||||||
|
|
||||||
|
object message = t->m->classpath->makeString
|
||||||
|
(t, s, 0, byteArrayLength(t, s) - 1);
|
||||||
|
|
||||||
|
return makeThrowable(t, type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object
|
||||||
|
makeThrowable(Thread* t, Machine::Type type, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list a;
|
||||||
|
va_start(a, format);
|
||||||
|
object r = makeThrowable(t, type, format, a);
|
||||||
|
va_end(a);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NO_RETURN
|
||||||
|
throw_(Thread* t, object e);
|
||||||
|
|
||||||
|
inline void NO_RETURN
|
||||||
|
throwNew(Thread* t, Machine::Type type)
|
||||||
|
{
|
||||||
|
throw_(t, makeThrowable(t, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void NO_RETURN
|
||||||
|
throwNew(Thread* t, Machine::Type type, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list a;
|
||||||
|
va_start(a, format);
|
||||||
|
object r = makeThrowable(t, type, format, a);
|
||||||
|
va_end(a);
|
||||||
|
|
||||||
|
throw_(t, r);
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
|
findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
|
||||||
object (*find)(Thread*, object, object, object));
|
object (*find)(Thread*, object, object, object));
|
||||||
@ -2359,12 +2606,10 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
|
|||||||
object o = findInHierarchyOrNull(t, class_, name, spec, find);
|
object o = findInHierarchyOrNull(t, class_, name, spec, find);
|
||||||
|
|
||||||
if (o == 0) {
|
if (o == 0) {
|
||||||
object message = makeString
|
throwNew(t, errorType, "%s %s not found in %s",
|
||||||
(t, "%s %s not found in %s",
|
|
||||||
&byteArrayBody(t, name, 0),
|
&byteArrayBody(t, name, 0),
|
||||||
&byteArrayBody(t, spec, 0),
|
&byteArrayBody(t, spec, 0),
|
||||||
&byteArrayBody(t, className(t, class_), 0));
|
&byteArrayBody(t, className(t, class_), 0));
|
||||||
t->exception = makeThrowable(t, errorType, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
@ -2390,8 +2635,7 @@ findMethodOrNull(Thread* t, object class_, const char* name, const char* spec)
|
|||||||
inline object
|
inline object
|
||||||
findVirtualMethod(Thread* t, object method, object class_)
|
findVirtualMethod(Thread* t, object method, object class_)
|
||||||
{
|
{
|
||||||
return arrayBody(t, classVirtualTable(t, class_),
|
return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method));
|
||||||
methodOffset(t, method));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
@ -2403,8 +2647,8 @@ findInterfaceMethod(Thread* t, object method, object class_)
|
|||||||
object itable = classInterfaceTable(t, class_);
|
object itable = classInterfaceTable(t, class_);
|
||||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||||
if (arrayBody(t, itable, i) == interface) {
|
if (arrayBody(t, itable, i) == interface) {
|
||||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
return arrayBody
|
||||||
methodOffset(t, method));
|
(t, arrayBody(t, itable, i + 1), methodOffset(t, method));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
abort(t);
|
abort(t);
|
||||||
@ -2849,10 +3093,10 @@ wait(Thread* t, object o, int64_t milliseconds)
|
|||||||
bool interrupted = monitorWait(t, m, milliseconds);
|
bool interrupted = monitorWait(t, m, milliseconds);
|
||||||
|
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
t->exception = makeThrowable(t, Machine::InterruptedExceptionType);
|
throwNew(t, Machine::InterruptedExceptionType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType);
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DebugMonitors) {
|
if (DebugMonitors) {
|
||||||
@ -2881,7 +3125,7 @@ notify(Thread* t, object o)
|
|||||||
if (m and monitorOwner(t, m) == t) {
|
if (m and monitorOwner(t, m) == t) {
|
||||||
monitorNotify(t, m);
|
monitorNotify(t, m);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType);
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2898,7 +3142,7 @@ notifyAll(Thread* t, object o)
|
|||||||
if (m and monitorOwner(t, m) == t) {
|
if (m and monitorOwner(t, m) == t) {
|
||||||
monitorNotifyAll(t, m);
|
monitorNotifyAll(t, m);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType);
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3057,7 +3301,6 @@ resolveClassInObject(Thread* t, object loader, object container,
|
|||||||
PROTECT(t, container);
|
PROTECT(t, container);
|
||||||
|
|
||||||
o = resolveClass(t, loader, o);
|
o = resolveClass(t, loader, o);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
set(t, container, classOffset, o);
|
set(t, container, classOffset, o);
|
||||||
}
|
}
|
||||||
@ -3072,7 +3315,6 @@ resolveClassInPool(Thread* t, object loader, object method, unsigned index)
|
|||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
|
||||||
o = resolveClass(t, loader, referenceName(t, o));
|
o = resolveClass(t, loader, referenceName(t, o));
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
set(t, codePool(t, methodCode(t, method)),
|
set(t, codePool(t, methodCode(t, method)),
|
||||||
SingletonBody + (index * BytesPerWord), o);
|
SingletonBody + (index * BytesPerWord), o);
|
||||||
@ -3101,12 +3343,10 @@ resolve(Thread* t, object loader, object method, unsigned index,
|
|||||||
PROTECT(t, reference);
|
PROTECT(t, reference);
|
||||||
|
|
||||||
object class_ = resolveClassInObject(t, loader, o, ReferenceClass);
|
object class_ = resolveClassInObject(t, loader, o, ReferenceClass);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
o = findInHierarchy
|
o = findInHierarchy
|
||||||
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
||||||
find, errorType);
|
find, errorType);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
|
||||||
|
|
||||||
set(t, codePool(t, methodCode(t, method)),
|
set(t, codePool(t, methodCode(t, method)),
|
||||||
SingletonBody + (index * BytesPerWord), o);
|
SingletonBody + (index * BytesPerWord), o);
|
||||||
@ -3236,9 +3476,7 @@ primitiveClass(Thread* t, char name)
|
|||||||
case 'S': return type(t, Machine::JshortType);
|
case 'S': return type(t, Machine::JshortType);
|
||||||
case 'V': return type(t, Machine::JvoidType);
|
case 'V': return type(t, Machine::JvoidType);
|
||||||
case 'Z': return type(t, Machine::JbooleanType);
|
case 'Z': return type(t, Machine::JbooleanType);
|
||||||
default:
|
default: throwNew(t, Machine::IllegalArgumentExceptionType);
|
||||||
t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,13 +153,13 @@ resolveNativeMethod(Thread* t, object method, const char* prefix,
|
|||||||
{
|
{
|
||||||
unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false);
|
unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false);
|
||||||
// extra 6 is for code below:
|
// extra 6 is for code below:
|
||||||
RUNTIME_ARRAY(char, undecorated, undecoratedSize + 1 + 6);
|
THREAD_RUNTIME_ARRAY(t, char, undecorated, undecoratedSize + 1 + 6);
|
||||||
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1,
|
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1,
|
||||||
method, false);
|
method, false);
|
||||||
|
|
||||||
unsigned decoratedSize = prefixLength + jniNameLength(t, method, true);
|
unsigned decoratedSize = prefixLength + jniNameLength(t, method, true);
|
||||||
// extra 6 is for code below:
|
// extra 6 is for code below:
|
||||||
RUNTIME_ARRAY(char, decorated, decoratedSize + 1 + 6);
|
THREAD_RUNTIME_ARRAY(t, char, decorated, decoratedSize + 1 + 6);
|
||||||
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1,
|
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1,
|
||||||
method, true);
|
method, true);
|
||||||
|
|
||||||
@ -232,20 +232,13 @@ resolveNative(Thread* t, object method)
|
|||||||
|
|
||||||
initClass(t, methodClass(t, method));
|
initClass(t, methodClass(t, method));
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)
|
if (methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) {
|
||||||
and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0)
|
|
||||||
{
|
|
||||||
object native = resolveNativeMethod(t, method);
|
object native = resolveNativeMethod(t, method);
|
||||||
if (UNLIKELY(native == 0)) {
|
if (UNLIKELY(native == 0)) {
|
||||||
object message = makeString
|
throwNew(t, Machine::UnsatisfiedLinkErrorType, "%s.%s%s",
|
||||||
(t, "%s.%s%s",
|
|
||||||
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||||
&byteArrayBody(t, methodName(t, method), 0),
|
&byteArrayBody(t, methodName(t, method), 0),
|
||||||
&byteArrayBody(t, methodSpec(t, method), 0));
|
&byteArrayBody(t, methodSpec(t, method), 0));
|
||||||
|
|
||||||
t->exception = makeThrowable
|
|
||||||
(t, Machine::UnsatisfiedLinkErrorType, message);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PROTECT(t, native);
|
PROTECT(t, native);
|
||||||
|
128
src/x86.S
128
src/x86.S
@ -23,6 +23,10 @@
|
|||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
#define CHECKPOINT_THREAD 8
|
||||||
|
#define CHECKPOINT_STACK 48
|
||||||
|
#define CHECKPOINT_BASE 56
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
.globl GLOBAL(detectFeature)
|
.globl GLOBAL(detectFeature)
|
||||||
GLOBAL(detectFeature):
|
GLOBAL(detectFeature):
|
||||||
@ -174,6 +178,48 @@ GLOBAL(vmJump):
|
|||||||
movq %r9,%rbx
|
movq %r9,%rbx
|
||||||
jmp *%rcx
|
jmp *%rcx
|
||||||
|
|
||||||
|
#define VMRUN_FRAME_SIZE 80
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun)
|
||||||
|
GLOBAL(vmRun):
|
||||||
|
// %rcx: function
|
||||||
|
// %rdx: arguments
|
||||||
|
// %r8 : checkpoint
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp,%rbp
|
||||||
|
subq $VMRUN_FRAME_SIZE,%rsp
|
||||||
|
|
||||||
|
movq %rbx,16(%rsp)
|
||||||
|
movq %r12,24(%rsp)
|
||||||
|
movq %r13,32(%rsp)
|
||||||
|
movq %r14,40(%rsp)
|
||||||
|
movq %r15,48(%rsp)
|
||||||
|
movq %rsi,56(%rsp)
|
||||||
|
movq %rdi,64(%rsp)
|
||||||
|
|
||||||
|
movq %rsp,CHECKPOINT_STACK(%rcx)
|
||||||
|
movq %rbp,CHECKPOINT_BASE(%rcx)
|
||||||
|
|
||||||
|
movq %rcx,%r11
|
||||||
|
movq CHECKPOINT_THREAD(%rdx),%rcx
|
||||||
|
|
||||||
|
call *%r11
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun_returnAddress)
|
||||||
|
GLOBAL(vmRun_returnAddress):
|
||||||
|
|
||||||
|
movq 16(%rsp),%rbx
|
||||||
|
movq 24(%rsp),%r12
|
||||||
|
movq 32(%rsp),%r13
|
||||||
|
movq 40(%rsp),%r14
|
||||||
|
movq 48(%rsp),%r15
|
||||||
|
movq 56(%rsp),%rsi
|
||||||
|
movq 64(%rsp),%rdi
|
||||||
|
|
||||||
|
addq $VMRUN_FRAME_SIZE,%rsp
|
||||||
|
popq %rbp
|
||||||
|
ret
|
||||||
|
|
||||||
#else // not __MINGW32__
|
#else // not __MINGW32__
|
||||||
.globl GLOBAL(detectFeature)
|
.globl GLOBAL(detectFeature)
|
||||||
GLOBAL(detectFeature):
|
GLOBAL(detectFeature):
|
||||||
@ -314,10 +360,52 @@ GLOBAL(vmJump):
|
|||||||
movq %r9,%rdx
|
movq %r9,%rdx
|
||||||
jmp *%rdi
|
jmp *%rdi
|
||||||
|
|
||||||
|
#define VMRUN_FRAME_SIZE 64
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun)
|
||||||
|
GLOBAL(vmRun):
|
||||||
|
// %rdi: function
|
||||||
|
// %rsi: arguments
|
||||||
|
// %rdx: checkpoint
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp,%rbp
|
||||||
|
subq $VMRUN_FRAME_SIZE,%rsp
|
||||||
|
|
||||||
|
movq %rbx,16(%rsp)
|
||||||
|
movq %r12,24(%rsp)
|
||||||
|
movq %r13,32(%rsp)
|
||||||
|
movq %r14,40(%rsp)
|
||||||
|
movq %r15,48(%rsp)
|
||||||
|
|
||||||
|
movq %rsp,CHECKPOINT_STACK(%rdx)
|
||||||
|
movq %rbp,CHECKPOINT_BASE(%rdx)
|
||||||
|
|
||||||
|
movq %rdi,%r11
|
||||||
|
movq CHECKPOINT_THREAD(%rdx),%rdi
|
||||||
|
|
||||||
|
call *%r11
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun_returnAddress)
|
||||||
|
GLOBAL(vmRun_returnAddress):
|
||||||
|
|
||||||
|
movq 16(%rsp),%rbx
|
||||||
|
movq 24(%rsp),%r12
|
||||||
|
movq 32(%rsp),%r13
|
||||||
|
movq 40(%rsp),%r14
|
||||||
|
movq 48(%rsp),%r15
|
||||||
|
|
||||||
|
addq $VMRUN_FRAME_SIZE,%rsp
|
||||||
|
popq %rbp
|
||||||
|
ret
|
||||||
|
|
||||||
#endif // not __MINGW32__
|
#endif // not __MINGW32__
|
||||||
|
|
||||||
#elif defined __i386__
|
#elif defined __i386__
|
||||||
|
|
||||||
|
#define CHECKPOINT_THREAD 4
|
||||||
|
#define CHECKPOINT_STACK 24
|
||||||
|
#define CHECKPOINT_BASE 28
|
||||||
|
|
||||||
.globl GLOBAL(detectFeature)
|
.globl GLOBAL(detectFeature)
|
||||||
GLOBAL(detectFeature):
|
GLOBAL(detectFeature):
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
@ -432,4 +520,42 @@ GLOBAL(vmJump):
|
|||||||
movl 12(%esp),%esp
|
movl 12(%esp),%esp
|
||||||
jmp *%esi
|
jmp *%esi
|
||||||
|
|
||||||
#endif //def __x86_64__
|
#define VMRUN_FRAME_SIZE 32
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun)
|
||||||
|
GLOBAL(vmRun):
|
||||||
|
// 8(%ebp): function
|
||||||
|
// 12(%ebp): arguments
|
||||||
|
// 16(%ebp): checkpoint
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp,%ebp
|
||||||
|
subl $VMRUN_FRAME_SIZE,%esp
|
||||||
|
|
||||||
|
movl %ebx,8(%esp)
|
||||||
|
movl %esi,12(%esp)
|
||||||
|
movl %edi,16(%esp)
|
||||||
|
|
||||||
|
movl 12(%ebp),%eax
|
||||||
|
movl %eax,4(%esp)
|
||||||
|
|
||||||
|
movl 16(%ebp),%ecx
|
||||||
|
movl CHECKPOINT_THREAD(%ecx),%eax
|
||||||
|
movl %eax,0(%esp)
|
||||||
|
|
||||||
|
movl %esp,CHECKPOINT_STACK(%ecx)
|
||||||
|
movl %ebp,CHECKPOINT_BASE(%ecx)
|
||||||
|
|
||||||
|
call *8(%ebp)
|
||||||
|
|
||||||
|
.globl GLOBAL(vmRun_returnAddress)
|
||||||
|
GLOBAL(vmRun_returnAddress):
|
||||||
|
|
||||||
|
movl 8(%esp),%ebx
|
||||||
|
movl 12(%esp),%esi
|
||||||
|
movl 16(%esp),%edi
|
||||||
|
|
||||||
|
addl $VMRUN_FRAME_SIZE,%esp
|
||||||
|
popl %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
#endif // __i386__
|
||||||
|
62
test/OutOfMemory.java
Normal file
62
test/OutOfMemory.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
public class OutOfMemory {
|
||||||
|
// assume a 128MB heap size:
|
||||||
|
private static final int Padding = 120 * 1024 * 1024;
|
||||||
|
|
||||||
|
private static class Node {
|
||||||
|
Object value;
|
||||||
|
Node next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void bigObjects() {
|
||||||
|
Object[] root = null;
|
||||||
|
while (true) {
|
||||||
|
Object[] x = new Object[1024 * 1024];
|
||||||
|
x[0] = root;
|
||||||
|
root = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void littleObjects() {
|
||||||
|
byte[] padding = new byte[Padding];
|
||||||
|
Node root = null;
|
||||||
|
while (true) {
|
||||||
|
Node x = new Node();
|
||||||
|
x.next = root;
|
||||||
|
root = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void bigAndLittleObjects() {
|
||||||
|
byte[] padding = new byte[Padding];
|
||||||
|
Node root = null;
|
||||||
|
while (true) {
|
||||||
|
Node x = new Node();
|
||||||
|
x.value = new Object[1024 * 1024];
|
||||||
|
x.next = root;
|
||||||
|
root = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
bigObjects();
|
||||||
|
throw new RuntimeException();
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
littleObjects();
|
||||||
|
throw new RuntimeException();
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
bigAndLittleObjects();
|
||||||
|
throw new RuntimeException();
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user