[Native] FIR version of EscapeAnalysisChecker
diff --git a/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLNativeDiagnosticsTestGenerated.java b/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLNativeDiagnosticsTestGenerated.java
index f80f069..6c313dd 100644
--- a/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLNativeDiagnosticsTestGenerated.java
+++ b/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLNativeDiagnosticsTestGenerated.java
@@ -63,6 +63,30 @@
}
@Test
+ @TestMetadata("escapeAnalysisBasic.kt")
+ public void testEscapeAnalysisBasic() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisDfgAndIntrinsics.kt")
+ public void testEscapeAnalysisDfgAndIntrinsics() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisPackages.kt")
+ public void testEscapeAnalysisPackages() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisPointsTo.kt")
+ public void testEscapeAnalysisPointsTo() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.kt");
+ }
+
+ @Test
@TestMetadata("externalNonFunctions.kt")
public void testExternalNonFunctions() {
runTest("compiler/testData/diagnostics/nativeTests/externalNonFunctions.kt");
diff --git a/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLReversedNativeDiagnosticsTestGenerated.java b/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLReversedNativeDiagnosticsTestGenerated.java
index c8d68e5..e22bf36 100644
--- a/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLReversedNativeDiagnosticsTestGenerated.java
+++ b/analysis/low-level-api-fir/low-level-api-fir-native/tests-gen/org/jetbrains/kotlin/analysis/low/level/api/fir/konan/compiler/based/LLReversedNativeDiagnosticsTestGenerated.java
@@ -63,6 +63,30 @@
}
@Test
+ @TestMetadata("escapeAnalysisBasic.kt")
+ public void testEscapeAnalysisBasic() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisDfgAndIntrinsics.kt")
+ public void testEscapeAnalysisDfgAndIntrinsics() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisPackages.kt")
+ public void testEscapeAnalysisPackages() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.kt");
+ }
+
+ @Test
+ @TestMetadata("escapeAnalysisPointsTo.kt")
+ public void testEscapeAnalysisPointsTo() {
+ runTest("compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.kt");
+ }
+
+ @Test
@TestMetadata("externalNonFunctions.kt")
public void testExternalNonFunctions() {
runTest("compiler/testData/diagnostics/nativeTests/externalNonFunctions.kt");
diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt
index da30c94..61587fe 100644
--- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt
+++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt
@@ -115,5 +115,48 @@
val IDENTITY_HASH_CODE_ON_VALUE_TYPE by warning<KtElement> {
parameter<ConeKotlinType>("type")
}
+
+ // Escape analysis annotation diagnostics
+ val UNUSED_ESCAPES_ANNOTATION by warning<KtElement> {
+ parameter<String>("reason")
+ }
+ val UNUSED_ESCAPES_NOTHING_ANNOTATION by warning<KtElement> {
+ parameter<String>("reason")
+ }
+ val UNUSED_POINTS_TO_ANNOTATION by warning<KtElement> {
+ parameter<String>("reason")
+ }
+ val CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING by error<KtElement>()
+ val MISSING_ESCAPE_ANALYSIS_ANNOTATION by error<KtElement>()
+ val MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE by error<KtElement>()
+ val INVALID_ESCAPES_VALUE by error<KtElement> {
+ parameter<String>("message")
+ }
+ val ESCAPES_MARKED_ON_NON_ESCAPING_TYPE by error<KtElement> {
+ parameter<String>("parameterName")
+ }
+ val ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE by error<KtElement> {
+ parameter<String>("parameterName")
+ }
+ val INVALID_POINTS_TO_VALUE by error<KtElement> {
+ parameter<String>("message")
+ }
+ val INVALID_POINTS_TO_INDEX by error<KtElement> {
+ parameter<Int>("fromIndex")
+ parameter<Int>("toIndex")
+ parameter<String>("message")
+ }
+ val POINTS_TO_KIND_1_ONLY_FOR_RETURN by error<KtElement> {
+ parameter<String>("fromName")
+ parameter<String>("toName")
+ }
+ val POINTS_TO_FROM_NON_ESCAPING_TYPE by error<KtElement> {
+ parameter<String>("fromName")
+ parameter<String>("toName")
+ }
+ val POINTS_TO_TO_NON_ESCAPING_TYPE by error<KtElement> {
+ parameter<String>("fromName")
+ parameter<String>("toName")
+ }
}
}
diff --git a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt
index 87447e1..217bbeb 100644
--- a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt
+++ b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt
@@ -11,6 +11,7 @@
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory1
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory2
+import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory3
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryForDeprecation1
import org.jetbrains.kotlin.diagnostics.KtDiagnosticsContainer
import org.jetbrains.kotlin.diagnostics.Severity.ERROR
@@ -72,6 +73,20 @@
val INAPPLICABLE_OBJC_OVERRIDE: KtDiagnosticFactory0 = KtDiagnosticFactory0("INAPPLICABLE_OBJC_OVERRIDE", ERROR, SourceElementPositioningStrategies.DEFAULT, PsiElement::class, getRendererFactory())
val NATIVE_SPECIFIC_ATOMIC: KtDiagnosticFactory1<Name> = KtDiagnosticFactory1("NATIVE_SPECIFIC_ATOMIC", WARNING, SourceElementPositioningStrategies.DEFAULT, KtTypeReference::class, getRendererFactory())
val IDENTITY_HASH_CODE_ON_VALUE_TYPE: KtDiagnosticFactory1<ConeKotlinType> = KtDiagnosticFactory1("IDENTITY_HASH_CODE_ON_VALUE_TYPE", WARNING, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val UNUSED_ESCAPES_ANNOTATION: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("UNUSED_ESCAPES_ANNOTATION", WARNING, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val UNUSED_ESCAPES_NOTHING_ANNOTATION: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("UNUSED_ESCAPES_NOTHING_ANNOTATION", WARNING, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val UNUSED_POINTS_TO_ANNOTATION: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("UNUSED_POINTS_TO_ANNOTATION", WARNING, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING: KtDiagnosticFactory0 = KtDiagnosticFactory0("CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val MISSING_ESCAPE_ANALYSIS_ANNOTATION: KtDiagnosticFactory0 = KtDiagnosticFactory0("MISSING_ESCAPE_ANALYSIS_ANNOTATION", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE: KtDiagnosticFactory0 = KtDiagnosticFactory0("MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val INVALID_ESCAPES_VALUE: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("INVALID_ESCAPES_VALUE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val ESCAPES_MARKED_ON_NON_ESCAPING_TYPE: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("ESCAPES_MARKED_ON_NON_ESCAPING_TYPE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val INVALID_POINTS_TO_VALUE: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("INVALID_POINTS_TO_VALUE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val INVALID_POINTS_TO_INDEX: KtDiagnosticFactory3<Int, Int, String> = KtDiagnosticFactory3("INVALID_POINTS_TO_INDEX", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val POINTS_TO_KIND_1_ONLY_FOR_RETURN: KtDiagnosticFactory2<String, String> = KtDiagnosticFactory2("POINTS_TO_KIND_1_ONLY_FOR_RETURN", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val POINTS_TO_FROM_NON_ESCAPING_TYPE: KtDiagnosticFactory2<String, String> = KtDiagnosticFactory2("POINTS_TO_FROM_NON_ESCAPING_TYPE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
+ val POINTS_TO_TO_NON_ESCAPING_TYPE: KtDiagnosticFactory2<String, String> = KtDiagnosticFactory2("POINTS_TO_TO_NON_ESCAPING_TYPE", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class, getRendererFactory())
override fun getRendererFactory(): BaseDiagnosticRendererFactory = FirNativeErrorsDefaultMessages
}
diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt
index 0c765ef..f08278c 100644
--- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt
+++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt
@@ -48,6 +48,20 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.PROPERTY_MUST_BE_VAR
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.SUBTYPE_OF_HIDDEN_FROM_OBJC
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.ESCAPES_MARKED_ON_NON_ESCAPING_TYPE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_ESCAPES_VALUE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_POINTS_TO_INDEX
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_POINTS_TO_VALUE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_ESCAPE_ANALYSIS_ANNOTATION
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.POINTS_TO_FROM_NON_ESCAPING_TYPE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.POINTS_TO_KIND_1_ONLY_FOR_RETURN
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.POINTS_TO_TO_NON_ESCAPING_TYPE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.UNUSED_ESCAPES_ANNOTATION
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.UNUSED_ESCAPES_NOTHING_ANNOTATION
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.UNUSED_POINTS_TO_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.THROWS_LIST_EMPTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.UNCHECKED_CAST_TO_FORWARD_DECLARATION
@@ -176,5 +190,79 @@
"Call to ''kotlin.native.identityHashCode'' on an instance of value type ''{0}'' can have unexpected behavior.",
RENDER_TYPE,
)
+
+ // Escape analysis annotation messages
+ map.put(
+ UNUSED_ESCAPES_ANNOTATION,
+ "Unused '@Escapes': {0}",
+ TO_STRING
+ )
+ map.put(
+ UNUSED_ESCAPES_NOTHING_ANNOTATION,
+ "Unused '@Escapes.Nothing': {0}",
+ TO_STRING
+ )
+ map.put(
+ UNUSED_POINTS_TO_ANNOTATION,
+ "Unused '@PointsTo': {0}",
+ TO_STRING
+ )
+ map.put(
+ CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING,
+ "Conflicting '@Escapes' and '@Escapes.Nothing'"
+ )
+ map.put(
+ MISSING_ESCAPE_ANALYSIS_ANNOTATION,
+ "External function with parameters that may escape requires '@Escapes' or '@Escapes.Nothing' or '@PointsTo'"
+ )
+ map.put(
+ MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE,
+ "External function with parameters that must always escape is not marked by '@Escapes'"
+ )
+ map.put(
+ INVALID_ESCAPES_VALUE,
+ "@Escapes value is invalid: {0}",
+ TO_STRING
+ )
+ map.put(
+ ESCAPES_MARKED_ON_NON_ESCAPING_TYPE,
+ "{0} is marked as escaping by '@Escapes', but the type cannot escape to the heap",
+ TO_STRING
+ )
+ map.put(
+ ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE,
+ "{0} is not marked as escaping by '@Escapes', but the type must always escape to the heap",
+ TO_STRING
+ )
+ map.put(
+ INVALID_POINTS_TO_VALUE,
+ "@PointsTo value is invalid: {0}",
+ TO_STRING
+ )
+ map.put(
+ INVALID_POINTS_TO_INDEX,
+ "@PointsTo value is invalid at index {0} nibble {1}: {2}",
+ TO_STRING,
+ TO_STRING,
+ TO_STRING
+ )
+ map.put(
+ POINTS_TO_KIND_1_ONLY_FOR_RETURN,
+ "{0} is marked as pointing to {1} by '@PointsTo' with kind 1, but kind 1 is only allowed for the return value",
+ TO_STRING,
+ TO_STRING
+ )
+ map.put(
+ POINTS_TO_FROM_NON_ESCAPING_TYPE,
+ "{0} is marked as pointing to {1} by '@PointsTo', but {0}''s type cannot escape to the heap",
+ TO_STRING,
+ TO_STRING
+ )
+ map.put(
+ POINTS_TO_TO_NON_ESCAPING_TYPE,
+ "{0} is marked as pointing to {1} by '@PointsTo', but {1}''s type cannot escape to the heap",
+ TO_STRING,
+ TO_STRING
+ )
}
}
diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeEscapeAnalysisChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeEscapeAnalysisChecker.kt
new file mode 100644
index 0000000..e19e524
--- /dev/null
+++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeEscapeAnalysisChecker.kt
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.analysis.native.checkers
+
+import org.jetbrains.kotlin.backend.konan.BinaryType
+import org.jetbrains.kotlin.builtins.StandardNames
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
+import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
+import org.jetbrains.kotlin.fir.backend.native.FirInlineClassesSupport
+import org.jetbrains.kotlin.fir.declarations.*
+import org.jetbrains.kotlin.fir.declarations.utils.isExternal
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirLiteralExpression
+import org.jetbrains.kotlin.fir.expressions.FirVarargArgumentsExpression
+import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
+import org.jetbrains.kotlin.fir.resolve.toRegularClassSymbol
+import org.jetbrains.kotlin.fir.types.*
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.name.NativeRuntimeNames
+import org.jetbrains.kotlin.native.internal.Escapes
+import org.jetbrains.kotlin.native.internal.IntrinsicType
+import org.jetbrains.kotlin.native.internal.PointsTo
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+
+@OptIn(SymbolInternals::class)
+object FirNativeEscapeAnalysisChecker : FirFunctionChecker(MppCheckerKind.Common) {
+
+ // Annotation ClassIds
+ private val escapesClassId = NativeRuntimeNames.Annotations.Escapes
+ private val escapesNothingClassId = NativeRuntimeNames.Annotations.EscapesNothing
+ private val pointsToClassId = NativeRuntimeNames.Annotations.PointsTo
+ private val hasFinalizerClassId = NativeRuntimeNames.Annotations.HasFinalizer
+ private val typedIntrinsicClassId = ClassId.fromString("kotlin/native/internal/TypedIntrinsic")
+
+ // Package names
+ private val kotlinPackageFqn = FqName("kotlin")
+ private val kotlinNativeInternalPackage = FqName("kotlin.native.internal")
+ private val kotlinConcurrentFqn = kotlinPackageFqn.child(Name.identifier("concurrent"))
+ private val kotlinNativeConcurrentFqn = kotlinPackageFqn.child(Name.identifier("native")).child(Name.identifier("concurrent"))
+
+ // DFGBuilder handled symbols
+ private val symbolNamesHandledByDFG = setOf(
+ "createUninitializedInstance",
+ "createUninitializedArray",
+ "createEmptyString",
+ "reinterpret",
+ "initInstance"
+ )
+
+ // Intrinsics that must be lowered
+ private val intrinsicsThatMustBeLowered = setOf(
+ IntrinsicType.ATOMIC_GET_FIELD,
+ IntrinsicType.ATOMIC_SET_FIELD,
+ IntrinsicType.GET_CONTINUATION,
+ IntrinsicType.RETURN_IF_SUSPENDED,
+ IntrinsicType.SAVE_COROUTINE_STATE,
+ IntrinsicType.RESTORE_COROUTINE_STATE,
+ IntrinsicType.INTEROP_BITS_TO_FLOAT,
+ IntrinsicType.INTEROP_BITS_TO_DOUBLE,
+ IntrinsicType.INTEROP_SIGN_EXTEND,
+ IntrinsicType.INTEROP_NARROW,
+ IntrinsicType.INTEROP_STATIC_C_FUNCTION,
+ IntrinsicType.INTEROP_FUNPTR_INVOKE,
+ IntrinsicType.INTEROP_CONVERT,
+ IntrinsicType.ENUM_VALUES,
+ IntrinsicType.ENUM_VALUE_OF,
+ IntrinsicType.ENUM_ENTRIES,
+ IntrinsicType.WORKER_EXECUTE,
+ IntrinsicType.COMPARE_AND_SET_FIELD,
+ IntrinsicType.COMPARE_AND_EXCHANGE_FIELD,
+ IntrinsicType.GET_AND_SET_FIELD,
+ IntrinsicType.GET_AND_ADD_FIELD
+ )
+
+ context(context: CheckerContext, reporter: DiagnosticReporter)
+ override fun check(declaration: FirFunction) {
+ if (declaration !is FirSimpleFunction) return
+ // Skip compiler-generated functions
+ if (declaration.origin != FirDeclarationOrigin.Source) return
+
+ checkEscapeAnalysisAnnotations(declaration)
+ }
+
+ context(context: CheckerContext, reporter: DiagnosticReporter)
+ private fun checkEscapeAnalysisAnnotations(declaration: FirSimpleFunction) {
+ val escapesAnnotation = declaration.getAnnotationByClassId(escapesClassId, context.session)
+ val escapesNothingAnnotation = declaration.getAnnotationByClassId(escapesNothingClassId, context.session)
+ val pointsToAnnotation = declaration.getAnnotationByClassId(pointsToClassId, context.session)
+
+ val hasEscapes = escapesAnnotation != null
+ val hasEscapesNothing = escapesNothingAnnotation != null
+ val hasPointsTo = pointsToAnnotation != null
+
+ fun warnUnusedIf(condition: Boolean, message: () -> String): Any? {
+ if (!condition)
+ return Unit
+ if (hasEscapes) {
+ reporter.reportOn(escapesAnnotation.source, FirNativeErrors.UNUSED_ESCAPES_ANNOTATION, message())
+ }
+ if (hasEscapesNothing) {
+ reporter.reportOn(escapesNothingAnnotation.source, FirNativeErrors.UNUSED_ESCAPES_NOTHING_ANNOTATION, message())
+ }
+ if (hasPointsTo) {
+ reporter.reportOn(pointsToAnnotation.source, FirNativeErrors.UNUSED_POINTS_TO_ANNOTATION, message())
+ }
+ // condition satisfied, potential unused warning emitted, no need to go on with other checks
+ return null
+ }
+
+ warnUnusedIf(!declaration.isExternal) { "non-external function" } ?: return
+
+ val packageFqName = declaration.symbol.callableId.packageName
+ warnUnusedIf(!isPackageSupportedByEscapeAnalysis(packageFqName)) { "package outside EA annotation checks" } ?: return
+ warnUnusedIf(isFunctionHandledByDFG(declaration)) { "function handled manually in DFGBuilder" } ?: return
+ warnUnusedIf(isFunctionLoweredIntrinsic(declaration)) { "function is lowered in the compiler" } ?: return
+
+ val signatureElements = collectSignatureElements(declaration)
+
+ warnUnusedIf(signatureElements.all { it.type.cannotEscape(context.session) }) { "all of function parameters, receivers and the return value types cannot escape to the heap" }
+ ?: return
+
+ // All the unused checks have passed.
+ // This also means, that we now know the declaration is external, in the correct package and so on.
+ when {
+ hasEscapes && hasEscapesNothing -> {
+ reporter.reportOn(declaration.source, FirNativeErrors.CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING)
+ }
+ !hasEscapes && signatureElements.any { it.type.mustEscape(context.session) } -> {
+ reporter.reportOn(declaration.source, FirNativeErrors.MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE)
+ }
+ !hasEscapes && !hasEscapesNothing && !hasPointsTo -> {
+ reporter.reportOn(declaration.source, FirNativeErrors.MISSING_ESCAPE_ANALYSIS_ANNOTATION)
+ }
+ }
+
+ // Check annotation values
+ if (hasEscapes || hasEscapesNothing) {
+ val annotation = escapesAnnotation ?: escapesNothingAnnotation!!
+ checkEscapesAnnotation(annotation, signatureElements, isEscapesNothing = hasEscapesNothing)
+ }
+
+ pointsToAnnotation?.let {
+ checkPointsToAnnotation(it, signatureElements)
+ }
+ }
+
+ context(context: CheckerContext, reporter: DiagnosticReporter)
+ private fun checkEscapesAnnotation(
+ annotation: FirAnnotation,
+ signatureElements: List<SignatureElement>,
+ isEscapesNothing: Boolean,
+ ) {
+ val escapesValue = try {
+ if (isEscapesNothing) {
+ // @Escapes.Nothing means nothing escapes (mask = 0)
+ Escapes(0, signatureElements.size)
+ } else {
+ getEscapesValue(annotation, context.session, signatureElements.size)
+ }
+ } catch (e: IllegalArgumentException) {
+ reporter.reportOn(annotation.source, FirNativeErrors.INVALID_ESCAPES_VALUE, e.message ?: "")
+ return
+ } ?: return
+
+ signatureElements.forEachIndexed { index, element ->
+ if (escapesValue.escapesAt(index)) {
+ if (element.type.cannotEscape(context.session)) {
+ reporter.reportOn(annotation.source, FirNativeErrors.ESCAPES_MARKED_ON_NON_ESCAPING_TYPE, element.name)
+ }
+ } else {
+ if (element.type.mustEscape(context.session)) {
+ reporter.reportOn(annotation.source, FirNativeErrors.ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE, element.name)
+ }
+ }
+ }
+ }
+
+ context(context: CheckerContext, reporter: DiagnosticReporter)
+ private fun checkPointsToAnnotation(
+ annotation: FirAnnotation,
+ signatureElements: List<SignatureElement>,
+ ) {
+ val pointsToValue = try {
+ getPointsToValue(annotation, context.session, signatureElements.size)
+ } catch (e: IllegalArgumentException) {
+ reporter.reportOn(annotation.source, FirNativeErrors.INVALID_POINTS_TO_VALUE, e.message ?: "")
+ return
+ } ?: return
+
+ for (indexFrom in signatureElements.indices) {
+ val from = signatureElements[indexFrom]
+ for (indexTo in signatureElements.indices) {
+ val to = signatureElements[indexTo]
+ val kind = try {
+ pointsToValue.kind(indexFrom, indexTo)
+ } catch (e: IllegalArgumentException) {
+ reporter.reportOn(annotation.source, FirNativeErrors.INVALID_POINTS_TO_INDEX, indexFrom, indexTo, e.message ?: "")
+ null
+ } ?: continue
+
+ if (kind.sourceIsDirect && kind.destinationIsDirect) {
+ if (from.name != "<return>") {
+ reporter.reportOn(annotation.source, FirNativeErrors.POINTS_TO_KIND_1_ONLY_FOR_RETURN, from.name, to.name)
+ }
+ }
+ if (from.type.cannotEscape(context.session)) {
+ reporter.reportOn(annotation.source, FirNativeErrors.POINTS_TO_FROM_NON_ESCAPING_TYPE, from.name, to.name)
+ break
+ }
+ if (to.type.cannotEscape(context.session)) {
+ reporter.reportOn(annotation.source, FirNativeErrors.POINTS_TO_TO_NON_ESCAPING_TYPE, from.name, to.name)
+ }
+ }
+ }
+ }
+
+ private fun getEscapesValue(annotation: FirAnnotation, session: FirSession, signatureSize: Int): Escapes? {
+ val argument = annotation.findArgumentByName(StandardNames.NAME, returnFirstWhenNotFound = true) ?: return null
+ val literal = argument.evaluateAs<FirLiteralExpression>(session) ?: return null
+ val value = literal.value as? Int ?: return null
+ return Escapes(value, signatureSize)
+ }
+
+ private fun getPointsToValue(annotation: FirAnnotation, session: FirSession, signatureSize: Int): PointsTo? {
+ val argument = annotation.findArgumentByName(StandardNames.NAME, returnFirstWhenNotFound = true) ?: return null
+ // PointsTo takes a vararg of integers
+ val values = when (argument) {
+ is FirVarargArgumentsExpression -> {
+ argument.arguments.map { arg ->
+ val literal = arg.evaluateAs<FirLiteralExpression>(session) ?: return null
+ literal.value as? Int ?: return null
+ }
+ }
+ else -> {
+ // Single value case (shouldn't happen for valid PointsTo, but handle gracefully)
+ val literal = argument.evaluateAs<FirLiteralExpression>(session) ?: return null
+ val value = literal.value as? Int ?: return null
+ listOf(value)
+ }
+ }
+ return PointsTo(values, signatureSize)
+ }
+
+ private fun ConeKotlinType.cannotEscape(session: FirSession): Boolean {
+ val type = this.fullyExpandedType(session)
+ return type.isUnit || type.isNothing || FirInlineClassesSupport(session).computeBinaryType(type) is BinaryType.Primitive
+ }
+
+ private fun ConeKotlinType.mustEscape(session: FirSession): Boolean {
+ val classSymbol = toRegularClassSymbol(session) ?: return false
+ return classSymbol.getAnnotationByClassId(hasFinalizerClassId, session) != null
+ }
+
+ private data class SignatureElement(val name: String, val type: ConeKotlinType)
+
+ // Helper functions
+ private fun isPackageSupportedByEscapeAnalysis(packageFqName: FqName): Boolean =
+ packageFqName.startsWith(kotlinPackageFqn) &&
+ !packageFqName.startsWith(kotlinConcurrentFqn) &&
+ !packageFqName.startsWith(kotlinNativeConcurrentFqn)
+
+ context(context: CheckerContext)
+ private fun isFunctionHandledByDFG(function: FirSimpleFunction): Boolean {
+ val callableId = function.symbol.callableId
+ return callableId.packageName == kotlinNativeInternalPackage &&
+ function.name.asString() in symbolNamesHandledByDFG
+ }
+
+ context(context: CheckerContext)
+ private fun isFunctionLoweredIntrinsic(function: FirSimpleFunction): Boolean {
+ val intrinsicType = getIntrinsicType(function) ?: return false
+ return intrinsicType in intrinsicsThatMustBeLowered
+ }
+
+ private fun collectSignatureElements(declaration: FirSimpleFunction): List<SignatureElement> = buildList {
+ declaration.dispatchReceiverType?.let {
+ add(SignatureElement("<this>", it))
+ }
+ declaration.contextParameters.forEach { contextParam ->
+ add(SignatureElement(contextParam.name.asString(), contextParam.returnTypeRef.coneType))
+ }
+ declaration.receiverParameter?.let {
+ add(SignatureElement("<receiver>", it.typeRef.coneType))
+ }
+ declaration.valueParameters.forEach {
+ add(SignatureElement(it.name.asString(), it.returnTypeRef.coneType))
+ }
+ add(SignatureElement("<return>", declaration.returnTypeRef.coneType))
+ }
+
+ context(context: CheckerContext)
+ private fun getIntrinsicType(function: FirSimpleFunction): IntrinsicType? {
+ val annotation = function.getAnnotationByClassId(typedIntrinsicClassId, context.session) ?: return null
+ val kindArgument = annotation.findArgumentByName(Name.identifier("kind"), returnFirstWhenNotFound = true) ?: return null
+ val literal = kindArgument.evaluateAs<FirLiteralExpression>(context.session) ?: return null
+ val kindString = literal.value as? String ?: return null
+
+ return try {
+ IntrinsicType.valueOf(kindString)
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt
index 60fd1c6..afb8ded 100644
--- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt
+++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt
@@ -21,7 +21,8 @@
override val functionCheckers: Set<FirFunctionChecker>
get() = setOf(
- FirNativeObjcOverrideApplicabilityChecker
+ FirNativeObjcOverrideApplicabilityChecker,
+ FirNativeEscapeAnalysisChecker
)
override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker>
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
index dc04bf9..5a137d6 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
@@ -826,6 +826,17 @@
"CONSTRUCTOR_MATCHES_SEVERAL_SUPER_CONSTRUCTORS",
"CONFLICTING_OBJC_OVERLOADS",
"INAPPLICABLE_OBJC_OVERRIDE",
+ "CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING",
+ "MISSING_ESCAPE_ANALYSIS_ANNOTATION",
+ "MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE",
+ "INVALID_ESCAPES_VALUE",
+ "ESCAPES_MARKED_ON_NON_ESCAPING_TYPE",
+ "ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE",
+ "INVALID_POINTS_TO_VALUE",
+ "INVALID_POINTS_TO_INDEX",
+ "POINTS_TO_KIND_1_ONLY_FOR_RETURN",
+ "POINTS_TO_FROM_NON_ESCAPING_TYPE",
+ "POINTS_TO_TO_NON_ESCAPING_TYPE",
"NESTED_EXTERNAL_DECLARATION",
"WRONG_EXTERNAL_DECLARATION",
"NESTED_CLASS_IN_EXTERNAL_INTERFACE",
diff --git a/compiler/fir/fir-native/src/org/jetbrains/kotlin/fir/backend/native/FirInlineClassesSupport.kt b/compiler/fir/fir-native/src/org/jetbrains/kotlin/fir/backend/native/FirInlineClassesSupport.kt
new file mode 100644
index 0000000..f80d6710
--- /dev/null
+++ b/compiler/fir/fir-native/src/org/jetbrains/kotlin/fir/backend/native/FirInlineClassesSupport.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.backend.native
+
+import org.jetbrains.kotlin.backend.konan.InlineClassesSupport
+import org.jetbrains.kotlin.backend.konan.InteropFqNames
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirClass
+import org.jetbrains.kotlin.fir.declarations.FirRegularClass
+import org.jetbrains.kotlin.fir.declarations.inlineClassRepresentation
+import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
+import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
+import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
+import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
+import org.jetbrains.kotlin.fir.resolve.toRegularClassSymbol
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+import org.jetbrains.kotlin.fir.types.*
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+
+@OptIn(SymbolInternals::class)
+class FirInlineClassesSupport(private val session: FirSession) : InlineClassesSupport<FirClass, ConeKotlinType>() {
+ override fun isNullable(type: ConeKotlinType): Boolean {
+ return type.isMarkedNullable
+ }
+
+ override fun makeNullable(type: ConeKotlinType): ConeKotlinType {
+ return type.withNullability(nullable = true, session.typeContext)
+ }
+
+ override fun erase(type: ConeKotlinType): FirClass {
+ val expandedType = type.fullyExpandedType(session)
+ return when (expandedType) {
+ is ConeClassLikeType -> {
+ val symbol = expandedType.lookupTag.toRegularClassSymbol(session)
+ ?: error("Cannot find class for ${expandedType.lookupTag}")
+ symbol.fir
+ }
+ is ConeTypeParameterType -> {
+ // For type parameters, we need to look at their bounds
+ val symbol = expandedType.lookupTag.symbol
+ val bounds = symbol.resolvedBounds
+ val firstBound = bounds.firstOrNull()?.coneType ?: session.builtinTypes.anyType.coneType
+ erase(firstBound)
+ }
+ else -> error("Unexpected type: $expandedType")
+ }
+ }
+
+ override fun computeFullErasure(type: ConeKotlinType): Sequence<FirClass> {
+ val expandedType = type.fullyExpandedType(session)
+ return when (expandedType) {
+ is ConeClassLikeType -> {
+ val symbol = expandedType.lookupTag.toRegularClassSymbol(session)
+ ?: error("Cannot find class for ${expandedType.lookupTag}")
+ sequenceOf(symbol.fir)
+ }
+ is ConeTypeParameterType -> {
+ val symbol = expandedType.lookupTag.symbol
+ symbol.resolvedBounds.asSequence()
+ .flatMap { computeFullErasure(it.coneType) }
+ .ifEmpty { sequenceOf(erase(session.builtinTypes.anyType.coneType)) }
+ }
+ else -> error("Unexpected type: $expandedType")
+ }
+ }
+
+ override fun hasInlineModifier(clazz: FirClass): Boolean {
+ return clazz is FirRegularClass && clazz.isInlineOrValue
+ }
+
+ override fun getNativePointedSuperclass(clazz: FirClass): FirClass? {
+ if (clazz !is FirRegularClass) return null
+
+ var currentClass: FirRegularClass? = clazz
+ while (currentClass != null) {
+ if (currentClass.symbol.classId.asSingleFqName() == InteropFqNames.nativePointed) {
+ return currentClass
+ }
+
+ val superTypes = currentClass.superConeTypes
+ currentClass = superTypes.firstOrNull()?.toRegularClassSymbol(session)?.fir
+ }
+
+ return null
+ }
+
+ override fun getInlinedClassUnderlyingType(clazz: FirClass): ConeKotlinType {
+ require(clazz is FirRegularClass) { "Expected FirRegularClass but got ${clazz::class.simpleName}" }
+
+ // First try to get from inline class representation (for already resolved classes)
+ clazz.inlineClassRepresentation?.underlyingType?.let { return it }
+
+ // Otherwise, get from primary constructor parameter
+ val primaryConstructor = clazz.primaryConstructorIfAny(session)?.fir
+ val parameter = primaryConstructor?.valueParameters?.singleOrNull()
+ ?: error("Inline class $clazz should have exactly one value parameter")
+
+ return parameter.returnTypeRef.coneType
+ }
+
+ override fun getPackageFqName(clazz: FirClass): FqName? {
+ return clazz.symbol.classId.packageFqName.takeUnless { it.isRoot }
+ }
+
+ override fun getName(clazz: FirClass): Name? {
+ return clazz.symbol.classId.shortClassName.takeUnless { it.isSpecial }
+ }
+
+ override fun isTopLevelClass(clazz: FirClass): Boolean {
+ return !clazz.symbol.classId.isNestedClass
+ }
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.fir.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.fir.kt
new file mode 100644
index 0000000..c7f90a4
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.fir.kt
@@ -0,0 +1,98 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
+
+// MODULE: escape
+
+package kotlin.native.internal.escapeAnalysis
+
+// Annotations for testing
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.BINARY)
+annotation class HasFinalizer
+
+// MODULE: main(escape)
+package kotlin.native.internal
+
+import kotlin.native.internal.escapeAnalysis.*
+
+// Valid external functions with escape annotations
+@Escapes(0b01)
+external fun externalFun1(x: Any): Any
+
+@Escapes(0b11)
+external fun externalFun2(x: Any, y: Any): Unit
+
+@Escapes.Nothing
+external fun externalFunNothing(x: Any): Any
+
+@PointsTo(0, 1)
+external fun externalFunPointsTo(x: Any): Any
+
+// Non-external functions - annotations should be unused
+<!UNUSED_ESCAPES_ANNOTATION("non-external function")!>@Escapes(0b01)<!>
+fun regularFun1(x: Any): Any = x
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("non-external function")!>@Escapes.Nothing<!>
+fun regularFun2(x: Any): Any = x
+
+<!UNUSED_POINTS_TO_ANNOTATION("non-external function")!>@PointsTo(0, 1)<!>
+fun regularFun3(x: Any): Any = x
+
+// External function without required annotations
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalFunNoAnnotation(x: Any): Any<!>
+
+// Conflicting annotations
+<!CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING!>@Escapes(0b01)
+@Escapes.Nothing
+external fun externalFunConflicting(x: Any): Any<!>
+
+// External functions with primitive types that cannot escape
+<!UNUSED_ESCAPES_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes(0b111)<!>
+external fun externalPrimitives(x: Int, y: Boolean): Double
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes.Nothing<!>
+external fun externalUnit(x: Int): Unit
+
+<!UNUSED_POINTS_TO_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@PointsTo(0, 1)<!>
+external fun externalNothing(x: Int): Nothing
+
+// Class with HasFinalizer
+@HasFinalizer
+class FinalizableClass
+
+// External function with must-escape type but no @Escapes
+<!MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE!>external fun externalWithFinalizer(x: FinalizableClass): Any<!>
+
+// Valid use with finalizer
+@Escapes(0b01)
+external fun externalWithFinalizerOk(x: FinalizableClass): Any
+
+// Invalid escapes value
+<!INVALID_ESCAPES_VALUE("0 must not be negative and not have bits higher than 2")!>@Escapes(-1)<!>
+external fun externalInvalidEscapes(x: Any): Any
+
+// Escapes marked on non-escaping type
+<!ESCAPES_MARKED_ON_NON_ESCAPING_TYPE("x")!>@Escapes(0b01)<!>
+external fun externalEscapesOnPrimitive(x: Int): Any
+
+// Escapes not marked on must-escape type
+<!ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE("x")!>@Escapes(0b10)<!>
+external fun externalNoEscapeForFinalizer(x: FinalizableClass): Any
+
+// Extension functions
+<!UNUSED_ESCAPES_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes(0b111)<!>
+external fun Int.externalExtension(x: Int): Int
+
+@Escapes(0b001)
+external fun Any.externalExtensionAny(x: Int): Any
+
+// Vararg parameters
+@Escapes(0b11)
+external fun externalVararg(vararg x: Any): Any
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.kt
new file mode 100644
index 0000000..1479d13
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisBasic.kt
@@ -0,0 +1,93 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
+
+package kotlin.native.internal
+
+import kotlin.native.internal.*
+
+// Annotations for testing
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.BINARY)
+annotation class HasFinalizer
+
+// Valid external functions with escape annotations
+@Escapes(0b01)
+external fun externalFun1(x: Any): Any
+
+@Escapes(0b11)
+external fun externalFun2(x: Any, y: Any): Unit
+
+@Escapes.Nothing
+external fun externalFunNothing(x: Any): Any
+
+@PointsTo(0, 1)
+external fun externalFunPointsTo(x: Any): Any
+
+// Non-external functions - annotations should be unused
+<!UNUSED_ESCAPES_ANNOTATION("non-external function")!>@Escapes(0b01)<!>
+fun regularFun1(x: Any): Any = x
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("non-external function")!>@Escapes.Nothing<!>
+fun regularFun2(x: Any): Any = x
+
+<!UNUSED_POINTS_TO_ANNOTATION("non-external function")!>@PointsTo(0, 1)<!>
+fun regularFun3(x: Any): Any = x
+
+// External function without required annotations
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalFunNoAnnotation(x: Any): Any<!>
+
+// Conflicting annotations
+<!CONFLICTING_ESCAPES_AND_ESCAPES_NOTHING!>@Escapes(0b01)
+@Escapes.Nothing
+external fun externalFunConflicting(x: Any): Any<!>
+
+// External functions with primitive types that cannot escape
+<!UNUSED_ESCAPES_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes(0b111)<!>
+external fun externalPrimitives(x: Int, y: Boolean): Double
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes.Nothing<!>
+external fun externalUnit(x: Int): Unit
+
+<!UNUSED_POINTS_TO_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@PointsTo(0, 1)<!>
+external fun externalNothing(x: Int): Nothing
+
+// Class with HasFinalizer
+@HasFinalizer
+class FinalizableClass
+
+// External function with must-escape type but no @Escapes
+<!MISSING_ESCAPES_FOR_MUST_ESCAPE_TYPE!>external fun externalWithFinalizer(x: FinalizableClass): Any<!>
+
+// Valid use with finalizer
+@Escapes(0b01)
+external fun externalWithFinalizerOk(x: FinalizableClass): Any
+
+// Invalid escapes value
+<!INVALID_ESCAPES_VALUE("")!>@Escapes(-1)<!>
+external fun externalInvalidEscapes(x: Any): Any
+
+// Escapes marked on non-escaping type
+<!ESCAPES_MARKED_ON_NON_ESCAPING_TYPE("x")!>@Escapes(0b01)<!>
+external fun externalEscapesOnPrimitive(x: Int): Any
+
+// Escapes not marked on must-escape type
+<!ESCAPES_NOT_MARKED_ON_MUST_ESCAPE_TYPE("x")!>@Escapes(0b10)<!>
+external fun externalNoEscapeForFinalizer(x: FinalizableClass): Any
+
+// Extension functions
+<!UNUSED_ESCAPES_ANNOTATION("all of function parameters, receivers and the return value types cannot escape to the heap")!>@Escapes(0b111)<!>
+external fun Int.externalExtension(x: Int): Int
+
+@Escapes(0b001)
+external fun Any.externalExtensionAny(x: Int): Any
+
+// Vararg parameters
+@Escapes(0b11)
+external fun externalVararg(vararg x: Any): Any
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.fir.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.fir.kt
new file mode 100644
index 0000000..52c4b13
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.fir.kt
@@ -0,0 +1,80 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER
+
+package kotlin.native.internal
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class TypedIntrinsic(val kind: String)
+
+// DFG-handled functions - annotations should be unused
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun createUninitializedInstance(): Any
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes.Nothing<!>
+external fun createUninitializedArray(): Any
+
+<!UNUSED_POINTS_TO_ANNOTATION("function handled manually in DFGBuilder")!>@PointsTo(0x01)<!>
+external fun createEmptyString(): String
+
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun reinterpret(x: Any): Any
+
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun initInstance(x: Any): Any
+
+// No error for DFG functions without annotations
+external fun createUninitializedInstanceNoAnnotation(): Any
+
+// Lowered intrinsics - annotations should be unused
+@TypedIntrinsic("ATOMIC_GET_FIELD")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun atomicGetField(x: Any): Any
+
+@TypedIntrinsic("GET_CONTINUATION")
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("function is lowered in the compiler")!>@Escapes.Nothing<!>
+external fun getContinuation(): Any
+
+@TypedIntrinsic("ENUM_VALUES")
+<!UNUSED_POINTS_TO_ANNOTATION("function is lowered in the compiler")!>@PointsTo(0x01)<!>
+external fun enumValues(): Any
+
+@TypedIntrinsic("INTEROP_BITS_TO_FLOAT")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun bitsToFloat(x: Int): Float
+
+@TypedIntrinsic("WORKER_EXECUTE")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun workerExecute(x: Any): Any
+
+// No error for intrinsics without annotations
+@TypedIntrinsic("ATOMIC_SET_FIELD")
+external fun atomicSetFieldNoAnnotation(x: Any, y: Any): Unit
+
+// Non-lowered intrinsic (should still require annotations)
+@TypedIntrinsic("PLUS")
+@Escapes(0b01)
+external fun plusIntrinsic(x: Any): Any
+
+@TypedIntrinsic("REINTERPRET")
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun reinterpretIntrinsicNoAnnotation(x: Any): Any<!>
+
+// Invalid intrinsic type doesn't affect checking
+@TypedIntrinsic("INVALID_INTRINSIC_TYPE")
+@Escapes(0b01)
+external fun invalidIntrinsicType(x: Any): Any
+
+// Functions with similar names but different packages should still be checked
+package kotlin.collections
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun createUninitializedInstance(): Any<!>
+
+@Escapes(0b01)
+external fun reinterpret(x: Any): Any
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.kt
new file mode 100644
index 0000000..52c4b13
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisDfgAndIntrinsics.kt
@@ -0,0 +1,80 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER
+
+package kotlin.native.internal
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class TypedIntrinsic(val kind: String)
+
+// DFG-handled functions - annotations should be unused
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun createUninitializedInstance(): Any
+
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes.Nothing<!>
+external fun createUninitializedArray(): Any
+
+<!UNUSED_POINTS_TO_ANNOTATION("function handled manually in DFGBuilder")!>@PointsTo(0x01)<!>
+external fun createEmptyString(): String
+
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun reinterpret(x: Any): Any
+
+<!UNUSED_ESCAPES_ANNOTATION("function handled manually in DFGBuilder")!>@Escapes(0b01)<!>
+external fun initInstance(x: Any): Any
+
+// No error for DFG functions without annotations
+external fun createUninitializedInstanceNoAnnotation(): Any
+
+// Lowered intrinsics - annotations should be unused
+@TypedIntrinsic("ATOMIC_GET_FIELD")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun atomicGetField(x: Any): Any
+
+@TypedIntrinsic("GET_CONTINUATION")
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("function is lowered in the compiler")!>@Escapes.Nothing<!>
+external fun getContinuation(): Any
+
+@TypedIntrinsic("ENUM_VALUES")
+<!UNUSED_POINTS_TO_ANNOTATION("function is lowered in the compiler")!>@PointsTo(0x01)<!>
+external fun enumValues(): Any
+
+@TypedIntrinsic("INTEROP_BITS_TO_FLOAT")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun bitsToFloat(x: Int): Float
+
+@TypedIntrinsic("WORKER_EXECUTE")
+<!UNUSED_ESCAPES_ANNOTATION("function is lowered in the compiler")!>@Escapes(0b01)<!>
+external fun workerExecute(x: Any): Any
+
+// No error for intrinsics without annotations
+@TypedIntrinsic("ATOMIC_SET_FIELD")
+external fun atomicSetFieldNoAnnotation(x: Any, y: Any): Unit
+
+// Non-lowered intrinsic (should still require annotations)
+@TypedIntrinsic("PLUS")
+@Escapes(0b01)
+external fun plusIntrinsic(x: Any): Any
+
+@TypedIntrinsic("REINTERPRET")
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun reinterpretIntrinsicNoAnnotation(x: Any): Any<!>
+
+// Invalid intrinsic type doesn't affect checking
+@TypedIntrinsic("INVALID_INTRINSIC_TYPE")
+@Escapes(0b01)
+external fun invalidIntrinsicType(x: Any): Any
+
+// Functions with similar names but different packages should still be checked
+package kotlin.collections
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun createUninitializedInstance(): Any<!>
+
+@Escapes(0b01)
+external fun reinterpret(x: Any): Any
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.fir.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.fir.kt
new file mode 100644
index 0000000..f506e21
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.fir.kt
@@ -0,0 +1,73 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER
+
+// FILE: annotations.kt
+package kotlin.native.internal
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+// FILE: kotlin_package.kt
+package kotlin.collections
+
+import kotlin.native.internal.*
+
+// Functions in kotlin package are checked
+@Escapes(0b01)
+external fun externalInKotlin(x: Any): Any
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalInKotlinNoAnnotation(x: Any): Any<!>
+
+// FILE: kotlin_concurrent.kt
+package kotlin.concurrent
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.concurrent are NOT checked
+<!UNUSED_ESCAPES_ANNOTATION("package outside EA annotation checks")!>@Escapes(0b01)<!>
+external fun externalInConcurrent(x: Any): Any
+
+// No error for missing annotation
+external fun externalInConcurrentNoAnnotation(x: Any): Any
+
+// FILE: kotlin_native_concurrent.kt
+package kotlin.native.concurrent
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.native.concurrent are NOT checked
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("package outside EA annotation checks")!>@Escapes.Nothing<!>
+external fun externalInNativeConcurrent(x: Any): Any
+
+// No error for missing annotation
+external fun externalInNativeConcurrentNoAnnotation(x: Any): Any
+
+// FILE: other_package.kt
+package com.example
+
+import kotlin.native.internal.*
+
+// Functions outside kotlin package are NOT checked
+<!UNUSED_ESCAPES_ANNOTATION("package outside EA annotation checks")!>@Escapes(0b01)<!>
+external fun externalOutsideKotlin(x: Any): Any
+
+<!UNUSED_POINTS_TO_ANNOTATION("package outside EA annotation checks")!>@PointsTo(0x10)<!>
+external fun externalOutsideKotlinPointsTo(x: Any): Any
+
+// No error for missing annotation
+external fun externalOutsideKotlinNoAnnotation(x: Any): Any
+
+// FILE: kotlin_text.kt
+package kotlin.text
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.text ARE checked (subpackage of kotlin)
+@Escapes(0b01)
+external fun externalInKotlinText(x: Any): Any
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalInKotlinTextNoAnnotation(x: Any): Any<!>
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.kt
new file mode 100644
index 0000000..f506e21
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPackages.kt
@@ -0,0 +1,73 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER
+
+// FILE: annotations.kt
+package kotlin.native.internal
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+// FILE: kotlin_package.kt
+package kotlin.collections
+
+import kotlin.native.internal.*
+
+// Functions in kotlin package are checked
+@Escapes(0b01)
+external fun externalInKotlin(x: Any): Any
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalInKotlinNoAnnotation(x: Any): Any<!>
+
+// FILE: kotlin_concurrent.kt
+package kotlin.concurrent
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.concurrent are NOT checked
+<!UNUSED_ESCAPES_ANNOTATION("package outside EA annotation checks")!>@Escapes(0b01)<!>
+external fun externalInConcurrent(x: Any): Any
+
+// No error for missing annotation
+external fun externalInConcurrentNoAnnotation(x: Any): Any
+
+// FILE: kotlin_native_concurrent.kt
+package kotlin.native.concurrent
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.native.concurrent are NOT checked
+<!UNUSED_ESCAPES_NOTHING_ANNOTATION("package outside EA annotation checks")!>@Escapes.Nothing<!>
+external fun externalInNativeConcurrent(x: Any): Any
+
+// No error for missing annotation
+external fun externalInNativeConcurrentNoAnnotation(x: Any): Any
+
+// FILE: other_package.kt
+package com.example
+
+import kotlin.native.internal.*
+
+// Functions outside kotlin package are NOT checked
+<!UNUSED_ESCAPES_ANNOTATION("package outside EA annotation checks")!>@Escapes(0b01)<!>
+external fun externalOutsideKotlin(x: Any): Any
+
+<!UNUSED_POINTS_TO_ANNOTATION("package outside EA annotation checks")!>@PointsTo(0x10)<!>
+external fun externalOutsideKotlinPointsTo(x: Any): Any
+
+// No error for missing annotation
+external fun externalOutsideKotlinNoAnnotation(x: Any): Any
+
+// FILE: kotlin_text.kt
+package kotlin.text
+
+import kotlin.native.internal.*
+
+// Functions in kotlin.text ARE checked (subpackage of kotlin)
+@Escapes(0b01)
+external fun externalInKotlinText(x: Any): Any
+
+<!MISSING_ESCAPE_ANALYSIS_ANNOTATION!>external fun externalInKotlinTextNoAnnotation(x: Any): Any<!>
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.fir.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.fir.kt
new file mode 100644
index 0000000..f91ec82
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.fir.kt
@@ -0,0 +1,60 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
+
+package kotlin.native.internal
+
+import kotlin.native.internal.*
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+// Valid PointsTo annotations
+@PointsTo(0x10)
+external fun validPointsTo1(x: Any): Any
+
+@PointsTo(0x10, 0x01)
+external fun validPointsTo2(x: Any, y: Any): Any
+
+// Invalid PointsTo value
+<!INVALID_POINTS_TO_VALUE("null cannot be cast to non-null type kotlin.Int")!>@PointsTo()<!>
+external fun invalidPointsToEmpty(x: Any): Any
+
+// PointsTo with kind 1 only allowed for return
+<!POINTS_TO_KIND_1_ONLY_FOR_RETURN("x", "y")!>@PointsTo(0x11)<!>
+external fun invalidKind1(x: Any, y: Any): Any
+
+// Valid kind 1 for return
+@PointsTo(0x01)
+external fun validKind1Return(x: Any): Any
+
+// PointsTo from non-escaping type
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("x", "<return>")!>@PointsTo(0x10)<!>
+external fun pointsToFromPrimitive(x: Int): Any
+
+// PointsTo to non-escaping type
+<!POINTS_TO_TO_NON_ESCAPING_TYPE("<return>", "x")!>@PointsTo(0x01)<!>
+external fun pointsToPrimitive(x: Any): Int
+
+// Complex PointsTo with multiple errors
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("x", "y")!>@PointsTo(0x20, 0x12)<!>
+external fun complexPointsTo(x: Int, y: Any, z: Any): Any
+
+// PointsTo with receiver
+@PointsTo(0x10)
+external fun Any.pointsToWithReceiver(x: Any): Any
+
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("<receiver>", "x")!>@PointsTo(0x10)<!>
+external fun Int.pointsToFromPrimitiveReceiver(x: Any): Any
+
+// Invalid PointsTo index
+<!INVALID_POINTS_TO_INDEX(0, 5, "value 1048576 too large for signature of size 2")!>@PointsTo(0x100000)<!>
+external fun invalidPointsToIndex(x: Any): Any
+
+// Combination with Escapes
+@Escapes(0b11)
+@PointsTo(0x10)
+external fun combinedAnnotations(x: Any): Any
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.kt b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.kt
new file mode 100644
index 0000000..dc77f09
--- /dev/null
+++ b/compiler/testData/diagnostics/nativeTests/escapeAnalysisPointsTo.kt
@@ -0,0 +1,60 @@
+// DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
+
+package kotlin.native.internal
+
+import kotlin.native.internal.*
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class PointsTo(vararg val value: Int)
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+annotation class Escapes(val value: Int)
+
+// Valid PointsTo annotations
+@PointsTo(0x10)
+external fun validPointsTo1(x: Any): Any
+
+@PointsTo(0x10, 0x01)
+external fun validPointsTo2(x: Any, y: Any): Any
+
+// Invalid PointsTo value
+<!INVALID_POINTS_TO_VALUE("")!>@PointsTo()<!>
+external fun invalidPointsToEmpty(x: Any): Any
+
+// PointsTo with kind 1 only allowed for return
+<!POINTS_TO_KIND_1_ONLY_FOR_RETURN("x", "y")!>@PointsTo(0x11)<!>
+external fun invalidKind1(x: Any, y: Any): Any
+
+// Valid kind 1 for return
+@PointsTo(0x01)
+external fun validKind1Return(x: Any): Any
+
+// PointsTo from non-escaping type
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("x", "<return>")!>@PointsTo(0x10)<!>
+external fun pointsToFromPrimitive(x: Int): Any
+
+// PointsTo to non-escaping type
+<!POINTS_TO_TO_NON_ESCAPING_TYPE("<return>", "x")!>@PointsTo(0x01)<!>
+external fun pointsToPrimitive(x: Any): Int
+
+// Complex PointsTo with multiple errors
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("x", "y")!>@PointsTo(0x20, 0x12)<!>
+external fun complexPointsTo(x: Int, y: Any, z: Any): Any
+
+// PointsTo with receiver
+@PointsTo(0x10)
+external fun Any.pointsToWithReceiver(x: Any): Any
+
+<!POINTS_TO_FROM_NON_ESCAPING_TYPE("<receiver>", "x")!>@PointsTo(0x10)<!>
+external fun Int.pointsToFromPrimitiveReceiver(x: Any): Any
+
+// Invalid PointsTo index
+<!INVALID_POINTS_TO_INDEX(0, 5, "")!>@PointsTo(0x100000)<!>
+external fun invalidPointsToIndex(x: Any): Any
+
+// Combination with Escapes
+@Escapes(0b11)
+@PointsTo(0x10)
+external fun combinedAnnotations(x: Any): Any
\ No newline at end of file
diff --git a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/BinaryType.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt
similarity index 100%
rename from native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/BinaryType.kt
rename to core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt
diff --git a/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InlineClassesSupport.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InlineClassesSupport.kt
new file mode 100644
index 0000000..6627dbd
--- /dev/null
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InlineClassesSupport.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.backend.konan
+
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import kotlin.collections.get
+
+abstract class InlineClassesSupport<Class : Any, Type : Any> {
+ abstract fun isNullable(type: Type): Boolean
+
+ abstract fun makeNullable(type: Type): Type
+ protected abstract fun erase(type: Type): Class
+ protected abstract fun computeFullErasure(type: Type): Sequence<Class>
+ protected abstract fun hasInlineModifier(clazz: Class): Boolean
+ protected abstract fun getNativePointedSuperclass(clazz: Class): Class?
+
+ abstract fun getInlinedClassUnderlyingType(clazz: Class): Type
+ protected abstract fun getPackageFqName(clazz: Class): FqName?
+ protected abstract fun getName(clazz: Class): Name?
+ abstract fun isTopLevelClass(clazz: Class): Boolean
+
+ @JvmName("classIsInlined")
+ fun isInlined(clazz: Class): Boolean = getInlinedClass(clazz) != null
+ fun isInlined(type: Type): Boolean = getInlinedClass(type) != null
+
+ fun isUsedAsBoxClass(clazz: Class) = getInlinedClass(clazz) == clazz // To handle NativePointed subclasses.
+
+ fun getInlinedClass(type: Type): Class? =
+ getInlinedClass(erase(type), isNullable(type))
+
+ fun getKonanPrimitiveType(clazz: Class): KonanPrimitiveType? =
+ if (isTopLevelClass(clazz))
+ KonanPrimitiveType.byFqNameParts[getPackageFqName(clazz)]?.get(getName(clazz))
+ else null
+
+ fun isImplicitInlineClass(clazz: Class): Boolean =
+ isTopLevelClass(clazz) && (getKonanPrimitiveType(clazz) != null ||
+ getName(clazz) == KonanFqNames.nativePtr.shortName() && getPackageFqName(clazz) == KonanFqNames.internalPackageName ||
+ getName(clazz) == InteropFqNames.cPointer.shortName() && getPackageFqName(clazz) == InteropFqNames.cPointer.parent()
+ .toSafe())
+
+ private fun getInlinedClass(erased: Class, isNullable: Boolean): Class? {
+ val inlinedClass = getInlinedClass(erased) ?: return null
+ return if (!isNullable || representationIsNonNullReferenceOrPointer(inlinedClass)) {
+ inlinedClass
+ } else {
+ null
+ }
+ }
+
+ tailrec fun representationIsNonNullReferenceOrPointer(clazz: Class): Boolean {
+ val konanPrimitiveType = getKonanPrimitiveType(clazz)
+ if (konanPrimitiveType != null) {
+ return konanPrimitiveType == KonanPrimitiveType.NON_NULL_NATIVE_PTR
+ }
+
+ val inlinedClass = getInlinedClass(clazz) ?: return true
+
+ val underlyingType = getInlinedClassUnderlyingType(inlinedClass)
+ return if (isNullable(underlyingType)) {
+ false
+ } else {
+ representationIsNonNullReferenceOrPointer(erase(underlyingType))
+ }
+ }
+
+ @JvmName("classGetInlinedClass")
+ private fun getInlinedClass(clazz: Class): Class? =
+ if (hasInlineModifier(clazz) || isImplicitInlineClass(clazz)) {
+ clazz
+ } else {
+ getNativePointedSuperclass(clazz)
+ }
+
+ inline fun <R> unwrapToPrimitiveOrReference(
+ type: Type,
+ eachInlinedClass: (inlinedClass: Class, nullable: Boolean) -> Unit,
+ ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
+ ifReference: (type: Type) -> R,
+ ): R {
+ var currentType: Type = type
+
+ while (true) {
+ val inlinedClass = getInlinedClass(currentType)
+ if (inlinedClass == null) {
+ return ifReference(currentType)
+ }
+
+ val nullable = isNullable(currentType)
+
+ getKonanPrimitiveType(inlinedClass)?.let { primitiveType ->
+ return ifPrimitive(primitiveType, nullable)
+ }
+
+ eachInlinedClass(inlinedClass, nullable)
+
+ val underlyingType = getInlinedClassUnderlyingType(inlinedClass)
+ currentType = if (nullable) makeNullable(underlyingType) else underlyingType
+ }
+ }
+
+ fun representationIsNullable(type: Type): Boolean {
+ unwrapToPrimitiveOrReference(
+ type,
+ eachInlinedClass = { _, nullable -> if (nullable) return true },
+ ifPrimitive = { _, nullable -> return nullable },
+ ifReference = { return isNullable(it) }
+ )
+ }
+
+ // TODO: optimize.
+ fun computeBinaryType(type: Type): BinaryType<Class> {
+ val erased = erase(type)
+ val inlinedClass = getInlinedClass(erased, isNullable(type)) ?: return createReferenceBinaryType(type)
+
+ getKonanPrimitiveType(inlinedClass)?.let {
+ return it.binaryType
+ }
+
+ val underlyingBinaryType = computeBinaryType(getInlinedClassUnderlyingType(inlinedClass))
+ return if (isNullable(type) && underlyingBinaryType is BinaryType.Reference) {
+ BinaryType.Reference(underlyingBinaryType.types, true)
+ } else {
+ underlyingBinaryType
+ }
+ }
+
+ private fun createReferenceBinaryType(type: Type): BinaryType.Reference<Class> =
+ BinaryType.Reference(computeFullErasure(type), true)
+}
\ No newline at end of file
diff --git a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InteropUtils.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InteropFqNames.kt
similarity index 74%
rename from native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InteropUtils.kt
rename to core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InteropFqNames.kt
index 841e3c4fa..e9d6575 100644
--- a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InteropUtils.kt
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/InteropFqNames.kt
@@ -5,12 +5,8 @@
package org.jetbrains.kotlin.backend.konan
-import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
-import org.jetbrains.kotlin.descriptors.ClassDescriptor
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.resolve.scopes.MemberScope
object InteropFqNames {
@@ -91,23 +87,3 @@
}
private fun FqName.child(nameIdent: String) = child(Name.identifier(nameIdent))
-
-@InternalKotlinNativeApi
-class InteropBuiltIns(builtIns: KonanBuiltIns) {
-
- private val packageScope = builtIns.builtInsModule.getPackage(InteropFqNames.packageName).memberScope
-
- internal fun getContributedVariables(name: String) = packageScope.getContributedVariables(name)
- internal fun getContributedFunctions(name: String) = packageScope.getContributedFunctions(name)
- internal fun getContributedClass(name: String) = packageScope.getContributedClass(name)
-}
-
-private fun MemberScope.getContributedVariables(name: String) =
- this.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
-
-internal fun MemberScope.getContributedClass(name: String): ClassDescriptor =
- this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS) as ClassDescriptor
-
-private fun MemberScope.getContributedFunctions(name: String) =
- this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
-
diff --git a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt
similarity index 93%
rename from native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt
rename to core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt
index c06ccf5..6d5da0d 100644
--- a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -9,13 +9,10 @@
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NativeRuntimeNames
-@InternalKotlinNativeApi
const val NATIVE_PTR_NAME = "NativePtr"
-@InternalKotlinNativeApi
const val NON_NULL_NATIVE_PTR_NAME = "NonNullNativePtr"
-@InternalKotlinNativeApi
const val IMMUTABLE_BLOB_OF = "immutableBlobOf"
object KonanFqNames {
diff --git a/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanPrimitiveType.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanPrimitiveType.kt
new file mode 100644
index 0000000..11312d1
--- /dev/null
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/backend/konan/KonanPrimitiveType.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.backend.konan
+
+import org.jetbrains.kotlin.builtins.PrimitiveType
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqNameUnsafe
+import org.jetbrains.kotlin.name.Name
+
+/**
+ * Most "underlying" user-visible non-reference type.
+ * It is visible as inlined to compiler for simplicity.
+ */
+enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.Primitive) {
+ BOOLEAN(PrimitiveType.BOOLEAN, PrimitiveBinaryType.BOOLEAN),
+ CHAR(PrimitiveType.CHAR, PrimitiveBinaryType.SHORT),
+ BYTE(PrimitiveType.BYTE, PrimitiveBinaryType.BYTE),
+ SHORT(PrimitiveType.SHORT, PrimitiveBinaryType.SHORT),
+ INT(PrimitiveType.INT, PrimitiveBinaryType.INT),
+ LONG(PrimitiveType.LONG, PrimitiveBinaryType.LONG),
+ FLOAT(PrimitiveType.FLOAT, PrimitiveBinaryType.FLOAT),
+ DOUBLE(PrimitiveType.DOUBLE, PrimitiveBinaryType.DOUBLE),
+ NON_NULL_NATIVE_PTR(ClassId.Companion.topLevel(KonanFqNames.nonNullNativePtr.toSafe()), PrimitiveBinaryType.POINTER),
+ VECTOR128(ClassId.Companion.topLevel(KonanFqNames.Vector128), PrimitiveBinaryType.VECTOR128)
+
+ ;
+
+ constructor(primitiveType: PrimitiveType, primitiveBinaryType: PrimitiveBinaryType)
+ : this(ClassId.Companion.topLevel(primitiveType.typeFqName), primitiveBinaryType)
+
+ constructor(classId: ClassId, primitiveBinaryType: PrimitiveBinaryType)
+ : this(classId, BinaryType.Primitive(primitiveBinaryType))
+
+ val fqName: FqNameUnsafe get() = this.classId.asSingleFqName().toUnsafe()
+
+ companion object {
+ val byFqNameParts = entries.toTypedArray().groupingBy {
+ assert(!it.classId.isNestedClass)
+ it.classId.packageFqName
+ }.fold({ _, _ -> mutableMapOf<Name, KonanPrimitiveType>() },
+ { _, accumulator, element ->
+ accumulator.also { it[element.classId.shortClassName] = element }
+ })
+ }
+}
\ No newline at end of file
diff --git a/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/Escapes.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/Escapes.kt
new file mode 100644
index 0000000..7017501
--- /dev/null
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/Escapes.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.native.internal
+
+/**
+ * A representation of `@Escapes` and `@Escapes.Nothing` annotations.
+ */
+@JvmInline
+value class Escapes private constructor(private val mask: Int) {
+ constructor(mask: Int, signatureSize: Int) : this(mask) {
+ assertIsValidFor(signatureSize)
+ }
+
+ /**
+ * Throws [IllegalArgumentException] if `this` is not valid for signature of size [signatureSize].
+ */
+ fun assertIsValidFor(signatureSize: Int) {
+ require(mask >= 0 && mask shr signatureSize == 0) {
+ "$this must not be negative and not have bits higher than $signatureSize"
+ }
+ }
+
+ /**
+ * Returns `true` if a signature element at [index] is marked as escaping.
+ */
+ fun escapesAt(index: Int): Boolean {
+ return (mask shr index) and 1 == 1
+ }
+
+ override fun toString(): String {
+ return "0b${mask.toString(2)}"
+ }
+}
\ No newline at end of file
diff --git a/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/IntrinsicType.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/IntrinsicType.kt
new file mode 100644
index 0000000..6a43d1b
--- /dev/null
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/IntrinsicType.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.native.internal
+
+enum class IntrinsicType {
+ PLUS,
+ MINUS,
+ TIMES,
+ SIGNED_DIV,
+ SIGNED_REM,
+ INC,
+ DEC,
+ UNARY_PLUS,
+ UNARY_MINUS,
+ SHL,
+ SHR,
+ USHR,
+ AND,
+ OR,
+ XOR,
+ INV,
+ SIGN_EXTEND,
+ ZERO_EXTEND,
+ INT_TRUNCATE,
+ FLOAT_TRUNCATE,
+ FLOAT_EXTEND,
+ SIGNED_TO_FLOAT,
+ UNSIGNED_TO_FLOAT,
+ SIGNED_COMPARE_TO,
+ UNSIGNED_COMPARE_TO,
+ NOT,
+ REINTERPRET,
+ EXTRACT_ELEMENT,
+ ARE_EQUAL_BY_VALUE,
+ IEEE_754_EQUALS,
+ // OBJC
+ OBJC_GET_MESSENGER,
+ OBJC_GET_MESSENGER_STRET,
+ OBJC_GET_OBJC_CLASS,
+ OBJC_CREATE_SUPER_STRUCT,
+ OBJC_INIT_BY,
+ OBJC_GET_SELECTOR,
+ BLOCK_PTR_TO_FUNCTION_OBJECT,
+ // Other
+ CREATE_UNINITIALIZED_INSTANCE,
+ CREATE_UNINITIALIZED_ARRAY,
+ CREATE_EMPTY_STRING,
+ IDENTITY,
+ IMMUTABLE_BLOB,
+ INIT_INSTANCE,
+ IS_SUBTYPE,
+ THE_UNIT_INSTANCE,
+ // Enums
+ ENUM_VALUES,
+ ENUM_VALUE_OF,
+ ENUM_ENTRIES,
+ // Coroutines
+ GET_CONTINUATION,
+ RETURN_IF_SUSPENDED,
+ SAVE_COROUTINE_STATE,
+ RESTORE_COROUTINE_STATE,
+ // Interop
+ INTEROP_READ_BITS,
+ INTEROP_WRITE_BITS,
+ INTEROP_READ_PRIMITIVE,
+ INTEROP_WRITE_PRIMITIVE,
+ INTEROP_GET_POINTER_SIZE,
+ INTEROP_NATIVE_PTR_TO_LONG,
+ INTEROP_NATIVE_PTR_PLUS_LONG,
+ INTEROP_GET_NATIVE_NULL_PTR,
+ INTEROP_CONVERT,
+ INTEROP_BITS_TO_FLOAT,
+ INTEROP_BITS_TO_DOUBLE,
+ INTEROP_SIGN_EXTEND,
+ INTEROP_NARROW,
+ INTEROP_STATIC_C_FUNCTION,
+ INTEROP_FUNPTR_INVOKE,
+ // Worker
+ WORKER_EXECUTE,
+ // Atomics
+ ATOMIC_GET_FIELD,
+ ATOMIC_SET_FIELD,
+ COMPARE_AND_SET_FIELD,
+ COMPARE_AND_EXCHANGE_FIELD,
+ GET_AND_SET_FIELD,
+ GET_AND_ADD_FIELD,
+ COMPARE_AND_SET,
+ COMPARE_AND_EXCHANGE,
+ GET_AND_SET,
+ GET_AND_ADD,
+ // Atomic arrays
+ ATOMIC_GET_ARRAY_ELEMENT,
+ ATOMIC_SET_ARRAY_ELEMENT,
+ COMPARE_AND_EXCHANGE_ARRAY_ELEMENT,
+ COMPARE_AND_SET_ARRAY_ELEMENT,
+ GET_AND_SET_ARRAY_ELEMENT,
+ GET_AND_ADD_ARRAY_ELEMENT
+}
\ No newline at end of file
diff --git a/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/PointsTo.kt b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/PointsTo.kt
new file mode 100644
index 0000000..fae10bf
--- /dev/null
+++ b/core/compiler.common.native/src/org/jetbrains/kotlin/native/internal/PointsTo.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.native.internal
+
+/**
+ * Kind in `@PointsTo` annotation.
+ * kind edge
+ * 0 p1 -/-> p2
+ * 1 p1 -> p2
+ * 2 p1 -> p2.intestines
+ * 3 p1.intestines -> p2
+ * 4 p1.intestines -> p2.intestines
+ */
+@JvmInline
+value class PointsToKind private constructor(private val value: Int) {
+ val sourceIsDirect: Boolean
+ get() = value < 3
+
+ val destinationIsDirect: Boolean
+ get() = value % 2 == 1
+
+ companion object {
+ fun fromMask(mask: Int): PointsToKind? {
+ require(mask >= 0 && mask <= 4) {
+ "$mask must be 0..4"
+ }
+ return if (mask == 0) null else PointsToKind(mask)
+ }
+ }
+}
+
+/**
+ * A representation of `@PointsTo` annotation.
+ */
+@JvmInline
+value class PointsTo private constructor(private val elements: IntArray) {
+ constructor(elements: List<Int>, signatureSize: Int) : this(elements.toIntArray()) {
+ assertIsValidFor(signatureSize)
+ }
+
+ /**
+ * Throws [IllegalArgumentException] if `this` is not valid for signature of size [signatureSize].
+ */
+ fun assertIsValidFor(signatureSize: Int) {
+ require(elements.size == signatureSize) {
+ "$this must have exactly $signatureSize elements"
+ }
+ elements.forEach {
+ require(it >= 0 && it shr (4 * signatureSize) == 0) {
+ "0x${it.toString(16)} must not be negative and not have nibbles higher than $signatureSize"
+ }
+ }
+ }
+
+ /**
+ * If signature element at [indexFrom] points to signature element at [indexTo], returns [PointsToKind]
+ * of the relationship. Otherwise, returns `null`.
+ */
+ fun kind(indexFrom: Int, indexTo: Int): PointsToKind? {
+ val mask = elements[indexFrom] shr (4 * indexTo) and 15
+ return PointsToKind.fromMask(mask)
+ }
+
+ override fun toString(): String = elements.joinToString(prefix = "(", postfix = ")", separator = ", ") {
+ "0x${it.toString(16)}"
+ }
+}
\ No newline at end of file
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/checkers/EscapeAnalysisChecker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/checkers/EscapeAnalysisChecker.kt
index fd3de0a..8a4b50f 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/checkers/EscapeAnalysisChecker.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/checkers/EscapeAnalysisChecker.kt
@@ -12,7 +12,6 @@
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.ir.annotations.escapes
import org.jetbrains.kotlin.backend.konan.ir.annotations.pointsTo
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.ir.IrElement
@@ -32,6 +31,7 @@
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NativeRuntimeNames
+import org.jetbrains.kotlin.native.internal.IntrinsicType
internal class EscapeAnalysisChecker(
private val context: PhaseContext,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/Escapes.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/Escapes.kt
index 68c017c..30d17ae 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/Escapes.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/Escapes.kt
@@ -11,36 +11,7 @@
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.name.NativeRuntimeNames
import org.jetbrains.kotlin.name.NativeRuntimeNames.Annotations.EscapesNothing
-
-/**
- * A representation of `@Escapes` and `@Escapes.Nothing` annotations.
- */
-@JvmInline
-internal value class Escapes private constructor(private val mask: Int) {
- constructor(mask: Int, signatureSize: Int) : this(mask) {
- assertIsValidFor(signatureSize)
- }
-
- /**
- * Throws [IllegalArgumentException] if `this` is not valid for signature of size [signatureSize].
- */
- fun assertIsValidFor(signatureSize: Int) {
- require(mask >= 0 && mask shr signatureSize == 0) {
- "$this must not be negative and not have bits higher than $signatureSize"
- }
- }
-
- /**
- * Returns `true` if a signature element at [index] is marked as escaping.
- */
- fun escapesAt(index: Int): Boolean {
- return (mask shr index) and 1 == 1
- }
-
- override fun toString(): String {
- return "0b${mask.toString(2)}"
- }
-}
+import org.jetbrains.kotlin.native.internal.Escapes
/**
* Get `@Escapes` signature for the function if any.
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/PointsTo.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/PointsTo.kt
index 3c89f29..bb8b061 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/PointsTo.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/annotations/PointsTo.kt
@@ -11,70 +11,7 @@
import org.jetbrains.kotlin.ir.util.allParameters
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.name.NativeRuntimeNames
-
-/**
- * Kind in `@PointsTo` annotation.
- * kind edge
- * 0 p1 -/-> p2
- * 1 p1 -> p2
- * 2 p1 -> p2.intestines
- * 3 p1.intestines -> p2
- * 4 p1.intestines -> p2.intestines
- */
-@JvmInline
-internal value class PointsToKind private constructor(private val value: Int) {
- val sourceIsDirect: Boolean
- get() = value < 3
-
- val destinationIsDirect: Boolean
- get() = value % 2 == 1
-
- companion object {
- fun fromMask(mask: Int): PointsToKind? {
- require(mask >= 0 && mask <= 4) {
- "$mask must be 0..4"
- }
- return if (mask == 0) null else PointsToKind(mask)
- }
- }
-}
-
-/**
- * A representation of `@PointsTo` annotation.
- */
-@JvmInline
-internal value class PointsTo private constructor(private val elements: IntArray) {
- constructor(elements: List<Int>, signatureSize: Int) : this(elements.toIntArray()) {
- assertIsValidFor(signatureSize)
- }
-
- /**
- * Throws [IllegalArgumentException] if `this` is not valid for signature of size [signatureSize].
- */
- fun assertIsValidFor(signatureSize: Int) {
- require(elements.size == signatureSize) {
- "$this must have exactly $signatureSize elements"
- }
- elements.forEach {
- require(it >= 0 && it shr (4 * signatureSize) == 0) {
- "0x${it.toString(16)} must not be negative and not have nibbles higher than $signatureSize"
- }
- }
- }
-
- /**
- * If signature element at [indexFrom] points to signature element at [indexTo], returns [PointsToKind]
- * of the relationship. Otherwise, returns `null`.
- */
- fun kind(indexFrom: Int, indexTo: Int): PointsToKind? {
- val mask = elements[indexFrom] shr (4 * indexTo) and 15
- return PointsToKind.fromMask(mask)
- }
-
- override fun toString(): String = elements.joinToString(prefix = "(", postfix = ")", separator = ", ") {
- "0x${it.toString(16)}"
- }
-}
+import org.jetbrains.kotlin.native.internal.PointsTo
/**
* Get `@PointsTo` signature for the function if any.
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt
index aaa5ea1..a46236c 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.konan.ir.interop
import org.jetbrains.kotlin.backend.konan.InteropFqNames
-import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt
index 9174593..5cd8a6b 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt
@@ -18,101 +18,7 @@
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.ir.util.isInterface
-
-internal enum class IntrinsicType {
- PLUS,
- MINUS,
- TIMES,
- SIGNED_DIV,
- SIGNED_REM,
- INC,
- DEC,
- UNARY_PLUS,
- UNARY_MINUS,
- SHL,
- SHR,
- USHR,
- AND,
- OR,
- XOR,
- INV,
- SIGN_EXTEND,
- ZERO_EXTEND,
- INT_TRUNCATE,
- FLOAT_TRUNCATE,
- FLOAT_EXTEND,
- SIGNED_TO_FLOAT,
- UNSIGNED_TO_FLOAT,
- SIGNED_COMPARE_TO,
- UNSIGNED_COMPARE_TO,
- NOT,
- REINTERPRET,
- EXTRACT_ELEMENT,
- ARE_EQUAL_BY_VALUE,
- IEEE_754_EQUALS,
- // OBJC
- OBJC_GET_MESSENGER,
- OBJC_GET_MESSENGER_STRET,
- OBJC_GET_OBJC_CLASS,
- OBJC_CREATE_SUPER_STRUCT,
- OBJC_INIT_BY,
- OBJC_GET_SELECTOR,
- BLOCK_PTR_TO_FUNCTION_OBJECT,
- // Other
- CREATE_UNINITIALIZED_INSTANCE,
- CREATE_UNINITIALIZED_ARRAY,
- CREATE_EMPTY_STRING,
- IDENTITY,
- IMMUTABLE_BLOB,
- INIT_INSTANCE,
- IS_SUBTYPE,
- THE_UNIT_INSTANCE,
- // Enums
- ENUM_VALUES,
- ENUM_VALUE_OF,
- ENUM_ENTRIES,
- // Coroutines
- GET_CONTINUATION,
- RETURN_IF_SUSPENDED,
- SAVE_COROUTINE_STATE,
- RESTORE_COROUTINE_STATE,
- // Interop
- INTEROP_READ_BITS,
- INTEROP_WRITE_BITS,
- INTEROP_READ_PRIMITIVE,
- INTEROP_WRITE_PRIMITIVE,
- INTEROP_GET_POINTER_SIZE,
- INTEROP_NATIVE_PTR_TO_LONG,
- INTEROP_NATIVE_PTR_PLUS_LONG,
- INTEROP_GET_NATIVE_NULL_PTR,
- INTEROP_CONVERT,
- INTEROP_BITS_TO_FLOAT,
- INTEROP_BITS_TO_DOUBLE,
- INTEROP_SIGN_EXTEND,
- INTEROP_NARROW,
- INTEROP_STATIC_C_FUNCTION,
- INTEROP_FUNPTR_INVOKE,
- // Worker
- WORKER_EXECUTE,
- // Atomics
- ATOMIC_GET_FIELD,
- ATOMIC_SET_FIELD,
- COMPARE_AND_SET_FIELD,
- COMPARE_AND_EXCHANGE_FIELD,
- GET_AND_SET_FIELD,
- GET_AND_ADD_FIELD,
- COMPARE_AND_SET,
- COMPARE_AND_EXCHANGE,
- GET_AND_SET,
- GET_AND_ADD,
- // Atomic arrays
- ATOMIC_GET_ARRAY_ELEMENT,
- ATOMIC_SET_ARRAY_ELEMENT,
- COMPARE_AND_EXCHANGE_ARRAY_ELEMENT,
- COMPARE_AND_SET_ARRAY_ELEMENT,
- GET_AND_SET_ARRAY_ELEMENT,
- GET_AND_ADD_ARRAY_ELEMENT
-}
+import org.jetbrains.kotlin.native.internal.IntrinsicType
internal enum class ConstantConstructorIntrinsicType {
KCLASS_IMPL,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt
index 84eec0c..97a51e1 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt
@@ -14,7 +14,6 @@
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.KonanNameConventions
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -36,6 +35,7 @@
import org.jetbrains.kotlin.ir.visitors.IrTransformer
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.native.internal.IntrinsicType
import org.jetbrains.kotlin.utils.addToStdlib.getOrSetIfNull
private var IrClass.enumValueGetter: IrSimpleFunction? by irAttribute(copyByDefault = false)
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt
index 5712846..91dccdd 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt
@@ -9,7 +9,6 @@
import org.jetbrains.kotlin.backend.konan.cgen.*
import org.jetbrains.kotlin.ir.util.getAnnotationStringValue
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -20,6 +19,7 @@
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
+import org.jetbrains.kotlin.native.internal.IntrinsicType
private class InteropCallContext(
val symbols: KonanSymbols,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt
index 2afde70..d0b6b37 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt
@@ -11,7 +11,6 @@
import org.jetbrains.kotlin.backend.konan.cgen.*
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.*
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.backend.konan.serialization.isFromCInteropLibrary
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -39,6 +38,7 @@
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NativeStandardInteropNames.objCActionClassId
+import org.jetbrains.kotlin.native.internal.IntrinsicType
import org.jetbrains.kotlin.native.interop.ObjCMethodInfo
internal class InteropLowering(val generationState: NativeGenerationState) : FileLoweringPass, BodyLoweringPass {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SpecialBackendChecksTraversal.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SpecialBackendChecksTraversal.kt
index 1b36238..e0d8e2b 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SpecialBackendChecksTraversal.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SpecialBackendChecksTraversal.kt
@@ -16,7 +16,6 @@
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.ir.allOverriddenFunctions
import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -37,6 +36,7 @@
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.NativeStandardInteropNames.objCActionClassId
+import org.jetbrains.kotlin.native.internal.IntrinsicType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.fileUtils.descendantRelativeTo
import java.io.File
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt
index 497562c..f77dca9 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt
@@ -10,7 +10,6 @@
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ir.buildSimpleAnnotation
-import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -27,9 +26,9 @@
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.native.internal.IntrinsicType
import org.jetbrains.kotlin.util.capitalizeDecapitalize.*
import org.jetbrains.kotlin.utils.addToStdlib.getOrSetIfNull
-import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
val IR_DECLARATION_ORIGIN_VOLATILE = IrDeclarationOriginImpl("VOLATILE")
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt
index 4e155fa..7f7a434 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt
@@ -30,6 +30,7 @@
import org.jetbrains.kotlin.backend.konan.lower.volatileField
import org.jetbrains.kotlin.ir.objcinterop.isObjCObjectType
import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.native.internal.IntrinsicType
internal val STATEMENT_ORIGIN_PRODUCER_INVOCATION = IrStatementOriginImpl("PRODUCER_INVOCATION")
internal val STATEMENT_ORIGIN_JOB_INVOCATION = IrStatementOriginImpl("JOB_INVOCATION")
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt
index bb3e350..64c1cb4 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt
@@ -6,8 +6,6 @@
package org.jetbrains.kotlin.backend.konan.optimizations
import org.jetbrains.kotlin.backend.konan.*
-import org.jetbrains.kotlin.backend.konan.ir.annotations.Escapes
-import org.jetbrains.kotlin.backend.konan.ir.annotations.PointsTo
import org.jetbrains.kotlin.backend.konan.ir.annotations.escapes
import org.jetbrains.kotlin.backend.konan.ir.annotations.pointsTo
import org.jetbrains.kotlin.backend.konan.ir.implementedInterfaces
@@ -34,6 +32,8 @@
import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.library.metadata.impl.KlibResolvedModuleDescriptorsFactoryImpl.Companion.FORWARD_DECLARATIONS_MODULE_NAME
+import org.jetbrains.kotlin.native.internal.Escapes
+import org.jetbrains.kotlin.native.internal.PointsTo
import java.util.*
internal object DataFlowIR {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt
index 2c030aa..eef2abe 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/EscapeAnalysis.kt
@@ -12,9 +12,6 @@
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DirectedGraphCondensationBuilder
import org.jetbrains.kotlin.backend.konan.DirectedGraphMultiNode
-import org.jetbrains.kotlin.backend.konan.ir.annotations.Escapes
-import org.jetbrains.kotlin.backend.konan.ir.annotations.PointsTo
-import org.jetbrains.kotlin.backend.konan.ir.annotations.PointsToKind
import org.jetbrains.kotlin.backend.konan.ir.isBuiltInOperator
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.logMultiple
@@ -24,6 +21,9 @@
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.getAllSuperclasses
+import org.jetbrains.kotlin.native.internal.Escapes
+import org.jetbrains.kotlin.native.internal.PointsTo
+import org.jetbrains.kotlin.native.internal.PointsToKind
import org.jetbrains.kotlin.utils.atMostOne
private val DataFlowIR.Node.ir
diff --git a/native/base/build.gradle.kts b/native/base/build.gradle.kts
index 1d81065..328da9a 100644
--- a/native/base/build.gradle.kts
+++ b/native/base/build.gradle.kts
@@ -5,7 +5,7 @@
dependencies {
implementation(project(":compiler:cli-base"))
implementation(project(":compiler:cli-common"))
- implementation(project(":core:compiler.common.native"))
+ api(project(":core:compiler.common.native"))
implementation(project(":core:descriptors"))
implementation(project(":native:frontend.native"))
}
diff --git a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InlineClasses.kt b/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InlineClasses.kt
index bb8e4c5..ff2768e 100644
--- a/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InlineClasses.kt
+++ b/native/base/src/main/kotlin/org/jetbrains/kotlin/backend/konan/InlineClasses.kt
@@ -5,14 +5,9 @@
package org.jetbrains.kotlin.backend.konan
-import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.findPackage
-import org.jetbrains.kotlin.name.ClassId
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.name.FqNameUnsafe
-import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.isInlineClass
@@ -21,8 +16,6 @@
import org.jetbrains.kotlin.types.typeUtil.makeNullable
-fun KotlinType.getInlinedClass(): ClassDescriptor? = KotlinTypeInlineClassesSupport.getInlinedClass(this)
-
fun ClassDescriptor.isInlined(): Boolean = KotlinTypeInlineClassesSupport.isInlined(this)
fun KotlinType.binaryRepresentationIsNullable() = KotlinTypeInlineClassesSupport.representationIsNullable(this)
@@ -43,173 +36,6 @@
fun KotlinType.computeBinaryType(): BinaryType<ClassDescriptor> = KotlinTypeInlineClassesSupport.computeBinaryType(this)
-/**
- * Most "underlying" user-visible non-reference type.
- * It is visible as inlined to compiler for simplicity.
- */
-enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.Primitive) {
- BOOLEAN(PrimitiveType.BOOLEAN, PrimitiveBinaryType.BOOLEAN),
- CHAR(PrimitiveType.CHAR, PrimitiveBinaryType.SHORT),
- BYTE(PrimitiveType.BYTE, PrimitiveBinaryType.BYTE),
- SHORT(PrimitiveType.SHORT, PrimitiveBinaryType.SHORT),
- INT(PrimitiveType.INT, PrimitiveBinaryType.INT),
- LONG(PrimitiveType.LONG, PrimitiveBinaryType.LONG),
- FLOAT(PrimitiveType.FLOAT, PrimitiveBinaryType.FLOAT),
- DOUBLE(PrimitiveType.DOUBLE, PrimitiveBinaryType.DOUBLE),
- NON_NULL_NATIVE_PTR(ClassId.topLevel(KonanFqNames.nonNullNativePtr.toSafe()), PrimitiveBinaryType.POINTER),
- VECTOR128(ClassId.topLevel(KonanFqNames.Vector128), PrimitiveBinaryType.VECTOR128)
-
- ;
-
- constructor(primitiveType: PrimitiveType, primitiveBinaryType: PrimitiveBinaryType)
- : this(ClassId.topLevel(primitiveType.typeFqName), primitiveBinaryType)
-
- constructor(classId: ClassId, primitiveBinaryType: PrimitiveBinaryType)
- : this(classId, BinaryType.Primitive(primitiveBinaryType))
-
- val fqName: FqNameUnsafe get() = this.classId.asSingleFqName().toUnsafe()
-
- companion object {
- val byFqNameParts = KonanPrimitiveType.values().groupingBy {
- assert(!it.classId.isNestedClass)
- it.classId.packageFqName
- }.fold({ _, _ -> mutableMapOf<Name, KonanPrimitiveType>() },
- { _, accumulator, element ->
- accumulator.also { it[element.classId.shortClassName] = element }
- })
- }
-}
-
-@InternalKotlinNativeApi
-abstract class InlineClassesSupport<Class : Any, Type : Any> {
- @InternalKotlinNativeApi
- abstract fun isNullable(type: Type): Boolean
-
- @InternalKotlinNativeApi
- abstract fun makeNullable(type: Type): Type
- protected abstract fun erase(type: Type): Class
- protected abstract fun computeFullErasure(type: Type): Sequence<Class>
- protected abstract fun hasInlineModifier(clazz: Class): Boolean
- protected abstract fun getNativePointedSuperclass(clazz: Class): Class?
-
- @InternalKotlinNativeApi
- abstract fun getInlinedClassUnderlyingType(clazz: Class): Type
- protected abstract fun getPackageFqName(clazz: Class): FqName?
- protected abstract fun getName(clazz: Class): Name?
- abstract fun isTopLevelClass(clazz: Class): Boolean
-
- @JvmName("classIsInlined")
- fun isInlined(clazz: Class): Boolean = getInlinedClass(clazz) != null
- fun isInlined(type: Type): Boolean = getInlinedClass(type) != null
-
- fun isUsedAsBoxClass(clazz: Class) = getInlinedClass(clazz) == clazz // To handle NativePointed subclasses.
-
- fun getInlinedClass(type: Type): Class? =
- getInlinedClass(erase(type), isNullable(type))
-
- @InternalKotlinNativeApi
- fun getKonanPrimitiveType(clazz: Class): KonanPrimitiveType? =
- if (isTopLevelClass(clazz))
- KonanPrimitiveType.byFqNameParts[getPackageFqName(clazz)]?.get(getName(clazz))
- else null
-
- @InternalKotlinNativeApi
- fun isImplicitInlineClass(clazz: Class): Boolean =
- isTopLevelClass(clazz) && (getKonanPrimitiveType(clazz) != null ||
- getName(clazz) == KonanFqNames.nativePtr.shortName() && getPackageFqName(clazz) == KonanFqNames.internalPackageName ||
- getName(clazz) == InteropFqNames.cPointer.shortName() && getPackageFqName(clazz) == InteropFqNames.cPointer.parent()
- .toSafe())
-
- private fun getInlinedClass(erased: Class, isNullable: Boolean): Class? {
- val inlinedClass = getInlinedClass(erased) ?: return null
- return if (!isNullable || representationIsNonNullReferenceOrPointer(inlinedClass)) {
- inlinedClass
- } else {
- null
- }
- }
-
- tailrec fun representationIsNonNullReferenceOrPointer(clazz: Class): Boolean {
- val konanPrimitiveType = getKonanPrimitiveType(clazz)
- if (konanPrimitiveType != null) {
- return konanPrimitiveType == KonanPrimitiveType.NON_NULL_NATIVE_PTR
- }
-
- val inlinedClass = getInlinedClass(clazz) ?: return true
-
- val underlyingType = getInlinedClassUnderlyingType(inlinedClass)
- return if (isNullable(underlyingType)) {
- false
- } else {
- representationIsNonNullReferenceOrPointer(erase(underlyingType))
- }
- }
-
- @JvmName("classGetInlinedClass")
- private fun getInlinedClass(clazz: Class): Class? =
- if (hasInlineModifier(clazz) || isImplicitInlineClass(clazz)) {
- clazz
- } else {
- getNativePointedSuperclass(clazz)
- }
-
- inline fun <R> unwrapToPrimitiveOrReference(
- type: Type,
- eachInlinedClass: (inlinedClass: Class, nullable: Boolean) -> Unit,
- ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
- ifReference: (type: Type) -> R,
- ): R {
- var currentType: Type = type
-
- while (true) {
- val inlinedClass = getInlinedClass(currentType)
- if (inlinedClass == null) {
- return ifReference(currentType)
- }
-
- val nullable = isNullable(currentType)
-
- getKonanPrimitiveType(inlinedClass)?.let { primitiveType ->
- return ifPrimitive(primitiveType, nullable)
- }
-
- eachInlinedClass(inlinedClass, nullable)
-
- val underlyingType = getInlinedClassUnderlyingType(inlinedClass)
- currentType = if (nullable) makeNullable(underlyingType) else underlyingType
- }
- }
-
- fun representationIsNullable(type: Type): Boolean {
- unwrapToPrimitiveOrReference(
- type,
- eachInlinedClass = { _, nullable -> if (nullable) return true },
- ifPrimitive = { _, nullable -> return nullable },
- ifReference = { return isNullable(it) }
- )
- }
-
- // TODO: optimize.
- fun computeBinaryType(type: Type): BinaryType<Class> {
- val erased = erase(type)
- val inlinedClass = getInlinedClass(erased, isNullable(type)) ?: return createReferenceBinaryType(type)
-
- getKonanPrimitiveType(inlinedClass)?.let {
- return it.binaryType
- }
-
- val underlyingBinaryType = computeBinaryType(getInlinedClassUnderlyingType(inlinedClass))
- return if (isNullable(type) && underlyingBinaryType is BinaryType.Reference) {
- BinaryType.Reference(underlyingBinaryType.types, true)
- } else {
- underlyingBinaryType
- }
- }
-
- private fun createReferenceBinaryType(type: Type): BinaryType.Reference<Class> =
- BinaryType.Reference(computeFullErasure(type), true)
-}
-
@InternalKotlinNativeApi
object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescriptor, KotlinType>() {