blob: 5118b14f17fd9c0d2da268863a523cde506b4e12 [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.
*/
#ifndef RUNTIME_MM_EXTRA_OBJECT_DATA_H
#define RUNTIME_MM_EXTRA_OBJECT_DATA_H
#include <atomic>
#include <cstddef>
#include <cstdint>
#include "Memory.h"
#include "TypeInfo.h"
#include "Utils.hpp"
#include "Weak.hpp"
namespace kotlin {
namespace mm {
// Optional data that's lazily allocated only for objects that need it.
class ExtraObjectData : private Pinned {
public:
// flags are stored as single atomic uint32, values are bit numbers in that uint32
enum Flags : uint32_t {
FLAGS_FROZEN = 0,
FLAGS_NEVER_FROZEN = 1,
FLAGS_IN_FINALIZER_QUEUE = 2,
FLAGS_SWEEPABLE = 3,
FLAGS_RELEASE_ON_MAIN_QUEUE = 4,
FLAGS_FINALIZED = 5,
};
static constexpr unsigned WEAK_REF_TAG = 1;
MetaObjHeader* AsMetaObjHeader() noexcept { return reinterpret_cast<MetaObjHeader*>(this); }
static ExtraObjectData& FromMetaObjHeader(MetaObjHeader* header) noexcept { return *reinterpret_cast<ExtraObjectData*>(header); }
// Get installed `ExtraObjectData` or `nullptr`.
static ExtraObjectData* Get(const ObjHeader* object) noexcept {
return reinterpret_cast<ExtraObjectData*>(object->meta_object_or_null());
}
static ExtraObjectData& GetOrInstall(ObjHeader* object) noexcept { return FromMetaObjHeader(object->meta_object()); }
static ExtraObjectData& Install(ObjHeader* object) noexcept;
void Uninstall() noexcept;
void UnlinkFromBaseObject() noexcept;
#ifdef KONAN_OBJC_INTEROP
std::atomic<void*>& AssociatedObject() noexcept { return associatedObject_; }
#endif
bool HasAssociatedObject() noexcept;
void ReleaseAssociatedObject() noexcept;
bool getFlag(Flags value) noexcept { return (flags_.load() & (1u << static_cast<uint32_t>(value))) != 0; }
void setFlag(Flags value) noexcept { flags_.fetch_or(1u << static_cast<uint32_t>(value)); }
bool HasRegularWeakReferenceImpl() noexcept { return hasPointerBits(weakReferenceOrBaseObject_.load(), WEAK_REF_TAG); }
void ClearRegularWeakReferenceImpl() noexcept; // TODO: Only exists for the sake of GetBaseObject. Refactor to remove the need for it.
ObjHeader* GetRegularWeakReferenceImpl() noexcept {
auto* pointer = weakReferenceOrBaseObject_.load();
if (hasPointerBits(pointer, WEAK_REF_TAG)) return clearPointerBits(pointer, WEAK_REF_TAG);
return nullptr;
}
ObjHeader* GetOrSetRegularWeakReferenceImpl(ObjHeader* object, ObjHeader* weakRef) noexcept {
if (weakReferenceOrBaseObject_.compare_exchange_strong(object, setPointerBits(weakRef, WEAK_REF_TAG))) {
return weakRef;
} else {
return clearPointerBits(object, WEAK_REF_TAG); // on fail current value of weakRef is stored to object
}
}
ObjHeader* GetBaseObject() noexcept {
auto* header = weakReferenceOrBaseObject_.load();
if (hasPointerBits(header, WEAK_REF_TAG)) {
return regularWeakReferenceImplBaseObjectUnsafe(clearPointerBits(header, WEAK_REF_TAG));
} else {
return header;
}
}
// info must be equal to objHeader->type_info(), but it needs to be loaded in advance to avoid data races
explicit ExtraObjectData(ObjHeader* objHeader, const TypeInfo* info) noexcept :
typeInfo_(nullptr), weakReferenceOrBaseObject_(objHeader) {
atomicSetRelease(&typeInfo_, info);
}
~ExtraObjectData();
private:
// Must be first to match `TypeInfo` layout.
const TypeInfo* typeInfo_;
std::atomic<uint32_t> flags_ = 0;
#ifdef KONAN_OBJC_INTEROP
std::atomic<void*> associatedObject_ = nullptr;
#endif
std::atomic<ObjHeader*> weakReferenceOrBaseObject_;
};
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_EXTRA_OBJECT_DATA_H