Migrate StablePtr to KRefSharedHolder (#3966)

This PR also fixes tests from #3969
This commit is contained in:
Alexander Shabalin
2020-03-12 17:30:14 +03:00
committed by GitHub
parent d91266d4c3
commit 02eb63162f
7 changed files with 84 additions and 12 deletions
+4
View File
@@ -2742,6 +2742,10 @@ standaloneTest("memory_only_gc") {
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") {
disabled = project.globalTestArgs.contains('-opt') || (project.testTarget == 'wasm32') // Needs debug build.
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
}
+10 -3
View File
@@ -18,21 +18,28 @@
#include <stdio.h>
#include <stdint.h>
#include "Alloc.h"
#include "Memory.h"
#include "MemorySharedRefs.hpp"
#include "Types.h"
extern "C" {
KNativePtr Kotlin_Interop_createStablePointer(KRef any) {
return CreateStablePointer(any);
KRefSharedHolder* holder = konanConstructInstance<KRefSharedHolder>();
holder->init(any);
return holder;
}
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) {
RETURN_RESULT_OF(DerefStablePointer, pointer);
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
RETURN_OBJ(holder->ref());
}
}
+8 -4
View File
@@ -2279,10 +2279,7 @@ void disposeStablePointer(KNativePtr pointer) {
OBJ_GETTER(derefStablePointer, KNativePtr pointer) {
KRef ref = reinterpret_cast<KRef>(pointer);
#if USE_GC
if (IsStrictMemoryModel && ref != nullptr)
rememberNewContainer(ref->container());
#endif // USE_GC
AdoptReferenceFromSharedVariable(ref);
RETURN_OBJ(ref);
}
@@ -2758,6 +2755,13 @@ bool IsForeignRefAccessible(ObjHeader* object, ForeignRefContext 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.
MemoryState* InitMemory() {
return initMemory();
+4
View File
@@ -36,6 +36,10 @@ 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);
} // extern "C"
#endif // RUNTIME_MEMORYPRIVATE_HPP
+9 -1
View File
@@ -22,6 +22,7 @@ void KRefSharedHolder::init(ObjHeader* obj) {
ObjHeader* KRefSharedHolder::ref() const {
ensureRefAccessible();
AdoptReferenceFromSharedVariable(obj_);
return obj_;
}
@@ -76,7 +77,8 @@ void BackRefFromAssociatedObject::addRef() {
bool BackRefFromAssociatedObject::tryAddRef() {
// Suboptimal but simple:
ObjHeader* obj = this->ref();
this->ensureRefAccessible();
ObjHeader* obj = this->obj_;
if (!TryAddHeapRef(obj)) return false;
this->addRef();
@@ -97,6 +99,12 @@ void BackRefFromAssociatedObject::releaseRef() {
}
}
ObjHeader* BackRefFromAssociatedObject::ref() const {
ensureRefAccessible();
AdoptReferenceFromSharedVariable(obj_);
return obj_;
}
void BackRefFromAssociatedObject::ensureRefAccessible() const {
ensureForeignRefAccessible(obj_, context_);
}
+1 -4
View File
@@ -35,10 +35,7 @@ class BackRefFromAssociatedObject {
void releaseRef();
ObjHeader* ref() const {
ensureRefAccessible();
return obj_;
}
ObjHeader* ref() const;
inline bool permanent() const {
return obj_->permanent(); // Safe to query from any thread.