[K/N] Split Weak and MemorySharedRefs between mm implementations ^KT-56233
* A separate RegularWeakReferenceImpl for the new mm. Name is chosen for better consistency with other WeakReferenceImpl implementations. * KRefSharedHolder and BackRefFromAssociatedObject implementations are independent between the legacy and the new mm. * Better support for WeakReference in runtime unit tests.
This commit is contained in:
committed by
Space Team
parent
87da670319
commit
1f1b26f2a5
@@ -149,10 +149,17 @@ ALWAYS_INLINE inline bool isNullOrMarker(const ObjHeader* obj) noexcept {
|
||||
return reinterpret_cast<uintptr_t>(obj) <= 1;
|
||||
}
|
||||
|
||||
class ForeignRefManager;
|
||||
struct FrameOverlay;
|
||||
|
||||
// Legacy MM only:
|
||||
class ForeignRefManager;
|
||||
typedef ForeignRefManager* ForeignRefContext;
|
||||
|
||||
namespace kotlin::mm {
|
||||
// New MM only:
|
||||
struct RawSpecialRef;
|
||||
} // namespace kotlin::mm
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -337,24 +344,6 @@ bool Kotlin_Any_isShareable(ObjHeader* thiz);
|
||||
void Kotlin_Any_share(ObjHeader* thiz);
|
||||
void PerformFullGC(MemoryState* memory) RUNTIME_NOTHROW;
|
||||
|
||||
// Only for legacy
|
||||
bool TryAddHeapRef(const ObjHeader* object);
|
||||
void ReleaseHeapRefNoCollect(const ObjHeader* object) RUNTIME_NOTHROW;
|
||||
|
||||
// Only for experimental
|
||||
OBJ_GETTER(TryRef, ObjHeader* object) RUNTIME_NOTHROW;
|
||||
|
||||
ForeignRefContext InitLocalForeignRef(ObjHeader* object);
|
||||
|
||||
ForeignRefContext InitForeignRef(ObjHeader* object);
|
||||
void DeinitForeignRef(ObjHeader* object, ForeignRefContext context);
|
||||
|
||||
bool IsForeignRefAccessible(ObjHeader* object, ForeignRefContext context);
|
||||
|
||||
// Should be used when reference is read from a possibly shared variable,
|
||||
// and there's nothing else keeping the object alive.
|
||||
void AdoptReferenceFromSharedVariable(ObjHeader* object);
|
||||
|
||||
void CheckGlobalsAccessible();
|
||||
|
||||
// Sets state of the current thread to NATIVE (used by the new MM).
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "MemorySharedRefs.hpp"
|
||||
#include "Runtime.h"
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -13,217 +12,11 @@ extern "C" {
|
||||
OBJ_GETTER(DescribeObjectForDebugging, KConstNativePtr typeInfo, KConstNativePtr address);
|
||||
} // extern "C"
|
||||
|
||||
namespace {
|
||||
|
||||
inline bool isForeignRefAccessible(ObjHeader* object, ForeignRefContext context) {
|
||||
// If runtime has not been initialized on this thread, then the object is either unowned or shared.
|
||||
// In the former case initialized runtime is required to throw exceptions
|
||||
// in the latter case -- to provide proper execution context for caller.
|
||||
// TODO: this probably can't be called in uninitialized state in the new MM.
|
||||
Kotlin_initRuntimeIfNeeded();
|
||||
|
||||
return IsForeignRefAccessible(object, context);
|
||||
}
|
||||
|
||||
RUNTIME_NORETURN inline void throwIllegalSharingException(ObjHeader* object) {
|
||||
// TODO: add some info about the context.
|
||||
// Note: retrieving 'type_info()' is supposed to be correct even for unowned object.
|
||||
ThrowIllegalObjectSharingException(object->type_info(), object);
|
||||
}
|
||||
|
||||
RUNTIME_NORETURN inline void terminateWithIllegalSharingException(ObjHeader* object) {
|
||||
#if KONAN_NO_EXCEPTIONS
|
||||
// This will terminate.
|
||||
throwIllegalSharingException(object);
|
||||
#else
|
||||
try {
|
||||
throwIllegalSharingException(object);
|
||||
} catch (...) {
|
||||
// A trick to terminate with unhandled exception. This will print a stack trace
|
||||
// and write to iOS crash log.
|
||||
std::terminate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
bool ensureRefAccessible(ObjHeader* object, ForeignRefContext context) {
|
||||
static_assert(errorPolicy != ErrorPolicy::kIgnore, "Must've been handled by specialization");
|
||||
|
||||
if (isForeignRefAccessible(object, context)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (errorPolicy) {
|
||||
case ErrorPolicy::kDefaultValue:
|
||||
return false;
|
||||
case ErrorPolicy::kThrow:
|
||||
throwIllegalSharingException(object);
|
||||
case ErrorPolicy::kTerminate:
|
||||
terminateWithIllegalSharingException(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ensureRefAccessible<ErrorPolicy::kIgnore>(ObjHeader* object, ForeignRefContext context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void KRefSharedHolder::initLocal(ObjHeader* obj) {
|
||||
RuntimeAssert(obj != nullptr, "must not be null");
|
||||
context_ = InitLocalForeignRef(obj);
|
||||
obj_ = obj;
|
||||
}
|
||||
|
||||
void KRefSharedHolder::init(ObjHeader* obj) {
|
||||
RuntimeAssert(obj != nullptr, "must not be null");
|
||||
context_ = InitForeignRef(obj);
|
||||
obj_ = obj;
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
ObjHeader* KRefSharedHolder::ref() const {
|
||||
kotlin::AssertThreadState(kotlin::ThreadState::kRunnable);
|
||||
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AdoptReferenceFromSharedVariable(obj_);
|
||||
return obj_;
|
||||
}
|
||||
|
||||
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kDefaultValue>() const;
|
||||
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kThrow>() const;
|
||||
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kTerminate>() const;
|
||||
|
||||
void KRefSharedHolder::dispose() const {
|
||||
if (obj_ == nullptr) {
|
||||
// To handle the case when it is not initialized. See [KotlinMutableSet/Dictionary dealloc].
|
||||
return;
|
||||
}
|
||||
|
||||
DeinitForeignRef(obj_, context_);
|
||||
}
|
||||
|
||||
OBJ_GETTER0(KRefSharedHolder::describe) const {
|
||||
// Note: retrieving 'type_info()' is supposed to be correct even for unowned object.
|
||||
RETURN_RESULT_OF(DescribeObjectForDebugging, obj_->type_info(), obj_);
|
||||
}
|
||||
|
||||
void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) {
|
||||
RuntimeAssert(obj != nullptr, "must not be null");
|
||||
obj_ = obj;
|
||||
|
||||
// Generally a specialized addRef below:
|
||||
context_ = InitForeignRef(obj);
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
void BackRefFromAssociatedObject::addRef() {
|
||||
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
|
||||
|
||||
// Can be called both from Native state (if ObjC or Swift code adds RC)
|
||||
// and from Runnable state (Kotlin_ObjCExport_refToObjC).
|
||||
|
||||
if (atomicAdd(&refCount, 1) == 1) {
|
||||
if (obj_ == nullptr) return; // E.g. after [detach].
|
||||
|
||||
kotlin::CalledFromNativeGuard guard(/* reentrant */ true);
|
||||
|
||||
// There are no references to the associated object itself, so Kotlin object is being passed from Kotlin,
|
||||
// and it is owned therefore.
|
||||
ensureRefAccessible<errorPolicy>(obj_, context_); // TODO: consider removing explicit verification.
|
||||
|
||||
// Foreign reference has already been deinitialized (see [releaseRef]).
|
||||
// Create a new one:
|
||||
context_ = InitForeignRef(obj_);
|
||||
}
|
||||
}
|
||||
|
||||
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kThrow>();
|
||||
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kTerminate>();
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
bool BackRefFromAssociatedObject::tryAddRef() {
|
||||
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
|
||||
kotlin::CalledFromNativeGuard guard;
|
||||
|
||||
if (obj_ == nullptr) return false; // E.g. after [detach].
|
||||
|
||||
if (CurrentMemoryModel == MemoryModel::kExperimental) {
|
||||
ObjHolder holder;
|
||||
ObjHeader* obj = TryRef(obj_, holder.slot());
|
||||
// Failed to lock weak reference.
|
||||
if (obj == nullptr) return false;
|
||||
RuntimeAssert(obj == obj_, "Mismatched locked weak. obj=%p obj_=%p", obj, obj_);
|
||||
// TODO: This is a very weird way to ask for "unsafe" addRef.
|
||||
addRef<ErrorPolicy::kIgnore>();
|
||||
return true;
|
||||
} else {
|
||||
// Suboptimal but simple:
|
||||
ensureRefAccessible<errorPolicy>(obj_, context_);
|
||||
|
||||
ObjHeader* obj = obj_;
|
||||
|
||||
if (!TryAddHeapRef(obj)) return false;
|
||||
RuntimeAssert(isForeignRefAccessible(obj_, context_), "Cannot be inaccessible because of the check above");
|
||||
// TODO: This is a very weird way to ask for "unsafe" addRef.
|
||||
addRef<ErrorPolicy::kIgnore>();
|
||||
ReleaseHeapRefNoCollect(obj); // Balance TryAddHeapRef.
|
||||
// TODO: consider optimizing for non-shared objects.
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kThrow>();
|
||||
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kTerminate>();
|
||||
|
||||
void BackRefFromAssociatedObject::releaseRef() {
|
||||
ForeignRefContext context = context_;
|
||||
if (atomicAdd(&refCount, -1) == 0) {
|
||||
if (obj_ == nullptr) return; // E.g. after [detach].
|
||||
|
||||
kotlin::CalledFromNativeGuard guard;
|
||||
|
||||
// Note: by this moment "subsequent" addRef may have already happened and patched context_.
|
||||
// So use the value loaded before refCount update:
|
||||
DeinitForeignRef(obj_, context);
|
||||
// From this moment [context] is generally a dangling pointer.
|
||||
// This is handled in [IsForeignRefAccessible] and [addRef].
|
||||
// TODO: This probably isn't fine in new MM. Make sure it works.
|
||||
}
|
||||
}
|
||||
|
||||
void BackRefFromAssociatedObject::detach() {
|
||||
RuntimeAssert(atomicGet(&refCount) == 0, "unexpected refCount");
|
||||
obj_ = nullptr; // Handled in addRef/tryAddRef/releaseRef/ref.
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void BackRefFromAssociatedObject::assertDetached() {
|
||||
RuntimeAssert(obj_ == nullptr, "Expecting this=%p to be detached, but found obj_=%p", this, obj_);
|
||||
}
|
||||
|
||||
template <ErrorPolicy errorPolicy>
|
||||
ObjHeader* BackRefFromAssociatedObject::ref() const {
|
||||
kotlin::AssertThreadState(kotlin::ThreadState::kRunnable);
|
||||
RuntimeAssert(obj_ != nullptr, "no valid Kotlin object found");
|
||||
|
||||
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AdoptReferenceFromSharedVariable(obj_);
|
||||
return obj_;
|
||||
}
|
||||
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
|
||||
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const;
|
||||
|
||||
extern "C" {
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj) {
|
||||
holder->initLocal(obj);
|
||||
@@ -233,8 +26,8 @@ RUNTIME_NOTHROW void KRefSharedHolder_init(KRefSharedHolder* holder, ObjHeader*
|
||||
holder->init(obj);
|
||||
}
|
||||
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_dispose(const KRefSharedHolder* holder) {
|
||||
holder->dispose();
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_dispose(KRefSharedHolder* holder) {
|
||||
holder->dispose();
|
||||
}
|
||||
|
||||
RUNTIME_NOTHROW ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) {
|
||||
|
||||
@@ -28,9 +28,9 @@ class KRefSharedHolder {
|
||||
template <ErrorPolicy errorPolicy>
|
||||
ObjHeader* ref() const;
|
||||
|
||||
void dispose() const;
|
||||
void dispose();
|
||||
|
||||
void disposeFromNative() const {
|
||||
void disposeFromNative() {
|
||||
kotlin::CalledFromNativeGuard guard;
|
||||
dispose();
|
||||
}
|
||||
@@ -78,7 +78,7 @@ static_assert(
|
||||
extern "C" {
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj);
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_init(KRefSharedHolder* holder, ObjHeader* obj);
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_dispose(const KRefSharedHolder* holder);
|
||||
RUNTIME_NOTHROW void KRefSharedHolder_dispose(KRefSharedHolder* holder);
|
||||
RUNTIME_NOTHROW ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder);
|
||||
} // extern "C"
|
||||
|
||||
|
||||
@@ -101,8 +101,21 @@ private:
|
||||
std_support::vector<int32_t> objOffsets_;
|
||||
};
|
||||
|
||||
class Any : private Pinned {
|
||||
public:
|
||||
ObjHeader* header() noexcept { return &header_; }
|
||||
|
||||
void installMetaObject() noexcept { (void)header()->meta_object(); }
|
||||
|
||||
protected:
|
||||
Any() noexcept = default;
|
||||
~Any() = default;
|
||||
|
||||
ObjHeader header_;
|
||||
};
|
||||
|
||||
template <typename Payload>
|
||||
class Object : private Pinned {
|
||||
class Object : public Any {
|
||||
public:
|
||||
class FieldIterator {
|
||||
public:
|
||||
@@ -160,15 +173,12 @@ public:
|
||||
header_.typeInfoOrMeta_ = const_cast<TypeInfo*>(typeInfo);
|
||||
}
|
||||
|
||||
ObjHeader* header() noexcept { return &header_; }
|
||||
|
||||
Payload& operator*() noexcept { return payload_; }
|
||||
Payload* operator->() noexcept { return &payload_; }
|
||||
|
||||
FieldIterable fields() noexcept { return FieldIterable(*this); }
|
||||
|
||||
private:
|
||||
ObjHeader header_;
|
||||
Payload payload_{};
|
||||
};
|
||||
|
||||
@@ -191,7 +201,7 @@ namespace internal {
|
||||
|
||||
// Array types are predetermined, use one of the subclasses below.
|
||||
template <typename Payload, size_t ElementCount>
|
||||
class Array : private Pinned {
|
||||
class Array : public Any {
|
||||
public:
|
||||
static Array<Payload, ElementCount>& FromArrayHeader(ArrayHeader* arr) noexcept {
|
||||
static_assert(std::is_trivially_destructible_v<Array>, "Array destructor is not guaranteed to be called.");
|
||||
@@ -210,17 +220,16 @@ public:
|
||||
TypeInfoHolder{TypeInfoHolder::ArrayBuilder<Payload>()}.typeInfo()->IsLayoutCompatible(typeInfo),
|
||||
"constructing array from incompatible type info");
|
||||
header_.typeInfoOrMeta_ = const_cast<TypeInfo*>(typeInfo);
|
||||
header_.count_ = ElementCount;
|
||||
count_ = ElementCount;
|
||||
}
|
||||
|
||||
ObjHeader* header() noexcept { return header_.obj(); }
|
||||
ArrayHeader* arrayHeader() noexcept { return &header_; }
|
||||
ArrayHeader* arrayHeader() noexcept { return header()->array(); }
|
||||
|
||||
std::array<Payload, ElementCount>& elements() noexcept { return elements_; }
|
||||
|
||||
private:
|
||||
ArrayHeader header_;
|
||||
std::array<Payload, ElementCount> elements_{};
|
||||
uint32_t count_;
|
||||
alignas(ArrayHeader) std::array<Payload, ElementCount> elements_{};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@@ -335,5 +344,31 @@ public:
|
||||
String() noexcept : internal::Array<KChar, ElementCount>(theStringTypeInfo) {}
|
||||
};
|
||||
|
||||
struct RegularWeakReferenceImplPayload {
|
||||
void* referred;
|
||||
|
||||
using Field = ObjHeader* RegularWeakReferenceImplPayload::*;
|
||||
static constexpr std::array<Field, 0> kFields{};
|
||||
};
|
||||
|
||||
extern "C" OBJ_GETTER(Konan_RegularWeakReferenceImpl_get, ObjHeader*);
|
||||
|
||||
class RegularWeakReferenceImpl : public Object<RegularWeakReferenceImplPayload> {
|
||||
public:
|
||||
static RegularWeakReferenceImpl& FromObjHeader(ObjHeader* obj) noexcept {
|
||||
RuntimeAssert(obj->type_info() == theRegularWeakReferenceImplTypeInfo, "Invalid type");
|
||||
return static_cast<RegularWeakReferenceImpl&>(Object::FromObjHeader(obj));
|
||||
}
|
||||
|
||||
RegularWeakReferenceImpl() noexcept : Object(theRegularWeakReferenceImplTypeInfo) {}
|
||||
|
||||
OBJ_GETTER0(get) noexcept { RETURN_RESULT_OF(Konan_RegularWeakReferenceImpl_get, header()); }
|
||||
|
||||
ObjHeader* get() noexcept {
|
||||
ObjHeader* result;
|
||||
return get(&result);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test_support
|
||||
} // namespace kotlin
|
||||
|
||||
@@ -70,6 +70,7 @@ extern const TypeInfo* theThrowableTypeInfo;
|
||||
extern const TypeInfo* theUnitTypeInfo;
|
||||
extern const TypeInfo* theWorkerBoundReferenceTypeInfo;
|
||||
extern const TypeInfo* theCleanerImplTypeInfo;
|
||||
extern const TypeInfo* theRegularWeakReferenceImplTypeInfo;
|
||||
|
||||
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE;
|
||||
KBoolean IsInstanceOfClassFast(const ObjHeader* obj, int32_t lo, int32_t hi) RUNTIME_PURE;
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Weak.h"
|
||||
|
||||
#include "Memory.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: an ugly hack with fixed layout.
|
||||
struct WeakReferenceCounter {
|
||||
ObjHeader header;
|
||||
KRef referred;
|
||||
KInt lock;
|
||||
KInt cookie;
|
||||
};
|
||||
|
||||
inline WeakReferenceCounter* asWeakReferenceCounter(ObjHeader* obj) {
|
||||
return reinterpret_cast<WeakReferenceCounter*>(obj);
|
||||
}
|
||||
|
||||
#if !KONAN_NO_THREADS
|
||||
|
||||
inline void lock(int32_t* address) {
|
||||
RuntimeAssert(*address == 0 || *address == 1, "Incorrect lock state");
|
||||
while (__sync_val_compare_and_swap(address, 0, 1) == 1);
|
||||
}
|
||||
|
||||
inline void unlock(int32_t* address) {
|
||||
int old = __sync_val_compare_and_swap(address, 1, 0);
|
||||
RuntimeAssert(old == 1, "Incorrect lock state");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
OBJ_GETTER(makeWeakReferenceCounter, void*);
|
||||
OBJ_GETTER(makeObjCWeakReferenceImpl, void*);
|
||||
OBJ_GETTER(makePermanentWeakReferenceImpl, ObjHeader*);
|
||||
|
||||
// See Weak.kt for implementation details.
|
||||
// Retrieve link on the counter object.
|
||||
OBJ_GETTER(Konan_getWeakReferenceImpl, ObjHeader* referred) {
|
||||
if (referred->permanent()) {
|
||||
RETURN_RESULT_OF(makePermanentWeakReferenceImpl, referred);
|
||||
}
|
||||
|
||||
#if KONAN_OBJC_INTEROP
|
||||
if (IsInstance(referred, theObjCObjectWrapperTypeInfo)) {
|
||||
RETURN_RESULT_OF(makeObjCWeakReferenceImpl, referred->GetAssociatedObject());
|
||||
}
|
||||
#endif // KONAN_OBJC_INTEROP
|
||||
|
||||
ObjHeader* weakCounter = referred->GetWeakCounter();
|
||||
if (weakCounter == nullptr) {
|
||||
ObjHolder counterHolder;
|
||||
// Cast unneeded, just to emphasize we store an object reference as void*.
|
||||
ObjHeader* counter = makeWeakReferenceCounter(reinterpret_cast<void*>(referred), counterHolder.slot());
|
||||
weakCounter = referred->GetOrSetWeakCounter(counter);
|
||||
}
|
||||
RETURN_OBJ(weakCounter);
|
||||
}
|
||||
|
||||
// Materialize a weak reference to either null or the real reference.
|
||||
OBJ_GETTER(Konan_WeakReferenceCounter_get, ObjHeader* counter) {
|
||||
ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
|
||||
#if KONAN_NO_THREADS
|
||||
RETURN_OBJ(*referredAddress);
|
||||
#else
|
||||
auto* weakCounter = asWeakReferenceCounter(counter);
|
||||
RETURN_RESULT_OF(ReadHeapRefLocked, referredAddress, &weakCounter->lock, &weakCounter->cookie);
|
||||
#endif
|
||||
}
|
||||
|
||||
ALWAYS_INLINE ObjHeader* UnsafeWeakReferenceCounterGet(ObjHeader* counter) {
|
||||
return asWeakReferenceCounter(counter)->referred;
|
||||
}
|
||||
|
||||
void WeakReferenceCounterClear(ObjHeader* counter) {
|
||||
ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
|
||||
// Note, that we don't do UpdateRef here, as reference is weak.
|
||||
#if KONAN_NO_THREADS
|
||||
*referredAddress = nullptr;
|
||||
#else
|
||||
int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
|
||||
// Spinlock.
|
||||
lock(lockAddress);
|
||||
*referredAddress = nullptr;
|
||||
unlock(lockAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* 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_WEAK_H
|
||||
#define RUNTIME_WEAK_H
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Atomically clears counter object reference.
|
||||
void WeakReferenceCounterClear(ObjHeader* counter);
|
||||
ObjHeader* UnsafeWeakReferenceCounterGet(ObjHeader* counter);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // RUNTIME_WEAK_H
|
||||
Reference in New Issue
Block a user