diff --git a/src/compile.cpp b/src/compile.cpp index d996a5c95f..95549702e0 100644 --- a/src/compile.cpp +++ b/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(-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(1) << (index % 32); + dst[index / 32] |= static_cast(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(1) << (index % 32)); + dst[index / 32] &= ~(static_cast(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 + (p->address->value())); + printSet(src[0], ceiling(mapSizeInBits, BitsPerWord)); + print(subroutinePath); + fprintf(stderr, "\n"); + + fprintf(stderr, "final roots at ip %p: ", reinterpret_cast + (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(c->returnAddress->value()) + - reinterpret_cast(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(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(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(p->address->value()) + - reinterpret_cast(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(p->address->value()) + - reinterpret_cast(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(p->address->value()) - - reinterpret_cast(start); - - if (DebugFrameMaps) { - fprintf(stderr, " orig roots at ip %p: ", reinterpret_cast - (p->address->value())); - printSet(p->map[0], frameMapSizeInWords(t, context->method)); - fprintf(stderr, "\n"); - - fprintf(stderr, "final roots at ip %p: ", reinterpret_cast - (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 + (&byteArrayBody(t, table, pathIndex)); + + void* address = static_cast(stack)[path->stackIndex]; + uint8_t* base = reinterpret_cast(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 + (&byteArrayBody(t, table, 0)); + + FrameMapTableIndexElement* index + = reinterpret_cast + (&byteArrayBody(t, table, sizeof(FrameMapTableHeader))); + + *map = reinterpret_cast(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(methodAddress(t, method)))); - void* stack = stackForFrame(t, frame, method); + int32_t* map; + unsigned offset; + findFrameMap + (t, stack, method, difference + (ip, reinterpret_cast(methodAddress(t, method))), &map, &offset); + for (unsigned i = 0; i < count; ++i) { - int j = index + i; - if ((intArrayBody(t, map, j / 32) - & (static_cast(1) << (j % 32)))) - { + int j = offset + i; + if (map[j / 32] & (static_cast(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(c) + stack, method, difference (continuationAddress(t, c), - reinterpret_cast(methodAddress(t, method)))); + reinterpret_cast(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(1) << (j % 32)))) - { + int j = offset + i; + if (map[j / 32] & (static_cast(1) << (j % 32))) { if (not w->visit(stack + localOffsetFromStack(t, i, method))) { return; } diff --git a/src/compiler.cpp b/src/compiler.cpp index 1b9b95ca44..a88a94828c 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -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(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) { diff --git a/src/compiler.h b/src/compiler.h index 9e28d57b5a..1a42888e8d 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -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; diff --git a/src/vector.h b/src/vector.h index 78a6059eb0..744ebdff45 100644 --- a/src/vector.h +++ b/src/vector.h @@ -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; diff --git a/test/Subroutine.java b/test/Subroutine.java index a976c53dfd..0e312f5ec6 100644 --- a/test/Subroutine.java +++ b/test/Subroutine.java @@ -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 { }