mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
handle subroutines properly when generating frame maps (initial sketch)
This commit is contained in:
parent
f239424930
commit
b308354a3a
683
src/compile.cpp
683
src/compile.cpp
@ -493,6 +493,70 @@ class PoolElement: public Promise {
|
||||
};
|
||||
|
||||
class Context;
|
||||
class SubroutineCall;
|
||||
|
||||
class Subroutine {
|
||||
public:
|
||||
Subroutine(unsigned ip, unsigned logIndex, Subroutine* next):
|
||||
next(next),
|
||||
calls(0),
|
||||
handle(0),
|
||||
ip(ip),
|
||||
logIndex(logIndex),
|
||||
stackIndex(0),
|
||||
callCount(0),
|
||||
tableIndex(0),
|
||||
visited(false)
|
||||
{ }
|
||||
|
||||
Subroutine* next;
|
||||
SubroutineCall* calls;
|
||||
Compiler::Subroutine* handle;
|
||||
unsigned ip;
|
||||
unsigned logIndex;
|
||||
unsigned stackIndex;
|
||||
unsigned callCount;
|
||||
unsigned tableIndex;
|
||||
bool visited;
|
||||
};
|
||||
|
||||
class SubroutineCall {
|
||||
public:
|
||||
SubroutineCall(Subroutine* subroutine, Promise* returnAddress):
|
||||
subroutine(subroutine),
|
||||
returnAddress(returnAddress),
|
||||
next(subroutine->calls)
|
||||
{
|
||||
subroutine->calls = this;
|
||||
}
|
||||
|
||||
Subroutine* subroutine;
|
||||
Promise* returnAddress;
|
||||
SubroutineCall* next;
|
||||
};
|
||||
|
||||
class SubroutinePath {
|
||||
public:
|
||||
SubroutinePath(SubroutineCall* call, SubroutinePath* next):
|
||||
call(call),
|
||||
next(next)
|
||||
{ }
|
||||
|
||||
SubroutineCall* call;
|
||||
SubroutinePath* next;
|
||||
};
|
||||
|
||||
class SubroutineTrace {
|
||||
public:
|
||||
SubroutineTrace(SubroutinePath* path, SubroutineTrace* next):
|
||||
path(path),
|
||||
next(next)
|
||||
{ }
|
||||
|
||||
SubroutinePath* path;
|
||||
SubroutineTrace* next;
|
||||
uintptr_t map[0];
|
||||
};
|
||||
|
||||
class TraceElement: public TraceHandler {
|
||||
public:
|
||||
@ -504,6 +568,7 @@ class TraceElement: public TraceHandler {
|
||||
context(context),
|
||||
address(0),
|
||||
next(next),
|
||||
subroutineTrace(0),
|
||||
target(target),
|
||||
argumentIndex(0),
|
||||
flags(flags)
|
||||
@ -519,6 +584,7 @@ class TraceElement: public TraceHandler {
|
||||
Context* context;
|
||||
Promise* address;
|
||||
TraceElement* next;
|
||||
SubroutineTrace* subroutineTrace;
|
||||
object target;
|
||||
unsigned argumentIndex;
|
||||
unsigned flags;
|
||||
@ -548,7 +614,9 @@ enum Event {
|
||||
IpEvent,
|
||||
MarkEvent,
|
||||
ClearEvent,
|
||||
TraceEvent
|
||||
TraceEvent,
|
||||
PushSubroutineEvent,
|
||||
PopSubroutineEvent
|
||||
};
|
||||
|
||||
unsigned
|
||||
@ -685,11 +753,13 @@ class Context {
|
||||
method(method),
|
||||
bootContext(bootContext),
|
||||
objectPool(0),
|
||||
objectPoolCount(0),
|
||||
subroutines(0),
|
||||
traceLog(0),
|
||||
traceLogCount(0),
|
||||
visitTable(makeVisitTable(t, &zone, method)),
|
||||
rootTable(makeRootTable(t, &zone, method)),
|
||||
objectPoolCount(0),
|
||||
traceLogCount(0),
|
||||
dirtyRoots(false),
|
||||
eventLog(t->m->system, t->m->heap, 1024),
|
||||
protector(this)
|
||||
{ }
|
||||
@ -703,11 +773,13 @@ class Context {
|
||||
method(0),
|
||||
bootContext(0),
|
||||
objectPool(0),
|
||||
objectPoolCount(0),
|
||||
subroutines(0),
|
||||
traceLog(0),
|
||||
traceLogCount(0),
|
||||
visitTable(0),
|
||||
rootTable(0),
|
||||
objectPoolCount(0),
|
||||
traceLogCount(0),
|
||||
dirtyRoots(false),
|
||||
eventLog(t->m->system, t->m->heap, 0),
|
||||
protector(this)
|
||||
{ }
|
||||
@ -725,11 +797,12 @@ class Context {
|
||||
object method;
|
||||
BootContext* bootContext;
|
||||
PoolElement* objectPool;
|
||||
unsigned objectPoolCount;
|
||||
Subroutine* subroutines;
|
||||
TraceElement* traceLog;
|
||||
unsigned traceLogCount;
|
||||
uint16_t* visitTable;
|
||||
uintptr_t* rootTable;
|
||||
unsigned objectPoolCount;
|
||||
unsigned traceLogCount;
|
||||
bool dirtyRoots;
|
||||
Vector eventLog;
|
||||
MyProtector protector;
|
||||
@ -1308,11 +1381,63 @@ class Frame {
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
unsigned startSubroutine(unsigned ip, Promise* returnAddress) {
|
||||
pushAddress(addressOperand(returnAddress));
|
||||
|
||||
Subroutine* subroutine = 0;
|
||||
for (Subroutine* s = context->subroutines; s; s = s->next) {
|
||||
if (s->ip == ip) {
|
||||
subroutine = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (subroutine == 0) {
|
||||
context->subroutines = subroutine = new
|
||||
(context->zone.allocate(sizeof(Subroutine)))
|
||||
Subroutine(ip, context->eventLog.length(), context->subroutines);
|
||||
}
|
||||
|
||||
subroutine->handle = c->startSubroutine();
|
||||
this->subroutine = subroutine;
|
||||
|
||||
SubroutineCall* call = new
|
||||
(context->zone.allocate(sizeof(SubroutineCall)))
|
||||
SubroutineCall(subroutine, returnAddress);
|
||||
|
||||
context->eventLog.append(PushSubroutineEvent);
|
||||
context->eventLog.appendAddress(call);
|
||||
|
||||
unsigned nextIndexIndex = context->eventLog.length();
|
||||
context->eventLog.append2(0);
|
||||
|
||||
c->saveLocals();
|
||||
|
||||
return nextIndexIndex;
|
||||
}
|
||||
|
||||
void returnFromSubroutine(unsigned returnAddressLocal) {
|
||||
c->endSubroutine(subroutine->handle);
|
||||
subroutine->stackIndex = localOffsetFromStack
|
||||
(t, translateLocalIndex(context, 1, returnAddressLocal),
|
||||
context->method);
|
||||
}
|
||||
|
||||
void endSubroutine(unsigned nextIndexIndex) {
|
||||
context->eventLog.set2(nextIndexIndex, context->eventLog.length());
|
||||
|
||||
c->cleanLocals();
|
||||
|
||||
poppedInt();
|
||||
|
||||
context->eventLog.append(PopSubroutineEvent);
|
||||
}
|
||||
|
||||
Context* context;
|
||||
MyThread* t;
|
||||
Compiler* c;
|
||||
Compiler::Subroutine* subroutine;
|
||||
Subroutine* subroutine;
|
||||
uint8_t* stackMap;
|
||||
unsigned ip;
|
||||
unsigned sp;
|
||||
@ -2296,67 +2421,6 @@ handleExit(MyThread* t, Frame* frame)
|
||||
(t, frame, getThunk(t, releaseMonitorForObjectThunk));
|
||||
}
|
||||
|
||||
int
|
||||
exceptionIndex(MyThread* t, object code, unsigned jsrIp, unsigned dstIp)
|
||||
{
|
||||
object table = codeExceptionHandlerTable(t, code);
|
||||
unsigned length = exceptionHandlerTableLength(t, table);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, table, i);
|
||||
if (exceptionHandlerCatchType(eh) == 0) {
|
||||
unsigned ip = exceptionHandlerIp(eh);
|
||||
unsigned index;
|
||||
switch (codeBody(t, code, ip++)) {
|
||||
case astore:
|
||||
index = codeBody(t, code, ip++);
|
||||
break;
|
||||
|
||||
case astore_0:
|
||||
index = 0;
|
||||
break;
|
||||
|
||||
case astore_1:
|
||||
index = 1;
|
||||
break;
|
||||
|
||||
case astore_2:
|
||||
index = 2;
|
||||
break;
|
||||
|
||||
case astore_3:
|
||||
index = 3;
|
||||
break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
|
||||
if (ip == jsrIp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (codeBody(t, code, ip++)) {
|
||||
case jsr: {
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
if ((ip - 3) + offset == dstIp) {
|
||||
return index;
|
||||
}
|
||||
} break;
|
||||
|
||||
case jsr_w: {
|
||||
uint32_t offset = codeReadInt32(t, code, ip);
|
||||
if ((ip - 5) + offset == dstIp) {
|
||||
return index;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
}
|
||||
|
||||
bool
|
||||
inTryBlock(MyThread* t, object code, unsigned ip)
|
||||
{
|
||||
@ -3540,30 +3604,14 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
int index = exceptionIndex(t, code, thisIp, newIp);
|
||||
if (index >= 0) {
|
||||
// store a null pointer at the same index the exception would
|
||||
// be stored in the finally block so we can safely treat that
|
||||
// location as a GC root. Of course, this assumes there
|
||||
// wasn't already a live value there, which is something we
|
||||
// should verify once we have complete data flow information
|
||||
// (todo).
|
||||
storeLocal(context, 1, c->constant(0), index);
|
||||
frame->storedObject(translateLocalIndex(context, 1, index));
|
||||
}
|
||||
|
||||
frame->pushAddress(frame->addressOperand(c->machineIp(ip)));
|
||||
unsigned start = frame->startSubroutine(newIp, c->machineIp(ip));
|
||||
|
||||
c->jmp(frame->machineIp(newIp));
|
||||
|
||||
frame->subroutine = c->startSubroutine();
|
||||
|
||||
compile(t, frame, newIp);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
|
||||
frame->poppedInt();
|
||||
|
||||
c->restoreFromSubroutine(frame->subroutine);
|
||||
frame->endSubroutine(start);
|
||||
} break;
|
||||
|
||||
case l2d: {
|
||||
@ -4047,10 +4095,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
}
|
||||
} break;
|
||||
|
||||
case ret:
|
||||
c->jmp(loadLocal(context, 1, codeBody(t, code, ip)));
|
||||
c->endSubroutine(frame->subroutine);
|
||||
return;
|
||||
case ret: {
|
||||
unsigned index = codeBody(t, code, ip);
|
||||
c->jmp(loadLocal(context, 1, index));
|
||||
frame->returnFromSubroutine(index);
|
||||
} return;
|
||||
|
||||
case return_:
|
||||
if (needsReturnBarrier(t, context->method)) {
|
||||
@ -4169,10 +4218,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
frame->storeLong(codeReadInt16(t, code, ip));
|
||||
} break;
|
||||
|
||||
case ret:
|
||||
c->jmp(loadLocal(context, 1, codeReadInt16(t, code, ip)));
|
||||
c->endSubroutine(frame->subroutine);
|
||||
return;
|
||||
case ret: {
|
||||
unsigned index = codeReadInt16(t, code, ip);
|
||||
c->jmp(loadLocal(context, 1, index));
|
||||
frame->returnFromSubroutine(index);
|
||||
} return;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
@ -4294,7 +4344,7 @@ printSet(uintptr_t m, unsigned limit)
|
||||
|
||||
unsigned
|
||||
calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
|
||||
unsigned eventIndex)
|
||||
unsigned eventIndex, SubroutinePath* subroutinePath = 0)
|
||||
{
|
||||
// for each instruction with more than one predecessor, and for each
|
||||
// stack position, determine if there exists a path to that
|
||||
@ -4395,11 +4445,36 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
memcpy(te->map, roots, mapSize * BytesPerWord);
|
||||
if (subroutinePath == 0) {
|
||||
memcpy(te->map, roots, mapSize * BytesPerWord);
|
||||
} else {
|
||||
te->subroutineTrace = new
|
||||
(context->zone.allocate
|
||||
(sizeof(SubroutineTrace) + (mapSize * BytesPerWord)))
|
||||
SubroutineTrace(subroutinePath, te->subroutineTrace);
|
||||
|
||||
memcpy(te->subroutineTrace->map, roots, mapSize * BytesPerWord);
|
||||
}
|
||||
|
||||
eventIndex += BytesPerWord;
|
||||
} break;
|
||||
|
||||
case PushSubroutineEvent: {
|
||||
SubroutineCall* call;
|
||||
context->eventLog.get(eventIndex, &call, BytesPerWord);
|
||||
eventIndex += BytesPerWord;
|
||||
unsigned nextIndex = context->eventLog.get2(eventIndex);
|
||||
eventIndex = nextIndex;
|
||||
|
||||
calculateFrameMaps
|
||||
(t, context, roots, call->subroutine->logIndex, new
|
||||
(context->zone.allocate(sizeof(SubroutinePath)))
|
||||
SubroutinePath(call, subroutinePath));
|
||||
} break;
|
||||
|
||||
case PopSubroutineEvent:
|
||||
return static_cast<unsigned>(-1);
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
@ -4422,7 +4497,7 @@ compareTraceElementPointers(const void* va, const void* vb)
|
||||
}
|
||||
|
||||
unsigned
|
||||
frameObjectMapSize(MyThread* t, object method, object map)
|
||||
simpleFrameMapTableSize(MyThread* t, object method, object map)
|
||||
{
|
||||
int size = frameMapSizeInBits(t, method);
|
||||
return ceiling(intArrayLength(t, map) * size, 32 + size);
|
||||
@ -4450,21 +4525,230 @@ finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name)
|
||||
}
|
||||
|
||||
void
|
||||
setBit(MyThread* t, object map, unsigned count, unsigned size, unsigned i,
|
||||
unsigned j)
|
||||
setBit(int32_t* dst, unsigned index)
|
||||
{
|
||||
unsigned index = ((i * size) + j);
|
||||
intArrayBody(t, map, count + (index / 32))
|
||||
|= static_cast<int32_t>(1) << (index % 32);
|
||||
dst[index / 32] |= static_cast<int32_t>(1) << (index % 32);
|
||||
}
|
||||
|
||||
void
|
||||
clearBit(MyThread* t, object map, unsigned count, unsigned size, unsigned i,
|
||||
unsigned j)
|
||||
clearBit(int32_t* dst, unsigned index)
|
||||
{
|
||||
unsigned index = ((i * size) + j);
|
||||
intArrayBody(t, map, count + (index / 32))
|
||||
&= ~(static_cast<int32_t>(1) << (index % 32));
|
||||
dst[index / 32] &= ~(static_cast<int32_t>(1) << (index % 32));
|
||||
}
|
||||
|
||||
void
|
||||
print(SubroutinePath* path)
|
||||
{
|
||||
if (path) {
|
||||
fprintf(stderr, " (");
|
||||
while (true) {
|
||||
fprintf(stderr, "%"LLD"", path->call->returnAddress->value());
|
||||
path = path->next;
|
||||
if (path) {
|
||||
fprintf(stderr, ", ");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, ")");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
copyFrameMap(int32_t* dst, uintptr_t* src, unsigned mapSizeInBits,
|
||||
unsigned offset, TraceElement* p,
|
||||
SubroutinePath* subroutinePath)
|
||||
{
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, " orig roots at ip %p: ", reinterpret_cast<void*>
|
||||
(p->address->value()));
|
||||
printSet(src[0], ceiling(mapSizeInBits, BitsPerWord));
|
||||
print(subroutinePath);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "final roots at ip %p: ", reinterpret_cast<void*>
|
||||
(p->address->value()));
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < p->argumentIndex; ++j) {
|
||||
if (getBit(src, j)) {
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, "1");
|
||||
}
|
||||
setBit(dst, offset + j);
|
||||
} else {
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, "_");
|
||||
}
|
||||
clearBit(dst, offset + j);
|
||||
}
|
||||
}
|
||||
|
||||
if (DebugFrameMaps) {
|
||||
print(subroutinePath);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
class FrameMapTableHeader {
|
||||
public:
|
||||
FrameMapTableHeader(unsigned indexCount):
|
||||
indexCount(indexCount)
|
||||
{ }
|
||||
|
||||
unsigned indexCount;
|
||||
};
|
||||
|
||||
class FrameMapTableIndexElement {
|
||||
public:
|
||||
FrameMapTableIndexElement(int offset, unsigned base, unsigned path):
|
||||
offset(offset),
|
||||
base(base),
|
||||
path(path)
|
||||
{ }
|
||||
|
||||
int offset;
|
||||
unsigned base;
|
||||
unsigned path;
|
||||
};
|
||||
|
||||
class FrameMapTablePath {
|
||||
public:
|
||||
FrameMapTablePath(unsigned stackIndex, unsigned elementCount, unsigned next):
|
||||
stackIndex(stackIndex),
|
||||
elementCount(elementCount),
|
||||
next(next)
|
||||
{ }
|
||||
|
||||
unsigned stackIndex;
|
||||
unsigned elementCount;
|
||||
unsigned next;
|
||||
int32_t elements[0];
|
||||
};
|
||||
|
||||
object
|
||||
makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start,
|
||||
TraceElement** elements, unsigned pathFootprint,
|
||||
unsigned mapCount)
|
||||
{
|
||||
unsigned mapSize = frameMapSizeInBits(t, context->method);
|
||||
unsigned indexOffset = sizeof(FrameMapTableHeader);
|
||||
unsigned mapsOffset = indexOffset
|
||||
+ (context->traceLogCount * sizeof(FrameMapTableIndexElement));
|
||||
unsigned pathsOffset = mapsOffset + (ceiling(mapCount * mapSize, 32) * 4);
|
||||
|
||||
object table = makeByteArray(t, pathsOffset + pathFootprint);
|
||||
|
||||
int8_t* body = &byteArrayBody(t, table, 0);
|
||||
new (body) FrameMapTableHeader(context->traceLogCount);
|
||||
|
||||
unsigned nextTableIndex = pathsOffset;
|
||||
unsigned nextMapIndex = 0;
|
||||
for (unsigned i = 0; i < context->traceLogCount; ++i) {
|
||||
TraceElement* p = elements[i];
|
||||
unsigned mapBase = nextMapIndex;
|
||||
|
||||
unsigned pathIndex;
|
||||
if (p->subroutineTrace) {
|
||||
FrameMapTablePath* previous = 0;
|
||||
Subroutine* subroutine = p->subroutineTrace->path->call->subroutine;
|
||||
for (Subroutine* s = subroutine; s; s = s->next) {
|
||||
if (s->tableIndex != 0) {
|
||||
unsigned pathObjectSize = sizeof(FrameMapTablePath)
|
||||
+ (sizeof(int32_t) * s->callCount);
|
||||
|
||||
assert(t, nextTableIndex + pathObjectSize
|
||||
<= byteArrayLength(t, table));
|
||||
|
||||
s->tableIndex = nextTableIndex;
|
||||
|
||||
nextTableIndex += pathObjectSize;
|
||||
|
||||
FrameMapTablePath* current = new (body + s->tableIndex)
|
||||
FrameMapTablePath
|
||||
(s->stackIndex, s->callCount, s->next ? s->next->tableIndex : 0);
|
||||
|
||||
unsigned i = 0;
|
||||
for (SubroutineCall* c = subroutine->calls; c; c = c->next) {
|
||||
assert(t, i < s->callCount);
|
||||
|
||||
current->elements[i]
|
||||
= static_cast<intptr_t>(c->returnAddress->value())
|
||||
- reinterpret_cast<intptr_t>(start);
|
||||
}
|
||||
|
||||
if (previous) {
|
||||
previous->next = s->tableIndex;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pathIndex = subroutine->tableIndex;
|
||||
|
||||
for (SubroutineTrace* trace = p->subroutineTrace;
|
||||
trace; trace = trace->next)
|
||||
{
|
||||
assert(t, ceiling(nextMapIndex + mapSize, 32) * 4 <= pathsOffset);
|
||||
|
||||
copyFrameMap(reinterpret_cast<int32_t*>(body + mapsOffset),
|
||||
trace->map, mapSize, nextMapIndex, p, trace->path);
|
||||
|
||||
nextMapIndex += mapSize;
|
||||
}
|
||||
} else {
|
||||
pathIndex = 0;
|
||||
|
||||
assert(t, ceiling(nextMapIndex + mapSize, 32) * 4 <= pathsOffset);
|
||||
|
||||
copyFrameMap(reinterpret_cast<int32_t*>(body + mapsOffset), p->map,
|
||||
mapSize, nextMapIndex, p, 0);
|
||||
|
||||
nextMapIndex += mapSize;
|
||||
}
|
||||
|
||||
unsigned elementIndex = indexOffset
|
||||
+ (i * sizeof(FrameMapTableIndexElement));
|
||||
|
||||
assert(t, elementIndex + sizeof(FrameMapTableIndexElement) <= mapsOffset);
|
||||
|
||||
new (body + elementIndex) FrameMapTableIndexElement
|
||||
(static_cast<intptr_t>(p->address->value())
|
||||
- reinterpret_cast<intptr_t>(start), mapBase, pathIndex);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
object
|
||||
makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start,
|
||||
TraceElement** elements)
|
||||
{
|
||||
unsigned mapSize = frameMapSizeInBits(t, context->method);
|
||||
object table = makeIntArray
|
||||
(t, context->traceLogCount
|
||||
+ ceiling(context->traceLogCount * mapSize, 32));
|
||||
|
||||
assert(t, intArrayLength(t, table) == context->traceLogCount
|
||||
+ simpleFrameMapTableSize(t, context->method, table));
|
||||
|
||||
for (unsigned i = 0; i < context->traceLogCount; ++i) {
|
||||
TraceElement* p = elements[i];
|
||||
|
||||
intArrayBody(t, table, i) = static_cast<intptr_t>(p->address->value())
|
||||
- reinterpret_cast<intptr_t>(start);
|
||||
|
||||
assert(t, context->traceLogCount + ceiling((i + 1) * mapSize, 32)
|
||||
<= intArrayLength(t, table));
|
||||
|
||||
copyFrameMap(&intArrayBody(t, table, context->traceLogCount), p->map,
|
||||
mapSize, i * mapSize, p, 0);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
@ -4535,9 +4819,27 @@ finish(MyThread* t, Allocator* allocator, Context* context)
|
||||
if (context->traceLogCount) {
|
||||
TraceElement* elements[context->traceLogCount];
|
||||
unsigned index = 0;
|
||||
unsigned pathFootprint = 0;
|
||||
unsigned mapCount = 0;
|
||||
for (TraceElement* p = context->traceLog; p; p = p->next) {
|
||||
assert(t, index < context->traceLogCount);
|
||||
|
||||
SubroutineTrace* trace = p->subroutineTrace;
|
||||
unsigned myMapCount = 1;
|
||||
if (trace) {
|
||||
for (SubroutinePath* sp = trace->path; sp; sp = sp->next) {
|
||||
Subroutine* subroutine = sp->call->subroutine;
|
||||
unsigned callCount = subroutine->callCount;
|
||||
myMapCount *= callCount;
|
||||
if (not subroutine->visited) {
|
||||
subroutine->visited = true;
|
||||
pathFootprint += sizeof(FrameMapTablePath)
|
||||
+ (sizeof(int32_t) * callCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
mapCount += myMapCount;
|
||||
|
||||
elements[index++] = p;
|
||||
|
||||
if (p->target) {
|
||||
@ -4550,47 +4852,12 @@ finish(MyThread* t, Allocator* allocator, Context* context)
|
||||
qsort(elements, context->traceLogCount, sizeof(TraceElement*),
|
||||
compareTraceElementPointers);
|
||||
|
||||
unsigned size = frameMapSizeInBits(t, context->method);
|
||||
object map = makeIntArray
|
||||
(t, context->traceLogCount
|
||||
+ ceiling(context->traceLogCount * size, 32));
|
||||
|
||||
assert(t, intArrayLength(t, map) == context->traceLogCount
|
||||
+ frameObjectMapSize(t, context->method, map));
|
||||
|
||||
for (unsigned i = 0; i < context->traceLogCount; ++i) {
|
||||
TraceElement* p = elements[i];
|
||||
|
||||
intArrayBody(t, map, i) = static_cast<intptr_t>(p->address->value())
|
||||
- reinterpret_cast<intptr_t>(start);
|
||||
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, " orig roots at ip %p: ", reinterpret_cast<void*>
|
||||
(p->address->value()));
|
||||
printSet(p->map[0], frameMapSizeInWords(t, context->method));
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "final roots at ip %p: ", reinterpret_cast<void*>
|
||||
(p->address->value()));
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < p->argumentIndex; ++j) {
|
||||
if (getBit(p->map, j)) {
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, "1");
|
||||
}
|
||||
setBit(t, map, context->traceLogCount, size, i, j);
|
||||
} else {
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, "_");
|
||||
}
|
||||
clearBit(t, map, context->traceLogCount, size, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
if (DebugFrameMaps) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
object map;
|
||||
if (pathFootprint) {
|
||||
map = makeGeneralFrameMapTable
|
||||
(t, context, start, elements, pathFootprint, mapCount);
|
||||
} else {
|
||||
map = makeSimpleFrameMapTable(t, context, start, elements);
|
||||
}
|
||||
|
||||
set(t, methodCode(t, context->method), CodePool, map);
|
||||
@ -5134,21 +5401,24 @@ invokeNative(MyThread* t)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
frameMapIndex(MyThread* t, object method, int32_t offset)
|
||||
void
|
||||
findFrameMapInSimpleTable(MyThread* t, object method, object table,
|
||||
int32_t offset, int32_t** map, unsigned* start)
|
||||
{
|
||||
object map = codePool(t, methodCode(t, method));
|
||||
unsigned mapSize = frameObjectMapSize(t, method, map);
|
||||
unsigned indexSize = intArrayLength(t, map) - mapSize;
|
||||
unsigned tableSize = simpleFrameMapTableSize(t, method, table);
|
||||
unsigned indexSize = intArrayLength(t, table) - tableSize;
|
||||
|
||||
*map = &intArrayBody(t, table, indexSize);
|
||||
|
||||
unsigned bottom = 0;
|
||||
unsigned top = indexSize;
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
int32_t v = intArrayBody(t, map, middle);
|
||||
int32_t v = intArrayBody(t, table, middle);
|
||||
|
||||
if (offset == v) {
|
||||
return (indexSize * 32) + (frameMapSizeInBits(t, method) * middle);
|
||||
*start = frameMapSizeInBits(t, method) * middle;
|
||||
return;
|
||||
} else if (offset < v) {
|
||||
top = middle;
|
||||
} else {
|
||||
@ -5159,6 +5429,75 @@ frameMapIndex(MyThread* t, object method, int32_t offset)
|
||||
abort(t);
|
||||
}
|
||||
|
||||
unsigned
|
||||
findFrameMap(MyThread* t, void* stack, object method, object table,
|
||||
unsigned pathIndex)
|
||||
{
|
||||
if (pathIndex) {
|
||||
FrameMapTablePath* path = reinterpret_cast<FrameMapTablePath*>
|
||||
(&byteArrayBody(t, table, pathIndex));
|
||||
|
||||
void* address = static_cast<void**>(stack)[path->stackIndex];
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(methodAddress(t, method));
|
||||
for (unsigned i = 0; i < path->elementCount; ++i) {
|
||||
if (address == base + path->elements[i]) {
|
||||
return i + (path->elementCount * findFrameMap
|
||||
(t, stack, method, table, path->next));
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
findFrameMapInGeneralTable(MyThread* t, void* stack, object method,
|
||||
object table, int32_t offset, int32_t** map,
|
||||
unsigned* start)
|
||||
{
|
||||
FrameMapTableHeader* header = reinterpret_cast<FrameMapTableHeader*>
|
||||
(&byteArrayBody(t, table, 0));
|
||||
|
||||
FrameMapTableIndexElement* index
|
||||
= reinterpret_cast<FrameMapTableIndexElement*>
|
||||
(&byteArrayBody(t, table, sizeof(FrameMapTableHeader)));
|
||||
|
||||
*map = reinterpret_cast<int32_t*>(index + header->indexCount);
|
||||
|
||||
unsigned bottom = 0;
|
||||
unsigned top = header->indexCount;
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
FrameMapTableIndexElement* v = index + middle;
|
||||
|
||||
if (offset == v->offset) {
|
||||
*start = v->base + findFrameMap(t, stack, method, table, v->path);
|
||||
} else if (offset < v->offset) {
|
||||
top = middle;
|
||||
} else {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
}
|
||||
|
||||
void
|
||||
findFrameMap(MyThread* t, void* stack, object method, int32_t offset,
|
||||
int32_t** map, unsigned* start)
|
||||
{
|
||||
object table = codePool(t, methodCode(t, method));
|
||||
if (objectClass(t, table)
|
||||
== arrayBody(t, t->m->types, Machine::IntArrayType))
|
||||
{
|
||||
findFrameMapInSimpleTable(t, method, table, offset, map, start);
|
||||
} else {
|
||||
findFrameMapInGeneralTable(t, stack, method, table, offset, map, start);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method,
|
||||
void* ip)
|
||||
@ -5166,18 +5505,17 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method,
|
||||
unsigned count = frameMapSizeInBits(t, method);
|
||||
|
||||
if (count) {
|
||||
object map = codePool(t, methodCode(t, method));
|
||||
int index = frameMapIndex
|
||||
(t, method, difference
|
||||
(ip, reinterpret_cast<void*>(methodAddress(t, method))));
|
||||
|
||||
void* stack = stackForFrame(t, frame, method);
|
||||
|
||||
int32_t* map;
|
||||
unsigned offset;
|
||||
findFrameMap
|
||||
(t, stack, method, difference
|
||||
(ip, reinterpret_cast<void*>(methodAddress(t, method))), &map, &offset);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
int j = index + i;
|
||||
if ((intArrayBody(t, map, j / 32)
|
||||
& (static_cast<int32_t>(1) << (j % 32))))
|
||||
{
|
||||
int j = offset + i;
|
||||
if (map[j / 32] & (static_cast<int32_t>(1) << (j % 32))) {
|
||||
v->visit(localObject(t, stack, method, i));
|
||||
}
|
||||
}
|
||||
@ -5288,17 +5626,16 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start)
|
||||
count -= start - first;
|
||||
}
|
||||
|
||||
object map = codePool(t, methodCode(t, method));
|
||||
int index = frameMapIndex
|
||||
(t, method, difference
|
||||
int32_t* map;
|
||||
unsigned offset;
|
||||
findFrameMap
|
||||
(t, reinterpret_cast<uintptr_t*>(c) + stack, method, difference
|
||||
(continuationAddress(t, c),
|
||||
reinterpret_cast<void*>(methodAddress(t, method))));
|
||||
reinterpret_cast<void*>(methodAddress(t, method))), &map, &offset);
|
||||
|
||||
for (int i = count - 1; i >= 0; --i) {
|
||||
int j = index + i;
|
||||
if ((intArrayBody(t, map, j / 32)
|
||||
& (static_cast<int32_t>(1) << (j % 32))))
|
||||
{
|
||||
int j = offset + i;
|
||||
if (map[j / 32] & (static_cast<int32_t>(1) << (j % 32))) {
|
||||
if (not w->visit(stack + localOffsetFromStack(t, i, method))) {
|
||||
return;
|
||||
}
|
||||
|
@ -4016,6 +4016,31 @@ appendSaveLocals(Context* c)
|
||||
SaveLocalsEvent(c));
|
||||
}
|
||||
|
||||
class CleanLocalsEvent: public Event {
|
||||
public:
|
||||
CleanLocalsEvent(Context* c):
|
||||
Event(c)
|
||||
{ }
|
||||
|
||||
virtual const char* name() {
|
||||
return "CleanLocalsEvent";
|
||||
}
|
||||
|
||||
virtual void compile(Context* c) {
|
||||
for (FrameIterator it(c, 0, c->locals); it.hasMore();) {
|
||||
FrameIterator::Element e = it.next(c);
|
||||
clean(c, e.value, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
appendCleanLocals(Context* c)
|
||||
{
|
||||
append(c, new (c->zone->allocate(sizeof(CleanLocalsEvent)))
|
||||
CleanLocalsEvent(c));
|
||||
}
|
||||
|
||||
class DummyEvent: public Event {
|
||||
public:
|
||||
DummyEvent(Context* c):
|
||||
@ -4927,6 +4952,8 @@ class MyCompiler: public Compiler {
|
||||
}
|
||||
|
||||
virtual void endSubroutine(Subroutine* subroutine) {
|
||||
saveLocals();
|
||||
|
||||
static_cast<MySubroutine*>(subroutine)->forkState = ::saveState(&c);
|
||||
}
|
||||
|
||||
@ -5038,6 +5065,13 @@ class MyCompiler: public Compiler {
|
||||
}
|
||||
|
||||
c.logicalIp = logicalIp;
|
||||
|
||||
for (unsigned li = 0; li < c.localFootprint; ++li) {
|
||||
Local* local = c.locals + li;
|
||||
if (local->value == 0) {
|
||||
initLocal(1, li);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual Promise* machineIp(unsigned logicalIp) {
|
||||
@ -5333,6 +5367,10 @@ class MyCompiler: public Compiler {
|
||||
appendSaveLocals(&c);
|
||||
}
|
||||
|
||||
virtual void cleanLocals() {
|
||||
appendCleanLocals(&c);
|
||||
}
|
||||
|
||||
virtual void checkBounds(Operand* object, unsigned lengthOffset,
|
||||
Operand* index, intptr_t handler)
|
||||
{
|
||||
|
@ -43,7 +43,6 @@ class Compiler {
|
||||
|
||||
virtual Subroutine* startSubroutine() = 0;
|
||||
virtual void endSubroutine(Subroutine* subroutine) = 0;
|
||||
virtual void restoreFromSubroutine(Subroutine* subroutine) = 0;
|
||||
|
||||
virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint,
|
||||
unsigned localFootprint, unsigned alignedFrameSize) = 0;
|
||||
@ -96,6 +95,7 @@ class Compiler {
|
||||
unsigned index) = 0;
|
||||
virtual Operand* loadLocal(unsigned footprint, unsigned index) = 0;
|
||||
virtual void saveLocals() = 0;
|
||||
virtual void cleanLocals() = 0;
|
||||
|
||||
virtual void checkBounds(Operand* object, unsigned lengthOffset,
|
||||
Operand* index, intptr_t handler) = 0;
|
||||
|
@ -110,6 +110,11 @@ class Vector {
|
||||
append(&v, BytesPerWord);
|
||||
}
|
||||
|
||||
void set2(unsigned offset, uint16_t v) {
|
||||
assert(s, offset <= position - 2);
|
||||
memcpy(data + offset, &v, 2);
|
||||
}
|
||||
|
||||
unsigned get(unsigned offset) {
|
||||
uint8_t v; get(offset, &v, 1);
|
||||
return v;
|
||||
|
@ -63,9 +63,9 @@ public class Subroutine {
|
||||
test(false, true);
|
||||
test(true, false);
|
||||
|
||||
test2(1);
|
||||
test2(2);
|
||||
test2(3);
|
||||
String.valueOf(test2(1));
|
||||
String.valueOf(test2(2));
|
||||
String.valueOf(test2(3));
|
||||
}
|
||||
|
||||
private static class DummyException extends RuntimeException { }
|
||||
|
Loading…
Reference in New Issue
Block a user