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) * CoreLocation platform library on macOS (GH-3041)
* Converting Unit type to Void during producing framework for Objective-C/Swift (GH-2549, GH-1271) * 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) * Performance improvements of memory manager (GH-2813)
* FreezableAtomicReference prototype (GH-2776) * FreezableAtomicReference prototype (GH-2776)
* Logging and error messages enhancements * 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 { components.main {
dependencies { dependencies {
cinterop('mystdio') { cinterop('mystdio') {
// Сinterop configuration. // Cinterop configuration.
} }
} }
} }
@@ -253,7 +253,7 @@ kotlin {
macosX64 { macosX64 {
compilations.main.cinterops { compilations.main.cinterops {
mystdio { mystdio {
// Сinterop configuration. // Cinterop configuration.
} }
} }
} }
@@ -101,12 +101,3 @@ inline fun buildKotlinCodeLines(scope: KotlinScope, block: KotlinCodeBuilder.()
builder.block() builder.block()
return builder.build() 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('_', '@', ':', ';', '.', ',', '{', '}', '=', '[', ']', '^', '#', '*', ' ', '(', ')')) 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 val annotationForUnableToImport
get() = "@Deprecated(${"Unable to import this declaration".quoteAsKotlinLiteral()}, level = DeprecationLevel.ERROR)" 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 { override fun declare(classifier: Classifier): String {
if (classifier.pkg != this.pkg) { 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) { if (!classifier.isTopLevel) {
@@ -17,10 +17,9 @@
package org.jetbrains.kotlin.native.interop.gen package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.native.interop.gen.jvm.StubGenerator
import org.jetbrains.kotlin.native.interop.indexer.* 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 selectorParts = this.selector.split(":")
val result = mutableListOf<String>() val result = mutableListOf<String>()
@@ -66,194 +65,168 @@ private fun ObjCMethod.getFirstKotlinParameterNameCandidate(forConstructorOrFact
} }
private fun ObjCMethod.getKotlinParameters( private fun ObjCMethod.getKotlinParameters(
stubGenerator: StubGenerator, stubIrBuilder: StubsBuildingContext,
forConstructorOrFactory: Boolean forConstructorOrFactory: Boolean
): List<KotlinParameter> { ): List<FunctionParameterStub> {
val names = getKotlinParameterNames(forConstructorOrFactory) // TODO: consider refactoring. val names = getKotlinParameterNames(forConstructorOrFactory) // TODO: consider refactoring.
val result = mutableListOf<KotlinParameter>() val result = mutableListOf<FunctionParameterStub>()
this.parameters.mapIndexedTo(result) { index, it -> 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 name = names[index]
val annotations = if (it.nsConsumed) listOf("@CCall.Consumed") else emptyList() val annotations = if (it.nsConsumed) listOf(AnnotationStub.ObjC.Consumed) else emptyList()
KotlinParameter(name, kotlinType, isVararg = false, annotations = annotations) FunctionParameterStub(name, WrapperStubType(kotlinType), isVararg = false, annotations = annotations)
} }
if (this.isVariadic) { if (this.isVariadic) {
result += KotlinParameter( result += FunctionParameterStub(
names.last(), names.last(),
KotlinTypes.any.makeNullable(), WrapperStubType(KotlinTypes.any.makeNullable()),
isVararg = true, isVararg = true,
annotations = emptyList() annotations = emptyList()
) )
} }
return result return result
} }
class ObjCMethodStub(private val stubGenerator: StubGenerator, private class ObjCMethodStubBuilder(
val method: ObjCMethod, private val method: ObjCMethod,
private val container: ObjCContainer, private val container: ObjCContainer,
private val isDesignatedInitializer: Boolean) : KotlinStub, NativeBacked { private val isDesignatedInitializer: Boolean,
override val context: StubsBuildingContext
override fun generate(context: StubGenerationContext): Sequence<String> = ) : StubElementBuilder {
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 val isStret: Boolean 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 { init {
kotlinMethodParameters = method.getKotlinParameters(stubGenerator, forConstructorOrFactory = false)
val returnType = method.getReturnType(container.classOrProtocol) val returnType = method.getReturnType(container.classOrProtocol)
isStret = returnType.isStret(context.configuration.target)
isStret = returnType.isStret(stubGenerator.configuration.target) stubReturnType = if (returnType.unwrapTypedefs() is VoidType) {
WrapperStubType(KotlinTypes.unit)
this.kotlinReturnType = if (returnType.unwrapTypedefs() is VoidType) {
KotlinTypes.unit
} else { } else {
stubGenerator.mirror(returnType).argType WrapperStubType(context.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()")
} }
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( private fun buildObjCMethodAnnotations(main: AnnotationStub): List<AnnotationStub> = listOfNotNull(
buildObjCMethodAnnotation(main), main,
"@CCall.ConsumesReceiver".takeIf { method.nsConsumesSelf }, AnnotationStub.ObjC.ConsumesReceiver.takeIf { method.nsConsumesSelf },
"@CCall.ReturnsRetained".takeIf { method.nsReturnsRetained } AnnotationStub.ObjC.ReturnsRetained.takeIf { method.nsReturnsRetained }
) )
private fun buildObjCMethodAnnotation(annotation: String) = buildString { fun isDefaultConstructor(): Boolean =
append(annotation) method.isInit && method.parameters.isEmpty()
append('(')
append(method.selector.quoteAsKotlinLiteral()) override fun build(): List<FunctionalStub> {
append(", ") val replacement = if (method.isInit) {
append(method.encoding.quoteAsKotlinLiteral()) val parameters = method.getKotlinParameters(context, forConstructorOrFactory = true)
if (isStret) { when (container) {
append(", ") is ObjCClass -> {
append("true") 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 { internal val ObjCContainer.classOrProtocol: ObjCClassOrProtocol
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
get() = when (this) { get() = when (this) {
is ObjCClassOrProtocol -> this is ObjCClassOrProtocol -> this
is ObjCCategory -> this.clazz 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. * 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() val unwrappedType = this.unwrapTypedefs()
return when (target) { return when (target) {
KonanTarget.IOS_ARM64 -> 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) { private fun Type.isIntegerLikeType(): Boolean = when (this) {
is RecordType -> { is RecordType -> {
val def = this.decl.def 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`? // TODO: should the recursive checks be made in indexer when computing `hasUnalignedFields`?
} }
private val ObjCMethod.kotlinName: String internal val ObjCMethod.kotlinName: String
get() { get() {
val candidate = selector.split(":").first() val candidate = selector.split(":").first()
val trimmed = candidate.trimEnd('_') 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 } get() = this.protocols.asSequence().flatMap { sequenceOf(it) + it.protocolsWithSupers }
private val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtocol> internal val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtocol>
get() { get() {
val baseClass = (this as? ObjCClass)?.baseClass val baseClass = (this as? ObjCClass)?.baseClass
if (baseClass != null) { if (baseClass != null) {
@@ -350,28 +330,28 @@ private val ObjCClassOrProtocol.immediateSuperTypes: Sequence<ObjCClassOrProtoco
return this.protocols.asSequence() return this.protocols.asSequence()
} }
private val ObjCClassOrProtocol.selfAndSuperTypes: Sequence<ObjCClassOrProtocol> internal val ObjCClassOrProtocol.selfAndSuperTypes: Sequence<ObjCClassOrProtocol>
get() = sequenceOf(this) + this.superTypes get() = sequenceOf(this) + this.superTypes
private val ObjCClassOrProtocol.superTypes: Sequence<ObjCClassOrProtocol> internal val ObjCClassOrProtocol.superTypes: Sequence<ObjCClassOrProtocol>
get() = this.immediateSuperTypes.flatMap { it.selfAndSuperTypes }.distinct() 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 } this.methods.asSequence().filter { it.isClass == isClass }
@Suppress("UNUSED_PARAMETER") @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]. 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) } this.immediateSuperTypes.flatMap { it.methodsWithInherited(isClass) }
.distinctBy { it.selector } .distinctBy { it.selector }
.inheritedTo(this, isClass) .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 } (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. // 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), // 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. // 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 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) } container.superTypes.any { superType -> superType.methods.any(this::replaces) }
abstract class ObjCContainerStub(stubGenerator: StubGenerator, internal abstract class ObjCContainerStubBuilder(
private val container: ObjCClassOrProtocol, final override val context: StubsBuildingContext,
protected val metaContainerStub: ObjCContainerStub? private val container: ObjCClassOrProtocol,
) : KotlinStub { protected val metaContainerStub: ObjCContainerStubBuilder?
) : StubElementBuilder {
private val isMeta: Boolean get() = metaContainerStub == null 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 methods: List<ObjCMethod>
private val properties: List<ObjCProperty> 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 { private val methodToStub = methods.map {
it to ObjCMethodStub( it to ObjCMethodStubBuilder(it, container, it.selector in designatedInitializerSelectors, context)
stubGenerator, it, container,
isDesignatedInitializer = it.selector in designatedInitializerSelectors
)
}.toMap() }.toMap()
private val methodStubs get() = methodToStub.values private val propertyBuilders = properties.mapNotNull {
createObjCPropertyBuilder(context, it, container, this.methodToStub)
val propertyStubs = properties.mapNotNull {
createObjCPropertyStub(stubGenerator, it, container, this.methodToStub)
} }
private val classHeader: String private val modality = when (container) {
is ObjCClass -> ClassStubModality.OPEN
is ObjCProtocol -> ClassStubModality.INTERFACE
}
init { private val classifier = context.getKotlinClassFor(container, isMeta)
val supers = mutableListOf<KotlinType>()
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) { if (container is ObjCClass) {
val baseClass = container.baseClass val baseClass = container.baseClass
val baseClassifier = if (baseClass != null) { val baseClassifier = if (baseClass != null) {
stubGenerator.declarationMapper.getKotlinClassFor(baseClass, isMeta) context.getKotlinClassFor(baseClass, isMeta)
} else { } else {
if (isMeta) KotlinTypes.objCObjectBaseMeta else KotlinTypes.objCObjectBase if (isMeta) KotlinTypes.objCObjectBaseMeta else KotlinTypes.objCObjectBase
} }
interfaces += WrapperStubType(baseClassifier.type)
supers.add(baseClassifier.type)
} }
container.protocols.forEach { container.protocols.forEach {
supers.add(stubGenerator.declarationMapper.getKotlinClassFor(it, isMeta).type) interfaces += WrapperStubType(context.getKotlinClassFor(it, isMeta).type)
} }
if (interfaces.isEmpty()) {
if (supers.isEmpty()) {
assert(container is ObjCProtocol) assert(container is ObjCProtocol)
val classifier = if (isMeta) KotlinTypes.objCObjectMeta else KotlinTypes.objCObject val classifier = if (isMeta) KotlinTypes.objCObjectMeta else KotlinTypes.objCObject
supers.add(classifier.type) interfaces += WrapperStubType(classifier.type)
} }
if (!isMeta && container.isProtocolClass()) { if (!isMeta && container.isProtocolClass()) {
// TODO: map Protocol type to ObjCProtocol instead. // TODO: map Protocol type to ObjCProtocol instead.
supers.add(KotlinTypes.objCProtocol.type) interfaces += WrapperStubType(KotlinTypes.objCProtocol.type)
} }
interfaces
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"
} }
open fun generateBody(context: StubGenerationContext): Sequence<String> { private fun buildBody(): Pair<List<PropertyStub>, List<FunctionalStub>> {
var result = (propertyStubs.asSequence() + methodStubs.asSequence()) val defaultConstructor = if (container is ObjCClass && methodToStub.values.none { it.isDefaultConstructor() }) {
.flatMap { sequenceOf("") + it.generate(context) }
if (container is ObjCClass && methodStubs.none {
it.method.isInit && it.method.parameters.isEmpty() && context.nativeBridges.isSupported(it)
}) {
// Always generate default constructor. // Always generate default constructor.
// If it is not produced for an init method, then include it manually: // 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( internal sealed class ObjCClassOrProtocolStubBuilder(
stubGenerator: StubGenerator, context: StubsBuildingContext,
private val container: ObjCClassOrProtocol private val container: ObjCClassOrProtocol
) : ObjCContainerStub( ) : ObjCContainerStubBuilder(
stubGenerator, context,
container, container,
metaContainerStub = object : ObjCContainerStub(stubGenerator, container, metaContainerStub = null) {} metaContainerStub = object : ObjCContainerStubBuilder(context, container, metaContainerStub = null) {
) {
override fun generate(context: StubGenerationContext) = override fun build(): List<StubIrElement> =
metaContainerStub!!.generate(context) + "" + super.generate(context) 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) : internal class ObjCClassStubBuilder(
ObjCClassOrProtocolStub(stubGenerator, protocol) context: StubsBuildingContext,
private val clazz: ObjCClass
class ObjCClassStub(private val stubGenerator: StubGenerator, private val clazz: ObjCClass) : ) : ObjCClassOrProtocolStubBuilder(context, clazz), StubElementBuilder {
ObjCClassOrProtocolStub(stubGenerator, clazz) { override fun build(): List<StubIrElement> {
val companionSuper = ClassifierStubType(context.getKotlinClassFor(clazz, isMeta = true))
override fun generateBody(context: StubGenerationContext): Sequence<String> {
val companionSuper = stubGenerator.declarationMapper
.getKotlinClassFor(clazz, isMeta = true).type
.render(stubGenerator.kotlinFile)
val objCClassType = KotlinTypes.objCClassOf.typeWith( val objCClassType = KotlinTypes.objCClassOf.typeWith(
stubGenerator.declarationMapper.getKotlinClassFor(clazz, isMeta = false).type context.getKotlinClassFor(clazz, isMeta = false).type
).render(stubGenerator.kotlinFile) ).let { WrapperStubType(it) }
return sequenceOf( "companion object : $companionSuper(), $objCClassType {}") + val superClassInit = SuperClassInit(companionSuper)
super.generateBody(context) 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( internal class ObjCCategoryStubBuilder(
private val stubGenerator: StubGenerator, private val category: ObjCCategory override val context: StubsBuildingContext,
) : KotlinStub { private val category: ObjCCategory
) : StubElementBuilder {
private val generatedMembers = stubGenerator.generatedObjCCategoriesMembers private val generatedMembers = context.generatedObjCCategoriesMembers
.getOrPut(category.clazz, { GeneratedObjCCategoriesMembers() }) .getOrPut(category.clazz, { GeneratedObjCCategoriesMembers() })
// TODO: consider removing members that are also present in the class or its supertypes. private val methodToBuilder = category.methods.filter { generatedMembers.register(it) }.map {
it to ObjCMethodStubBuilder(it, category, isDesignatedInitializer = false, context = context)
private val methodToStub = category.methods.filter { generatedMembers.register(it) }.map {
it to ObjCMethodStub(stubGenerator, it, category, isDesignatedInitializer = false)
}.toMap() }.toMap()
private val methodStubs get() = methodToStub.values private val methodBuilders get() = methodToBuilder.values
private val propertyStubs = category.properties.filter { generatedMembers.register(it) }.mapNotNull { private val propertyBuilders = category.properties.filter { generatedMembers.register(it) }.mapNotNull {
createObjCPropertyStub(stubGenerator, it, category, methodToStub) createObjCPropertyBuilder(context, it, category, methodToBuilder)
} }
override fun generate(context: StubGenerationContext): Sequence<String> { override fun build(): List<StubIrElement> {
val description = "${category.clazz.name} (${category.name})" val description = "${category.clazz.name} (${category.name})"
return sequenceOf("// @interface $description") + val meta = StubContainerMeta(
propertyStubs.asSequence().flatMap { sequenceOf("") + it.generate(context) } + "// @interface $description",
methodStubs.asSequence().flatMap { sequenceOf("") + it.generate(context) } + "// @end; // $description"
sequenceOf("// @end; // $description") )
val container = SimpleStubContainer(
meta = meta,
functions = methodBuilders.flatMap { it.build() },
properties = propertyBuilders.flatMap { it.build() }
)
return listOf(container)
} }
} }
private fun createObjCPropertyStub( private fun createObjCPropertyBuilder(
stubGenerator: StubGenerator, context: StubsBuildingContext,
property: ObjCProperty, property: ObjCProperty,
container: ObjCContainer, container: ObjCContainer,
methodToStub: Map<ObjCMethod, ObjCMethodStub> methodToStub: Map<ObjCMethod, ObjCMethodStubBuilder>
): ObjCPropertyStub? { ): ObjCPropertyStubBuilder? {
// Note: the code below assumes that if the property is generated, // Note: the code below assumes that if the property is generated,
// then its accessors are also generated as explicit methods. // then its accessors are also generated as explicit methods.
val getterStub = methodToStub[property.getter] ?: return null val getterStub = methodToStub[property.getter] ?: return null
val setterStub = property.setter?.let { methodToStub[it] ?: 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( private class ObjCPropertyStubBuilder(
val stubGenerator: StubGenerator, val property: ObjCProperty, val container: ObjCContainer, override val context: StubsBuildingContext,
val getterStub: ObjCMethodStub, val setterStub: ObjCMethodStub? private val property: ObjCProperty,
) : KotlinStub { private val container: ObjCContainer,
private val getterBuilder: ObjCMethodStubBuilder,
override fun generate(context: StubGenerationContext): Sequence<String> { private val setterMethod: ObjCMethodStubBuilder?
) : StubElementBuilder {
override fun build(): List<PropertyStub> {
val type = property.getType(container.classOrProtocol) val type = property.getType(container.classOrProtocol)
val kotlinType = context.mirror(type).argType
val kotlinType = stubGenerator.mirror(type).argType.render(stubGenerator.kotlinFile) val getter = PropertyAccessor.Getter.ExternalGetter(annotations = getterBuilder.annotations)
val setter = property.setter?.let { PropertyAccessor.Setter.ExternalSetter(annotations = setterMethod!!.annotations) }
val kind = if (property.setter == null) "val" else "var" val kind = setter?.let { PropertyStub.Kind.Var(getter, it) } ?: PropertyStub.Kind.Val(getter)
val modifiers = if (container is ObjCProtocol) "final " else "" val modality = MemberStubModality.FINAL
val receiver = when (container) { val receiver = when (container) {
is ObjCClassOrProtocol -> "" is ObjCClassOrProtocol -> null
is ObjCCategory -> stubGenerator.declarationMapper is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass).type
.render(stubGenerator.kotlinFile) + "."
} }
val result = mutableListOf( return listOf(PropertyStub(property.name, WrapperStubType(kotlinType), kind, modality, receiver))
"$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()
} }
} }
fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String { fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
@@ -676,27 +647,7 @@ fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
return if (isMeta) "${baseClassName}Meta" else baseClassName return if (isMeta) "${baseClassName}Meta" else baseClassName
} }
private fun genProtocolGetter( internal fun ObjCClassOrProtocol.isProtocolClass(): Boolean = when (this) {
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) {
is ObjCClass -> (name == "Protocol" || binaryName == "Protocol") is ObjCClass -> (name == "Protocol" || binaryName == "Protocol")
is ObjCProtocol -> false is ObjCProtocol -> false
} }
@@ -234,7 +234,6 @@ class SimpleBridgeGeneratorImpl(
} }
// TODO: exclude unused bridges. // TODO: exclude unused bridges.
return object : NativeBridges { return object : NativeBridges {
override val kotlinLines: Sequence<String> 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>> { override fun getReady(): Map<File, Set<String>> {
return dependencyAssigners.map { it.getReady() }.reduce { left, right -> return dependencyAssigners.map { it.getReady() }.reduce { left, right ->
(left.keys intersect right.keys) (left.keys intersect right.keys)
.associateWith { left[it]!! union right[it]!! } .associateWith { left.getValue(it) union right.getValue(it) }
}.also { }.also {
require(it.isNotEmpty()) { "incompatible dependencies" } // TODO: add more info. require(it.isNotEmpty()) { "incompatible dependencies" } // TODO: add more info.
} }
@@ -34,3 +34,8 @@ class InteropConfiguration(
val disableDesignatedInitializerChecks: Boolean, val disableDesignatedInitializerChecks: Boolean,
val target: KonanTarget 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 excludedMacros = def.config.excludedMacros.toSet()
val staticLibraries = def.config.staticLibraries + argParser.getValuesAsArray("staticLibrary") val staticLibraries = def.config.staticLibraries + argParser.getValuesAsArray("staticLibrary")
val libraryPaths = def.config.libraryPaths + argParser.getValuesAsArray("libraryPath") val libraryPaths = def.config.libraryPaths + argParser.getValuesAsArray("libraryPath")
val fqParts = (argParser.get<String>("pkg") ?: def.config.packageName)?.let { val fqParts = (argParser.get<String>("pkg") ?: def.config.packageName)?.split('.')
it.split('.') ?: defFile!!.name.split('.').reversed().drop(1)
} ?: defFile!!.name.split('.').reversed().drop(1)
val outKtFileName = fqParts.last() + ".kt" val outKtFileName = fqParts.last() + ".kt"
@@ -235,19 +234,21 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
target = tool.target target = tool.target
) )
val gen = StubGenerator(nativeIndex, configuration, libName, verbose, flavor, imports)
outKtFile.parentFile.mkdirs() outKtFile.parentFile.mkdirs()
File(nativeLibsDir).mkdirs() File(nativeLibsDir).mkdirs()
val outCFile = tempFiles.create(libName, ".${language.sourceFileExtension}") val outCFile = tempFiles.create(libName, ".${language.sourceFileExtension}")
outKtFile.bufferedWriter().use { ktFile -> val logger = if (verbose) {
File(outCFile.absolutePath).bufferedWriter().use { cFile -> { message: String -> println(message) }
gen.generateFiles(ktFile = ktFile, cFile = cFile, entryPoint = entryPoint) } 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. // 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 } 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" def.manifestAddendProperties["interop"] = "true"
gen.addManifestProperties(def.manifestAddendProperties) stubIrContext.addManifestProperties(def.manifestAddendProperties)
manifestAddend?.parentFile?.mkdirs() manifestAddend?.parentFile?.mkdirs()
manifestAddend?.let { def.manifestAddendProperties.storeProperties(it) } 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 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) "-c", outCFile.absolutePath, "-o", outOFile.absolutePath)
runCmd(compilerCmd, verbose) runCmd(compilerCmd, verbose)
@@ -282,7 +283,7 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
} else if (flavor == KotlinPlatform.NATIVE) { } else if (flavor == KotlinPlatform.NATIVE) {
val outBcName = libName + ".bc" val outBcName = libName + ".bc"
val outLib = File(nativeLibsDir, outBcName) 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) "-emit-llvm", "-c", outCFile.absolutePath, "-o", outLib.absolutePath)
runCmd(compilerCmd, verbose) runCmd(compilerCmd, verbose)
+2 -2
View File
@@ -71,7 +71,7 @@ task copyGenerated(type: Copy) {
task deleteGenerated(type: Delete) { task deleteGenerated(type: Delete) {
dependsOn('copyGenerated') dependsOn('copyGenerated')
delete 'build/generated' delete 'build/generated/source/proto/compiler/java'
} }
task renamePackage { task renamePackage {
@@ -171,7 +171,7 @@ def commonSrc = file('build/stdlib')
task unzipStdlibSources(type: CopyCommonSources) { task unzipStdlibSources(type: CopyCommonSources) {
outputDir commonSrc outputDir commonSrc
sourcePaths configurations.kotlinCommonSources.files sourcePaths configurations.kotlinCommonSources
} }
final List<File> stdLibSrc = [ final List<File> stdLibSrc = [
@@ -160,16 +160,14 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(PURGE_USER_LIBS, arguments.purgeUserLibs) put(PURGE_USER_LIBS, arguments.purgeUserLibs)
put(VERIFY_IR, arguments.verifyIr) if (arguments.verifyCompiler != null)
put(VERIFY_DESCRIPTORS, arguments.verifyDescriptors) put(VERIFY_COMPILER, arguments.verifyCompiler == "true")
put(VERIFY_BITCODE, arguments.verifyBitCode) put(VERIFY_BITCODE, arguments.verifyBitCode)
put(ENABLED_PHASES, put(ENABLED_PHASES,
arguments.enablePhases.toNonNullList()) arguments.enablePhases.toNonNullList())
put(DISABLED_PHASES, put(DISABLED_PHASES,
arguments.disablePhases.toNonNullList()) arguments.disablePhases.toNonNullList())
put(VERBOSE_PHASES,
arguments.verbosePhases.toNonNullList())
put(LIST_PHASES, arguments.listPhases) put(LIST_PHASES, arguments.listPhases)
put(COMPATIBLE_COMPILER_VERSIONS, put(COMPATIBLE_COMPILER_VERSIONS,
@@ -179,13 +177,13 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(MEMORY_MODEL, when (arguments.memoryModel) { put(MEMORY_MODEL, when (arguments.memoryModel) {
"relaxed" -> { "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 MemoryModel.RELAXED
} }
"strict" -> MemoryModel.STRICT "strict" -> MemoryModel.STRICT
else -> { else -> {
configuration.report(ERROR, "Unsupported memory model ${arguments.memoryModel}") 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") @Argument(value="-include-binary", deprecatedName = "-includeBinary", shortName = "-ib", valueDescription = "<path>", description = "Pack external binary within the klib")
var includeBinaries: Array<String>? = null 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 var libraries: Array<String>? = null
@Argument(value = "-library-version", shortName = "-lv", valueDescription = "<version>", description = "Set library version") @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") @Argument(value="-module-name", deprecatedName = "-module_name", valueDescription = "<name>", description = "Specify a name for the compilation module")
var moduleName: String? = null 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 var nativeLibraries: Array<String>? = null
@Argument(value = "-nodefaultlibs", description = "Don't link the libraries from dist/klib automatically") @Argument(value = "-nodefaultlibs", description = "Don't link the libraries from dist/klib automatically")
@@ -120,7 +121,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = "-Xexport-library", value = "-Xexport-library",
valueDescription = "<path>", valueDescription = "<path>",
description = "Path to the library to be included into produced framework API\n" + 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 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") @Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method")
var verifyBitCode: Boolean = false var verifyBitCode: Boolean = false
@Argument(value = "-Xverify-descriptors", deprecatedName = "--verify_descriptors", description = "Verify descriptor tree") @Argument(value = "-Xverify-compiler", description = "Verify compiler")
var verifyDescriptors: Boolean = false var verifyCompiler: String? = null
@Argument(value = "-Xverify-ir", deprecatedName = "--verify_ir", description = "Verify IR")
var verifyIr: Boolean = false
@Argument( @Argument(
value = "-friend-modules", value = "-friend-modules",
@@ -183,7 +182,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument( @Argument(
value = "-Xlibrary-to-cover", value = "-Xlibrary-to-cover",
valueDescription = "<path>", valueDescription = "<path>",
description = "Path to library that should be covered." description = "Path to library that should be covered.",
delimiter = ""
) )
var coveredLibraries: Array<String>? = null 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.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
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.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -44,6 +41,8 @@ private fun KonanSymbols.getTypeConversionImpl(
}?.symbol }?.symbol
} }
internal object DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION : IrDeclarationOriginImpl("INLINE_CLASS_SPECIAL_FUNCTION")
internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.lazyMapMember { inlinedClass -> internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.lazyMapMember { inlinedClass ->
assert(inlinedClass.isUsedAsBoxClass()) assert(inlinedClass.isUsedAsBoxClass())
assert(inlinedClass.parent is IrFile) { "Expected top level inline class" } 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() val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl( IrFunctionImpl(
startOffset, endOffset, startOffset, endOffset,
IrDeclarationOrigin.DEFINED, DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor), IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<${inlinedClass.name}-box>"), Name.special("<${inlinedClass.name}-box>"),
Visibilities.PUBLIC, Visibilities.PUBLIC,
@@ -114,7 +113,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
val descriptor = WrappedSimpleFunctionDescriptor() val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl( IrFunctionImpl(
startOffset, endOffset, startOffset, endOffset,
IrDeclarationOrigin.DEFINED, DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor), IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<${inlinedClass.name}-unbox>"), Name.special("<${inlinedClass.name}-unbox>"),
Visibilities.PUBLIC, Visibilities.PUBLIC,
@@ -7,10 +7,11 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
internal fun IrClass.isNonGeneratedAnnotation(): Boolean = internal fun IrClass.isNonGeneratedAnnotation(): Boolean =
this.kind == ClassKind.ANNOTATION_CLASS && this.kind == ClassKind.ANNOTATION_CLASS &&
!this.descriptor.annotations.hasAnnotation(serialInfoAnnotationFqName) !this.annotations.hasAnnotation(serialInfoAnnotationFqName)
private val serialInfoAnnotationFqName = FqName("kotlinx.serialization.SerialInfo") 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.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor 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.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr 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.library.SerializedMetadata
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
@@ -351,11 +349,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
moduleDescriptor.deepPrint() moduleDescriptor.deepPrint()
} }
fun verifyIr() {
val module = irModule ?: return
validateIrModule(this, module)
}
fun printIr() { fun printIr() {
if (irModule == null) return if (irModule == null) return
separator("IR:") separator("IR:")
@@ -418,7 +411,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun verify() { fun verify() {
verifyDescriptors() verifyDescriptors()
verifyIr()
verifyBitCode() verifyBitCode()
} }
@@ -48,6 +48,11 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val memoryModel: MemoryModel get() = configuration.get(KonanConfigKeys.MEMORY_MODEL)!! 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 { init {
if (!platformManager.isEnabled(target)) { if (!platformManager.isEnabled(target)) {
error("Target ${target.visibleName} is not available on the ${HostManager.hostName} host") error("Target ${target.visibleName} is not available on the ${HostManager.hostName} host")
@@ -102,18 +102,14 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("directory for temporary files") = CompilerConfigurationKey.create("directory for temporary files")
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean> val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify bitcode") = CompilerConfigurationKey.create("verify bitcode")
val VERIFY_DESCRIPTORS: CompilerConfigurationKey<Boolean> val VERIFY_COMPILER: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify descriptors") = CompilerConfigurationKey.create("verify compiler")
val VERIFY_IR: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify ir")
val VERBOSE_PHASES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("verbose backend phases")
val DEBUG_INFO_VERSION: CompilerConfigurationKey<Int> val DEBUG_INFO_VERSION: CompilerConfigurationKey<Int>
= CompilerConfigurationKey.create("debug info format version") = CompilerConfigurationKey.create("debug info format version")
val COVERAGE: CompilerConfigurationKey<Boolean> val COVERAGE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("emit coverage info for sources") = CompilerConfigurationKey.create("emit coverage info for sources")
val LIBRARIES_TO_COVER: CompilerConfigurationKey<List<String>> 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?> val PROFRAW_PATH: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("path to *.profraw coverage output") = CompilerConfigurationKey.create("path to *.profraw coverage output")
val OBJC_GENERICS: CompilerConfigurationKey<Boolean> 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" internal const val NON_NULL_NATIVE_PTR_NAME = "NonNullNativePtr"
object KonanFqNames { object KonanFqNames {
val packageName = FqName("kotlin.native") val packageName = FqName("kotlin.native")
val internalPackageName = FqName("kotlin.native.internal") val internalPackageName = FqName("kotlin.native.internal")
val nativePtr = internalPackageName.child(Name.identifier(NATIVE_PTR_NAME)).toUnsafe() val nativePtr = internalPackageName.child(Name.identifier(NATIVE_PTR_NAME)).toUnsafe()
val nonNullNativePtr = internalPackageName.child(Name.identifier(NON_NULL_NATIVE_PTR_NAME)).toUnsafe() val nonNullNativePtr = internalPackageName.child(Name.identifier(NON_NULL_NATIVE_PTR_NAME)).toUnsafe()
val throws = FqName("kotlin.native.Throws") 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.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment 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( private fun makeKonanFileLoweringPhase(
lowering: (Context) -> FileLoweringPass, lowering: (Context) -> FileLoweringPass,
name: String, name: String,
description: String, description: String,
prerequisite: Set<AnyNamedPhase> = emptySet() prerequisite: Set<AnyNamedPhase> = emptySet()
) = makeIrFilePhase(lowering, name, description, prerequisite) ) = makeIrFilePhase(lowering, name, description, prerequisite, actions = filePhaseActions)
private fun makeKonanModuleLoweringPhase( private fun makeKonanModuleLoweringPhase(
lowering: (Context) -> FileLoweringPass, lowering: (Context) -> FileLoweringPass,
name: String, name: String,
description: String, description: String,
prerequisite: Set<AnyNamedPhase> = emptySet() prerequisite: Set<AnyNamedPhase> = emptySet()
) = makeIrModulePhase(lowering, name, description, prerequisite) ) = makeIrModulePhase(lowering, name, description, prerequisite, actions = modulePhaseActions)
internal fun makeKonanFileOpPhase( internal fun makeKonanFileOpPhase(
op: (Context, IrFile) -> Unit, op: (Context, IrFile) -> Unit,
@@ -39,7 +41,8 @@ internal fun makeKonanFileOpPhase(
op(context, input) op(context, input)
return input return input
} }
} },
actions = filePhaseActions
) )
internal fun makeKonanModuleOpPhase( internal fun makeKonanModuleOpPhase(
@@ -54,7 +57,8 @@ internal fun makeKonanModuleOpPhase(
op(context, input) op(context, input)
return input return input
} }
} },
actions = modulePhaseActions
) )
internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase( internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase(
@@ -79,7 +83,8 @@ internal val inlinePhase = namedIrModulePhase(
name = "Inline", name = "Inline",
description = "Functions inlining", description = "Functions inlining",
prerequisite = setOf(lowerBeforeInlinePhase), prerequisite = setOf(lowerBeforeInlinePhase),
nlevels = 0 nlevels = 0,
actions = modulePhaseActions
) )
internal val lowerAfterInlinePhase = makeKonanModuleOpPhase( internal val lowerAfterInlinePhase = makeKonanModuleOpPhase(
@@ -99,24 +104,6 @@ internal val interopPart1Phase = makeKonanModuleLoweringPhase(
prerequisite = setOf(inlinePhase) 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 */ /* IrFile phases */
internal val lateinitPhase = makeKonanFileLoweringPhase( internal val lateinitPhase = makeKonanFileLoweringPhase(
@@ -284,11 +271,8 @@ internal val bridgesPhase = makeKonanFileOpPhase(
prerequisite = setOf(coroutinesPhase) prerequisite = setOf(coroutinesPhase)
) )
internal val autoboxPhase = makeKonanFileOpPhase( internal val autoboxPhase = makeKonanFileLoweringPhase(
{ context, irFile -> ::Autoboxing,
// validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished.
Autoboxing(context).lower(irFile)
},
name = "Autobox", name = "Autobox",
description = "Autoboxing of primitive types", description = "Autoboxing of primitive types",
prerequisite = setOf(bridgesPhase, coroutinesPhase) prerequisite = setOf(bridgesPhase, coroutinesPhase)
@@ -14,10 +14,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.constructedClass import org.jetbrains.kotlin.ir.util.*
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.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
@@ -61,8 +58,7 @@ fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
} }
fun IrClass.isExternalObjCClass(): Boolean = this.isObjCClass() && fun IrClass.isExternalObjCClass(): Boolean = this.isObjCClass() &&
(this as IrDeclaration).parentDeclarationsWithSelf.filterIsInstance<IrClass>().any { (this as IrDeclaration).parentDeclarationsWithSelf.filterIsInstance<IrClass>().any {
it.annotations.hasAnnotation(externalObjCClassFqName) || it.annotations.hasAnnotation(externalObjCClassFqName)
it.descriptor.annotations.hasAnnotation(externalObjCClassFqName)
} }
fun ClassDescriptor.isObjCForwardDeclaration(): Boolean = fun ClassDescriptor.isObjCForwardDeclaration(): Boolean =
@@ -140,9 +136,9 @@ fun FunctionDescriptor.getObjCMethodInfo(): ObjCMethodInfo? = this.getObjCMethod
fun IrFunction.isObjCBridgeBased(): Boolean { fun IrFunction.isObjCBridgeBased(): Boolean {
assert(this.isReal) assert(this.isReal)
return this.descriptor.annotations.hasAnnotation(objCMethodFqName) || return this.annotations.hasAnnotation(objCMethodFqName) ||
this.descriptor.annotations.hasAnnotation(objCFactoryFqName) || this.annotations.hasAnnotation(objCFactoryFqName) ||
this.descriptor.annotations.hasAnnotation(objCConstructorFqName) 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. // TODO-DCE-OBJC-INIT: Selector should be preserved by DCE.
fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? { fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
return this.descriptor.annotations.findAnnotation(objCConstructorFqName)?.let { return this.annotations.findAnnotation(objCConstructorFqName)?.let {
val initSelector = it.getStringValue("initSelector") val initSelector = it.getStringValue("initSelector")
this.constructedClass.declarations.asSequence() this.constructedClass.declarations.asSequence()
.filterIsInstance<IrSimpleFunction>() .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? { fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
@@ -1,6 +1,6 @@
package org.jetbrains.kotlin.backend.konan 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.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable 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.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable 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.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import java.util.Collections.emptySet 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( internal fun konanUnitPhase(
name: String, name: String,
description: String, description: String,
@@ -128,8 +165,6 @@ internal val psiToIrPhase = konanUnitPhase(
irModule = module irModule = module
irModules = deserializer.modules irModules = deserializer.modules
ir.symbols = symbols ir.symbols = symbols
// validateIrModule(this, module)
}, },
name = "Psi2Ir", name = "Psi2Ir",
description = "Psi to IR conversion", description = "Psi to IR conversion",
@@ -169,12 +204,6 @@ internal val copyDefaultValuesToActualPhase = konanUnitPhase(
description = "Copy default values from expect to actual declarations" 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( internal val serializerPhase = konanUnitPhase(
op = { op = {
val declarationTable = KonanDeclarationTable(irModule!!.irBuiltins, DescriptorTable()) val declarationTable = KonanDeclarationTable(irModule!!.irBuiltins, DescriptorTable())
@@ -213,7 +242,6 @@ internal val allLoweringsPhase = namedIrModulePhase(
inlinePhase then inlinePhase then
lowerAfterInlinePhase then lowerAfterInlinePhase then
interopPart1Phase then interopPart1Phase then
patchDeclarationParents1Phase then
performByIrFile( performByIrFile(
name = "IrLowerByFile", name = "IrLowerByFile",
description = "IR Lowering by file", description = "IR Lowering by file",
@@ -242,9 +270,8 @@ internal val allLoweringsPhase = namedIrModulePhase(
bridgesPhase then bridgesPhase then
autoboxPhase then autoboxPhase then
returnsInsertionPhase returnsInsertionPhase
) then ),
checkDeclarationParentsPhase actions = setOf(defaultDumper, ::moduleValidationCallback)
// validateIrModulePhase // Temporarily disabled until moving to new IR finished.
) )
internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper( internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper(
@@ -313,7 +340,6 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
destroySymbolTablePhase then destroySymbolTablePhase then
irGeneratorPluginsPhase then irGeneratorPluginsPhase then
copyDefaultValuesToActualPhase then copyDefaultValuesToActualPhase then
patchDeclarationParents0Phase then
serializerPhase then serializerPhase then
namedUnitPhase( namedUnitPhase(
name = "Backend", name = "Backend",
@@ -347,5 +373,6 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
switch(buildDFGPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)) switch(buildDFGPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION))
switch(devirtualizationPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)) switch(devirtualizationPhase, config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION))
switch(dcePhase, 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?, superQualifier: IrClassSymbol?,
receiver: IrExpression, receiver: IrExpression,
arguments: List<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) } val messenger = irCall(if (isStret) {
?: builder.irNullNativePtr(symbols)
val messenger = builder.irCall(if (isStret) {
symbols.interopGetMessengerStret symbols.interopGetMessengerStret
} else { } else {
symbols.interopGetMessenger symbols.interopGetMessenger
}.owner).apply { }.owner).apply {
putValueArgument(0, superClass) // TODO: check superClass statically. putValueArgument(0, irGet(superClass)) // TODO: check superClass statically.
} }
val targetPtrParameter = callBuilder.passThroughBridge( val targetPtrParameter = callBuilder.passThroughBridge(
@@ -320,7 +320,7 @@ internal fun KotlinStubs.generateObjCCall(
val targetFunctionName = "targetPtr" val targetFunctionName = "targetPtr"
val preparedReceiver = if (method.consumesReceiver()) { val preparedReceiver = if (method.consumesReceiver()) {
builder.irCall(symbols.interopObjCRetain.owner).apply { irCall(symbols.interopObjCRetain.owner).apply {
putValueArgument(0, receiver) putValueArgument(0, receiver)
} }
} else { } else {
@@ -328,9 +328,9 @@ internal fun KotlinStubs.generateObjCCall(
} }
val receiverOrSuper = if (superQualifier != null) { val receiverOrSuper = if (superQualifier != null) {
builder.irCall(symbols.interopCreateObjCSuperStruct.owner).apply { irCall(symbols.interopCreateObjCSuperStruct.owner).apply {
putValueArgument(0, preparedReceiver) putValueArgument(0, preparedReceiver)
putValueArgument(1, superClass) putValueArgument(1, irGet(superClass))
} }
} else { } else {
preparedReceiver preparedReceiver
@@ -355,7 +355,7 @@ internal fun KotlinStubs.generateObjCCall(
callBuilder.emitCBridge() callBuilder.emitCBridge()
return result +result
} }
private fun IrBuilderWithScope.getObjCClass(symbols: KonanSymbols, symbol: IrClassSymbol): IrExpression { 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") } .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. // Make sure external stubs always get proper annotaions.
private fun IrDeclaration.hasCCallAnnotation(name: String): Boolean = private fun IrDeclaration.hasCCallAnnotation(name: String): Boolean =
this.annotations.hasAnnotation(cCall.child(Name.identifier(name))) || this.annotations.hasAnnotation(cCall.child(Name.identifier(name)))
this.descriptor.annotations.hasAnnotation(cCall.child(Name.identifier(name)))
private fun IrValueParameter.isWCStringParameter() = hasCCallAnnotation("WCString") private fun IrValueParameter.isWCStringParameter() = hasCCallAnnotation("WCString")
@@ -1170,7 +1168,6 @@ private class ObjCBlockPointerValuePassing(
Name.identifier("blockHolder"), Name.identifier("blockHolder"),
isMutable = false, owner = irClass isMutable = false, owner = irClass
) )
irClass.addChild(blockHolderField)
val constructorDescriptor = WrappedClassConstructorDescriptor() val constructorDescriptor = WrappedClassConstructorDescriptor()
val constructor = IrConstructorImpl( val constructor = IrConstructorImpl(
@@ -5,17 +5,19 @@
package org.jetbrains.kotlin.backend.konan.descriptors 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.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.descriptors.*
import org.jetbrains.kotlin.ir.declarations.* 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.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.*
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.types.SimpleType 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 } return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT }
} }
// TODO: don't forget to remove descriptor access here.
internal val IrFunction.isTypedIntrinsic: Boolean internal val IrFunction.isTypedIntrinsic: Boolean
get() = this.descriptor.isTypedIntrinsic get() = annotations.hasAnnotation(KonanFqNames.typedIntrinsic)
internal val IrDeclaration.isFrozen: Boolean
get() = this.descriptor.isFrozen
internal val arrayTypes = setOf( internal val arrayTypes = setOf(
"kotlin.Array", "kotlin.Array",
@@ -243,3 +241,27 @@ fun IrDeclaration.findTopLevelDeclaration(): IrDeclaration = when {
else -> else ->
(this.parent as IrDeclaration).findTopLevelDeclaration() (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.common.atMostOne
import org.jetbrains.kotlin.backend.konan.RuntimeNames 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.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns 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.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.konanModuleOrigin import org.jetbrains.kotlin.descriptors.konan.konanModuleOrigin
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName 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.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module 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.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment 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.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
/** /**
* Implementation of given method. * Implementation of given method.
@@ -172,31 +161,6 @@ internal val DeclarationDescriptor.isExpectMember: Boolean
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this) 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 { private fun sourceByIndex(descriptor: CallableMemberDescriptor, index: Int): SourceFile {
val fragment = descriptor.findPackage() as KonanPackageFragment val fragment = descriptor.findPackage() as KonanPackageFragment
return fragment.sourceFileMap.sourceFile(index) 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 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 listOfInternal = internalFunction("listOfInternal")
val threadLocal = val threadLocal = symbolTable.referenceClass(
context.builtIns.builtInsModule.findClassAcrossModuleDependencies( 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( 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: String): IrClassSymbol = topLevelClass(FqName(fqName))
private fun topLevelClass(fqName: FqName): IrClassSymbol = classById(ClassId.topLevel(fqName)) private fun topLevelClass(fqName: FqName): IrClassSymbol = classById(ClassId.topLevel(fqName))
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.ir package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.common.atMostOne 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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -69,14 +68,7 @@ val IrClass.isFinalClass: Boolean
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing() fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? { fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? {
val annotation = this.annotations.findAnnotation(fqName) val annotation = this.annotations.findAnnotation(fqName) ?: return null
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)
}
for (index in 0 until annotation.valueArgumentsCount) { for (index in 0 until annotation.valueArgumentsCount) {
val parameter = annotation.symbol.owner.valueParameters[index] val parameter = annotation.symbol.owner.valueParameters[index]
if (parameter.name == Name.identifier(argumentName)) { 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 } 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, fun buildSimpleAnnotation(irBuiltIns: IrBuiltIns, startOffset: Int, endOffset: Int,
annotationClass: IrClass, vararg args: String): IrConstructorCall { annotationClass: IrClass, vararg args: String): IrConstructorCall {
val constructor = annotationClass.constructors.single() 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.backend.konan.llvm.KonanMangler.isExported
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.* 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.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.backend.konan.isInlinedNative
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.library.uniqueName import org.jetbrains.kotlin.library.uniqueName
@@ -36,8 +34,6 @@ object KonanMangler : KotlinManglerImpl() {
override val IrType.isInlined override val IrType.isInlined
get() = this.isInlinedNative() get() = this.isInlinedNative()
override val String.hashMangle get() = this.localHash.value
/** /**
* Defines whether the declaration is exported, i.e. visible from other modules. * Defines whether the declaration is exported, i.e. visible from other modules.
* *
@@ -47,20 +43,19 @@ object KonanMangler : KotlinManglerImpl() {
*/ */
override fun IrDeclaration.isPlatformSpecificExported(): Boolean { override fun IrDeclaration.isPlatformSpecificExported(): Boolean {
// TODO: revise // TODO: revise
val descriptorAnnotations = this.descriptor.annotations if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
if (descriptorAnnotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported. // Treat any `@SymbolName` declaration as exported.
return true return true
} }
if (descriptorAnnotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) { if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
// Treat any `@ExportForCppRuntime` declaration as exported. // Treat any `@ExportForCppRuntime` declaration as exported.
return true return true
} }
if (descriptorAnnotations.hasAnnotation(RuntimeNames.cnameAnnotation)) { if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
// Treat `@CName` declaration as exported. // Treat `@CName` declaration as exported.
return true return true
} }
if (descriptorAnnotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) { if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
return true return true
} }
@@ -109,13 +104,13 @@ object KonanMangler : KotlinManglerImpl() {
} }
if (isExternal) { if (isExternal) {
this.descriptor.externalSymbolOrThrow()?.let { this.externalSymbolOrThrow()?.let {
return it return it
} }
} }
this.descriptor.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let { this.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let {
val name = getAnnotationValue(it) ?: this.name.asString() val name = it.getAnnotationValue() ?: this.name.asString()
return name // no wrapping currently required return name // no wrapping currently required
} }
@@ -308,7 +308,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
fun checkMainThread(exceptionHandler: ExceptionHandler) { 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) { 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 allocArrayFunction = importModelSpecificRtFunction("AllocArrayInstance")
val initInstanceFunction = importModelSpecificRtFunction("InitInstance") val initInstanceFunction = importModelSpecificRtFunction("InitInstance")
val initSharedInstanceFunction = importModelSpecificRtFunction("InitSharedInstance") val initSharedInstanceFunction = importModelSpecificRtFunction("InitSharedInstance")
val updateHeapRefFunction = importRtFunction("UpdateHeapRef") val updateHeapRefFunction = importModelSpecificRtFunction("UpdateHeapRef")
val updateStackRefFunction = importRtFunction("UpdateStackRef") val updateStackRefFunction = importModelSpecificRtFunction("UpdateStackRef")
val updateReturnRefFunction = importRtFunction("UpdateReturnRef") val updateReturnRefFunction = importModelSpecificRtFunction("UpdateReturnRef")
val enterFrameFunction = importRtFunction("EnterFrame") val enterFrameFunction = importModelSpecificRtFunction("EnterFrame")
val leaveFrameFunction = importRtFunction("LeaveFrame") val leaveFrameFunction = importModelSpecificRtFunction("LeaveFrame")
val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod") val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod")
val isInstanceFunction = importRtFunction("IsInstance") val isInstanceFunction = importRtFunction("IsInstance")
val checkInstanceFunction = importRtFunction("CheckInstance") 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. * that can be found in the LICENSE file.
*/ */
@@ -9,18 +9,18 @@ import kotlinx.cinterop.allocArrayOf
import kotlinx.cinterop.memScoped import kotlinx.cinterop.memScoped
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.ir.SourceManager.FileEntry import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrFunction 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.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.CURRENT
import org.jetbrains.kotlin.konan.KonanVersion import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
internal object DWARF { internal object DWARF {
val producer = "konanc ${KonanVersion.CURRENT} / kotlin-compiler: ${KotlinVersion.CURRENT}" 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>() val inlinedSubprograms = mutableMapOf<IrFunction, DISubprogramRef>()
var builder: DIBuilderRef? = null var builder: DIBuilderRef? = null
var module: DIModuleRef? = null var module: DIModuleRef? = null
var types = mutableMapOf<KotlinType, DITypeOpaqueRef>() var types = mutableMapOf<IrType, DITypeOpaqueRef>()
val llvmTypes = mapOf<KotlinType, LLVMTypeRef>( val llvmTypes = mapOf<IrType, LLVMTypeRef>(
context.builtIns.booleanType to context.llvm.llvmInt8, context.irBuiltIns.booleanType to context.llvm.llvmInt8,
context.builtIns.byteType to context.llvm.llvmInt8, context.irBuiltIns.byteType to context.llvm.llvmInt8,
context.builtIns.charType to context.llvm.llvmInt8, context.irBuiltIns.charType to context.llvm.llvmInt8,
context.builtIns.shortType to context.llvm.llvmInt16, context.irBuiltIns.shortType to context.llvm.llvmInt16,
context.builtIns.intType to context.llvm.llvmInt32, context.irBuiltIns.intType to context.llvm.llvmInt32,
context.builtIns.longType to context.llvm.llvmInt64, context.irBuiltIns.longType to context.llvm.llvmInt64,
context.builtIns.floatType to context.llvm.llvmFloat, context.irBuiltIns.floatType to context.llvm.llvmFloat,
context.builtIns.doubleType to context.llvm.llvmDouble) context.irBuiltIns.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 llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap() 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 llvmTypeAlignments = llvmTypes.map {it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value)}.toMap()
val otherLlvmType = LLVMPointerType(LLVMInt64Type(), 0)!! val otherLlvmType = LLVMPointerType(LLVMInt64Type(), 0)!!
@@ -159,13 +157,12 @@ internal fun generateDebugInfoHeader(context: Context) {
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef { internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
when { 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 -> { else -> {
val classDescriptor = TypeUtils.getClassDescriptor(this)
return when { return when {
classDescriptor != null -> { classOrNull != null -> {
val type = DICreateStructType( val type = DICreateStructType(
refBuilder = context.debugInfo.builder, refBuilder = context.debugInfo.builder,
// TODO: here should be DIFile as scope. // TODO: here should be DIFile as scope.
@@ -182,7 +179,7 @@ internal fun KotlinType.dwarfType(context: Context, targetData: LLVMTargetDataRe
refPlace = null)!! as DITypeOpaqueRef refPlace = null)!! as DITypeOpaqueRef
dwarfPointerType(context, type) 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()) debugInfoBaseType(context, targetData, this.toString(), llvmType(context), encoding(context).value.toInt())
else -> TODO("$this: Does this case really exist?") 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) { context.debugInfo.types.getOrPut(this) {
dwarfType(context, llvmTargetData) dwarfType(context, llvmTargetData)
} }
@@ -201,17 +198,17 @@ private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typ
LLVMSizeOfTypeInBits(targetData, type), LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef
internal val IrFunction.types:List<KotlinType> internal val IrFunction.types:List<IrType>
get() { get() {
val parameters = descriptor.valueParameters.map{it.type} val parameters = valueParameters.map { it.type }
return listOf(descriptor.returnType!!, *parameters.toTypedArray()) 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()) { when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BYTE -> context.llvm.llvmInt8 PrimitiveBinaryType.BYTE -> context.llvm.llvmInt8
PrimitiveBinaryType.SHORT -> context.llvm.llvmInt16 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.FLOAT -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.DOUBLE -> DwarfTypeKind.DW_ATE_float PrimitiveBinaryType.DOUBLE -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.BOOLEAN -> DwarfTypeKind.DW_ATE_boolean PrimitiveBinaryType.BOOLEAN -> DwarfTypeKind.DW_ATE_boolean
PrimitiveBinaryType.POINTER -> DwarfTypeKind.DW_ATE_address PrimitiveBinaryType.POINTER -> DwarfTypeKind.DW_ATE_address
else -> { else -> {
//TODO: not recursive. //TODO: not recursive.
if (UnsignedTypes.isUnsignedType(this)) DwarfTypeKind.DW_ATE_unsigned if (this.isUnsigned()) DwarfTypeKind.DW_ATE_unsigned
else DwarfTypeKind.DW_ATE_signed else DwarfTypeKind.DW_ATE_signed
} }
} }
@@ -242,7 +239,7 @@ internal fun IrFunction.subroutineType(context: Context, llvmTargetData: LLVMTar
return subroutineType(context, llvmTargetData, types) 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 { return memScoped {
DICreateSubroutineType(context.debugInfo.builder, allocArrayOf( DICreateSubroutineType(context.debugInfo.builder, allocArrayOf(
types.map { it.diType(context, llvmTargetData) }), types.map { it.diType(context, llvmTargetData) }),
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf import kotlinx.cinterop.cValuesOf
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.RuntimeNames 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.descriptors.isTypedIntrinsic
import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector
import org.jetbrains.kotlin.backend.konan.reportCompilationError 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.expressions.*
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.dump 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.ir.util.isSuspend
import org.jetbrains.kotlin.name.Name
internal enum class IntrinsicType { internal enum class IntrinsicType {
PLUS, PLUS,
@@ -113,8 +114,8 @@ internal fun tryGetIntrinsicType(callSite: IrFunctionAccessExpression): Intrinsi
private fun getIntrinsicType(callSite: IrFunctionAccessExpression): IntrinsicType { private fun getIntrinsicType(callSite: IrFunctionAccessExpression): IntrinsicType {
val function = callSite.symbol.owner val function = callSite.symbol.owner
val annotation = function.descriptor.annotations.findAnnotation(RuntimeNames.typedIntrinsicAnnotation)!! val annotation = function.annotations.findAnnotation(RuntimeNames.typedIntrinsicAnnotation)!!
val value = annotation.allValueArguments.getValue(Name.identifier("kind")).value as String val value = annotation.getAnnotationValue()!!
return IntrinsicType.valueOf(value) 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. * 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.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.* 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.*
import org.jetbrains.kotlin.backend.konan.ir.NaiveSourceBasedFileEntryImpl import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
import org.jetbrains.kotlin.backend.konan.ir.containsNull import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
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.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.classId 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 { internal enum class FieldStorage {
MAIN_THREAD, MAIN_THREAD,
SHARED, SHARED,
@@ -59,17 +38,18 @@ internal enum class FieldStorage {
// TODO: maybe unannotated singleton objects shall be accessed from main thread only as well? // TODO: maybe unannotated singleton objects shall be accessed from main thread only as well?
val IrClass.objectIsShared get() = val IrClass.objectIsShared get() =
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) !annotations.hasAnnotation(KonanFqNames.threadLocal)
internal val IrField.storageClass: FieldStorage get() { internal val IrField.storageClass: FieldStorage get() {
val descriptor = propertyDescriptor // TODO: Is this correct?
val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations
return when { return when {
descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) -> FieldStorage.THREAD_LOCAL annotations.hasAnnotation(KonanFqNames.threadLocal) -> FieldStorage.THREAD_LOCAL
!isFinal -> FieldStorage.MAIN_THREAD !isFinal -> FieldStorage.MAIN_THREAD
descriptor.annotations.hasAnnotation(sharedAnnotationFqName) -> FieldStorage.SHARED annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorage.SHARED
// TODO: simplify, once IR types are fully there. // TODO: simplify, once IR types are fully there.
type is IrSimpleType && (type as IrSimpleType). (type.classifierOrNull?.owner as? IrAnnotationContainer)
classifier.descriptor.annotations.hasAnnotation(frozenAnnotationFqName) -> FieldStorage.SHARED ?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorage.SHARED
else -> FieldStorage.MAIN_THREAD else -> FieldStorage.MAIN_THREAD
} }
} }
@@ -630,7 +610,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy { private val scope by lazy {
if (!context.shouldContainDebugInfo()) if (!context.shouldContainDebugInfo())
return@lazy null 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) } 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)) 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( is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation(
builder = context.debugInfo.builder, builder = context.debugInfo.builder,
functionScope = locationInfo.scope, functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData), diType = element.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name, name = element.descriptor.name,
file = file, file = file,
line = locationInfo.line, line = locationInfo.line,
@@ -1198,7 +1178,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrValueParameter -> debugInfoParameterLocation( is IrValueParameter -> debugInfoParameterLocation(
builder = context.debugInfo.builder, builder = context.debugInfo.builder,
functionScope = locationInfo.scope, functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData), diType = element.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name, name = element.descriptor.name,
argNo = function.allParameters.indexOf(element) + 1, argNo = function.allParameters.indexOf(element) + 1,
file = file, file = file,
@@ -1452,11 +1432,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
// TODO: rewrite in IR! private fun needMutationCheck(irClass: IrClass): Boolean {
private fun needMutationCheck(descriptor: org.jetbrains.kotlin.descriptors.DeclarationDescriptor): Boolean {
// For now we omit mutation checks on immutable types, as this allows initialization in constructor // 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. // and it is assumed that API doesn't allow to change them.
return !descriptor.isFrozen return !irClass.isFrozen
} }
private fun evaluateSetField(value: IrSetField): LLVMValueRef { 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) { assert(thisPtr.type == codegen.kObjHeaderPtr) {
LLVMPrintTypeToString(thisPtr.type)?.toKString().toString() LLVMPrintTypeToString(thisPtr.type)?.toKString().toString()
} }
if (needMutationCheck(value.descriptor.containingDeclaration)) { if (needMutationCheck(value.symbol.owner.parentAsClass)) {
functionGenerationContext.call(context.llvm.mutationCheck, functionGenerationContext.call(context.llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)), listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, ExceptionHandler.Caller) 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 val scope = currentCodeContext.classScope() as? ClassScope ?: return
if (!scope.isExported || !context.shouldContainDebugInfo()) return if (!scope.isExported || !context.shouldContainDebugInfo()) return
val irFile = (currentCodeContext.fileScope() as FileScope).file val irFile = (currentCodeContext.fileScope() as FileScope).file
val sizeInBits = expression.descriptor.type.size(context) val sizeInBits = expression.type.size(context)
scope.offsetInBits += sizeInBits scope.offsetInBits += sizeInBits
val alignInBits = expression.descriptor.type.alignment(context) val alignInBits = expression.type.alignment(context)
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits) scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType( scope.members.add(DICreateMemberType(
@@ -1799,7 +1778,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
alignInBits = alignInBits, alignInBits = alignInBits,
offsetInBits = scope.offsetInBits, offsetInBits = scope.offsetInBits,
flags = 0, 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.isInterface)
assert(irClass.isExternalObjCClass()) assert(irClass.isExternalObjCClass())
val annotation = irClass.descriptor.annotations.findAnnotation(externalObjCClassFqName)!! val annotation = irClass.annotations.findAnnotation(externalObjCClassFqName)!!
val protocolGetterName = annotation.getStringValue("protocolGetter") val protocolGetterName = annotation.getStringValue("protocolGetter")
val protocolGetter = context.llvm.externalFunction( val protocolGetter = context.llvm.externalFunction(
protocolGetterName, protocolGetterName,
@@ -8,13 +8,13 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMStoreSizeOfType import llvm.LLVMStoreSizeOfType
import llvm.LLVMValueRef import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.common.atMostOne 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.*
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.constructors 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.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -118,7 +118,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
.filterIsInstance<IrSimpleFunction>() .filterIsInstance<IrSimpleFunction>()
.mapNotNull { .mapNotNull {
val annotation = val annotation =
it.descriptor.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?: it.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
return@mapNotNull null return@mapNotNull null
ObjCMethodDesc( ObjCMethodDesc(
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* 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.isAnnotationClass
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.library.KotlinAbiVersion 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 val EXPORT_TYPE_INFO_FQ_NAME = FqName.fromSegments(listOf("kotlin", "native", "internal", "ExportTypeInfo"))
private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) { 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) { if (annotation != null) {
val name = getAnnotationValue(annotation)!! val name = annotation.getAnnotationValue()!!
// TODO: use LLVMAddAlias. // TODO: use LLVMAddAlias.
val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true) val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true)
LLVMSetInitializer(global, typeInfoGlobal) LLVMSetInitializer(global, typeInfoGlobal)
@@ -5,18 +5,18 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue
import org.jetbrains.kotlin.descriptors.* 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.konan.target.KonanTarget
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
private val retainAnnotationName = FqName("kotlin.native.Retain") private val retainAnnotationName = FqName("kotlin.native.Retain")
private val retainForTargetAnnotationName = FqName("kotlin.native.RetainForTarget") private val retainForTargetAnnotationName = FqName("kotlin.native.RetainForTarget")
internal fun IrFunction.retainAnnotation(target: KonanTarget): Boolean {
internal fun FunctionDescriptor.retainAnnotation(target: KonanTarget): Boolean {
if (this.annotations.findAnnotation(retainAnnotationName) != null) return true if (this.annotations.findAnnotation(retainAnnotationName) != null) return true
val forTarget = this.annotations.findAnnotation(retainForTargetAnnotationName) 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 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.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl 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.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
@@ -401,7 +402,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
startOffset, startOffset,
endOffset, endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
descriptor, IrPropertySymbolImpl(descriptor),
irField.name, irField.name,
irField.visibility, irField.visibility,
Modality.FINAL, 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.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push 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.ir.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -95,11 +94,10 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
if (cur !is IrCall) if (cur !is IrCall)
break break
val argument = if (i < stack.size - 1) stack[i + 1] else expression val argument = if (i < stack.size - 1) stack[i + 1] else expression
val descriptor = cur.descriptor val parameter = cur.symbol.owner.valueParameters.singleOrNull {
val argumentDescriptor = descriptor.valueParameters.singleOrNull {
cur.getValueArgument(it.index) == argument 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 return expression
} }
break break
@@ -10,12 +10,13 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
internal class ContractsDslRemover(val context: Context) : DeclarationContainerLoweringPass { internal class ContractsDslRemover(val context: Context) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { 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 null
else else
listOf(it) 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.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName 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.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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 kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = WrappedFieldDescriptor( val kPropertiesField = WrappedFieldDescriptor().let {
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
).let {
IrFieldImpl( IrFieldImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
@@ -104,6 +105,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
).apply { ).apply {
it.bind(this) it.bind(this)
parent = irFile 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)) putValueArgument(0, irInt(it.index))
} }
val initializer = it.value.initializerExpression!! val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(constructor) initializer.setDeclarationsParent(constructor)
when { when {
initializer is IrConstructorCall -> +initInstanceCall(instance, initializer) 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.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.*
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.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -103,7 +100,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
val defaultValue = parameter.defaultValue ?: continue val defaultValue = parameter.defaultValue ?: continue
defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true)) defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
defaultValue.patchDeclarationParents(loweredEnumConstructor) defaultValue.setDeclarationsParent(loweredEnumConstructor)
} }
return loweredEnumConstructor return loweredEnumConstructor
@@ -129,7 +126,9 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
).apply { ).apply {
it.bind(this) it.bind(this)
parent = constructor.parent 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.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression 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.symbols.*
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper 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.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -77,9 +79,12 @@ internal class ExpectToActualDefaultValueCopier(private val irModule: IrModuleFr
return return
} }
function.findActualForExpected().valueParameters[index].defaultValue = defaultValue.also { val actualForExpected = function.findActualForExpected()
it.expression = it.expression.remapExpectValueSymbols() 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 package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.Symbols 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.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context 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.descriptors.ValueDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement 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.irGet
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -56,9 +54,8 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val actualCallee = getFunctionDeclaration(callee.symbol) val actualCallee = getFunctionDeclaration(callee.symbol)
actualCallee.transformChildrenVoid(this) // Process recursive inline.
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context) val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context)
return inliner.inline() return inliner.inline()
} }
@@ -105,9 +102,9 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent) 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: * 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 { private fun inlineFunction(callSite: IrFunctionAccessExpression,
val copiedCallee = copyIrElement.copy(callee) as IrFunction 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 evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements val statements = (copiedCallee.body as IrBlockBody).statements
@@ -194,6 +195,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
return expression 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 newExpression = super.visitGetValue(expression) as IrGetValue
val argument = substituteMap[newExpression.symbol.owner] ?: return newExpression val argument = substituteMap[newExpression.symbol.owner] ?: return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution. argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return if (argument is IrVariable) { return if (argument is IrGetValueWithoutLocation)
IrGetValueImpl(startOffset = newExpression.startOffset, argument.withLocation(newExpression.startOffset, newExpression.endOffset)
endOffset = newExpression.endOffset, else (copyIrElement.copy(argument) as IrExpression)
symbol = argument.symbol)
} else (copyIrElement.copy(argument) as IrExpression)
} }
//-----------------------------------------------------------------// //-----------------------------------------------------------------//
@@ -225,6 +224,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
return super.visitCall(expression) return super.visitCall(expression)
if (functionArgument is IrFunctionReference) { if (functionArgument is IrFunctionReference) {
functionArgument.transformChildrenVoid(this)
val function = functionArgument.symbol.owner val function = functionArgument.symbol.owner
val functionParameters = function.explicitParameters val functionParameters = function.explicitParameters
val boundFunctionParameters = functionArgument.getArgumentsWithIr() val boundFunctionParameters = functionArgument.getArgumentsWithIr()
@@ -237,33 +237,41 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val immediateCall = with(expression) { val immediateCall = with(expression) {
if (function is IrConstructor) if (function is IrConstructor)
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, function.symbol) IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, function.returnType, function.symbol)
else else
IrCallImpl(startOffset, endOffset, type, functionArgument.symbol) IrCallImpl(startOffset, endOffset, function.returnType, functionArgument.symbol)
}.apply { }.apply {
functionParameters.forEach { functionParameters.forEach {
val argument = val argument =
if (!unboundArgsSet.contains(it)) if (unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
valueParameters[unboundIndex++].second valueParameters[unboundIndex++].second
else {
val arg = boundFunctionParametersMap[it]!!
if (arg is IrGetValueWithoutLocation)
arg.withLocation(expression.startOffset, expression.endOffset)
else arg
}
when (it) { when (it) {
function.dispatchReceiverParameter -> this.dispatchReceiver = argument function.dispatchReceiverParameter ->
function.extensionReceiverParameter -> this.extensionReceiver = argument this.dispatchReceiver = argument.implicitCastIfNeededTo(function.dispatchReceiverParameter!!.type)
else -> putValueArgument(it.index, argument)
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" } assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
for (index in 0 until functionArgument.typeArgumentsCount) for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index)) putTypeArgument(index, functionArgument.getTypeArgument(index))
} }.implicitCastIfNeededTo(expression.type)
return this@FunctionInlining.visitExpression(super.visitExpression(immediateCall)) return this@FunctionInlining.visitExpression(super.visitExpression(immediateCall))
} }
if (functionArgument !is IrBlock) if (functionArgument !is IrBlock)
return super.visitCall(expression) return super.visitCall(expression)
val functionDeclaration = functionArgument.statements[0] as IrFunction 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. 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) 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 { private fun isLambdaCall(irCall: IrCall): Boolean {
val callee = irCall.symbol.owner val callee = irCall.symbol.owner
val dispatchReceiver = callee.dispatchReceiverParameter ?: return false 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> { private fun buildParameterToArgument(callSite: IrFunctionAccessExpression, callee: IrFunction): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<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> { private fun evaluateArguments(functionReference: IrFunctionReference): List<IrStatement> {
val arguments = functionReference.getArgumentsWithIr().map { ParameterToArgument(it.first, it.second) }
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>() val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor() 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. * 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, * 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) { if (it.isInlinableLambdaArgument) {
substituteMap[it.parameter] = it.argumentExpression substituteMap[it.parameter] = it.argumentExpression
(it.argumentExpression as? IrFunctionReference)?.let { evaluationStatements += evaluateArguments(it) }
return@forEach return@forEach
} }
@@ -414,9 +454,28 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
isMutable = false) isMutable = false)
evaluationStatements.add(newVariable) evaluationStatements.add(newVariable)
substituteMap[it.parameter] = newVariable substituteMap[it.parameter] = IrGetValueWithoutLocation(newVariable.symbol)
} }
return evaluationStatements 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 return expression
} }
}) })
initializer.patchDeclarationParents(initializeFun) initializer.setDeclarationsParent(initializeFun)
} }
return initializeFun.symbol return initializeFun.symbol
@@ -166,7 +166,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
if (initializeMethodSymbol == null) { if (initializeMethodSymbol == null) {
assert(declaration.isPrimary) assert(declaration.isPrimary)
for (initializer in initializers) for (initializer in initializers)
initializer.patchDeclarationParents(declaration) initializer.setDeclarationsParent(declaration)
initializers initializers
} else { } else {
val startOffset = it.startOffset val startOffset = it.startOffset
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.backend.konan.lower 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.createDispatchReceiverParameter
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.common.lower.* 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.*
import org.jetbrains.kotlin.backend.konan.cgen.* import org.jetbrains.kotlin.backend.konan.cgen.*
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions 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.builtins.UnsignedTypes
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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.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.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* 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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil 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.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
internal abstract class BaseInteropIrTransformer(private val context: Context) : IrBuildingTransformer(context) { 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 { irClass.declarations.toList().mapNotNull {
when { when {
it is IrSimpleFunction && it.descriptor.annotations.hasAnnotation(interop.objCAction) -> it is IrSimpleFunction && it.annotations.hasAnnotation(interop.objCAction.fqNameSafe) ->
generateActionImp(it) generateActionImp(it)
it is IrProperty && it.descriptor.annotations.hasAnnotation(interop.objCOutlet) -> it is IrProperty && it.annotations.hasAnnotation(interop.objCOutlet.fqNameSafe) ->
generateOutletSetterImp(it) generateOutletSetterImp(it)
it is IrConstructor && it.descriptor.annotations.hasAnnotation(interop.objCOverrideInit) -> it is IrConstructor && it.annotations.hasAnnotation(interop.objCOverrideInit.fqNameSafe) ->
generateOverrideInit(irClass, it) generateOverrideInit(irClass, it)
else -> null else -> null
} }
}.let { irClass.addChildren(it) } }.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) val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
topLevelInitializers.add(irBuilder.getObjCClass(irClass.symbol)) topLevelInitializers.add(irBuilder.getObjCClass(irClass.symbol))
} }
@@ -224,51 +219,26 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
// Generate `override fun init...(...) = this.initBy(...)`: // Generate `override fun init...(...) = this.initBy(...)`:
val resultDescriptor = SimpleFunctionDescriptorImpl.create( val resultDescriptor = WrappedSimpleFunctionDescriptor()
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
)
return IrFunctionImpl( return IrFunctionImpl(
constructor.startOffset, constructor.endOffset, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR, constructor.startOffset, constructor.endOffset,
resultDescriptor, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
irClass.defaultType IrSimpleFunctionSymbolImpl(resultDescriptor),
initMethod.name,
Visibilities.PUBLIC,
Modality.OPEN,
irClass.defaultType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).also { result -> ).also { result ->
resultDescriptor.bind(result)
result.parent = irClass result.parent = irClass
result.createDispatchReceiverParameter() result.createDispatchReceiverParameter()
result.valueParameters += valueParameters constructor.valueParameters.mapTo(result.valueParameters) { it.copyTo(result) }
result.overriddenSymbols.add(initMethod.symbol) result.overriddenSymbols.add(initMethod.symbol)
result.descriptor.overriddenDescriptors = listOf(initMethod.descriptor)
result.body = context.createIrBuilder(result.symbol).irBlockBody(result) { result.body = context.createIrBuilder(result.symbol).irBlockBody(result) {
+irReturn( +irReturn(
@@ -390,54 +360,40 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
} }
} }
val newDescriptor = SimpleFunctionDescriptorImpl.create( val newFunction = WrappedSimpleFunctionDescriptor().let {
function.descriptor.containingDeclaration, IrFunctionImpl(
Annotations.EMPTY, function.startOffset, function.endOffset,
("imp:" + selector).synthesizedName, IrDeclarationOrigin.DEFINED,
CallableMemberDescriptor.Kind.SYNTHESIZED, IrSimpleFunctionSymbolImpl(it),
SourceElement.NO_SOURCE ("imp:$selector").synthesizedName,
) Visibilities.PRIVATE,
Modality.FINAL,
val valueParameters = parameterTypes.mapIndexed { index, it -> returnType,
ValueParameterDescriptorImpl( isInline = false,
newDescriptor, isExternal = false,
null, isTailrec = false,
index, isSuspend = false
Annotations.EMPTY, ).apply {
Name.identifier("p$index"), it.bind(this)
it.toKotlinType(), }
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
} }
newDescriptor.initialize( parameterTypes.mapIndexedTo(newFunction.valueParameters) { index, type ->
null, null, WrappedValueParameterDescriptor().let {
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 ->
IrValueParameterImpl( IrValueParameterImpl(
startOffset, function.startOffset, function.endOffset,
endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
descriptor.valueParameters[index], IrValueParameterSymbolImpl(it),
it, Name.identifier("p$index"),
null 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) { private fun checkKotlinObjCClass(irClass: IrClass) {
val kind = irClass.descriptor.kind val kind = irClass.descriptor.kind
if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT) { if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT) {
@@ -561,7 +505,6 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
builder.at(expression) builder.at(expression)
val constructedClass = outerClasses.peek()!! val constructedClass = outerClasses.peek()!!
val constructedClassDescriptor = constructedClass.descriptor
if (!constructedClass.isObjCClass()) { if (!constructedClass.isObjCClass()) {
return expression return expression
@@ -578,12 +521,13 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
} }
} }
val delegatingCallConstructingClass = expression.symbol.owner.constructedClass
if (!constructedClass.isExternalObjCClass() && if (!constructedClass.isExternalObjCClass() &&
(expression.symbol.owner.constructedClass).isExternalObjCClass()) { delegatingCallConstructingClass.isExternalObjCClass()) {
// Calling super constructor from Kotlin Objective-C class. // Calling super constructor from Kotlin Objective-C class.
assert(constructedClassDescriptor.getSuperClassNotAny() == expression.descriptor.constructedClass) assert(constructedClass.getSuperClassNotAny() == delegatingCallConstructingClass)
val initMethod = expression.symbol.owner.getObjCInitMethod()!! val initMethod = expression.symbol.owner.getObjCInitMethod()!!
@@ -602,14 +546,14 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
val initCall = builder.genLoweredObjCMethodCall( val initCall = builder.genLoweredObjCMethodCall(
initMethodInfo, initMethodInfo,
superQualifier = expression.symbol.owner.constructedClass.symbol, superQualifier = delegatingCallConstructingClass.symbol,
receiver = builder.getRawPtr(builder.irGet(constructedClass.thisReceiver!!)), receiver = builder.getRawPtr(builder.irGet(constructedClass.thisReceiver!!)),
arguments = initMethod.valueParameters.map { expression.getValueArgument(it.index) }, arguments = initMethod.valueParameters.map { expression.getValueArgument(it.index) },
call = expression, call = expression,
method = initMethod method = initMethod
) )
val superConstructor = expression.symbol.owner.constructedClass val superConstructor = delegatingCallConstructingClass
.constructors.single { it.valueParameters.size == 0 }.symbol .constructors.single { it.valueParameters.size == 0 }.symbol
return builder.irBlock(expression) { 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) context.llvmImports.add(function.descriptor.llvmSymbolOrigin)
return generateWithStubs { generateCCall(expression, builder, isInvoke = false) } return generateWithStubs { generateCCall(expression, builder, isInvoke = false) }
} }
@@ -1186,5 +1130,3 @@ private fun IrBuilder.irFloat(value: Float) =
private fun IrBuilder.irDouble(value: Double) = private fun IrBuilder.irDouble(value: Double) =
IrConstImpl.double(startOffset, endOffset, context.irBuiltIns.doubleType, value) 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". // Basic Multilingual Plane, so we could just append data "as is".
builder.append(value.toChar()) builder.append(value.toChar())
} }
expression.putValueArgument(0, IrConstImpl<String>( expression.putValueArgument(0, IrConstImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
context.ir.symbols.immutableBlob.typeWithoutArguments, context.irBuiltIns.stringType,
IrConstKind.String, builder.toString())) IrConstKind.String, builder.toString()))
} else if (expression.symbol.owner.isTypeOfIntrinsic()) { } else if (expression.symbol.owner.isTypeOfIntrinsic()) {
val type = expression.getTypeArgument(0) 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) * 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 return null
} }
private tailrec fun ObjCExportMapper.isHiddenByDeprecation(descriptor: ClassDescriptor): Boolean { private fun ObjCExportMapper.isHiddenByDeprecation(descriptor: ClassDescriptor): Boolean {
if (deprecationResolver == null) return false if (deprecationResolver == null) return false
if (deprecationResolver.isDeprecatedHidden(descriptor)) return true if (deprecationResolver.isDeprecatedHidden(descriptor)) return true
val superClass = descriptor.getSuperClassNotAny() ?: return false
// Note: ObjCExport requires super class of exposed class to be exposed. // Note: ObjCExport requires super class of exposed class to be exposed.
// So hide a class if its super class is hidden: // 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. // 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.*
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.functionName import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.functionName
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.symbolName 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.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.*
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.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isNothing
@@ -601,15 +599,15 @@ internal object DataFlowIR {
} }
val symbol = when { val symbol = when {
it.isExternal || (it.symbol in context.irBuiltIns.irBuiltInsSymbols) -> { it.isExternal || (it.symbol in context.irBuiltIns.irBuiltInsSymbols) -> {
val escapesAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_ESCAPES) val escapesAnnotation = it.annotations.findAnnotation(FQ_NAME_ESCAPES)
val pointsToAnnotation = it.descriptor.annotations.findAnnotation(FQ_NAME_POINTS_TO) val pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO)
@Suppress("UNCHECKED_CAST") @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") @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 { FunctionSymbol.External(name.localHash.value, attributes, it, takeName { name }).apply {
escapes = escapesBitMask 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() = 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 { private fun mapPropertyInitializer(irField: IrField): FunctionSymbol {
functionMap[irField]?.let { return it } functionMap[irField]?.let { return it }
@@ -1047,10 +1047,8 @@ internal object Devirtualization {
} }
} }
private val specialNames = listOf("-box>", "-unbox>") private fun IrExpression.isBoxOrUnboxCall() =
(this is IrCall && symbol.owner.origin == DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION)
// 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 devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG, private fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) { 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.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.hasAnnotation
class KonanIrModuleSerializer( class KonanIrModuleSerializer(
logger: LoggingContext, logger: LoggingContext,
@@ -15,9 +16,9 @@ class KonanIrModuleSerializer(
) : IrModuleSerializer(logger, declarationTable, KonanMangler, bodiesOnlyForInlines) { ) : IrModuleSerializer(logger, declarationTable, KonanMangler, bodiesOnlyForInlines) {
override fun backendSpecificExplicitRoot(declaration: IrFunction) = override fun backendSpecificExplicitRoot(declaration: IrFunction) =
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime) declaration.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)
override fun backendSpecificExplicitRoot(declaration: IrClass) = 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.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker
import org.jetbrains.kotlin.backend.common.serialization.UniqId 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.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.descriptors.ModuleDescriptor 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.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -53,6 +55,16 @@ class KonanIrLinker(
override val ModuleDescriptor.irHeader get() = this.konanLibrary!!.irHeader 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 { val modules: Map<String, IrModuleFragment> get() = mutableMapOf<String, IrModuleFragment>().apply {
deserializersForModules.forEach { deserializersForModules.forEach {
this.put(it.key.konanLibrary!!.libraryName, it.value.module) 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.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.* 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.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.substitute 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.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException 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.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.backend.konan.ir.containsNull
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor 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.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* 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.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl 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.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl 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 private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) { internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val descriptor = WrappedFieldDescriptor( val descriptor = WrappedFieldDescriptor()
if (threadLocal)
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
else
Annotations.EMPTY
)
val irField = IrFieldImpl( val irField = IrFieldImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
@@ -85,7 +75,12 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: Ko
).apply { ).apply {
descriptor.bind(this) 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) 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? { tailrec fun IrDeclaration.getContainingFile(): IrFile? {
val parent = this.parent val parent = this.parent
@@ -322,6 +284,7 @@ fun IrBuilderWithScope.irCatch(type: IrType) =
false false
).apply { ).apply {
descriptor.bind(this) descriptor.bind(this)
parent = this@irCatch.parent
} }
} }
) )
+13 -1
View File
@@ -2357,9 +2357,16 @@ standaloneTest("args0") {
standaloneTest("devirtualization_lateinitInterface") { standaloneTest("devirtualization_lateinitInterface") {
goldValue = "42\n" goldValue = "42\n"
flags = ["-opt"]
source = "codegen/devirtualization/lateinitInterface.kt" 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") { standaloneTest("multiargs") {
arguments = ["AAA", "BB", "C"] arguments = ["AAA", "BB", "C"]
multiRuns = true multiRuns = true
@@ -2867,6 +2874,11 @@ task inline_genericFunctionReference(type: KonanLocalTest) {
source = "codegen/inline/genericFunctionReference.kt" source = "codegen/inline/genericFunctionReference.kt"
} }
task inline_correctOrderFunctionReference(type: KonanLocalTest) {
goldValue = "OK\n"
source = "codegen/inline/correctOrderFunctionReference.kt"
}
task classDeclarationInsideInline(type: KonanLocalTest) { task classDeclarationInsideInline(type: KonanLocalTest) {
source = "codegen/inline/classDeclarationInsideInline.kt" source = "codegen/inline/classDeclarationInsideInline.kt"
goldValue = "test1: 1.0\n1\ntest2\n" goldValue = "test1: 1.0\n1\ntest2\n"
@@ -3500,7 +3512,7 @@ if (isAppleTarget(project)) {
final String dir = "$testOutputFramework/$frameworkName" final String dir = "$testOutputFramework/$frameworkName"
final File lazyHeader = file("$dir/$target-lazy.h") final File lazyHeader = file("$dir/$target-lazy.h")
doFirst { doLast {
final File expectedLazyHeader = file("framework/values/expectedLazy.h") final File expectedLazyHeader = file("framework/values/expectedLazy.h")
if (expectedLazyHeader.readLines() != lazyHeader.readLines()) { 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)openWarning __attribute__((swift_name("openWarning()"))) __attribute__((deprecated("warning")));
- (void)normal __attribute__((swift_name("normal()"))); - (void)normal __attribute__((swift_name("normal()")));
- (int32_t)openNormal __attribute__((swift_name("openNormal()"))); - (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 (readonly) id _Nullable errorVal __attribute__((swift_name("errorVal"))) __attribute__((unavailable("error")));
@property id _Nullable errorVar __attribute__((swift_name("errorVar"))) __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"))); @property (readonly) id _Nullable openErrorVal __attribute__((swift_name("openErrorVal"))) __attribute__((unavailable("error")));
@@ -681,6 +694,11 @@ __attribute__((swift_name("TestDeprecation.ExtendingHidden")))
@interface ValuesTestDeprecationExtendingHidden : NSObject @interface ValuesTestDeprecationExtendingHidden : NSObject
@end; @end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("TestDeprecation.ExtendingHiddenNested")))
@interface ValuesTestDeprecationExtendingHiddenNested : NSObject
@end;
__attribute__((swift_name("TestDeprecationHiddenInterface"))) __attribute__((swift_name("TestDeprecationHiddenInterface")))
@protocol ValuesTestDeprecationHiddenInterface @protocol ValuesTestDeprecationHiddenInterface
@required @required
@@ -698,6 +716,35 @@ __attribute__((swift_name("TestDeprecation.Hidden")))
@interface ValuesTestDeprecationHidden : NSObject @interface ValuesTestDeprecationHidden : NSObject
@end; @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"))) __attribute__((swift_name("TestDeprecation.OpenError")))
@interface ValuesTestDeprecationOpenError : ValuesTestDeprecation @interface ValuesTestDeprecationOpenError : ValuesTestDeprecation
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable("error"))); - (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"))); @property id _Nullable openNormalVar __attribute__((swift_name("openNormalVar")));
@end; @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) @interface ValuesEnumeration (ValuesKt)
- (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()"))); - (ValuesEnumeration *)getAnswer __attribute__((swift_name("getAnswer()")));
@end; @end;
@@ -495,7 +495,9 @@ class TestInvalidIdentifiers {
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
open class TestDeprecation() { open class TestDeprecation() {
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) open class OpenHidden : 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 { @Deprecated("hidden", level = DeprecationLevel.HIDDEN) interface HiddenInterface {
fun effectivelyHidden(): Any fun effectivelyHidden(): Any
@@ -508,7 +510,19 @@ open class TestDeprecation() {
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
fun callEffectivelyHidden(obj: Any): Int = (obj as HiddenInterface).effectivelyHidden() as Int 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() @Suppress("DEPRECATION_ERROR") fun getHidden() = Hidden()
@Deprecated("hidden", level = DeprecationLevel.HIDDEN) constructor(hidden: Byte) : this() @Deprecated("hidden", level = DeprecationLevel.HIDDEN) constructor(hidden: Byte) : this()
@@ -648,6 +662,34 @@ open class TestDeprecation() {
override val openNormalVal: Any? = null override val openNormalVal: Any? = null
override var openNormalVar: 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() {} @Deprecated("hidden", level = DeprecationLevel.HIDDEN) fun hidden() {}
+5 -2
View File
@@ -70,9 +70,12 @@ fun run() {
// hashCode (directly): // hashCode (directly):
if (foo.hashCode() == foo.hash().let { it.toInt() xor (it shr 32).toInt() }) { if (foo.hashCode() == foo.hash().let { it.toInt() xor (it shr 32).toInt() }) {
// toString (virtually): // 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) println(globalString)
autoreleasepool { autoreleasepool {
globalString = "Another global string" globalString = "Another global string"
@@ -9,6 +9,8 @@ import kotlin.test.*
import kotlin.native.ref.* import kotlin.native.ref.*
@Test fun runTest() { @Test fun runTest() {
// TODO: make it work in relaxed model as well.
if (Platform.memoryModel == MemoryModel.RELAXED) return
val weakRefToTrashCycle = createLoop() val weakRefToTrashCycle = createLoop()
kotlin.native.internal.GC.collect() kotlin.native.internal.GC.collect()
assertNull(weakRefToTrashCycle.get()) assertNull(weakRefToTrashCycle.get())
@@ -9,7 +9,7 @@ import kotlin.test.*
import kotlin.native.concurrent.* import kotlin.native.concurrent.*
object Immutable { object AnObject {
var x = 1 var x = 1
} }
@@ -19,11 +19,17 @@ object Mutable {
} }
@Test fun runTest() { @Test fun runTest() {
assertEquals(1, Immutable.x) assertEquals(1, AnObject.x)
assertFailsWith<InvalidMutabilityException> { if (Platform.memoryModel == MemoryModel.STRICT) {
Immutable.x++ assertFailsWith<InvalidMutabilityException> {
AnObject.x++
}
assertEquals(1, AnObject.x)
} else {
AnObject.x++
assertEquals(2, AnObject.x)
} }
assertEquals(1, Immutable.x)
Mutable.x++ Mutable.x++
assertEquals(3, Mutable.x) assertEquals(3, Mutable.x)
println("OK") println("OK")
@@ -45,6 +45,8 @@ fun testSingleData(workers: Array<Worker>) {
} }
fun testFrozenLazy(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>() val set = mutableSetOf<Int>()
for (attempt in 1 .. 3) { for (attempt in 1 .. 3) {
val futures = Array(workers.size, { workerIndex -> val futures = Array(workers.size, { workerIndex ->
@@ -45,7 +45,7 @@ val topSharedData = Data(43)
false false
} }
}).consume { }).consume {
result -> assertEquals(false, result) result -> assertEquals(Platform.memoryModel == MemoryModel.RELAXED, result)
} }
worker.execute(TransferMode.SAFE, { -> }, { worker.execute(TransferMode.SAFE, { -> }, {
@@ -65,7 +65,7 @@ val topSharedData = Data(43)
false false
} }
}).consume { }).consume {
result -> assertEquals(false, result) result -> assertEquals(Platform.memoryModel == MemoryModel.RELAXED, result)
} }
worker.execute(TransferMode.SAFE, { -> }, { worker.execute(TransferMode.SAFE, { -> }, {
@@ -164,3 +164,21 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
future.result future.result
worker.requestTermination().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) { } catch (e: IllegalStateException) {
null null
} }
if (future != null) if (future != null && Platform.memoryModel == MemoryModel.STRICT)
println("Fail 1") println("Fail 1")
if (dataParam.int != 17) println("Fail 2") if (dataParam.int != 17) println("Fail 2")
worker.requestTermination().result worker.requestTermination().result
@@ -14,7 +14,6 @@ import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.process.ExecSpec import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
import java.io.File import java.io.File
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
@@ -151,10 +150,16 @@ open class KonanGTest : KonanTest() {
executor = project.executor::execute, executor = project.executor::execute,
executable = executable, executable = executable,
args = arguments args = arguments
).let { ).run {
parse(it.stdOut) parse(stdOut)
it.print() println("""
check(it.exitCode == 0) { "Test $executable exited with ${it.exitCode}" } |stdout:
|$stdOut
|stderr:
|$stdErr
|exit code: $exitCode
""".trimMargin())
check(exitCode == 0) { "Test $executable exited with $exitCode" }
} }
private fun parse(output: String) = statistics.apply { 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. // 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 // It should capture output from the build task using Gradle's LoggerManager and LoggerOutput
val compilationLog = project.file("$executable.compilation.log").readText() 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.check()
output.print() output.print()
@@ -15,6 +15,7 @@ import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.tasks.AbstractExecTask import org.gradle.api.tasks.AbstractExecTask
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.jetbrains.report.* import org.jetbrains.report.*
import org.jetbrains.report.json.* import org.jetbrains.report.json.*
import java.nio.file.Paths import java.nio.file.Paths
@@ -151,12 +152,10 @@ fun sendUploadRequest(url: String, fileName: String, username: String? = null, p
fun createRunTask( fun createRunTask(
subproject: Project, subproject: Project,
name: String, name: String,
runTask: AbstractExecTask<*>, linkTask: KotlinNativeLink,
configureClosure: Closure<Any>? = null outputFileName: String
): Task { ): Task {
val task = subproject.tasks.create(name, RunKotlinNativeTask::class.java, runTask) return subproject.tasks.create(name, RunKotlinNativeTask::class.java, linkTask, outputFileName)
task.configure(configureClosure ?: task.emptyConfigureClosure())
return task
} }
@JvmOverloads @JvmOverloads
@@ -5,17 +5,17 @@
package org.jetbrains.kotlin package org.jetbrains.kotlin
import groovy.lang.Closure
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Task import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.gradle.api.tasks.AbstractExecTask
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import java.io.ByteArrayOutputStream
import java.io.File
import javax.inject.Inject import javax.inject.Inject
open class RunKotlinNativeTask @Inject constructor( open class RunKotlinNativeTask @Inject constructor(private val linkTask: KotlinNativeLink,
private val runTask: AbstractExecTask<*> private val outputFileName: String
) : DefaultTask() { ) : DefaultTask() {
@Input @Input
var buildType = "RELEASE" 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)") @Option(option = "filterRegex", description = "Benchmarks to run, described by regular expressions (comma-separated)")
var filterRegex: String = "" var filterRegex: String = ""
override fun configure(configureClosure: Closure<Any>): Task { private val argumentsList = mutableListOf<String>()
val task = super.configure(configureClosure)
this.finalizedBy(runTask.name) init {
runTask.finalizedBy("konanJsonReport") this.dependsOn += linkTask.name
return task this.finalizedBy("konanJsonReport")
} }
fun depends(taskName: String) { fun depends(taskName: String) {
this.dependsOn += taskName this.dependsOn += taskName
} }
@TaskAction fun args(vararg arguments: String) {
fun run() { argumentsList.addAll(arguments.toList())
runTask.run {
val filterArgs = filter.splitCommaSeparatedOption("-f")
val filterRegexArgs = filterRegex.splitCommaSeparatedOption("-fr")
runTask.args(filterArgs)
runTask.args(filterRegexArgs)
}
} }
internal fun emptyConfigureClosure() = object : Closure<Any>(this) { @TaskAction
override fun call(): RunKotlinNativeTask { fun run() {
return this@RunKotlinNativeTask 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 val mainWrapperVersion: String
@Input get() = mainWrapperTask.gradleVersion @Input get() = mainWrapperTask.gradleVersion
val mainWrapperDistrType: DistributionType
@Input get() = mainWrapperTask.distributionType
val mainWrapperDistrUrl: String
@Input get() = mainWrapperTask.distributionUrl
val mainWrapperDistrSha256: String? val mainWrapperDistrSha256: String?
@Optional @Input get() = mainWrapperTask.distributionSha256Sum @Optional @Input get() = mainWrapperTask.distributionSha256Sum
} }
open class WrappersExtension { open class WrappersExtension {
var projects = mutableListOf<Any>() var projects = mutableListOf<Any>()
var distributionType = Wrapper.DistributionType.BIN
} }
class GradleWrappers : Plugin<Project> { class GradleWrappers : Plugin<Project> {
@@ -38,16 +35,15 @@ class GradleWrappers : Plugin<Project> {
this.mainWrapperTask = mainWrapperTask this.mainWrapperTask = mainWrapperTask
jarFile = it.resolve("gradle/wrapper/gradle-wrapper.jar") jarFile = it.resolve("gradle/wrapper/gradle-wrapper.jar")
scriptFile = it.resolve("gradlew") scriptFile = it.resolve("gradlew")
distributionType = wrappers.distributionType
mainWrapperTask.dependsOn(this) mainWrapperTask.dependsOn(this)
// Get these parameters from the main wrapper task to support // 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 // 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 { doFirst {
gradleVersion = mainWrapperVersion gradleVersion = mainWrapperVersion
distributionType = mainWrapperDistrType
distributionUrl = mainWrapperDistrUrl
distributionSha256Sum = mainWrapperDistrSha256 distributionSha256Sum = mainWrapperDistrSha256
} }
} }
@@ -134,17 +134,15 @@ open class BenchmarkingPlugin: Plugin<Project> {
linkerOpts.add("-L${mingwPath}/lib") linkerOpts.add("-L${mingwPath}/lib")
} }
runTask!!.apply {
group = ""
enabled = false
}
// Specify settings configured by a user in the benchmark extension. // Specify settings configured by a user in the benchmark extension.
afterEvaluate { afterEvaluate {
linkerOpts.addAll(benchmark.linkerOpts) 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. // Native run task.
val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget val nativeTarget = kotlin.targets.getByName(NATIVE_TARGET_NAME) as KotlinNativeTarget
val nativeExecutable = nativeTarget.binaries.getExecutable(NATIVE_EXECUTABLE_NAME, NativeBuildType.RELEASE) 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 group = BENCHMARKING_GROUP
description = "Runs the benchmark for Kotlin/Native." description = "Runs the benchmark for Kotlin/Native."
} }
afterEvaluate {
(konanRun as RunKotlinNativeTask).args(
"-w", nativeWarmup.toString(),
"-r", attempts.toString(),
"-p", "${benchmark.applicationName}::"
)
}
// JVM run task. // JVM run task.
val jvmRun = tasks.create("jvmRun", RunJvmTask::class.java) { 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. // Run './gradlew wrapper --gradle-version <version>' to update all the wrappers.
apply plugin: org.jetbrains.kotlin.GradleWrappers 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 wrapper.distributionType = Wrapper.DistributionType.ALL
defaultTasks 'clean', 'dist' defaultTasks 'clean', 'dist'
@@ -67,12 +67,7 @@ ext {
kotlinUtilKlibModule="org.jetbrains.kotlin:kotlin-util-klib:${kotlinVersion}" kotlinUtilKlibModule="org.jetbrains.kotlin:kotlin-util-klib:${kotlinVersion}"
konanVersionFull = KonanVersionGeneratedKt.getCurrentKonanVersion() konanVersionFull = KonanVersionGeneratedKt.getCurrentKonanVersion()
gradlePluginVersion = konanVersionFull
if (konanVersionFull.meta == MetaVersion.RELEASE) {
gradlePluginVersion = kotlinVersion
} else {
gradlePluginVersion = "$kotlinVersion-native-$konanVersionFull"
}
} }
allprojects { allprojects {
@@ -192,14 +187,6 @@ task gradlePluginCheck {
dependsOn gradle.includedBuild('kotlin-native-gradle-plugin').task(':check') 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_compiler(dependsOn: "distCompiler")
task dist_runtime(dependsOn: "distRuntime") task dist_runtime(dependsOn: "distRuntime")
task cross_dist(dependsOn: "crossDist") task cross_dist(dependsOn: "crossDist")
+1 -1
View File
@@ -59,7 +59,7 @@ protobuf {
compileJava { compileJava {
dependsOn('renamePackage') dependsOn('renamePackage')
doFirst { 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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
Vendored
+17 -1
View File
@@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/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 ## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" 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 @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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. @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 @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome 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 'clean'
dependsOn 'сinterop:konanRun' dependsOn 'cinterop:konanRun'
} }
task framework { task framework {
+14 -17
View File
@@ -21,29 +21,26 @@ import org.jetbrains.structsBenchmarks.*
import org.jetbrains.typesBenchmarks.* import org.jetbrains.typesBenchmarks.*
import org.jetbrains.kliopt.* import org.jetbrains.kliopt.*
class CinteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String) : Launcher(numWarmIterations, numberOfAttempts, prefix) { class CinteropLauncher : Launcher() {
val stringBenchmark = StringBenchmark()
val intMatrixBenchmark = IntMatrixBenchmark()
val intBenchmark = IntBenchmark()
val boxedIntBenchmark = BoxedIntBenchmark()
override val benchmarks = BenchmarksCollection( override val benchmarks = BenchmarksCollection(
mutableMapOf( mutableMapOf(
"macros" to ::macrosBenchmark, "macros" to BenchmarkEntry(::macrosBenchmark),
"struct" to ::structBenchmark, "struct" to BenchmarkEntry(::structBenchmark),
"union" to ::unionBenchmark, "union" to BenchmarkEntry(::unionBenchmark),
"enum" to ::enumBenchmark, "enum" to BenchmarkEntry(::enumBenchmark),
"stringToC" to stringBenchmark::stringToCBenchmark, "stringToC" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringToCBenchmark() }),
"stringToKotlin" to stringBenchmark::stringToKotlinBenchmark, "stringToKotlin" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringToKotlinBenchmark() }),
"intMatrix" to intMatrixBenchmark::intMatrixBenchmark, "intMatrix" to BenchmarkEntryWithInit.create(::IntMatrixBenchmark, { intMatrixBenchmark() }),
"int" to intBenchmark::intBenchmark, "int" to BenchmarkEntryWithInit.create(::IntBenchmark, { intBenchmark() }),
"boxedInt" to boxedIntBenchmark::boxedIntBenchmark "boxedInt" to BenchmarkEntryWithInit.create(::BoxedIntBenchmark, { boxedIntBenchmark() })
) )
) )
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
val launcher = CinteropLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser -> BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
CinteropLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!) launcher.launch(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!,
.launch(parser.getAll<String>("filter"), parser.getAll<String>("filterRegex")) 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) { for (j in 0 until length/2) {
val first = sequence[i + j] val first = sequence[i + j]
val second = sequence[i + j + length/2].mul(value) val second = sequence[i + j + length/2].mul(value)
sequence[i + j] = (first.add(second) as Complex)!! sequence[i + j] = first.add(second) as Complex
sequence[i + j + length/2] = (first.sub(second) as Complex)!! sequence[i + j + length/2] = first.sub(second) as Complex
value = value.mul(base)!! value = value.mul(base)
} }
} }
length = length shl 1 length = length shl 1
@@ -128,7 +128,7 @@ actual class ComplexNumbersBenchmark actual constructor() {
val sequence = fftRoutine(true) val sequence = fftRoutine(true)
sequence.forEachIndexed { index, number -> 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.complexNumbers.*
import org.jetbrains.kliopt.* import org.jetbrains.kliopt.*
class ObjCInteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) { class ObjCInteropLauncher: Launcher() {
val complexNumbersBecnhmark = ComplexNumbersBenchmark()
override val benchmarks = BenchmarksCollection( override val benchmarks = BenchmarksCollection(
mutableMapOf( mutableMapOf(
"generateNumbersSequence" to complexNumbersBecnhmark::generateNumbersSequence, "generateNumbersSequence" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { generateNumbersSequence() }),
"sumComplex" to complexNumbersBecnhmark::sumComplex, "sumComplex" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { sumComplex() }),
"subComplex" to complexNumbersBecnhmark::subComplex, "subComplex" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { subComplex() }),
"classInheritance" to complexNumbersBecnhmark::classInheritance, "classInheritance" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { classInheritance() }),
"categoryMethods" to complexNumbersBecnhmark::categoryMethods, "categoryMethods" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { categoryMethods() }),
"stringToObjC" to complexNumbersBecnhmark::stringToObjC, "stringToObjC" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { stringToObjC() }),
"stringFromObjC" to complexNumbersBecnhmark::stringFromObjC, "stringFromObjC" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { stringFromObjC() }),
"fft" to complexNumbersBecnhmark::fft, "fft" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { fft() }),
"invertFft" to complexNumbersBecnhmark::invertFft "invertFft" to BenchmarkEntryWithInit.create(::ComplexNumbersBenchmark, { invertFft() })
) )
) )
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
val launcher = ObjCInteropLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser -> 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.benchmarksLauncher.*
import org.jetbrains.kliopt.* import org.jetbrains.kliopt.*
class RingLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String) : Launcher(numWarmIterations, numberOfAttempts, prefix) { class RingLauncher : Launcher() {
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()
override val benchmarks = BenchmarksCollection( override val benchmarks = BenchmarksCollection(
mutableMapOf( mutableMapOf(
"AbstractMethod.sortStrings" to abstractMethodBenchmark::sortStrings, "AbstractMethod.sortStrings" to BenchmarkEntryWithInit.create(::AbstractMethodBenchmark, { sortStrings() }),
"AbstractMethod.sortStringsWithComparator" to abstractMethodBenchmark::sortStringsWithComparator, "AbstractMethod.sortStringsWithComparator" to BenchmarkEntryWithInit.create(::AbstractMethodBenchmark, { sortStringsWithComparator() }),
"ClassArray.copy" to classArrayBenchmark::copy, "ClassArray.copy" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { copy() }),
"ClassArray.copyManual" to classArrayBenchmark::copyManual, "ClassArray.copyManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { copyManual() }),
"ClassArray.filterAndCount" to classArrayBenchmark::filterAndCount, "ClassArray.filterAndCount" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndCount() }),
"ClassArray.filterAndMap" to classArrayBenchmark::filterAndMap, "ClassArray.filterAndMap" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndMap() }),
"ClassArray.filterAndMapManual" to classArrayBenchmark::filterAndMapManual, "ClassArray.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterAndMapManual() }),
"ClassArray.filter" to classArrayBenchmark::filter, "ClassArray.filter" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filter() }),
"ClassArray.filterManual" to classArrayBenchmark::filterManual, "ClassArray.filterManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { filterManual() }),
"ClassArray.countFilteredManual" to classArrayBenchmark::countFilteredManual, "ClassArray.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFilteredManual() }),
"ClassArray.countFiltered" to classArrayBenchmark::countFiltered, "ClassArray.countFiltered" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFiltered() }),
"ClassArray.countFilteredLocal" to classArrayBenchmark::countFilteredLocal, "ClassArray.countFilteredLocal" to BenchmarkEntryWithInit.create(::ClassArrayBenchmark, { countFilteredLocal() }),
"ClassBaseline.consume" to classBaselineBenchmark::consume, "ClassBaseline.consume" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { consume() }),
"ClassBaseline.consumeField" to classBaselineBenchmark::consumeField, "ClassBaseline.consumeField" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { consumeField() }),
"ClassBaseline.allocateList" to classBaselineBenchmark::allocateList, "ClassBaseline.allocateList" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateList() }),
"ClassBaseline.allocateArray" to classBaselineBenchmark::allocateArray, "ClassBaseline.allocateArray" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateArray() }),
"ClassBaseline.allocateListAndFill" to classBaselineBenchmark::allocateListAndFill, "ClassBaseline.allocateListAndFill" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateListAndFill() }),
"ClassBaseline.allocateListAndWrite" to classBaselineBenchmark::allocateListAndWrite, "ClassBaseline.allocateListAndWrite" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateListAndWrite() }),
"ClassBaseline.allocateArrayAndFill" to classBaselineBenchmark::allocateArrayAndFill, "ClassBaseline.allocateArrayAndFill" to BenchmarkEntryWithInit.create(::ClassBaselineBenchmark, { allocateArrayAndFill() }),
"ClassList.copy" to classListBenchmark::copy, "ClassList.copy" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { copy() }),
"ClassList.copyManual" to classListBenchmark::copyManual, "ClassList.copyManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { copyManual() }),
"ClassList.filterAndCount" to classListBenchmark::filterAndCount, "ClassList.filterAndCount" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndCount() }),
"ClassList.filterAndCountWithLambda" to classListBenchmark::filterAndCountWithLambda, "ClassList.filterAndCountWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndCountWithLambda() }),
"ClassList.filterWithLambda" to classListBenchmark::filterWithLambda, "ClassList.filterWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterWithLambda() }),
"ClassList.mapWithLambda" to classListBenchmark::mapWithLambda, "ClassList.mapWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { mapWithLambda() }),
"ClassList.countWithLambda" to classListBenchmark::countWithLambda, "ClassList.countWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countWithLambda() }),
"ClassList.filterAndMapWithLambda" to classListBenchmark::filterAndMapWithLambda, "ClassList.filterAndMapWithLambda" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapWithLambda() }),
"ClassList.filterAndMapWithLambdaAsSequence" to classListBenchmark::filterAndMapWithLambdaAsSequence, "ClassList.filterAndMapWithLambdaAsSequence" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapWithLambdaAsSequence() }),
"ClassList.filterAndMap" to classListBenchmark::filterAndMap, "ClassList.filterAndMap" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMap() }),
"ClassList.filterAndMapManual" to classListBenchmark::filterAndMapManual, "ClassList.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterAndMapManual() }),
"ClassList.filter" to classListBenchmark::filter, "ClassList.filter" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filter() }),
"ClassList.filterManual" to classListBenchmark::filterManual, "ClassList.filterManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { filterManual() }),
"ClassList.countFilteredManual" to classListBenchmark::countFilteredManual, "ClassList.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countFilteredManual() }),
"ClassList.countFiltered" to classListBenchmark::countFiltered, "ClassList.countFiltered" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { countFiltered() }),
"ClassList.reduce" to classListBenchmark::reduce, "ClassList.reduce" to BenchmarkEntryWithInit.create(::ClassListBenchmark, { reduce() }),
"ClassStream.copy" to classStreamBenchmark::copy, "ClassStream.copy" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { copy() }),
"ClassStream.copyManual" to classStreamBenchmark::copyManual, "ClassStream.copyManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { copyManual() }),
"ClassStream.filterAndCount" to classStreamBenchmark::filterAndCount, "ClassStream.filterAndCount" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndCount() }),
"ClassStream.filterAndMap" to classStreamBenchmark::filterAndMap, "ClassStream.filterAndMap" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndMap() }),
"ClassStream.filterAndMapManual" to classStreamBenchmark::filterAndMapManual, "ClassStream.filterAndMapManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterAndMapManual() }),
"ClassStream.filter" to classStreamBenchmark::filter, "ClassStream.filter" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filter() }),
"ClassStream.filterManual" to classStreamBenchmark::filterManual, "ClassStream.filterManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { filterManual() }),
"ClassStream.countFilteredManual" to classStreamBenchmark::countFilteredManual, "ClassStream.countFilteredManual" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { countFilteredManual() }),
"ClassStream.countFiltered" to classStreamBenchmark::countFiltered, "ClassStream.countFiltered" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { countFiltered() }),
"ClassStream.reduce" to classStreamBenchmark::reduce, "ClassStream.reduce" to BenchmarkEntryWithInit.create(::ClassStreamBenchmark, { reduce() }),
"CompanionObject.invokeRegularFunction" to companionObjectBenchmark::invokeRegularFunction, "CompanionObject.invokeRegularFunction" to BenchmarkEntryWithInit.create(::CompanionObjectBenchmark, { invokeRegularFunction() }),
"CompanionObject.invokeJvmStaticFunction" to companionObjectBenchmark::invokeJvmStaticFunction, "CompanionObject.invokeJvmStaticFunction" to BenchmarkEntryWithInit.create(::CompanionObjectBenchmark, { invokeJvmStaticFunction() }),
"DefaultArgument.testOneOfTwo" to defaultArgumentBenchmark::testOneOfTwo, "DefaultArgument.testOneOfTwo" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfTwo() }),
"DefaultArgument.testTwoOfTwo" to defaultArgumentBenchmark::testTwoOfTwo, "DefaultArgument.testTwoOfTwo" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testTwoOfTwo() }),
"DefaultArgument.testOneOfFour" to defaultArgumentBenchmark::testOneOfFour, "DefaultArgument.testOneOfFour" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfFour() }),
"DefaultArgument.testFourOfFour" to defaultArgumentBenchmark::testFourOfFour, "DefaultArgument.testFourOfFour" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testFourOfFour() }),
"DefaultArgument.testOneOfEight" to defaultArgumentBenchmark::testOneOfEight, "DefaultArgument.testOneOfEight" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testOneOfEight() }),
"DefaultArgument.testEightOfEight" to defaultArgumentBenchmark::testEightOfEight, "DefaultArgument.testEightOfEight" to BenchmarkEntryWithInit.create(::DefaultArgumentBenchmark, { testEightOfEight() }),
"Elvis.testElvis" to elvisBenchmark::testElvis, "Elvis.testElvis" to BenchmarkEntryWithInit.create(::ElvisBenchmark, { testElvis() }),
"Euler.problem1bySequence" to eulerBenchmark::problem1bySequence, "Euler.problem1bySequence" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem1bySequence() }),
"Euler.problem1" to eulerBenchmark::problem1, "Euler.problem1" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem1() }),
"Euler.problem2" to eulerBenchmark::problem2, "Euler.problem2" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem2() }),
"Euler.problem4" to eulerBenchmark::problem4, "Euler.problem4" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem4() }),
"Euler.problem8" to eulerBenchmark::problem8, "Euler.problem8" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem8() }),
"Euler.problem9" to eulerBenchmark::problem9, "Euler.problem9" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem9() }),
"Euler.problem14" to eulerBenchmark::problem14, "Euler.problem14" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem14() }),
"Euler.problem14full" to eulerBenchmark::problem14full, "Euler.problem14full" to BenchmarkEntryWithInit.create(::EulerBenchmark, { problem14full() }),
"Fibonacci.calcClassic" to fibonacciBenchmark::calcClassic, "Fibonacci.calcClassic" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcClassic() }),
"Fibonacci.calc" to fibonacciBenchmark::calc, "Fibonacci.calc" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calc() }),
"Fibonacci.calcWithProgression" to fibonacciBenchmark::calcWithProgression, "Fibonacci.calcWithProgression" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcWithProgression() }),
"Fibonacci.calcSquare" to fibonacciBenchmark::calcSquare, "Fibonacci.calcSquare" to BenchmarkEntryWithInit.create(::FibonacciBenchmark, { calcSquare() }),
"ForLoops.arrayLoop" to forLoopsBenchmark::arrayLoop, "ForLoops.arrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { arrayLoop() }),
"ForLoops.intArrayLoop" to forLoopsBenchmark::intArrayLoop, "ForLoops.intArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { intArrayLoop() }),
"ForLoops.floatArrayLoop" to forLoopsBenchmark::floatArrayLoop, "ForLoops.floatArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { floatArrayLoop() }),
"ForLoops.charArrayLoop" to forLoopsBenchmark::charArrayLoop, "ForLoops.charArrayLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { charArrayLoop() }),
"ForLoops.stringLoop" to forLoopsBenchmark::stringLoop, "ForLoops.stringLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { stringLoop() }),
"ForLoops.arrayIndicesLoop" to forLoopsBenchmark::arrayIndicesLoop, "ForLoops.arrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { arrayIndicesLoop() }),
"ForLoops.intArrayIndicesLoop" to forLoopsBenchmark::intArrayIndicesLoop, "ForLoops.intArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { intArrayIndicesLoop() }),
"ForLoops.floatArrayIndicesLoop" to forLoopsBenchmark::floatArrayIndicesLoop, "ForLoops.floatArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { floatArrayIndicesLoop() }),
"ForLoops.charArrayIndicesLoop" to forLoopsBenchmark::charArrayIndicesLoop, "ForLoops.charArrayIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { charArrayIndicesLoop() }),
"ForLoops.stringIndicesLoop" to forLoopsBenchmark::stringIndicesLoop, "ForLoops.stringIndicesLoop" to BenchmarkEntryWithInit.create(::ForLoopsBenchmark, { stringIndicesLoop() }),
"Inline.calculate" to inlineBenchmark::calculate, "Inline.calculate" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculate() }),
"Inline.calculateInline" to inlineBenchmark::calculateInline, "Inline.calculateInline" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateInline() }),
"Inline.calculateGeneric" to inlineBenchmark::calculateGeneric, "Inline.calculateGeneric" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateGeneric() }),
"Inline.calculateGenericInline" to inlineBenchmark::calculateGenericInline, "Inline.calculateGenericInline" to BenchmarkEntryWithInit.create(::InlineBenchmark, { calculateGenericInline() }),
"IntArray.copy" to intArrayBenchmark::copy, "IntArray.copy" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { copy() }),
"IntArray.copyManual" to intArrayBenchmark::copyManual, "IntArray.copyManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { copyManual() }),
"IntArray.filterAndCount" to intArrayBenchmark::filterAndCount, "IntArray.filterAndCount" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndCount() }),
"IntArray.filterSomeAndCount" to intArrayBenchmark::filterSomeAndCount, "IntArray.filterSomeAndCount" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSomeAndCount() }),
"IntArray.filterAndMap" to intArrayBenchmark::filterAndMap, "IntArray.filterAndMap" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndMap() }),
"IntArray.filterAndMapManual" to intArrayBenchmark::filterAndMapManual, "IntArray.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterAndMapManual() }),
"IntArray.filter" to intArrayBenchmark::filter, "IntArray.filter" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filter() }),
"IntArray.filterSome" to intArrayBenchmark::filterSome, "IntArray.filterSome" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSome() }),
"IntArray.filterPrime" to intArrayBenchmark::filterPrime, "IntArray.filterPrime" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterPrime() }),
"IntArray.filterManual" to intArrayBenchmark::filterManual, "IntArray.filterManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterManual() }),
"IntArray.filterSomeManual" to intArrayBenchmark::filterSomeManual, "IntArray.filterSomeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { filterSomeManual() }),
"IntArray.countFilteredManual" to intArrayBenchmark::countFilteredManual, "IntArray.countFilteredManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredManual() }),
"IntArray.countFilteredSomeManual" to intArrayBenchmark::countFilteredSomeManual, "IntArray.countFilteredSomeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSomeManual() }),
"IntArray.countFilteredPrimeManual" to intArrayBenchmark::countFilteredPrimeManual, "IntArray.countFilteredPrimeManual" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredPrimeManual() }),
"IntArray.countFiltered" to intArrayBenchmark::countFiltered, "IntArray.countFiltered" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFiltered() }),
"IntArray.countFilteredSome" to intArrayBenchmark::countFilteredSome, "IntArray.countFilteredSome" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSome() }),
"IntArray.countFilteredPrime" to intArrayBenchmark::countFilteredPrime, "IntArray.countFilteredPrime" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredPrime() }),
"IntArray.countFilteredLocal" to intArrayBenchmark::countFilteredLocal, "IntArray.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredLocal() }),
"IntArray.countFilteredSomeLocal" to intArrayBenchmark::countFilteredSomeLocal, "IntArray.countFilteredSomeLocal" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { countFilteredSomeLocal() }),
"IntArray.reduce" to intArrayBenchmark::reduce, "IntArray.reduce" to BenchmarkEntryWithInit.create(::IntArrayBenchmark, { reduce() }),
"IntBaseline.consume" to intBaselineBenchmark::consume, "IntBaseline.consume" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { consume() }),
"IntBaseline.allocateList" to intBaselineBenchmark::allocateList, "IntBaseline.allocateList" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateList() }),
"IntBaseline.allocateArray" to intBaselineBenchmark::allocateArray, "IntBaseline.allocateArray" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateArray() }),
"IntBaseline.allocateListAndFill" to intBaselineBenchmark::allocateListAndFill, "IntBaseline.allocateListAndFill" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateListAndFill() }),
"IntBaseline.allocateArrayAndFill" to intBaselineBenchmark::allocateArrayAndFill, "IntBaseline.allocateArrayAndFill" to BenchmarkEntryWithInit.create(::IntBaselineBenchmark, { allocateArrayAndFill() }),
"IntList.copy" to intListBenchmark::copy, "IntList.copy" to BenchmarkEntryWithInit.create(::IntListBenchmark, { copy() }),
"IntList.copyManual" to intListBenchmark::copyManual, "IntList.copyManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { copyManual() }),
"IntList.filterAndCount" to intListBenchmark::filterAndCount, "IntList.filterAndCount" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndCount() }),
"IntList.filterAndMap" to intListBenchmark::filterAndMap, "IntList.filterAndMap" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndMap() }),
"IntList.filterAndMapManual" to intListBenchmark::filterAndMapManual, "IntList.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterAndMapManual() }),
"IntList.filter" to intListBenchmark::filter, "IntList.filter" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filter() }),
"IntList.filterManual" to intListBenchmark::filterManual, "IntList.filterManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { filterManual() }),
"IntList.countFilteredManual" to intListBenchmark::countFilteredManual, "IntList.countFilteredManual" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFilteredManual() }),
"IntList.countFiltered" to intListBenchmark::countFiltered, "IntList.countFiltered" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFiltered() }),
"IntList.countFilteredLocal" to intListBenchmark::countFilteredLocal, "IntList.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntListBenchmark, { countFilteredLocal() }),
"IntList.reduce" to intListBenchmark::reduce, "IntList.reduce" to BenchmarkEntryWithInit.create(::IntListBenchmark, { reduce() }),
"IntStream.copy" to intStreamBenchmark::copy, "IntStream.copy" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { copy() }),
"IntStream.copyManual" to intStreamBenchmark::copyManual, "IntStream.copyManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { copyManual() }),
"IntStream.filterAndCount" to intStreamBenchmark::filterAndCount, "IntStream.filterAndCount" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndCount() }),
"IntStream.filterAndMap" to intStreamBenchmark::filterAndMap, "IntStream.filterAndMap" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndMap() }),
"IntStream.filterAndMapManual" to intStreamBenchmark::filterAndMapManual, "IntStream.filterAndMapManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterAndMapManual() }),
"IntStream.filter" to intStreamBenchmark::filter, "IntStream.filter" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filter() }),
"IntStream.filterManual" to intStreamBenchmark::filterManual, "IntStream.filterManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { filterManual() }),
"IntStream.countFilteredManual" to intStreamBenchmark::countFilteredManual, "IntStream.countFilteredManual" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFilteredManual() }),
"IntStream.countFiltered" to intStreamBenchmark::countFiltered, "IntStream.countFiltered" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFiltered() }),
"IntStream.countFilteredLocal" to intStreamBenchmark::countFilteredLocal, "IntStream.countFilteredLocal" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { countFilteredLocal() }),
"IntStream.reduce" to intStreamBenchmark::reduce, "IntStream.reduce" to BenchmarkEntryWithInit.create(::IntStreamBenchmark, { reduce() }),
"Lambda.noncapturingLambda" to lambdaBenchmark::noncapturingLambda, "Lambda.noncapturingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { noncapturingLambda() }),
"Lambda.noncapturingLambdaNoInline" to lambdaBenchmark::noncapturingLambdaNoInline, "Lambda.noncapturingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { noncapturingLambdaNoInline() }),
"Lambda.capturingLambda" to lambdaBenchmark::capturingLambda, "Lambda.capturingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { capturingLambda() }),
"Lambda.capturingLambdaNoInline" to lambdaBenchmark::capturingLambdaNoInline, "Lambda.capturingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { capturingLambdaNoInline() }),
"Lambda.mutatingLambda" to lambdaBenchmark::mutatingLambda, "Lambda.mutatingLambda" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambda() }),
"Lambda.mutatingLambdaNoInline" to lambdaBenchmark::mutatingLambdaNoInline, "Lambda.mutatingLambdaNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { mutatingLambdaNoInline() }),
"Lambda.methodReference" to lambdaBenchmark::methodReference, "Lambda.methodReference" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReference() }),
"Lambda.methodReferenceNoInline" to lambdaBenchmark::methodReferenceNoInline, "Lambda.methodReferenceNoInline" to BenchmarkEntryWithInit.create(::LambdaBenchmark, { methodReferenceNoInline() }),
"Loop.arrayLoop" to loopBenchmark::arrayLoop, "Loop.arrayLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayLoop() }),
"Loop.arrayIndexLoop" to loopBenchmark::arrayIndexLoop, "Loop.arrayIndexLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayIndexLoop() }),
"Loop.rangeLoop" to loopBenchmark::rangeLoop, "Loop.rangeLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { rangeLoop() }),
"Loop.arrayListLoop" to loopBenchmark::arrayListLoop, "Loop.arrayListLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListLoop() }),
"Loop.arrayWhileLoop" to loopBenchmark::arrayWhileLoop, "Loop.arrayWhileLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayWhileLoop() }),
"Loop.arrayForeachLoop" to loopBenchmark::arrayForeachLoop, "Loop.arrayForeachLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayForeachLoop() }),
"Loop.arrayListForeachLoop" to loopBenchmark::arrayListForeachLoop, "Loop.arrayListForeachLoop" to BenchmarkEntryWithInit.create(::LoopBenchmark, { arrayListForeachLoop() }),
"MatrixMap.add" to matrixMapBenchmark::add, "MatrixMap.add" to BenchmarkEntryWithInit.create(::MatrixMapBenchmark, { add() }),
"ParameterNotNull.invokeOneArgWithNullCheck" to parameterNotNullAssertionBenchmark::invokeOneArgWithNullCheck, "ParameterNotNull.invokeOneArgWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithNullCheck() }),
"ParameterNotNull.invokeOneArgWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeOneArgWithoutNullCheck, "ParameterNotNull.invokeOneArgWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeOneArgWithoutNullCheck() }),
"ParameterNotNull.invokeTwoArgsWithNullCheck" to parameterNotNullAssertionBenchmark::invokeTwoArgsWithNullCheck, "ParameterNotNull.invokeTwoArgsWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeTwoArgsWithNullCheck() }),
"ParameterNotNull.invokeTwoArgsWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeTwoArgsWithoutNullCheck, "ParameterNotNull.invokeTwoArgsWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeTwoArgsWithoutNullCheck() }),
"ParameterNotNull.invokeEightArgsWithNullCheck" to parameterNotNullAssertionBenchmark::invokeEightArgsWithNullCheck, "ParameterNotNull.invokeEightArgsWithNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithNullCheck() }),
"ParameterNotNull.invokeEightArgsWithoutNullCheck" to parameterNotNullAssertionBenchmark::invokeEightArgsWithoutNullCheck, "ParameterNotNull.invokeEightArgsWithoutNullCheck" to BenchmarkEntryWithInit.create(::ParameterNotNullAssertionBenchmark, { invokeEightArgsWithoutNullCheck() }),
"PrimeList.calcDirect" to primeListBenchmark::calcDirect, "PrimeList.calcDirect" to BenchmarkEntryWithInit.create(::PrimeListBenchmark, { calcDirect() }),
"PrimeList.calcEratosthenes" to primeListBenchmark::calcEratosthenes, "PrimeList.calcEratosthenes" to BenchmarkEntryWithInit.create(::PrimeListBenchmark, { calcEratosthenes() }),
"String.stringConcat" to stringBenchmark::stringConcat, "String.stringConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcat() }),
"String.stringConcatNullable" to stringBenchmark::stringConcatNullable, "String.stringConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringConcatNullable() }),
"String.stringBuilderConcat" to stringBenchmark::stringBuilderConcat, "String.stringBuilderConcat" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcat() }),
"String.stringBuilderConcatNullable" to stringBenchmark::stringBuilderConcatNullable, "String.stringBuilderConcatNullable" to BenchmarkEntryWithInit.create(::StringBenchmark, { stringBuilderConcatNullable() }),
"String.summarizeSplittedCsv" to stringBenchmark::summarizeSplittedCsv, "String.summarizeSplittedCsv" to BenchmarkEntryWithInit.create(::StringBenchmark, { summarizeSplittedCsv() }),
"Switch.testSparseIntSwitch" to switchBenchmark::testSparseIntSwitch, "Switch.testSparseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testSparseIntSwitch() }),
"Switch.testDenseIntSwitch" to switchBenchmark::testDenseIntSwitch, "Switch.testDenseIntSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testDenseIntSwitch() }),
"Switch.testConstSwitch" to switchBenchmark::testConstSwitch, "Switch.testConstSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testConstSwitch() }),
"Switch.testObjConstSwitch" to switchBenchmark::testObjConstSwitch, "Switch.testObjConstSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testObjConstSwitch() }),
"Switch.testVarSwitch" to switchBenchmark::testVarSwitch, "Switch.testVarSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testVarSwitch() }),
"Switch.testStringsSwitch" to switchBenchmark::testStringsSwitch, "Switch.testStringsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testStringsSwitch() }),
"Switch.testEnumsSwitch" to switchBenchmark::testEnumsSwitch, "Switch.testEnumsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testEnumsSwitch() }),
"Switch.testDenseEnumsSwitch" to switchBenchmark::testDenseEnumsSwitch, "Switch.testDenseEnumsSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testDenseEnumsSwitch() }),
"Switch.testSealedWhenSwitch" to switchBenchmark::testSealedWhenSwitch, "Switch.testSealedWhenSwitch" to BenchmarkEntryWithInit.create(::SwitchBenchmark, { testSealedWhenSwitch() }),
"WithIndicies.withIndicies" to withIndiciesBenchmark::withIndicies, "WithIndicies.withIndicies" to BenchmarkEntryWithInit.create(::WithIndiciesBenchmark, { withIndicies() }),
"WithIndicies.withIndiciesManual" to withIndiciesBenchmark::withIndiciesManual, "WithIndicies.withIndiciesManual" to BenchmarkEntryWithInit.create(::WithIndiciesBenchmark, { withIndiciesManual() }),
"OctoTest" to ::octoTest, "OctoTest" to BenchmarkEntry(::octoTest),
"Calls.finalMethod" to callsBenchmark::finalMethodCall, "Calls.finalMethod" to BenchmarkEntryWithInit.create(::CallsBenchmark, { finalMethodCall() }),
"Calls.openMethodMonomorphic" to callsBenchmark::classOpenMethodCall_MonomorphicCallsite, "Calls.openMethodMonomorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_MonomorphicCallsite() }),
"Calls.openMethodBimorphic" to callsBenchmark::classOpenMethodCall_BimorphicCallsite, "Calls.openMethodBimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_BimorphicCallsite() }),
"Calls.openMethodTrimorphic" to callsBenchmark::classOpenMethodCall_TrimorphicCallsite, "Calls.openMethodTrimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { classOpenMethodCall_TrimorphicCallsite() }),
"Calls.interfaceMethodMonomorphic" to callsBenchmark::interfaceMethodCall_MonomorphicCallsite, "Calls.interfaceMethodMonomorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_MonomorphicCallsite() }),
"Calls.interfaceMethodBimorphic" to callsBenchmark::interfaceMethodCall_BimorphicCallsite, "Calls.interfaceMethodBimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_BimorphicCallsite() }),
"Calls.interfaceMethodTrimorphic" to callsBenchmark::interfaceMethodCall_TrimorphicCallsite, "Calls.interfaceMethodTrimorphic" to BenchmarkEntryWithInit.create(::CallsBenchmark, { interfaceMethodCall_TrimorphicCallsite() }),
"Calls.returnBoxUnboxFolding" to callsBenchmark::returnBoxUnboxFolding, "Calls.returnBoxUnboxFolding" to BenchmarkEntryWithInit.create(::CallsBenchmark, { returnBoxUnboxFolding() }),
"Calls.parameterBoxUnboxFolding" to callsBenchmark::parameterBoxUnboxFolding, "Calls.parameterBoxUnboxFolding" to BenchmarkEntryWithInit.create(::CallsBenchmark, { parameterBoxUnboxFolding() }),
"CoordinatesSolver.solve" to coordinatesSolverBenchmark::solve, "CoordinatesSolver.solve" to BenchmarkEntryWithInit.create(::CoordinatesSolverBenchmark, { solve() }),
"GraphSolver.solve" to graphSolverBenchmark::solve "GraphSolver.solve" to BenchmarkEntryWithInit.create(::GraphSolverBenchmark, { solve() })
) )
) )
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
val launcher = RingLauncher()
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser -> BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
RingLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!) launcher.launch(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!,
.launch(parser.getAll<String>("filter"), parser.getAll<String>("filterRegex")) parser.getAll<String>("filter"), parser.getAll<String>("filterRegex"))
}) }, benchmarksListAction = launcher::benchmarksListAction)
} }
@@ -133,8 +133,6 @@ class CoordinatesSolverBenchmark {
var ss: List<Coordinate>? = null var ss: List<Coordinate>? = null
while (ss == null) { while (ss == null) {
//println("o$o, limit: $limit")
if (o == 0) { if (o == 0) {
ss = solveWithLimit(limit, MAZE_START) { it[it.size - 1] == objects[0] } ss = solveWithLimit(limit, MAZE_START) { it[it.size - 1] == objects[0] }
} else { } else {
@@ -342,7 +340,11 @@ class CoordinatesSolverBenchmark {
val output = solver.solve() val output = solver.solve()
for (c in output.steps) { 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 package org.jetbrains.benchmarksLauncher
import kotlin.reflect.KFunction0 interface AbstractBenchmarkEntry
class BenchmarksCollection(private val benchmarks: MutableMap<String, KFunction0<Any?>> = mutableMapOf()) : class BenchmarkEntryWithInit(val ctor: ()->Any, val lambda: (Any) -> Any?): AbstractBenchmarkEntry {
MutableMap<String, KFunction0<Any?>> by benchmarks { 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 import org.jetbrains.report.BenchmarkResult
class JsonReportCreator(val data: Iterable<BenchmarkResult>) { class JsonReportCreator(val data: Iterable<BenchmarkResult>) {
fun printJsonReport(jsonReport: String): Unit { fun printJsonReport(jsonReport: String?): Unit {
val reportText = data.joinToString(prefix = "[", postfix = "]") { val reportText = data.joinToString(prefix = "[", postfix = "]") {
it.toJson() it.toJson()
} }
writeToFile(jsonReport, reportText) jsonReport?.let { writeToFile(it, reportText) } ?: print(reportText)
} }
} }
@@ -16,24 +16,40 @@
package org.jetbrains.benchmarksLauncher package org.jetbrains.benchmarksLauncher
import kotlin.math.sqrt
import org.jetbrains.report.BenchmarkResult import org.jetbrains.report.BenchmarkResult
import org.jetbrains.kliopt.* 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 abstract val benchmarks: BenchmarksCollection
fun add(name: String, benchmark:() -> Any?) { fun add(name: String, benchmark: AbstractBenchmarkEntry) {
fun benchmarkWrapper() { benchmarks[name] = benchmark
benchmark()
}
benchmarks[name] = ::benchmarkWrapper
} }
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> { filterRegexes: Collection<String>? = null): List<BenchmarkResult> {
val regexes = filterRegexes?.map { it.toRegex() } ?: listOf() val regexes = filterRegexes?.map { it.toRegex() } ?: listOf()
val filterSet = filters?.toHashSet() ?: hashSetOf() val filterSet = filters?.toHashSet() ?: hashSetOf()
@@ -45,19 +61,13 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
error("No matching benchmarks found") error("No matching benchmarks found")
val benchmarkResults = mutableListOf<BenchmarkResult>() val benchmarkResults = mutableListOf<BenchmarkResult>()
for ((name, benchmark) in runningBenchmarks) { for ((name, benchmark) in runningBenchmarks) {
val benchmarkInstance = (benchmark as? BenchmarkEntryWithInit)?.ctor?.invoke()
var i = numWarmIterations var i = numWarmIterations
while (i-- > 0) benchmark() runBenchmark(benchmarkInstance, benchmark, i)
cleanup()
var autoEvaluatedNumberOfMeasureIteration = 1 var autoEvaluatedNumberOfMeasureIteration = 1
while (true) { while (true) {
var j = autoEvaluatedNumberOfMeasureIteration var j = autoEvaluatedNumberOfMeasureIteration
cleanup() val time = runBenchmark(benchmarkInstance, benchmark, j)
val time = measureNanoTime {
while (j-- > 0) {
benchmark()
}
cleanup()
}
if (time >= 100L * 1_000_000) // 100ms if (time >= 100L * 1_000_000) // 100ms
break break
autoEvaluatedNumberOfMeasureIteration *= 2 autoEvaluatedNumberOfMeasureIteration *= 2
@@ -65,13 +75,7 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
val samples = DoubleArray(numberOfAttempts) val samples = DoubleArray(numberOfAttempts)
for (k in samples.indices) { for (k in samples.indices) {
i = autoEvaluatedNumberOfMeasureIteration i = autoEvaluatedNumberOfMeasureIteration
cleanup() val time = runBenchmark(benchmarkInstance, benchmark, i)
val time = measureNanoTime {
while (i-- > 0) {
benchmark()
}
cleanup()
}
val scaledTime = time * 1.0 / autoEvaluatedNumberOfMeasureIteration val scaledTime = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
samples[k] = scaledTime samples[k] = scaledTime
// Save benchmark object // Save benchmark object
@@ -82,10 +86,20 @@ abstract class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int, v
} }
return benchmarkResults return benchmarkResults
} }
fun benchmarksListAction(argParser: ArgParser) {
benchmarks.keys.forEach {
println(it)
}
}
} }
object BenchmarksRunner { 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( val options = listOf(
OptionDescriptor(ArgType.Int(), "warmup", "w", "Number of warm up iterations", "20"), OptionDescriptor(ArgType.Int(), "warmup", "w", "Number of warm up iterations", "20"),
OptionDescriptor(ArgType.Int(), "repeat", "r", "Number of each benchmark run", "60"), OptionDescriptor(ArgType.Int(), "repeat", "r", "Number of each benchmark run", "60"),
@@ -96,23 +110,23 @@ object BenchmarksRunner {
) )
// Parse args. // Parse args.
val argParser = ArgParser(options) val argParser = ArgParser(options, actions = actions)
argParser.parse(args) return if (argParser.parse(args)) argParser else null
return argParser
} }
fun collect(results: List<BenchmarkResult>, parser: ArgParser) { fun collect(results: List<BenchmarkResult>, parser: ArgParser) {
parser.get<String>("output")?.let { JsonReportCreator(results).printJsonReport(parser.get<String>("output"))
JsonReportCreator(results).printJsonReport(it)
}
} }
fun runBenchmarks(args: Array<String>, fun runBenchmarks(args: Array<String>,
run: (parser: ArgParser) -> List<BenchmarkResult>, run: (parser: ArgParser) -> List<BenchmarkResult>,
parseArgs: (args: Array<String>) -> ArgParser = this::parse, parseArgs: (args: Array<String>, benchmarksListAction: (ArgParser)->Unit) -> ArgParser? = this::parse,
collect: (results: List<BenchmarkResult>, parser: ArgParser) -> Unit = this::collect) { collect: (results: List<BenchmarkResult>, parser: ArgParser) -> Unit = this::collect,
val parser = parseArgs(args) benchmarksListAction: (ArgParser)->Unit) {
val results = run(parser) val parser = parseArgs(args, benchmarksListAction)
collect(results, parser) parser?.let {
val results = run(parser)
collect(results, parser)
}
} }
} }
@@ -6,7 +6,7 @@
import org.jetbrains.benchmarksLauncher.* import org.jetbrains.benchmarksLauncher.*
import org.jetbrains.kliopt.* import org.jetbrains.kliopt.*
class SwiftLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) { class SwiftLauncher: Launcher() {
override val benchmarks = BenchmarksCollection( override val benchmarks = BenchmarksCollection(
mutableMapOf( mutableMapOf(
) )
+35 -17
View File
@@ -10,22 +10,40 @@ var runner = BenchmarksRunner()
let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {index in let args = KotlinArray(size: Int32(CommandLine.arguments.count - 1), init: {index in
CommandLine.arguments[Int(truncating: index) + 1] CommandLine.arguments[Int(truncating: index) + 1]
}) })
let companion = BenchmarkEntryWithInit.Companion()
var swiftLauncher = SwiftLauncher()
runner.runBenchmarks(args: args, run: { (parser: ArgParser) -> [BenchmarkResult] in runner.runBenchmarks(args: args, run: { (parser: ArgParser) -> [BenchmarkResult] in
var swiftBenchmarks = SwiftInteropBenchmarks() swiftLauncher.add(name: "createMultigraphOfInt", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
var swiftLauncher = SwiftLauncher(numWarmIterations: parser.get(name: "warmup") as! Int32, lambda: { ($0 as! SwiftInteropBenchmarks).createMultigraphOfInt() }))
numberOfAttempts: parser.get(name: "repeat") as! Int32, prefix: parser.get(name: "prefix") as! String) swiftLauncher.add(name: "fillCityMap", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "createMultigraphOfInt", benchmark: swiftBenchmarks.createMultigraphOfInt) lambda: { ($0 as! SwiftInteropBenchmarks).fillCityMap() }))
swiftLauncher.add(name: "fillCityMap", benchmark: swiftBenchmarks.fillCityMap) swiftLauncher.add(name: "searchRoutesInSwiftMultigraph", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "searchRoutesInSwiftMultigraph", benchmark: swiftBenchmarks.searchRoutesInSwiftMultigraph) lambda: { ($0 as! SwiftInteropBenchmarks).searchRoutesInSwiftMultigraph () }))
swiftLauncher.add(name: "searchTravelRoutes", benchmark: swiftBenchmarks.searchTravelRoutes) swiftLauncher.add(name: "searchTravelRoutes", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "availableTransportOnMap", benchmark: swiftBenchmarks.availableTransportOnMap) lambda: { ($0 as! SwiftInteropBenchmarks).searchTravelRoutes() }))
swiftLauncher.add(name: "allPlacesMapedByInterests", benchmark: swiftBenchmarks.allPlacesMapedByInterests) swiftLauncher.add(name: "availableTransportOnMap", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "getAllPlacesWithStraightRoutesTo", benchmark: swiftBenchmarks.getAllPlacesWithStraightRoutesTo) lambda: { ($0 as! SwiftInteropBenchmarks).availableTransportOnMap() }))
swiftLauncher.add(name: "goToAllAvailablePlaces", benchmark: swiftBenchmarks.goToAllAvailablePlaces) swiftLauncher.add(name: "allPlacesMapedByInterests", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "removeVertexAndEdgesSwiftMultigraph", benchmark: swiftBenchmarks.removeVertexAndEdgesSwiftMultigraph) lambda: { ($0 as! SwiftInteropBenchmarks).allPlacesMapedByInterests() }))
swiftLauncher.add(name: "stringInterop", benchmark: swiftBenchmarks.stringInterop) swiftLauncher.add(name: "getAllPlacesWithStraightRoutesTo", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
swiftLauncher.add(name: "simpleFunction", benchmark: swiftBenchmarks.simpleFunction) lambda: { ($0 as! SwiftInteropBenchmarks).getAllPlacesWithStraightRoutesTo() }))
return swiftLauncher.launch(filters: parser.getAll(name: "filter"), filterRegexes: parser.getAll(name: "filterRegex")) swiftLauncher.add(name: "goToAllAvailablePlaces", benchmark: companion.create(ctor: { return SwiftInteropBenchmarks() },
}, parseArgs: runner.parse, collect: { (benchmarks: [BenchmarkResult], parser: ArgParser) -> Void in 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) 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