[K2/N] Export C adapters for non-root packages
^KT-56182 Merge-request: KT-MR-10160 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
c57c34525f
commit
363c56e226
+28
-8
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.driver.phases.PsiToIrContext
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys.USE_FIR
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||
@@ -394,6 +396,7 @@ private fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescript
|
||||
*/
|
||||
internal class CAdapterGenerator(
|
||||
private val context: PsiToIrContext,
|
||||
private val configuration: CompilerConfiguration,
|
||||
private val typeTranslator: CAdapterTypeTranslator,
|
||||
) : DeclarationDescriptorVisitor<Boolean, Void?> {
|
||||
private val scopes = mutableListOf<ExportedElementScope>()
|
||||
@@ -481,6 +484,20 @@ internal class CAdapterGenerator(
|
||||
val fragments = descriptor.module.getPackage(FqName.ROOT).fragments.filter {
|
||||
it.module in moduleDescriptors }
|
||||
visitChildren(fragments)
|
||||
|
||||
if (configuration.get(USE_FIR) == true) {
|
||||
// K2 does not serialize empty package fragments, thus breaking the scope chain.
|
||||
// The following traverse definitely reaches every subpackage fragment.
|
||||
scopes.push(getPackageScope(FqName.ROOT))
|
||||
val subfragments = descriptor.module.getSubPackagesOf(FqName.ROOT) { true }
|
||||
.flatMap {
|
||||
descriptor.module.getPackage(it).fragments.filter {
|
||||
it.module in moduleDescriptors
|
||||
}
|
||||
}
|
||||
visitChildren(subfragments)
|
||||
scopes.pop()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -508,25 +525,28 @@ internal class CAdapterGenerator(
|
||||
|
||||
override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, ignored: Void?): Boolean {
|
||||
val fqName = descriptor.fqName
|
||||
val packageScope = packageScopes.getOrPut(fqName) {
|
||||
val name = if (fqName.isRoot) "root" else translateName(fqName.shortName())
|
||||
val scope = ExportedElementScope(ScopeKind.PACKAGE, name)
|
||||
scopes.last().scopes += scope
|
||||
scope
|
||||
}
|
||||
val packageScope = getPackageScope(fqName)
|
||||
scopes.push(packageScope)
|
||||
visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getMemberScope()))
|
||||
if (!seenPackageFragments.contains(descriptor))
|
||||
visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getMemberScope()))
|
||||
for (currentPackageFragment in currentPackageFragments) {
|
||||
if (!seenPackageFragments.contains(currentPackageFragment) &&
|
||||
currentPackageFragment.fqName.isChildOf(descriptor.fqName)) {
|
||||
seenPackageFragments += currentPackageFragment
|
||||
visitChildren(currentPackageFragment)
|
||||
seenPackageFragments += currentPackageFragment
|
||||
}
|
||||
}
|
||||
scopes.pop()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getPackageScope(fqName: FqName) = packageScopes.getOrPut(fqName) {
|
||||
val name = if (fqName.isRoot) "root" else translateName(fqName.shortName())
|
||||
val scope = ExportedElementScope(ScopeKind.PACKAGE, name)
|
||||
scopes.last().scopes += scope
|
||||
scope
|
||||
}
|
||||
|
||||
|
||||
private val moduleDescriptors = mutableSetOf<ModuleDescriptor>()
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ internal val BuildCExports = createSimpleNamedCompilerPhase<PsiToIrContext, Fron
|
||||
) { context, input ->
|
||||
val prefix = context.config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_")
|
||||
val typeTranslator = CAdapterTypeTranslator(prefix, context.builtIns)
|
||||
CAdapterGenerator(context, typeTranslator).buildExports(input.moduleDescriptor)
|
||||
CAdapterGenerator(context, input.environment.configuration, typeTranslator).buildExports(input.moduleDescriptor)
|
||||
}
|
||||
|
||||
internal data class CExportGenerateApiInput(
|
||||
|
||||
@@ -5418,8 +5418,7 @@ dynamicTest("kt41904") {
|
||||
for (i in 0..2) {
|
||||
dynamicTest("kt42796_$i") {
|
||||
clangTool = "clang++"
|
||||
disabled = (project.testTarget == 'wasm32') || // wasm doesn't support -produce dynamic
|
||||
(i==1 && isK2(project)) // KT-56182
|
||||
disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic
|
||||
source = "produce_dynamic/kt-42796/main-${i}.kt"
|
||||
cSource = "$projectDir/produce_dynamic/kt-42796/main.cpp"
|
||||
useGoldenData = true
|
||||
@@ -5455,12 +5454,16 @@ dynamicTest("interop_concurrentRuntime") {
|
||||
expectedExitStatus = 99
|
||||
}
|
||||
|
||||
dynamicTest("interop_kt42397") {
|
||||
disabled = (project.testTarget == 'wasm32') || // wasm doesn't support -produce dynamic
|
||||
isK2(project) // KT-56182
|
||||
source = "interop/kt42397/knlibrary.kt"
|
||||
cSource = "$projectDir/interop/kt42397/test.cpp"
|
||||
clangTool = "clang++"
|
||||
for (i in ["kt42397", "kt56182_root", "kt56182_package1lvl", "kt56182_subpackage2lvl", "kt56182_root_package1lvl", "kt56182_root_subpackage2lvl"]) {
|
||||
// note: kt56182_package1lvl is same as kt42397
|
||||
// note: kt56182_root_package1lvl is similar as kt41904
|
||||
// note: kt56182_subpackage2lvl is similar as kt42796_1
|
||||
dynamicTest("interop_$i") {
|
||||
disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic
|
||||
source = "interop/$i/knlibrary.kt"
|
||||
cSource = "$projectDir/interop/$i/test.cpp"
|
||||
clangTool = "clang++"
|
||||
}
|
||||
}
|
||||
|
||||
dynamicTest("interop_cleaners_main_thread") {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// This test is similar to kt42397, just everything is doubled: in "package knlibrary" and the root package
|
||||
|
||||
package knlibrary
|
||||
|
||||
import kotlin.native.Platform
|
||||
|
||||
// The following 2 singletons are unused. However, since we are generating C bindings for them,
|
||||
// they should be marked as used, so that the code generator emits their deinitialization.
|
||||
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
auto t = std::thread([] {
|
||||
auto lib = testlib_symbols();
|
||||
|
||||
lib->kotlin.root.knlibrary.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a = lib->kotlin.root.knlibrary.A._instance();
|
||||
auto bCompanion = lib->kotlin.root.knlibrary.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion.pinned);
|
||||
lib->DisposeStablePointer(a.pinned);
|
||||
|
||||
// A and B.Companion now are owned by the global references only.
|
||||
});
|
||||
|
||||
// This causes Kotlin runtime full deinitialization, because `t` is the only thread
|
||||
// with the Kotlin runtime. So, all the globals will get deinitialized and memory
|
||||
// leak checker will get executed (because .kt code is compiled with -g).
|
||||
t.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// This test is similar to kt42397, just everything is in root package instead of "package knlibrary"
|
||||
|
||||
import kotlin.native.Platform
|
||||
|
||||
// The following 2 singletons are unused. However, since we are generating C bindings for them,
|
||||
// they should be marked as used, so that the code generator emits their deinitialization.
|
||||
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
auto t = std::thread([] {
|
||||
auto lib = testlib_symbols();
|
||||
|
||||
lib->kotlin.root.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a = lib->kotlin.root.A._instance();
|
||||
auto bCompanion = lib->kotlin.root.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion.pinned);
|
||||
lib->DisposeStablePointer(a.pinned);
|
||||
|
||||
// A and B.Companion now are owned by the global references only.
|
||||
});
|
||||
|
||||
// This causes Kotlin runtime full deinitialization, because `t` is the only thread
|
||||
// with the Kotlin runtime. So, all the globals will get deinitialized and memory
|
||||
// leak checker will get executed (because .kt code is compiled with -g).
|
||||
t.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// This test is similar to kt42397, just everything is doubled: in "package knlibrary.subpackage" and the root package
|
||||
|
||||
// FILE: FirstLevelPackage.kt
|
||||
package knlibrary
|
||||
|
||||
import kotlin.native.Platform
|
||||
|
||||
// The following 2 singletons are unused. However, since we are generating C bindings for them,
|
||||
// they should be marked as used, so that the code generator emits their deinitialization.
|
||||
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
|
||||
// FILE: rootPackage.kt
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
auto t = std::thread([] {
|
||||
auto lib = testlib_symbols();
|
||||
|
||||
lib->kotlin.root.knlibrary.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a = lib->kotlin.root.knlibrary.A._instance();
|
||||
auto bCompanion = lib->kotlin.root.knlibrary.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion.pinned);
|
||||
lib->DisposeStablePointer(a.pinned);
|
||||
|
||||
// A and B.Companion now are owned by the global references only.
|
||||
|
||||
// Now same actions for objects in the root package
|
||||
lib->kotlin.root.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a2 = lib->kotlin.root.A._instance();
|
||||
auto bCompanion2 = lib->kotlin.root.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion2.pinned);
|
||||
lib->DisposeStablePointer(a2.pinned);
|
||||
});
|
||||
|
||||
// This causes Kotlin runtime full deinitialization, because `t` is the only thread
|
||||
// with the Kotlin runtime. So, all the globals will get deinitialized and memory
|
||||
// leak checker will get executed (because .kt code is compiled with -g).
|
||||
t.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// This test is similar to kt42397, just everything is doubled: in "package knlibrary.subpackage" and the root package
|
||||
|
||||
// FILE: SecondLevelPackage.kt
|
||||
package knlibrary.subpackage
|
||||
|
||||
import kotlin.native.Platform
|
||||
|
||||
// The following 2 singletons are unused. However, since we are generating C bindings for them,
|
||||
// they should be marked as used, so that the code generator emits their deinitialization.
|
||||
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
|
||||
// FILE: rootPackage.kt
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
auto t = std::thread([] {
|
||||
auto lib = testlib_symbols();
|
||||
|
||||
lib->kotlin.root.knlibrary.subpackage.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a = lib->kotlin.root.knlibrary.subpackage.A._instance();
|
||||
auto bCompanion = lib->kotlin.root.knlibrary.subpackage.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion.pinned);
|
||||
lib->DisposeStablePointer(a.pinned);
|
||||
|
||||
// A and B.Companion now are owned by the global references only.
|
||||
|
||||
// Now same actions for objects in the root package
|
||||
lib->kotlin.root.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a2 = lib->kotlin.root.A._instance();
|
||||
auto bCompanion2 = lib->kotlin.root.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion2.pinned);
|
||||
lib->DisposeStablePointer(a2.pinned);
|
||||
});
|
||||
|
||||
// This causes Kotlin runtime full deinitialization, because `t` is the only thread
|
||||
// with the Kotlin runtime. So, all the globals will get deinitialized and memory
|
||||
// leak checker will get executed (because .kt code is compiled with -g).
|
||||
t.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// This test is similar to kt42397, just everything is in "package knlibrary.subpackage" instead of "package knlibrary"
|
||||
package knlibrary.subpackage
|
||||
|
||||
import kotlin.native.Platform
|
||||
|
||||
// The following 2 singletons are unused. However, since we are generating C bindings for them,
|
||||
// they should be marked as used, so that the code generator emits their deinitialization.
|
||||
|
||||
object A {}
|
||||
|
||||
class B {
|
||||
companion object {}
|
||||
}
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
auto t = std::thread([] {
|
||||
auto lib = testlib_symbols();
|
||||
|
||||
lib->kotlin.root.knlibrary.subpackage.enableMemoryChecker();
|
||||
|
||||
// Initialize A and B.Companion and get their stable pointers.
|
||||
auto a = lib->kotlin.root.knlibrary.subpackage.A._instance();
|
||||
auto bCompanion = lib->kotlin.root.knlibrary.subpackage.B.Companion._instance();
|
||||
|
||||
// Now, dispose of the stable pointers.
|
||||
lib->DisposeStablePointer(bCompanion.pinned);
|
||||
lib->DisposeStablePointer(a.pinned);
|
||||
|
||||
// A and B.Companion now are owned by the global references only.
|
||||
});
|
||||
|
||||
// This causes Kotlin runtime full deinitialization, because `t` is the only thread
|
||||
// with the Kotlin runtime. So, all the globals will get deinitialized and memory
|
||||
// leak checker will get executed (because .kt code is compiled with -g).
|
||||
t.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user