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),
makeByteArray(t, "%.*s", nameSize - 6, name), true);
if (t->exception) return 0;
PROTECT(t, c);
if (classMethodTable(t, c)) {
@ -138,8 +136,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
o = resolveClass
(t, root(t, Machine::BootLoader), referenceName(t, o));
if (t->exception) return 0;
set(t, addendumPool(t, addendum),
SingletonBody + (index * BytesPerWord), o);
@ -360,9 +356,9 @@ offset(object a, uintptr_t* b)
}
void
writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
unsigned codeCapacity, const char* className,
const char* methodName, const char* methodSpec)
writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
unsigned codeCapacity, const char* className,
const char* methodName, const char* methodSpec)
{
Zone zone(t->m->system, t->m->heap, 64 * 1024);
@ -373,8 +369,6 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
object constants = makeCodeImage
(t, &zone, image, code, codeMap, className, methodName, methodSpec);
if (t->exception) return;
PROTECT(t, constants);
// 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
int
@ -540,15 +551,22 @@ main(int ac, const char** av)
return -1;
}
writeBootImage
(t, output, &image, code, CodeCapacity,
(ac > 3 ? av[3] : 0), (ac > 4 ? av[4] : 0), (ac > 5 ? av[5] : 0));
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(output),
reinterpret_cast<uintptr_t>(&image),
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);
if (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);
}
object r = op(t, loader, n);
if (t->exception) {
return 0;
}
return reinterpret_cast<int64_t>(r);
return reinterpret_cast<int64_t>(op(t, loader, n));
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
return 0;
throwNew(t, Machine::NullPointerExceptionType);
}
}
@ -81,7 +75,7 @@ Avian_avian_SystemClassLoader_resourceExists
object name = reinterpret_cast<object>(arguments[1]);
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));
unsigned length;
@ -92,8 +86,7 @@ Avian_avian_SystemClassLoader_resourceExists
return r;
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
return 0;
throwNew(t, Machine::NullPointerExceptionType);
}
}
@ -114,17 +107,16 @@ Avian_avian_Machine_dumpHeap
object outputFile = reinterpret_cast<object>(*arguments);
unsigned length = stringLength(t, outputFile);
char n[length + 1];
stringChars(t, outputFile, n);
FILE* out = vm::fopen(n, "wb");
THREAD_RUNTIME_ARRAY(t, char, n, length + 1);
stringChars(t, outputFile, RUNTIME_ARRAY_BODY(n));
FILE* out = vm::fopen(RUNTIME_ARRAY_BODY(n), "wb");
if (out) {
{ ENTER(t, Thread::ExclusiveState);
dumpHeap(t, out);
}
fclose(out);
} else {
object message = makeString(t, "file not found: %s", n);
t->exception = makeThrowable(t, Machine::RuntimeExceptionType, message);
throwNew(t, Machine::RuntimeExceptionType, "file not found: %s", n);
}
}
@ -146,7 +138,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
object path = reinterpret_cast<object>(*arguments);
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));
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);
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));
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);
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
return 0;
throwNew(t, Machine::NullPointerExceptionType);
}
}

View File

@ -60,9 +60,7 @@ class MyClasspath : public Classpath {
(t, root(t, Machine::BootLoader), "java/lang/Thread", "run",
"(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
@ -134,9 +132,8 @@ extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Object_getVMClass
(Thread* t, object, uintptr_t* arguments)
{
object o = reinterpret_cast<object>(arguments[0]);
return reinterpret_cast<int64_t>(objectClass(t, o));
return reinterpret_cast<int64_t>
(objectClass(t, reinterpret_cast<object>(arguments[0])));
}
extern "C" JNIEXPORT void JNICALL
@ -307,12 +304,16 @@ Avian_java_lang_reflect_Method_invoke
object instance = reinterpret_cast<object>(arguments[1]);
object args = reinterpret_cast<object>(arguments[2]);
object v = t->m->processor->invokeArray(t, method, instance, args);
if (t->exception) {
t->exception = makeThrowable
(t, Machine::InvocationTargetExceptionType, 0, 0, t->exception);
}
return reinterpret_cast<int64_t>(v);
THREAD_RESOURCE0(t, {
if (t->exception) {
object exception = t->exception;
t->exception = makeThrowable
(t, Machine::InvocationTargetExceptionType, 0, 0, exception);
}
});
return reinterpret_cast<int64_t>
(t->m->processor->invokeArray(t, method, instance, args));
}
extern "C" JNIEXPORT int64_t JNICALL
@ -327,12 +328,11 @@ Avian_java_lang_reflect_Array_getLength
if (LIKELY(elementSize)) {
return cast<uintptr_t>(array, BytesPerWord);
} else {
t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType);
throwNew(t, Machine::IllegalArgumentExceptionType);
}
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
throwNew(t, Machine::NullPointerExceptionType);
}
return 0;
}
extern "C" JNIEXPORT int64_t JNICALL
@ -394,7 +394,7 @@ Avian_java_lang_System_getVMProperty
PROTECT(t, found);
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));
int64_t r = 0;
@ -439,8 +439,7 @@ Avian_java_lang_System_identityHashCode
if (LIKELY(o)) {
return objectHash(t, o);
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
return 0;
throwNew(t, Machine::NullPointerExceptionType);
}
}
@ -452,7 +451,7 @@ Avian_java_lang_Runtime_load
bool mapName = arguments[1];
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));
loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true);
@ -622,11 +621,13 @@ Avian_avian_Classes_defineVMClass
uint8_t* buffer = static_cast<uint8_t*>
(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);
THREAD_RESOURCE2(t, uint8_t*, buffer, int, length,
t->m->heap->free(buffer, length));
return reinterpret_cast<int64_t>(c);
memcpy(buffer, &byteArrayBody(t, b, offset), length);
return reinterpret_cast<int64_t>(defineClass(t, loader, buffer, length));
}
extern "C" JNIEXPORT void JNICALL
@ -648,8 +649,7 @@ Avian_avian_Classes_isAssignableFrom
if (LIKELY(that)) {
return vm::isAssignableFrom(t, this_, that);
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
return 0;
throwNew(t, Machine::NullPointerExceptionType);
}
}

View File

@ -101,9 +101,7 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
return;
} else {
t->exception = makeThrowable
(t, Machine::IndexOutOfBoundsExceptionType);
return;
throwNew(t, Machine::IndexOutOfBoundsExceptionType);
}
} else {
return;
@ -111,11 +109,11 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
}
}
} else {
t->exception = makeThrowable(t, Machine::NullPointerExceptionType);
throwNew(t, Machine::NullPointerExceptionType);
return;
}
t->exception = makeThrowable(t, Machine::ArrayStoreExceptionType);
throwNew(t, Machine::ArrayStoreExceptionType);
}
void
@ -158,6 +156,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
{
ACQUIRE(t, t->m->classLock);
char* mappedName;
unsigned nameLength = strlen(name);
if (mapName) {
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();
unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix);
char* mappedName = static_cast<char*>
mappedName = static_cast<char*>
(t->m->heap->allocate(mappedNameLength + 1));
snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix);
name = mappedName;
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;
for (Tokenizer tokenizer(path, t->m->system->pathSeparator());
tokenizer.hasMore();)
@ -202,7 +208,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName,
Tokenizer::Token token(tokenizer.next());
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,
"%*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);
}
} else {
object message = makeString(t, "library not found: %s", name);
t->exception = makeThrowable
(t, Machine::UnsatisfiedLinkErrorType, message);
}
if (mapName) {
t->m->heap->free(name, nameLength + 1);
throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s",
name);
}
return lib;
@ -264,7 +265,7 @@ makeStackTraceElement(Thread* t, object e)
object class_ = className(t, methodClass(t, traceElementMethod(t, e)));
PROTECT(t, class_);
RUNTIME_ARRAY(char, s, byteArrayLength(t, class_));
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_));
replace('/', '.', RUNTIME_ARRAY_BODY(s),
reinterpret_cast<char*>(&byteArrayBody(t, class_, 0)));
class_ = makeString(t, "%s", s);

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@
#ifdef __x86_64__
#define THREAD_STACK 2216
#define THREAD_STACK 2232
#if defined __MINGW32__ || defined __CYGWIN32__
@ -306,7 +306,7 @@ LOCAL(vmJumpAndInvoke_argumentTest):
#elif defined __i386__
#define THREAD_STACK 2144
#define THREAD_STACK 2152
#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__
#define THREAD_CONTINUATION 2224
#define THREAD_CONTINUATION 2240
#define THREAD_EXCEPTION 80
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232
#define THREAD_EXCEPTION_OFFSET 2240
#define THREAD_EXCEPTION_HANDLER 2248
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2248
#define THREAD_EXCEPTION_OFFSET 2256
#define THREAD_EXCEPTION_HANDLER 2264
#define CONTINUATION_NEXT 8
#define CONTINUATION_ADDRESS 32
@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit):
#elif defined __i386__
#define THREAD_CONTINUATION 2148
#define THREAD_CONTINUATION 2156
#define THREAD_EXCEPTION 44
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152
#define THREAD_EXCEPTION_OFFSET 2156
#define THREAD_EXCEPTION_HANDLER 2160
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160
#define THREAD_EXCEPTION_OFFSET 2164
#define THREAD_EXCEPTION_HANDLER 2168
#define CONTINUATION_NEXT 4
#define CONTINUATION_ADDRESS 16

View File

@ -68,6 +68,7 @@ void assert(Context*, bool);
System* system(Context*);
void* tryAllocate(Context* c, unsigned size);
void* allocate(Context* c, unsigned size);
void free(Context* c, const void* p, unsigned size);
void outOfMemory(Context*);
@ -360,7 +361,9 @@ class Segment {
break;
}
} else {
outOfMemory(context);
data = static_cast<uintptr_t*>
(local::allocate
(context, (footprint(capacity_)) * BytesPerWord));
}
}
}
@ -1710,7 +1713,7 @@ collect(Context* c)
}
void*
tryAllocate(Context* c, unsigned size)
allocate(Context* c, unsigned size, bool limit)
{
ACQUIRE(c->lock);
@ -1718,7 +1721,7 @@ tryAllocate(Context* c, unsigned size)
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);
if (p) {
c->count += size;
@ -1735,6 +1738,18 @@ tryAllocate(Context* c, unsigned size)
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
free(Context* c, const void* p, unsigned size)
{
@ -1787,16 +1802,16 @@ class MyHeap: public Heap {
c.immortalHeapEnd = start + sizeInWords;
}
virtual bool limitExceeded() {
return c.count > c.limit;
}
virtual void* tryAllocate(unsigned size) {
return local::tryAllocate(&c, size);
}
virtual void* allocate(unsigned size) {
void* p = local::tryAllocate(&c, size);
if (p == 0) {
c.client->outOfMemory();
}
return p;
return local::allocate(&c, 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 setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
virtual bool limitExceeded() = 0;
virtual void collect(CollectionType type, unsigned footprint) = 0;
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes) = 0;

View File

@ -375,7 +375,7 @@ popFrame(Thread* t)
if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)
and t->classInitList
and t->classInitList->class_ == methodClass(t, method))
{
{
t->classInitList->pop();
postInitClass(t, methodClass(t, method));
@ -435,7 +435,7 @@ checkStack(Thread* t, object method)
+ codeMaxStack(t, methodCode(t, method))
> 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;
RUNTIME_ARRAY(uintptr_t, args, footprint);
THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint);
unsigned argOffset = 0;
RUNTIME_ARRAY(uint8_t, types, count);
THREAD_RUNTIME_ARRAY(t, uint8_t, types, count);
unsigned typeOffset = 0;
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);
bool noThrow = t->checkpoint->noThrow;
t->checkpoint->noThrow = true;
THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow);
result = t->m->system->call
(function,
RUNTIME_ARRAY_BODY(args),
@ -633,7 +637,9 @@ invokeNativeSlow(Thread* t, object method, void* function)
popFrame(t);
if (UNLIKELY(t->exception)) {
return VoidField;
object exception = t->exception;
t->exception = 0;
throw_(t, exception);
}
pushResult(t, returnCode, result, true);
@ -648,10 +654,6 @@ invokeNative(Thread* t, object method)
resolveNative(t, method);
if (UNLIKELY(t->exception)) {
return VoidField;
}
object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method));
if (nativeFast(t, native)) {
pushFrame(t, method);
@ -673,10 +675,6 @@ invokeNative(Thread* t, object method)
popFrame(t);
if (UNLIKELY(t->exception)) {
return VoidField;
}
pushResult(t, methodReturnCode(t, method), result, false);
return methodReturnCode(t, method);
@ -802,10 +800,8 @@ pushField(Thread* t, object target, object field)
}
object
interpret(Thread* t)
interpret3(Thread* t, const int base)
{
const int base = t->frame;
unsigned instruction = nop;
unsigned& ip = t->ip;
unsigned& sp = t->sp;
@ -858,10 +854,9 @@ interpret(Thread* t)
{
pushObject(t, objectArrayBody(t, array, index));
} else {
object message = makeString
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, objectArrayLength(t, array));
goto throw_;
}
} else {
@ -881,10 +876,9 @@ interpret(Thread* t)
{
set(t, array, ArrayBody + (index * BytesPerWord), value);
} else {
object message = makeString
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, objectArrayLength(t, array));
goto throw_;
}
} else {
@ -924,13 +918,11 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
pushObject(t, makeObjectArray(t, class_, count));
} else {
object message = makeString(t, "%d", count);
exception = makeThrowable
(t, Machine::NegativeArraySizeExceptionType, message);
(t, Machine::NegativeArraySizeExceptionType, "%d", count);
goto throw_;
}
} goto loop;
@ -995,10 +987,9 @@ interpret(Thread* t)
{
pushInt(t, booleanArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
booleanArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
"%d not in [0,%d)", index, booleanArrayLength(t, array));
goto throw_;
}
} else {
@ -1008,11 +999,9 @@ interpret(Thread* t)
{
pushInt(t, byteArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
byteArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
"%d not in [0,%d)", index, byteArrayLength(t, array));
goto throw_;
}
}
@ -1035,10 +1024,9 @@ interpret(Thread* t)
{
booleanArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
booleanArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
"%d not in [0,%d)", index, booleanArrayLength(t, array));
goto throw_;
}
} else {
@ -1047,10 +1035,9 @@ interpret(Thread* t)
{
byteArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
byteArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType,
"%d not in [0,%d)", index, byteArrayLength(t, array));
goto throw_;
}
}
@ -1074,10 +1061,9 @@ interpret(Thread* t)
{
pushInt(t, charArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
charArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, charArrayLength(t, array));
goto throw_;
}
} else {
@ -1097,10 +1083,9 @@ interpret(Thread* t)
{
charArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
charArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, charArrayLength(t, array));
goto throw_;
}
} else {
@ -1117,13 +1102,11 @@ interpret(Thread* t)
if (UNLIKELY(exception)) goto throw_;
if (not instanceOf(t, class_, peekObject(t, sp - 1))) {
object message = makeString
(t, "%s as %s",
exception = makeThrowable
(t, Machine::ClassCastExceptionType, "%s as %s",
&byteArrayBody
(t, className(t, objectClass(t, peekObject(t, sp - 1))), 0),
&byteArrayBody(t, className(t, class_), 0));
exception = makeThrowable
(t, Machine::ClassCastExceptionType, message);
goto throw_;
}
}
@ -1158,10 +1141,9 @@ interpret(Thread* t)
{
pushLong(t, doubleArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
doubleArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, doubleArrayLength(t, array));
goto throw_;
}
} else {
@ -1181,10 +1163,9 @@ interpret(Thread* t)
{
memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
doubleArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, doubleArrayLength(t, array));
goto throw_;
}
} else {
@ -1360,10 +1341,9 @@ interpret(Thread* t)
{
pushInt(t, floatArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
floatArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, floatArrayLength(t, array));
goto throw_;
}
} else {
@ -1383,10 +1363,9 @@ interpret(Thread* t)
{
memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
floatArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, floatArrayLength(t, array));
goto throw_;
}
} else {
@ -1476,7 +1455,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
@ -1511,7 +1489,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
assert(t, fieldFlags(t, field) & ACC_STATIC);
@ -1592,10 +1569,9 @@ interpret(Thread* t)
{
pushInt(t, intArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
intArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, intArrayLength(t, array));
goto throw_;
}
} else {
@ -1622,10 +1598,9 @@ interpret(Thread* t)
{
intArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
intArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, intArrayLength(t, array));
goto throw_;
}
} else {
@ -1874,7 +1849,6 @@ interpret(Thread* t)
if (peekObject(t, sp - 1)) {
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
if (instanceOf(t, class_, popObject(t))) {
pushInt(t, 1);
@ -1893,7 +1867,6 @@ interpret(Thread* t)
ip += 2;
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
unsigned parameterFootprint = methodParameterFootprint(t, method);
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
@ -1910,7 +1883,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
unsigned parameterFootprint = methodParameterFootprint(t, method);
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
@ -1935,7 +1907,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
PROTECT(t, method);
if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke;
@ -1947,7 +1918,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
unsigned parameterFootprint = methodParameterFootprint(t, method);
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
@ -2096,10 +2066,9 @@ interpret(Thread* t)
{
pushLong(t, longArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
longArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, longArrayLength(t, array));
goto throw_;
}
} else {
@ -2126,10 +2095,9 @@ interpret(Thread* t)
{
longArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
longArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, longArrayLength(t, array));
goto throw_;
}
} else {
@ -2170,7 +2138,6 @@ interpret(Thread* t)
if (objectClass(t, v) == type(t, Machine::ReferenceType)) {
object class_ = resolveClassInPool
(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
pushObject(t, getJClass(t, class_));
} else if (objectClass(t, v) == type(t, Machine::ClassType)) {
@ -2389,16 +2356,14 @@ interpret(Thread* t)
uint8_t dimensions = codeBody(t, code, ip++);
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
PROTECT(t, class_);
int32_t counts[dimensions];
for (int i = dimensions - 1; i >= 0; --i) {
counts[i] = popInt(t);
if (UNLIKELY(counts[i] < 0)) {
object message = makeString(t, "%d", counts[i]);
exception = makeThrowable
(t, Machine::NegativeArraySizeExceptionType, message);
(t, Machine::NegativeArraySizeExceptionType, "%d", counts[i]);
goto throw_;
}
}
@ -2416,7 +2381,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
PROTECT(t, class_);
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
@ -2470,9 +2434,8 @@ interpret(Thread* t)
pushObject(t, array);
} else {
object message = makeString(t, "%d", count);
exception = makeThrowable
(t, Machine::NegativeArraySizeExceptionType, message);
(t, Machine::NegativeArraySizeExceptionType, "%d", count);
goto throw_;
}
} goto loop;
@ -2491,7 +2454,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
PROTECT(t, field);
@ -2582,7 +2544,6 @@ interpret(Thread* t)
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, frameMethod(t, frame), index - 1);
if (UNLIKELY(exception)) goto throw_;
assert(t, fieldFlags(t, field) & ACC_STATIC);
@ -2683,10 +2644,9 @@ interpret(Thread* t)
{
pushInt(t, shortArrayBody(t, array, index));
} else {
object message = makeString(t, "%d not in [0,%d)", index,
shortArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, shortArrayLength(t, array));
goto throw_;
}
} else {
@ -2706,10 +2666,9 @@ interpret(Thread* t)
{
shortArrayBody(t, array, index) = value;
} else {
object message = makeString(t, "%d not in [0,%d)", index,
shortArrayLength(t, array));
exception = makeThrowable
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
(t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)",
index, shortArrayLength(t, array));
goto throw_;
}
} else {
@ -2771,7 +2730,6 @@ interpret(Thread* t)
resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))),
className(t, class_));
if (UNLIKELY(exception)) goto throw_;
ip -= 3;
} goto loop;
@ -2822,11 +2780,8 @@ interpret(Thread* t)
invoke: {
if (methodFlags(t, code) & ACC_NATIVE) {
invokeNative(t, code);
if (UNLIKELY(exception)) goto throw_;
} else {
checkStack(t, code);
if (UNLIKELY(exception)) goto throw_;
pushFrame(t, code);
}
} goto loop;
@ -2851,6 +2806,39 @@ interpret(Thread* t)
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
pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects,
va_list a)
@ -2957,47 +2945,45 @@ invoke(Thread* t, object method)
if (methodFlags(t, method) & ACC_NATIVE) {
unsigned returnCode = invokeNative(t, method);
if (LIKELY(t->exception == 0)) {
switch (returnCode) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
result = makeInt(t, popInt(t));
break;
switch (returnCode) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
result = makeInt(t, popInt(t));
break;
case LongField:
case DoubleField:
result = makeLong(t, popLong(t));
break;
case LongField:
case DoubleField:
result = makeLong(t, popLong(t));
break;
case ObjectField:
result = popObject(t);
break;
case ObjectField:
result = popObject(t);
break;
case VoidField:
result = 0;
break;
case VoidField:
result = 0;
break;
default:
abort(t);
};
}
default:
abort(t);
};
} else {
checkStack(t, method);
if (LIKELY(t->exception == 0)) {
pushFrame(t, method);
result = interpret(t);
if (LIKELY(t->exception == 0)) {
popFrame(t);
}
}
}
pushFrame(t, method);
if (UNLIKELY(t->exception)) {
return 0;
result = interpret(t);
if (LIKELY(t->exception == 0)) {
popFrame(t);
} else {
object exception = t->exception;
t->exception = 0;
throw_(t, exception);
}
}
return result;
@ -3155,8 +3141,7 @@ class MyProcessor: public Processor {
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
> StackSizeInWords / 2))
{
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
return 0;
throwNew(t, Machine::StackOverflowErrorType);
}
const char* spec = reinterpret_cast<char*>
@ -3180,8 +3165,7 @@ class MyProcessor: public Processor {
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
> StackSizeInWords / 2))
{
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
return 0;
throwNew(t, Machine::StackOverflowErrorType);
}
const char* spec = reinterpret_cast<char*>
@ -3204,8 +3188,7 @@ class MyProcessor: public Processor {
if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false)
> StackSizeInWords / 2))
{
t->exception = makeThrowable(t, Machine::StackOverflowErrorType);
return 0;
throwNew(t, Machine::StackOverflowErrorType);
}
pushArguments(t, this_, methodSpec, false, arguments);
@ -3213,13 +3196,9 @@ class MyProcessor: public Processor {
object method = resolveMethod
(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);
} else {
return 0;
}
return ::invoke(t, method);
}
virtual object getStackTrace(vm::Thread*, vm::Thread*) {

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,7 @@ dispose(Thread* t, Thread* o, bool remove)
expect(t, find(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));
#endif
@ -578,7 +578,14 @@ postCollect(Thread* t)
}
t->heapOffset = 0;
t->heapIndex = 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;
}
if (t->flags & Thread::UseBackupHeapFlag) {
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
finalizeObject(Thread* t, object o)
{
@ -604,7 +622,11 @@ finalizeObject(Thread* t, object o)
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
&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;
return;
}
@ -613,21 +635,6 @@ finalizeObject(Thread* t, object o)
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
readByte(Stream& s, unsigned* value)
{
@ -858,6 +865,9 @@ parsePool(Thread* t, Stream& s)
if (count) {
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) {
index[i] = s.position();
@ -889,6 +899,7 @@ parsePool(Thread* t, Stream& s)
s.skip(8);
++ i;
break;
case CONSTANT_Double:
singletonSetBit(t, pool, count, i);
singletonSetBit(t, pool, count, i + 1);
@ -911,8 +922,6 @@ parsePool(Thread* t, Stream& s)
i += parsePoolEntry(t, s, index, pool, i);
}
t->m->heap->free(index, count * 4);
s.setPosition(end);
}
@ -960,7 +969,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
PROTECT(t, name);
object interface = resolveClass(t, classLoader(t, class_), name);
if (UNLIKELY(t->exception)) return;
PROTECT(t, interface);
@ -981,7 +989,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
unsigned i = 0;
for (HashMapIterator it(t, map); it.hasMore();) {
object interface = tripleSecond(t, it.next());
if (UNLIKELY(t->exception)) return;
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
++ i;
@ -1028,7 +1035,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
object addendum = 0;
PROTECT(t, addendum);
RUNTIME_ARRAY(uint8_t, staticTypes, count);
THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count);
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
@ -2046,6 +2053,7 @@ boot(Thread* t)
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0));
m->processor->boot(t, 0);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1);
@ -2162,6 +2170,67 @@ class HeapClient: public Heap::Client {
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 vm {
@ -2663,7 +2732,9 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
> ThreadHeapSizeInWords)
{
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->m->heap->tryAllocate(ThreadHeapSizeInBytes));
@ -2694,6 +2765,10 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
// vmPrintTrace(t);
collect(t, Heap::MinorCollection);
}
if (t->m->heap->limitExceeded()) {
throw_(t, root(t, Machine::OutOfMemoryError));
}
} while (type == Machine::MovableAllocation
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords);
@ -2759,12 +2834,51 @@ makeNewGeneral(Thread* t, object class_)
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
makeByteArray(Thread* t, const char* format, ...)
{
va_list a;
va_start(a, format);
object s = ::makeByteArray(t, format, a);
object s = makeByteArray(t, format, a);
va_end(a);
return s;
@ -2775,7 +2889,7 @@ makeString(Thread* t, const char* format, ...)
{
va_list a;
va_start(a, format);
object s = ::makeByteArray(t, format, a);
object s = makeByteArray(t, format, a);
va_end(a);
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
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 (classVmFlags(t, b) & BootstrapFlag) {
resolveSystemClass(t, root(t, Machine::BootLoader), className(t, b));
if (UNLIKELY(t->exception)) {
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(className(t, b)) };
if (run(t, resolveBootstrap, arguments) == 0) {
t->exception = 0;
return false;
}
@ -3084,7 +3209,6 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
if (super) {
object sc = resolveClass
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)));
if (UNLIKELY(t->exception)) return 0;
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);
if (UNLIKELY(t->exception)) return 0;
parseFieldTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
parseMethodTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
parseAttributeTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
object vtable = classVirtualTable(t, class_);
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) == '[') {
class_ = resolveArrayClass(t, loader, spec, throw_);
} else {
RUNTIME_ARRAY(char, file, byteArrayLength(t, spec) + 6);
THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6);
memcpy(RUNTIME_ARRAY_BODY(file),
&byteArrayBody(t, spec, 0),
byteArrayLength(t, spec) - 1);
@ -3177,27 +3297,27 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
}
// parse class file
class_ = parseClass(t, loader, region->start(), region->length());
region->dispose();
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
if (LIKELY(t->exception == 0)) {
if (Verbose) {
fprintf(stderr, "done parsing %s: %p\n",
&byteArrayBody(t, spec, 0),
class_);
}
// parse class file
class_ = parseClass(t, loader, region->start(), region->length());
}
object bootstrapClass = hashMapFind
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
byteArrayEqual);
if (Verbose) {
fprintf(stderr, "done parsing %s: %p\n",
&byteArrayBody(t, spec, 0),
class_);
}
if (bootstrapClass) {
PROTECT(t, bootstrapClass);
updateBootstrapClass(t, bootstrapClass, class_);
class_ = bootstrapClass;
}
object bootstrapClass = hashMapFind
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
byteArrayEqual);
if (bootstrapClass) {
PROTECT(t, bootstrapClass);
updateBootstrapClass(t, bootstrapClass, class_);
class_ = bootstrapClass;
}
}
}
@ -3206,10 +3326,9 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
PROTECT(t, class_);
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
} else if (throw_ and t->exception == 0) {
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
t->exception = makeThrowable
(t, Machine::ClassNotFoundExceptionType, message);
} else if (throw_) {
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
}
}
@ -3265,28 +3384,24 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
}
}
if (LIKELY(t->exception == 0)) {
object method = findVirtualMethod
(t, root(t, Machine::LoadClassMethod), objectClass(t, loader));
object method = findVirtualMethod
(t, root(t, Machine::LoadClassMethod), objectClass(t, loader));
if (LIKELY(t->exception == 0)) {
PROTECT(t, method);
PROTECT(t, method);
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec));
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
(&byteArrayBody(t, spec, 0)));
RUNTIME_ARRAY(char, s, byteArrayLength(t, spec));
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
(&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);
if (LIKELY(jc and t->exception == 0)) {
c = jclassVmClass(t, jc);
}
}
object jc = t->m->processor->invoke(t, method, loader, specString);
if (LIKELY(jc)) {
c = jclassVmClass(t, jc);
}
}
if (LIKELY(c and t->exception == 0)) {
if (LIKELY(c)) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
@ -3301,13 +3416,8 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
return c;
} else {
if (t->exception == 0) {
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
t->exception = makeThrowable
(t, Machine::ClassNotFoundExceptionType, message);
}
return 0;
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
}
}
}
@ -3325,13 +3435,10 @@ resolveMethod(Thread* t, object class_, const char* methodName,
object method = findMethodInClass(t, class_, name, spec);
if (t->exception == 0 and method == 0) {
object message = makeString
(t, "%s %s not found in %s", methodName, methodSpec,
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeThrowable(t, Machine::NoSuchMethodErrorType, message);
return 0;
if (method == 0) {
throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s",
methodName, methodSpec, &byteArrayBody
(t, className(t, class_), 0));
} else {
return method;
}
@ -3358,13 +3465,9 @@ resolveField(Thread* t, object class_, const char* fieldName,
field = findFieldInClass(t, c, name, spec);
}
if (t->exception == 0 and field == 0) {
object message = makeString
(t, "%s %s not found in %s", fieldName, fieldSpec,
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeThrowable(t, Machine::NoSuchFieldErrorType, message);
return 0;
if (field == 0) {
throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s",
fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0));
} else {
return field;
}
@ -3413,11 +3516,8 @@ preInitClass(Thread* t, object c)
t->m->classLock->wait(t->systemThread, 0);
}
} else if (classVmFlags(t, c) & InitErrorFlag) {
object message = makeString
(t, "%s", &byteArrayBody(t, className(t, c), 0));
t->exception = makeThrowable
(t, Machine::NoClassDefFoundErrorType, message);
throwNew(t, Machine::NoClassDefFoundErrorType, "%s",
&byteArrayBody(t, className(t, c), 0));
} else {
classVmFlags(t, c) |= InitFlag;
return true;
@ -3434,13 +3534,13 @@ postInitClass(Thread* t, object c)
ACQUIRE(t, t->m->classLock);
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) &= ~InitFlag;
object exception = t->exception;
t->exception = 0;
throwNew(t, Machine::ExceptionInInitializerErrorType, 0, 0, exception);
} else {
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
}
@ -3453,11 +3553,11 @@ initClass(Thread* t, object c)
PROTECT(t, c);
if (preInitClass(t, c)) {
OBJECT_RESOURCE(t, c, postInitClass(t, c));
Thread::ClassInitStack stack(t, c);
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);
if (UNLIKELY(t->exception)) return 0;
set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass,
arrayClass);
@ -3509,7 +3608,6 @@ makeObjectArray(Thread* t, object elementClass, unsigned count)
{
object arrayClass = resolveObjectArrayClass
(t, classLoader(t, elementClass), elementClass);
if (UNLIKELY(t->exception)) return 0;
PROTECT(t, arrayClass);
@ -3692,57 +3790,16 @@ collect(Thread* t, Heap::CollectionType type)
{
ENTER(t, Thread::ExclusiveState);
#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;
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 (t->m->heap->limitExceeded()) {
type = Heap::MajorCollection;
}
if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) {
object javaThread = t->m->classpath->makeThread(t, m->rootThread);
threadDaemon(t, javaThread) = true;
doCollect(t, type);
m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread);
addThread(t, m->finalizeThread);
if (not startThread(t, m->finalizeThread)) {
removeThread(t, m->finalizeThread);
m->finalizeThread = 0;
}
if (t->m->heap->limitExceeded()) {
// try once more, giving the heap a chance to squeeze everything
// into the smallest possible space:
doCollect(t, Heap::MajorCollection);
}
}
@ -3762,7 +3819,7 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start)
= (arrayElementSize ?
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),
intArrayLength(t, objectMask) * 4);
@ -3836,7 +3893,7 @@ printTrace(Thread* t, object exception)
if (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));
fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message));
} else {

View File

@ -37,6 +37,56 @@
#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 {
const bool Verbose = false;
@ -1201,10 +1251,12 @@ class Machine {
MethodRuntimeDataTable,
JNIMethodTable,
ShutdownHooks,
FinalizerThread,
ObjectsToFinalize,
NullPointerException,
ArithmeticException,
ArrayIndexOutOfBoundsException,
OutOfMemoryError,
VirtualFileFinders,
VirtualFiles
};
@ -1280,15 +1332,23 @@ inline void stress(Thread* t);
#endif // not VM_STRESS
void
runJavaThread(Thread* t);
uint64_t
runThread(Thread*, uintptr_t*);
void
runFinalizeThread(Thread* t);
uint64_t
run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
uintptr_t* arguments);
void
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 {
public:
enum State {
@ -1336,9 +1396,26 @@ class Thread {
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:
ClassInitStack(Thread* t, object class_):
Resource(t),
next(t->classInitStack),
class_(class_),
protector(t, &(this->class_))
@ -1347,7 +1424,11 @@ class Thread {
}
~ClassInitStack() {
protector.t->classInitStack = next;
t->classInitStack = next;
}
virtual void release() {
this->ClassInitStack::~ClassInitStack();
}
ClassInitStack* next;
@ -1355,6 +1436,50 @@ class Thread {
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 {
public:
Runnable(Thread* t): t(t) { }
@ -1366,18 +1491,10 @@ class Thread {
virtual void run() {
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) {
printTrace(t, t->exception);
}
if (t->exception) {
printTrace(t, t->exception);
}
t->exit();
@ -1416,6 +1533,8 @@ class Thread {
unsigned heapOffset;
Protector* protector;
ClassInitStack* classInitStack;
Resource* resource;
Checkpoint* checkpoint;
Runnable runnable;
uintptr_t* defaultHeap;
uintptr_t* heap;
@ -1448,6 +1567,38 @@ class Classpath {
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*
makeClasspath(System* system, Allocator* allocator, const char* javaHome,
const char* embedPrefix);
@ -1469,16 +1620,21 @@ enterActiveState(Thread* t)
enter(t, Thread::ActiveState);
}
class StateResource {
class StateResource: public Thread::Resource {
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);
}
~StateResource() { enter(t, oldState); }
virtual void release() {
this->StateResource::~StateResource();
}
private:
Thread* t;
Thread::State oldState;
};
@ -1553,33 +1709,43 @@ release(Thread* t, System::Monitor* m)
m->release(t->systemThread);
}
class MonitorResource {
class MonitorResource: public Thread::Resource {
public:
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
MonitorResource(Thread* t, System::Monitor* m):
Resource(t), m(m)
{
acquire(t, m);
}
~MonitorResource() {
release(t, m);
vm::release(t, m);
}
virtual void release() {
this->MonitorResource::~MonitorResource();
}
private:
Thread* t;
System::Monitor* m;
};
class RawMonitorResource {
class RawMonitorResource: public Thread::Resource {
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);
}
~RawMonitorResource() {
release(t, m);
vm::release(t, m);
}
virtual void release() {
this->RawMonitorResource::~RawMonitorResource();
}
private:
Thread* t;
System::Monitor* m;
};
@ -1622,8 +1788,12 @@ class FixedAllocator: public Allocator {
return p;
}
virtual void free(const void*, unsigned) {
abort(s);
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);
}
}
System* s;
@ -1667,7 +1837,6 @@ allocateSmall(Thread* t, unsigned sizeInBytes)
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
cast<object>(o, 0) = 0;
return o;
}
@ -1745,12 +1914,39 @@ instanceOf(Thread* t, object class_, object o);
#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
runJavaThread(Thread* 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
startThread(Thread* t, Thread* p)
{
@ -1820,17 +2016,12 @@ checkDaemon(Thread* t)
}
}
inline Thread*
attachThread(Machine* m, bool daemon)
inline uint64_t
initAttachedThread(Thread* t, uintptr_t* arguments)
{
Thread* t = m->processor->makeThread(m, 0, m->rootThread);
m->system->attach(&(t->runnable));
bool daemon = arguments[0];
addThread(t, t);
enter(t, Thread::ActiveState);
t->javaThread = m->classpath->makeThread(t, m->rootThread);
t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread);
threadPeer(t, t->javaThread) = reinterpret_cast<jlong>(t);
@ -1840,11 +2031,30 @@ attachThread(Machine* m, bool daemon)
registerDaemon(t);
}
enter(t, Thread::IdleState);
t->m->localThread->set(t);
m->localThread->set(t);
return 1;
}
return t;
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);
return t;
} else {
t->exit();
return 0;
}
}
inline object&
@ -1939,6 +2149,9 @@ make(Thread* t, object class_)
}
}
object
makeByteArray(Thread* t, const char* format, va_list a);
object
makeByteArray(Thread* t, const char* format, ...);
@ -2248,12 +2461,8 @@ inline object
resolveMethod(Thread* t, object loader, const char* className,
const char* methodName, const char* methodSpec)
{
object class_ = resolveClass(t, loader, className);
if (LIKELY(t->exception == 0)) {
return resolveMethod(t, class_, methodName, methodSpec);
} else {
return 0;
}
return resolveMethod
(t, resolveClass(t, loader, className), methodName, methodSpec);
}
object
@ -2264,12 +2473,8 @@ inline object
resolveField(Thread* t, object loader, const char* className,
const char* fieldName, const char* fieldSpec)
{
object class_ = resolveClass(t, loader, className);
if (LIKELY(t->exception == 0)) {
return resolveField(t, class_, fieldName, fieldSpec);
} else {
return 0;
}
return resolveField
(t, resolveClass(t, loader, className), fieldName, fieldSpec);
}
bool
@ -2347,6 +2552,48 @@ makeThrowable
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
findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
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);
if (o == 0) {
object message = makeString
(t, "%s %s not found in %s",
&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, 0),
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeThrowable(t, errorType, message);
throwNew(t, errorType, "%s %s not found in %s",
&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, 0),
&byteArrayBody(t, className(t, class_), 0));
}
return o;
@ -2390,8 +2635,7 @@ findMethodOrNull(Thread* t, object class_, const char* name, const char* spec)
inline object
findVirtualMethod(Thread* t, object method, object class_)
{
return arrayBody(t, classVirtualTable(t, class_),
methodOffset(t, method));
return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method));
}
inline object
@ -2403,8 +2647,8 @@ findInterfaceMethod(Thread* t, object method, object class_)
object itable = classInterfaceTable(t, class_);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == interface) {
return arrayBody(t, arrayBody(t, itable, i + 1),
methodOffset(t, method));
return arrayBody
(t, arrayBody(t, itable, i + 1), methodOffset(t, method));
}
}
abort(t);
@ -2849,10 +3093,10 @@ wait(Thread* t, object o, int64_t milliseconds)
bool interrupted = monitorWait(t, m, milliseconds);
if (interrupted) {
t->exception = makeThrowable(t, Machine::InterruptedExceptionType);
throwNew(t, Machine::InterruptedExceptionType);
}
} else {
t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType);
throwNew(t, Machine::IllegalMonitorStateExceptionType);
}
if (DebugMonitors) {
@ -2881,7 +3125,7 @@ notify(Thread* t, object o)
if (m and monitorOwner(t, m) == t) {
monitorNotify(t, m);
} 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) {
monitorNotifyAll(t, m);
} 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);
o = resolveClass(t, loader, o);
if (UNLIKELY(t->exception)) return 0;
set(t, container, classOffset, o);
}
@ -3072,7 +3315,6 @@ resolveClassInPool(Thread* t, object loader, object method, unsigned index)
PROTECT(t, method);
o = resolveClass(t, loader, referenceName(t, o));
if (UNLIKELY(t->exception)) return 0;
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
@ -3101,12 +3343,10 @@ resolve(Thread* t, object loader, object method, unsigned index,
PROTECT(t, reference);
object class_ = resolveClassInObject(t, loader, o, ReferenceClass);
if (UNLIKELY(t->exception)) return 0;
o = findInHierarchy
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
find, errorType);
if (UNLIKELY(t->exception)) return 0;
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
@ -3236,9 +3476,7 @@ primitiveClass(Thread* t, char name)
case 'S': return type(t, Machine::JshortType);
case 'V': return type(t, Machine::JvoidType);
case 'Z': return type(t, Machine::JbooleanType);
default:
t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType);
return 0;
default: throwNew(t, Machine::IllegalArgumentExceptionType);
}
}

View File

@ -153,13 +153,13 @@ resolveNativeMethod(Thread* t, object method, const char* prefix,
{
unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false);
// 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,
method, false);
unsigned decoratedSize = prefixLength + jniNameLength(t, method, true);
// 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,
method, true);
@ -232,20 +232,13 @@ resolveNative(Thread* t, object method)
initClass(t, methodClass(t, method));
if (LIKELY(t->exception == 0)
and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0)
{
if (methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) {
object native = resolveNativeMethod(t, method);
if (UNLIKELY(native == 0)) {
object message = makeString
(t, "%s.%s%s",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0),
&byteArrayBody(t, methodSpec(t, method), 0));
t->exception = makeThrowable
(t, Machine::UnsatisfiedLinkErrorType, message);
return;
throwNew(t, Machine::UnsatisfiedLinkErrorType, "%s.%s%s",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0),
&byteArrayBody(t, methodSpec(t, method), 0));
}
PROTECT(t, native);

128
src/x86.S
View File

@ -23,6 +23,10 @@
#ifdef __x86_64__
#define CHECKPOINT_THREAD 8
#define CHECKPOINT_STACK 48
#define CHECKPOINT_BASE 56
#ifdef __MINGW32__
.globl GLOBAL(detectFeature)
GLOBAL(detectFeature):
@ -173,6 +177,48 @@ GLOBAL(vmJump):
movq %r8,%rsp
movq %r9,%rbx
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__
.globl GLOBAL(detectFeature)
@ -314,10 +360,52 @@ GLOBAL(vmJump):
movq %r9,%rdx
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__
#elif defined __i386__
#define CHECKPOINT_THREAD 4
#define CHECKPOINT_STACK 24
#define CHECKPOINT_BASE 28
.globl GLOBAL(detectFeature)
GLOBAL(detectFeature):
pushl %ebp
@ -432,4 +520,42 @@ GLOBAL(vmJump):
movl 12(%esp),%esp
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();
}
}
}