mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +00:00
fix various bugs uncovered in GC stress test
This commit is contained in:
parent
7dab93de00
commit
6dec1cbd42
@ -205,6 +205,7 @@ start(Thread* t, jobject this_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
populate(Thread* t, object map)
|
||||
{
|
||||
@ -212,28 +213,32 @@ populate(Thread* t, object map)
|
||||
const char* key;
|
||||
void* value;
|
||||
} builtins[] = {
|
||||
{ "Java_java_lang_Object_toString",
|
||||
reinterpret_cast<void*>(toString) },
|
||||
{ "Java_java_lang_System_arraycopy",
|
||||
reinterpret_cast<void*>(arraycopy) },
|
||||
{ "Java_java_lang_System_loadLibrary",
|
||||
reinterpret_cast<void*>(loadLibrary) },
|
||||
|
||||
{ "Java_java_lang_Thread_start",
|
||||
reinterpret_cast<void*>(start) },
|
||||
{ "Java_java_lang_Thread_sleep",
|
||||
reinterpret_cast<void*>(sleep) },
|
||||
|
||||
{ "Java_java_lang_Throwable_resolveTrace",
|
||||
reinterpret_cast<void*>(resolveTrace) },
|
||||
{ "Java_java_lang_Throwable_trace",
|
||||
reinterpret_cast<void*>(trace) },
|
||||
|
||||
{ "Java_java_lang_Object_getClass",
|
||||
reinterpret_cast<void*>(getClass) },
|
||||
{ "Java_java_lang_Object_wait",
|
||||
reinterpret_cast<void*>(wait) },
|
||||
{ "Java_java_lang_Object_notify",
|
||||
reinterpret_cast<void*>(notify) },
|
||||
{ "Java_java_lang_Object_notifyAll",
|
||||
reinterpret_cast<void*>(notifyAll) },
|
||||
{ "Java_java_lang_Thread_sleep",
|
||||
reinterpret_cast<void*>(sleep) },
|
||||
{ "Java_java_lang_System_loadLibrary",
|
||||
reinterpret_cast<void*>(loadLibrary) },
|
||||
{ "Java_java_lang_System_arraycopy",
|
||||
reinterpret_cast<void*>(arraycopy) },
|
||||
{ "Java_java_lang_Throwable_trace",
|
||||
reinterpret_cast<void*>(trace) },
|
||||
{ "Java_java_lang_Throwable_resolveTrace",
|
||||
reinterpret_cast<void*>(resolveTrace) },
|
||||
{ "Java_java_lang_Thread_start",
|
||||
reinterpret_cast<void*>(start) },
|
||||
{ "Java_java_lang_Object_toString",
|
||||
reinterpret_cast<void*>(toString) },
|
||||
{ "Java_java_lang_Object_wait",
|
||||
reinterpret_cast<void*>(wait) },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
198
src/machine.cpp
198
src/machine.cpp
@ -271,6 +271,12 @@ postVisit(Thread* t, Heap::Visitor* v)
|
||||
void
|
||||
postCollect(Thread* t)
|
||||
{
|
||||
#ifdef VM_STRESS
|
||||
t->vm->system->free(t->heap);
|
||||
t->heap = static_cast<object*>
|
||||
(t->vm->system->allocate(Thread::HeapSizeInBytes));
|
||||
#endif
|
||||
|
||||
if (t->large) {
|
||||
t->vm->system->free(t->large);
|
||||
t->large = 0;
|
||||
@ -410,88 +416,6 @@ makeJNIName(Thread* t, object method, bool decorate)
|
||||
return name;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(Thread* t, object spec)
|
||||
{
|
||||
unsigned footprint = 0;
|
||||
const char* s = reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0));
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
++ s;
|
||||
++ footprint;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
return footprint;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterCount(Thread* t, object spec)
|
||||
{
|
||||
unsigned count = 0;
|
||||
const char* s = reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0));
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
object
|
||||
parsePool(Thread* t, Stream& s)
|
||||
{
|
||||
@ -805,11 +729,10 @@ parseCode(Thread* t, Stream& s, object pool)
|
||||
|
||||
object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false);
|
||||
s.read(&codeBody(t, code, 0), length);
|
||||
PROTECT(t, code);
|
||||
|
||||
unsigned ehtLength = s.read2();
|
||||
if (ehtLength) {
|
||||
PROTECT(t, code);
|
||||
|
||||
object eht = makeExceptionHandlerTable(t, ehtLength, false);
|
||||
for (unsigned i = 0; i < ehtLength; ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
@ -1012,6 +935,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object vtable = makeArray(t, virtualCount, false);
|
||||
|
||||
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||
PROTECT(t, vtable);
|
||||
|
||||
object it = hashMapIterator(t, virtualMap);
|
||||
|
||||
for (; it; it = hashMapIteratorNext(t, it)) {
|
||||
@ -1144,12 +1069,16 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
||||
|
||||
ENTER(t, Thread::ExclusiveState);
|
||||
|
||||
classVmFlags(t, class_) |= classVmFlags(t, bootstrapClass);
|
||||
classFlags(t, bootstrapClass) = classFlags(t, class_);
|
||||
|
||||
memcpy(bootstrapClass,
|
||||
class_,
|
||||
extendedSize(t, class_, baseSize(t, class_, objectClass(t, class_)))
|
||||
* BytesPerWord);
|
||||
set(t, classSuper(t, bootstrapClass), classSuper(t, class_));
|
||||
set(t, classInterfaceTable(t, bootstrapClass),
|
||||
classInterfaceTable(t, class_));
|
||||
set(t, classVirtualTable(t, bootstrapClass), classVirtualTable(t, class_));
|
||||
set(t, classFieldTable(t, bootstrapClass), classFieldTable(t, class_));
|
||||
set(t, classMethodTable(t, bootstrapClass), classMethodTable(t, class_));
|
||||
set(t, classStaticTable(t, bootstrapClass), classStaticTable(t, class_));
|
||||
set(t, classInitializer(t, bootstrapClass), classInitializer(t, class_));
|
||||
|
||||
object fieldTable = classFieldTable(t, class_);
|
||||
if (fieldTable) {
|
||||
@ -1318,9 +1247,6 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread,
|
||||
peer((parent ? parent->child : 0)),
|
||||
child(0),
|
||||
state(NoState),
|
||||
#ifdef VM_STRESS
|
||||
stress(false),
|
||||
#endif // VM_STRESS
|
||||
systemThread(0),
|
||||
javaThread(javaThread),
|
||||
code(0),
|
||||
@ -1331,6 +1257,10 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread,
|
||||
frame(-1),
|
||||
heapIndex(0),
|
||||
protector(0)
|
||||
#ifdef VM_STRESS
|
||||
, stress(false),
|
||||
heap(static_cast<object*>(m->system->allocate(HeapSizeInBytes)))
|
||||
#endif // VM_STRESS
|
||||
{
|
||||
if (parent == 0) {
|
||||
assert(this, m->rootThread == 0);
|
||||
@ -1605,6 +1535,86 @@ stringChars(Thread* t, object string, char* chars)
|
||||
chars[stringLength(t, string)] = 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(const char* s)
|
||||
{
|
||||
unsigned footprint = 0;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
++ s;
|
||||
++ footprint;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
return footprint;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterCount(const char* s)
|
||||
{
|
||||
unsigned count = 0;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
@ -1919,8 +1929,6 @@ resolveClass(Thread* t, object spec)
|
||||
(t, className(t, class_), 0));
|
||||
}
|
||||
|
||||
PROTECT(t, class_);
|
||||
|
||||
object bootstrapClass = hashMapFind
|
||||
(t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
||||
|
||||
@ -1934,6 +1942,8 @@ resolveClass(Thread* t, object spec)
|
||||
}
|
||||
|
||||
if (class_) {
|
||||
PROTECT(t, class_);
|
||||
|
||||
hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash);
|
||||
} else if (t->exception == 0) {
|
||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
||||
|
@ -22,7 +22,7 @@
|
||||
namespace vm {
|
||||
|
||||
const bool Verbose = false;
|
||||
const bool DebugRun = false;
|
||||
const bool DebugRun = true;
|
||||
const bool DebugStack = false;
|
||||
const bool DebugMonitors = false;
|
||||
|
||||
@ -1172,9 +1172,6 @@ class Thread {
|
||||
Thread* peer;
|
||||
Thread* child;
|
||||
State state;
|
||||
#ifdef VM_STRESS
|
||||
bool stress;
|
||||
#endif // VM_STRESS
|
||||
System::Thread* systemThread;
|
||||
object javaThread;
|
||||
object code;
|
||||
@ -1185,8 +1182,13 @@ class Thread {
|
||||
int frame;
|
||||
unsigned heapIndex;
|
||||
Protector* protector;
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
#ifdef VM_STRESS
|
||||
bool stress;
|
||||
object* heap;
|
||||
#else // not VM_STRESS
|
||||
object heap[HeapSizeInWords];
|
||||
#endif // not VM_STRESS
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
};
|
||||
|
||||
inline object
|
||||
@ -1324,15 +1326,21 @@ allocate(Thread* t, unsigned sizeInBytes)
|
||||
}
|
||||
|
||||
inline void
|
||||
set(Thread* t, object& target, object value)
|
||||
mark(Thread* t, object& target)
|
||||
{
|
||||
target = value;
|
||||
if (t->vm->heap->needsMark(&target)) {
|
||||
ACQUIRE_RAW(t, t->vm->heapLock);
|
||||
t->vm->heap->mark(&target);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
set(Thread* t, object& target, object value)
|
||||
{
|
||||
target = value;
|
||||
mark(t, target);
|
||||
}
|
||||
|
||||
inline void
|
||||
setObjectClass(Thread* t, object o, object value)
|
||||
{
|
||||
@ -1910,6 +1918,26 @@ objectArrayBody(Thread* t, object array, unsigned index)
|
||||
return cast<object>(array, (2 + index) * BytesPerWord);
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(const char* s);
|
||||
|
||||
inline unsigned
|
||||
parameterFootprint(Thread* t, object spec)
|
||||
{
|
||||
return parameterFootprint
|
||||
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterCount(const char* s);
|
||||
|
||||
inline unsigned
|
||||
parameterCount(Thread* t, object spec)
|
||||
{
|
||||
return parameterCount
|
||||
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
||||
}
|
||||
|
||||
int
|
||||
lineNumber(Thread* t, object method, unsigned ip);
|
||||
|
||||
|
110
src/run.cpp
110
src/run.cpp
@ -2218,6 +2218,8 @@ run(Thread* t)
|
||||
void
|
||||
run(Thread* t, const char* className, int argc, const char** argv)
|
||||
{
|
||||
enter(t, Thread::ActiveState);
|
||||
|
||||
object args = makeObjectArray
|
||||
(t, arrayBody(t, t->vm->types, Machine::StringType), argc, true);
|
||||
|
||||
@ -2228,7 +2230,7 @@ run(Thread* t, const char* className, int argc, const char** argv)
|
||||
set(t, objectArrayBody(t, args, i), arg);
|
||||
}
|
||||
|
||||
run(t, className, "main", "([Ljava/lang/String;)V", args);
|
||||
run(t, className, "main", "([Ljava/lang/String;)V", 0, args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -2237,9 +2239,64 @@ namespace vm {
|
||||
|
||||
object
|
||||
run(Thread* t, const char* className, const char* methodName,
|
||||
const char* methodSpec, ...)
|
||||
const char* methodSpec, object this_, ...)
|
||||
{
|
||||
enter(t, Thread::ActiveState);
|
||||
assert(t, t->state == Thread::ActiveState
|
||||
or t->state == Thread::ExclusiveState);
|
||||
|
||||
if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this_) {
|
||||
pushObject(t, this_);
|
||||
}
|
||||
|
||||
va_list a;
|
||||
va_start(a, this_);
|
||||
|
||||
const char* s = methodSpec;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
++ s;
|
||||
pushLong(t, va_arg(a, uint64_t));
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
pushInt(t, va_arg(a, uint32_t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(a);
|
||||
|
||||
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
@ -2253,52 +2310,7 @@ run(Thread* t, const char* className, const char* methodName,
|
||||
|
||||
object method = findMethodInClass(t, class_, reference);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
va_list a;
|
||||
va_start(a, methodSpec);
|
||||
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
pushObject(t, va_arg(a, object));
|
||||
}
|
||||
|
||||
const char* s = methodSpec;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
++ s;
|
||||
pushLong(t, va_arg(a, uint64_t));
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
pushInt(t, va_arg(a, uint32_t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(a);
|
||||
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
|
||||
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
unsigned returnCode = invokeNative(t, method);
|
||||
|
Loading…
Reference in New Issue
Block a user