improve handling of unusual bytecode in JIT compiler

Bytecode generated by compilers other than javac or ecj (such as
jython's dynamically generated classes) can contain unreachable code
and exception handlers which apply to more than one try/catch scope.
Previously, the VM's JIT compiler did not handle either of these cases
well, hence this commit.
This commit is contained in:
Joel Dice 2011-04-08 18:50:22 -06:00
parent 60db8cc047
commit 36aa0d6792

View File

@ -5883,36 +5883,75 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_,
}
}
unsigned
resolveIp(MyThread* t, Context* context, object code, unsigned ip)
int
resolveIpForwards(Context* context, int start, int end)
{
if (context->visitTable[ip]) {
return ip;
} else {
// Very rarely, we'll encounter an unreachable goto which is
// referred to by the exception handler table or line number
// table. This can be a problem if we need to determine the
// corresponding machine address for the bytecode instruction
// since we never generated any machine code for it. For now, we
// just follow the goto. The "proper" fix is probably to go ahead
// and generate machine code even though it's unreachable; that
// will protect us against unreachable instructions which aren't
// gotos as well.
switch (codeBody(t, code, ip)) {
case goto_: {
unsigned tmp = ip + 1;
return ip + codeReadInt16(t, code, tmp);
}
case goto_w: {
unsigned tmp = ip + 1;
return ip + codeReadInt32(t, code, tmp);
}
default:
return ip;
}
while (start < end and context->visitTable[start] == 0) {
++ start;
}
if (start >= end) {
return -1;
} else {
return start;
}
}
int
resolveIpBackwards(Context* context, int start, int end)
{
while (start >= end and context->visitTable[start] == 0) {
-- start;
}
if (start < end) {
return -1;
} else {
return start;
}
}
object
truncateIntArray(Thread* t, object array, unsigned length)
{
expect(t, intArrayLength(t, array) > length);
PROTECT(t, array);
object newArray = makeIntArray(t, length);
memcpy(&intArrayBody(t, newArray, 0), &intArrayBody(t, array, 0),
length * 4);
return newArray;
}
object
truncateArray(Thread* t, object array, unsigned length)
{
expect(t, arrayLength(t, array) > length);
PROTECT(t, array);
object newArray = makeArray(t, length);
memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0),
length * BytesPerWord);
return newArray;
}
object
truncateLineNumberTable(Thread* t, object table, unsigned length)
{
expect(t, lineNumberTableLength(t, table) > length);
PROTECT(t, table);
object newTable = makeLineNumberTable(t, length);
memcpy(lineNumberTableBody(t, newTable, 0),
lineNumberTableBody(t, table, 0),
length * sizeof(LineNumber));
return newTable;
}
object
@ -5934,35 +5973,52 @@ translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start)
object newTable = makeArray(t, length + 1);
PROTECT(t, newTable);
set(t, newTable, ArrayBody, newIndex);
for (unsigned i = 0; i < length; ++i) {
unsigned ni = 0;
for (unsigned oi = 0; oi < length; ++ oi) {
ExceptionHandler* oldHandler = exceptionHandlerTableBody
(t, oldTable, i);
(t, oldTable, oi);
intArrayBody(t, newIndex, i * 3)
= c->machineIp
(resolveIp
(t, context, methodCode(t, context->method),
exceptionHandlerStart(oldHandler)))->value() - start;
int handlerStart = resolveIpForwards
(context, exceptionHandlerStart(oldHandler),
exceptionHandlerEnd(oldHandler));
intArrayBody(t, newIndex, (i * 3) + 1)
= c->machineIp(exceptionHandlerEnd(oldHandler))->value() - start;
if (LIKELY(handlerStart >= 0)) {
int handlerEnd = resolveIpBackwards
(context, exceptionHandlerEnd(oldHandler),
exceptionHandlerStart(oldHandler));
intArrayBody(t, newIndex, (i * 3) + 2)
= c->machineIp(exceptionHandlerIp(oldHandler))->value() - start;
assert(t, handlerEnd >= 0);
object type;
if (exceptionHandlerCatchType(oldHandler)) {
type = resolveClassInPool
(t, context->method, exceptionHandlerCatchType(oldHandler) - 1);
} else {
type = 0;
intArrayBody(t, newIndex, ni * 3)
= c->machineIp(handlerStart)->value() - start;
intArrayBody(t, newIndex, (ni * 3) + 1)
= c->machineIp(handlerEnd)->value() - start;
intArrayBody(t, newIndex, (ni * 3) + 2)
= c->machineIp(exceptionHandlerIp(oldHandler))->value() - start;
object type;
if (exceptionHandlerCatchType(oldHandler)) {
type = resolveClassInPool
(t, context->method, exceptionHandlerCatchType(oldHandler) - 1);
} else {
type = 0;
}
set(t, newTable, ArrayBody + ((ni + 1) * BytesPerWord), type);
++ ni;
}
set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type);
}
if (UNLIKELY(ni < length)) {
newIndex = truncateIntArray(t, newIndex, ni * 3);
newTable = truncateArray(t, newTable, ni + 1);
}
set(t, newTable, ArrayBody, newIndex);
return newTable;
} else {
return 0;
@ -5978,18 +6034,28 @@ translateLineNumberTable(MyThread* t, Context* context, intptr_t start)
unsigned length = lineNumberTableLength(t, oldTable);
object newTable = makeLineNumberTable(t, length);
for (unsigned i = 0; i < length; ++i) {
LineNumber* oldLine = lineNumberTableBody(t, oldTable, i);
LineNumber* newLine = lineNumberTableBody(t, newTable, i);
unsigned ni = 0;
for (unsigned oi = 0; oi < length; ++oi) {
LineNumber* oldLine = lineNumberTableBody(t, oldTable, oi);
LineNumber* newLine = lineNumberTableBody(t, newTable, ni);
lineNumberIp(newLine)
= context->compiler->machineIp
(resolveIp
(t, context, methodCode(t, context->method), lineNumberIp(oldLine)))
->value()
- start;
int ip = resolveIpForwards
(context, lineNumberIp(oldLine), oi + 1 < length
? lineNumberIp(lineNumberTableBody(t, oldTable, oi + 1)) - 1
: lineNumberIp(oldLine) + 1);
lineNumberLine(newLine) = lineNumberLine(oldLine);
if (LIKELY(ip >= 0)) {
lineNumberIp(newLine)
= context->compiler->machineIp(ip)->value() - start;
lineNumberLine(newLine) = lineNumberLine(oldLine);
++ ni;
}
}
if (UNLIKELY(ni < length)) {
newTable = truncateLineNumberTable(t, newTable, ni);
}
return newTable;
@ -6881,55 +6947,56 @@ compile(MyThread* t, Context* context)
THREAD_RUNTIME_ARRAY(t, bool, visited, visitCount);
memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool));
while (visitCount) {
bool progress UNUSED = false;
bool progress = true;
while (progress) {
progress = false;
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
c->restoreState(state);
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
unsigned start = resolveIp
(t, context, methodCode(t, context->method),
exceptionHandlerStart(eh));
int start = resolveIpForwards
(context, exceptionHandlerStart(eh), exceptionHandlerEnd(eh));
if ((not RUNTIME_ARRAY_BODY(visited)[i])
and start >= 0
and context->visitTable[start])
{
-- visitCount;
RUNTIME_ARRAY_BODY(visited)[i] = true;
progress = true;
THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap,
codeMaxStack(t, methodCode(t, context->method)));
Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap));
if (context->visitTable[exceptionHandlerIp(eh)] == 0) {
THREAD_RUNTIME_ARRAY
(t, uint8_t, stackMap,
codeMaxStack(t, methodCode(t, context->method)));
Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap));
unsigned end = exceptionHandlerEnd(eh);
if (exceptionHandlerIp(eh) >= start
and exceptionHandlerIp(eh) < end)
{
end = exceptionHandlerIp(eh);
unsigned end = exceptionHandlerEnd(eh);
if (exceptionHandlerIp(eh) >= start
and exceptionHandlerIp(eh) < end)
{
end = exceptionHandlerIp(eh);
}
context->eventLog.append(PushExceptionHandlerEvent);
context->eventLog.append2(start);
context->eventLog.append2(end);
for (unsigned i = 1;
i < codeMaxStack(t, methodCode(t, context->method));
++i)
{
frame2.set(localSize(t, context->method) + i, Frame::Integer);
}
compile(t, &frame2, exceptionHandlerIp(eh), start);
context->eventLog.append(PopContextEvent);
eventIndex = calculateFrameMaps(t, context, 0, eventIndex);
}
context->eventLog.append(PushExceptionHandlerEvent);
context->eventLog.append2(start);
context->eventLog.append2(end);
for (unsigned i = 1;
i < codeMaxStack(t, methodCode(t, context->method));
++i)
{
frame2.set(localSize(t, context->method) + i, Frame::Integer);
}
compile(t, &frame2, exceptionHandlerIp(eh), start);
context->eventLog.append(PopContextEvent);
eventIndex = calculateFrameMaps(t, context, 0, eventIndex);
}
}
assert(t, progress);
}
}