blob: 89b829d91669055a14dc6ec0a547e777067b7981 [file]
/*
* Copyright 2010-2020 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 "ExtraObjectData.hpp"
#include "MainQueueProcessor.hpp"
#include "PointerBits.h"
#include "ThreadData.hpp"
#ifdef KONAN_OBJC_INTEROP
#include "ObjCMMAPI.h"
#endif
#ifdef CUSTOM_ALLOCATOR
#include "CustomAllocator.hpp"
#endif
using namespace kotlin;
// static
mm::ExtraObjectData& mm::ExtraObjectData::Install(ObjHeader* object) noexcept {
// TODO: Consider extracting initialization scheme with speculative load.
// `object->typeInfoOrMeta_` is assigned at most once. If we read some old value (i.e. not a meta object),
// we will fail at CAS below. If we read the new value, we will immediately return it.
TypeInfo* typeInfo = object->typeInfoOrMetaAcquire();
if (auto* metaObject = ObjHeader::AsMetaObject(typeInfo)) {
return mm::ExtraObjectData::FromMetaObjHeader(metaObject);
}
RuntimeCheck(!hasPointerBits(typeInfo, OBJECT_TAG_MASK), "Object must not be tagged");
auto *threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
#ifdef CUSTOM_ALLOCATOR
auto& data = threadData->gc().Allocator().CreateExtraObjectDataForObject(object, typeInfo);
if (!compareExchange(object->typeInfoOrMeta_, typeInfo, reinterpret_cast<TypeInfo*>(&data))) {
// Somebody else created `mm::ExtraObjectData` for this object.
data.setFlag(mm::ExtraObjectData::FLAGS_SWEEPABLE);
#else
auto& data = mm::ExtraObjectDataFactory::Instance().CreateExtraObjectDataForObject(threadData, object, typeInfo);
if (!compareExchange(object->typeInfoOrMeta_, typeInfo, reinterpret_cast<TypeInfo*>(&data))) {
// Somebody else created `mm::ExtraObjectData` for this object
mm::ExtraObjectDataFactory::Instance().DestroyExtraObjectData(threadData, data);
#endif
return *reinterpret_cast<mm::ExtraObjectData*>(typeInfo);
}
return data;
}
void mm::ExtraObjectData::UnlinkFromBaseObject() noexcept {
auto *object = GetBaseObject();
atomicSetRelease(const_cast<const TypeInfo**>(&object->typeInfoOrMeta_), typeInfo_);
RuntimeAssert(
!object->has_meta_object(), "Object %p has metaobject %p after removing metaobject %p", object, object->meta_object_or_null(),
this);
}
void mm::ExtraObjectData::ReleaseAssociatedObject() noexcept {
#ifdef KONAN_OBJC_INTEROP
if (void* associatedObject = associatedObject_) {
if (getFlag(FLAGS_RELEASE_ON_MAIN_QUEUE) && isMainQueueProcessorAvailable()) {
runOnMainQueue(associatedObject, [](void* obj) {
Kotlin_ObjCExport_releaseAssociatedObject(obj);
});
} else {
Kotlin_ObjCExport_releaseAssociatedObject(associatedObject);
}
associatedObject_ = nullptr;
}
#endif
}
void mm::ExtraObjectData::Uninstall() noexcept {
UnlinkFromBaseObject();
ReleaseAssociatedObject();
}
bool mm::ExtraObjectData::HasAssociatedObject() noexcept {
#ifdef KONAN_OBJC_INTEROP
return associatedObject_ != nullptr;
#else
return false;
#endif
}
void mm::ExtraObjectData::ClearRegularWeakReferenceImpl() noexcept {
auto *object = GetBaseObject();
// Not using `mm::SetHeapRef here`, because this code is called during sweep phase by the GC thread,
// and so cannot affect marking.
// TODO: Asserts on the above?
weakReferenceOrBaseObject_ = object;
}
mm::ExtraObjectData::~ExtraObjectData() {
auto* weakReference = weakReferenceOrBaseObject_.load(std::memory_order_relaxed);
if (hasPointerBits(weakReference, WEAK_REF_TAG)) {
weakReference = clearPointerBits(weakReference, WEAK_REF_TAG);
} else {
weakReference = nullptr;
}
RuntimeAssert(weakReference == nullptr, "ExtraObjectData %p must have cleared weak reference %p", this, weakReference);
#ifdef KONAN_OBJC_INTEROP
auto* associatedObject = associatedObject_.load(std::memory_order_relaxed);
RuntimeAssert(associatedObject == nullptr, "ExtraObjectData %p must have cleared associated object %p", this, associatedObject);
#endif
}