Merge branch 'master' into kotlin-mirror/master
This commit is contained in:
+22
-2
@@ -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
@@ -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.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-9
@@ -100,13 +100,4 @@ inline fun buildKotlinCodeLines(scope: KotlinScope, block: KotlinCodeBuilder.()
|
|||||||
val builder = KotlinCodeBuilder(scope)
|
val builder = KotlinCodeBuilder(scope)
|
||||||
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>
|
|
||||||
}
|
}
|
||||||
-17
@@ -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) }
|
|
||||||
|
|||||||
-128
@@ -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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+1
-1
@@ -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) {
|
||||||
|
|||||||
+293
-342
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -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>
|
||||||
|
|||||||
+425
@@ -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)
|
||||||
|
}
|
||||||
+294
@@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+359
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+499
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
@@ -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
|
||||||
|
}
|
||||||
+667
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -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
|
||||||
|
}
|
||||||
+1
-1
@@ -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.
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -33,4 +33,9 @@ class InteropConfiguration(
|
|||||||
val exportForwardDeclarations: List<String>,
|
val exportForwardDeclarations: List<String>,
|
||||||
val disableDesignatedInitializerChecks: Boolean,
|
val disableDesignatedInitializerChecks: Boolean,
|
||||||
val target: KonanTarget
|
val target: KonanTarget
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class KotlinPlatform {
|
||||||
|
JVM,
|
||||||
|
NATIVE
|
||||||
|
}
|
||||||
-1043
File diff suppressed because it is too large
Load Diff
+13
-12
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -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,
|
||||||
|
|||||||
+2
-1
@@ -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")
|
||||||
|
|||||||
-8
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
@@ -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")
|
||||||
|
|||||||
+5
-9
@@ -46,7 +46,7 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("library version")
|
= CompilerConfigurationKey.create("library version")
|
||||||
val LINKER_ARGS: CompilerConfigurationKey<List<String>>
|
val LINKER_ARGS: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create("additional linker arguments")
|
= CompilerConfigurationKey.create("additional linker arguments")
|
||||||
val LIST_PHASES: CompilerConfigurationKey<Boolean>
|
val LIST_PHASES: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("list backend phases")
|
= CompilerConfigurationKey.create("list backend phases")
|
||||||
val LIST_TARGETS: CompilerConfigurationKey<Boolean>
|
val LIST_TARGETS: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("list available targets")
|
= CompilerConfigurationKey.create("list available targets")
|
||||||
@@ -100,20 +100,16 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("target we compile for")
|
= CompilerConfigurationKey.create("target we compile for")
|
||||||
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
|
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
|
||||||
= 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>
|
||||||
|
|||||||
+5
-1
@@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+14
-30
@@ -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)
|
||||||
|
|||||||
+9
-13
@@ -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
|
||||||
|
|||||||
+42
-15
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
-15
@@ -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(
|
||||||
|
|||||||
+33
-11
@@ -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",
|
||||||
@@ -242,4 +240,28 @@ fun IrDeclaration.findTopLevelDeclaration(): IrDeclaration = when {
|
|||||||
(this as IrField).correspondingProperty!!.findTopLevelDeclaration()
|
(this as IrField).correspondingProperty!!.findTopLevelDeclaration()
|
||||||
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")
|
||||||
|
}
|
||||||
|
|||||||
-75
@@ -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
|
||||||
|
|||||||
+4
-4
@@ -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))
|
||||||
|
|||||||
+1
-15
@@ -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()
|
||||||
|
|||||||
+8
-13
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -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) {
|
||||||
|
|||||||
+5
-5
@@ -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")
|
||||||
|
|||||||
+30
-33
@@ -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) }),
|
||||||
|
|||||||
+4
-3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-42
@@ -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,
|
||||||
|
|||||||
+2
-2
@@ -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(
|
||||||
|
|||||||
+2
-4
@@ -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
-5
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -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,
|
||||||
|
|||||||
+2
-4
@@ -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
|
||||||
|
|||||||
+2
-1
@@ -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)
|
||||||
|
|||||||
+6
-4
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+92
-33
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+60
-118
@@ -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)
|
|
||||||
|
|||||||
+2
-2
@@ -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)
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|||||||
+15
-4
@@ -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.
|
||||||
|
|||||||
+9
-10
@@ -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 }
|
||||||
|
|||||||
+2
-4
@@ -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>) {
|
||||||
|
|||||||
+3
-2
@@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
+12
@@ -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)
|
||||||
|
|||||||
+11
-48
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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() {}
|
||||||
|
|||||||
@@ -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, { -> }, {
|
||||||
@@ -163,4 +163,22 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
|
|||||||
semaphore.increment()
|
semaphore.increment()
|
||||||
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
@@ -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")
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ protobuf {
|
|||||||
compileJava {
|
compileJava {
|
||||||
dependsOn('renamePackage')
|
dependsOn('renamePackage')
|
||||||
doFirst {
|
doFirst {
|
||||||
delete 'build/generated'
|
delete 'build/generated/source/proto/main/java'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
+4
-4
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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
+10
-3
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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(
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
Reference in New Issue
Block a user