implement lazy class/field/method resolution in JIT compiler

Unlike the interpreter, the JIT compiler tries to resolve all the
symbols referenced by a method when compiling that method.  However,
this can backfire if a symbol cannot be resolved: we end up throwing
an e.g. NoClassDefFoundError for code which may never be executed.
This is particularly troublesome for code which supports multiple
APIs, choosing one at runtime.

The solution is to defer to stub code for symbols which can't be
resolved at JIT compile time.  Such a stub will try again at runtime
to resolve the needed symbol and throw an appropriate error if it
still can't be found.
This commit is contained in:
Joel Dice
2011-03-15 17:52:02 -06:00
parent 48e569c65a
commit 453ceb42ab
9 changed files with 1508 additions and 540 deletions

View File

@ -1460,27 +1460,11 @@ interpret3(Thread* t, const int base)
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
PROTECT(t, field);
acquire(t, field);
}
PROTECT(t, field);
ACQUIRE_FIELD_FOR_READ(t, field);
pushField(t, popObject(t), field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
loadMemoryBarrier();
}
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
goto throw_;
@ -1498,26 +1482,9 @@ interpret3(Thread* t, const int base)
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
acquire(t, field);
}
ACQUIRE_FIELD_FOR_READ(t, field);
pushField(t, classStaticTable(t, fieldClass(t, field)), field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
loadMemoryBarrier();
}
}
} goto loop;
case goto_: {
@ -2460,80 +2427,61 @@ interpret3(Thread* t, const int base)
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
PROTECT(t, field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
{ ACQUIRE_FIELD_FOR_WRITE(t, field);
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
int32_t value = popInt(t);
object o = popObject(t);
if (LIKELY(o)) {
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
cast<int8_t>(o, fieldOffset(t, field)) = value;
break;
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
int32_t value = popInt(t);
object o = popObject(t);
if (LIKELY(o)) {
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
cast<int8_t>(o, fieldOffset(t, field)) = value;
break;
case CharField:
case ShortField:
cast<int16_t>(o, fieldOffset(t, field)) = value;
break;
case CharField:
case ShortField:
cast<int16_t>(o, fieldOffset(t, field)) = value;
break;
case FloatField:
case IntField:
cast<int32_t>(o, fieldOffset(t, field)) = value;
break;
case FloatField:
case IntField:
cast<int32_t>(o, fieldOffset(t, field)) = value;
break;
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
} break;
case DoubleField:
case LongField: {
int64_t value = popLong(t);
object o = popObject(t);
if (LIKELY(o)) {
cast<int64_t>(o, fieldOffset(t, field)) = value;
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case DoubleField:
case LongField: {
int64_t value = popLong(t);
object o = popObject(t);
if (LIKELY(o)) {
cast<int64_t>(o, fieldOffset(t, field)) = value;
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case ObjectField: {
object value = popObject(t);
object o = popObject(t);
if (LIKELY(o)) {
set(t, o, fieldOffset(t, field), value);
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case ObjectField: {
object value = popObject(t);
object o = popObject(t);
if (LIKELY(o)) {
set(t, o, fieldOffset(t, field), value);
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
default: abort(t);
}
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
storeLoadMemoryBarrier();
default: abort(t);
}
}
@ -2551,16 +2499,7 @@ interpret3(Thread* t, const int base)
PROTECT(t, field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
ACQUIRE_FIELD_FOR_WRITE(t, field);
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
@ -2603,17 +2542,6 @@ interpret3(Thread* t, const int base)
default: abort(t);
}
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
storeLoadMemoryBarrier();
}
}
} goto loop;
case ret: {