Merge branch 'master' into kotlin-mirror/master

This commit is contained in:
Pavel Punegov
2019-07-12 14:13:32 +03:00
committed by GitHub
224 changed files with 6392 additions and 4094 deletions
+22 -2
View File
@@ -1,7 +1,27 @@
# v1.3.0 (June 2019)
# v1.3.50 (Aug 2019)
* Kotlin/Native versioning now aligned with Kotlin versioning
* Exhaustive platform libraries on macOS (GH-3141)
* Update to Gradle 5.5 (GH-3166)
* Improved debug information correctness (GH-3130)
* Major memory manager refactoring (GH-3129)
* Embed actual bitcode in produced frameworks (GH-2974)
* Compilation speed improvements
* Interop:
* Support kotlin.Deprecated when producing framework (GH-3114)
* Ensure produced Objective-C header does not have warnings (GH-3101)
* Speed up interop stub generator (GH-3082, GH-3050)
* getOriginalKotlinClass() to get KClass for Kotlin classes in Objective-C (GH-3036)
* Implement ObjCExportLazy (GH-2990)
* Standard library
* API for delayed job execution on worker (GH-2971)
* API for running via worker's job queue (GH-3078)
* MonoClock and Duration support (GH-3028)
* Support typeOf (KT-29917, KT-28625)
# v1.3.0 (Jun 2019)
* CoreLocation platform library on macOS (GH-3041)
* Converting Unit type to Void during producing framework for Objective-C/Swift (GH-2549, GH-1271)
* Support linux/arm64 targets (GH-1709)
* Support linux/arm64 targets (GH-2917)
* Performance improvements of memory manager (GH-2813)
* FreezableAtomicReference prototype (GH-2776)
* Logging and error messages enhancements
+2 -2
View File
@@ -235,7 +235,7 @@ With the `kotlin-platform-native` plugin interop with a native library can be de
components.main {
dependencies {
cinterop('mystdio') {
// Сinterop configuration.
// Cinterop configuration.
}
}
}
@@ -253,7 +253,7 @@ kotlin {
macosX64 {
compilations.main.cinterops {
mystdio {
// Сinterop configuration.
// Cinterop configuration.
}
}
}
@@ -100,13 +100,4 @@ inline fun buildKotlinCodeLines(scope: KotlinScope, block: KotlinCodeBuilder.()
val builder = KotlinCodeBuilder(scope)
builder.block()
return builder.build()
}
interface StubGenerationContext {
val nativeBridges: NativeBridges
fun addTopLevelDeclaration(lines: List<String>)
}
interface KotlinStub {
fun generate(context: StubGenerationContext): Sequence<String>
}
@@ -71,22 +71,5 @@ private val charactersAllowedInKotlinStringLiterals: Set<Char> = mutableSetOf<Ch
addAll(listOf('_', '@', ':', ';', '.', ',', '{', '}', '=', '[', ']', '^', '#', '*', ' ', '(', ')'))
}
fun block(header: String, lines: Iterable<String>) = block(header, lines.asSequence())
fun block(header: String, lines: Sequence<String>) =
sequenceOf("$header {") +
lines.map { " $it" } +
sequenceOf("}")
val annotationForUnableToImport
get() = "@Deprecated(${"Unable to import this declaration".quoteAsKotlinLiteral()}, level = DeprecationLevel.ERROR)"
fun String.applyToStrings(vararg arguments: String) =
"${this}(${arguments.joinToString { it.quoteAsKotlinLiteral() }})"
fun List<KotlinParameter>.renderParameters(scope: KotlinScope) = buildString {
this@renderParameters.renderParametersTo(scope, this)
}
fun List<KotlinParameter>.renderParametersTo(scope: KotlinScope, buffer: Appendable) =
this.joinTo(buffer, ", ") { it.render(scope) }
@@ -1,128 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.StubGenerator
import org.jetbrains.kotlin.native.interop.indexer.ArrayType
import org.jetbrains.kotlin.native.interop.indexer.GlobalDecl
import org.jetbrains.kotlin.native.interop.indexer.unwrapTypedefs
class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : KotlinStub, NativeBacked {
private val getAddressExpression: KotlinExpression by lazy {
stubGenerator.simpleBridgeGenerator.kotlinToNative(
nativeBacked = this,
returnType = BridgedType.NATIVE_PTR,
kotlinValues = emptyList(),
independent = false
) {
"&${global.name}"
}
}
private val setterStub = object : NativeBacked {}
val header: String
val getter: KotlinExpression
val setter: KotlinExpression?
init {
val kotlinScope = stubGenerator.kotlinFile
// TODO: consider sharing the logic below with field generator.
val kotlinType: KotlinType
val mirror = mirror(stubGenerator.declarationMapper, global.type)
val unwrappedType = global.type.unwrapTypedefs()
if (unwrappedType is ArrayType) {
kotlinType = (mirror as TypeMirror.ByValue).valueType
getter = mirror.info.argFromBridged(getAddressExpression, kotlinScope, nativeBacked = this) + "!!"
setter = null
} else {
if (mirror is TypeMirror.ByValue) {
getter = mirror.info.argFromBridged(stubGenerator.simpleBridgeGenerator.kotlinToNative(
nativeBacked = this,
returnType = mirror.info.bridgedType,
kotlinValues = emptyList(),
independent = false
) {
mirror.info.cToBridged(expr = global.name)
}, kotlinScope, nativeBacked = this)
setter = if (global.isConst) {
null
} else {
val bridgedValue = BridgeTypedKotlinValue(mirror.info.bridgedType, mirror.info.argToBridged("value"))
stubGenerator.simpleBridgeGenerator.kotlinToNative(
nativeBacked = setterStub,
returnType = BridgedType.VOID,
kotlinValues = listOf(bridgedValue),
independent = false
) { nativeValues ->
out("${global.name} = ${mirror.info.cFromBridged(
nativeValues.single(),
scope,
nativeBacked = setterStub
)};")
""
}
}
kotlinType = mirror.argType
} else {
val pointedTypeName = mirror.pointedType.render(kotlinScope)
val storagePointed = "interpretPointed<$pointedTypeName>($getAddressExpression)"
kotlinType = mirror.pointedType
getter = storagePointed
setter = null
}
}
header = buildString {
append(getDeclarationName(kotlinScope, global.name))
append(": ")
append(kotlinType.render(kotlinScope))
}
}
// Try to use the provided name. If failed, mangle it with underscore and try again:
private tailrec fun getDeclarationName(scope: KotlinScope, name: String): String =
scope.declareProperty(name) ?: getDeclarationName(scope, name + "_")
override fun generate(context: StubGenerationContext): Sequence<String> {
val lines = mutableListOf<String>()
if (context.nativeBridges.isSupported(this)) {
val mutable = setter != null && context.nativeBridges.isSupported(setterStub)
val kind = if (mutable) "var" else "val"
lines.add("$kind $header")
lines.add(" get() = $getter")
if (mutable) {
lines.add(" set(value) { $setter }")
}
} else {
lines.add(annotationForUnableToImport)
lines.add("val $header")
lines.add(" get() = TODO()")
}
return lines.asSequence()
}
}
@@ -284,7 +284,7 @@ abstract class KotlinFile(
override fun declare(classifier: Classifier): String {
if (classifier.pkg != this.pkg) {
throw IllegalArgumentException("wrong package; expected '$pkg', got '${classifier.pkg}'")
throw IllegalArgumentException("wrong package for classifier ${classifier.fqName}; expected '$pkg', got '${classifier.pkg}'")
}
if (!classifier.isTopLevel) {
@@ -17,10 +17,9 @@
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.native.interop.gen.jvm.StubGenerator
import org.jetbrains.kotlin.native.interop.indexer.*
private fun ObjCMethod.getKotlinParameterNames(forConstructorOrFactory: Boolean = false): List<String> {
internal fun ObjCMethod.getKotlinParameterNames(forConstructorOrFactory: Boolean = false): List<String> {
val selectorParts = this.selector.split(":")
val result = mutableListOf<String>()
@@ -66,194 +65,168 @@ private fun ObjCMethod.getFirstKotlinParameterNameCandidate(forConstructorOrFact
}
private fun ObjCMethod.getKotlinParameters(
stubGenerator: StubGenerator,
stubIrBuilder: StubsBuildingContext,
forConstructorOrFactory: Boolean
): List<KotlinParameter> {
): List<FunctionParameterStub> {
val names = getKotlinParameterNames(forConstructorOrFactory) // TODO: consider refactoring.
val result = mutableListOf<KotlinParameter>()
val result = mutableListOf<FunctionParameterStub>()
this.parameters.mapIndexedTo(result) { index, it ->
val kotlinType = stubGenerator.mirror(it.type).argType
val kotlinType = stubIrBuilder.mirror(it.type).argType
val name = names[index]
val annotations = if (it.nsConsumed) listOf("@CCall.Consumed") else emptyList()
KotlinParameter(name, kotlinType, isVararg = false, annotations = annotations)
val annotations = if (it.nsConsumed) listOf(AnnotationStub.ObjC.Consumed) else emptyList()
FunctionParameterStub(name, WrapperStubType(kotlinType), isVararg = false, annotations = annotations)
}
if (this.isVariadic) {
result += KotlinParameter(
result += FunctionParameterStub(
names.last(),
KotlinTypes.any.makeNullable(),
WrapperStubType(KotlinTypes.any.makeNullable()),
isVararg = true,
annotations = emptyList()
)
}
return result
}
class ObjCMethodStub(private val stubGenerator: StubGenerator,
val method: ObjCMethod,
private val container: ObjCContainer,
private val isDesignatedInitializer: Boolean) : KotlinStub, NativeBacked {
override fun generate(context: StubGenerationContext): Sequence<String> =
if (context.nativeBridges.isSupported(this)) {
val result = mutableListOf<String>()
result.addAll(objCMethodAnnotations)
result.add(header)
if (method.isInit) {
// TODO: generate only constructor/factory in this case.
val kotlinScope = stubGenerator.kotlinFile
val parameters = method.getKotlinParameters(stubGenerator, forConstructorOrFactory = true)
.renderParameters(kotlinScope)
when (container) {
is ObjCClass -> {
result.add(0,
deprecatedInit(
container.kotlinClassName(method.isClass),
kotlinMethodParameters.map { it.name },
factory = false
)
)
// TODO: consider generating non-designated initializers as factories.
val designated = isDesignatedInitializer ||
stubGenerator.configuration.disableDesignatedInitializerChecks
result.add("")
result.add("@ObjCConstructor(${method.selector.quoteAsKotlinLiteral()}, $designated)")
result.add("constructor($parameters) {}")
}
is ObjCCategory -> {
assert(!method.isClass)
val className = stubGenerator.declarationMapper
.getKotlinClassFor(container.clazz, isMeta = false).type
.render(kotlinScope)
result.add(0,
deprecatedInit(
className,
kotlinMethodParameters.map { it.name },
factory = true
)
)
// TODO: add support for type parameters to [KotlinType] etc.
val receiver = kotlinScope.reference(KotlinTypes.objCClassOf) + "<T>"
val originalReturnType = method.getReturnType(container.clazz)
val returnType = if (originalReturnType is ObjCPointer) {
if (originalReturnType.isNullable) "T?" else "T"
} else {
// This shouldn't happen actually.
this.kotlinReturnType
}
result.add("")
result.addAll(buildObjCMethodAnnotations("@ObjCFactory"))
result.add("external fun <T : $className> $receiver.create($parameters): $returnType")
}
is ObjCProtocol -> {} // Nothing to do.
}
}
result.asSequence()
} else {
sequenceOf(
annotationForUnableToImport,
header
)
}
private val kotlinMethodParameters: List<KotlinParameter>
private val kotlinReturnType: String
private val header: String
internal val objCMethodAnnotations: List<String>
private class ObjCMethodStubBuilder(
private val method: ObjCMethod,
private val container: ObjCContainer,
private val isDesignatedInitializer: Boolean,
override val context: StubsBuildingContext
) : StubElementBuilder {
private val isStret: Boolean
private val stubReturnType: StubType
val annotations = mutableListOf<AnnotationStub>()
private val kotlinMethodParameters: List<FunctionParameterStub>
private val external: Boolean
private val receiver: ReceiverParameterStub?
private val name: String = method.kotlinName
private val origin = StubOrigin.ObjCMethod(method, container)
private val modality: MemberStubModality
init {
kotlinMethodParameters = method.getKotlinParameters(stubGenerator, forConstructorOrFactory = false)
val returnType = method.getReturnType(container.classOrProtocol)
isStret = returnType.isStret(stubGenerator.configuration.target)
this.kotlinReturnType = if (returnType.unwrapTypedefs() is VoidType) {
KotlinTypes.unit
isStret = returnType.isStret(context.configuration.target)
stubReturnType = if (returnType.unwrapTypedefs() is VoidType) {
WrapperStubType(KotlinTypes.unit)
} else {
stubGenerator.mirror(returnType).argType
}.render(stubGenerator.kotlinFile)
objCMethodAnnotations = buildObjCMethodAnnotations("@ObjCMethod")
val joinedKotlinParameters = kotlinMethodParameters.renderParameters(stubGenerator.kotlinFile)
this.header = buildString {
if (container !is ObjCProtocol) append("external ")
val modality = when (container) {
is ObjCClassOrProtocol -> if (method.isOverride(container)) {
"override "
} else when (container) {
is ObjCClass -> "open "
is ObjCProtocol -> ""
}
is ObjCCategory -> ""
}
append(modality)
append("fun ")
if (container is ObjCCategory) {
val receiverType = stubGenerator.declarationMapper
.getKotlinClassFor(container.clazz, isMeta = method.isClass).type
.render(stubGenerator.kotlinFile)
append(receiverType)
append('.')
}
append("${method.kotlinName.asSimpleName()}($joinedKotlinParameters): $kotlinReturnType")
if (container is ObjCProtocol && method.isOptional) append(" = optional()")
WrapperStubType(context.mirror(returnType).argType)
}
val methodAnnotation = AnnotationStub.ObjC.Method(
method.selector,
method.encoding,
isStret
)
annotations += buildObjCMethodAnnotations(methodAnnotation)
kotlinMethodParameters = method.getKotlinParameters(context, forConstructorOrFactory = false)
external = (container !is ObjCProtocol)
modality = when (container) {
is ObjCClassOrProtocol -> {
if (method.isOverride(container)) {
MemberStubModality.OVERRIDE
} else when (container) {
is ObjCClass -> MemberStubModality.OPEN
is ObjCProtocol -> MemberStubModality.OPEN
}
}
is ObjCCategory -> MemberStubModality.FINAL
}
receiver = if (container is ObjCCategory) {
val receiverType = ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = method.isClass))
ReceiverParameterStub(receiverType)
} else null
}
private fun buildObjCMethodAnnotations(main: String) = listOfNotNull(
buildObjCMethodAnnotation(main),
"@CCall.ConsumesReceiver".takeIf { method.nsConsumesSelf },
"@CCall.ReturnsRetained".takeIf { method.nsReturnsRetained }
private fun buildObjCMethodAnnotations(main: AnnotationStub): List<AnnotationStub> = listOfNotNull(
main,
AnnotationStub.ObjC.ConsumesReceiver.takeIf { method.nsConsumesSelf },
AnnotationStub.ObjC.ReturnsRetained.takeIf { method.nsReturnsRetained }
)
private fun buildObjCMethodAnnotation(annotation: String) = buildString {
append(annotation)
append('(')
append(method.selector.quoteAsKotlinLiteral())
append(", ")
append(method.encoding.quoteAsKotlinLiteral())
if (isStret) {
append(", ")
append("true")
fun isDefaultConstructor(): Boolean =
method.isInit && method.parameters.isEmpty()
override fun build(): List<FunctionalStub> {
val replacement = if (method.isInit) {
val parameters = method.getKotlinParameters(context, forConstructorOrFactory = true)
when (container) {
is ObjCClass -> {
annotations.add(0, deprecatedInit(
container.kotlinClassName(method.isClass),
kotlinMethodParameters.map { it.name },
factory = false
))
val designated = isDesignatedInitializer ||
context.configuration.disableDesignatedInitializerChecks
val annotations = listOf(AnnotationStub.ObjC.Constructor(method.selector, designated))
val constructor = ConstructorStub(parameters, annotations)
constructor
}
is ObjCCategory -> {
assert(!method.isClass)
val clazz = context.getKotlinClassFor(container.clazz, isMeta = false).type
annotations.add(0, deprecatedInit(
clazz.classifier.relativeFqName,
kotlinMethodParameters.map { it.name },
factory = true
))
val factoryAnnotation = AnnotationStub.ObjC.Factory(
method.selector,
method.encoding,
isStret
)
val annotations = buildObjCMethodAnnotations(factoryAnnotation)
val originalReturnType = method.getReturnType(container.clazz)
val typeParameter = TypeParameterStub("T", WrapperStubType(clazz))
val returnType = if (originalReturnType is ObjCPointer) {
typeParameter.getStubType(originalReturnType.isNullable)
} else {
// This shouldn't happen actually.
this.stubReturnType
}
val typeArgument = TypeArgumentStub(typeParameter.getStubType(false))
val receiverType = ClassifierStubType(KotlinTypes.objCClassOf, listOf(typeArgument))
val receiver = ReceiverParameterStub(receiverType)
val createMethod = FunctionStub(
"create",
returnType,
parameters,
receiver = receiver,
typeParameters = listOf(typeParameter),
external = true,
origin = StubOrigin.None,
annotations = annotations,
modality = MemberStubModality.FINAL
)
createMethod
}
is ObjCProtocol -> null
}
} else {
null
}
append(')')
return listOfNotNull(
FunctionStub(
name,
stubReturnType,
kotlinMethodParameters.toList(),
origin,
annotations.toList(),
external,
receiver,
modality),
replacement
)
}
}
private fun deprecatedInit(className: String, initParameterNames: List<String>, factory: Boolean): String {
val replacement = if (factory) "$className.create" else className
val replacementKind = if (factory) "factory method" else "constructor"
val replaceWith = "$replacement(${initParameterNames.joinToString { it.asSimpleName() }})"
return deprecated("Use $replacementKind instead", replaceWith)
}
private fun deprecated(message: String, replaceWith: String): String =
"@Deprecated(${message.quoteAsKotlinLiteral()}, " +
"ReplaceWith(${replaceWith.quoteAsKotlinLiteral()}), " +
"DeprecationLevel.ERROR)"
private val ObjCContainer.classOrProtocol: ObjCClassOrProtocol
internal val ObjCContainer.classOrProtocol: ObjCClassOrProtocol
get() = when (this) {
is ObjCClassOrProtocol -> this
is ObjCCategory -> this.clazz
@@ -265,7 +238,7 @@ private val ObjCContainer.classOrProtocol: ObjCClassOrProtocol
*
* The entire implementation is just the real ABI approximation which is enough for practical cases.
*/
private fun Type.isStret(target: KonanTarget): Boolean {
internal fun Type.isStret(target: KonanTarget): Boolean {
val unwrappedType = this.unwrapTypedefs()
return when (target) {
KonanTarget.IOS_ARM64 ->
@@ -286,6 +259,13 @@ private fun Type.isStret(target: KonanTarget): Boolean {
}
}
private fun deprecatedInit(className: String, initParameterNames: List<String>, factory: Boolean): AnnotationStub {
val replacement = if (factory) "$className.create" else className
val replacementKind = if (factory) "factory method" else "constructor"
val replaceWith = "$replacement(${initParameterNames.joinToString { it.asSimpleName() }})"
return AnnotationStub.Deprecated("Use $replacementKind instead", replaceWith)
}
private fun Type.isIntegerLikeType(): Boolean = when (this) {
is RecordType -> {
val def = this.decl.def
@@ -325,7 +305,7 @@ private fun Type.hasUnalignedMembers(): Boolean = when (this) {
// TODO: should the recursive checks be made in indexer when computing `hasUnalignedFields`?
}
private val ObjCMethod.kotlinName: String
internal val ObjCMethod.kotlinName: String
get() {
val candidate = selector.split(":").first()
val trimmed = candidate.trimEnd('_')
@@ -337,10 +317,10 @@ private val ObjCMethod.kotlinName: String
}
}
private val ObjCClassOrProtocol.protocolsWithSupers: Sequence<ObjCProtocol>
internal val ObjCClassOrProtocol.protocolsWithSupers: Sequence<ObjCProtocol>
get() = this.protocols.asSequence().flatMap { sequenceOf(it) + it.protocolsWithSupers }
private val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtocol>
internal val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtocol>
get() {
val baseClass = (this as? ObjCClass)?.baseClass
if (baseClass != null) {
@@ -350,28 +330,28 @@ private val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtoco
return this.protocols.asSequence()
}
private val ObjCClassOrProtocol.selfAndSuperTypes: Sequence<ObjCClassOrProtocol>
internal val ObjCClassOrProtocol.selfAndSuperTypes: Sequence<ObjCClassOrProtocol>
get() = sequenceOf(this) + this.superTypes
private val ObjCClassOrProtocol.superTypes: Sequence<ObjCClassOrProtocol>
internal val ObjCClassOrProtocol.superTypes: Sequence<ObjCClassOrProtocol>
get() = this.immediateSuperTypes.flatMap { it.selfAndSuperTypes }.distinct()
private fun ObjCClassOrProtocol.declaredMethods(isClass: Boolean): Sequence<ObjCMethod> =
internal fun ObjCClassOrProtocol.declaredMethods(isClass: Boolean): Sequence<ObjCMethod> =
this.methods.asSequence().filter { it.isClass == isClass }
@Suppress("UNUSED_PARAMETER")
private fun Sequence<ObjCMethod>.inheritedTo(container: ObjCClassOrProtocol, isMeta: Boolean): Sequence<ObjCMethod> =
internal fun Sequence<ObjCMethod>.inheritedTo(container: ObjCClassOrProtocol, isMeta: Boolean): Sequence<ObjCMethod> =
this // TODO: exclude methods that are marked as unavailable in [container].
private fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence<ObjCMethod> =
internal fun ObjCClassOrProtocol.inheritedMethods(isClass: Boolean): Sequence<ObjCMethod> =
this.immediateSuperTypes.flatMap { it.methodsWithInherited(isClass) }
.distinctBy { it.selector }
.inheritedTo(this, isClass)
private fun ObjCClassOrProtocol.methodsWithInherited(isClass: Boolean): Sequence<ObjCMethod> =
internal fun ObjCClassOrProtocol.methodsWithInherited(isClass: Boolean): Sequence<ObjCMethod> =
(this.declaredMethods(isClass) + this.inheritedMethods(isClass)).distinctBy { it.selector }
private fun ObjCClass.getDesignatedInitializerSelectors(result: MutableSet<String>): Set<String> {
internal fun ObjCClass.getDesignatedInitializerSelectors(result: MutableSet<String>): Set<String> {
// Note: Objective-C initializers act as usual methods and thus are inherited by subclasses.
// Swift considers all super initializers to be available (unless otherwise specified explicitly),
// but seems to consider them as non-designated if class declares its own ones explicitly.
@@ -392,16 +372,22 @@ private fun ObjCClass.getDesignatedInitializerSelectors(result: MutableSet<Strin
return result
}
private fun ObjCMethod.isOverride(container: ObjCClassOrProtocol): Boolean =
internal fun ObjCMethod.isOverride(container: ObjCClassOrProtocol): Boolean =
container.superTypes.any { superType -> superType.methods.any(this::replaces) }
abstract class ObjCContainerStub(stubGenerator: StubGenerator,
private val container: ObjCClassOrProtocol,
protected val metaContainerStub: ObjCContainerStub?
) : KotlinStub {
internal abstract class ObjCContainerStubBuilder(
final override val context: StubsBuildingContext,
private val container: ObjCClassOrProtocol,
protected val metaContainerStub: ObjCContainerStubBuilder?
) : StubElementBuilder {
private val isMeta: Boolean get() = metaContainerStub == null
private val designatedInitializerSelectors = if (container is ObjCClass && !isMeta) {
container.getDesignatedInitializerSelectors(mutableSetOf())
} else {
emptySet()
}
private val methods: List<ObjCMethod>
private val properties: List<ObjCProperty>
@@ -446,139 +432,130 @@ abstract class ObjCContainerStub(stubGenerator: StubGenerator,
}
}
private val designatedInitializerSelectors = if (container is ObjCClass && !isMeta) {
container.getDesignatedInitializerSelectors(mutableSetOf())
} else {
emptySet()
}
private val methodToStub = methods.map {
it to ObjCMethodStub(
stubGenerator, it, container,
isDesignatedInitializer = it.selector in designatedInitializerSelectors
)
it to ObjCMethodStubBuilder(it, container, it.selector in designatedInitializerSelectors, context)
}.toMap()
private val methodStubs get() = methodToStub.values
val propertyStubs = properties.mapNotNull {
createObjCPropertyStub(stubGenerator, it, container, this.methodToStub)
private val propertyBuilders = properties.mapNotNull {
createObjCPropertyBuilder(context, it, container, this.methodToStub)
}
private val classHeader: String
private val modality = when (container) {
is ObjCClass -> ClassStubModality.OPEN
is ObjCProtocol -> ClassStubModality.INTERFACE
}
init {
val supers = mutableListOf<KotlinType>()
private val classifier = context.getKotlinClassFor(container, isMeta)
private val externalObjCAnnotation = when (container) {
is ObjCProtocol -> {
protocolGetter = if (metaContainerStub != null) {
metaContainerStub.protocolGetter!!
} else {
// TODO: handle the case when protocol getter stub can't be compiled.
context.generateNextUniqueId("kniprot_")
}
AnnotationStub.ObjC.ExternalClass(protocolGetter)
}
is ObjCClass -> {
protocolGetter = null
val binaryName = container.binaryName
AnnotationStub.ObjC.ExternalClass("", binaryName ?: "")
}
}
private val interfaces: List<StubType> by lazy {
val interfaces = mutableListOf<StubType>()
if (container is ObjCClass) {
val baseClass = container.baseClass
val baseClassifier = if (baseClass != null) {
stubGenerator.declarationMapper.getKotlinClassFor(baseClass, isMeta)
context.getKotlinClassFor(baseClass, isMeta)
} else {
if (isMeta) KotlinTypes.objCObjectBaseMeta else KotlinTypes.objCObjectBase
}
supers.add(baseClassifier.type)
interfaces += WrapperStubType(baseClassifier.type)
}
container.protocols.forEach {
supers.add(stubGenerator.declarationMapper.getKotlinClassFor(it, isMeta).type)
interfaces += WrapperStubType(context.getKotlinClassFor(it, isMeta).type)
}
if (supers.isEmpty()) {
if (interfaces.isEmpty()) {
assert(container is ObjCProtocol)
val classifier = if (isMeta) KotlinTypes.objCObjectMeta else KotlinTypes.objCObject
supers.add(classifier.type)
interfaces += WrapperStubType(classifier.type)
}
if (!isMeta && container.isProtocolClass()) {
// TODO: map Protocol type to ObjCProtocol instead.
supers.add(KotlinTypes.objCProtocol.type)
interfaces += WrapperStubType(KotlinTypes.objCProtocol.type)
}
val keywords = when (container) {
is ObjCClass -> "open class"
is ObjCProtocol -> "interface"
}
val supersString = supers.joinToString { it.render(stubGenerator.kotlinFile) }
val classifier = stubGenerator.declarationMapper.getKotlinClassFor(container, isMeta)
val name = stubGenerator.kotlinFile.declare(classifier)
val externalObjCClassAnnotationName = "@ExternalObjCClass"
val externalObjCClassAnnotation: String = when (container) {
is ObjCProtocol -> {
protocolGetter = if (metaContainerStub != null) {
metaContainerStub.protocolGetter!!
} else {
val nativeBacked = object : NativeBacked {}
// TODO: handle the case when protocol getter stub can't be compiled.
genProtocolGetter(stubGenerator, nativeBacked, container)
}
externalObjCClassAnnotationName.applyToStrings(protocolGetter)
}
is ObjCClass -> {
protocolGetter = null
val binaryName = container.binaryName
if (binaryName != null) {
externalObjCClassAnnotationName.applyToStrings("", binaryName)
} else {
externalObjCClassAnnotationName
}
}
}
this.classHeader = "$externalObjCClassAnnotation $keywords $name : $supersString"
interfaces
}
open fun generateBody(context: StubGenerationContext): Sequence<String> {
var result = (propertyStubs.asSequence() + methodStubs.asSequence())
.flatMap { sequenceOf("") + it.generate(context) }
if (container is ObjCClass && methodStubs.none {
it.method.isInit && it.method.parameters.isEmpty() && context.nativeBridges.isSupported(it)
}) {
private fun buildBody(): Pair<List<PropertyStub>, List<FunctionalStub>> {
val defaultConstructor = if (container is ObjCClass && methodToStub.values.none { it.isDefaultConstructor() }) {
// Always generate default constructor.
// If it is not produced for an init method, then include it manually:
result += sequenceOf("", "protected constructor() {}")
}
ConstructorStub(listOf(), listOf(), VisibilityModifier.PROTECTED)
} else null
return result
return Pair(
propertyBuilders.flatMap { it.build() },
methodToStub.values.flatMap { it.build() } + listOfNotNull(defaultConstructor)
)
}
override fun generate(context: StubGenerationContext): Sequence<String> = block(classHeader, generateBody(context))
protected fun buildClassStub(origin: StubOrigin, companion: ClassStub.Companion? = null): ClassStub {
val (properties, methods) = buildBody()
return ClassStub.Simple(
classifier,
properties = properties,
functions = methods,
origin = origin,
modality = modality,
annotations = listOf(externalObjCAnnotation),
interfaces = interfaces,
companion = companion
)
}
}
open class ObjCClassOrProtocolStub(
stubGenerator: StubGenerator,
internal sealed class ObjCClassOrProtocolStubBuilder(
context: StubsBuildingContext,
private val container: ObjCClassOrProtocol
) : ObjCContainerStub(
stubGenerator,
) : ObjCContainerStubBuilder(
context,
container,
metaContainerStub = object : ObjCContainerStub(stubGenerator, container, metaContainerStub = null) {}
) {
override fun generate(context: StubGenerationContext) =
metaContainerStub!!.generate(context) + "" + super.generate(context)
metaContainerStub = object : ObjCContainerStubBuilder(context, container, metaContainerStub = null) {
override fun build(): List<StubIrElement> =
listOf(buildClassStub(StubOrigin.None))
}
)
internal class ObjCProtocolStubBuilder(
context: StubsBuildingContext,
private val protocol: ObjCProtocol
) : ObjCClassOrProtocolStubBuilder(context, protocol), StubElementBuilder {
override fun build(): List<StubIrElement> {
val classStub = buildClassStub(StubOrigin.ObjCProtocol(protocol))
return listOf(*metaContainerStub!!.build().toTypedArray(), classStub)
}
}
class ObjCProtocolStub(stubGenerator: StubGenerator, protocol: ObjCProtocol) :
ObjCClassOrProtocolStub(stubGenerator, protocol)
class ObjCClassStub(private val stubGenerator: StubGenerator, private val clazz: ObjCClass) :
ObjCClassOrProtocolStub(stubGenerator, clazz) {
override fun generateBody(context: StubGenerationContext): Sequence<String> {
val companionSuper = stubGenerator.declarationMapper
.getKotlinClassFor(clazz, isMeta = true).type
.render(stubGenerator.kotlinFile)
internal class ObjCClassStubBuilder(
context: StubsBuildingContext,
private val clazz: ObjCClass
) : ObjCClassOrProtocolStubBuilder(context, clazz), StubElementBuilder {
override fun build(): List<StubIrElement> {
val companionSuper = ClassifierStubType(context.getKotlinClassFor(clazz, isMeta = true))
val objCClassType = KotlinTypes.objCClassOf.typeWith(
stubGenerator.declarationMapper.getKotlinClassFor(clazz, isMeta = false).type
).render(stubGenerator.kotlinFile)
context.getKotlinClassFor(clazz, isMeta = false).type
).let { WrapperStubType(it) }
return sequenceOf( "companion object : $companionSuper(), $objCClassType {}") +
super.generateBody(context)
val superClassInit = SuperClassInit(companionSuper)
val companion = ClassStub.Companion(superClassInit, listOf(objCClassType))
val classStub = buildClassStub(StubOrigin.ObjCClass(clazz), companion)
return listOf(*metaContainerStub!!.build().toTypedArray(), classStub)
}
}
@@ -594,77 +571,71 @@ class GeneratedObjCCategoriesMembers {
}
class ObjCCategoryStub(
private val stubGenerator: StubGenerator, private val category: ObjCCategory
) : KotlinStub {
private val generatedMembers = stubGenerator.generatedObjCCategoriesMembers
internal class ObjCCategoryStubBuilder(
override val context: StubsBuildingContext,
private val category: ObjCCategory
) : StubElementBuilder {
private val generatedMembers = context.generatedObjCCategoriesMembers
.getOrPut(category.clazz, { GeneratedObjCCategoriesMembers() })
// TODO: consider removing members that are also present in the class or its supertypes.
private val methodToStub = category.methods.filter { generatedMembers.register(it) }.map {
it to ObjCMethodStub(stubGenerator, it, category, isDesignatedInitializer = false)
private val methodToBuilder = category.methods.filter { generatedMembers.register(it) }.map {
it to ObjCMethodStubBuilder(it, category, isDesignatedInitializer = false, context = context)
}.toMap()
private val methodStubs get() = methodToStub.values
private val methodBuilders get() = methodToBuilder.values
private val propertyStubs = category.properties.filter { generatedMembers.register(it) }.mapNotNull {
createObjCPropertyStub(stubGenerator, it, category, methodToStub)
private val propertyBuilders = category.properties.filter { generatedMembers.register(it) }.mapNotNull {
createObjCPropertyBuilder(context, it, category, methodToBuilder)
}
override fun generate(context: StubGenerationContext): Sequence<String> {
override fun build(): List<StubIrElement> {
val description = "${category.clazz.name} (${category.name})"
return sequenceOf("// @interface $description") +
propertyStubs.asSequence().flatMap { sequenceOf("") + it.generate(context) } +
methodStubs.asSequence().flatMap { sequenceOf("") + it.generate(context) } +
sequenceOf("// @end; // $description")
val meta = StubContainerMeta(
"// @interface $description",
"// @end; // $description"
)
val container = SimpleStubContainer(
meta = meta,
functions = methodBuilders.flatMap { it.build() },
properties = propertyBuilders.flatMap { it.build() }
)
return listOf(container)
}
}
private fun createObjCPropertyStub(
stubGenerator: StubGenerator,
private fun createObjCPropertyBuilder(
context: StubsBuildingContext,
property: ObjCProperty,
container: ObjCContainer,
methodToStub: Map<ObjCMethod, ObjCMethodStub>
): ObjCPropertyStub? {
methodToStub: Map<ObjCMethod, ObjCMethodStubBuilder>
): ObjCPropertyStubBuilder? {
// Note: the code below assumes that if the property is generated,
// then its accessors are also generated as explicit methods.
val getterStub = methodToStub[property.getter] ?: return null
val setterStub = property.setter?.let { methodToStub[it] ?: return null }
return ObjCPropertyStub(stubGenerator, property, container, getterStub, setterStub)
return ObjCPropertyStubBuilder(context, property, container, getterStub, setterStub)
}
class ObjCPropertyStub(
val stubGenerator: StubGenerator, val property: ObjCProperty, val container: ObjCContainer,
val getterStub: ObjCMethodStub, val setterStub: ObjCMethodStub?
) : KotlinStub {
override fun generate(context: StubGenerationContext): Sequence<String> {
private class ObjCPropertyStubBuilder(
override val context: StubsBuildingContext,
private val property: ObjCProperty,
private val container: ObjCContainer,
private val getterBuilder: ObjCMethodStubBuilder,
private val setterMethod: ObjCMethodStubBuilder?
) : StubElementBuilder {
override fun build(): List<PropertyStub> {
val type = property.getType(container.classOrProtocol)
val kotlinType = stubGenerator.mirror(type).argType.render(stubGenerator.kotlinFile)
val kind = if (property.setter == null) "val" else "var"
val modifiers = if (container is ObjCProtocol) "final " else ""
val kotlinType = context.mirror(type).argType
val getter = PropertyAccessor.Getter.ExternalGetter(annotations = getterBuilder.annotations)
val setter = property.setter?.let { PropertyAccessor.Setter.ExternalSetter(annotations = setterMethod!!.annotations) }
val kind = setter?.let { PropertyStub.Kind.Var(getter, it) } ?: PropertyStub.Kind.Val(getter)
val modality = MemberStubModality.FINAL
val receiver = when (container) {
is ObjCClassOrProtocol -> ""
is ObjCCategory -> stubGenerator.declarationMapper
.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass).type
.render(stubGenerator.kotlinFile) + "."
is ObjCClassOrProtocol -> null
is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
}
val result = mutableListOf(
"$modifiers$kind $receiver${property.name.asSimpleName()}: $kotlinType",
" ${getterStub.objCMethodAnnotations.joinToString(" ")} external get"
)
property.setter?.let {
result.add(" ${setterStub!!.objCMethodAnnotations.joinToString(" ")} external set")
}
return result.asSequence()
return listOf(PropertyStub(property.name, WrapperStubType(kotlinType), kind, modality, receiver))
}
}
fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
@@ -676,27 +647,7 @@ fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
return if (isMeta) "${baseClassName}Meta" else baseClassName
}
private fun genProtocolGetter(
stubGenerator: StubGenerator,
nativeBacked: NativeBacked,
protocol: ObjCProtocol
): String {
val functionName = "kniprot_" + stubGenerator.pkgName.replace('.', '_') + stubGenerator.nextUniqueId()
val builder = NativeCodeBuilder(stubGenerator.simpleBridgeGenerator.topLevelNativeScope)
with(builder) {
out("Protocol* $functionName() {")
out(" return @protocol(${protocol.name});")
out("}")
}
stubGenerator.simpleBridgeGenerator.insertNativeBridge(nativeBacked, emptyList(), builder.lines)
return functionName
}
private fun ObjCClassOrProtocol.isProtocolClass(): Boolean = when (this) {
internal fun ObjCClassOrProtocol.isProtocolClass(): Boolean = when (this) {
is ObjCClass -> (name == "Protocol" || binaryName == "Protocol")
is ObjCProtocol -> false
}
@@ -234,7 +234,6 @@ class SimpleBridgeGeneratorImpl(
}
// TODO: exclude unused bridges.
return object : NativeBridges {
override val kotlinLines: Sequence<String>
@@ -0,0 +1,425 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.indexer.*
interface StubIrElement {
fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T): R
}
sealed class StubContainer : StubIrElement {
abstract val meta: StubContainerMeta
abstract val classes: List<ClassStub>
abstract val functions: List<FunctionalStub>
abstract val properties: List<PropertyStub>
abstract val typealiases: List<TypealiasStub>
abstract val simpleContainers: List<SimpleStubContainer>
}
/**
* Meta information about [StubContainer].
* For example, can be used for comments in textual representation.
*/
class StubContainerMeta(
val textAtStart: String = "",
val textAtEnd: String = ""
)
class SimpleStubContainer(
override val meta: StubContainerMeta = StubContainerMeta(),
override val classes: List<ClassStub> = emptyList(),
override val functions: List<FunctionalStub> = emptyList(),
override val properties: List<PropertyStub> = emptyList(),
override val typealiases: List<TypealiasStub> = emptyList(),
override val simpleContainers: List<SimpleStubContainer> = emptyList()
) : StubContainer() {
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T): R {
return visitor.visitSimpleStubContainer(this, data)
}
}
val StubContainer.children: List<StubIrElement>
get() = (classes as List<StubIrElement>) + properties + functions + typealiases
sealed class StubType {
abstract val nullable: Boolean
}
/**
* Marks that abstract value of such type can be passed as value.
*/
sealed class ValueStub
class TypeParameterStub(
val name: String,
val upperBound: StubType? = null
) {
fun getStubType(nullable: Boolean): StubType =
SymbolicStubType(name, nullable = nullable)
}
// Add variance if needed
class TypeArgumentStub(val type: StubType)
/**
* Wrapper over [KotlinType].
*/
class WrapperStubType(
val kotlinType: KotlinType
) : StubType() {
override val nullable: Boolean
get() = when (kotlinType) {
is KotlinClassifierType -> kotlinType.nullable
is KotlinFunctionType -> kotlinType.nullable
else -> error("Unknown KotlinType: $kotlinType")
}
}
/**
* Wrapper over [Classifier].
*/
class ClassifierStubType(
val classifier: Classifier,
val typeArguments: List<TypeArgumentStub> = emptyList(),
override val nullable: Boolean = false
) : StubType()
/**
* Fallback variant for all cases where we cannot refer to specific [KotlinType] or [Classifier].
*/
class SymbolicStubType(
val name: String,
override val nullable: Boolean = false
) : StubType()
/**
* Represents a source of StubIr element.
*/
sealed class StubOrigin {
/**
* Special case when element of IR was generated.
*/
object None : StubOrigin()
class ObjCMethod(
val method: org.jetbrains.kotlin.native.interop.indexer.ObjCMethod,
val container: ObjCContainer
) : StubOrigin()
class ObjCClass(
val clazz: org.jetbrains.kotlin.native.interop.indexer.ObjCClass
) : StubOrigin()
class ObjCProtocol(
val protocol: org.jetbrains.kotlin.native.interop.indexer.ObjCProtocol
) : StubOrigin()
class Enum(val enum: EnumDef) : StubOrigin()
class Function(val function: FunctionDecl) : StubOrigin()
class FunctionParameter(val parameter: Parameter) : StubOrigin()
class Struct(val struct: StructDecl) : StubOrigin()
}
interface StubElementWithOrigin : StubIrElement {
val origin: StubOrigin
}
interface AnnotationHolder {
val annotations: List<AnnotationStub>
}
sealed class AnnotationStub {
sealed class ObjC : AnnotationStub() {
object ConsumesReceiver : ObjC()
object ReturnsRetained : ObjC()
class Method(val selector: String, val encoding: String, val isStret: Boolean = false) : ObjC()
class Factory(val selector: String, val encoding: String, val isStret: Boolean = false) : ObjC()
object Consumed : ObjC()
class Constructor(val selector: String, val designated: Boolean) : ObjC()
class ExternalClass(val protocolGetter: String = "", val binaryName: String = "") : ObjC()
}
sealed class CCall : AnnotationStub() {
object CString : CCall()
object WCString : CCall()
class Symbol(val symbolName: String) : CCall()
}
class CStruct(val struct: String) : AnnotationStub()
class CNaturalStruct(val members: List<StructMember>) : AnnotationStub()
class CLength(val length: Long) : AnnotationStub()
class Deprecated(val message: String, val replaceWith: String) : AnnotationStub()
}
/**
* Compile-time known values.
*/
sealed class ConstantStub : ValueStub()
class StringConstantStub(val value: String) : ConstantStub()
data class IntegralConstantStub(val value: Long, val size: Int, val isSigned: Boolean) : ConstantStub()
data class DoubleConstantStub(val value: Double, val size: Int) : ConstantStub()
class PropertyStub(
val name: String,
val type: StubType,
val kind: Kind,
val modality: MemberStubModality = MemberStubModality.FINAL,
val receiverType: StubType? = null,
override val annotations: List<AnnotationStub> = emptyList()
) : StubIrElement, AnnotationHolder {
sealed class Kind {
class Val(
val getter: PropertyAccessor.Getter
) : Kind()
class Var(
val getter: PropertyAccessor.Getter,
val setter: PropertyAccessor.Setter
) : Kind()
class Constant(val constant: ConstantStub) : Kind()
}
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T): R {
return visitor.visitProperty(this, data)
}
}
enum class ClassStubModality {
INTERFACE, OPEN, ABSTRACT, NONE
}
enum class VisibilityModifier {
PRIVATE, PROTECTED, INTERNAL, PUBLIC
}
class ConstructorParameterStub(val name: String, val type: StubType, val qualifier: Qualifier = Qualifier.NONE) {
sealed class Qualifier {
class VAL(val overrides: Boolean) : Qualifier()
class VAR(val overrides: Boolean) : Qualifier()
object NONE : Qualifier()
}
}
class GetConstructorParameter(
val constructorParameterStub: ConstructorParameterStub
) : ValueStub()
class SuperClassInit(
val type: StubType,
val arguments: List<ValueStub> = listOf()
)
sealed class ClassStub : StubContainer(), StubElementWithOrigin, AnnotationHolder {
abstract val superClassInit: SuperClassInit?
abstract val interfaces: List<StubType>
abstract val childrenClasses: List<ClassStub>
abstract val companion : Companion?
class Simple(
val classifier: Classifier,
val modality: ClassStubModality,
val constructorParameters: List<ConstructorParameterStub> = emptyList(),
override val superClassInit: SuperClassInit? = null,
override val interfaces: List<StubType> = emptyList(),
override val properties: List<PropertyStub> = emptyList(),
override val origin: StubOrigin,
override val annotations: List<AnnotationStub> = emptyList(),
override val childrenClasses: List<ClassStub> = emptyList(),
override val companion: Companion? = null,
override val functions: List<FunctionalStub> = emptyList(),
override val simpleContainers: List<SimpleStubContainer> = emptyList()
) : ClassStub()
class Companion(
override val superClassInit: SuperClassInit? = null,
override val interfaces: List<StubType> = emptyList(),
override val properties: List<PropertyStub> = emptyList(),
override val origin: StubOrigin = StubOrigin.None,
override val annotations: List<AnnotationStub> = emptyList(),
override val childrenClasses: List<ClassStub> = emptyList(),
override val functions: List<FunctionalStub> = emptyList(),
override val simpleContainers: List<SimpleStubContainer> = emptyList()
) : ClassStub() {
override val companion: Companion? = null
}
class Enum(
val classifier: Classifier,
val entries: List<EnumEntryStub>,
val constructorParameters: List<ConstructorParameterStub> = emptyList(),
override val superClassInit: SuperClassInit? = null,
override val interfaces: List<StubType> = emptyList(),
override val properties: List<PropertyStub> = emptyList(),
override val origin: StubOrigin,
override val annotations: List<AnnotationStub> = emptyList(),
override val childrenClasses: List<ClassStub> = emptyList(),
override val companion: Companion?= null,
override val functions: List<FunctionalStub> = emptyList(),
override val simpleContainers: List<SimpleStubContainer> = emptyList()
) : ClassStub()
override val meta: StubContainerMeta = StubContainerMeta()
override val classes: List<ClassStub>
get() = childrenClasses + listOfNotNull(companion)
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T) =
visitor.visitClass(this, data)
override val typealiases: List<TypealiasStub> = emptyList()
}
class ReceiverParameterStub(
val type: StubType
)
class FunctionParameterStub(
val name: String,
val type: StubType,
override val annotations: List<AnnotationStub> = emptyList(),
val isVararg: Boolean = false,
val origin: StubOrigin = StubOrigin.None
) : AnnotationHolder
enum class MemberStubModality {
OVERRIDE,
OPEN,
FINAL
}
interface FunctionalStub : AnnotationHolder, StubIrElement, NativeBacked {
val parameters: List<FunctionParameterStub>
}
sealed class PropertyAccessor : FunctionalStub {
sealed class Getter : PropertyAccessor() {
override val parameters: List<FunctionParameterStub> = emptyList()
class SimpleGetter(
override val annotations: List<AnnotationStub> = emptyList(),
val constant: ConstantStub? = null
) : Getter()
class ExternalGetter(
override val annotations: List<AnnotationStub> = emptyList()
) : Getter()
class ArrayMemberAt(
val offset: Long
) : Getter() {
override val parameters: List<FunctionParameterStub> = emptyList()
override val annotations: List<AnnotationStub> = emptyList()
}
class MemberAt(
val offset: Long,
val typeArguments: List<TypeArgumentStub> = emptyList(),
val hasValueAccessor: Boolean
) : Getter() {
override val annotations: List<AnnotationStub> = emptyList()
}
class ReadBits(
val offset: Long,
val size: Int,
val signed: Boolean
) : Getter() {
override val annotations: List<AnnotationStub> = emptyList()
}
class InterpretPointed(val cGlobalName:String, pointedType: WrapperStubType) : Getter() {
override val annotations: List<AnnotationStub> = emptyList()
val typeParameters: List<StubType> = listOf(pointedType)
}
}
sealed class Setter : PropertyAccessor() {
override val parameters: List<FunctionParameterStub> = emptyList()
class SimpleSetter(
override val annotations: List<AnnotationStub> = emptyList()
) : Setter()
class ExternalSetter(
override val annotations: List<AnnotationStub> = emptyList()
) : Setter()
class MemberAt(
val offset: Long,
override val annotations: List<AnnotationStub> = emptyList(),
val typeArguments: List<TypeArgumentStub> = emptyList()
) : Setter()
class WriteBits(
val offset: Long,
val size: Int,
override val annotations: List<AnnotationStub> = emptyList()
) : Setter()
}
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T) =
visitor.visitPropertyAccessor(this, data)
}
class FunctionStub(
val name: String,
val returnType: StubType,
override val parameters: List<FunctionParameterStub>,
override val origin: StubOrigin,
override val annotations: List<AnnotationStub>,
val external: Boolean = false,
val receiver: ReceiverParameterStub?,
val modality: MemberStubModality,
val typeParameters: List<TypeParameterStub> = emptyList()
) : StubElementWithOrigin, FunctionalStub {
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T) =
visitor.visitFunction(this, data)
}
// TODO: should we support non-trivial constructors?
class ConstructorStub(
override val parameters: List<FunctionParameterStub>,
override val annotations: List<AnnotationStub>,
val visibility: VisibilityModifier = VisibilityModifier.PUBLIC
) : FunctionalStub {
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T) =
visitor.visitConstructor(this, data)
}
class EnumEntryStub(
val name: String,
val constant: IntegralConstantStub,
val aliases: List<Alias>
) {
class Alias(val name: String)
}
class TypealiasStub(
val alias: ClassifierStubType,
val aliasee: StubType
) : StubIrElement {
override fun <T, R> accept(visitor: StubIrVisitor<T, R>, data: T) =
visitor.visitTypealias(this, data)
}
@@ -0,0 +1,294 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.indexer.ObjCProtocol
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class BridgeBuilderResult(
val kotlinFile: KotlinFile,
val nativeBridges: NativeBridges,
val propertyAccessorBridgeBodies: Map<PropertyAccessor, String>,
val functionBridgeBodies: Map<FunctionStub, List<String>>,
val excludedStubs: Set<StubIrElement>
)
/**
* Generates [NativeBridges] and corresponding function bodies and property accessors.
*/
class StubIrBridgeBuilder(
private val context: StubIrContext,
private val builderResult: StubIrBuilderResult) {
private val globalAddressExpressions = mutableMapOf<Pair<String, PropertyAccessor>, KotlinExpression>()
private fun getGlobalAddressExpression(cGlobalName: String, accessor: PropertyAccessor) =
globalAddressExpressions.getOrPut(Pair(cGlobalName, accessor)) {
simpleBridgeGenerator.kotlinToNative(
nativeBacked = accessor,
returnType = BridgedType.NATIVE_PTR,
kotlinValues = emptyList(),
independent = false
) {
"&$cGlobalName"
}
}
private val declarationMapper = builderResult.declarationMapper
private val kotlinFile = object : KotlinFile(
context.configuration.pkgName,
namesToBeDeclared = builderResult.stubs.computeNamesToBeDeclared(context.configuration.pkgName)
) {
override val mappingBridgeGenerator: MappingBridgeGenerator
get() = this@StubIrBridgeBuilder.mappingBridgeGenerator
}
private val simpleBridgeGenerator: SimpleBridgeGenerator =
SimpleBridgeGeneratorImpl(
context.platform,
context.configuration.pkgName,
context.jvmFileClassName,
context.libraryForCStubs,
topLevelNativeScope = object : NativeScope {
override val mappingBridgeGenerator: MappingBridgeGenerator
get() = this@StubIrBridgeBuilder.mappingBridgeGenerator
},
topLevelKotlinScope = kotlinFile
)
private val mappingBridgeGenerator: MappingBridgeGenerator =
MappingBridgeGeneratorImpl(declarationMapper, simpleBridgeGenerator)
private val propertyAccessorBridgeBodies = mutableMapOf<PropertyAccessor, String>()
private val functionBridgeBodies = mutableMapOf<FunctionStub, List<String>>()
private val excludedStubs = mutableSetOf<StubIrElement>()
private val bridgeGeneratingVisitor = object : StubIrVisitor<StubContainer?, Unit> {
override fun visitClass(element: ClassStub, owner: StubContainer?) {
element.annotations.filterIsInstance<AnnotationStub.ObjC.ExternalClass>().firstOrNull()?.let {
if (it.protocolGetter.isNotEmpty() && element.origin is StubOrigin.ObjCProtocol) {
val protocol = (element.origin as StubOrigin.ObjCProtocol).protocol
// TODO: handle the case when protocol getter stub can't be compiled.
generateProtocolGetter(it.protocolGetter, protocol)
}
}
element.children.forEach {
it.accept(this, element)
}
}
override fun visitTypealias(element: TypealiasStub, owner: StubContainer?) {
}
override fun visitFunction(element: FunctionStub, owner: StubContainer?) {
try {
when {
element.external -> tryProcessCCallAnnotation(element)
element.isOptionalObjCMethod() -> { }
owner != null && owner.isInterface -> { }
else -> generateBridgeBody(element)
}
} catch (e: Throwable) {
context.log("Warning: cannot generate bridge for ${element.name}.")
excludedStubs += element
}
}
private fun tryProcessCCallAnnotation(function: FunctionStub) {
val origin = function.origin as? StubOrigin.Function
?: return
val cCallAnnotation = function.annotations.firstIsInstanceOrNull<AnnotationStub.CCall.Symbol>()
?: return
val cCallSymbolName = cCallAnnotation.symbolName
simpleBridgeGenerator.insertNativeBridge(
function,
emptyList(),
listOf("extern const void* $cCallSymbolName __asm(${cCallSymbolName.quoteAsKotlinLiteral()});",
"extern const void* $cCallSymbolName = &${origin.function.name};")
)
}
override fun visitProperty(element: PropertyStub, owner: StubContainer?) {
try {
when (val kind = element.kind) {
is PropertyStub.Kind.Constant -> {
}
is PropertyStub.Kind.Val -> {
visitPropertyAccessor(kind.getter, owner)
}
is PropertyStub.Kind.Var -> {
visitPropertyAccessor(kind.getter, owner)
visitPropertyAccessor(kind.setter, owner)
}
}
} catch (e: Throwable) {
context.log("Warning: cannot generate bridge for ${element.name}.")
excludedStubs += element
}
}
override fun visitConstructor(constructorStub: ConstructorStub, owner: StubContainer?) {
}
override fun visitPropertyAccessor(accessor: PropertyAccessor, owner: StubContainer?) {
when (accessor) {
is PropertyAccessor.Getter.SimpleGetter -> {
if (accessor in builderResult.bridgeGenerationComponents.getterToBridgeInfo) {
val extra = builderResult.bridgeGenerationComponents.getterToBridgeInfo.getValue(accessor)
val typeInfo = extra.typeInfo
val expression = if (extra.isArray) {
val getAddressExpression = getGlobalAddressExpression(extra.cGlobalName, accessor)
typeInfo.argFromBridged(getAddressExpression, kotlinFile, nativeBacked = accessor) + "!!"
} else {
typeInfo.argFromBridged(simpleBridgeGenerator.kotlinToNative(
nativeBacked = accessor,
returnType = typeInfo.bridgedType,
kotlinValues = emptyList(),
independent = false
) {
typeInfo.cToBridged(expr = extra.cGlobalName)
}, kotlinFile, nativeBacked = accessor)
}
propertyAccessorBridgeBodies[accessor] = expression
}
}
is PropertyAccessor.Getter.ReadBits -> {
val extra = builderResult.bridgeGenerationComponents.getterToBridgeInfo.getValue(accessor)
val rawType = extra.typeInfo.bridgedType
val readBits = "readBits(this.rawPtr, ${accessor.offset}, ${accessor.size}, ${accessor.signed}).${rawType.convertor!!}()"
val getExpr = extra.typeInfo.argFromBridged(readBits, kotlinFile, object : NativeBacked {})
propertyAccessorBridgeBodies[accessor] = getExpr
}
is PropertyAccessor.Setter.SimpleSetter -> when (accessor) {
in builderResult.bridgeGenerationComponents.setterToBridgeInfo -> {
val extra = builderResult.bridgeGenerationComponents.setterToBridgeInfo.getValue(accessor)
val typeInfo = extra.typeInfo
val bridgedValue = BridgeTypedKotlinValue(typeInfo.bridgedType, typeInfo.argToBridged("value"))
val setter = simpleBridgeGenerator.kotlinToNative(
nativeBacked = accessor,
returnType = BridgedType.VOID,
kotlinValues = listOf(bridgedValue),
independent = false
) { nativeValues ->
out("${extra.cGlobalName} = ${typeInfo.cFromBridged(
nativeValues.single(),
scope,
nativeBacked = accessor
)};")
""
}
propertyAccessorBridgeBodies[accessor] = setter
}
}
is PropertyAccessor.Setter.WriteBits -> {
val extra = builderResult.bridgeGenerationComponents.setterToBridgeInfo.getValue(accessor)
val rawValue = extra.typeInfo.argToBridged("value")
propertyAccessorBridgeBodies[accessor] = "writeBits(this.rawPtr, ${accessor.offset}, ${accessor.size}, $rawValue.toLong())"
}
is PropertyAccessor.Getter.InterpretPointed -> {
val getAddressExpression = getGlobalAddressExpression(accessor.cGlobalName, accessor)
propertyAccessorBridgeBodies[accessor] = getAddressExpression
}
}
}
override fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, owner: StubContainer?) {
simpleStubContainer.classes.forEach {
it.accept(this, simpleStubContainer)
}
simpleStubContainer.functions.forEach {
it.accept(this, simpleStubContainer)
}
simpleStubContainer.properties.forEach {
it.accept(this, simpleStubContainer)
}
simpleStubContainer.typealiases.forEach {
it.accept(this, simpleStubContainer)
}
simpleStubContainer.simpleContainers.forEach {
it.accept(this, simpleStubContainer)
}
}
}
private fun isCValuesRef(type: StubType): Boolean {
if (type !is WrapperStubType) return false
return type.kotlinType is KotlinClassifierType && type.kotlinType.classifier == KotlinTypes.cValuesRef
}
private fun generateBridgeBody(function: FunctionStub) {
assert(function.origin is StubOrigin.Function) { "Can't create bridge for ${function.name}" }
val origin = function.origin as StubOrigin.Function
val bodyGenerator = KotlinCodeBuilder(scope = kotlinFile)
val bridgeArguments = mutableListOf<TypedKotlinValue>()
var isVararg = false
function.parameters.forEachIndexed { index, parameter ->
isVararg = isVararg or parameter.isVararg
val parameterName = parameter.name.asSimpleName()
val bridgeArgument = when {
parameter in builderResult.bridgeGenerationComponents.cStringParameters -> {
bodyGenerator.pushMemScoped()
"$parameterName?.cstr?.getPointer(memScope)"
}
parameter in builderResult.bridgeGenerationComponents.wCStringParameters -> {
bodyGenerator.pushMemScoped()
"$parameterName?.wcstr?.getPointer(memScope)"
}
isCValuesRef(parameter.type) -> {
bodyGenerator.pushMemScoped()
bodyGenerator.getNativePointer(parameterName)
}
else -> {
parameterName
}
}
bridgeArguments += TypedKotlinValue(origin.function.parameters[index].type, bridgeArgument)
}
// TODO: Improve assertion message.
assert(!isVararg || context.platform != KotlinPlatform.NATIVE) {
"Function ${function.name} was processed incorrectly."
}
val result = mappingBridgeGenerator.kotlinToNative(
bodyGenerator,
function,
origin.function.returnType,
bridgeArguments,
independent = false
) { nativeValues ->
"${origin.function.name}(${nativeValues.joinToString()})"
}
bodyGenerator.returnResult(result)
functionBridgeBodies[function] = bodyGenerator.build()
}
private fun generateProtocolGetter(protocolGetterName: String, protocol: ObjCProtocol) {
val builder = NativeCodeBuilder(simpleBridgeGenerator.topLevelNativeScope)
val nativeBacked = object : NativeBacked {}
with(builder) {
out("Protocol* $protocolGetterName() {")
out(" return @protocol(${protocol.name});")
out("}")
}
simpleBridgeGenerator.insertNativeBridge(nativeBacked, emptyList(), builder.lines)
}
fun build(): BridgeBuilderResult {
bridgeGeneratingVisitor.visitSimpleStubContainer(builderResult.stubs, null)
return BridgeBuilderResult(
kotlinFile,
simpleBridgeGenerator.prepare(),
propertyAccessorBridgeBodies.toMap(),
functionBridgeBodies.toMap(),
excludedStubs.toSet()
)
}
}
@@ -0,0 +1,359 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.InteropConfiguration
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.indexer.*
/**
* Additional components that are required to generate bridges.
*/
interface BridgeGenerationComponents {
class GlobalSetterBridgeInfo(
val cGlobalName: String,
val typeInfo: TypeInfo
)
class GlobalGetterBridgeInfo(
val cGlobalName: String,
val typeInfo: TypeInfo,
val isArray: Boolean
)
val setterToBridgeInfo: Map<PropertyAccessor.Setter, GlobalSetterBridgeInfo>
val getterToBridgeInfo: Map<PropertyAccessor.Getter, GlobalGetterBridgeInfo>
val enumToTypeMirror: Map<ClassStub.Enum, TypeMirror>
val wCStringParameters: Set<FunctionParameterStub>
val cStringParameters: Set<FunctionParameterStub>
}
class BridgeGenerationComponentsBuilder(
val getterToBridgeInfo: MutableMap<PropertyAccessor.Getter, BridgeGenerationComponents.GlobalGetterBridgeInfo> = mutableMapOf(),
val setterToBridgeInfo: MutableMap<PropertyAccessor.Setter, BridgeGenerationComponents.GlobalSetterBridgeInfo> = mutableMapOf(),
val enumToTypeMirror: MutableMap<ClassStub.Enum, TypeMirror> = mutableMapOf(),
val wCStringParameters: MutableSet<FunctionParameterStub> = mutableSetOf(),
val cStringParameters: MutableSet<FunctionParameterStub> = mutableSetOf()
) {
fun build(): BridgeGenerationComponents = object : BridgeGenerationComponents {
override val getterToBridgeInfo =
this@BridgeGenerationComponentsBuilder.getterToBridgeInfo.toMap()
override val setterToBridgeInfo =
this@BridgeGenerationComponentsBuilder.setterToBridgeInfo.toMap()
override val enumToTypeMirror =
this@BridgeGenerationComponentsBuilder.enumToTypeMirror.toMap()
override val wCStringParameters: Set<FunctionParameterStub> =
this@BridgeGenerationComponentsBuilder.wCStringParameters.toSet()
override val cStringParameters: Set<FunctionParameterStub> =
this@BridgeGenerationComponentsBuilder.cStringParameters.toSet()
}
}
/**
* Common part of all [StubIrBuilder] implementations.
*/
interface StubsBuildingContext {
val configuration: InteropConfiguration
fun mirror(type: Type): TypeMirror
val declarationMapper: DeclarationMapper
fun generateNextUniqueId(prefix: String): String
val generatedObjCCategoriesMembers: MutableMap<ObjCClass, GeneratedObjCCategoriesMembers>
val platform: KotlinPlatform
fun isStrictEnum(enumDef: EnumDef): Boolean
val macroConstantsByName: Map<String, MacroDef>
fun tryCreateIntegralStub(type: Type, value: Long): IntegralConstantStub?
fun tryCreateDoubleStub(type: Type, value: Double): DoubleConstantStub?
val bridgeComponentsBuilder: BridgeGenerationComponentsBuilder
fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean = false): Classifier
fun getKotlinClassForPointed(structDecl: StructDecl): Classifier
}
/**
*
*/
internal interface StubElementBuilder {
val context: StubsBuildingContext
fun build(): List<StubIrElement>
}
class StubsBuildingContextImpl(
private val stubIrContext: StubIrContext
) : StubsBuildingContext {
override val configuration: InteropConfiguration = stubIrContext.configuration
override val platform: KotlinPlatform = stubIrContext.platform
val imports: Imports = stubIrContext.imports
private val nativeIndex: NativeIndex = stubIrContext.nativeIndex
private var theCounter = 0
override fun generateNextUniqueId(prefix: String) =
prefix + pkgName.replace('.', '_') + theCounter++
override fun mirror(type: Type): TypeMirror = mirror(declarationMapper, type)
/**
* Indicates whether this enum should be represented as Kotlin enum.
*/
override fun isStrictEnum(enumDef: EnumDef): Boolean = with(enumDef) {
if (this.isAnonymous) {
return false
}
val name = this.kotlinName
if (name in configuration.strictEnums) {
return true
}
if (name in configuration.nonStrictEnums) {
return false
}
// Let the simple heuristic decide:
return !this.constants.any { it.isExplicitlyDefined }
}
override val generatedObjCCategoriesMembers = mutableMapOf<ObjCClass, GeneratedObjCCategoriesMembers>()
override val declarationMapper = object : DeclarationMapper {
override fun getKotlinClassForPointed(structDecl: StructDecl): Classifier {
val baseName = structDecl.kotlinName
val pkg = when (platform) {
KotlinPlatform.JVM -> pkgName
KotlinPlatform.NATIVE -> if (structDecl.def == null) {
cnamesStructsPackageName // to be imported as forward declaration.
} else {
getPackageFor(structDecl)
}
}
return Classifier.topLevel(pkg, baseName)
}
override fun isMappedToStrict(enumDef: EnumDef): Boolean = isStrictEnum(enumDef)
override fun getKotlinNameForValue(enumDef: EnumDef): String = enumDef.kotlinName
override fun getPackageFor(declaration: TypeDeclaration): String {
return imports.getPackage(declaration.location) ?: pkgName
}
override val useUnsignedTypes: Boolean
get() = when (platform) {
KotlinPlatform.JVM -> false
KotlinPlatform.NATIVE -> true
}
}
override val macroConstantsByName: Map<String, MacroDef> =
(nativeIndex.macroConstants + nativeIndex.wrappedMacros).associateBy { it.name }
/**
* The name to be used for this enum in Kotlin
*/
val EnumDef.kotlinName: String
get() = if (spelling.startsWith("enum ")) {
spelling.substringAfter(' ')
} else {
assert (!isAnonymous)
spelling
}
private val pkgName: String
get() = configuration.pkgName
/**
* The name to be used for this struct in Kotlin
*/
val StructDecl.kotlinName: String
get() = stubIrContext.getKotlinName(this)
override fun tryCreateIntegralStub(type: Type, value: Long): IntegralConstantStub? {
val integerType = type.unwrapTypedefs() as? IntegerType ?: return null
val size = integerType.size
if (size != 1 && size != 2 && size != 4 && size != 8) return null
return IntegralConstantStub(value, size, declarationMapper.isMappedToSigned(integerType))
}
override fun tryCreateDoubleStub(type: Type, value: Double): DoubleConstantStub? {
val unwrappedType = type.unwrapTypedefs() as? FloatingType ?: return null
val size = unwrappedType.size
if (size != 4 && size != 8) return null
return DoubleConstantStub(value, size)
}
override val bridgeComponentsBuilder = BridgeGenerationComponentsBuilder()
override fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean): Classifier {
return declarationMapper.getKotlinClassFor(objCClassOrProtocol, isMeta)
}
override fun getKotlinClassForPointed(structDecl: StructDecl): Classifier {
val classifier = declarationMapper.getKotlinClassForPointed(structDecl)
return classifier
}
}
data class StubIrBuilderResult(
val stubs: SimpleStubContainer,
val declarationMapper: DeclarationMapper,
val bridgeGenerationComponents: BridgeGenerationComponents
)
/**
* Produces [StubIrBuilderResult] for given [KotlinPlatform] using [InteropConfiguration].
*/
class StubIrBuilder(private val context: StubIrContext) {
private val configuration = context.configuration
private val nativeIndex: NativeIndex = context.nativeIndex
private val classes = mutableListOf<ClassStub>()
private val functions = mutableListOf<FunctionStub>()
private val globals = mutableListOf<PropertyStub>()
private val typealiases = mutableListOf<TypealiasStub>()
private val containers = mutableListOf<SimpleStubContainer>()
private fun addStubs(stubs: List<StubIrElement>) = stubs.forEach(this::addStub)
private fun addStub(stub: StubIrElement) {
when(stub) {
is ClassStub -> classes += stub
is FunctionStub -> functions += stub
is PropertyStub -> globals += stub
is TypealiasStub -> typealiases += stub
is SimpleStubContainer -> containers += stub
else -> error("Unexpected stub: $stub")
}
}
private val excludedFunctions: Set<String>
get() = configuration.excludedFunctions
private val excludedMacros: Set<String>
get() = configuration.excludedMacros
private val buildingContext = StubsBuildingContextImpl(context)
fun build(): StubIrBuilderResult {
nativeIndex.objCProtocols.filter { !it.isForwardDeclaration }.forEach { generateStubsForObjCProtocol(it) }
nativeIndex.objCClasses.filter { !it.isForwardDeclaration && !it.isNSStringSubclass()} .forEach { generateStubsForObjCClass(it) }
nativeIndex.objCCategories.filter { !it.clazz.isNSStringSubclass() }.forEach { generateStubsForObjCCategory(it) }
nativeIndex.structs.forEach { generateStubsForStruct(it) }
nativeIndex.enums.forEach { generateStubsForEnum(it) }
nativeIndex.functions.filter { it.name !in excludedFunctions }.forEach { generateStubsForFunction(it) }
nativeIndex.typedefs.forEach { generateStubsForTypedef(it) }
nativeIndex.globals.filter { it.name !in excludedFunctions }.forEach { generateStubsForGlobal(it) }
nativeIndex.macroConstants.filter { it.name !in excludedMacros }.forEach { generateStubsForMacroConstant(it) }
nativeIndex.wrappedMacros.filter { it.name !in excludedMacros }.forEach { generateStubsForWrappedMacro(it) }
val meta = StubContainerMeta()
val stubs = SimpleStubContainer(
meta,
classes.toList(),
functions.toList(),
globals.toList(),
typealiases.toList(),
containers.toList()
)
return StubIrBuilderResult(
stubs,
buildingContext.declarationMapper,
buildingContext.bridgeComponentsBuilder.build()
)
}
private fun generateStubsForWrappedMacro(macro: WrappedMacroDef) {
try {
generateStubsForGlobal(GlobalDecl(macro.name, macro.type, isConst = true))
} catch (e: Throwable) {
context.log("Warning: cannot generate stubs for macro ${macro.name}")
}
}
private fun generateStubsForMacroConstant(constant: ConstantDef) {
try {
addStubs(MacroConstantStubBuilder(buildingContext, constant).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate stubs for constant ${constant.name}")
}
}
private fun generateStubsForEnum(enumDef: EnumDef) {
try {
addStubs(EnumStubBuilder(buildingContext, enumDef).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate definition for enum ${enumDef.spelling}")
}
}
private fun generateStubsForFunction(func: FunctionDecl) {
try {
addStubs(FunctionStubBuilder(buildingContext, func).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate stubs for function ${func.name}")
}
}
private fun generateStubsForStruct(decl: StructDecl) {
try {
addStubs(StructStubBuilder(buildingContext, decl).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate definition for struct ${decl.spelling}")
}
}
private fun generateStubsForTypedef(typedefDef: TypedefDef) {
try {
addStubs(TypedefStubBuilder(buildingContext, typedefDef).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate typedef ${typedefDef.name}")
}
}
private fun generateStubsForGlobal(global: GlobalDecl) {
try {
addStubs(GlobalStubBuilder(buildingContext, global).build())
} catch (e: Throwable) {
context.log("Warning: cannot generate stubs for global ${global.name}")
}
}
private fun generateStubsForObjCProtocol(objCProtocol: ObjCProtocol) {
addStubs(ObjCProtocolStubBuilder(buildingContext, objCProtocol).build())
}
private fun generateStubsForObjCClass(objCClass: ObjCClass) {
addStubs(ObjCClassStubBuilder(buildingContext, objCClass).build())
}
private fun generateStubsForObjCCategory(objCCategory: ObjCCategory) {
addStubs(ObjCCategoryStubBuilder(buildingContext, objCCategory).build())
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.InteropConfiguration
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.indexer.*
import java.io.File
import java.util.*
class StubIrContext(
val log: (String) -> Unit,
val configuration: InteropConfiguration,
val nativeIndex: NativeIndex,
val imports: Imports,
val platform: KotlinPlatform,
val libName: String
) {
val libraryForCStubs = configuration.library.copy(
includes = mutableListOf<String>().apply {
add("stdint.h")
add("string.h")
if (platform == KotlinPlatform.JVM) {
add("jni.h")
}
addAll(configuration.library.includes)
},
compilerArgs = configuration.library.compilerArgs,
additionalPreambleLines = configuration.library.additionalPreambleLines +
when (configuration.library.language) {
Language.C -> emptyList()
Language.OBJECTIVE_C -> listOf("void objc_terminate();")
}
).precompileHeaders()
val jvmFileClassName = if (configuration.pkgName.isEmpty()) {
libName
} else {
configuration.pkgName.substringAfterLast('.')
}
private val anonymousStructKotlinNames = mutableMapOf<StructDecl, String>()
private val forbiddenStructNames = run {
val typedefNames = nativeIndex.typedefs.map { it.name }
typedefNames.toSet()
}
/**
* The name to be used for this struct in Kotlin
*/
fun getKotlinName(decl: StructDecl): String {
val spelling = decl.spelling
if (decl.isAnonymous) {
val names = anonymousStructKotlinNames
return names.getOrPut(decl) {
"anonymousStruct${names.size + 1}"
}
}
val strippedCName = if (spelling.startsWith("struct ") || spelling.startsWith("union ")) {
spelling.substringAfter(' ')
} else {
spelling
}
// TODO: don't mangle struct names because it wouldn't work if the struct
// is imported into another interop library.
return if (strippedCName !in forbiddenStructNames) strippedCName else (strippedCName + "Struct")
}
fun addManifestProperties(properties: Properties) {
val exportForwardDeclarations = configuration.exportForwardDeclarations.toMutableList()
nativeIndex.structs
.filter { it.def == null }
.mapTo(exportForwardDeclarations) {
"$cnamesStructsPackageName.${getKotlinName(it)}"
}
properties["exportForwardDeclarations"] = exportForwardDeclarations.joinToString(" ")
// TODO: consider exporting Objective-C class and protocol forward refs.
}
}
class StubIrDriver(private val context: StubIrContext) {
fun run(outKtFile: File, outCFile: File, entryPoint: String?) {
val builderResult = StubIrBuilder(context).build()
val bridgeBuilderResult = StubIrBridgeBuilder(context, builderResult).build()
outKtFile.bufferedWriter().use { ktFile ->
File(outCFile.absolutePath).bufferedWriter().use { cFile ->
StubIrTextEmitter(
context,
builderResult,
bridgeBuilderResult
).emit(ktFile, cFile, entryPoint)
}
}
}
}
@@ -0,0 +1,499 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.indexer.*
internal class MacroConstantStubBuilder(
override val context: StubsBuildingContext,
private val constant: ConstantDef
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
val kotlinName = constant.name
val declaration = when (constant) {
is IntegerConstantDef -> {
val literal = context.tryCreateIntegralStub(constant.type, constant.value) ?: return emptyList()
val kotlinType = WrapperStubType(context.mirror(constant.type).argType)
when (context.platform) {
KotlinPlatform.NATIVE -> PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Constant(literal))
// No reason to make it const val with backing field on Kotlin/JVM yet:
KotlinPlatform.JVM -> {
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Val(getter))
}
}
}
is FloatingConstantDef -> {
val literal = context.tryCreateDoubleStub(constant.type, constant.value) ?: return emptyList()
val kotlinType = WrapperStubType(context.mirror(constant.type).argType)
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Val(getter))
}
is StringConstantDef -> {
val literal = StringConstantStub(constant.value.quoteAsKotlinLiteral())
val kotlinType = WrapperStubType(KotlinTypes.string)
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
PropertyStub(kotlinName, kotlinType, PropertyStub.Kind.Val(getter))
}
else -> return emptyList()
}
return listOf(declaration)
}
}
internal class StructStubBuilder(
override val context: StubsBuildingContext,
private val decl: StructDecl
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
val platform = context.platform
val def = decl.def ?: return generateForwardStruct(decl)
val structAnnotation: AnnotationStub? = if (platform == KotlinPlatform.JVM) {
if (def.kind == StructDef.Kind.STRUCT && def.fieldsHaveDefaultAlignment()) {
AnnotationStub.CNaturalStruct(def.members)
} else {
null
}
} else {
tryRenderStructOrUnion(def)?.let {
AnnotationStub.CStruct(it)
}
}
val classifier = context.getKotlinClassForPointed(decl)
val fields: List<PropertyStub?> = def.fields.map { field ->
try {
assert(field.name.isNotEmpty())
assert(field.offset % 8 == 0L)
val offset = field.offset / 8
val fieldRefType = context.mirror(field.type)
val unwrappedFieldType = field.type.unwrapTypedefs()
if (unwrappedFieldType is ArrayType) {
val type = (fieldRefType as TypeMirror.ByValue).valueType
val annotations = if (platform == KotlinPlatform.JVM) {
val length = getArrayLength(unwrappedFieldType)
// TODO: @CLength should probably be used on types instead of properties.
listOf(AnnotationStub.CLength(length))
} else {
emptyList()
}
val kind = PropertyStub.Kind.Val(PropertyAccessor.Getter.ArrayMemberAt(offset))
// TODO: Should receiver be added?
PropertyStub(field.name, WrapperStubType(type), kind, annotations = annotations)
} else {
val pointedType = WrapperStubType(fieldRefType.pointedType)
val pointedTypeArgument = TypeArgumentStub(pointedType)
if (fieldRefType is TypeMirror.ByValue) {
val kind = PropertyStub.Kind.Var(
PropertyAccessor.Getter.MemberAt(offset, typeArguments = listOf(pointedTypeArgument), hasValueAccessor = true),
PropertyAccessor.Setter.MemberAt(offset, typeArguments = listOf(pointedTypeArgument))
)
PropertyStub(field.name, WrapperStubType(fieldRefType.argType), kind)
} else {
val kind = PropertyStub.Kind.Val(PropertyAccessor.Getter.MemberAt(offset, hasValueAccessor = false))
PropertyStub(field.name, pointedType, kind)
}
}
} catch (e: Throwable) {
null
}
}
val bitFields: List<PropertyStub> = def.bitFields.map { field ->
val typeMirror = context.mirror(field.type)
val typeInfo = typeMirror.info
val kotlinType = typeMirror.argType
val signed = field.type.isIntegerTypeSigned()
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
val writeBits = PropertyAccessor.Setter.WriteBits(field.offset, field.size)
// TODO: Use something instead of [GlobalGetterBridgeInfo].
context.bridgeComponentsBuilder.getterToBridgeInfo[readBits] = BridgeGenerationComponents.GlobalGetterBridgeInfo("", typeInfo, false)
context.bridgeComponentsBuilder.setterToBridgeInfo[writeBits] = BridgeGenerationComponents.GlobalSetterBridgeInfo("", typeInfo)
val kind = PropertyStub.Kind.Var(readBits, writeBits)
PropertyStub(field.name, WrapperStubType(kotlinType), kind)
}
val superClass = SymbolicStubType("CStructVar")
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", SymbolicStubType("NativePtr"))
val superClassInit = SuperClassInit(superClass, listOf(GetConstructorParameter(rawPtrConstructorParam)))
// TODO: How we will differ Type and CStructVar.Type?
val companionSuper = SymbolicStubType("Type")
val typeSize = listOf(IntegralConstantStub(def.size, 4, true), IntegralConstantStub(def.align.toLong(), 4, true))
val companionSuperInit = SuperClassInit(companionSuper, typeSize)
val companion = ClassStub.Companion(companionSuperInit)
return listOf(ClassStub.Simple(
classifier,
origin = StubOrigin.Struct(decl),
properties = fields.filterNotNull() + if (platform == KotlinPlatform.NATIVE) bitFields else emptyList(),
functions = emptyList(),
modality = ClassStubModality.NONE,
annotations = listOfNotNull(structAnnotation),
superClassInit = superClassInit,
constructorParameters = listOf(rawPtrConstructorParam),
companion = companion
))
}
private fun getArrayLength(type: ArrayType): Long {
val unwrappedElementType = type.elemType.unwrapTypedefs()
val elementLength = if (unwrappedElementType is ArrayType) {
getArrayLength(unwrappedElementType)
} else {
1L
}
val elementCount = when (type) {
is ConstArrayType -> type.length
is IncompleteArrayType -> 0L
else -> TODO(type.toString())
}
return elementLength * elementCount
}
private tailrec fun Type.isIntegerTypeSigned(): Boolean = when (this) {
is IntegerType -> this.isSigned
is BoolType -> false
is EnumType -> this.def.baseType.isIntegerTypeSigned()
is Typedef -> this.def.aliased.isIntegerTypeSigned()
else -> error(this)
}
/**
* Produces to [out] the definition of Kotlin class representing the reference to given forward (incomplete) struct.
*/
private fun generateForwardStruct(s: StructDecl): List<StubIrElement> = when (context.platform) {
KotlinPlatform.JVM -> {
val classifier = context.getKotlinClassForPointed(s)
val superClass = SymbolicStubType("COpaque")
val rawPtrConstructorParam = ConstructorParameterStub("rawPtr", SymbolicStubType("NativePtr"))
val superClassInit = SuperClassInit(superClass, listOf(GetConstructorParameter(rawPtrConstructorParam)))
val origin = StubOrigin.Struct(s)
listOf(ClassStub.Simple(classifier, ClassStubModality.NONE, listOf(rawPtrConstructorParam), superClassInit, origin = origin))
}
KotlinPlatform.NATIVE -> emptyList()
}
}
internal class EnumStubBuilder(
override val context: StubsBuildingContext,
private val enumDef: EnumDef
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
if (!context.isStrictEnum(enumDef)) {
return generateEnumAsConstants(enumDef)
}
val baseTypeMirror = context.mirror(enumDef.baseType)
val baseType = WrapperStubType(baseTypeMirror.argType)
val clazz = (context.mirror(EnumType(enumDef)) as TypeMirror.ByValue).valueType.classifier
val qualifier = ConstructorParameterStub.Qualifier.VAL(overrides = true)
val valueParamStub = ConstructorParameterStub("value", baseType, qualifier)
val canonicalsByValue = enumDef.constants
.groupingBy { it.value }
.reduce { _, accumulator, element ->
if (element.isMoreCanonicalThan(accumulator)) {
element
} else {
accumulator
}
}
val (canonicalConstants, aliasConstants) = enumDef.constants.partition { canonicalsByValue[it.value] == it }
val canonicalEntries = canonicalConstants.map { constant ->
val literal = context.tryCreateIntegralStub(enumDef.baseType, constant.value)
?: error("Cannot create enum value ${constant.value} of type ${enumDef.baseType}")
val aliases = aliasConstants.filter { it.value == constant.value }.map { EnumEntryStub.Alias(it.name) }
EnumEntryStub(constant.name, literal, aliases)
}
val enum = ClassStub.Enum(clazz, canonicalEntries,
origin = StubOrigin.Enum(enumDef),
constructorParameters = listOf(valueParamStub),
interfaces = listOf(SymbolicStubType("CEnum"))
)
context.bridgeComponentsBuilder.enumToTypeMirror[enum] = baseTypeMirror
return listOf(enum)
}
private fun EnumConstant.isMoreCanonicalThan(other: EnumConstant): Boolean = with(other.name.toLowerCase()) {
contains("min") || contains("max") ||
contains("first") || contains("last") ||
contains("begin") || contains("end")
}
/**
* Produces to [out] the Kotlin definitions for given enum which shouldn't be represented as Kotlin enum.
*/
private fun generateEnumAsConstants(e: EnumDef): List<StubIrElement> {
// TODO: if this enum defines e.g. a type of struct field, then it should be generated inside the struct class
// to prevent name clashing
val entries = mutableListOf<PropertyStub>()
val typealiases = mutableListOf<TypealiasStub>()
val constants = e.constants.filter {
// Macro "overrides" the original enum constant.
it.name !in context.macroConstantsByName
}
val kotlinType: KotlinType
val baseKotlinType = context.mirror(e.baseType).argType
val meta = if (e.isAnonymous) {
kotlinType = baseKotlinType
StubContainerMeta(textAtStart = if (constants.isNotEmpty()) "// ${e.spelling}:" else "")
} else {
val typeMirror = context.mirror(EnumType(e))
if (typeMirror !is TypeMirror.ByValue) {
error("unexpected enum type mirror: $typeMirror")
}
val varTypeName = typeMirror.info.constructPointedType(typeMirror.valueType)
val varTypeClassifier = typeMirror.pointedType.classifier
val valueTypeClassifier = typeMirror.valueType.classifier
typealiases += TypealiasStub(ClassifierStubType(varTypeClassifier), WrapperStubType(varTypeName))
typealiases += TypealiasStub(ClassifierStubType(valueTypeClassifier), WrapperStubType(baseKotlinType))
kotlinType = typeMirror.valueType
StubContainerMeta()
}
for (constant in constants) {
val literal = context.tryCreateIntegralStub(e.baseType, constant.value) ?: continue
val getter = PropertyAccessor.Getter.SimpleGetter(constant = literal)
val kind = PropertyStub.Kind.Val(getter)
entries += PropertyStub(
constant.name,
WrapperStubType(kotlinType),
kind,
MemberStubModality.FINAL,
null
)
}
val container = SimpleStubContainer(
meta,
properties = entries.toList(),
typealiases = typealiases.toList()
)
return listOf(container)
}
}
internal class FunctionStubBuilder(
override val context: StubsBuildingContext,
private val func: FunctionDecl
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
val platform = context.platform
val parameters = mutableListOf<FunctionParameterStub>()
func.parameters.forEachIndexed { index, parameter ->
val parameterName = parameter.name.let {
if (it == null || it.isEmpty()) {
"arg$index"
} else {
it
}
}
val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type)
val origin = StubOrigin.FunctionParameter(parameter)
parameters += when {
representCFunctionParameterAsString(func, parameter.type) -> {
val annotations = when (platform) {
KotlinPlatform.JVM -> emptyList()
KotlinPlatform.NATIVE -> listOf(AnnotationStub.CCall.CString)
}
val type = WrapperStubType(KotlinTypes.string.makeNullable())
val functionParameterStub = FunctionParameterStub(parameterName, type, annotations, origin = origin)
context.bridgeComponentsBuilder.cStringParameters += functionParameterStub
functionParameterStub
}
representCFunctionParameterAsWString(func, parameter.type) -> {
val annotations = when (platform) {
KotlinPlatform.JVM -> emptyList()
KotlinPlatform.NATIVE -> listOf(AnnotationStub.CCall.WCString)
}
val type = WrapperStubType(KotlinTypes.string.makeNullable())
val functionParameterStub = FunctionParameterStub(parameterName, type, annotations, origin = origin)
context.bridgeComponentsBuilder.wCStringParameters += functionParameterStub
functionParameterStub
}
representAsValuesRef != null -> {
FunctionParameterStub(parameterName, WrapperStubType(representAsValuesRef), origin = origin)
}
else -> {
val mirror = context.mirror(parameter.type)
val type = WrapperStubType(mirror.argType)
FunctionParameterStub(parameterName, type, origin = origin)
}
}
}
val returnType = WrapperStubType(if (func.returnsVoid()) {
KotlinTypes.unit
} else {
context.mirror(func.returnType).argType
})
val annotations: List<AnnotationStub>
val mustBeExternal: Boolean
if (!func.isVararg || platform != KotlinPlatform.NATIVE) {
annotations = emptyList()
mustBeExternal = false
} else {
val type = WrapperStubType(KotlinTypes.any.makeNullable())
parameters += FunctionParameterStub("variadicArguments", type, isVararg = true)
annotations = listOf(AnnotationStub.CCall.Symbol(context.generateNextUniqueId("knifunptr_")))
mustBeExternal = true
}
val functionStub = FunctionStub(
func.name,
returnType,
parameters.toList(),
StubOrigin.Function(func),
annotations,
mustBeExternal,
null,
MemberStubModality.FINAL
)
return listOf(functionStub)
}
private fun FunctionDecl.returnsVoid(): Boolean = this.returnType.unwrapTypedefs() is VoidType
private fun representCFunctionParameterAsValuesRef(type: Type): KotlinType? {
val pointeeType = when (type) {
is PointerType -> type.pointeeType
is ArrayType -> type.elemType
else -> return null
}
val unwrappedPointeeType = pointeeType.unwrapTypedefs()
if (unwrappedPointeeType is VoidType) {
// Represent `void*` as `CValuesRef<*>?`:
return KotlinTypes.cValuesRef.typeWith(StarProjection).makeNullable()
}
if (unwrappedPointeeType is FunctionType) {
// Don't represent function pointer as `CValuesRef<T>?` currently:
return null
}
if (unwrappedPointeeType is ArrayType) {
return representCFunctionParameterAsValuesRef(pointeeType)
}
return KotlinTypes.cValuesRef.typeWith(context.mirror(pointeeType).pointedType).makeNullable()
}
private val platformWStringTypes = setOf("LPCWSTR")
private val noStringConversion: Set<String>
get() = context.configuration.noStringConversion
private fun Type.isAliasOf(names: Set<String>): Boolean {
var type = this
while (type is Typedef) {
if (names.contains(type.def.name)) return true
type = type.def.aliased
}
return false
}
private fun representCFunctionParameterAsString(function: FunctionDecl, type: Type): Boolean {
val unwrappedType = type.unwrapTypedefs()
return unwrappedType is PointerType && unwrappedType.pointeeIsConst &&
unwrappedType.pointeeType.unwrapTypedefs() == CharType &&
!noStringConversion.contains(function.name)
}
// We take this approach as generic 'const short*' shall not be used as String.
private fun representCFunctionParameterAsWString(function: FunctionDecl, type: Type) = type.isAliasOf(platformWStringTypes)
&& !noStringConversion.contains(function.name)
}
internal class GlobalStubBuilder(
override val context: StubsBuildingContext,
private val global: GlobalDecl
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
val mirror = context.mirror(global.type)
val unwrappedType = global.type.unwrapTypedefs()
val kotlinType: KotlinType
val kind: PropertyStub.Kind
if (unwrappedType is ArrayType) {
kotlinType = (mirror as TypeMirror.ByValue).valueType
val getter = PropertyAccessor.Getter.SimpleGetter()
val extra = BridgeGenerationComponents.GlobalGetterBridgeInfo(global.name, mirror.info, isArray = true)
context.bridgeComponentsBuilder.getterToBridgeInfo[getter] = extra
kind = PropertyStub.Kind.Val(getter)
} else {
when (mirror) {
is TypeMirror.ByValue -> {
kotlinType = mirror.argType
val getter = PropertyAccessor.Getter.SimpleGetter()
val getterExtra = BridgeGenerationComponents.GlobalGetterBridgeInfo(global.name, mirror.info, isArray = false)
context.bridgeComponentsBuilder.getterToBridgeInfo[getter] = getterExtra
kind = if (global.isConst) {
PropertyStub.Kind.Val(getter)
} else {
val setter = PropertyAccessor.Setter.SimpleSetter()
val setterExtra = BridgeGenerationComponents.GlobalSetterBridgeInfo(global.name, mirror.info)
context.bridgeComponentsBuilder.setterToBridgeInfo[setter] = setterExtra
PropertyStub.Kind.Var(getter, setter)
}
}
is TypeMirror.ByRef -> {
kotlinType = mirror.pointedType
val getter = PropertyAccessor.Getter.InterpretPointed(global.name, WrapperStubType(kotlinType))
kind = PropertyStub.Kind.Val(getter)
}
}
}
return listOf(PropertyStub(global.name, WrapperStubType(kotlinType), kind))
}
}
internal class TypedefStubBuilder(
override val context: StubsBuildingContext,
private val typedefDef: TypedefDef
) : StubElementBuilder {
override fun build(): List<StubIrElement> {
val mirror = context.mirror(Typedef(typedefDef))
val baseMirror = context.mirror(typedefDef.aliased)
val varType = mirror.pointedType.classifier
return when (baseMirror) {
is TypeMirror.ByValue -> {
val valueType = (mirror as TypeMirror.ByValue).valueType
val varTypeAliasee = mirror.info.constructPointedType(valueType)
val valueTypeAliasee = baseMirror.valueType
listOf(
TypealiasStub(ClassifierStubType(varType), WrapperStubType(varTypeAliasee)),
TypealiasStub(ClassifierStubType(valueType.classifier), WrapperStubType(valueTypeAliasee))
)
}
is TypeMirror.ByRef -> {
val varTypeAliasee = baseMirror.pointedType
listOf(TypealiasStub(ClassifierStubType(varType), WrapperStubType(varTypeAliasee)))
}
}
}
}
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.indexer.ObjCProtocol
private val StubOrigin.ObjCMethod.isOptional: Boolean
get() = container is ObjCProtocol && method.isOptional
fun FunctionStub.isOptionalObjCMethod(): Boolean = this.origin is StubOrigin.ObjCMethod &&
this.origin.isOptional
val StubContainer.isInterface: Boolean
get() = if (this is ClassStub.Simple) {
modality == ClassStubModality.INTERFACE
} else {
false
}
/**
* Compute which names will be declared by [StubContainer] in the given [pkgName]
*/
fun StubContainer.computeNamesToBeDeclared(pkgName: String): List<String> {
fun checkPackageCorrectness(classifier: Classifier) {
assert(classifier.pkg == pkgName) {
"""Wrong classifier package.
|Expected: $pkgName
|Got: ${classifier.pkg}
|""".trimMargin()
}
}
val classNames = classes.mapNotNull {
when (it) {
is ClassStub.Simple -> it.classifier
is ClassStub.Companion -> null
is ClassStub.Enum -> it.classifier
}
}.onEach { checkPackageCorrectness(it) }.map { it.topLevelName }
val typealiasNames = typealiases
.onEach { checkPackageCorrectness(it.alias.classifier) }
.map { it.alias.classifier.topLevelName }
val namesFromNestedContainers = simpleContainers
.flatMap { it.computeNamesToBeDeclared(pkgName) }
return classNames + typealiasNames + namesFromNestedContainers
}
val StubContainer.defaultMemberModality: MemberStubModality
get() = when (this) {
is SimpleStubContainer -> MemberStubModality.FINAL
is ClassStub.Simple -> if (this.modality == ClassStubModality.INTERFACE) {
MemberStubModality.OPEN
} else {
MemberStubModality.FINAL
}
is ClassStub.Companion -> MemberStubModality.FINAL
is ClassStub.Enum -> MemberStubModality.FINAL
}
@@ -0,0 +1,667 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.indexer.*
import org.jetbrains.kotlin.utils.addIfNotNull
import java.lang.IllegalStateException
/**
* Emits stubs and bridge functions as *.kt and *.c files.
* Many unintuitive printings are made for compatability with previous version of stub generator.
*
* [omitEmptyLines] is useful for testing output (e.g. diff calculating).
*/
class StubIrTextEmitter(
private val context: StubIrContext,
private val builderResult: StubIrBuilderResult,
private val bridgeBuilderResult: BridgeBuilderResult,
private val omitEmptyLines: Boolean = false
) {
private val kotlinFile = bridgeBuilderResult.kotlinFile
private val nativeBridges = bridgeBuilderResult.nativeBridges
private val propertyAccessorBridgeBodies = bridgeBuilderResult.propertyAccessorBridgeBodies
private val functionBridgeBodies = bridgeBuilderResult.functionBridgeBodies
private val pkgName: String
get() = context.configuration.pkgName
private val jvmFileClassName = if (pkgName.isEmpty()) {
context.libName
} else {
pkgName.substringAfterLast('.')
}
private val StubContainer.isTopLevelContainer: Boolean
get() = this == builderResult.stubs
companion object {
private val VALID_PACKAGE_NAME_REGEX = "[a-zA-Z0-9_.]+".toRegex()
}
/**
* The output currently used by the generator.
* Should append line separator after any usage.
*/
private var out: (String) -> Unit = {
throw IllegalStateException()
}
private fun emitEmptyLine() {
if (!omitEmptyLines) {
out("")
}
}
private fun <R> withOutput(output: (String) -> Unit, action: () -> R): R {
val oldOut = out
out = output
try {
return action()
} finally {
out = oldOut
}
}
private fun <R> withOutput(appendable: Appendable, action: () -> R): R {
return withOutput({ appendable.appendln(it) }, action)
}
private fun generateLinesBy(action: () -> Unit): List<String> {
val result = mutableListOf<String>()
withOutput({ result.add(it) }, action)
return result
}
private fun generateKotlinFragmentBy(block: () -> Unit): Sequence<String> {
val lines = generateLinesBy(block)
return lines.asSequence()
}
private fun <R> indent(action: () -> R): R {
val oldOut = out
return withOutput({ oldOut(" $it") }, action)
}
private fun <R> block(header: String, body: () -> R): R {
out("$header {")
val res = indent {
body()
}
out("}")
return res
}
private fun emitKotlinFileHeader() {
if (context.platform == KotlinPlatform.JVM) {
out("@file:JvmName(${jvmFileClassName.quoteAsKotlinLiteral()})")
}
if (context.platform == KotlinPlatform.NATIVE) {
out("@file:kotlinx.cinterop.InteropStubs")
}
val suppress = mutableListOf("UNUSED_VARIABLE", "UNUSED_EXPRESSION").apply {
if (context.configuration.library.language == Language.OBJECTIVE_C) {
add("CONFLICTING_OVERLOADS")
add("RETURN_TYPE_MISMATCH_ON_INHERITANCE")
add("PROPERTY_TYPE_MISMATCH_ON_INHERITANCE") // Multiple-inheriting property with conflicting types
add("VAR_TYPE_MISMATCH_ON_INHERITANCE") // Multiple-inheriting mutable property with conflicting types
add("RETURN_TYPE_MISMATCH_ON_OVERRIDE")
add("WRONG_MODIFIER_CONTAINING_DECLARATION") // For `final val` in interface.
add("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
add("UNUSED_PARAMETER") // For constructors.
add("MANY_IMPL_MEMBER_NOT_IMPLEMENTED") // Workaround for multiple-inherited properties.
add("MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED") // Workaround for multiple-inherited properties.
add("EXTENSION_SHADOWED_BY_MEMBER") // For Objective-C categories represented as extensions.
add("REDUNDANT_NULLABLE") // This warning appears due to Obj-C typedef nullability incomplete support.
add("DEPRECATION") // For uncheckedCast.
add("DEPRECATION_ERROR") // For initializers.
}
}
out("@file:Suppress(${suppress.joinToString { it.quoteAsKotlinLiteral() }})")
if (pkgName != "") {
val packageName = pkgName.split(".").joinToString("."){
if(it.matches(VALID_PACKAGE_NAME_REGEX)){
it
}else{
"`$it`"
}
}
out("package $packageName")
out("")
}
if (context.platform == KotlinPlatform.NATIVE) {
out("import kotlin.native.SymbolName")
out("import kotlinx.cinterop.internal.*")
}
out("import kotlinx.cinterop.*")
kotlinFile.buildImports().forEach {
out(it)
}
out("")
out("// NOTE THIS FILE IS AUTO-GENERATED")
}
fun emit(ktFile: Appendable, cFile: Appendable, entryPoint: String?) {
withOutput(cFile) {
context.libraryForCStubs.preambleLines.forEach {
out(it)
}
out("")
out("// NOTE THIS FILE IS AUTO-GENERATED")
out("")
nativeBridges.nativeLines.forEach(out)
if (entryPoint != null) {
out("extern int Konan_main(int argc, char** argv);")
out("")
out("__attribute__((__used__))")
out("int $entryPoint(int argc, char** argv) {")
out(" return Konan_main(argc, argv);")
out("}")
}
}
// Stubs generation may affect imports list so do it before header generation.
val stubLines = generateKotlinFragmentBy {
printer.visitSimpleStubContainer(builderResult.stubs, null)
}
withOutput(ktFile) {
emitKotlinFileHeader()
stubLines.forEach(out)
nativeBridges.kotlinLines.forEach(out)
if (context.platform == KotlinPlatform.JVM) {
out("private val loadLibrary = System.loadLibrary(\"${context.libName}\")")
}
}
}
private val printer = object : StubIrVisitor<StubContainer?, Unit> {
override fun visitClass(element: ClassStub, owner: StubContainer?) {
element.annotations.forEach {
out(renderAnnotation(it))
}
val header = renderClassHeader(element)
when {
element is ClassStub.Simple && element.children.isEmpty() -> out(header)
element is ClassStub.Companion && element.children.isEmpty() -> out(header)
else -> block(header) {
if (element is ClassStub.Enum) {
emitEnumBody(element)
} else {
element.children.forEach {
emitEmptyLine()
it.accept(this, element)
}
}
}
}
}
override fun visitTypealias(element: TypealiasStub, owner: StubContainer?) {
val alias = renderClassifierDeclaration(element.alias.classifier) + renderTypeArguments(element.alias.typeArguments)
val aliasee = renderStubType(element.aliasee)
out("typealias $alias = $aliasee")
}
override fun visitFunction(element: FunctionStub, owner: StubContainer?) {
if (element in bridgeBuilderResult.excludedStubs) return
val modality = renderMemberModality(element.modality, owner)
element.annotations.forEach {
out(renderAnnotation(it))
}
val parameters = element.parameters.joinToString(prefix = "(", postfix = ")") { renderFunctionParameter(it) }
val receiver = element.receiver?.let { renderFunctionReceiver(it) + "." } ?: ""
val typeParameters = renderTypeParameters(element.typeParameters)
val header = "${modality}fun$typeParameters $receiver${element.name.asSimpleName()}$parameters: ${renderStubType(element.returnType)}"
when {
element.external -> out("external $header")
element.isOptionalObjCMethod() -> out("$header = optional()")
owner != null && owner.isInterface -> out(header)
else -> if (nativeBridges.isSupported(element)) {
block(header) {
functionBridgeBodies.getValue(element).forEach(out)
}
} else {
sequenceOf(
annotationForUnableToImport,
"$header = throw UnsupportedOperationException()"
).forEach(out)
}
}
}
override fun visitProperty(element: PropertyStub, owner: StubContainer?) {
if (element in bridgeBuilderResult.excludedStubs) return
val modality = renderMemberModality(element.modality, owner)
val receiver = if (element.receiverType != null) "${renderStubType(element.receiverType)}." else ""
val name = if (owner?.isTopLevelContainer == true) {
getTopLevelPropertyDeclarationName(kotlinFile, element.name)
} else {
element.name.asSimpleName()
}
val header = "$receiver$name: ${renderStubType(element.type)}"
if (element.kind is PropertyStub.Kind.Val && !nativeBridges.isSupported(element.kind.getter)
|| element.kind is PropertyStub.Kind.Var && !nativeBridges.isSupported(element.kind.getter)) {
out(annotationForUnableToImport)
out("val $header")
out(" get() = TODO()")
} else {
element.annotations.forEach {
out(renderAnnotation(it))
}
when (val kind = element.kind) {
is PropertyStub.Kind.Constant -> {
out("${modality}const val $header = ${renderValueUsage(kind.constant)}")
}
is PropertyStub.Kind.Val -> {
val shouldWriteInline = kind.getter is PropertyAccessor.Getter.SimpleGetter && kind.getter.constant != null
if (shouldWriteInline) {
out("${modality}val $header ${renderGetter(kind.getter)}")
} else {
out("${modality}val $header")
indent {
out(renderGetter(kind.getter))
}
}
}
is PropertyStub.Kind.Var -> {
val isSupported = nativeBridges.isSupported(kind.setter)
val variableKind = if (isSupported) "var" else "val"
out("$modality$variableKind $header")
indent {
out(renderGetter(kind.getter))
if (isSupported) {
out(renderSetter(kind.setter))
}
}
}
}
}
}
// Try to use the provided name. If failed, mangle it with underscore and try again:
private tailrec fun getTopLevelPropertyDeclarationName(scope: KotlinScope, name: String): String =
scope.declareProperty(name) ?: getTopLevelPropertyDeclarationName(scope, name + "_")
override fun visitConstructor(constructorStub: ConstructorStub, owner: StubContainer?) {
constructorStub.annotations.forEach {
out(renderAnnotation(it))
}
val visibility = renderVisibilityModifier(constructorStub.visibility)
out("${visibility}constructor(${constructorStub.parameters.joinToString { renderFunctionParameter(it) }}) {}")
}
override fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, owner: StubContainer?) {
}
override fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, owner: StubContainer?) {
if (simpleStubContainer.meta.textAtStart.isNotEmpty()) {
out(simpleStubContainer.meta.textAtStart)
}
simpleStubContainer.classes.forEach {
emitEmptyLine()
it.accept(this, simpleStubContainer)
}
simpleStubContainer.functions.forEach {
emitEmptyLine()
it.accept(this, simpleStubContainer)
}
simpleStubContainer.properties.forEach {
emitEmptyLine()
it.accept(this, simpleStubContainer)
}
simpleStubContainer.typealiases.forEach {
emitEmptyLine()
it.accept(this, simpleStubContainer)
}
simpleStubContainer.simpleContainers.forEach {
emitEmptyLine()
it.accept(this, simpleStubContainer)
}
if (simpleStubContainer.meta.textAtEnd.isNotEmpty()) {
out(simpleStubContainer.meta.textAtEnd)
}
}
}
// About method naming convention:
// - "emit" prefix means that method will call `out` by itself.
// - "render" prefix means that method returns string that should be emitted by caller.
private fun emitEnumBody(enum: ClassStub.Enum) {
enum.entries.forEach {
out(renderEnumEntry(it) + ",")
}
val simpleKotlinName = enum.classifier.topLevelName.asSimpleName()
val typeMirror = builderResult.bridgeGenerationComponents.enumToTypeMirror.getValue(enum)
val baseKotlinType = typeMirror.argType.render(kotlinFile)
val basePointedTypeName = typeMirror.pointedType.render(kotlinFile)
out(";")
emitEmptyLine()
block("companion object") {
enum.entries.forEach { entry ->
entry.aliases.forEach {
out("val ${it.name.asSimpleName()} = ${entry.name.asSimpleName()}")
}
}
emitEmptyLine()
out("fun byValue(value: $baseKotlinType) = " +
"$simpleKotlinName.values().find { it.value == value }!!")
}
emitEmptyLine()
block("class Var(rawPtr: NativePtr) : CEnumVar(rawPtr)") {
out("companion object : Type($basePointedTypeName.size.toInt())")
out("var value: $simpleKotlinName")
out(" get() = byValue(this.reinterpret<$basePointedTypeName>().value)")
out(" set(value) { this.reinterpret<$basePointedTypeName>().value = value.value }")
}
}
private fun renderFunctionReceiver(receiver: ReceiverParameterStub): String {
return renderStubType(receiver.type)
}
private fun renderFunctionParameter(parameter: FunctionParameterStub): String {
val annotations = if (parameter.annotations.isEmpty())
""
else
parameter.annotations.joinToString(separator = " ") { renderAnnotation(it) } + " "
val vararg = if (parameter.isVararg) "vararg " else ""
return "$annotations$vararg${parameter.name.asSimpleName()}: ${renderStubType(parameter.type)}"
}
private fun renderMemberModality(modality: MemberStubModality, container: StubContainer?): String =
if (container?.defaultMemberModality == modality) {
""
} else
when (modality) {
MemberStubModality.OVERRIDE -> "override "
MemberStubModality.OPEN -> "open "
MemberStubModality.FINAL -> "final "
}
private fun renderVisibilityModifier(visibilityModifier: VisibilityModifier) = when (visibilityModifier) {
VisibilityModifier.PRIVATE -> "private "
VisibilityModifier.PROTECTED -> "protected "
VisibilityModifier.INTERNAL -> "internal "
VisibilityModifier.PUBLIC -> ""
}
private fun renderClassHeader(classStub: ClassStub): String {
val modality = when (classStub) {
is ClassStub.Simple -> renderClassStubModality(classStub.modality)
is ClassStub.Companion -> ""
is ClassStub.Enum -> "enum class "
}
val className = when (classStub) {
is ClassStub.Simple -> renderClassifierDeclaration(classStub.classifier)
is ClassStub.Companion -> "companion object"
is ClassStub.Enum -> renderClassifierDeclaration(classStub.classifier)
}
val constructorParams = when (classStub) {
is ClassStub.Simple -> renderConstructorParams(classStub.constructorParameters)
is ClassStub.Companion -> ""
is ClassStub.Enum -> renderConstructorParams(classStub.constructorParameters)
}
val inheritance = mutableListOf<String>().apply {
addIfNotNull(classStub.superClassInit?.let { renderSuperInit(it) })
addAll(classStub.interfaces.map { renderStubType(it) })
}.let { if (it.isNotEmpty()) " : ${it.joinToString()}" else "" }
return "$modality$className$constructorParams$inheritance"
}
private fun renderClassifierDeclaration(classifier: Classifier): String =
kotlinFile.declare(classifier)
private fun renderClassStubModality(classStubModality: ClassStubModality): String = when (classStubModality) {
ClassStubModality.INTERFACE -> "interface "
ClassStubModality.OPEN -> "open class "
ClassStubModality.ABSTRACT -> "abstract class "
ClassStubModality.NONE -> "class "
}
private fun renderConstructorParams(parameters: List<ConstructorParameterStub>): String =
if (parameters.isEmpty()) {
""
} else {
parameters.joinToString(prefix = "(", postfix = ")") { renderConstructorParameter(it) }
}
private fun renderConstructorParameter(parameterStub: ConstructorParameterStub): String {
val prefix = when (parameterStub.qualifier) {
is ConstructorParameterStub.Qualifier.VAL -> if (parameterStub.qualifier.overrides) "override val " else "val "
is ConstructorParameterStub.Qualifier.VAR -> if (parameterStub.qualifier.overrides) "override var " else "var "
ConstructorParameterStub.Qualifier.NONE -> ""
}
return "$prefix${parameterStub.name.asSimpleName()}: ${renderStubType(parameterStub.type)}"
}
private fun renderSuperInit(superClassInit: SuperClassInit): String {
val parameters = superClassInit.arguments.joinToString(prefix = "(", postfix = ")") { renderValueUsage(it) }
return "${renderStubType(superClassInit.type)}$parameters"
}
private fun renderStubType(stubType: StubType): String = when (stubType) {
is WrapperStubType -> stubType.kotlinType.render(kotlinFile)
is ClassifierStubType -> {
val classifier = kotlinFile.reference(stubType.classifier)
val typeArguments = renderTypeArguments(stubType.typeArguments)
val nullability = if (stubType.nullable) "?" else ""
"$classifier$typeArguments$nullability"
}
is SymbolicStubType -> stubType.name + if (stubType.nullable) "?" else ""
}
private fun renderValueUsage(value: ValueStub): String = when (value) {
is StringConstantStub -> value.value
is IntegralConstantStub -> renderIntegralConstant(value)!!
is DoubleConstantStub -> renderDoubleConstant(value)!!
is GetConstructorParameter -> value.constructorParameterStub.name
}
private fun renderAnnotation(annotationStub: AnnotationStub): String = when (annotationStub) {
AnnotationStub.ObjC.ConsumesReceiver -> "@CCall.ConsumesReceiver"
AnnotationStub.ObjC.ReturnsRetained -> "@CCall.ReturnsRetained"
is AnnotationStub.ObjC.Method -> {
val stret = if (annotationStub.isStret) ", true" else ""
val selector = annotationStub.selector.quoteAsKotlinLiteral()
val encoding = annotationStub.encoding.quoteAsKotlinLiteral()
"@ObjCMethod($selector, $encoding$stret)"
}
is AnnotationStub.ObjC.Factory -> {
val stret = if (annotationStub.isStret) ", true" else ""
val selector = annotationStub.selector.quoteAsKotlinLiteral()
val encoding = annotationStub.encoding.quoteAsKotlinLiteral()
"@ObjCFactory($selector, $encoding$stret)"
}
AnnotationStub.ObjC.Consumed ->
"@CCall.Consumed"
is AnnotationStub.ObjC.Constructor ->
"@ObjCConstructor(${annotationStub.selector.quoteAsKotlinLiteral()}, ${annotationStub.designated})"
is AnnotationStub.ObjC.ExternalClass -> {
val protocolGetter = annotationStub.protocolGetter.quoteAsKotlinLiteral()
val binaryName = annotationStub.binaryName.quoteAsKotlinLiteral()
"@ExternalObjCClass" + when {
annotationStub.protocolGetter.isEmpty() && annotationStub.binaryName.isEmpty() -> ""
annotationStub.protocolGetter.isEmpty() -> "(\"\", $binaryName)"
annotationStub.binaryName.isEmpty() -> "($protocolGetter)"
else -> "($protocolGetter, $binaryName)"
}
}
AnnotationStub.CCall.CString ->
"@CCall.CString"
AnnotationStub.CCall.WCString ->
"@CCall.WCString"
is AnnotationStub.CCall.Symbol ->
"@CCall(${annotationStub.symbolName.quoteAsKotlinLiteral()})"
is AnnotationStub.CStruct ->
"@CStruct(${annotationStub.struct.quoteAsKotlinLiteral()})"
is AnnotationStub.CNaturalStruct ->
"@CNaturalStruct(${annotationStub.members.joinToString { it.name.quoteAsKotlinLiteral() }})"
is AnnotationStub.CLength ->
"@CLength(${annotationStub.length})"
is AnnotationStub.Deprecated ->
"@Deprecated(${annotationStub.message.quoteAsKotlinLiteral()}, " +
"ReplaceWith(${annotationStub.replaceWith.quoteAsKotlinLiteral()}), " +
"DeprecationLevel.ERROR)"
}
private fun renderEnumEntry(enumEntryStub: EnumEntryStub): String =
"${enumEntryStub.name.asSimpleName()}(${renderValueUsage(enumEntryStub.constant)})"
private fun renderGetter(accessor: PropertyAccessor.Getter): String {
val annotations = accessor.annotations.joinToString(separator = "") { renderAnnotation(it) + " " }
return annotations + if (accessor is PropertyAccessor.Getter.ExternalGetter) {
"external get"
} else {
"get() = ${renderPropertyAccessorBody(accessor)}"
}
}
private fun renderSetter(accessor: PropertyAccessor.Setter): String {
val annotations = accessor.annotations.joinToString(separator = "") { renderAnnotation(it) + " " }
return annotations + if (accessor is PropertyAccessor.Setter.ExternalSetter) {
"external set"
} else {
"set(value) { ${renderPropertyAccessorBody(accessor)} }"
}
}
private fun renderPropertyAccessorBody(accessor: PropertyAccessor): String = when (accessor) {
is PropertyAccessor.Getter.SimpleGetter -> {
when {
accessor in propertyAccessorBridgeBodies -> propertyAccessorBridgeBodies.getValue(accessor)
accessor.constant != null -> renderValueUsage(accessor.constant)
else -> error("Bridge body for getter was not generated")
}
}
is PropertyAccessor.Getter.ArrayMemberAt -> "arrayMemberAt(${accessor.offset})"
is PropertyAccessor.Getter.MemberAt -> {
val typeArguments = renderTypeArguments(accessor.typeArguments)
val valueAccess = if (accessor.hasValueAccessor) ".value" else ""
"memberAt$typeArguments(${accessor.offset})$valueAccess"
}
is PropertyAccessor.Getter.ReadBits -> {
propertyAccessorBridgeBodies.getValue(accessor)
}
is PropertyAccessor.Setter.SimpleSetter -> when {
accessor in propertyAccessorBridgeBodies -> propertyAccessorBridgeBodies.getValue(accessor)
else -> error("Bridge body for setter was not generated")
}
is PropertyAccessor.Setter.MemberAt -> {
if (accessor.typeArguments.isEmpty()) {
error("Unexpected memberAt setter without type parameters!")
} else {
val typeArguments = renderTypeArguments(accessor.typeArguments)
"memberAt$typeArguments(${accessor.offset}).value = value"
}
}
is PropertyAccessor.Setter.WriteBits -> {
propertyAccessorBridgeBodies.getValue(accessor)
}
is PropertyAccessor.Getter.InterpretPointed -> {
val typeParameters = accessor.typeParameters.joinToString(prefix = "<", postfix = ">") { renderStubType(it) }
val getAddressExpression = propertyAccessorBridgeBodies.getValue(accessor)
"interpretPointed$typeParameters($getAddressExpression)"
}
is PropertyAccessor.Getter.ExternalGetter,
is PropertyAccessor.Setter.ExternalSetter -> error("External property accessor shouldn't have a body!")
}
private fun renderIntegralConstant(integralValue: IntegralConstantStub): String? {
val (value, size, isSigned) = integralValue
return if (isSigned) {
if (value == Long.MIN_VALUE) {
return "${value + 1} - 1" // Workaround for "The value is out of range" compile error.
}
val narrowedValue: Number = when (size) {
1 -> value.toByte()
2 -> value.toShort()
4 -> value.toInt()
8 -> value
else -> return null
}
narrowedValue.toString()
} else {
// Note: stub generator is built and run with different ABI versions,
// so Kotlin unsigned types can't be used here currently.
val narrowedValue: String = when (size) {
1 -> (value and 0xFF).toString()
2 -> (value and 0xFFFF).toString()
4 -> (value and 0xFFFFFFFF).toString()
8 -> java.lang.Long.toUnsignedString(value)
else -> return null
}
"${narrowedValue}u"
}
}
private fun renderDoubleConstant(doubleValue: DoubleConstantStub): String? {
val (value, size) = doubleValue
return when (size) {
4 -> {
val floatValue = value.toFloat()
val bits = java.lang.Float.floatToRawIntBits(floatValue)
"bitsToFloat($bits) /* == $floatValue */"
}
8 -> {
val bits = java.lang.Double.doubleToRawLongBits(value)
"bitsToDouble($bits) /* == $value */"
}
else -> null
}
}
private fun renderTypeArguments(typeArguments: List<TypeArgumentStub>) = if (typeArguments.isNotEmpty()) {
typeArguments.joinToString(", ", "<", ">") { renderStubType(it.type) }
} else {
""
}
private fun renderTypeParameters(typeParameters: List<TypeParameterStub>) = if (typeParameters.isNotEmpty()) {
typeParameters.joinToString(", ", " <", ">") { renderTypeParameter(it) }
} else {
""
}
private fun renderTypeParameter(typeParameterStub: TypeParameterStub): String {
val name = typeParameterStub.name
return typeParameterStub.upperBound?.let {
"$name : ${renderStubType(it)}"
} ?: name
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.native.interop.gen
interface StubIrVisitor<T, R> {
fun visitClass(element: ClassStub, data: T): R
fun visitTypealias(element: TypealiasStub, data: T): R
fun visitFunction(element: FunctionStub, data: T): R
fun visitProperty(element: PropertyStub, data: T): R
fun visitConstructor(constructorStub: ConstructorStub, data: T): R
fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, data: T): R
fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, data: T): R
}
@@ -89,7 +89,7 @@ private class CompositeDependencyAssigner(val dependencyAssigners: List<Dependen
override fun getReady(): Map<File, Set<String>> {
return dependencyAssigners.map { it.getReady() }.reduce { left, right ->
(left.keys intersect right.keys)
.associateWith { left[it]!! union right[it]!! }
.associateWith { left.getValue(it) union right.getValue(it) }
}.also {
require(it.isNotEmpty()) { "incompatible dependencies" } // TODO: add more info.
}
@@ -33,4 +33,9 @@ class InteropConfiguration(
val exportForwardDeclarations: List<String>,
val disableDesignatedInitializerChecks: Boolean,
val target: KonanTarget
)
)
enum class KotlinPlatform {
JVM,
NATIVE
}
@@ -202,9 +202,8 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
val excludedMacros = def.config.excludedMacros.toSet()
val staticLibraries = def.config.staticLibraries + argParser.getValuesAsArray("staticLibrary")
val libraryPaths = def.config.libraryPaths + argParser.getValuesAsArray("libraryPath")
val fqParts = (argParser.get<String>("pkg") ?: def.config.packageName)?.let {
it.split('.')
} ?: defFile!!.name.split('.').reversed().drop(1)
val fqParts = (argParser.get<String>("pkg") ?: def.config.packageName)?.split('.')
?: defFile!!.name.split('.').reversed().drop(1)
val outKtFileName = fqParts.last() + ".kt"
@@ -235,19 +234,21 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
target = tool.target
)
val gen = StubGenerator(nativeIndex, configuration, libName, verbose, flavor, imports)
outKtFile.parentFile.mkdirs()
File(nativeLibsDir).mkdirs()
val outCFile = tempFiles.create(libName, ".${language.sourceFileExtension}")
outKtFile.bufferedWriter().use { ktFile ->
File(outCFile.absolutePath).bufferedWriter().use { cFile ->
gen.generateFiles(ktFile = ktFile, cFile = cFile, entryPoint = entryPoint)
}
val logger = if (verbose) {
{ message: String -> println(message) }
} else {
{}
}
val stubIrContext = StubIrContext(logger, configuration, nativeIndex, imports, flavor, libName)
val stubIrDriver = StubIrDriver(stubIrContext)
stubIrDriver.run(outKtFile, File(outCFile.absolutePath), entryPoint)
// TODO: if a library has partially included headers, then it shouldn't be used as a dependency.
def.manifestAddendProperties["includedHeaders"] = nativeIndex.includedHeaders.joinToString(" ") { it.value }
@@ -258,7 +259,7 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
def.manifestAddendProperties["interop"] = "true"
gen.addManifestProperties(def.manifestAddendProperties)
stubIrContext.addManifestProperties(def.manifestAddendProperties)
manifestAddend?.parentFile?.mkdirs()
manifestAddend?.let { def.manifestAddendProperties.storeProperties(it) }
@@ -267,7 +268,7 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
val outOFile = tempFiles.create(libName,".o")
val compilerCmd = arrayOf(compiler, *gen.libraryForCStubs.compilerArgs.toTypedArray(),
val compilerCmd = arrayOf(compiler, *stubIrContext.libraryForCStubs.compilerArgs.toTypedArray(),
"-c", outCFile.absolutePath, "-o", outOFile.absolutePath)
runCmd(compilerCmd, verbose)
@@ -282,7 +283,7 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
} else if (flavor == KotlinPlatform.NATIVE) {
val outBcName = libName + ".bc"
val outLib = File(nativeLibsDir, outBcName)
val compilerCmd = arrayOf(compiler, *gen.libraryForCStubs.compilerArgs.toTypedArray(),
val compilerCmd = arrayOf(compiler, *stubIrContext.libraryForCStubs.compilerArgs.toTypedArray(),
"-emit-llvm", "-c", outCFile.absolutePath, "-o", outLib.absolutePath)
runCmd(compilerCmd, verbose)
+2 -2
View File
@@ -71,7 +71,7 @@ task copyGenerated(type: Copy) {
task deleteGenerated(type: Delete) {
dependsOn('copyGenerated')
delete 'build/generated'
delete 'build/generated/source/proto/compiler/java'
}
task renamePackage {
@@ -171,7 +171,7 @@ def commonSrc = file('build/stdlib')
task unzipStdlibSources(type: CopyCommonSources) {
outputDir commonSrc
sourcePaths configurations.kotlinCommonSources.files
sourcePaths configurations.kotlinCommonSources
}
final List<File> stdLibSrc = [
@@ -160,16 +160,14 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(PURGE_USER_LIBS, arguments.purgeUserLibs)
put(VERIFY_IR, arguments.verifyIr)
put(VERIFY_DESCRIPTORS, arguments.verifyDescriptors)
if (arguments.verifyCompiler != null)
put(VERIFY_COMPILER, arguments.verifyCompiler == "true")
put(VERIFY_BITCODE, arguments.verifyBitCode)
put(ENABLED_PHASES,
arguments.enablePhases.toNonNullList())
put(DISABLED_PHASES,
arguments.disablePhases.toNonNullList())
put(VERBOSE_PHASES,
arguments.verbosePhases.toNonNullList())
put(LIST_PHASES, arguments.listPhases)
put(COMPATIBLE_COMPILER_VERSIONS,
@@ -179,13 +177,13 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(MEMORY_MODEL, when (arguments.memoryModel) {
"relaxed" -> {
configuration.report(STRONG_WARNING, "Relaxed memory model is not yet functional")
configuration.report(STRONG_WARNING, "Relaxed memory model is not yet fully functional")
MemoryModel.RELAXED
}
"strict" -> MemoryModel.STRICT
else -> {
configuration.report(ERROR, "Unsupported memory model ${arguments.memoryModel}")
return
MemoryModel.STRICT
}
})
@@ -35,7 +35,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-include-binary", deprecatedName = "-includeBinary", shortName = "-ib", valueDescription = "<path>", description = "Pack external binary within the klib")
var includeBinaries: Array<String>? = null
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library")
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library", delimiter = "")
var libraries: Array<String>? = null
@Argument(value = "-library-version", shortName = "-lv", valueDescription = "<version>", description = "Set library version")
@@ -53,7 +53,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-module-name", deprecatedName = "-module_name", valueDescription = "<name>", description = "Specify a name for the compilation module")
var moduleName: String? = null
@Argument(value = "-native-library", deprecatedName = "-nativelibrary", shortName = "-nl", valueDescription = "<path>", description = "Include the native bitcode library")
@Argument(value = "-native-library", deprecatedName = "-nativelibrary", shortName = "-nl",
valueDescription = "<path>", description = "Include the native bitcode library", delimiter = "")
var nativeLibraries: Array<String>? = null
@Argument(value = "-nodefaultlibs", description = "Don't link the libraries from dist/klib automatically")
@@ -120,7 +121,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = "-Xexport-library",
valueDescription = "<path>",
description = "Path to the library to be included into produced framework API\n" +
"Must be the path of a library passed with '-library'"
"Must be the path of a library passed with '-library'",
delimiter = ""
)
var exportedLibraries: Array<String>? = null
@@ -161,11 +163,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method")
var verifyBitCode: Boolean = false
@Argument(value = "-Xverify-descriptors", deprecatedName = "--verify_descriptors", description = "Verify descriptor tree")
var verifyDescriptors: Boolean = false
@Argument(value = "-Xverify-ir", deprecatedName = "--verify_ir", description = "Verify IR")
var verifyIr: Boolean = false
@Argument(value = "-Xverify-compiler", description = "Verify compiler")
var verifyCompiler: String? = null
@Argument(
value = "-friend-modules",
@@ -183,7 +182,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(
value = "-Xlibrary-to-cover",
valueDescription = "<path>",
description = "Path to library that should be covered."
description = "Path to library that should be covered.",
delimiter = ""
)
var coveredLibraries: Array<String>? = null
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -44,6 +41,8 @@ private fun KonanSymbols.getTypeConversionImpl(
}?.symbol
}
internal object DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION : IrDeclarationOriginImpl("INLINE_CLASS_SPECIAL_FUNCTION")
internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.lazyMapMember { inlinedClass ->
assert(inlinedClass.isUsedAsBoxClass())
assert(inlinedClass.parent is IrFile) { "Expected top level inline class" }
@@ -63,7 +62,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<${inlinedClass.name}-box>"),
Visibilities.PUBLIC,
@@ -114,7 +113,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<${inlinedClass.name}-unbox>"),
Visibilities.PUBLIC,
@@ -7,10 +7,11 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName
internal fun IrClass.isNonGeneratedAnnotation(): Boolean =
this.kind == ClassKind.ANNOTATION_CLASS &&
!this.descriptor.annotations.hasAnnotation(serialInfoAnnotationFqName)
!this.annotations.hasAnnotation(serialInfoAnnotationFqName)
private val serialInfoAnnotationFqName = FqName("kotlinx.serialization.SerialInfo")
@@ -10,10 +10,8 @@ import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
@@ -351,11 +349,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
moduleDescriptor.deepPrint()
}
fun verifyIr() {
val module = irModule ?: return
validateIrModule(this, module)
}
fun printIr() {
if (irModule == null) return
separator("IR:")
@@ -418,7 +411,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun verify() {
verifyDescriptors()
verifyIr()
verifyBitCode()
}
@@ -48,6 +48,11 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val memoryModel: MemoryModel get() = configuration.get(KonanConfigKeys.MEMORY_MODEL)!!
val needCompilerVerification: Boolean
get() = configuration.get(KonanConfigKeys.VERIFY_COMPILER) ?:
(configuration.getBoolean(KonanConfigKeys.OPTIMIZATION) ||
KonanVersion.CURRENT.meta != MetaVersion.RELEASE)
init {
if (!platformManager.isEnabled(target)) {
error("Target ${target.visibleName} is not available on the ${HostManager.hostName} host")
@@ -46,7 +46,7 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("library version")
val LINKER_ARGS: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("additional linker arguments")
val LIST_PHASES: CompilerConfigurationKey<Boolean>
val LIST_PHASES: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("list backend phases")
val LIST_TARGETS: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("list available targets")
@@ -100,20 +100,16 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("target we compile for")
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("directory for temporary files")
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify bitcode")
val VERIFY_DESCRIPTORS: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify descriptors")
val VERIFY_IR: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify ir")
val VERBOSE_PHASES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("verbose backend phases")
val VERIFY_COMPILER: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify compiler")
val DEBUG_INFO_VERSION: CompilerConfigurationKey<Int>
= CompilerConfigurationKey.create("debug info format version")
val COVERAGE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("emit coverage info for sources")
val LIBRARIES_TO_COVER: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create<List<String>>("libraries that should be covered")
= CompilerConfigurationKey.create("libraries that should be covered")
val PROFRAW_PATH: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("path to *.profraw coverage output")
val OBJC_GENERICS: CompilerConfigurationKey<Boolean>
@@ -13,12 +13,16 @@ internal const val NATIVE_PTR_NAME = "NativePtr"
internal const val NON_NULL_NATIVE_PTR_NAME = "NonNullNativePtr"
object KonanFqNames {
val packageName = FqName("kotlin.native")
val internalPackageName = FqName("kotlin.native.internal")
val nativePtr = internalPackageName.child(Name.identifier(NATIVE_PTR_NAME)).toUnsafe()
val nonNullNativePtr = internalPackageName.child(Name.identifier(NON_NULL_NATIVE_PTR_NAME)).toUnsafe()
val throws = FqName("kotlin.native.Throws")
val threadLocal = FqName("kotlin.native.concurrent.ThreadLocal")
val sharedImmutable = FqName("kotlin.native.concurrent.SharedImmutable")
val frozen = FqName("kotlin.native.internal.Frozen")
val typedIntrinsic = FqName("kotlin.native.internal.TypedIntrinsic")
val objCMethod = FqName("kotlinx.cinterop.ObjCMethod")
}
/**
@@ -10,22 +10,24 @@ import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering
import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.checkDeclarationParents
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
private val validateAll = false
private val filePhaseActions = if (validateAll) setOf(defaultDumper, ::fileValidationCallback) else setOf(defaultDumper)
private val modulePhaseActions = if (validateAll) setOf(defaultDumper, ::moduleValidationCallback) else setOf(defaultDumper)
private fun makeKonanFileLoweringPhase(
lowering: (Context) -> FileLoweringPass,
name: String,
description: String,
prerequisite: Set<AnyNamedPhase> = emptySet()
) = makeIrFilePhase(lowering, name, description, prerequisite)
) = makeIrFilePhase(lowering, name, description, prerequisite, actions = filePhaseActions)
private fun makeKonanModuleLoweringPhase(
lowering: (Context) -> FileLoweringPass,
name: String,
description: String,
prerequisite: Set<AnyNamedPhase> = emptySet()
) = makeIrModulePhase(lowering, name, description, prerequisite)
) = makeIrModulePhase(lowering, name, description, prerequisite, actions = modulePhaseActions)
internal fun makeKonanFileOpPhase(
op: (Context, IrFile) -> Unit,
@@ -39,7 +41,8 @@ internal fun makeKonanFileOpPhase(
op(context, input)
return input
}
}
},
actions = filePhaseActions
)
internal fun makeKonanModuleOpPhase(
@@ -54,7 +57,8 @@ internal fun makeKonanModuleOpPhase(
op(context, input)
return input
}
}
},
actions = modulePhaseActions
)
internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase(
@@ -79,7 +83,8 @@ internal val inlinePhase = namedIrModulePhase(
name = "Inline",
description = "Functions inlining",
prerequisite = setOf(lowerBeforeInlinePhase),
nlevels = 0
nlevels = 0,
actions = modulePhaseActions
)
internal val lowerAfterInlinePhase = makeKonanModuleOpPhase(
@@ -99,24 +104,6 @@ internal val interopPart1Phase = makeKonanModuleLoweringPhase(
prerequisite = setOf(inlinePhase)
)
internal val patchDeclarationParents1Phase = makeKonanModuleOpPhase(
{ _, irModule -> irModule.patchDeclarationParents() },
name = "PatchDeclarationParents1",
description = "Patch declaration parents 1"
)
internal val checkDeclarationParentsPhase = makeKonanModuleOpPhase(
{ _, irModule -> irModule.checkDeclarationParents() },
name = "CheckDeclarationParents",
description = "Check declaration parents"
)
internal val validateIrModulePhase = makeKonanModuleOpPhase(
{ context, irModule -> validateIrModule(context, irModule) },
name = "ValidateIrModule",
description = "Validate generated module"
)
/* IrFile phases */
internal val lateinitPhase = makeKonanFileLoweringPhase(
@@ -284,11 +271,8 @@ internal val bridgesPhase = makeKonanFileOpPhase(
prerequisite = setOf(coroutinesPhase)
)
internal val autoboxPhase = makeKonanFileOpPhase(
{ context, irFile ->
// validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished.
Autoboxing(context).lower(irFile)
},
internal val autoboxPhase = makeKonanFileLoweringPhase(
::Autoboxing,
name = "Autobox",
description = "Autoboxing of primitive types",
prerequisite = setOf(bridgesPhase, coroutinesPhase)
@@ -14,10 +14,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isReal
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
@@ -61,8 +58,7 @@ fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
}
fun IrClass.isExternalObjCClass(): Boolean = this.isObjCClass() &&
(this as IrDeclaration).parentDeclarationsWithSelf.filterIsInstance<IrClass>().any {
it.annotations.hasAnnotation(externalObjCClassFqName) ||
it.descriptor.annotations.hasAnnotation(externalObjCClassFqName)
it.annotations.hasAnnotation(externalObjCClassFqName)
}
fun ClassDescriptor.isObjCForwardDeclaration(): Boolean =
@@ -140,9 +136,9 @@ fun FunctionDescriptor.getObjCMethodInfo(): ObjCMethodInfo? = this.getObjCMethod
fun IrFunction.isObjCBridgeBased(): Boolean {
assert(this.isReal)
return this.descriptor.annotations.hasAnnotation(objCMethodFqName) ||
this.descriptor.annotations.hasAnnotation(objCFactoryFqName) ||
this.descriptor.annotations.hasAnnotation(objCConstructorFqName)
return this.annotations.hasAnnotation(objCMethodFqName) ||
this.annotations.hasAnnotation(objCFactoryFqName) ||
this.annotations.hasAnnotation(objCConstructorFqName)
}
/**
@@ -222,11 +218,11 @@ fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
}
val IrConstructor.isObjCConstructor get() = this.descriptor.annotations.hasAnnotation(objCConstructorFqName)
val IrConstructor.isObjCConstructor get() = this.annotations.hasAnnotation(objCConstructorFqName)
// TODO-DCE-OBJC-INIT: Selector should be preserved by DCE.
fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
return this.descriptor.annotations.findAnnotation(objCConstructorFqName)?.let {
return this.annotations.findAnnotation(objCConstructorFqName)?.let {
val initSelector = it.getStringValue("initSelector")
this.constructedClass.declarations.asSequence()
.filterIsInstance<IrSimpleFunction>()
@@ -234,9 +230,9 @@ fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
}
}
val IrFunction.hasObjCFactoryAnnotation get() = this.descriptor.annotations.hasAnnotation(objCFactoryFqName)
val IrFunction.hasObjCFactoryAnnotation get() = this.annotations.hasAnnotation(objCFactoryFqName)
val IrFunction.hasObjCMethodAnnotation get() = this.descriptor.annotations.hasAnnotation(objCMethodFqName)
val IrFunction.hasObjCMethodAnnotation get() = this.annotations.hasAnnotation(objCMethodFqName)
fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
@@ -1,6 +1,6 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
@@ -20,12 +20,49 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import java.util.Collections.emptySet
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
if (!context.config.needCompilerVerification) return
val validatorConfig = IrValidatorConfig(
abortOnError = false,
ensureAllNodesAreDifferent = true,
checkTypes = true,
checkDescriptors = false
)
try {
module.accept(IrValidator(context, validatorConfig), null)
module.accept(CheckDeclarationParentsVisitor, null)
} catch (t: Throwable) {
// TODO: Add reference to source.
if (validatorConfig.abortOnError)
throw IllegalStateException("Failed IR validation ${state.beforeOrAfter} ${state.phase}", t)
else context.reportCompilationWarning("[IR VALIDATION] ${state.beforeOrAfter} ${state.phase}: ${t.message}")
}
}
internal fun fileValidationCallback(state: ActionState, irFile: IrFile, context: Context) {
val validatorConfig = IrValidatorConfig(
abortOnError = false,
ensureAllNodesAreDifferent = true,
checkTypes = true,
checkDescriptors = false
)
try {
irFile.accept(IrValidator(context, validatorConfig), null)
irFile.accept(CheckDeclarationParentsVisitor, null)
} catch (t: Throwable) {
// TODO: Add reference to source.
if (validatorConfig.abortOnError)
throw IllegalStateException("Failed IR validation ${state.beforeOrAfter} ${state.phase}", t)
else context.reportCompilationWarning("[IR VALIDATION] ${state.beforeOrAfter} ${state.phase}: ${t.message}")
}
}
internal fun konanUnitPhase(
name: String,
description: String,
@@ -128,8 +165,6 @@ internal val psiToIrPhase = konanUnitPhase(
irModule = module
irModules = deserializer.modules
ir.symbols = symbols
// validateIrModule(this, module)
},
name = "Psi2Ir",
description = "Psi to IR conversion",
@@ -169,12 +204,6 @@ internal val copyDefaultValuesToActualPhase = konanUnitPhase(
description = "Copy default values from expect to actual declarations"
)
internal val patchDeclarationParents0Phase = konanUnitPhase(
op = { irModule!!.patchDeclarationParents() }, // why do we need it?
name = "PatchDeclarationParents0",
description = "Patch declaration parents"
)
internal val serializerPhase = konanUnitPhase(
op = {
val declarationTable = KonanDeclarationTable(irModule!!.irBuiltins, DescriptorTable())
@@ -213,7 +242,6 @@ internal val allLoweringsPhase = namedIrModulePhase(
inlinePhase then
lowerAfterInlinePhase then
interopPart1Phase then
patchDeclarationParents1Phase then
performByIrFile(
name = "IrLowerByFile",
description = "IR Lowering by file",
@@ -242,9 +270,8 @@ internal val allLoweringsPhase = namedIrModulePhase(
bridgesPhase then
autoboxPhase then
returnsInsertionPhase
) then
checkDeclarationParentsPhase
// validateIrModulePhase // Temporarily disabled until moving to new IR finished.
),
actions = setOf(defaultDumper, ::moduleValidationCallback)
)
internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper(
@@ -313,7 +340,6 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
destroySymbolTablePhase then
irGeneratorPluginsPhase then
copyDefaultValuesToActualPhase then
patchDeclarationParents0Phase then
serializerPhase then
namedUnitPhase(
name = "Backend",
@@ -347,5 +373,6 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
switch(buildDFGPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION))
switch(devirtualizationPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION))
switch(dcePhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION))
switch(verifyBitcodePhase, config.needCompilerVerification || config.configuration.getBoolean(KonanConfigKeys.VERIFY_BITCODE))
}
}
@@ -297,19 +297,19 @@ internal fun KotlinStubs.generateObjCCall(
superQualifier: IrClassSymbol?,
receiver: IrExpression,
arguments: List<IrExpression?>
): IrExpression {
) = builder.irBlock {
val callBuilder = KotlinToCCallBuilder(builder, this@generateObjCCall, isObjCMethod = true)
val callBuilder = KotlinToCCallBuilder(builder, this, isObjCMethod = true)
val superClass = irTemporaryVar(
superQualifier?.let { getObjCClass(symbols, it) } ?: irNullNativePtr(symbols)
)
val superClass = superQualifier?.let { builder.getObjCClass(symbols, it) }
?: builder.irNullNativePtr(symbols)
val messenger = builder.irCall(if (isStret) {
val messenger = irCall(if (isStret) {
symbols.interopGetMessengerStret
} else {
symbols.interopGetMessenger
}.owner).apply {
putValueArgument(0, superClass) // TODO: check superClass statically.
putValueArgument(0, irGet(superClass)) // TODO: check superClass statically.
}
val targetPtrParameter = callBuilder.passThroughBridge(
@@ -320,7 +320,7 @@ internal fun KotlinStubs.generateObjCCall(
val targetFunctionName = "targetPtr"
val preparedReceiver = if (method.consumesReceiver()) {
builder.irCall(symbols.interopObjCRetain.owner).apply {
irCall(symbols.interopObjCRetain.owner).apply {
putValueArgument(0, receiver)
}
} else {
@@ -328,9 +328,9 @@ internal fun KotlinStubs.generateObjCCall(
}
val receiverOrSuper = if (superQualifier != null) {
builder.irCall(symbols.interopCreateObjCSuperStruct.owner).apply {
irCall(symbols.interopCreateObjCSuperStruct.owner).apply {
putValueArgument(0, preparedReceiver)
putValueArgument(1, superClass)
putValueArgument(1, irGet(superClass))
}
} else {
preparedReceiver
@@ -355,7 +355,7 @@ internal fun KotlinStubs.generateObjCCall(
callBuilder.emitCBridge()
return result
+result
}
private fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression {
@@ -581,11 +581,9 @@ private fun IrType.isCEnumType(): Boolean {
.any { (it.classifierOrNull?.owner as? IrClass)?.fqNameForIrSerialization == FqName("kotlinx.cinterop.CEnum") }
}
// TODO: get rid of consulting descriptors for annotations.
// Make sure external stubs always get proper annotaions.
private fun IrDeclaration.hasCCallAnnotation(name: String): Boolean =
this.annotations.hasAnnotation(cCall.child(Name.identifier(name))) ||
this.descriptor.annotations.hasAnnotation(cCall.child(Name.identifier(name)))
this.annotations.hasAnnotation(cCall.child(Name.identifier(name)))
private fun IrValueParameter.isWCStringParameter() = hasCCallAnnotation("WCString")
@@ -1170,7 +1168,6 @@ private class ObjCBlockPointerValuePassing(
Name.identifier("blockHolder"),
isMutable = false, owner = irClass
)
irClass.addChild(blockHolderField)
val constructorDescriptor = WrappedClassConstructorDescriptor()
val constructor = IrConstructorImpl(
@@ -5,17 +5,19 @@
package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.isInlinedNative
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.backend.konan.llvm.longName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isReal
import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.overrides
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.types.SimpleType
/**
@@ -75,12 +77,8 @@ internal fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false
return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT }
}
// TODO: don't forget to remove descriptor access here.
internal val IrFunction.isTypedIntrinsic: Boolean
get() = this.descriptor.isTypedIntrinsic
internal val IrDeclaration.isFrozen: Boolean
get() = this.descriptor.isFrozen
get() = annotations.hasAnnotation(KonanFqNames.typedIntrinsic)
internal val arrayTypes = setOf(
"kotlin.Array",
@@ -242,4 +240,28 @@ fun IrDeclaration.findTopLevelDeclaration(): IrDeclaration = when {
(this as IrField).correspondingProperty!!.findTopLevelDeclaration()
else ->
(this.parent as IrDeclaration).findTopLevelDeclaration()
}
}
internal val IrClass.isFrozen: Boolean
get() = annotations.hasAnnotation(KonanFqNames.frozen) ||
// RTTI is used for non-reference type box or Objective-C object wrapper:
!this.defaultType.binaryTypeIsReference() || this.isObjCClass()
fun IrConstructorCall.getAnnotationValue() = (getValueArgument(0) as? IrConst<String>)?.value
fun IrConstructorCall.getStringValue(name: String): String {
val parameter = symbol.owner.valueParameters.single { it.name.asString() == name }
return (getValueArgument(parameter.index) as IrConst<String>).value
}
fun IrFunction.externalSymbolOrThrow(): String? {
annotations.findAnnotation(RuntimeNames.symbolNameAnnotation)?.let { return it.getAnnotationValue() }
if (annotations.hasAnnotation(KonanFqNames.objCMethod)) return null
if (annotations.hasAnnotation(KonanFqNames.typedIntrinsic)) return null
if (annotations.hasAnnotation(RuntimeNames.cCall)) return null
throw Error("external function ${this.longName} must have @TypedIntrinsic, @SymbolName or @ObjCMethod annotation")
}
@@ -7,22 +7,14 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.konanModuleOrigin
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -30,11 +22,8 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
/**
* Implementation of given method.
@@ -172,31 +161,6 @@ internal val DeclarationDescriptor.isExpectMember: Boolean
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this)
internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? =
DescriptorFactory.createExtensionReceiverParameterForCallable(
owner,
this,
Annotations.EMPTY
)
internal fun FunctionDescriptorImpl.initialize(
extensionReceiverType: KotlinType?,
dispatchReceiverParameter: ReceiverParameterDescriptor?,
typeParameters: List<TypeParameterDescriptor>,
unsubstitutedValueParameters: List<ValueParameterDescriptor>,
unsubstitutedReturnType: KotlinType?,
modality: Modality?,
visibility: Visibility
): FunctionDescriptorImpl = this.initialize(
extensionReceiverType.createExtensionReceiver(this),
dispatchReceiverParameter,
typeParameters,
unsubstitutedValueParameters,
unsubstitutedReturnType,
modality,
visibility
)
private fun sourceByIndex(descriptor: CallableMemberDescriptor, index: Int): SourceFile {
val fragment = descriptor.findPackage() as KonanPackageFragment
return fragment.sourceFileMap.sourceFile(index)
@@ -216,43 +180,4 @@ fun CallableMemberDescriptor.findSourceFile(): SourceFile {
}
}
internal val DeclarationDescriptor.isFrozen: Boolean
get() = this.annotations.hasAnnotation(RuntimeNames.frozenAnnotation) ||
(this is org.jetbrains.kotlin.descriptors.ClassDescriptor
// RTTI is used for non-reference type box or Objective-C object wrapper:
&& (!this.defaultType.binaryTypeIsReference() || this.isObjCClass()))
internal val FunctionDescriptor.isTypedIntrinsic: Boolean
get() = this.annotations.hasAnnotation(RuntimeNames.typedIntrinsicAnnotation)
// TODO: coalesce all our annotation value getters into fewer functions.
fun getAnnotationValue(annotation: AnnotationDescriptor): String? {
return annotation.allValueArguments.values.ifNotEmpty {
val stringValue = single() as? StringValue
stringValue?.value
}
}
fun CallableMemberDescriptor.externalSymbolOrThrow(): String? {
this.annotations.findAnnotation(RuntimeNames.symbolNameAnnotation)?.let {
return getAnnotationValue(it)!!
}
if (this.annotations.hasAnnotation(RuntimeNames.objCMethodAnnotation)) return null
if (this.annotations.hasAnnotation(RuntimeNames.typedIntrinsicAnnotation)) return null
if (this.annotations.hasAnnotation(RuntimeNames.cCall)) return null
throw Error("external function ${this} must have @TypedIntrinsic, @SymbolName or @ObjCMethod annotation")
}
fun createAnnotation(
descriptor: ClassDescriptor,
vararg values: Pair<String, String>
): AnnotationDescriptor = AnnotationDescriptorImpl(
descriptor.defaultType,
values.map { (name, value) -> Name.identifier(name) to StringValue(value) }.toMap(),
SourceElement.NO_SOURCE
)
val ModuleDescriptor.konanLibrary get() = (this.konanModuleOrigin as? DeserializedKonanModuleOrigin)?.library
@@ -449,13 +449,13 @@ internal class KonanSymbols(context: Context, private val symbolTable: SymbolTab
)
val listOfInternal = internalFunction("listOfInternal")
val threadLocal =
val threadLocal = symbolTable.referenceClass(
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.native.concurrent.ThreadLocal")))!!
ClassId.topLevel(KonanFqNames.threadLocal))!!)
val sharedImmutable =
val sharedImmutable = symbolTable.referenceClass(
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(FqName("kotlin.native.concurrent.SharedImmutable")))!!
ClassId.topLevel(KonanFqNames.sharedImmutable))!!)
private fun topLevelClass(fqName: String): IrClassSymbol = topLevelClass(FqName(fqName))
private fun topLevelClass(fqName: FqName): IrClassSymbol = classById(ClassId.topLevel(fqName))
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.descriptors.getArgumentValueOrNull
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
@@ -69,14 +68,7 @@ val IrClass.isFinalClass: Boolean
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? {
val annotation = this.annotations.findAnnotation(fqName)
if (annotation == null) {
// As a last resort try searching the descriptor.
// This is needed for a period while we don't have IR for platform libraries.
return this.descriptor.annotations
.findAnnotation(fqName)
?.getArgumentValueOrNull<T>(argumentName)
}
val annotation = this.annotations.findAnnotation(fqName) ?: return null
for (index in 0 until annotation.valueArgumentsCount) {
val parameter = annotation.symbol.owner.valueParameters[index]
if (parameter.name == Name.identifier(argumentName)) {
@@ -95,12 +87,6 @@ val IrDeclaration.parentDeclarationsWithSelf: Sequence<IrDeclaration>
fun IrClass.companionObject() = this.declarations.filterIsInstance<IrClass>().atMostOne { it.isCompanion }
val IrDeclaration.isGetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.getter
val IrDeclaration.isSetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.setter
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
fun buildSimpleAnnotation(irBuiltIns: IrBuiltIns, startOffset: Int, endOffset: Int,
annotationClass: IrClass, vararg args: String): IrConstructorCall {
val constructor = annotationClass.constructors.single()
@@ -18,11 +18,9 @@ import org.jetbrains.kotlin.backend.konan.ir.isUnit
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.isExported
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.isVararg
import org.jetbrains.kotlin.backend.konan.isInlinedNative
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.library.uniqueName
@@ -36,8 +34,6 @@ object KonanMangler : KotlinManglerImpl() {
override val IrType.isInlined
get() = this.isInlinedNative()
override val String.hashMangle get() = this.localHash.value
/**
* Defines whether the declaration is exported, i.e. visible from other modules.
*
@@ -47,20 +43,19 @@ object KonanMangler : KotlinManglerImpl() {
*/
override fun IrDeclaration.isPlatformSpecificExported(): Boolean {
// TODO: revise
val descriptorAnnotations = this.descriptor.annotations
if (descriptorAnnotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
return true
}
@@ -109,13 +104,13 @@ object KonanMangler : KotlinManglerImpl() {
}
if (isExternal) {
this.descriptor.externalSymbolOrThrow()?.let {
this.externalSymbolOrThrow()?.let {
return it
}
}
this.descriptor.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let {
val name = getAnnotationValue(it) ?: this.name.asString()
this.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let {
val name = it.getAnnotationValue() ?: this.name.asString()
return name // no wrapping currently required
}
@@ -308,7 +308,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
fun checkMainThread(exceptionHandler: ExceptionHandler) {
call(context.llvm.checkMainThread, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
if (context.memoryModel == MemoryModel.STRICT)
call(context.llvm.checkMainThread, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
}
private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
@@ -428,11 +428,11 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val allocArrayFunction = importModelSpecificRtFunction("AllocArrayInstance")
val initInstanceFunction = importModelSpecificRtFunction("InitInstance")
val initSharedInstanceFunction = importModelSpecificRtFunction("InitSharedInstance")
val updateHeapRefFunction = importRtFunction("UpdateHeapRef")
val updateStackRefFunction = importRtFunction("UpdateStackRef")
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
val enterFrameFunction = importRtFunction("EnterFrame")
val leaveFrameFunction = importRtFunction("LeaveFrame")
val updateHeapRefFunction = importModelSpecificRtFunction("UpdateHeapRef")
val updateStackRefFunction = importModelSpecificRtFunction("UpdateStackRef")
val updateReturnRefFunction = importModelSpecificRtFunction("UpdateReturnRef")
val enterFrameFunction = importModelSpecificRtFunction("EnterFrame")
val leaveFrameFunction = importModelSpecificRtFunction("LeaveFrame")
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
val isInstanceFunction = importRtFunction("IsInstance")
val checkInstanceFunction = importRtFunction("CheckInstance")
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@@ -9,18 +9,18 @@ import kotlinx.cinterop.allocArrayOf
import kotlinx.cinterop.memScoped
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.ir.util.isTypeParameter
import org.jetbrains.kotlin.ir.util.isUnsigned
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
internal object DWARF {
val producer = "konanc ${KonanVersion.CURRENT} / kotlin-compiler: ${KotlinVersion.CURRENT}"
@@ -65,19 +65,17 @@ internal class DebugInfo internal constructor(override val context: Context):Con
val inlinedSubprograms = mutableMapOf<IrFunction, DISubprogramRef>()
var builder: DIBuilderRef? = null
var module: DIModuleRef? = null
var types = mutableMapOf<KotlinType, DITypeOpaqueRef>()
var types = mutableMapOf<IrType, DITypeOpaqueRef>()
val llvmTypes = mapOf<KotlinType, LLVMTypeRef>(
context.builtIns.booleanType to context.llvm.llvmInt8,
context.builtIns.byteType to context.llvm.llvmInt8,
context.builtIns.charType to context.llvm.llvmInt8,
context.builtIns.shortType to context.llvm.llvmInt16,
context.builtIns.intType to context.llvm.llvmInt32,
context.builtIns.longType to context.llvm.llvmInt64,
context.builtIns.floatType to context.llvm.llvmFloat,
context.builtIns.doubleType to context.llvm.llvmDouble)
val intTypes = listOf<KotlinType>(context.builtIns.byteType, context.builtIns.shortType, context.builtIns.intType, context.builtIns.longType)
val realTypes = listOf<KotlinType>(context.builtIns.floatType, context.builtIns.doubleType)
val llvmTypes = mapOf<IrType, LLVMTypeRef>(
context.irBuiltIns.booleanType to context.llvm.llvmInt8,
context.irBuiltIns.byteType to context.llvm.llvmInt8,
context.irBuiltIns.charType to context.llvm.llvmInt8,
context.irBuiltIns.shortType to context.llvm.llvmInt16,
context.irBuiltIns.intType to context.llvm.llvmInt32,
context.irBuiltIns.longType to context.llvm.llvmInt64,
context.irBuiltIns.floatType to context.llvm.llvmFloat,
context.irBuiltIns.doubleType to context.llvm.llvmDouble)
val llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap()
val llvmTypeAlignments = llvmTypes.map {it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value)}.toMap()
val otherLlvmType = LLVMPointerType(LLVMInt64Type(), 0)!!
@@ -159,13 +157,12 @@ internal fun generateDebugInfoHeader(context: Context) {
}
@Suppress("UNCHECKED_CAST")
internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
when {
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.getJetTypeFqName(false), llvmType(context), encoding(context).value.toInt())
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.render(), llvmType(context), encoding(context).value.toInt())
else -> {
val classDescriptor = TypeUtils.getClassDescriptor(this)
return when {
classDescriptor != null -> {
classOrNull != null -> {
val type = DICreateStructType(
refBuilder = context.debugInfo.builder,
// TODO: here should be DIFile as scope.
@@ -182,7 +179,7 @@ internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRe
refPlace = null)!! as DITypeOpaqueRef
dwarfPointerType(context, type)
}
TypeUtils.isTypeParameter(this) -> //TODO: Type parameter, how to deal with if?
this.isTypeParameter() -> //TODO: Type parameter, how to deal with if?
debugInfoBaseType(context, targetData, this.toString(), llvmType(context), encoding(context).value.toInt())
else -> TODO("$this: Does this case really exist?")
}
@@ -190,7 +187,7 @@ internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRe
}
}
internal fun KotlinType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
internal fun IrType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
context.debugInfo.types.getOrPut(this) {
dwarfType(context, llvmTargetData)
}
@@ -201,17 +198,17 @@ private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typ
LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef
internal val IrFunction.types:List<KotlinType>
internal val IrFunction.types:List<IrType>
get() {
val parameters = descriptor.valueParameters.map{it.type}
return listOf(descriptor.returnType!!, *parameters.toTypedArray())
val parameters = valueParameters.map { it.type }
return listOf(returnType, *parameters.toTypedArray())
}
internal fun KotlinType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize)
internal fun IrType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize)
internal fun KotlinType.alignment(context:Context) = context.debugInfo.llvmTypeAlignments.getOrDefault(this, context.debugInfo.otherTypeAlignment).toLong()
internal fun IrType.alignment(context:Context) = context.debugInfo.llvmTypeAlignments.getOrDefault(this, context.debugInfo.otherTypeAlignment).toLong()
internal fun KotlinType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrElse(this) {
internal fun IrType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrElse(this) {
when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BYTE -> context.llvm.llvmInt8
PrimitiveBinaryType.SHORT -> context.llvm.llvmInt16
@@ -223,14 +220,14 @@ internal fun KotlinType.llvmType(context:Context): LLVMTypeRef = context.debugIn
}
}
internal fun KotlinType.encoding(context: Context): DwarfTypeKind = when(computePrimitiveBinaryTypeOrNull()) {
internal fun IrType.encoding(context: Context): DwarfTypeKind = when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.FLOAT -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.DOUBLE -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.BOOLEAN -> DwarfTypeKind.DW_ATE_boolean
PrimitiveBinaryType.POINTER -> DwarfTypeKind.DW_ATE_address
else -> {
//TODO: not recursive.
if (UnsignedTypes.isUnsignedType(this)) DwarfTypeKind.DW_ATE_unsigned
if (this.isUnsigned()) DwarfTypeKind.DW_ATE_unsigned
else DwarfTypeKind.DW_ATE_signed
}
}
@@ -242,7 +239,7 @@ internal fun IrFunction.subroutineType(context: Context, llvmTargetData: LLVMTar
return subroutineType(context, llvmTargetData, types)
}
internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<KotlinType>): DISubroutineTypeRef {
internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef {
return memScoped {
DICreateSubroutineType(context.debugInfo.builder, allocArrayOf(
types.map { it.diType(context, llvmTargetData) }),
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector
import org.jetbrains.kotlin.backend.konan.reportCompilationError
@@ -12,8 +13,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.name.Name
internal enum class IntrinsicType {
PLUS,
@@ -113,8 +114,8 @@ internal fun tryGetIntrinsicType(callSite: IrFunctionAccessExpression): Intrinsi
private fun getIntrinsicType(callSite: IrFunctionAccessExpression): IntrinsicType {
val function = callSite.symbol.owner
val annotation = function.descriptor.annotations.findAnnotation(RuntimeNames.typedIntrinsicAnnotation)!!
val value = annotation.allValueArguments.getValue(Name.identifier("kind")).value as String
val annotation = function.annotations.findAnnotation(RuntimeNames.typedIntrinsicAnnotation)!!
val value = annotation.getAnnotationValue()!!
return IntrinsicType.valueOf(value)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@@ -11,46 +11,25 @@ import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.ir.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.backend.konan.ir.containsNull
import org.jetbrains.kotlin.backend.konan.llvm.coverage.*
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.is64Bit
import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
private val threadLocalAnnotationFqName = FqName("kotlin.native.concurrent.ThreadLocal")
private val sharedAnnotationFqName = FqName("kotlin.native.concurrent.SharedImmutable")
private val frozenAnnotationFqName = FqName("kotlin.native.internal.Frozen")
val IrField.propertyDescriptor: PropertyDescriptor
get() {
val descriptor = this.descriptor
return if (descriptor is IrPropertyDelegateDescriptor)
descriptor.correspondingProperty
else
descriptor
}
internal enum class FieldStorage {
MAIN_THREAD,
SHARED,
@@ -59,17 +38,18 @@ internal enum class FieldStorage {
// TODO: maybe unannotated singleton objects shall be accessed from main thread only as well?
val IrClass.objectIsShared get() =
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName)
!annotations.hasAnnotation(KonanFqNames.threadLocal)
internal val IrField.storageClass: FieldStorage get() {
val descriptor = propertyDescriptor
// TODO: Is this correct?
val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations
return when {
descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) -> FieldStorage.THREAD_LOCAL
annotations.hasAnnotation(KonanFqNames.threadLocal) -> FieldStorage.THREAD_LOCAL
!isFinal -> FieldStorage.MAIN_THREAD
descriptor.annotations.hasAnnotation(sharedAnnotationFqName) -> FieldStorage.SHARED
annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorage.SHARED
// TODO: simplify, once IR types are fully there.
type is IrSimpleType && (type as IrSimpleType).
classifier.descriptor.annotations.hasAnnotation(frozenAnnotationFqName) -> FieldStorage.SHARED
(type.classifierOrNull?.owner as? IrAnnotationContainer)
?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorage.SHARED
else -> FieldStorage.MAIN_THREAD
}
}
@@ -630,7 +610,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy {
if (!context.shouldContainDebugInfo())
return@lazy null
declaration?.scope() ?: llvmFunction!!.scope(0, subroutineType(context, codegen.llvmTargetData, listOf(context.builtIns.intType)))
declaration?.scope() ?: llvmFunction!!.scope(0, subroutineType(context, codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
}
override fun location(line: Int, column: Int) = scope?.let { LocationInfo(it, line, column) }
@@ -682,7 +662,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
if (declaration.descriptor.retainAnnotation(context.config.target)) {
if (declaration.retainAnnotation(context.config.target)) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
}
@@ -1189,7 +1169,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation(
builder = context.debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
diType = element.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name,
file = file,
line = locationInfo.line,
@@ -1198,7 +1178,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrValueParameter -> debugInfoParameterLocation(
builder = context.debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
diType = element.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name,
argNo = function.allParameters.indexOf(element) + 1,
file = file,
@@ -1452,11 +1432,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
//-------------------------------------------------------------------------//
// TODO: rewrite in IR!
private fun needMutationCheck(descriptor: org.jetbrains.kotlin.descriptors.DeclarationDescriptor): Boolean {
private fun needMutationCheck(irClass: IrClass): Boolean {
// For now we omit mutation checks on immutable types, as this allows initialization in constructor
// and it is assumed that API doesn't allow to change them.
return !descriptor.isFrozen
return !irClass.isFrozen
}
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
@@ -1467,7 +1446,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert(thisPtr.type == codegen.kObjHeaderPtr) {
LLVMPrintTypeToString(thisPtr.type)?.toKString().toString()
}
if (needMutationCheck(value.descriptor.containingDeclaration)) {
if (needMutationCheck(value.symbol.owner.parentAsClass)) {
functionGenerationContext.call(context.llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, ExceptionHandler.Caller)
@@ -1784,9 +1763,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val scope = currentCodeContext.classScope() as? ClassScope ?: return
if (!scope.isExported || !context.shouldContainDebugInfo()) return
val irFile = (currentCodeContext.fileScope() as FileScope).file
val sizeInBits = expression.descriptor.type.size(context)
val sizeInBits = expression.type.size(context)
scope.offsetInBits += sizeInBits
val alignInBits = expression.descriptor.type.alignment(context)
val alignInBits = expression.type.alignment(context)
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType(
@@ -1799,7 +1778,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
alignInBits = alignInBits,
offsetInBits = scope.offsetInBits,
flags = 0,
type = expression.descriptor.type.diType(context, codegen.llvmTargetData)
type = expression.type.diType(context, codegen.llvmTargetData)
)!!)
}
@@ -2086,7 +2065,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert(irClass.isInterface)
assert(irClass.isExternalObjCClass())
val annotation = irClass.descriptor.annotations.findAnnotation(externalObjCClassFqName)!!
val annotation = irClass.annotations.findAnnotation(externalObjCClassFqName)!!
val protocolGetterName = annotation.getStringValue("protocolGetter")
val protocolGetter = context.llvm.externalFunction(
protocolGetterName,
@@ -8,13 +8,13 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMStoreSizeOfType
import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -118,7 +118,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
.filterIsInstance<IrSimpleFunction>()
.mapNotNull {
val annotation =
it.descriptor.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
it.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
return@mapNotNull null
ObjCMethodDesc(
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.ir.util.fqNameSafe
import org.jetbrains.kotlin.ir.util.isAnnotationClass
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.library.KotlinAbiVersion
@@ -128,9 +126,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private val EXPORT_TYPE_INFO_FQ_NAME = FqName.fromSegments(listOf("kotlin", "native", "internal", "ExportTypeInfo"))
private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) {
val annotation = irClass.descriptor.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
val annotation = irClass.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
if (annotation != null) {
val name = getAnnotationValue(annotation)!!
val name = annotation.getAnnotationValue()!!
// TODO: use LLVMAddAlias.
val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true)
LLVMSetInitializer(global, typeInfoGlobal)
@@ -5,18 +5,18 @@
package org.jetbrains.kotlin.backend.konan.llvm
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.FqName
private val retainAnnotationName = FqName("kotlin.native.Retain")
private val retainForTargetAnnotationName = FqName("kotlin.native.RetainForTarget")
internal fun FunctionDescriptor.retainAnnotation(target: KonanTarget): Boolean {
internal fun IrFunction.retainAnnotation(target: KonanTarget): Boolean {
if (this.annotations.findAnnotation(retainAnnotationName) != null) return true
val forTarget = this.annotations.findAnnotation(retainForTargetAnnotationName)
if (forTarget != null && forTarget.getStringValueOrNull("target") == target.name) return true
if (forTarget != null && forTarget.getAnnotationValue() == target.name) return true
return false
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrPropertySymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
@@ -401,7 +402,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
descriptor,
IrPropertySymbolImpl(descriptor),
irField.name,
irField.visibility,
Modality.FINAL,
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.ir.fqNameForIrSerialization
import org.jetbrains.kotlin.backend.konan.ir.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.*
@@ -95,11 +94,10 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
if (cur !is IrCall)
break
val argument = if (i < stack.size - 1) stack[i + 1] else expression
val descriptor = cur.descriptor
val argumentDescriptor = descriptor.valueParameters.singleOrNull {
val parameter = cur.symbol.owner.valueParameters.singleOrNull {
cur.getValueArgument(it.index) == argument
}
if (argumentDescriptor?.annotations?.findAnnotation(VOLATILE_LAMBDA_FQ_NAME) != null) {
if (parameter?.annotations?.findAnnotation(VOLATILE_LAMBDA_FQ_NAME) != null) {
return expression
}
break
@@ -10,12 +10,13 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.transformFlat
internal class ContractsDslRemover(val context: Context) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat {
if (it is IrClass && it.descriptor.annotations.hasAnnotation(ContractsDslNames.CONTRACTS_DSL_ANNOTATION_FQN))
if (it is IrClass && it.annotations.hasAnnotation(ContractsDslNames.CONTRACTS_DSL_ANNOTATION_FQN))
null
else
listOf(it)
@@ -12,6 +12,10 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.ir.buildSimpleAnnotation
import org.jetbrains.kotlin.backend.konan.ir.typeWithStarProjections
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -87,10 +91,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = WrappedFieldDescriptor(
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
).let {
val kPropertiesField = WrappedFieldDescriptor().let {
IrFieldImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
@@ -104,6 +105,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
).apply {
it.bind(this)
parent = irFile
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.sharedImmutable.owner)
}
}
@@ -287,7 +287,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
putValueArgument(0, irInt(it.index))
}
val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(constructor)
initializer.setDeclarationsParent(constructor)
when {
initializer is IrConstructorCall -> +initInstanceCall(instance, initializer)
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
@@ -103,7 +100,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
val defaultValue = parameter.defaultValue ?: continue
defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
defaultValue.patchDeclarationParents(loweredEnumConstructor)
defaultValue.setDeclarationsParent(loweredEnumConstructor)
}
return loweredEnumConstructor
@@ -129,7 +126,9 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
).apply {
it.bind(this)
parent = constructor.parent
body = constructor.body!! // Will be transformed later.
val body = constructor.body!!
this.body = body // Will be transformed later.
body.setDeclarationsParent(this)
}
}
@@ -14,10 +14,12 @@ import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -77,9 +79,12 @@ internal class ExpectToActualDefaultValueCopier(private val irModule: IrModuleFr
return
}
function.findActualForExpected().valueParameters[index].defaultValue = defaultValue.also {
it.expression = it.expression.remapExpectValueSymbols()
}
val actualForExpected = function.findActualForExpected()
actualForExpected.valueParameters[index].defaultValue =
IrExpressionBodyImpl(
defaultValue.startOffset, defaultValue.endOffset,
defaultValue.expression.remapExpectValueSymbols().patchDeclarationParents(actualForExpected)
)
}
})
}
@@ -5,12 +5,9 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
@@ -20,6 +17,7 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.*
@@ -56,9 +54,8 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val actualCallee = getFunctionDeclaration(callee.symbol)
actualCallee.transformChildrenVoid(this) // Process recursive inline.
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context)
return inliner.inline()
}
@@ -105,9 +102,9 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
}
val substituteMap = mutableMapOf<IrValueParameter, IrElement>()
val substituteMap = mutableMapOf<IrValueParameter, IrExpression>()
fun inline() = inlineFunction(callSite, callee)
fun inline() = inlineFunction(callSite, callee, true)
/**
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
@@ -120,8 +117,12 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
}
}
private fun inlineFunction(callSite: IrFunctionAccessExpression, callee: IrFunction): IrReturnableBlock {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
private fun inlineFunction(callSite: IrFunctionAccessExpression,
callee: IrFunction,
performRecursiveInline: Boolean): IrReturnableBlock {
val copiedCallee = if (performRecursiveInline)
visitElement(copyIrElement.copy(callee)) as IrFunction
else copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
@@ -194,6 +195,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
return expression
}
})
patchDeclarationParents(parent) // TODO: Why it is not enough to just run SetDeclarationsParentVisitor?
}
}
@@ -205,12 +207,9 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val newExpression = super.visitGetValue(expression) as IrGetValue
val argument = substituteMap[newExpression.symbol.owner] ?: return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return if (argument is IrVariable) {
IrGetValueImpl(startOffset = newExpression.startOffset,
endOffset = newExpression.endOffset,
symbol = argument.symbol)
} else (copyIrElement.copy(argument) as IrExpression)
return if (argument is IrGetValueWithoutLocation)
argument.withLocation(newExpression.startOffset, newExpression.endOffset)
else (copyIrElement.copy(argument) as IrExpression)
}
//-----------------------------------------------------------------//
@@ -225,6 +224,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
return super.visitCall(expression)
if (functionArgument is IrFunctionReference) {
functionArgument.transformChildrenVoid(this)
val function = functionArgument.symbol.owner
val functionParameters = function.explicitParameters
val boundFunctionParameters = functionArgument.getArgumentsWithIr()
@@ -237,33 +237,41 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val immediateCall = with(expression) {
if (function is IrConstructor)
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, function.symbol)
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, function.returnType, function.symbol)
else
IrCallImpl(startOffset, endOffset, type, functionArgument.symbol)
IrCallImpl(startOffset, endOffset, function.returnType, functionArgument.symbol)
}.apply {
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
if (unboundArgsSet.contains(it))
valueParameters[unboundIndex++].second
else {
val arg = boundFunctionParametersMap[it]!!
if (arg is IrGetValueWithoutLocation)
arg.withLocation(expression.startOffset, expression.endOffset)
else arg
}
when (it) {
function.dispatchReceiverParameter -> this.dispatchReceiver = argument
function.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument(it.index, argument)
function.dispatchReceiverParameter ->
this.dispatchReceiver = argument.implicitCastIfNeededTo(function.dispatchReceiverParameter!!.type)
function.extensionReceiverParameter ->
this.extensionReceiver = argument.implicitCastIfNeededTo(function.extensionReceiverParameter!!.type)
else -> putValueArgument(it.index, argument.implicitCastIfNeededTo(function.valueParameters[it.index].type))
}
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index))
}
}.implicitCastIfNeededTo(expression.type)
return this@FunctionInlining.visitExpression(super.visitExpression(immediateCall))
}
if (functionArgument !is IrBlock)
return super.visitCall(expression)
val functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
val newExpression = inlineFunction(expression, functionDeclaration, false) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
}
@@ -272,6 +280,12 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
override fun visitElement(element: IrElement) = element.accept(this, null)
}
private fun IrExpression.implicitCastIfNeededTo(type: IrType) =
if (type == this.type)
this
else
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.IMPLICIT_CAST, type, this)
private fun isLambdaCall(irCall: IrCall): Boolean {
val callee = irCall.symbol.owner
val dispatchReceiver = callee.dispatchReceiverParameter ?: return false
@@ -310,8 +324,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
}
}
//-------------------------------------------------------------------------//
// callee might be a copied version of callsite.symbol.owner
private fun buildParameterToArgument(callSite: IrFunctionAccessExpression, callee: IrFunction): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>()
@@ -387,12 +400,38 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
//-------------------------------------------------------------------------//
private fun evaluateArguments(callSite: IrFunctionAccessExpression, callee: IrFunction): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
private fun evaluateArguments(functionReference: IrFunctionReference): List<IrStatement> {
val arguments = functionReference.getArgumentsWithIr().map { ParameterToArgument(it.first, it.second) }
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val referenced = functionReference.symbol.owner
arguments.forEach {
val newArgument = if (it.isImmutableVariableLoad) {
it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
} else {
val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.symbol.owner.name.toString(),
isMutable = false)
evaluationStatements.add(newVariable)
IrGetValueWithoutLocation(newVariable.symbol)
}
when (it.parameter) {
referenced.dispatchReceiverParameter -> functionReference.dispatchReceiver = newArgument
referenced.extensionReceiverParameter -> functionReference.extensionReceiver = newArgument
else -> functionReference.putValueArgument(it.parameter.index, newArgument)
}
}
return evaluationStatements
}
private fun evaluateArguments(callSite: IrFunctionAccessExpression, callee: IrFunction): List<IrStatement> {
val arguments = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
arguments.forEach {
/*
* We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
@@ -400,6 +439,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
*/
if (it.isInlinableLambdaArgument) {
substituteMap[it.parameter] = it.argumentExpression
(it.argumentExpression as? IrFunctionReference)?.let { evaluationStatements += evaluateArguments(it) }
return@forEach
}
@@ -414,9 +454,28 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
isMutable = false)
evaluationStatements.add(newVariable)
substituteMap[it.parameter] = newVariable
substituteMap[it.parameter] = IrGetValueWithoutLocation(newVariable.symbol)
}
return evaluationStatements
}
}
private class IrGetValueWithoutLocation(
symbol: IrValueSymbol,
override val origin: IrStatementOrigin? = null
) : IrTerminalDeclarationReferenceBase<IrValueSymbol, ValueDescriptor>(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
symbol.owner.type,
symbol, symbol.descriptor
), IrGetValue {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D) =
visitor.visitGetValue(this, data)
override fun copy(): IrGetValue {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
fun withLocation(startOffset: Int, endOffset: Int) =
IrGetValueImpl(startOffset, endOffset, type, symbol, origin)
}
}
@@ -132,7 +132,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
return expression
}
})
initializer.patchDeclarationParents(initializeFun)
initializer.setDeclarationsParent(initializeFun)
}
return initializeFun.symbol
@@ -166,7 +166,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
if (initializeMethodSymbol == null) {
assert(declaration.isPrimary)
for (initializer in initializers)
initializer.patchDeclarationParents(declaration)
initializer.setDeclarationsParent(declaration)
initializers
} else {
val startOffset = it.startOffset
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.cgen.*
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions
@@ -26,12 +26,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -43,15 +38,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
internal abstract class BaseInteropIrTransformer(private val context: Context) : IrBuildingTransformer(context) {
@@ -159,20 +154,20 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
irClass.declarations.toList().mapNotNull {
when {
it is IrSimpleFunction && it.descriptor.annotations.hasAnnotation(interop.objCAction) ->
it is IrSimpleFunction && it.annotations.hasAnnotation(interop.objCAction.fqNameSafe) ->
generateActionImp(it)
it is IrProperty && it.descriptor.annotations.hasAnnotation(interop.objCOutlet) ->
it is IrProperty && it.annotations.hasAnnotation(interop.objCOutlet.fqNameSafe) ->
generateOutletSetterImp(it)
it is IrConstructor && it.descriptor.annotations.hasAnnotation(interop.objCOverrideInit) ->
it is IrConstructor && it.annotations.hasAnnotation(interop.objCOverrideInit.fqNameSafe) ->
generateOverrideInit(irClass, it)
else -> null
}
}.let { irClass.addChildren(it) }
if (irClass.descriptor.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
if (irClass.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
topLevelInitializers.add(irBuilder.getObjCClass(irClass.symbol))
}
@@ -224,51 +219,26 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
// Generate `override fun init...(...) = this.initBy(...)`:
val resultDescriptor = SimpleFunctionDescriptorImpl.create(
irClass.descriptor,
Annotations.EMPTY,
initMethod.name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
val valueParameters = constructor.valueParameters.map {
val descriptor = ValueParameterDescriptorImpl(
resultDescriptor,
null,
it.index,
Annotations.EMPTY,
it.name,
it.descriptor.type,
false,
false,
false,
it.varargElementType?.toKotlinType(),
SourceElement.NO_SOURCE
)
it.copy(descriptor)
}
resultDescriptor.initialize(
null,
irClass.descriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
valueParameters.map { it.descriptor as ValueParameterDescriptor },
irClass.descriptor.defaultType,
Modality.OPEN,
Visibilities.PUBLIC
)
val resultDescriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
constructor.startOffset, constructor.endOffset, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
resultDescriptor,
irClass.defaultType
constructor.startOffset, constructor.endOffset,
OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
IrSimpleFunctionSymbolImpl(resultDescriptor),
initMethod.name,
Visibilities.PUBLIC,
Modality.OPEN,
irClass.defaultType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).also { result ->
resultDescriptor.bind(result)
result.parent = irClass
result.createDispatchReceiverParameter()
result.valueParameters += valueParameters
constructor.valueParameters.mapTo(result.valueParameters) { it.copyTo(result) }
result.overriddenSymbols.add(initMethod.symbol)
result.descriptor.overriddenDescriptors = listOf(initMethod.descriptor)
result.body = context.createIrBuilder(result.symbol).irBlockBody(result) {
+irReturn(
@@ -390,54 +360,40 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
}
}
val newDescriptor = SimpleFunctionDescriptorImpl.create(
function.descriptor.containingDeclaration,
Annotations.EMPTY,
("imp:" + selector).synthesizedName,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
)
val valueParameters = parameterTypes.mapIndexed { index, it ->
ValueParameterDescriptorImpl(
newDescriptor,
null,
index,
Annotations.EMPTY,
Name.identifier("p$index"),
it.toKotlinType(),
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
val newFunction = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
("imp:$selector").synthesizedName,
Visibilities.PRIVATE,
Modality.FINAL,
returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
it.bind(this)
}
}
newDescriptor.initialize(
null, null,
emptyList(),
valueParameters,
function.descriptor.returnType,
Modality.FINAL,
Visibilities.PRIVATE
)
val newFunction = IrFunctionImpl(
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
newDescriptor,
function.returnType
).apply {
parameterTypes.mapIndexedTo(this.valueParameters) { index, it ->
parameterTypes.mapIndexedTo(newFunction.valueParameters) { index, type ->
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset,
endOffset,
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
descriptor.valueParameters[index],
it,
null
)
IrValueParameterSymbolImpl(it),
Name.identifier("p$index"),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
it.bind(this)
parent = newFunction
}
}
}
@@ -480,18 +436,6 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
}
}
private fun createObjCMethodImpAnnotations(selector: String, encoding: String): Annotations {
val annotation = AnnotationDescriptorImpl(
context.interopBuiltIns.objCMethodImp.defaultType,
mapOf("selector" to selector, "encoding" to encoding)
.mapKeys { Name.identifier(it.key) }
.mapValues { StringValue(it.value) },
SourceElement.NO_SOURCE
)
return Annotations.create(listOf(annotation))
}
private fun checkKotlinObjCClass(irClass: IrClass) {
val kind = irClass.descriptor.kind
if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT) {
@@ -561,7 +505,6 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
builder.at(expression)
val constructedClass = outerClasses.peek()!!
val constructedClassDescriptor = constructedClass.descriptor
if (!constructedClass.isObjCClass()) {
return expression
@@ -578,12 +521,13 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
}
}
val delegatingCallConstructingClass = expression.symbol.owner.constructedClass
if (!constructedClass.isExternalObjCClass() &&
(expression.symbol.owner.constructedClass).isExternalObjCClass()) {
delegatingCallConstructingClass.isExternalObjCClass()) {
// Calling super constructor from Kotlin Objective-C class.
assert(constructedClassDescriptor.getSuperClassNotAny() == expression.descriptor.constructedClass)
assert(constructedClass.getSuperClassNotAny() == delegatingCallConstructingClass)
val initMethod = expression.symbol.owner.getObjCInitMethod()!!
@@ -602,14 +546,14 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
val initCall = builder.genLoweredObjCMethodCall(
initMethodInfo,
superQualifier = expression.symbol.owner.constructedClass.symbol,
superQualifier = delegatingCallConstructingClass.symbol,
receiver = builder.getRawPtr(builder.irGet(constructedClass.thisReceiver!!)),
arguments = initMethod.valueParameters.map { expression.getValueArgument(it.index) },
call = expression,
method = initMethod
)
val superConstructor = expression.symbol.owner.constructedClass
val superConstructor = delegatingCallConstructingClass
.constructors.single { it.valueParameters.size == 0 }.symbol
return builder.irBlock(expression) {
@@ -897,7 +841,7 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
}
}
if (function.descriptor.annotations.hasAnnotation(RuntimeNames.cCall)) {
if (function.annotations.hasAnnotation(RuntimeNames.cCall)) {
context.llvmImports.add(function.descriptor.llvmSymbolOrigin)
return generateWithStubs { generateCCall(expression, builder, isInvoke = false) }
}
@@ -1186,5 +1130,3 @@ private fun IrBuilder.irFloat(value: Float) =
private fun IrBuilder.irDouble(value: Double) =
IrConstImpl.double(startOffset, endOffset, context.irBuiltIns.doubleType, value)
private fun Annotations.hasAnnotation(descriptor: ClassDescriptor) = this.hasAnnotation(descriptor.fqNameSafe)
@@ -100,9 +100,9 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
// Basic Multilingual Plane, so we could just append data "as is".
builder.append(value.toChar())
}
expression.putValueArgument(0, IrConstImpl<String>(
expression.putValueArgument(0, IrConstImpl(
expression.startOffset, expression.endOffset,
context.ir.symbols.immutableBlob.typeWithoutArguments,
context.irBuiltIns.stringType,
IrConstKind.String, builder.toString()))
} else if (expression.symbol.owner.isTypeOfIntrinsic()) {
val type = expression.getTypeArgument(0)
@@ -463,7 +463,7 @@ internal class TestProcessor (val context: Context) {
}
}
private val IrClass.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME)
private val IrClass.ignored: Boolean get() = annotations.hasAnnotation(IGNORE_FQ_NAME)
/**
* Builds a test suite class representing a test class (any class in the original IrFile with method(s)
@@ -118,15 +118,26 @@ internal fun ObjCExportMapper.getDeprecation(descriptor: DeclarationDescriptor):
return null
}
private tailrec fun ObjCExportMapper.isHiddenByDeprecation(descriptor: ClassDescriptor): Boolean {
private fun ObjCExportMapper.isHiddenByDeprecation(descriptor: ClassDescriptor): Boolean {
if (deprecationResolver == null) return false
if (deprecationResolver.isDeprecatedHidden(descriptor)) return true
val superClass = descriptor.getSuperClassNotAny() ?: return false
// Note: ObjCExport requires super class of exposed class to be exposed.
// So hide a class if its super class is hidden:
return isHiddenByDeprecation(superClass)
val superClass = descriptor.getSuperClassNotAny()
if (superClass != null && isHiddenByDeprecation(superClass)) {
return true
}
// Note: ObjCExport requires enclosing class of exposed class to be exposed.
// Also in Kotlin hidden class members (including other classes) aren't directly accessible.
// So hide a class if its enclosing class is hidden:
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor && isHiddenByDeprecation(containingDeclaration)) {
return true
}
return false
}
// Note: the logic is partially duplicated in ObjCExportLazyImpl.translateClasses.
@@ -12,16 +12,14 @@ import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.functionName
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.symbolName
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isNothing
@@ -601,15 +599,15 @@ internal object DataFlowIR {
}
val symbol = when {
it.isExternal || (it.symbol in context.irBuiltIns.irBuiltInsSymbols) -> {
val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES)
val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO)
val escapesAnnotation = it.annotations.findAnnotation(FQ_NAME_ESCAPES)
val pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO)
@Suppress("UNCHECKED_CAST")
val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue<Int>)?.value
val escapesBitMask = (escapesAnnotation?.getValueArgument(0) as? IrConst<Int>)?.value
@Suppress("UNCHECKED_CAST")
val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue<List<IntValue>>)?.value
val pointsToBitMask = (pointsToAnnotation?.getValueArgument(0) as? IrVararg)?.elements?.map { (it as IrConst<Int>).value }
FunctionSymbol.External(name.localHash.value, attributes, it, takeName { name }).apply {
escapes = escapesBitMask
pointsTo = pointsToBitMask?.let { it.map { it.value }.toIntArray() }
pointsTo = pointsToBitMask?.let { it.toIntArray() }
}
}
@@ -646,7 +644,8 @@ internal object DataFlowIR {
}
private val IrFunction.isSpecial get() =
name.asString().let { it.startsWith("<bridge-") || it.endsWith("-box>") || it.endsWith("-unbox>") }
origin == DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION
|| origin is DECLARATION_ORIGIN_BRIDGE_METHOD
private fun mapPropertyInitializer(irField: IrField): FunctionSymbol {
functionMap[irField]?.let { return it }
@@ -1047,10 +1047,8 @@ internal object Devirtualization {
}
}
private val specialNames = listOf("-box>", "-unbox>")
// TODO: do it more reliably.
private fun IrExpression.isBoxOrUnboxCall() = (this is IrCall && symbol.owner.name.asString().let { name -> specialNames.any { name.endsWith(it) } })
private fun IrExpression.isBoxOrUnboxCall() =
(this is IrCall && symbol.owner.origin == DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION)
private fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.hasAnnotation
class KonanIrModuleSerializer(
logger: LoggingContext,
@@ -15,9 +16,9 @@ class KonanIrModuleSerializer(
) : IrModuleSerializer(logger, declarationTable, KonanMangler, bodiesOnlyForInlines) {
override fun backendSpecificExplicitRoot(declaration: IrFunction) =
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)
declaration.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)
override fun backendSpecificExplicitRoot(declaration: IrClass) =
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
declaration.annotations.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
}
@@ -20,8 +20,10 @@ import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker
import org.jetbrains.kotlin.backend.common.serialization.UniqId
import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -53,6 +55,16 @@ class KonanIrLinker(
override val ModuleDescriptor.irHeader get() = this.konanLibrary!!.irHeader
override fun List<IrFile>.handleClashes(uniqIdKey: UniqIdKey): IrFile {
if (size == 1)
return this[0]
assert(size != 0)
error("UniqId clash: ${uniqIdKey.uniqId.index}. Found in the " +
"[${this.joinToString { it.packageFragmentDescriptor.containingDeclaration.userName }}]")
}
private val ModuleDescriptor.userName get() = konanLibrary?.libraryFile?.absolutePath ?: name.asString()
val modules: Map<String, IrModuleFragment> get() = mutableMapOf<String, IrModuleFragment>().apply {
deserializersForModules.forEach {
this.put(it.key.konanLibrary!!.libraryName, it.value.module)
@@ -7,22 +7,20 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.KonanFqNames
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.allParameters
import org.jetbrains.kotlin.backend.konan.ir.buildSimpleAnnotation
import org.jetbrains.kotlin.backend.konan.ir.containsNull
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
@@ -36,8 +34,6 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -65,13 +61,7 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC
private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val descriptor = WrappedFieldDescriptor(
if (threadLocal)
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
else
Annotations.EMPTY
)
val descriptor = WrappedFieldDescriptor()
val irField = IrFieldImpl(
expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED,
@@ -85,7 +75,12 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: Ko
).apply {
descriptor.bind(this)
initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
expression.setDeclarationsParent(this)
if (threadLocal)
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.threadLocal.owner)
initializer = IrExpressionBodyImpl(startOffset, endOffset, expression)
}
addChild(irField)
}
@@ -128,39 +123,6 @@ object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent
}
}
fun IrModuleFragment.checkDeclarationParents() {
this.accept(CheckDeclarationParentsVisitor, null)
}
object CheckDeclarationParentsVisitor : IrElementVisitor<Unit, IrDeclarationParent?> {
override fun visitElement(element: IrElement, data: IrDeclarationParent?) {
element.acceptChildren(this, element as? IrDeclarationParent ?: data)
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) {
if (declaration !is IrVariable && declaration !is IrValueParameter && declaration !is IrTypeParameter) {
checkParent(declaration, data)
} else {
// Don't check IrVariable parent.
}
super.visitDeclaration(declaration, data)
}
private fun checkParent(declaration: IrDeclaration, expectedParent: IrDeclarationParent?) {
val parent = try {
declaration.parent
} catch (e: Throwable) {
error("$declaration for ${declaration.descriptor} has no parent")
}
if (parent != expectedParent) {
error("$declaration for ${declaration.descriptor} has unexpected parent $parent")
}
}
}
tailrec fun IrDeclaration.getContainingFile(): IrFile? {
val parent = this.parent
@@ -322,6 +284,7 @@ fun IrBuilderWithScope.irCatch(type: IrType) =
false
).apply {
descriptor.bind(this)
parent = this@irCatch.parent
}
}
)
+13 -1
View File
@@ -2357,9 +2357,16 @@ standaloneTest("args0") {
standaloneTest("devirtualization_lateinitInterface") {
goldValue = "42\n"
flags = ["-opt"]
source = "codegen/devirtualization/lateinitInterface.kt"
}
standaloneTest("devirtualization_getter_looking_as_box_function") {
goldValue = "box\n"
flags = ["-opt"]
source = "codegen/devirtualization/getter_looking_as_box_function.kt"
}
standaloneTest("multiargs") {
arguments = ["AAA", "BB", "C"]
multiRuns = true
@@ -2867,6 +2874,11 @@ task inline_genericFunctionReference(type: KonanLocalTest) {
source = "codegen/inline/genericFunctionReference.kt"
}
task inline_correctOrderFunctionReference(type: KonanLocalTest) {
goldValue = "OK\n"
source = "codegen/inline/correctOrderFunctionReference.kt"
}
task classDeclarationInsideInline(type: KonanLocalTest) {
source = "codegen/inline/classDeclarationInsideInline.kt"
goldValue = "test1: 1.0\n1\ntest2\n"
@@ -3500,7 +3512,7 @@ if (isAppleTarget(project)) {
final String dir = "$testOutputFramework/$frameworkName"
final File lazyHeader = file("$dir/$target-lazy.h")
doFirst {
doLast {
final File expectedLazyHeader = file("framework/values/expectedLazy.h")
if (expectedLazyHeader.readLines() != lazyHeader.readLines()) {
@@ -0,0 +1,5 @@
class Foo(val box: String = "box")
fun main() {
println(Foo().box)
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package codegen.inline.correctOrderFunctionReference
import kotlin.test.*
class Foo(val a: String) {
fun test() = a
}
inline fun test(a: String, b: () -> String, c: () -> String, d: () -> String, e: String): String {
return a + b() + c() + d() + e
}
var effects = ""
fun create(a: String): Foo {
effects += a
return Foo(a)
}
fun create2(a: String, f: () -> String): Foo {
effects += a
return Foo(a)
}
fun box(): String {
val result = test(create("A").a, create("B")::a, create("C")::test, create2("E", create("D")::test)::test, create("F").a)
if (effects != "ABCDEF") return "fail 1: $effects"
return if (result == "ABCEF") "OK" else "fail 2: $result"
}
@Test fun runTest() {
println(box())
}
@@ -658,6 +658,19 @@ __attribute__((swift_name("TestDeprecation")))
- (void)openWarning __attribute__((swift_name("openWarning()"))) __attribute__((deprecated("warning")));
- (void)normal __attribute__((swift_name("normal()")));
- (int32_t)openNormal __attribute__((swift_name("openNormal()")));
- (void)testHiddenNested:(id)hiddenNested __attribute__((swift_name("test(hiddenNested:)")));
- (void)testHiddenNestedNested:(id)hiddenNestedNested __attribute__((swift_name("test(hiddenNestedNested:)")));
- (void)testHiddenNestedInner:(id)hiddenNestedInner __attribute__((swift_name("test(hiddenNestedInner:)")));
- (void)testHiddenInner:(id)hiddenInner __attribute__((swift_name("test(hiddenInner:)")));
- (void)testHiddenInnerInner:(id)hiddenInnerInner __attribute__((swift_name("test(hiddenInnerInner:)")));
- (void)testTopLevelHidden:(id)topLevelHidden __attribute__((swift_name("test(topLevelHidden:)")));
- (void)testTopLevelHiddenNested:(id)topLevelHiddenNested __attribute__((swift_name("test(topLevelHiddenNested:)")));
- (void)testTopLevelHiddenNestedNested:(id)topLevelHiddenNestedNested __attribute__((swift_name("test(topLevelHiddenNestedNested:)")));
- (void)testTopLevelHiddenNestedInner:(id)topLevelHiddenNestedInner __attribute__((swift_name("test(topLevelHiddenNestedInner:)")));
- (void)testTopLevelHiddenInner:(id)topLevelHiddenInner __attribute__((swift_name("test(topLevelHiddenInner:)")));
- (void)testTopLevelHiddenInnerInner:(id)topLevelHiddenInnerInner __attribute__((swift_name("test(topLevelHiddenInnerInner:)")));
- (void)testExtendingHiddenNested:(id)extendingHiddenNested __attribute__((swift_name("test(extendingHiddenNested:)")));
- (void)testExtendingNestedInHidden:(id)extendingNestedInHidden __attribute__((swift_name("test(extendingNestedInHidden:)")));
@property (readonly) id _Nullable errorVal __attribute__((swift_name("errorVal"))) __attribute__((unavailable("error")));
@property id _Nullable errorVar __attribute__((swift_name("errorVar"))) __attribute__((unavailable("error")));
@property (readonly) id _Nullable openErrorVal __attribute__((swift_name("openErrorVal"))) __attribute__((unavailable("error")));
@@ -681,6 +694,11 @@ __attribute__((swift_name("TestDeprecation.ExtendingHidden")))
@interface ValuesTestDeprecationExtendingHidden : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.ExtendingHiddenNested")))
@interface ValuesTestDeprecationExtendingHiddenNested : NSObject
@end;
__attribute__((swift_name("TestDeprecationHiddenInterface")))
@protocol ValuesTestDeprecationHiddenInterface
@required
@@ -698,6 +716,35 @@ __attribute__((swift_name("TestDeprecation.Hidden")))
@interface ValuesTestDeprecationHidden : NSObject
@end;
__attribute__((swift_name("TestDeprecation.HiddenNested")))
@interface ValuesTestDeprecationHiddenNested : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.HiddenNestedNested")))
@interface ValuesTestDeprecationHiddenNestedNested : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.HiddenNestedInner")))
@interface ValuesTestDeprecationHiddenNestedInner : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.HiddenInner")))
@interface ValuesTestDeprecationHiddenInner : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.HiddenInnerInner")))
@interface ValuesTestDeprecationHiddenInnerInner : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.ExtendingNestedInHidden")))
@interface ValuesTestDeprecationExtendingNestedInHidden : NSObject
@end;
__attribute__((swift_name("TestDeprecation.OpenError")))
@interface ValuesTestDeprecationOpenError : ValuesTestDeprecation
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable("error")));
@@ -859,6 +906,36 @@ __attribute__((swift_name("TestDeprecation.NormalOverride")))
@property id _Nullable openNormalVar __attribute__((swift_name("openNormalVar")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden")))
@interface ValuesTopLevelHidden : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden.Nested")))
@interface ValuesTopLevelHiddenNested : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden.NestedNested")))
@interface ValuesTopLevelHiddenNestedNested : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden.NestedInner")))
@interface ValuesTopLevelHiddenNestedInner : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden.Inner")))
@interface ValuesTopLevelHiddenInner : NSObject
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TopLevelHidden.InnerInner")))
@interface ValuesTopLevelHiddenInnerInner : NSObject
@end;
@interface ValuesEnumeration (ValuesKt)
- (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()")));
@end;
@@ -495,7 +495,9 @@ class TestInvalidIdentifiers {
@Suppress("UNUSED_PARAMETER")
open class TestDeprecation() {
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) open class OpenHidden : TestDeprecation()
@Suppress("DEPRECATION_ERROR") class ExtendingHidden : OpenHidden()
@Suppress("DEPRECATION_ERROR") class ExtendingHidden : OpenHidden() {
class Nested
}
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) interface HiddenInterface {
fun effectivelyHidden(): Any
@@ -508,7 +510,19 @@ open class TestDeprecation() {
@Suppress("DEPRECATION_ERROR")
fun callEffectivelyHidden(obj: Any): Int = (obj as HiddenInterface).effectivelyHidden() as Int
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) class Hidden : TestDeprecation()
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) class Hidden : TestDeprecation() {
open class Nested {
class Nested
inner class Inner
}
inner class Inner {
inner class Inner
}
}
@Suppress("DEPRECATION_ERROR") class ExtendingNestedInHidden : Hidden.Nested()
@Suppress("DEPRECATION_ERROR") fun getHidden() = Hidden()
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) constructor(hidden: Byte) : this()
@@ -648,6 +662,34 @@ open class TestDeprecation() {
override val openNormalVal: Any? = null
override var openNormalVar: Any? = null
}
@Suppress("DEPRECATION_ERROR") fun test(hiddenNested: Hidden.Nested) {}
@Suppress("DEPRECATION_ERROR") fun test(hiddenNestedNested: Hidden.Nested.Nested) {}
@Suppress("DEPRECATION_ERROR") fun test(hiddenNestedInner: Hidden.Nested.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(hiddenInner: Hidden.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(hiddenInnerInner: Hidden.Inner.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHidden: TopLevelHidden) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHiddenNested: TopLevelHidden.Nested) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHiddenNestedNested: TopLevelHidden.Nested.Nested) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHiddenNestedInner: TopLevelHidden.Nested.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHiddenInner: TopLevelHidden.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(topLevelHiddenInnerInner: TopLevelHidden.Inner.Inner) {}
@Suppress("DEPRECATION_ERROR") fun test(extendingHiddenNested: ExtendingHidden.Nested) {}
@Suppress("DEPRECATION_ERROR") fun test(extendingNestedInHidden: ExtendingNestedInHidden) {}
}
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) class TopLevelHidden {
class Nested {
class Nested
inner class Inner
}
inner class Inner {
inner class Inner
}
}
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) fun hidden() {}
+5 -2
View File
@@ -70,9 +70,12 @@ fun run() {
// hashCode (directly):
if (foo.hashCode() == foo.hash().let { it.toInt() xor (it shr 32).toInt() }) {
// toString (virtually):
println(map.keys.map { it.toString() }.min() == foo.description())
if (Platform.memoryModel == MemoryModel.STRICT)
println(map.keys.map { it.toString() }.min() == foo.description())
else
// TODO: hack until proper cycle collection in maps.
println(true)
}
println(globalString)
autoreleasepool {
globalString = "Another global string"
@@ -9,6 +9,8 @@ import kotlin.test.*
import kotlin.native.ref.*
@Test fun runTest() {
// TODO: make it work in relaxed model as well.
if (Platform.memoryModel == MemoryModel.RELAXED) return
val weakRefToTrashCycle = createLoop()
kotlin.native.internal.GC.collect()
assertNull(weakRefToTrashCycle.get())
@@ -9,7 +9,7 @@ import kotlin.test.*
import kotlin.native.concurrent.*
object Immutable {
object AnObject {
var x = 1
}
@@ -19,11 +19,17 @@ object Mutable {
}
@Test fun runTest() {
assertEquals(1, Immutable.x)
assertFailsWith<InvalidMutabilityException> {
Immutable.x++
assertEquals(1, AnObject.x)
if (Platform.memoryModel == MemoryModel.STRICT) {
assertFailsWith<InvalidMutabilityException> {
AnObject.x++
}
assertEquals(1, AnObject.x)
} else {
AnObject.x++
assertEquals(2, AnObject.x)
}
assertEquals(1, Immutable.x)
Mutable.x++
assertEquals(3, Mutable.x)
println("OK")
@@ -45,6 +45,8 @@ fun testSingleData(workers: Array<Worker>) {
}
fun testFrozenLazy(workers: Array<Worker>) {
// To make sure it is always frozen, and we don't race in relaxed mode.
Immutable3.freeze()
val set = mutableSetOf<Int>()
for (attempt in 1 .. 3) {
val futures = Array(workers.size, { workerIndex ->
@@ -45,7 +45,7 @@ val topSharedData = Data(43)
false
}
}).consume {
result -> assertEquals(false, result)
result -> assertEquals(Platform.memoryModel == MemoryModel.RELAXED, result)
}
worker.execute(TransferMode.SAFE, { -> }, {
@@ -65,7 +65,7 @@ val topSharedData = Data(43)
false
}
}).consume {
result -> assertEquals(false, result)
result -> assertEquals(Platform.memoryModel == MemoryModel.RELAXED, result)
}
worker.execute(TransferMode.SAFE, { -> }, {
@@ -163,4 +163,22 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
semaphore.increment()
future.result
worker.requestTermination().result
}
val atomicRef2 = AtomicReference<Any?>(Any().freeze())
@Test fun runTest6() {
semaphore.value = 0
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, { null }) {
val value = atomicRef2.compareAndSwap(null, null)
semaphore.increment()
while (semaphore.value != 2) {}
assertEquals(true, value.toString() != "")
}
while (semaphore.value != 1) {}
atomicRef2.value = null
kotlin.native.internal.GC.collect()
semaphore.increment()
future.result
worker.requestTermination().result
}
@@ -28,7 +28,7 @@ fun main(args: Array<String>) {
} catch (e: IllegalStateException) {
null
}
if (future != null)
if (future != null && Platform.memoryModel == MemoryModel.STRICT)
println("Fail 1")
if (dataParam.int != 17) println("Fail 2")
worker.requestTermination().result
@@ -14,7 +14,6 @@ import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
import java.io.File
import java.io.ByteArrayOutputStream
@@ -151,10 +150,16 @@ open class KonanGTest : KonanTest() {
executor = project.executor::execute,
executable = executable,
args = arguments
).let {
parse(it.stdOut)
it.print()
check(it.exitCode == 0) { "Test $executable exited with ${it.exitCode}" }
).run {
parse(stdOut)
println("""
|stdout:
|$stdOut
|stderr:
|$stdErr
|exit code: $exitCode
""".trimMargin())
check(exitCode == 0) { "Test $executable exited with $exitCode" }
}
private fun parse(output: String) = statistics.apply {
@@ -238,7 +243,11 @@ open class KonanLocalTest : KonanTest() {
// TODO: as for now it captures output only in the driver task.
// It should capture output from the build task using Gradle's LoggerManager and LoggerOutput
val compilationLog = project.file("$executable.compilation.log").readText()
output.stdOut = compilationLog + output.stdOut
// TODO: ugly hack to fix irrelevant warnings.
val filteredCompilationLog = compilationLog.split('\n').filter {
it != "warning: relaxed memory model is not yet fully functional"
}.joinToString(separator = "\n")
output.stdOut = filteredCompilationLog + output.stdOut
}
output.check()
output.print()
@@ -15,6 +15,7 @@ import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.tasks.AbstractExecTask
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.jetbrains.report.*
import org.jetbrains.report.json.*
import java.nio.file.Paths
@@ -151,12 +152,10 @@ fun sendUploadRequest(url: String, fileName: String, username: String? = null, p
fun createRunTask(
subproject: Project,
name: String,
runTask: AbstractExecTask<*>,
configureClosure: Closure<Any>? = null
linkTask: KotlinNativeLink,
outputFileName: String
): Task {
val task = subproject.tasks.create(name, RunKotlinNativeTask::class.java, runTask)
task.configure(configureClosure ?: task.emptyConfigureClosure())
return task
return subproject.tasks.create(name, RunKotlinNativeTask::class.java, linkTask, outputFileName)
}
@JvmOverloads
@@ -5,17 +5,17 @@
package org.jetbrains.kotlin
import groovy.lang.Closure
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.tasks.AbstractExecTask
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.Input
import java.io.ByteArrayOutputStream
import java.io.File
import javax.inject.Inject
open class RunKotlinNativeTask @Inject constructor(
private val runTask: AbstractExecTask<*>
open class RunKotlinNativeTask @Inject constructor(private val linkTask: KotlinNativeLink,
private val outputFileName: String
) : DefaultTask() {
@Input
var buildType = "RELEASE"
@@ -26,30 +26,51 @@ open class RunKotlinNativeTask @Inject constructor(
@Option(option = "filterRegex", description = "Benchmarks to run, described by regular expressions (comma-separated)")
var filterRegex: String = ""
override fun configure(configureClosure: Closure<Any>): Task {
val task = super.configure(configureClosure)
this.finalizedBy(runTask.name)
runTask.finalizedBy("konanJsonReport")
return task
private val argumentsList = mutableListOf<String>()
init {
this.dependsOn += linkTask.name
this.finalizedBy("konanJsonReport")
}
fun depends(taskName: String) {
this.dependsOn += taskName
}
@TaskAction
fun run() {
runTask.run {
val filterArgs = filter.splitCommaSeparatedOption("-f")
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
runTask.args(filterArgs)
runTask.args(filterRegexArgs)
}
fun args(vararg arguments: String) {
argumentsList.addAll(arguments.toList())
}
internal fun emptyConfigureClosure() = object : Closure<Any>(this) {
override fun call(): RunKotlinNativeTask {
return this@RunKotlinNativeTask
@TaskAction
fun run() {
var output = ByteArrayOutputStream()
project.exec {
it.executable = linkTask.binary.outputFile.absolutePath
it.args("list")
it.standardOutput = output
}
val benchmarks = output.toString().lines()
val filterArgs = filter.splitCommaSeparatedOption("-f")
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
val regexes = filterRegexArgs.map { it.toRegex() }
val benchmarksToRun = if (filterArgs.isNotEmpty() || regexes.isNotEmpty()) {
benchmarks.filter { benchmark -> benchmark in filterArgs || regexes.any { it.matches(benchmark) } }
} else benchmarks.filter { !it.isEmpty() }
val results = benchmarksToRun.map { benchmark ->
output = ByteArrayOutputStream()
project.exec {
it.executable = linkTask.binary.outputFile.absolutePath
it.args(argumentsList)
it.args("-f", benchmark)
it.standardOutput = output
}
output.toString().removePrefix("[").removeSuffix("]")
}
File(outputFileName).printWriter().use { out ->
out.println("[${results.joinToString(",")}]")
}
}
}
@@ -11,16 +11,13 @@ open class CustomWrapper : Wrapper() {
val mainWrapperVersion: String
@Input get() = mainWrapperTask.gradleVersion
val mainWrapperDistrType: DistributionType
@Input get() = mainWrapperTask.distributionType
val mainWrapperDistrUrl: String
@Input get() = mainWrapperTask.distributionUrl
val mainWrapperDistrSha256: String?
@Optional @Input get() = mainWrapperTask.distributionSha256Sum
}
open class WrappersExtension {
var projects = mutableListOf<Any>()
var distributionType = Wrapper.DistributionType.BIN
}
class GradleWrappers : Plugin<Project> {
@@ -38,16 +35,15 @@ class GradleWrappers : Plugin<Project> {
this.mainWrapperTask = mainWrapperTask
jarFile = it.resolve("gradle/wrapper/gradle-wrapper.jar")
scriptFile = it.resolve("gradlew")
distributionType = wrappers.distributionType
mainWrapperTask.dependsOn(this)
// Get these parameters from the main wrapper task to support
// command line options like --gradle-version or --distribution-type.
// command line options like --gradle-version.
// Gradle doesn't provide access to the values passed in command line
// at the configuration phase, so we have to get these values at execution phase.
// at the configuration phase, so we have to get these values at the execution phase.
doFirst {
gradleVersion = mainWrapperVersion
distributionType = mainWrapperDistrType
distributionUrl = mainWrapperDistrUrl
distributionSha256Sum = mainWrapperDistrSha256
}
}
@@ -134,17 +134,15 @@ open class BenchmarkingPlugin: Plugin<Project> {
linkerOpts.add("-L${mingwPath}/lib")
}
runTask!!.apply {
group = ""
enabled = false
}
// Specify settings configured by a user in the benchmark extension.
afterEvaluate {
linkerOpts.addAll(benchmark.linkerOpts)
runTask!!.args(
"-w", nativeWarmup,
"-r", attempts,
"-o", buildDir.resolve(nativeBenchResults).absolutePath,
"-p", "${benchmark.applicationName}::"
)
}
}
}
}
@@ -161,10 +159,18 @@ open class BenchmarkingPlugin: Plugin<Project> {
// Native run task.
val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget
val nativeExecutable = nativeTarget.binaries.getExecutable(NATIVE_EXECUTABLE_NAME, NativeBuildType.RELEASE)
val konanRun = createRunTask(this, "konanRun", nativeExecutable.runTask!!).apply {
val konanRun = createRunTask(this, "konanRun", nativeExecutable.linkTask,
buildDir.resolve(nativeBenchResults).absolutePath).apply {
group = BENCHMARKING_GROUP
description = "Runs the benchmark for Kotlin/Native."
}
afterEvaluate {
(konanRun as RunKotlinNativeTask).args(
"-w", nativeWarmup.toString(),
"-r", attempts.toString(),
"-p", "${benchmark.applicationName}::"
)
}
// JVM run task.
val jvmRun = tasks.create("jvmRun", RunJvmTask::class.java) { task ->
+2 -15
View File
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.konan.*
// Run './gradlew wrapper --gradle-version <version>' to update all the wrappers.
apply plugin: org.jetbrains.kotlin.GradleWrappers
wrappers.projects = ['samples', 'samples/calculator', 'samples/androidNativeActivity', 'samples/curl']
wrappers.projects = ['samples', 'samples/calculator', 'samples/androidNativeActivity', 'samples/cocoapods/kotlin-library']
wrapper.distributionType = Wrapper.DistributionType.ALL
defaultTasks 'clean', 'dist'
@@ -67,12 +67,7 @@ ext {
kotlinUtilKlibModule="org.jetbrains.kotlin:kotlin-util-klib:${kotlinVersion}"
konanVersionFull = KonanVersionGeneratedKt.getCurrentKonanVersion()
if (konanVersionFull.meta == MetaVersion.RELEASE) {
gradlePluginVersion = kotlinVersion
} else {
gradlePluginVersion = "$kotlinVersion-native-$konanVersionFull"
}
gradlePluginVersion = konanVersionFull
}
allprojects {
@@ -192,14 +187,6 @@ task gradlePluginCheck {
dependsOn gradle.includedBuild('kotlin-native-gradle-plugin').task(':check')
}
task gradlePluginUpload {
dependsOn gradle.includedBuild('kotlin-native-gradle-plugin').task(':bintrayUpload')
// Publish releases to the plugin-portal too.
if (konanVersionFull.meta == MetaVersion.RELEASE) {
dependsOn gradle.includedBuild('kotlin-native-gradle-plugin').task(':publishPlugins')
}
}
task dist_compiler(dependsOn: "distCompiler")
task dist_runtime(dependsOn: "distRuntime")
task cross_dist(dependsOn: "crossDist")
+1 -1
View File
@@ -59,7 +59,7 @@ protobuf {
compileJava {
dependsOn('renamePackage')
doFirst {
delete 'build/generated'
delete 'build/generated/source/proto/main/java'
}
}
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+17 -1
View File
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
Vendored
+17 -1
View File
@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
+2 -2
View File
@@ -138,9 +138,9 @@ task teamCityStat(type:Exec) {
}
}
task сinterop {
task cinterop {
dependsOn 'clean'
dependsOn 'сinterop:konanRun'
dependsOn 'cinterop:konanRun'
}
task framework {
+14 -17
View File
@@ -21,29 +21,26 @@ import org.jetbrains.structsBenchmarks.*
import org.jetbrains.typesBenchmarks.*
import org.jetbrains.kliopt.*
class CinteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String) : Launcher(numWarmIterations, numberOfAttempts, prefix) {
val stringBenchmark = StringBenchmark()
val intMatrixBenchmark = IntMatrixBenchmark()
val intBenchmark = IntBenchmark()
val boxedIntBenchmark = BoxedIntBenchmark()
class CinteropLauncher : Launcher() {
override val benchmarks = BenchmarksCollection(
mutableMapOf(
"macros" to ::macrosBenchmark,
"struct" to ::structBenchmark,
"union" to ::unionBenchmark,
"enum" to ::enumBenchmark,
"stringToC" to stringBenchmark::stringToCBenchmark,
"stringToKotlin" to stringBenchmark::stringToKotlinBenchmark,
"intMatrix" to intMatrixBenchmark::intMatrixBenchmark,
"int" to intBenchmark::intBenchmark,
"boxedInt" to boxedIntBenchmark::boxedIntBenchmark
"macros" to BenchmarkEntry(::macrosBenchmark),
"struct" to BenchmarkEntry(::structBenchmark),
"union" to BenchmarkEntry(::unionBenchmark),
"enum" to BenchmarkEntry(::enumBenchmark),
"stringToC" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringToCBenchmark() }),
"stringToKotlin" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringToKotlinBenchmark() }),
"intMatrix" to BenchmarkEntryWithInit.create(::IntMatrixBenchmark, { intMatrixBenchmark() }),
"int" to BenchmarkEntryWithInit.create(::IntBenchmark, { intBenchmark() }),
"boxedInt" to BenchmarkEntryWithInit.create(::BoxedIntBenchmark, { boxedIntBenchmark() })
)
)
}
fun main(args: Array<String>) {
val launcher = CinteropLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
CinteropLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!)
.launch(parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
})
launcher.launch(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!,
parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
}, benchmarksListAction = launcher::benchmarksListAction)
}
@@ -110,9 +110,9 @@ actual class ComplexNumbersBenchmark actual constructor() {
for (j in 0 until length/2) {
val first = sequence[i + j]
val second = sequence[i + j + length/2].mul(value)
sequence[i + j] = (first.add(second) as Complex)!!
sequence[i + j + length/2] = (first.sub(second) as Complex)!!
value = value.mul(base)!!
sequence[i + j] = first.add(second) as Complex
sequence[i + j + length/2] = first.sub(second) as Complex
value = value.mul(base)
}
}
length = length shl 1
@@ -128,7 +128,7 @@ actual class ComplexNumbersBenchmark actual constructor() {
val sequence = fftRoutine(true)
sequence.forEachIndexed { index, number ->
sequence[index] = number.div(Complex(sequence.size.toDouble(), 0.0)) ?: Complex(0.0, 0.0)
sequence[index] = number.div(Complex(sequence.size.toDouble(), 0.0))
}
}
}
+14 -13
View File
@@ -8,25 +8,26 @@ import org.jetbrains.benchmarksLauncher.*
import org.jetbrains.complexNumbers.*
import org.jetbrains.kliopt.*
class ObjCInteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) {
val complexNumbersBecnhmark = ComplexNumbersBenchmark()
class ObjCInteropLauncher: Launcher() {
override val benchmarks = BenchmarksCollection(
mutableMapOf(
"generateNumbersSequence" to complexNumbersBecnhmark::generateNumbersSequence,
"sumComplex" to complexNumbersBecnhmark::sumComplex,
"subComplex" to complexNumbersBecnhmark::subComplex,
"classInheritance" to complexNumbersBecnhmark::classInheritance,
"categoryMethods" to complexNumbersBecnhmark::categoryMethods,
"stringToObjC" to complexNumbersBecnhmark::stringToObjC,
"stringFromObjC" to complexNumbersBecnhmark::stringFromObjC,
"fft" to complexNumbersBecnhmark::fft,
"invertFft" to complexNumbersBecnhmark::invertFft
"generateNumbersSequence" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { generateNumbersSequence() }),
"sumComplex" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { sumComplex() }),
"subComplex" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { subComplex() }),
"classInheritance" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { classInheritance() }),
"categoryMethods" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { categoryMethods() }),
"stringToObjC" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { stringToObjC() }),
"stringFromObjC" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { stringFromObjC() }),
"fft" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { fft() }),
"invertFft" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { invertFft() })
)
)
}
fun main(args: Array<String>) {
val launcher = ObjCInteropLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
ObjCInteropLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!).launch(parser.getAll<String>("filter"))
})
launcher.launch(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!,
parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
}, benchmarksListAction = launcher::benchmarksListAction)
}
+184 -210
View File
@@ -20,223 +20,197 @@ import octoTest
import org.jetbrains.benchmarksLauncher.*
import org.jetbrains.kliopt.*
class RingLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String) : Launcher(numWarmIterations, numberOfAttempts, prefix) {
val abstractMethodBenchmark = AbstractMethodBenchmark()
val classArrayBenchmark = ClassArrayBenchmark()
val classBaselineBenchmark = ClassBaselineBenchmark()
val classListBenchmark = ClassListBenchmark()
val classStreamBenchmark = ClassStreamBenchmark()
val companionObjectBenchmark = CompanionObjectBenchmark()
val defaultArgumentBenchmark = DefaultArgumentBenchmark()
val elvisBenchmark = ElvisBenchmark()
val eulerBenchmark = EulerBenchmark()
val fibonacciBenchmark = FibonacciBenchmark()
val forLoopsBenchmark = ForLoopsBenchmark()
val inlineBenchmark = InlineBenchmark()
val intArrayBenchmark = IntArrayBenchmark()
val intBaselineBenchmark = IntBaselineBenchmark()
val intListBenchmark = IntListBenchmark()
val intStreamBenchmark = IntStreamBenchmark()
val lambdaBenchmark = LambdaBenchmark()
val loopBenchmark = LoopBenchmark()
val matrixMapBenchmark = MatrixMapBenchmark()
val parameterNotNullAssertionBenchmark = ParameterNotNullAssertionBenchmark()
val primeListBenchmark = PrimeListBenchmark()
val stringBenchmark = StringBenchmark()
val switchBenchmark = SwitchBenchmark()
val withIndiciesBenchmark = WithIndiciesBenchmark()
val callsBenchmark = CallsBenchmark()
val coordinatesSolverBenchmark = CoordinatesSolverBenchmark()
val graphSolverBenchmark = GraphSolverBenchmark()
class RingLauncher : Launcher() {
override val benchmarks = BenchmarksCollection(
mutableMapOf(
"AbstractMethod.sortStrings" to abstractMethodBenchmark::sortStrings,
"AbstractMethod.sortStringsWithComparator" to abstractMethodBenchmark::sortStringsWithComparator,
"ClassArray.copy" to classArrayBenchmark::copy,
"ClassArray.copyManual" to classArrayBenchmark::copyManual,
"ClassArray.filterAndCount" to classArrayBenchmark::filterAndCount,
"ClassArray.filterAndMap" to classArrayBenchmark::filterAndMap,
"ClassArray.filterAndMapManual" to classArrayBenchmark::filterAndMapManual,
"ClassArray.filter" to classArrayBenchmark::filter,
"ClassArray.filterManual" to classArrayBenchmark::filterManual,
"ClassArray.countFilteredManual" to classArrayBenchmark::countFilteredManual,
"ClassArray.countFiltered" to classArrayBenchmark::countFiltered,
"ClassArray.countFilteredLocal" to classArrayBenchmark::countFilteredLocal,
"ClassBaseline.consume" to classBaselineBenchmark::consume,
"ClassBaseline.consumeField" to classBaselineBenchmark::consumeField,
"ClassBaseline.allocateList" to classBaselineBenchmark::allocateList,
"ClassBaseline.allocateArray" to classBaselineBenchmark::allocateArray,
"ClassBaseline.allocateListAndFill" to classBaselineBenchmark::allocateListAndFill,
"ClassBaseline.allocateListAndWrite" to classBaselineBenchmark::allocateListAndWrite,
"ClassBaseline.allocateArrayAndFill" to classBaselineBenchmark::allocateArrayAndFill,
"ClassList.copy" to classListBenchmark::copy,
"ClassList.copyManual" to classListBenchmark::copyManual,
"ClassList.filterAndCount" to classListBenchmark::filterAndCount,
"ClassList.filterAndCountWithLambda" to classListBenchmark::filterAndCountWithLambda,
"ClassList.filterWithLambda" to classListBenchmark::filterWithLambda,
"ClassList.mapWithLambda" to classListBenchmark::mapWithLambda,
"ClassList.countWithLambda" to classListBenchmark::countWithLambda,
"ClassList.filterAndMapWithLambda" to classListBenchmark::filterAndMapWithLambda,
"ClassList.filterAndMapWithLambdaAsSequence" to classListBenchmark::filterAndMapWithLambdaAsSequence,
"ClassList.filterAndMap" to classListBenchmark::filterAndMap,
"ClassList.filterAndMapManual" to classListBenchmark::filterAndMapManual,
"ClassList.filter" to classListBenchmark::filter,
"ClassList.filterManual" to classListBenchmark::filterManual,
"ClassList.countFilteredManual" to classListBenchmark::countFilteredManual,
"ClassList.countFiltered" to classListBenchmark::countFiltered,
"ClassList.reduce" to classListBenchmark::reduce,
"ClassStream.copy" to classStreamBenchmark::copy,
"ClassStream.copyManual" to classStreamBenchmark::copyManual,
"ClassStream.filterAndCount" to classStreamBenchmark::filterAndCount,
"ClassStream.filterAndMap" to classStreamBenchmark::filterAndMap,
"ClassStream.filterAndMapManual" to classStreamBenchmark::filterAndMapManual,
"ClassStream.filter" to classStreamBenchmark::filter,
"ClassStream.filterManual" to classStreamBenchmark::filterManual,
"ClassStream.countFilteredManual" to classStreamBenchmark::countFilteredManual,
"ClassStream.countFiltered" to classStreamBenchmark::countFiltered,
"ClassStream.reduce" to classStreamBenchmark::reduce,
"CompanionObject.invokeRegularFunction" to companionObjectBenchmark::invokeRegularFunction,
"CompanionObject.invokeJvmStaticFunction" to companionObjectBenchmark::invokeJvmStaticFunction,
"DefaultArgument.testOneOfTwo" to defaultArgumentBenchmark::testOneOfTwo,
"DefaultArgument.testTwoOfTwo" to defaultArgumentBenchmark::testTwoOfTwo,
"DefaultArgument.testOneOfFour" to defaultArgumentBenchmark::testOneOfFour,
"DefaultArgument.testFourOfFour" to defaultArgumentBenchmark::testFourOfFour,
"DefaultArgument.testOneOfEight" to defaultArgumentBenchmark::testOneOfEight,
"DefaultArgument.testEightOfEight" to defaultArgumentBenchmark::testEightOfEight,
"Elvis.testElvis" to elvisBenchmark::testElvis,
"Euler.problem1bySequence" to eulerBenchmark::problem1bySequence,
"Euler.problem1" to eulerBenchmark::problem1,
"Euler.problem2" to eulerBenchmark::problem2,
"Euler.problem4" to eulerBenchmark::problem4,
"Euler.problem8" to eulerBenchmark::problem8,
"Euler.problem9" to eulerBenchmark::problem9,
"Euler.problem14" to eulerBenchmark::problem14,
"Euler.problem14full" to eulerBenchmark::problem14full,
"Fibonacci.calcClassic" to fibonacciBenchmark::calcClassic,
"Fibonacci.calc" to fibonacciBenchmark::calc,
"Fibonacci.calcWithProgression" to fibonacciBenchmark::calcWithProgression,
"Fibonacci.calcSquare" to fibonacciBenchmark::calcSquare,
"ForLoops.arrayLoop" to forLoopsBenchmark::arrayLoop,
"ForLoops.intArrayLoop" to forLoopsBenchmark::intArrayLoop,
"ForLoops.floatArrayLoop" to forLoopsBenchmark::floatArrayLoop,
"ForLoops.charArrayLoop" to forLoopsBenchmark::charArrayLoop,
"ForLoops.stringLoop" to forLoopsBenchmark::stringLoop,
"ForLoops.arrayIndicesLoop" to forLoopsBenchmark::arrayIndicesLoop,
"ForLoops.intArrayIndicesLoop" to forLoopsBenchmark::intArrayIndicesLoop,
"ForLoops.floatArrayIndicesLoop" to forLoopsBenchmark::floatArrayIndicesLoop,
"ForLoops.charArrayIndicesLoop" to forLoopsBenchmark::charArrayIndicesLoop,
"ForLoops.stringIndicesLoop" to forLoopsBenchmark::stringIndicesLoop,
"Inline.calculate" to inlineBenchmark::calculate,
"Inline.calculateInline" to inlineBenchmark::calculateInline,
"Inline.calculateGeneric" to inlineBenchmark::calculateGeneric,
"Inline.calculateGenericInline" to inlineBenchmark::calculateGenericInline,
"IntArray.copy" to intArrayBenchmark::copy,
"IntArray.copyManual" to intArrayBenchmark::copyManual,
"IntArray.filterAndCount" to intArrayBenchmark::filterAndCount,
"IntArray.filterSomeAndCount" to intArrayBenchmark::filterSomeAndCount,
"IntArray.filterAndMap" to intArrayBenchmark::filterAndMap,
"IntArray.filterAndMapManual" to intArrayBenchmark::filterAndMapManual,
"IntArray.filter" to intArrayBenchmark::filter,
"IntArray.filterSome" to intArrayBenchmark::filterSome,
"IntArray.filterPrime" to intArrayBenchmark::filterPrime,
"IntArray.filterManual" to intArrayBenchmark::filterManual,
"IntArray.filterSomeManual" to intArrayBenchmark::filterSomeManual,
"IntArray.countFilteredManual" to intArrayBenchmark::countFilteredManual,
"IntArray.countFilteredSomeManual" to intArrayBenchmark::countFilteredSomeManual,
"IntArray.countFilteredPrimeManual" to intArrayBenchmark::countFilteredPrimeManual,
"IntArray.countFiltered" to intArrayBenchmark::countFiltered,
"IntArray.countFilteredSome" to intArrayBenchmark::countFilteredSome,
"IntArray.countFilteredPrime" to intArrayBenchmark::countFilteredPrime,
"IntArray.countFilteredLocal" to intArrayBenchmark::countFilteredLocal,
"IntArray.countFilteredSomeLocal" to intArrayBenchmark::countFilteredSomeLocal,
"IntArray.reduce" to intArrayBenchmark::reduce,
"IntBaseline.consume" to intBaselineBenchmark::consume,
"IntBaseline.allocateList" to intBaselineBenchmark::allocateList,
"IntBaseline.allocateArray" to intBaselineBenchmark::allocateArray,
"IntBaseline.allocateListAndFill" to intBaselineBenchmark::allocateListAndFill,
"IntBaseline.allocateArrayAndFill" to intBaselineBenchmark::allocateArrayAndFill,
"IntList.copy" to intListBenchmark::copy,
"IntList.copyManual" to intListBenchmark::copyManual,
"IntList.filterAndCount" to intListBenchmark::filterAndCount,
"IntList.filterAndMap" to intListBenchmark::filterAndMap,
"IntList.filterAndMapManual" to intListBenchmark::filterAndMapManual,
"IntList.filter" to intListBenchmark::filter,
"IntList.filterManual" to intListBenchmark::filterManual,
"IntList.countFilteredManual" to intListBenchmark::countFilteredManual,
"IntList.countFiltered" to intListBenchmark::countFiltered,
"IntList.countFilteredLocal" to intListBenchmark::countFilteredLocal,
"IntList.reduce" to intListBenchmark::reduce,
"IntStream.copy" to intStreamBenchmark::copy,
"IntStream.copyManual" to intStreamBenchmark::copyManual,
"IntStream.filterAndCount" to intStreamBenchmark::filterAndCount,
"IntStream.filterAndMap" to intStreamBenchmark::filterAndMap,
"IntStream.filterAndMapManual" to intStreamBenchmark::filterAndMapManual,
"IntStream.filter" to intStreamBenchmark::filter,
"IntStream.filterManual" to intStreamBenchmark::filterManual,
"IntStream.countFilteredManual" to intStreamBenchmark::countFilteredManual,
"IntStream.countFiltered" to intStreamBenchmark::countFiltered,
"IntStream.countFilteredLocal" to intStreamBenchmark::countFilteredLocal,
"IntStream.reduce" to intStreamBenchmark::reduce,
"Lambda.noncapturingLambda" to lambdaBenchmark::noncapturingLambda,
"Lambda.noncapturingLambdaNoInline" to lambdaBenchmark::noncapturingLambdaNoInline,
"Lambda.capturingLambda" to lambdaBenchmark::capturingLambda,
"Lambda.capturingLambdaNoInline" to lambdaBenchmark::capturingLambdaNoInline,
"Lambda.mutatingLambda" to lambdaBenchmark::mutatingLambda,
"Lambda.mutatingLambdaNoInline" to lambdaBenchmark::mutatingLambdaNoInline,
"Lambda.methodReference" to lambdaBenchmark::methodReference,
"Lambda.methodReferenceNoInline" to lambdaBenchmark::methodReferenceNoInline,
"Loop.arrayLoop" to loopBenchmark::arrayLoop,
"Loop.arrayIndexLoop" to loopBenchmark::arrayIndexLoop,
"Loop.rangeLoop" to loopBenchmark::rangeLoop,
"Loop.arrayListLoop" to loopBenchmark::arrayListLoop,
"Loop.arrayWhileLoop" to loopBenchmark::arrayWhileLoop,
"Loop.arrayForeachLoop" to loopBenchmark::arrayForeachLoop,
"Loop.arrayListForeachLoop" to loopBenchmark::arrayListForeachLoop,
"MatrixMap.add" to matrixMapBenchmark::add,
"ParameterNotNull.invokeOneArgWithNullCheck" to parameterNotNullAssertionBenchmark::invokeOneArgWithNullCheck,
"ParameterNotNull.invokeOneArgWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeOneArgWithoutNullCheck,
"ParameterNotNull.invokeTwoArgsWithNullCheck" to parameterNotNullAssertionBenchmark::invokeTwoArgsWithNullCheck,
"ParameterNotNull.invokeTwoArgsWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeTwoArgsWithoutNullCheck,
"ParameterNotNull.invokeEightArgsWithNullCheck" to parameterNotNullAssertionBenchmark::invokeEightArgsWithNullCheck,
"ParameterNotNull.invokeEightArgsWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeEightArgsWithoutNullCheck,
"PrimeList.calcDirect" to primeListBenchmark::calcDirect,
"PrimeList.calcEratosthenes" to primeListBenchmark::calcEratosthenes,
"String.stringConcat" to stringBenchmark::stringConcat,
"String.stringConcatNullable" to stringBenchmark::stringConcatNullable,
"String.stringBuilderConcat" to stringBenchmark::stringBuilderConcat,
"String.stringBuilderConcatNullable" to stringBenchmark::stringBuilderConcatNullable,
"String.summarizeSplittedCsv" to stringBenchmark::summarizeSplittedCsv,
"Switch.testSparseIntSwitch" to switchBenchmark::testSparseIntSwitch,
"Switch.testDenseIntSwitch" to switchBenchmark::testDenseIntSwitch,
"Switch.testConstSwitch" to switchBenchmark::testConstSwitch,
"Switch.testObjConstSwitch" to switchBenchmark::testObjConstSwitch,
"Switch.testVarSwitch" to switchBenchmark::testVarSwitch,
"Switch.testStringsSwitch" to switchBenchmark::testStringsSwitch,
"Switch.testEnumsSwitch" to switchBenchmark::testEnumsSwitch,
"Switch.testDenseEnumsSwitch" to switchBenchmark::testDenseEnumsSwitch,
"Switch.testSealedWhenSwitch" to switchBenchmark::testSealedWhenSwitch,
"WithIndicies.withIndicies" to withIndiciesBenchmark::withIndicies,
"WithIndicies.withIndiciesManual" to withIndiciesBenchmark::withIndiciesManual,
"OctoTest" to ::octoTest,
"Calls.finalMethod" to callsBenchmark::finalMethodCall,
"Calls.openMethodMonomorphic" to callsBenchmark::classOpenMethodCall_MonomorphicCallsite,
"Calls.openMethodBimorphic" to callsBenchmark::classOpenMethodCall_BimorphicCallsite,
"Calls.openMethodTrimorphic" to callsBenchmark::classOpenMethodCall_TrimorphicCallsite,
"Calls.interfaceMethodMonomorphic" to callsBenchmark::interfaceMethodCall_MonomorphicCallsite,
"Calls.interfaceMethodBimorphic" to callsBenchmark::interfaceMethodCall_BimorphicCallsite,
"Calls.interfaceMethodTrimorphic" to callsBenchmark::interfaceMethodCall_TrimorphicCallsite,
"Calls.returnBoxUnboxFolding" to callsBenchmark::returnBoxUnboxFolding,
"Calls.parameterBoxUnboxFolding" to callsBenchmark::parameterBoxUnboxFolding,
"CoordinatesSolver.solve" to coordinatesSolverBenchmark::solve,
"GraphSolver.solve" to graphSolverBenchmark::solve
"AbstractMethod.sortStrings" to BenchmarkEntryWithInit.create(::AbstractMethodBenchmark, { sortStrings() }),
"AbstractMethod.sortStringsWithComparator" to BenchmarkEntryWithInit.create(::AbstractMethodBenchmark, { sortStringsWithComparator() }),
"ClassArray.copy" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { copy() }),
"ClassArray.copyManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { copyManual() }),
"ClassArray.filterAndCount" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndCount() }),
"ClassArray.filterAndMap" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndMap() }),
"ClassArray.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndMapManual() }),
"ClassArray.filter" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filter() }),
"ClassArray.filterManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterManual() }),
"ClassArray.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFilteredManual() }),
"ClassArray.countFiltered" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFiltered() }),
"ClassArray.countFilteredLocal" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFilteredLocal() }),
"ClassBaseline.consume" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { consume() }),
"ClassBaseline.consumeField" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { consumeField() }),
"ClassBaseline.allocateList" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateList() }),
"ClassBaseline.allocateArray" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateArray() }),
"ClassBaseline.allocateListAndFill" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateListAndFill() }),
"ClassBaseline.allocateListAndWrite" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateListAndWrite() }),
"ClassBaseline.allocateArrayAndFill" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateArrayAndFill() }),
"ClassList.copy" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { copy() }),
"ClassList.copyManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { copyManual() }),
"ClassList.filterAndCount" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndCount() }),
"ClassList.filterAndCountWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndCountWithLambda() }),
"ClassList.filterWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterWithLambda() }),
"ClassList.mapWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { mapWithLambda() }),
"ClassList.countWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countWithLambda() }),
"ClassList.filterAndMapWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapWithLambda() }),
"ClassList.filterAndMapWithLambdaAsSequence" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapWithLambdaAsSequence() }),
"ClassList.filterAndMap" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMap() }),
"ClassList.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapManual() }),
"ClassList.filter" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filter() }),
"ClassList.filterManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterManual() }),
"ClassList.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countFilteredManual() }),
"ClassList.countFiltered" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countFiltered() }),
"ClassList.reduce" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { reduce() }),
"ClassStream.copy" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { copy() }),
"ClassStream.copyManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { copyManual() }),
"ClassStream.filterAndCount" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndCount() }),
"ClassStream.filterAndMap" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndMap() }),
"ClassStream.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndMapManual() }),
"ClassStream.filter" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filter() }),
"ClassStream.filterManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterManual() }),
"ClassStream.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { countFilteredManual() }),
"ClassStream.countFiltered" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { countFiltered() }),
"ClassStream.reduce" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { reduce() }),
"CompanionObject.invokeRegularFunction" to BenchmarkEntryWithInit.create(::CompanionObjectBenchmark, { invokeRegularFunction() }),
"CompanionObject.invokeJvmStaticFunction" to BenchmarkEntryWithInit.create(::CompanionObjectBenchmark, { invokeJvmStaticFunction() }),
"DefaultArgument.testOneOfTwo" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfTwo() }),
"DefaultArgument.testTwoOfTwo" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testTwoOfTwo() }),
"DefaultArgument.testOneOfFour" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfFour() }),
"DefaultArgument.testFourOfFour" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testFourOfFour() }),
"DefaultArgument.testOneOfEight" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfEight() }),
"DefaultArgument.testEightOfEight" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testEightOfEight() }),
"Elvis.testElvis" to BenchmarkEntryWithInit.create(::ElvisBenchmark, { testElvis() }),
"Euler.problem1bySequence" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem1bySequence() }),
"Euler.problem1" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem1() }),
"Euler.problem2" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem2() }),
"Euler.problem4" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem4() }),
"Euler.problem8" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem8() }),
"Euler.problem9" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem9() }),
"Euler.problem14" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem14() }),
"Euler.problem14full" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem14full() }),
"Fibonacci.calcClassic" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcClassic() }),
"Fibonacci.calc" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calc() }),
"Fibonacci.calcWithProgression" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcWithProgression() }),
"Fibonacci.calcSquare" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcSquare() }),
"ForLoops.arrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { arrayLoop() }),
"ForLoops.intArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { intArrayLoop() }),
"ForLoops.floatArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { floatArrayLoop() }),
"ForLoops.charArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { charArrayLoop() }),
"ForLoops.stringLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { stringLoop() }),
"ForLoops.arrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { arrayIndicesLoop() }),
"ForLoops.intArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { intArrayIndicesLoop() }),
"ForLoops.floatArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { floatArrayIndicesLoop() }),
"ForLoops.charArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { charArrayIndicesLoop() }),
"ForLoops.stringIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { stringIndicesLoop() }),
"Inline.calculate" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculate() }),
"Inline.calculateInline" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateInline() }),
"Inline.calculateGeneric" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateGeneric() }),
"Inline.calculateGenericInline" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateGenericInline() }),
"IntArray.copy" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { copy() }),
"IntArray.copyManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { copyManual() }),
"IntArray.filterAndCount" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndCount() }),
"IntArray.filterSomeAndCount" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSomeAndCount() }),
"IntArray.filterAndMap" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndMap() }),
"IntArray.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndMapManual() }),
"IntArray.filter" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filter() }),
"IntArray.filterSome" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSome() }),
"IntArray.filterPrime" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterPrime() }),
"IntArray.filterManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterManual() }),
"IntArray.filterSomeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSomeManual() }),
"IntArray.countFilteredManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredManual() }),
"IntArray.countFilteredSomeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSomeManual() }),
"IntArray.countFilteredPrimeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredPrimeManual() }),
"IntArray.countFiltered" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFiltered() }),
"IntArray.countFilteredSome" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSome() }),
"IntArray.countFilteredPrime" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredPrime() }),
"IntArray.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredLocal() }),
"IntArray.countFilteredSomeLocal" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSomeLocal() }),
"IntArray.reduce" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { reduce() }),
"IntBaseline.consume" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { consume() }),
"IntBaseline.allocateList" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateList() }),
"IntBaseline.allocateArray" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateArray() }),
"IntBaseline.allocateListAndFill" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateListAndFill() }),
"IntBaseline.allocateArrayAndFill" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateArrayAndFill() }),
"IntList.copy" to BenchmarkEntryWithInit.create(::IntListBenchmark, { copy() }),
"IntList.copyManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { copyManual() }),
"IntList.filterAndCount" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndCount() }),
"IntList.filterAndMap" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndMap() }),
"IntList.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndMapManual() }),
"IntList.filter" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filter() }),
"IntList.filterManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterManual() }),
"IntList.countFilteredManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFilteredManual() }),
"IntList.countFiltered" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFiltered() }),
"IntList.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFilteredLocal() }),
"IntList.reduce" to BenchmarkEntryWithInit.create(::IntListBenchmark, { reduce() }),
"IntStream.copy" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { copy() }),
"IntStream.copyManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { copyManual() }),
"IntStream.filterAndCount" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndCount() }),
"IntStream.filterAndMap" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndMap() }),
"IntStream.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndMapManual() }),
"IntStream.filter" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filter() }),
"IntStream.filterManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterManual() }),
"IntStream.countFilteredManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFilteredManual() }),
"IntStream.countFiltered" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFiltered() }),
"IntStream.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFilteredLocal() }),
"IntStream.reduce" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { reduce() }),
"Lambda.noncapturingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { noncapturingLambda() }),
"Lambda.noncapturingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { noncapturingLambdaNoInline() }),
"Lambda.capturingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { capturingLambda() }),
"Lambda.capturingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { capturingLambdaNoInline() }),
"Lambda.mutatingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambda() }),
"Lambda.mutatingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambdaNoInline() }),
"Lambda.methodReference" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReference() }),
"Lambda.methodReferenceNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReferenceNoInline() }),
"Loop.arrayLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayLoop() }),
"Loop.arrayIndexLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayIndexLoop() }),
"Loop.rangeLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { rangeLoop() }),
"Loop.arrayListLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListLoop() }),
"Loop.arrayWhileLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayWhileLoop() }),
"Loop.arrayForeachLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayForeachLoop() }),
"Loop.arrayListForeachLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListForeachLoop() }),
"MatrixMap.add" to BenchmarkEntryWithInit.create(::MatrixMapBenchmark, { add() }),
"ParameterNotNull.invokeOneArgWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithNullCheck() }),
"ParameterNotNull.invokeOneArgWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithoutNullCheck() }),
"ParameterNotNull.invokeTwoArgsWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeTwoArgsWithNullCheck() }),
"ParameterNotNull.invokeTwoArgsWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeTwoArgsWithoutNullCheck() }),
"ParameterNotNull.invokeEightArgsWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithNullCheck() }),
"ParameterNotNull.invokeEightArgsWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithoutNullCheck() }),
"PrimeList.calcDirect" to BenchmarkEntryWithInit.create(::PrimeListBenchmark, { calcDirect() }),
"PrimeList.calcEratosthenes" to BenchmarkEntryWithInit.create(::PrimeListBenchmark, { calcEratosthenes() }),
"String.stringConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcat() }),
"String.stringConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcatNullable() }),
"String.stringBuilderConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcat() }),
"String.stringBuilderConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcatNullable() }),
"String.summarizeSplittedCsv" to BenchmarkEntryWithInit.create(::StringBenchmark, { summarizeSplittedCsv() }),
"Switch.testSparseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testSparseIntSwitch() }),
"Switch.testDenseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testDenseIntSwitch() }),
"Switch.testConstSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testConstSwitch() }),
"Switch.testObjConstSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testObjConstSwitch() }),
"Switch.testVarSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testVarSwitch() }),
"Switch.testStringsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testStringsSwitch() }),
"Switch.testEnumsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testEnumsSwitch() }),
"Switch.testDenseEnumsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testDenseEnumsSwitch() }),
"Switch.testSealedWhenSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testSealedWhenSwitch() }),
"WithIndicies.withIndicies" to BenchmarkEntryWithInit.create(::WithIndiciesBenchmark, { withIndicies() }),
"WithIndicies.withIndiciesManual" to BenchmarkEntryWithInit.create(::WithIndiciesBenchmark, { withIndiciesManual() }),
"OctoTest" to BenchmarkEntry(::octoTest),
"Calls.finalMethod" to BenchmarkEntryWithInit.create(::CallsBenchmark, { finalMethodCall() }),
"Calls.openMethodMonomorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_MonomorphicCallsite() }),
"Calls.openMethodBimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_BimorphicCallsite() }),
"Calls.openMethodTrimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_TrimorphicCallsite() }),
"Calls.interfaceMethodMonomorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_MonomorphicCallsite() }),
"Calls.interfaceMethodBimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_BimorphicCallsite() }),
"Calls.interfaceMethodTrimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_TrimorphicCallsite() }),
"Calls.returnBoxUnboxFolding" to BenchmarkEntryWithInit.create(::CallsBenchmark, { returnBoxUnboxFolding() }),
"Calls.parameterBoxUnboxFolding" to BenchmarkEntryWithInit.create(::CallsBenchmark, { parameterBoxUnboxFolding() }),
"CoordinatesSolver.solve" to BenchmarkEntryWithInit.create(::CoordinatesSolverBenchmark, { solve() }),
"GraphSolver.solve" to BenchmarkEntryWithInit.create(::GraphSolverBenchmark, { solve() })
)
)
}
fun main(args: Array<String>) {
val launcher = RingLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
RingLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!)
.launch(parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
})
launcher.launch(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!,
parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
}, benchmarksListAction = launcher::benchmarksListAction)
}
@@ -133,8 +133,6 @@ class CoordinatesSolverBenchmark {
var ss: List<Coordinate>? = null
while (ss == null) {
//println("o$o, limit: $limit")
if (o == 0) {
ss = solveWithLimit(limit, MAZE_START) { it[it.size - 1] == objects[0] }
} else {
@@ -342,7 +340,11 @@ class CoordinatesSolverBenchmark {
val output = solver.solve()
for (c in output.steps) {
val value = if (c == null) { "felvesz" } else { "${c.x} ${c.y}" }
val value = if (c == null) {
"felvesz"
} else {
"${c.x} ${c.y}"
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -16,8 +16,15 @@
package org.jetbrains.benchmarksLauncher
import kotlin.reflect.KFunction0
interface AbstractBenchmarkEntry
class BenchmarksCollection(private val benchmarks: MutableMap<String, KFunction0<Any?>> = mutableMapOf()) :
MutableMap<String, KFunction0<Any?>> by benchmarks {
class BenchmarkEntryWithInit(val ctor: ()->Any, val lambda: (Any) -> Any?): AbstractBenchmarkEntry {
companion object {
inline fun <reified T: Any> create(noinline ctor: ()->T, crossinline lambda: T.() -> Any?) = BenchmarkEntryWithInit(ctor) { (it as T).lambda() }
}
}
class BenchmarkEntry(val lambda: () -> Any?) : AbstractBenchmarkEntry
class BenchmarksCollection(private val benchmarks: MutableMap<String, AbstractBenchmarkEntry> = mutableMapOf()) :
MutableMap<String, AbstractBenchmarkEntry> by benchmarks
@@ -19,10 +19,10 @@ package org.jetbrains.benchmarksLauncher
import org.jetbrains.report.BenchmarkResult
class JsonReportCreator(val data: Iterable<BenchmarkResult>) {
fun printJsonReport(jsonReport: String): Unit {
fun printJsonReport(jsonReport: String?): Unit {
val reportText = data.joinToString(prefix = "[", postfix = "]") {
it.toJson()
}
writeToFile(jsonReport, reportText)
jsonReport?.let { writeToFile(it, reportText) } ?: print(reportText)
}
}
@@ -16,24 +16,40 @@
package org.jetbrains.benchmarksLauncher
import kotlin.math.sqrt
import org.jetbrains.report.BenchmarkResult
import org.jetbrains.kliopt.*
import kotlin.reflect.KFunction0
abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, val prefix: String = "") {
class Results(val mean: Double, val variance: Double)
abstract class Launcher {
abstract val benchmarks: BenchmarksCollection
fun add(name: String, benchmark:() -> Any?) {
fun benchmarkWrapper() {
benchmark()
}
benchmarks[name] = ::benchmarkWrapper
fun add(name: String, benchmark: AbstractBenchmarkEntry) {
benchmarks[name] = benchmark
}
fun launch(filters: Collection<String>? = null,
fun runBenchmark(benchmarkInstance: Any?, benchmark: AbstractBenchmarkEntry, repeatNumber: Int): Long {
var i = repeatNumber
return if (benchmark is BenchmarkEntryWithInit) {
cleanup()
measureNanoTime {
while (i-- > 0) benchmark.lambda(benchmarkInstance!!)
cleanup()
}
} else {
cleanup()
measureNanoTime {
if (benchmark is BenchmarkEntry) {
while (i-- > 0) benchmark.lambda()
cleanup()
}
}
}
}
fun launch(numWarmIterations: Int,
numberOfAttempts: Int,
prefix: String = "",
filters: Collection<String>? = null,
filterRegexes: Collection<String>? = null): List<BenchmarkResult> {
val regexes = filterRegexes?.map { it.toRegex() } ?: listOf()
val filterSet = filters?.toHashSet() ?: hashSetOf()
@@ -45,19 +61,13 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
error("No matching benchmarks found")
val benchmarkResults = mutableListOf<BenchmarkResult>()
for ((name, benchmark) in runningBenchmarks) {
val benchmarkInstance = (benchmark as? BenchmarkEntryWithInit)?.ctor?.invoke()
var i = numWarmIterations
while (i-- > 0) benchmark()
cleanup()
runBenchmark(benchmarkInstance, benchmark, i)
var autoEvaluatedNumberOfMeasureIteration = 1
while (true) {
var j = autoEvaluatedNumberOfMeasureIteration
cleanup()
val time = measureNanoTime {
while (j-- > 0) {
benchmark()
}
cleanup()
}
val time = runBenchmark(benchmarkInstance, benchmark, j)
if (time >= 100L * 1_000_000) // 100ms
break
autoEvaluatedNumberOfMeasureIteration *= 2
@@ -65,13 +75,7 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
val samples = DoubleArray(numberOfAttempts)
for (k in samples.indices) {
i = autoEvaluatedNumberOfMeasureIteration
cleanup()
val time = measureNanoTime {
while (i-- > 0) {
benchmark()
}
cleanup()
}
val time = runBenchmark(benchmarkInstance, benchmark, i)
val scaledTime = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
samples[k] = scaledTime
// Save benchmark object
@@ -82,10 +86,20 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
}
return benchmarkResults
}
fun benchmarksListAction(argParser: ArgParser) {
benchmarks.keys.forEach {
println(it)
}
}
}
object BenchmarksRunner {
fun parse(args: Array<String>): ArgParser {
fun parse(args: Array<String>, benchmarksListAction: (ArgParser)->Unit): ArgParser? {
val actions = mapOf("list" to Action(
benchmarksListAction,
ArgParser(listOf<OptionDescriptor>()))
)
val options = listOf(
OptionDescriptor(ArgType.Int(), "warmup", "w", "Number of warm up iterations", "20"),
OptionDescriptor(ArgType.Int(), "repeat", "r", "Number of each benchmark run", "60"),
@@ -96,23 +110,23 @@ object BenchmarksRunner {
)
// Parse args.
val argParser = ArgParser(options)
argParser.parse(args)
return argParser
val argParser = ArgParser(options, actions = actions)
return if (argParser.parse(args)) argParser else null
}
fun collect(results: List<BenchmarkResult>, parser: ArgParser) {
parser.get<String>("output")?.let {
JsonReportCreator(results).printJsonReport(it)
}
JsonReportCreator(results).printJsonReport(parser.get<String>("output"))
}
fun runBenchmarks(args: Array<String>,
run: (parser: ArgParser) -> List<BenchmarkResult>,
parseArgs: (args: Array<String>) -> ArgParser = this::parse,
collect: (results: List<BenchmarkResult>, parser: ArgParser) -> Unit = this::collect) {
val parser = parseArgs(args)
val results = run(parser)
collect(results, parser)
parseArgs: (args: Array<String>, benchmarksListAction: (ArgParser)->Unit) -> ArgParser? = this::parse,
collect: (results: List<BenchmarkResult>, parser: ArgParser) -> Unit = this::collect,
benchmarksListAction: (ArgParser)->Unit) {
val parser = parseArgs(args, benchmarksListAction)
parser?.let {
val results = run(parser)
collect(results, parser)
}
}
}
@@ -6,7 +6,7 @@
import org.jetbrains.benchmarksLauncher.*
import org.jetbrains.kliopt.*
class SwiftLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) {
class SwiftLauncher: Launcher() {
override val benchmarks = BenchmarksCollection(
mutableMapOf(
)
+35 -17
View File
@@ -10,22 +10,40 @@ var runner = BenchmarksRunner()
let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {index in
CommandLine.arguments[Int(truncating: index) + 1]
})
let companion = BenchmarkEntryWithInit.Companion()
var swiftLauncher = SwiftLauncher()
runner.runBenchmarks(args: args, run: { (parser: ArgParser) -> [BenchmarkResult] in
var swiftBenchmarks = SwiftInteropBenchmarks()
var swiftLauncher = SwiftLauncher(numWarmIterations: parser.get(name: "warmup") as! Int32,
numberOfAttempts: parser.get(name: "repeat") as! Int32, prefix: parser.get(name: "prefix") as! String)
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: swiftBenchmarks.createMultigraphOfInt)
swiftLauncher.add(name: "fillCityMap", benchmark: swiftBenchmarks.fillCityMap)
swiftLauncher.add(name: "searchRoutesInSwiftMultigraph", benchmark: swiftBenchmarks.searchRoutesInSwiftMultigraph)
swiftLauncher.add(name: "searchTravelRoutes", benchmark: swiftBenchmarks.searchTravelRoutes)
swiftLauncher.add(name: "availableTransportOnMap", benchmark: swiftBenchmarks.availableTransportOnMap)
swiftLauncher.add(name: "allPlacesMapedByInterests", benchmark: swiftBenchmarks.allPlacesMapedByInterests)
swiftLauncher.add(name: "getAllPlacesWithStraightRoutesTo", benchmark: swiftBenchmarks.getAllPlacesWithStraightRoutesTo)
swiftLauncher.add(name: "goToAllAvailablePlaces", benchmark: swiftBenchmarks.goToAllAvailablePlaces)
swiftLauncher.add(name: "removeVertexAndEdgesSwiftMultigraph", benchmark: swiftBenchmarks.removeVertexAndEdgesSwiftMultigraph)
swiftLauncher.add(name: "stringInterop", benchmark: swiftBenchmarks.stringInterop)
swiftLauncher.add(name: "simpleFunction", benchmark: swiftBenchmarks.simpleFunction)
return swiftLauncher.launch(filters: parser.getAll(name: "filter"), filterRegexes: parser.getAll(name: "filterRegex"))
}, parseArgs: runner.parse, collect: { (benchmarks: [BenchmarkResult], parser: ArgParser) -> Void in
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).createMultigraphOfInt() }))
swiftLauncher.add(name: "fillCityMap", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).fillCityMap() }))
swiftLauncher.add(name: "searchRoutesInSwiftMultigraph", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).searchRoutesInSwiftMultigraph () }))
swiftLauncher.add(name: "searchTravelRoutes", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).searchTravelRoutes() }))
swiftLauncher.add(name: "availableTransportOnMap", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).availableTransportOnMap() }))
swiftLauncher.add(name: "allPlacesMapedByInterests", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).allPlacesMapedByInterests() }))
swiftLauncher.add(name: "getAllPlacesWithStraightRoutesTo", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).getAllPlacesWithStraightRoutesTo() }))
swiftLauncher.add(name: "goToAllAvailablePlaces", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).goToAllAvailablePlaces() }))
swiftLauncher.add(name: "removeVertexAndEdgesSwiftMultigraph", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).removeVertexAndEdgesSwiftMultigraph() }))
swiftLauncher.add(name: "stringInterop", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).stringInterop() }))
swiftLauncher.add(name: "simpleFunction", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
lambda: { ($0 as! SwiftInteropBenchmarks).simpleFunction() }))
return swiftLauncher.launch(numWarmIterations: parser.get(name: "warmup") as! Int32,
numberOfAttempts: parser.get(name: "repeat") as! Int32,
prefix: parser.get(name: "prefix") as! String, filters: parser.getAll(name: "filter"),
filterRegexes: parser.getAll(name: "filterRegex"))
}, parseArgs: { (args: KotlinArray, benchmarksListAction: ((ArgParser) -> KotlinUnit)) -> ArgParser? in
return runner.parse(args: args, benchmarksListAction: swiftLauncher.benchmarksListAction) },
collect: { (benchmarks: [BenchmarkResult], parser: ArgParser) -> Void in
runner.collect(results: benchmarks, parser: parser)
})
}, benchmarksListAction: swiftLauncher.benchmarksListAction)
@@ -0,0 +1,7 @@
depends = ApplicationServices AudioToolbox CFNetwork CoreAudio CoreFoundation CoreGraphics CoreImage CoreMIDI CoreMedia CoreServices CoreText CoreVideo DiskArbitration Foundation IOKit IOSurface ImageIO MediaToolbox Metal OpenGLCommon QuartzCore Security darwin libkern osx posix
language = Objective-C
package = platform.AVFoundation
modules = AVFoundation
compilerOpts = -framework AVFoundation
linkerOpts = -framework AVFoundation
+7
View File
@@ -0,0 +1,7 @@
depends = AVFoundation AppKit ApplicationServices AudioToolbox CFNetwork CoreAudio CoreData CoreFoundation CoreGraphics CoreImage CoreMIDI CoreMedia CoreServices CoreText CoreVideo DiskArbitration Foundation IOKit IOSurface ImageIO MediaToolbox Metal OpenGLCommon QuartzCore Security darwin libkern osx posix
language = Objective-C
package = platform.AVKit
modules = AVKit
compilerOpts = -framework AVKit
linkerOpts = -framework AVKit

Some files were not shown because too many files have changed in this diff Show More