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:
Joel Dice
2010-12-27 15:55:23 -07:00
parent 5da8b96931
commit afabe8e07e
17 changed files with 2165 additions and 1305 deletions

View File

@ -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;
}
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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*) {

View File

@ -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);

View File

@ -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 {

View File

@ -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;
} }
} }

View File

@ -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
View File

@ -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
View 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();
}
}
}