Migrate StablePtr to KRefSharedHolder (#3966)
This PR also fixes tests from #3969
This commit is contained in:
committed by
GitHub
parent
d91266d4c3
commit
02eb63162f
@@ -2742,6 +2742,10 @@ standaloneTest("memory_only_gc") {
|
|||||||
source = "runtime/memory/only_gc.kt"
|
source = "runtime/memory/only_gc.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task memory_stable_ref_cross_thread_check(type: KonanLocalTest) {
|
||||||
|
source = "runtime/memory/stable_ref_cross_thread_check.kt"
|
||||||
|
}
|
||||||
|
|
||||||
standaloneTest("cycle_collector") {
|
standaloneTest("cycle_collector") {
|
||||||
disabled = project.globalTestArgs.contains('-opt') || (project.testTarget == 'wasm32') // Needs debug build.
|
disabled = project.globalTestArgs.contains('-opt') || (project.testTarget == 'wasm32') // Needs debug build.
|
||||||
flags = ['-g']
|
flags = ['-g']
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package runtime.memory.stable_ref_cross_thread_check
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
import kotlin.native.concurrent.*
|
||||||
|
import kotlinx.cinterop.*
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun runTest1() {
|
||||||
|
val worker = Worker.start()
|
||||||
|
|
||||||
|
val future = worker.execute(TransferMode.SAFE, { }) {
|
||||||
|
StableRef.create(Any())
|
||||||
|
}
|
||||||
|
val ref = future.result
|
||||||
|
assertFailsWith<IncorrectDereferenceException> {
|
||||||
|
val value = ref.get()
|
||||||
|
println(value.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.requestTermination().result
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun runTest2() {
|
||||||
|
val worker = Worker.start()
|
||||||
|
|
||||||
|
val mainThreadRef = StableRef.create(Any())
|
||||||
|
// Simulate this going through interop as raw C pointer.
|
||||||
|
val pointerValue: Long = mainThreadRef.asCPointer().toLong()
|
||||||
|
val future = worker.execute(TransferMode.SAFE, { pointerValue }) {
|
||||||
|
val pointer: COpaquePointer = it.toCPointer()!!
|
||||||
|
assertFailsWith<IncorrectDereferenceException> {
|
||||||
|
// Even attempting to convert a pointer to StableRef should fail.
|
||||||
|
val otherThreadRef: StableRef<Any> = pointer.asStableRef()
|
||||||
|
println(otherThreadRef.toString())
|
||||||
|
}
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
future.result
|
||||||
|
|
||||||
|
worker.requestTermination().result
|
||||||
|
}
|
||||||
@@ -18,21 +18,28 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "Alloc.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
#include "MemorySharedRefs.hpp"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
KNativePtr Kotlin_Interop_createStablePointer(KRef any) {
|
KNativePtr Kotlin_Interop_createStablePointer(KRef any) {
|
||||||
return CreateStablePointer(any);
|
KRefSharedHolder* holder = konanConstructInstance<KRefSharedHolder>();
|
||||||
|
holder->init(any);
|
||||||
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) {
|
void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) {
|
||||||
DisposeStablePointer(pointer);
|
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
|
||||||
|
holder->dispose();
|
||||||
|
konanDestructInstance(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) {
|
OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) {
|
||||||
RETURN_RESULT_OF(DerefStablePointer, pointer);
|
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
|
||||||
|
RETURN_OBJ(holder->ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2279,10 +2279,7 @@ void disposeStablePointer(KNativePtr pointer) {
|
|||||||
|
|
||||||
OBJ_GETTER(derefStablePointer, KNativePtr pointer) {
|
OBJ_GETTER(derefStablePointer, KNativePtr pointer) {
|
||||||
KRef ref = reinterpret_cast<KRef>(pointer);
|
KRef ref = reinterpret_cast<KRef>(pointer);
|
||||||
#if USE_GC
|
AdoptReferenceFromSharedVariable(ref);
|
||||||
if (IsStrictMemoryModel && ref != nullptr)
|
|
||||||
rememberNewContainer(ref->container());
|
|
||||||
#endif // USE_GC
|
|
||||||
RETURN_OBJ(ref);
|
RETURN_OBJ(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2758,6 +2755,13 @@ bool IsForeignRefAccessible(ObjHeader* object, ForeignRefContext context) {
|
|||||||
return isForeignRefAccessible(object, context);
|
return isForeignRefAccessible(object, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdoptReferenceFromSharedVariable(ObjHeader* object) {
|
||||||
|
#if USE_GC
|
||||||
|
if (IsStrictMemoryModel && object != nullptr && isShareable(object->container()))
|
||||||
|
rememberNewContainer(object->container());
|
||||||
|
#endif // USE_GC
|
||||||
|
}
|
||||||
|
|
||||||
// Public memory interface.
|
// Public memory interface.
|
||||||
MemoryState* InitMemory() {
|
MemoryState* InitMemory() {
|
||||||
return initMemory();
|
return initMemory();
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ void DeinitForeignRef(ObjHeader* object, ForeignRefContext context);
|
|||||||
|
|
||||||
bool IsForeignRefAccessible(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);
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
#endif // RUNTIME_MEMORYPRIVATE_HPP
|
#endif // RUNTIME_MEMORYPRIVATE_HPP
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ void KRefSharedHolder::init(ObjHeader* obj) {
|
|||||||
|
|
||||||
ObjHeader* KRefSharedHolder::ref() const {
|
ObjHeader* KRefSharedHolder::ref() const {
|
||||||
ensureRefAccessible();
|
ensureRefAccessible();
|
||||||
|
AdoptReferenceFromSharedVariable(obj_);
|
||||||
return obj_;
|
return obj_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +77,8 @@ void BackRefFromAssociatedObject::addRef() {
|
|||||||
|
|
||||||
bool BackRefFromAssociatedObject::tryAddRef() {
|
bool BackRefFromAssociatedObject::tryAddRef() {
|
||||||
// Suboptimal but simple:
|
// Suboptimal but simple:
|
||||||
ObjHeader* obj = this->ref();
|
this->ensureRefAccessible();
|
||||||
|
ObjHeader* obj = this->obj_;
|
||||||
|
|
||||||
if (!TryAddHeapRef(obj)) return false;
|
if (!TryAddHeapRef(obj)) return false;
|
||||||
this->addRef();
|
this->addRef();
|
||||||
@@ -97,6 +99,12 @@ void BackRefFromAssociatedObject::releaseRef() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjHeader* BackRefFromAssociatedObject::ref() const {
|
||||||
|
ensureRefAccessible();
|
||||||
|
AdoptReferenceFromSharedVariable(obj_);
|
||||||
|
return obj_;
|
||||||
|
}
|
||||||
|
|
||||||
void BackRefFromAssociatedObject::ensureRefAccessible() const {
|
void BackRefFromAssociatedObject::ensureRefAccessible() const {
|
||||||
ensureForeignRefAccessible(obj_, context_);
|
ensureForeignRefAccessible(obj_, context_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,7 @@ class BackRefFromAssociatedObject {
|
|||||||
|
|
||||||
void releaseRef();
|
void releaseRef();
|
||||||
|
|
||||||
ObjHeader* ref() const {
|
ObjHeader* ref() const;
|
||||||
ensureRefAccessible();
|
|
||||||
return obj_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool permanent() const {
|
inline bool permanent() const {
|
||||||
return obj_->permanent(); // Safe to query from any thread.
|
return obj_->permanent(); // Safe to query from any thread.
|
||||||
|
|||||||
Reference in New Issue
Block a user