void MarkObject(StorageBase &Q, bool M) { if (M == Q.IsMarked()) return; Q.SetMarked(M); Q.GetClass()->SetMarked(Q, M); }
void MarkObjectAndChildren(StorageBase &Q, bool M) { MarkObject(Q, M); Dictionary::const_iterator A = Q.GetDictionary().begin(), B = Q.GetDictionary().end(); for (; A != B; ++A) { Object &child = const_cast<Object &>(A->second); if (child.GetHandle() == Q.GetHandle()) // HACK to sorta/kinda avoid cycles :/ continue; MarkObjectAndChildren(child, M); } }
void StorageBase::RemovedFromContainer(Object const &container) { ObjectColor::Color color = ObjectColor::White; StorageBase *parent = GetRegistry()->GetStorageBase(GetParentHandle()); bool parent_is_black = parent && parent->IsBlack(); if (parent_is_black) color = ObjectColor::Grey; bool removed = false; auto iter = containers.begin(), end = containers.end(); for (; iter != end; ) { StorageBase *base = GetRegistry()->GetStorageBase(*iter); if (!base) { iter = containers.erase(iter); continue; } if (!removed && *iter == container.GetHandle()) { iter = containers.erase(iter); removed = true; if (parent_is_black) { // if removed from container and parent is black early out break; } else { // we need to check for other black parents to enforce the TriColor invariant continue; } } if (base->IsBlack()) { color = ObjectColor::Grey; parent_is_black = true; // if any parent container is black, and we have already removed from the // given container, we can early out if (removed) break; } ++iter; } SetColorRecursive(color); }
void StorageBase::MakeReachableGrey() { Dictionary::const_iterator child = dictionary.begin(), end = dictionary.end(); for (; child != end; ++child) { StorageBase *sub = GetRegistry()->GetStorageBase(child->second.GetHandle()); if (!sub) continue; if (sub->IsWhite()) sub->SetColor(ObjectColor::Grey); } GetClass()->MakeReachableGrey(*this); }
void StorageBase::DetachFromContainers() { if (containers.empty()) return; Containers tmp = containers; Containers::const_iterator iter = tmp.begin(), end = tmp.end(); for (; iter != end; ++iter) { StorageBase *cont = GetRegistry()->GetStorageBase(*iter); if (!cont) continue; cont->GetClass()->DetachFromContainer(*cont, *this); } }
void StorageBase::Remove(const Label &label) { Dictionary::iterator iter = dictionary.find(label); if (iter == dictionary.end()) return; SetDirty(); StorageBase *child = iter->second.GetBasePtr(); dictionary.erase(iter); if (child) { child->SetParentHandle(Handle()); child->RemovedFromContainer(*this); } }
void Registry::TriColor() { // this is a magic number. the higher it is, the more objects may be deleted in this call // the cost has to be paid at some point, so this number really means "how much do I want // to spread out cost of GC over time versus memory use". // // if you have lots of memory, set max_cycles to 1. (or zero!). if not, set it higher // until you can fit memory usage into a sequence of frames. // // see also https://github.com/cschladetsch/Monotonic const int max_cycles = 17; if (gc_trace_level >= 1) { KAI_TRACE_3(instances.size(), grey.size(), white.size()); } int cycle = 0; for (; cycle < max_cycles; ++cycle) { #ifdef KAI_DEBUG_REGISTRY if (gc_trace_level > 2) TraceTriColor(); #endif if (grey.empty()) { ReleaseWhite(); break; } ColoredSet::iterator iter = grey.begin(); Handle handle = *iter; grey.erase(iter); StorageBase *base = GetStorageBase(handle); if (base == 0) continue; base->MakeReachableGrey(); base->SetColor(ObjectColor::Black); } if (gc_trace_level >= 1) KAI_TRACE() << "TriColor: " << cycle << " passes"; }
void StorageBase::Delete() { // avoid double deletion if (IsMarked()) return; SetManaged(true); // remove from all containers DetachFromContainers(); // remove from parent StorageBase *parent = GetParentBasePtr(); if (parent != 0) parent->Remove(GetLabel()); // set this and all referent objects to be white, and mark it for deletion. SetColorRecursive(ObjectColor::White); SetMarked(true); }
bool StorageBase::SetColor(ObjectColor::Color color) { auto reg = GetRegistry(); if (!reg->SetColor(*this, color)) return false; this->color = color; if (color == ObjectColor::White) { Containers::const_iterator container = containers.begin(), end = containers.end(); for (; container != end; ++container) { StorageBase *cont = GetRegistry()->GetStorageBase(*container); if (cont && cont->IsBlack()) cont->SetColor(ObjectColor::Grey); } } return true; }
void Registry::MarkAll(StorageBase &root, bool marked) { MarkObject(root, marked); const Dictionary &dict = root.GetDictionary(); Dictionary::const_iterator C = dict.begin(), D = dict.end(); for (; C != D; ++C) { Object const &child = C->second; StorageBase *base = GetStorageBase(child.GetHandle()); if (base == 0) continue; if (base->IsManaged()) MarkObject(*base, marked); if (base->GetSwitches() & IObject::NoRecurse) continue; MarkAll(*base, marked); } }
Object Registry::NewFromClass(const ClassBase *klass) { if (klass == 0) KAI_THROW_1(UnknownClass<>, "NULL Class"); Handle handle = next_handle.NextValue(); StorageBase *base = 0; base = klass->NewStorage(this, handle); #ifdef KAI_DEBUG_REGISTRY if (IsWatchingType(klass->GetTypeNumber())) KAI_TRACE() << klass->GetName() << ": " << handle; #endif base->SetColor(ObjectColor::White); base->SetMarked(false); instances[handle] = base; klass->Create(*base); return Object(ObjectConstructParams(this, klass, handle)); }
Pathname GetFullname(const StorageBase &Q) { nstd::list<String> parentage; Label const &label = Q.GetLabel(); if (!label.ToString().empty()) parentage.push_back(label.ToString()); Object parent = Q.GetParent(); for (; parent.Valid(); parent = parent.GetParent()) parentage.push_front(GetStorageBase(parent).GetLabel().ToString()); StringStream path; if (!parentage.empty()) ;//path << "[anon]"; else path.Append('/'); foreach (String const &name, parentage) { path.Append(name); path.Append('/'); }
void Registry::Sweep() { if (instances.empty()) return; Instances::iterator A = instances.begin(), B = instances.end(); // the handle of the next object created Handle last = next_handle.GetValue(); for (; A != B; ++A) { StorageBase *base = A->second; // do not consider objects that were created during this loop! if (last < base->GetHandle()) continue; if (!base->IsManaged()) continue; if (!base->IsMarked()) Delete(A->first); else base->SetMarked(false); } }
// avoid loops by passing history of objects traversed via handles argument void StorageBase::SetColorRecursive(ObjectColor::Color color, HandleSet& handles) { Handle handle = GetHandle(); if (handles.find(handle) != handles.end()) return; handles.insert(handle); if (!SetColor(color)) return; GetClass()->SetReferencedObjectsColor(*this, color, handles); if (dictionary.empty()) return; for (Dictionary::value_type const &child : dictionary) { StorageBase *sub = GetRegistry()->GetStorageBase(child.second.GetHandle()); if (!sub) continue; sub->SetColorRecursive(color, handles); } }