Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
olonho committed Mar 31, 2019
1 parent 17f1da8 commit d28e986
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 66 deletions.
136 changes: 72 additions & 64 deletions runtime/src/main/cpp/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,13 +653,14 @@ inline void DecrementRC(ContainerHeader* container) {
if (container->decRefCount<Atomic>() == 0) {
FreeContainer(container);
} else if (UseCycleCollector) { // Possible root.
RuntimeAssert(!Atomic, "Cycle collector shalln't be used with shared objects yet");
RuntimeAssert(!Atomic && !container->shareable(), "Cycle collector shalln't be used with shared objects yet");
RuntimeAssert(container->objectCount() == 1, "cycle collector shall only work with single object containers");
// We do not use cycle collector for frozen objects, as we already detected
// possible cycles during freezing.
// Also do not use cycle collector for provable acyclic objects.
int color = container->color();
if (color != CONTAINER_TAG_GC_PURPLE && color != CONTAINER_TAG_GC_GREEN) {
RuntimeAssert(!container->shareable(), "Shareable cannot be cycle collected");
container->setColorAssertIfGreen(CONTAINER_TAG_GC_PURPLE);
if (!container->buffered()) {
container->setBuffered();
Expand Down Expand Up @@ -1668,9 +1669,10 @@ void incrementStack(MemoryState* state) {
}
}

void incrementNewlyFrozenOnStack(MemoryState* state, const ContainerHeaderSet* newlyFrozen) {
void actualizeNewlyFrozenOnStack(MemoryState* state, const ContainerHeaderSet* newlyFrozen) {
// For all frozen objects in stack slots - perform reference increment.
FrameOverlay* frame = state->currentFrame;
MEMORY_LOG("incrementNewlyFrozenOnStack: newly frozen size is %d\n", newlyFrozen->size())
MEMORY_LOG("actualizeNewlyFrozenOnStack: newly frozen size is %d\n", newlyFrozen->size())
while (frame != nullptr) {
MEMORY_LOG("current frame %p: %d parameters %d locals\n", frame, frame->parameters, frame->count)
ObjHeader** current = reinterpret_cast<ObjHeader**>(frame + 1) + frame->parameters;
Expand All @@ -1681,15 +1683,23 @@ void incrementNewlyFrozenOnStack(MemoryState* state, const ContainerHeaderSet* n
if (obj != nullptr) {
auto* container = obj->container();
// No need to use atomic increment yet, object is still local.
if (container != nullptr &&
container->tag() == CONTAINER_TAG_FROZEN &&
newlyFrozen->count(container) != 0) {
if (container != nullptr && container->frozen() && newlyFrozen->count(container) != 0) {
IncrementRC<false>(container);
}
}
}
frame = frame->previous;
}

// And actualize RC of those objects using toRelease set.
for (auto& container : *(state->toRelease)) {
if (!isMarkedAsRemoved(container) && container->frozen()) {
RuntimeAssert(newlyFrozen->count(container) != 0, "Must be newly frozen");
auto oldRc = container->decRefCount<false>();
MEMORY_LOG("decremented rc of %p to %d\n", container, oldRc);
container = markAsRemoved(container);
}
}
}

void processDecrements(MemoryState* state) {
Expand Down Expand Up @@ -1859,7 +1869,8 @@ OBJ_GETTER(AdoptStablePointer, KNativePtr pointer) {
MEMORY_LOG("adopting stable pointer %p, rc=%d\n", ref, (ref->container() != nullptr) ? ref->container()->refCount() : -1)
auto* container = ref->container();
*getReturnSlot(OBJ_RESULT) = ref;
// We just adopted an object, if it is adopted on the stack, we need to schedule RC decrement.
// We just adopted an object, if it is adopted on the stack, we need to schedule RC decrement,
// as for this worker it looks like if it was
if (container != nullptr && container->tag() == CONTAINER_TAG_NORMAL && !isHeapReturnSlot(OBJ_RESULT))
EnqueueDecrementRC</* CanCollect = */true>(container);
}
Expand All @@ -1885,71 +1896,66 @@ bool hasExternalRefs(ContainerHeader* start, ContainerHeaderSet* visited) {
}
return false;
}
#endif
#endif // USE_GC

bool ClearSubgraphReferences(ObjHeader* root, bool checked) {
#if USE_GC
if (root != nullptr) {
auto state = memoryState;
auto* container = root->container();

if (container == nullptr || container->frozen())
// We assume, that frozen objects can be safely passed and are already removed
// from the GC candidate list.
return true;

// Now compute how much time we shall decrement RC for reachibility analysis.
// Initial 1 is for holder holding the object.
int rcDecrement = 1;
if (root == nullptr) return true;
auto state = memoryState;
auto* container = root->container();

if (Shareable(container))
// We assume, that frozen/shareable objects can be safely passed and not present
// in the GC candidate list.
// TODO: assert for that?
return true;

ContainerHeaderSet visited;
if (!checked) {
hasExternalRefs(container, &visited);
} else {
// Now decrement RC of elements in toRelease set for reachibility analysis.
for (auto it = state->toRelease->begin(); it != state->toRelease->end(); ++it) {
auto released = *it;
// Actually first check is excessive, just for clarity of intentions.
if (!isMarkedAsRemoved(released) && container == released) {
rcDecrement++;
*it = markAsRemoved(released);
if (!isMarkedAsRemoved(released) && released->tag() == CONTAINER_TAG_NORMAL) {
released->decRefCount<false>();
}
}

ContainerHeaderSet visited;
if (!checked) {
hasExternalRefs(container, &visited);
} else {
if (!Shareable(container)) {
for (int i = 0; i < rcDecrement; i++)
container->decRefCount<false>();
MarkGray<false>(container);
auto bad = hasExternalRefs(container, &visited);
ScanBlack<false>(container);
if (bad) {
// Restore original RC if the check failed.
for (int i = 0; i < rcDecrement; i++) container->incRefCount<false>();
return false;
}
container->incRefCount<false>();
}
container->decRefCount<false>();
MarkGray<false>(container);
auto bad = hasExternalRefs(container, &visited);
ScanBlack<false>(container);
// Restore original RC.
container->incRefCount<false>();
for (auto it = state->toRelease->begin(); it != state->toRelease->end(); ++it) {
auto released = *it;
if (!isMarkedAsRemoved(released) && released->tag() == CONTAINER_TAG_NORMAL) {
released->incRefCount<false>();
}
}
if (bad) {
return false;
}
}

// Remove all no longer owned containers from GC structures.
state->gcSuspendCount++;
// TODO: not very efficient traversal.
for (auto it = state->toFree->begin(); it != state->toFree->end(); ++it) {
auto container = *it;
if (visited.count(container) != 0) {
MEMORY_LOG("removing %p from the toFree list", container)
container->resetBuffered();
container->setColorAssertIfGreen(CONTAINER_TAG_GC_BLACK);
*it = markAsRemoved(container);
}
// Remove all no longer owned containers from GC structures.
// TODO: not very efficient traversal.
for (auto it = state->toFree->begin(); it != state->toFree->end(); ++it) {
auto container = *it;
if (visited.count(container) != 0) {
MEMORY_LOG("removing %p from the toFree list", container)
container->resetBuffered();
container->setColorAssertIfGreen(CONTAINER_TAG_GC_BLACK);
*it = markAsRemoved(container);
}
for (auto it = state->toRelease->begin(); it != state->toRelease->end(); ++it) {
auto container = *it;
if (!isMarkedAsRemoved(container) && visited.count(container) != 0) {
MEMORY_LOG("removing %p from the toRelease list", container)
DecrementRC(container);
*it = markAsRemoved(container);
}
}
for (auto it = state->toRelease->begin(); it != state->toRelease->end(); ++it) {
auto container = *it;
if (!isMarkedAsRemoved(container) && visited.count(container) != 0) {
MEMORY_LOG("removing %p from the toRelease list", container)
container->decRefCount<false>();
*it = markAsRemoved(container);
}
state->gcSuspendCount--;
}
#endif // USE_GC
return true;
Expand Down Expand Up @@ -2174,11 +2180,13 @@ void FreezeSubgraph(ObjHeader* root) {
// and use it when analyzing toFree during collection.
auto state = memoryState;
for (auto& container : *(state->toFree)) {
if (!isMarkedAsRemoved(container) && container->frozen())
container = markAsRemoved(container);
if (!isMarkedAsRemoved(container) && container->frozen()) {
RuntimeAssert(newlyFrozen.count(container) != 0, "Must be newly frozen");
container = markAsRemoved(container);
}
}
// Actualize reference counters of newly frozen objects.
incrementNewlyFrozenOnStack(memoryState, &newlyFrozen);
actualizeNewlyFrozenOnStack(memoryState, &newlyFrozen);
#endif
}

Expand Down
4 changes: 2 additions & 2 deletions runtime/src/main/cpp/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ struct ContainerHeader {
return (refCount_ & CONTAINER_TAG_MASK) == CONTAINER_TAG_STACK;
}

inline unsigned refCount() const {
return refCount_ >> CONTAINER_TAG_SHIFT;
inline int refCount() const {
return (int)refCount_ >> CONTAINER_TAG_SHIFT;
}

inline void setRefCount(unsigned refCount) {
Expand Down

0 comments on commit d28e986

Please sign in to comment.