fix subroutine stack mapping bug leading to crashes during GC

The stack mapping code was broken for cases of stack slots being
reused to hold primitives or addresses within subroutines after
previously being used to hold object references.  We now bitwise "and"
the stack map upon return from the subroutine with the map as it
existed prior to calling the subroutine, which has the effect of
clearing map locations previously marked as GC roots where
appropriate.
This commit is contained in:
Joel Dice 2011-02-16 14:29:57 -07:00
parent c743140e08
commit 59183c7821
2 changed files with 72 additions and 47 deletions

View File

@ -5288,7 +5288,8 @@ calculateTryCatchRoots(Context* context, SubroutinePath* subroutinePath,
unsigned unsigned
calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
unsigned eventIndex, SubroutinePath* subroutinePath = 0) unsigned eventIndex, SubroutinePath* subroutinePath = 0,
uintptr_t* resultRoots = 0)
{ {
// for each instruction with more than one predecessor, and for each // for each instruction with more than one predecessor, and for each
// stack position, determine if there exists a path to that // stack position, determine if there exists a path to that
@ -5321,11 +5322,12 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
switch (e) { switch (e) {
case PushContextEvent: { case PushContextEvent: {
eventIndex = calculateFrameMaps eventIndex = calculateFrameMaps
(t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath); (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath,
resultRoots);
} break; } break;
case PopContextEvent: case PopContextEvent:
return eventIndex; goto exit;
case IpEvent: { case IpEvent: {
ip = context->eventLog.get2(eventIndex); ip = context->eventLog.get2(eventIndex);
@ -5491,18 +5493,41 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
makeRootTable(t, &(context->zone), context->method)); makeRootTable(t, &(context->zone), context->method));
} }
THREAD_RUNTIME_ARRAY(t, uintptr_t, subroutineRoots, mapSize);
calculateFrameMaps calculateFrameMaps
(t, context, RUNTIME_ARRAY_BODY(roots), call->subroutine->logIndex, (t, context, RUNTIME_ARRAY_BODY(roots), call->subroutine->logIndex,
path); path, RUNTIME_ARRAY_BODY(subroutineRoots));
for (unsigned wi = 0; wi < mapSize; ++wi) {
RUNTIME_ARRAY_BODY(roots)[wi]
&= RUNTIME_ARRAY_BODY(subroutineRoots)[wi];
}
} break; } break;
case PopSubroutineEvent: case PopSubroutineEvent:
return static_cast<unsigned>(-1); eventIndex = static_cast<unsigned>(-1);
goto exit;
default: abort(t); default: abort(t);
} }
} }
exit:
if (resultRoots and ip != -1) {
if (DebugFrameMaps) {
fprintf(stderr, "result roots at ip %3d: ", ip);
printSet(*RUNTIME_ARRAY_BODY(roots), mapSize);
if (subroutinePath) {
fprintf(stderr, " ");
print(subroutinePath);
}
fprintf(stderr, "\n");
}
memcpy(resultRoots, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord);
}
return eventIndex; return eventIndex;
} }

View File

@ -237,58 +237,58 @@ public class Subroutine {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// test(false, false); test(false, false);
// test(false, true); test(false, true);
// test(true, false); test(true, false);
// String.valueOf(test2(1)); String.valueOf(test2(1));
// String.valueOf(test2(2)); String.valueOf(test2(2));
// String.valueOf(test2(3)); String.valueOf(test2(3));
// String.valueOf(test3(1, 1, 1)); String.valueOf(test3(1, 1, 1));
// String.valueOf(test3(2, 1, 1)); String.valueOf(test3(2, 1, 1));
// String.valueOf(test3(3, 1, 1)); String.valueOf(test3(3, 1, 1));
// String.valueOf(test3(1, 2, 1)); String.valueOf(test3(1, 2, 1));
// String.valueOf(test3(2, 2, 1)); String.valueOf(test3(2, 2, 1));
// String.valueOf(test3(3, 2, 1)); String.valueOf(test3(3, 2, 1));
// String.valueOf(test3(1, 3, 1)); String.valueOf(test3(1, 3, 1));
// String.valueOf(test3(2, 3, 1)); String.valueOf(test3(2, 3, 1));
// String.valueOf(test3(3, 3, 1)); String.valueOf(test3(3, 3, 1));
// String.valueOf(test3(1, 1, 2)); String.valueOf(test3(1, 1, 2));
// String.valueOf(test3(2, 1, 2)); String.valueOf(test3(2, 1, 2));
// String.valueOf(test3(3, 1, 2)); String.valueOf(test3(3, 1, 2));
// String.valueOf(test3(1, 2, 2)); String.valueOf(test3(1, 2, 2));
// String.valueOf(test3(2, 2, 2)); String.valueOf(test3(2, 2, 2));
// String.valueOf(test3(3, 2, 2)); String.valueOf(test3(3, 2, 2));
// String.valueOf(test3(1, 3, 2)); String.valueOf(test3(1, 3, 2));
// String.valueOf(test3(2, 3, 2)); String.valueOf(test3(2, 3, 2));
// String.valueOf(test3(3, 3, 2)); String.valueOf(test3(3, 3, 2));
// String.valueOf(test3(1, 1, 3)); String.valueOf(test3(1, 1, 3));
// String.valueOf(test3(2, 1, 3)); String.valueOf(test3(2, 1, 3));
// String.valueOf(test3(3, 1, 3)); String.valueOf(test3(3, 1, 3));
// String.valueOf(test3(1, 2, 3)); String.valueOf(test3(1, 2, 3));
// String.valueOf(test3(2, 2, 3)); String.valueOf(test3(2, 2, 3));
// String.valueOf(test3(3, 2, 3)); String.valueOf(test3(3, 2, 3));
// String.valueOf(test3(1, 3, 3)); String.valueOf(test3(1, 3, 3));
// String.valueOf(test3(2, 3, 3)); String.valueOf(test3(2, 3, 3));
// String.valueOf(test3(3, 3, 3)); String.valueOf(test3(3, 3, 3));
// String.valueOf(test4(1)); String.valueOf(test4(1));
// String.valueOf(test4(2)); String.valueOf(test4(2));
// String.valueOf(test4(3)); String.valueOf(test4(3));
// expect(test4(1) == 0xFABFABFABFL); expect(test4(1) == 0xFABFABFABFL);
// new Subroutine().test5(true); new Subroutine().test5(true);
// new Subroutine().test5(false); new Subroutine().test5(false);
makeTestClass().getMethod("test", new Class[0]).invoke makeTestClass().getMethod("test", new Class[0]).invoke
(null, new Object[0]); (null, new Object[0]);