blob: a815426e63cb314094f9afbb8648f1136960be82 [file]
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Freezing.hpp"
#include "ExtraObjectData.hpp"
#include "FreezeHooks.hpp"
#include "Memory.h"
#include "Natives.h"
#include "ObjectTraversal.hpp"
#include "Types.h"
#include "std_support/UnorderedSet.hpp"
#include "std_support/Vector.hpp"
using namespace kotlin;
bool mm::IsFrozen(const ObjHeader* object) noexcept {
if (!compiler::freezingChecksEnabled()) return false;
if (object->permanent()) {
return true;
}
if (auto* extraObjectData = mm::ExtraObjectData::Get(object)) {
return extraObjectData->getFlag(mm::ExtraObjectData::FLAGS_FROZEN);
}
return false;
}
ObjHeader* mm::FreezeSubgraph(ObjHeader* root) noexcept {
if (IsFrozen(root)) return nullptr;
std_support::vector<ObjHeader*> objects;
std_support::vector<ObjHeader*> stack;
// TODO: This may be a suboptimal container for the job.
std_support::unordered_set<ObjHeader*> visited;
stack.push_back(root);
while (!stack.empty()) {
ObjHeader* object = stack.back();
stack.pop_back();
auto visitedResult = visited.insert(object);
if (!visitedResult.second) continue;
objects.push_back(object);
RunFreezeHooks(object);
traverseReferredObjects(object, [&stack](ObjHeader* field) noexcept {
if (!IsFrozen(field)) {
stack.push_back(field);
}
});
}
for (auto* object : objects) {
if (auto* extraObjectData = mm::ExtraObjectData::Get(object)) {
if (extraObjectData->getFlag(mm::ExtraObjectData::FLAGS_NEVER_FROZEN)) {
return object;
}
}
}
for (auto* object : objects) {
mm::ExtraObjectData::GetOrInstall(object).setFlag(mm::ExtraObjectData::FLAGS_FROZEN);
}
return nullptr;
}
bool mm::EnsureNeverFrozen(ObjHeader* object) noexcept {
if (IsFrozen(object)) {
return false;
}
mm::ExtraObjectData::GetOrInstall(object).setFlag(mm::ExtraObjectData::FLAGS_NEVER_FROZEN);
return true;
}