Compare commits

...

9 Commits

Author SHA1 Message Date
Sergey Bogolepov
a236ca68ec Update coverage sample documentation.
We need to invoke `llvm-profdata` tool from
the same toolchain as Clang (on macOS we use the one from Xcode).

(cherry picked from commit 91665b36af68b7fb3a56c0e7ed7ebb7d819adfb2)
2021-03-09 10:46:14 +01:00
Alexander Shabalin
6c6c91be70 Add FinalizerQueue to ObjectFactory (#4725)
(cherry picked from commit af70866594c31c81dfcc41b2e8b33c7a0cdc38f5)
2021-03-09 10:45:19 +01:00
Sergey Bogolepov
d59004dc0d Add hack for kotlinx-datetime:0.1.1 linkage
Provide a `std::system_category` wrapper with
the same mangling as in GCC 4.8.5

(cherry picked from commit ec5828a1f375a74a09aa49182571201e1f67b4fa)
2021-03-09 10:45:17 +01:00
LepilkinaElena
62ca6fb7d2 [LEGACY MM] Escape making extra increments and decrements during coping to the same array (#4731)
(cherry picked from commit 8b601d8e2c6bc772386ebd88d303a032a6f54237)
2021-03-09 10:45:16 +01:00
Igor Chevdar
5eac21b73b [IR] Fixed problems with nested inline classes
Fixes https://youtrack.jetbrains.com/issue/KT-45139 as well

(cherry picked from commit 44916e39bfa69325a9ab73cb4533bd2612fb4e56)
2021-03-09 10:45:07 +01:00
Sergey Bogolepov
d54c618466 Fix #KT-45094
Rebuild linux toolchains with an older OS.

(cherry picked from commit 1d249ad7b592573dc4478f0f6cefe2766c323e12)
2021-03-09 10:43:52 +01:00
Sergey Bogolepov
f24e766ac8 [Toolchain] Archive versioning
Allow toolchain builder to add a suffix to toolchain name.
It is useful for rebuilding the same toolchain in different environment.

(cherry picked from commit 83148fc5bb4e8bcc5afcf119df53ec1bc854be17)
2021-03-09 10:43:51 +01:00
Florian Kistner
c7043665f5 Retain typed generics in ObjC export stubs (#4727)
* Add ObjC export test with disabled generics
* Retain typed generics in ObjC export stubs
* Introduce ObjC variance enum to decouple stubs from Kotlin variance

(cherry picked from commit 4d7c78b952a467ca3318c8c49d36b768fdc1ef9c)
2021-03-09 10:43:36 +01:00
LepilkinaElena
7a7424c6bb [LEGACY MM] Fixed types in messages for tracing GC (#4729)
(cherry picked from commit 2f34b0f98e77226f02809a685a96ebb683a69e9d)
2021-03-09 10:41:55 +01:00
35 changed files with 3125 additions and 150 deletions

View File

@@ -42,8 +42,14 @@ private fun KonanSymbols.getTypeConversionImpl(
internal object DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION : IrDeclarationOriginImpl("INLINE_CLASS_SPECIAL_FUNCTION")
internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.lazyMapMember { inlinedClass ->
assert(inlinedClass.isUsedAsBoxClass())
assert(inlinedClass.parent is IrFile) { "Expected top level inline class" }
require(inlinedClass.isUsedAsBoxClass())
val classes = mutableListOf<IrClass>(inlinedClass)
var parent = inlinedClass.parent
while (parent is IrClass) {
classes.add(parent)
parent = parent.parent
}
require(parent is IrFile) { "Local inline classes are not supported" }
val symbols = ir.symbols
@@ -61,7 +67,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
startOffset, endOffset,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(),
Name.special("<${inlinedClass.name}-box>"),
Name.special("<${classes.reversed().joinToString(".") { it.name.asString() }}-box>"),
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
returnType,
@@ -95,8 +101,14 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
}
internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.lazyMapMember { inlinedClass ->
assert(inlinedClass.isUsedAsBoxClass())
assert(inlinedClass.parent is IrFile) { "Expected top level inline class" }
require(inlinedClass.isUsedAsBoxClass())
val classes = mutableListOf<IrClass>(inlinedClass)
var parent = inlinedClass.parent
while (parent is IrClass) {
classes.add(parent)
parent = parent.parent
}
require(parent is IrFile) { "Local inline classes are not supported" }
val symbols = ir.symbols
@@ -114,7 +126,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
startOffset, endOffset,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(),
Name.special("<${inlinedClass.name}-unbox>"),
Name.special("<${classes.reversed().joinToString(".") { it.name.asString() } }-unbox>"),
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
returnType,

View File

@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isInterface
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
@@ -79,19 +78,23 @@ internal class ObjCExportTranslatorImpl(
// TODO: only if appears
add {
val generics = listOf("ObjectType")
objCInterface(
namer.mutableSetName,
generics = listOf("ObjectType"),
superClass = "NSMutableSet<ObjectType>"
generics = generics,
superClass = "NSMutableSet",
superClassGenerics = generics
)
}
// TODO: only if appears
add {
val generics = listOf("KeyType", "ObjectType")
objCInterface(
namer.mutableMapName,
generics = listOf("KeyType", "ObjectType"),
superClass = "NSMutableDictionary<KeyType, ObjectType>"
generics = generics,
superClass = "NSMutableDictionary",
superClassGenerics = generics
)
}
@@ -192,23 +195,14 @@ internal class ObjCExportTranslatorImpl(
}
private fun referenceClass(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName {
fun forwardDeclarationObjcClassName(objcGenerics: Boolean, descriptor: ClassDescriptor, namer:ObjCExportNamer): String {
val className = translateClassOrInterfaceName(descriptor)
val builder = StringBuilder(className.objCName)
if (objcGenerics)
formatGenerics(builder, descriptor.typeConstructor.parameters.map { typeParameterDescriptor ->
"${typeParameterDescriptor.variance.objcDeclaration()}${namer.getTypeParameterName(typeParameterDescriptor)}"
})
return builder.toString()
}
assert(mapper.shouldBeExposed(descriptor)) { "Shouldn't be exposed: $descriptor" }
assert(!descriptor.isInterface)
generator?.requireClassOrInterface(descriptor)
return translateClassOrInterfaceName(descriptor).also {
val objcName = forwardDeclarationObjcClassName(objcGenerics, descriptor, namer)
generator?.referenceClass(objcName)
return translateClassOrInterfaceName(descriptor).also { className ->
val generics = mapTypeConstructorParameters(descriptor)
val forwardDeclaration = ObjCClassForwardDeclaration(className.objCName, generics)
generator?.referenceClass(forwardDeclaration)
}
}
@@ -296,14 +290,14 @@ internal class ObjCExportTranslatorImpl(
}
fun superClassGenerics(genericExportScope: ObjCExportScope): List<ObjCNonNullReferenceType> {
val parentType = computeSuperClassType(descriptor)
return if(parentType != null) {
parentType.arguments.map { typeProjection ->
mapReferenceTypeIgnoringNullability(typeProjection.type, genericExportScope)
if (objcGenerics) {
computeSuperClassType(descriptor)?.let { parentType ->
return parentType.arguments.map { typeProjection ->
mapReferenceTypeIgnoringNullability(typeProjection.type, genericExportScope)
}
}
} else {
emptyList()
}
return emptyList()
}
val superClass = descriptor.getSuperClassNotAny()
@@ -397,20 +391,8 @@ internal class ObjCExportTranslatorImpl(
val attributes = if (descriptor.isFinalOrEnum) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
val name = translateClassOrInterfaceName(descriptor)
val generics = if (objcGenerics) {
descriptor.typeConstructor.parameters.map {
"${it.variance.objcDeclaration()}${namer.getTypeParameterName(it)}"
}
} else {
emptyList()
}
val superClassGenerics = if (objcGenerics) {
superClassGenerics(genericExportScope)
} else {
emptyList()
}
val generics = mapTypeConstructorParameters(descriptor)
val superClassGenerics = superClassGenerics(genericExportScope)
return objCInterface(
name,
@@ -424,6 +406,15 @@ internal class ObjCExportTranslatorImpl(
)
}
private fun mapTypeConstructorParameters(descriptor: ClassDescriptor): List<ObjCGenericTypeParameterDeclaration> {
if (objcGenerics) {
return descriptor.typeConstructor.parameters.map {
ObjCGenericTypeParameterDeclaration(it, namer)
}
}
return emptyList()
}
private fun buildEnumValuesMethod(
enumValues: SimpleFunctionDescriptor,
genericExportScope: ObjCExportScope
@@ -822,9 +813,9 @@ internal class ObjCExportTranslatorImpl(
}
if(objcGenerics && kotlinType.isTypeParameter()){
val genericTypeDeclaration = objCExportScope.getGenericDeclaration(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
if(genericTypeDeclaration != null)
return genericTypeDeclaration
val genericTypeUsage = objCExportScope.getGenericTypeUsage(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
if(genericTypeUsage != null)
return genericTypeUsage
}
val classDescriptor = kotlinType.getErasedTypeClass()
@@ -892,7 +883,7 @@ internal class ObjCExportTranslatorImpl(
}
private fun foreignClassType(name: String): ObjCClassType {
generator?.referenceClass(name)
generator?.referenceClass(ObjCClassForwardDeclaration(name))
return ObjCClassType(name)
}
@@ -971,7 +962,7 @@ abstract class ObjCExportHeaderGenerator internal constructor(
) {
private val stubs = mutableListOf<Stub<*>>()
private val classForwardDeclarations = linkedSetOf<String>()
private val classForwardDeclarations = linkedSetOf<ObjCClassForwardDeclaration>()
private val protocolForwardDeclarations = linkedSetOf<String>()
private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
@@ -987,7 +978,14 @@ abstract class ObjCExportHeaderGenerator internal constructor(
add("")
if (classForwardDeclarations.isNotEmpty()) {
add("@class ${classForwardDeclarations.joinToString()};")
add("@class ${
classForwardDeclarations.joinToString {
buildString {
append(it.className)
formatGenerics(this, it.typeDeclarations)
}
}
};")
add("")
}
@@ -1161,8 +1159,8 @@ abstract class ObjCExportHeaderGenerator internal constructor(
}
}
internal fun referenceClass(objCName: String) {
classForwardDeclarations += objCName
internal fun referenceClass(forwardDeclaration: ObjCClassForwardDeclaration) {
classForwardDeclarations += forwardDeclaration
}
internal fun referenceProtocol(objCName: String) {
@@ -1190,7 +1188,19 @@ abstract class ObjCExportHeaderGenerator internal constructor(
private fun objCInterface(
name: ObjCExportNamer.ClassOrProtocolName,
generics: List<String> = emptyList(),
generics: List<String>,
superClass: String,
superClassGenerics: List<String>
): ObjCInterface = objCInterface(
name,
generics = generics.map { ObjCGenericTypeRawDeclaration(it) },
superClass = superClass,
superClassGenerics = superClassGenerics.map { ObjCGenericTypeRawUsage(it) }
)
private fun objCInterface(
name: ObjCExportNamer.ClassOrProtocolName,
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
descriptor: ClassDescriptor? = null,
superClass: String? = null,
superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
@@ -1232,7 +1242,7 @@ private fun swiftNameAttribute(swiftName: String) = "swift_name(\"$swiftName\")"
private fun objcRuntimeNameAttribute(name: String) = "objc_runtime_name(\"$name\")"
interface ObjCExportScope{
fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration?
fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage?
}
internal class ObjCClassExportScope constructor(container:DeclarationDescriptor, val namer: ObjCExportNamer): ObjCExportScope {
@@ -1242,7 +1252,7 @@ internal class ObjCClassExportScope constructor(container:DeclarationDescriptor,
emptyList<TypeParameterDescriptor>()
}
override fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration? {
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? {
val localTypeParam = typeNames.firstOrNull {
typeParameterDescriptor != null &&
(it == typeParameterDescriptor || (it.isCapturedFromOuterDeclaration && it.original == typeParameterDescriptor))
@@ -1251,19 +1261,13 @@ internal class ObjCClassExportScope constructor(container:DeclarationDescriptor,
return if(localTypeParam == null) {
null
} else {
ObjCGenericTypeDeclaration(localTypeParam, namer)
ObjCGenericTypeParameterUsage(localTypeParam, namer)
}
}
}
internal object ObjCNoneExportScope: ObjCExportScope{
override fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration? = null
}
internal fun Variance.objcDeclaration():String = when(this){
Variance.OUT_VARIANCE -> "__covariant "
Variance.IN_VARIANCE -> "__contravariant "
else -> ""
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? = null
}
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = descriptor.typeConstructor.supertypes.filter { !it.isInterface() }.firstOrNull()

View File

@@ -150,9 +150,14 @@ internal class ObjCExportLazyImpl(
}
}
private fun translateGenerics(ktClassOrObject: KtClassOrObject): List<String> = if (configuration.objcGenerics) {
private fun translateGenerics(ktClassOrObject: KtClassOrObject): List<ObjCGenericTypeDeclaration> = if (configuration.objcGenerics) {
ktClassOrObject.typeParametersWithOuter
.map { nameTranslator.getTypeParameterName(it) }
.map {
ObjCGenericTypeRawDeclaration(
nameTranslator.getTypeParameterName(it),
ObjCVariance.fromKotlinVariance(it.variance)
)
}
.toList()
} else {
emptyList()
@@ -316,7 +321,7 @@ internal class ObjCExportLazyImpl(
private class LazyObjCInterfaceImpl(
name: ObjCExportNamer.ClassOrProtocolName,
attributes: List<String>,
generics: List<String>,
generics: List<ObjCGenericTypeDeclaration>,
override val psi: KtClassOrObject,
private val lazy: ObjCExportLazyImpl
) : LazyObjCInterface(name = name, generics = generics, categoryName = null, attributes = attributes) {
@@ -382,14 +387,14 @@ private abstract class LazyObjCInterface : ObjCInterface {
constructor(
name: ObjCExportNamer.ClassOrProtocolName,
generics: List<String>,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String?,
attributes: List<String>
) : super(name.objCName, generics, categoryName, attributes + name.toNameAttributes())
constructor(
name: String,
generics: List<String>,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String,
attributes: List<String>
) : super(name, generics, categoryName, attributes)

View File

@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.backend.konan.objcexport
data class ObjCExportedStubs(
val classForwardDeclarations: Set<String>,
val classForwardDeclarations: Set<ObjCClassForwardDeclaration>,
val protocolForwardDeclarations: Set<String>,
val stubs: List<Stub<*>>
)

View File

@@ -145,7 +145,7 @@ object StubRenderer {
private fun ObjCInterface.renderInterfaceHeader() = buildString {
fun appendSuperClass() {
if (superClass != null) append(" : $superClass")
formatGenerics(this, superClassGenerics.map { it.render() })
formatGenerics(this, superClassGenerics)
}
fun appendGenerics() {
@@ -196,7 +196,7 @@ object StubRenderer {
}
}
internal fun formatGenerics(buffer: Appendable, generics:List<String>) {
fun formatGenerics(buffer: Appendable, generics: List<Any>) {
if (generics.isNotEmpty()) {
generics.joinTo(buffer, separator = ", ", prefix = "<", postfix = ">")
}

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.types.Variance
sealed class ObjCType {
final override fun toString(): String = this.render()
@@ -18,7 +19,7 @@ sealed class ObjCType {
if (attrsAndName.isEmpty()) this else "$this ${attrsAndName.trimStart()}"
}
class ObjCRawType(
data class ObjCRawType(
val rawText: String
) : ObjCType() {
override fun render(attrsAndName: String): String = rawText.withAttrsAndName(attrsAndName)
@@ -34,7 +35,7 @@ data class ObjCNullableReferenceType(
override fun render(attrsAndName: String) = nonNullType.render(" _Nullable".withAttrsAndName(attrsAndName))
}
class ObjCClassType(
data class ObjCClassType(
val className: String,
val typeArguments: List<ObjCNonNullReferenceType> = emptyList()
) : ObjCNonNullReferenceType() {
@@ -51,16 +52,24 @@ class ObjCClassType(
}
}
class ObjCGenericTypeDeclaration(
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer
) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String): String {
return namer.getTypeParameterName(typeParameterDescriptor).withAttrsAndName(attrsAndName)
sealed class ObjCGenericTypeUsage: ObjCNonNullReferenceType() {
abstract val typeName: String
final override fun render(attrsAndName: String): String {
return typeName.withAttrsAndName(attrsAndName)
}
}
class ObjCProtocolType(
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
data class ObjCGenericTypeParameterUsage(
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer
) : ObjCGenericTypeUsage() {
override val typeName: String
get() = namer.getTypeParameterName(typeParameterDescriptor)
}
data class ObjCProtocolType(
val protocolName: String
) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = "id<$protocolName>".withAttrsAndName(attrsAndName)
@@ -74,7 +83,7 @@ object ObjCInstanceType : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String): String = "instancetype".withAttrsAndName(attrsAndName)
}
class ObjCBlockPointerType(
data class ObjCBlockPointerType(
val returnType: ObjCType,
val parameterTypes: List<ObjCReferenceType>
) : ObjCNonNullReferenceType() {
@@ -124,7 +133,7 @@ sealed class ObjCPrimitiveType(
override fun render(attrsAndName: String) = cName.withAttrsAndName(attrsAndName)
}
class ObjCPointerType(
data class ObjCPointerType(
val pointee: ObjCType,
val nullable: Boolean = false
) : ObjCType() {
@@ -156,6 +165,41 @@ internal enum class ObjCValueType(val encoding: String) {
POINTER("^v")
}
enum class ObjCVariance(internal val declaration: String) {
INVARIANT(""),
COVARIANT("__covariant "),
CONTRAVARIANT("__contravariant ");
companion object {
fun fromKotlinVariance(variance: Variance): ObjCVariance = when (variance) {
Variance.OUT_VARIANCE -> COVARIANT
Variance.IN_VARIANCE -> CONTRAVARIANT
else -> INVARIANT
}
}
}
sealed class ObjCGenericTypeDeclaration {
abstract val typeName: String
abstract val variance: ObjCVariance
final override fun toString(): String = variance.declaration + typeName
}
data class ObjCGenericTypeRawDeclaration(
override val typeName: String,
override val variance: ObjCVariance = ObjCVariance.INVARIANT
) : ObjCGenericTypeDeclaration()
data class ObjCGenericTypeParameterDeclaration(
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer
) : ObjCGenericTypeDeclaration() {
override val typeName: String
get() = namer.getTypeParameterName(typeParameterDescriptor)
override val variance: ObjCVariance
get() = ObjCVariance.fromKotlinVariance(typeParameterDescriptor.variance)
}
internal fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this) {
is ObjCPointerType -> ObjCPointerType(this.pointee, nullable = true)
@@ -167,4 +211,4 @@ internal fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this)
internal fun ObjCReferenceType.makeNullable(): ObjCNullableReferenceType = when (this) {
is ObjCNonNullReferenceType -> ObjCNullableReferenceType(this)
is ObjCNullableReferenceType -> this
}
}

View File

@@ -14,6 +14,11 @@ class ObjCComment(val contentLines: List<String>) {
constructor(vararg contentLines: String) : this(contentLines.toList())
}
data class ObjCClassForwardDeclaration(
val className: String,
val typeDeclarations: List<ObjCGenericTypeDeclaration> = emptyList()
)
abstract class Stub<out D : DeclarationDescriptor>(val name: String, val comment: ObjCComment? = null) {
abstract val descriptor: D?
open val psi: PsiElement?
@@ -41,7 +46,7 @@ class ObjCProtocolImpl(
attributes: List<String> = emptyList()) : ObjCProtocol(name, attributes)
abstract class ObjCInterface(name: String,
val generics: List<String>,
val generics: List<ObjCGenericTypeDeclaration>,
val categoryName: String?,
attributes: List<String>) : ObjCClass<ClassDescriptor>(name, attributes) {
abstract val superClass: String?
@@ -50,7 +55,7 @@ abstract class ObjCInterface(name: String,
class ObjCInterfaceImpl(
name: String,
generics: List<String> = emptyList(),
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
override val descriptor: ClassDescriptor? = null,
override val superClass: String? = null,
override val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),

View File

@@ -3262,6 +3262,10 @@ task inlineClass_secondaryConstructorWithGenerics(type: KonanLocalTest) {
source = "codegen/inlineClass/secondaryConstructorWithGenerics.kt"
}
task inlineClass_nestedInlineClasses(type: KonanLocalTest) {
source = "codegen/inlineClass/nestedInlineClasses.kt"
}
task valueClass0(type: KonanLocalTest) {
source = "codegen/inlineClass/valueClass0.kt"
}
@@ -4730,6 +4734,59 @@ if (isAppleTarget(project)) {
swiftSources = ['objcexport']
}
frameworkTest('testObjCExportNoGenerics') {
enabled = !isExperimentalMM // Experimental MM doesn't support ObjC blocks yet.
final String frameworkName = 'KtNoGenerics'
final String frameworkArtifactName = 'Kt'
final String dir = "$testOutputFramework/testObjCExportNoGenerics"
final File lazyHeader = file("$dir/$target-lazy.h")
doLast {
final String expectedLazyHeaderName = "expectedLazyNoGenerics.h"
final String expectedLazyHeaderDir = file("objcexport/")
final File expectedLazyHeader = new File(expectedLazyHeaderDir, expectedLazyHeaderName)
if (expectedLazyHeader.readLines() != lazyHeader.readLines()) {
exec {
commandLine 'diff', '-u', expectedLazyHeader, lazyHeader
ignoreExitValue = true
}
copy {
from(lazyHeader)
into(expectedLazyHeaderDir)
rename { expectedLazyHeaderName }
}
throw new Error("$expectedLazyHeader file patched;\nre-run the test and don't forget to commit the patch")
}
}
def libraryName = frameworkName + "Library"
konanArtifacts {
library(libraryName, targets: [target.name]) {
srcDir "objcexport/library"
artifactName "test-library"
if (!useCustomDist) {
dependsOn ":${target.name}CrossDistRuntime", ':distCompiler'
}
extraOpts "-Xshort-module-name=MyLibrary"
extraOpts "-module-name", "org.jetbrains.kotlin.native.test-library"
}
}
framework(frameworkName) {
sources = ['objcexport']
artifact = frameworkArtifactName
library = libraryName
opts = ["-Xemit-lazy-objc-header=$lazyHeader", "-Xno-objc-generics"]
}
swiftSources = ['objcexport']
swiftExtraOpts = [ '-D', 'NO_GENERICS' ]
}
frameworkTest('testObjCExportStatic') {
enabled = !isExperimentalMM // Experimental MM doesn't support ObjC blocks yet.
final String frameworkName = 'KtStatic'

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2010-2018 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.inlineClass.nestedInlineClasses
import kotlin.test.*
interface I {
inline class IC(val x: Int)
}
interface I2 {
inline class IC(val x: Int)
}
@Test fun runTest() {
assertEquals(42, I.IC(42).x)
assertEquals(117, I2.IC(117).x)
}

View File

@@ -51,7 +51,11 @@ private func testSuspendFuncAsync(doThrow: Bool) throws {
var result: AnyObject? = nil
var error: Error? = nil
#if NO_GENERICS
let continuationHolder = ContinuationHolder()
#else
let continuationHolder = ContinuationHolder<AnyObject>()
#endif
CoroutinesKt.suspendFunAsync(result: nil, continuationHolder: continuationHolder) { _result, _error in
completionCalled += 1
@@ -114,7 +118,11 @@ private class SuspendFunImpl : SuspendFun {
}
private func testSuspendFunImpl(doYield: Bool, doThrow: Bool) throws {
#if NO_GENERICS
let resultHolder = ResultHolder()
#else
let resultHolder = ResultHolder<KotlinInt>()
#endif
let impl = SuspendFunImpl()
@@ -141,7 +149,7 @@ private func testSuspendFunImpl(doYield: Bool, doThrow: Bool) throws {
try fail()
}
} else {
try assertEquals(actual: resultHolder.result, expected: 17)
try assertEquals(actual: resultHolder.result as! Int, expected: 17)
try assertNil(resultHolder.exception)
}
}
@@ -213,12 +221,16 @@ private class SwiftSuspendBridge : AbstractSuspendBridge {
}
private func testBridges() throws {
#if NO_GENERICS
let resultHolder = ResultHolder()
#else
let resultHolder = ResultHolder<KotlinUnit>()
#endif
try CoroutinesKt.callSuspendBridge(bridge: SwiftSuspendBridge(), resultHolder: resultHolder)
try assertEquals(actual: resultHolder.completed, expected: 1)
try assertNil(resultHolder.exception)
try assertSame(actual: resultHolder.result, expected: KotlinUnit())
try assertSame(actual: resultHolder.result as AnyObject, expected: KotlinUnit())
}
private func testImplicitThrows1() throws {

View File

@@ -33,7 +33,11 @@ private class DeallocRetain : DeallocRetainBase {
static var deallocated = false
static var retainObject: DeallocRetain? = nil
static weak var weakObject: DeallocRetain? = nil
#if NO_GENERICS
static var kotlinWeakRef: KotlinWeakReference? = nil
#else
static var kotlinWeakRef: KotlinWeakReference<AnyObject>? = nil
#endif
override init() {
super.init()
@@ -43,7 +47,7 @@ private class DeallocRetain : DeallocRetainBase {
func checkWeak() throws {
try assertSame(actual: DeallocRetain.weakObject, expected: self)
try assertSame(actual: DeallocRetain.kotlinWeakRef!.value, expected: self)
try assertSame(actual: DeallocRetain.kotlinWeakRef!.value as AnyObject, expected: self)
}
deinit {

View File

@@ -5,10 +5,10 @@ private func testEnumValues() throws {
try assertEquals(actual: values.size, expected: 4)
try assertSame(actual: values.get(index: 0), expected: EnumLeftRightUpDown.left)
try assertSame(actual: values.get(index: 1), expected: EnumLeftRightUpDown.right)
try assertSame(actual: values.get(index: 2), expected: EnumLeftRightUpDown.up)
try assertSame(actual: values.get(index: 3), expected: EnumLeftRightUpDown.down)
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumLeftRightUpDown.left)
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumLeftRightUpDown.right)
try assertSame(actual: values.get(index: 2) as AnyObject, expected: EnumLeftRightUpDown.up)
try assertSame(actual: values.get(index: 3) as AnyObject, expected: EnumLeftRightUpDown.down)
}
private func testEnumValuesMangled() throws {
@@ -16,10 +16,10 @@ private func testEnumValuesMangled() throws {
try assertEquals(actual: values.size, expected: 4)
try assertSame(actual: values.get(index: 0), expected: EnumOneTwoThreeValues.one)
try assertSame(actual: values.get(index: 1), expected: EnumOneTwoThreeValues.two)
try assertSame(actual: values.get(index: 2), expected: EnumOneTwoThreeValues.three)
try assertSame(actual: values.get(index: 3), expected: EnumOneTwoThreeValues.values)
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumOneTwoThreeValues.one)
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumOneTwoThreeValues.two)
try assertSame(actual: values.get(index: 2) as AnyObject, expected: EnumOneTwoThreeValues.three)
try assertSame(actual: values.get(index: 3) as AnyObject, expected: EnumOneTwoThreeValues.values)
}
private func testEnumValuesMangledTwice() throws {
@@ -27,8 +27,8 @@ private func testEnumValuesMangledTwice() throws {
try assertEquals(actual: values.size, expected: 2)
try assertSame(actual: values.get(index: 0), expected: EnumValuesValues_.values)
try assertSame(actual: values.get(index: 1), expected: EnumValuesValues_.values_)
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumValuesValues_.values)
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumValuesValues_.values_)
}
private func testEnumValuesEmpty() throws {

View File

@@ -2227,3 +2227,42 @@ __attribute__((swift_name("ValuesKt")))
@property (class) int32_t gh3525InitCount __attribute__((swift_name("gh3525InitCount")));
@end;
__attribute__((swift_name("InvariantSuper")))
@interface KtInvariantSuper<T> : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Invariant")))
@interface KtInvariant<T> : KtInvariantSuper<T>
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
__attribute__((swift_name("OutVariantSuper")))
@interface KtOutVariantSuper<__covariant T> : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("OutVariant")))
@interface KtOutVariant<__covariant T> : KtOutVariantSuper<T>
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
__attribute__((swift_name("InVariantSuper")))
@interface KtInVariantSuper<__contravariant T> : KtBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("InVariant")))
@interface KtInVariant<__contravariant T> : KtInVariantSuper<T>
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ import Kt
// It is enough to have just Kotlin declarations at the moment.
// Adding usages for all declarations to avoid any kind of DCE that may appear later.
#if !NO_GENERICS
private func testIncompatiblePropertyType() throws {
let c = TestIncompatiblePropertyTypeWarning.ClassOverridingInterfaceWithGenericProperty(
p: TestIncompatiblePropertyTypeWarningGeneric<NSString>(value: "cba")
@@ -21,6 +22,7 @@ private func testIncompatiblePropertyType() throws {
let pi: TestIncompatiblePropertyTypeWarningGeneric<AnyObject> = i.p
try assertEquals(actual: pi.value as! String, expected: "cba")
}
#endif
private func testGH3992() throws {
let d = TestGH3992.D(a: TestGH3992.B())
@@ -36,7 +38,9 @@ class HeaderWarningsTests : SimpleTestProvider {
override init() {
super.init()
#if !NO_GENERICS
test("TestIncompatiblePropertyType", testIncompatiblePropertyType)
#endif
test("TestGH3992", testGH3992)
}
}

View File

@@ -384,7 +384,11 @@ func testGenericsFoo() throws {
}
func testVararg() throws {
#if NO_GENERICS
let ktArray = KotlinArray(size: 3, init: { (_) -> NSNumber in return 42 })
#else
let ktArray = KotlinArray<AnyObject>(size: 3, init: { (_) -> NSNumber in return 42 })
#endif
let arr: [Int] = ValuesKt.varargToList(args: ktArray) as! [Int]
try assertEquals(actual: arr, expected: [42, 42, 42])
}
@@ -507,13 +511,21 @@ func testDataClass() throws {
let s = "2"
let t = "3"
#if NO_GENERICS
let tripleVal = TripleVals(first: f as NSString, second: s as NSString, third: t as NSString)
#else
let tripleVal = TripleVals<NSString>(first: f as NSString, second: s as NSString, third: t as NSString)
#endif
try assertEquals(actual: tripleVal.first as! String, expected: f, "Data class' value")
try assertEquals(actual: tripleVal.component2() as! String, expected: s, "Data class' component")
print(tripleVal)
try assertEquals(actual: String(describing: tripleVal), expected: "TripleVals(first=\(f), second=\(s), third=\(t))")
#if NO_GENERICS
let tripleVar = TripleVars(first: f as NSString, second: s as NSString, third: t as NSString)
#else
let tripleVar = TripleVars<NSString>(first: f as NSString, second: s as NSString, third: t as NSString)
#endif
try assertEquals(actual: tripleVar.first as! String, expected: f, "Data class' value")
try assertEquals(actual: tripleVar.component2() as! String, expected: s, "Data class' component")
print(tripleVar)
@@ -542,7 +554,11 @@ func testInlineClasses() throws {
let ic1N = ValuesKt.box(ic1: 17)
let ic2 = "foo"
let ic2N = "bar"
#if NO_GENERICS
let ic3 = TripleVals(first: 1, second: 2, third: 3)
#else
let ic3 = TripleVals<NSNumber>(first: 1, second: 2, third: 3)
#endif
let ic3N = ValuesKt.box(ic3: nil)
try assertEquals(
@@ -609,7 +625,11 @@ func testPureSwiftClasses() throws {
func testNames() throws {
try assertEquals(actual: ValuesKt.PROPERTY_NAME_MUST_NOT_BE_ALTERED_BY_SWIFT, expected: 111)
try assertEquals(actual: Deeply.NestedType().thirtyTwo, expected: 32)
#if NO_GENERICS
try assertEquals(actual: WithGenericDeeply.NestedType().thirtyThree, expected: 33)
#else
try assertEquals(actual: WithGenericDeeplyNestedType<AnyObject>().thirtyThree, expected: 33)
#endif
try assertEquals(actual: CKeywords(float: 1.0, enum : 42, goto: true).goto_, expected: true)
try assertEquals(actual: TypeOuter.Type_().thirtyFour, expected: 34)
try assertTrue(String(describing: DeeplyNestedIType.self).hasSuffix("DeeplyNestedIType"))
@@ -637,7 +657,11 @@ class TransformIntToLongCallingSuper : TransformIntToLong {
}
func testKotlinOverride() throws {
#if NO_GENERICS
try assertEquals(actual: TransformInheritingDefault().map(value: 1) as! Int32, expected: 1)
#else
try assertEquals(actual: TransformInheritingDefault<NSNumber>().map(value: 1) as! Int32, expected: 1)
#endif
try assertEquals(actual: TransformIntToDecimalString().map(value: 2), expected: "2")
try assertEquals(actual: TransformIntToDecimalString().map(intValue: 3), expected: "3")
try assertEquals(actual: ValuesKt.createTransformDecimalStringToInt().map(value: "4") as! Int32, expected: 4)

View File

@@ -0,0 +1,15 @@
/*
* Copyright 2010-2021 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 variance
sealed class InvariantSuper<T>
class Invariant<T> : InvariantSuper<T>()
sealed class OutVariantSuper<out T>
class OutVariant<out T> : OutVariantSuper<T>()
sealed class InVariantSuper<in T>
class InVariant<in T> : InVariantSuper<T>()

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2010-2021 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.
*/
import Foundation
import Kt
// -------- Tests --------
func testInstantiation() {
#if NO_GENERICS
Invariant()
OutVariant()
InVariant()
#else
Invariant<VarianceTests>()
OutVariant<VarianceTests>()
InVariant<VarianceTests>()
#endif
}
// -------- Execution of the test --------
class VarianceTests : SimpleTestProvider {
override init() {
super.init()
test("TestInstantiation", testInstantiation)
}
}

View File

@@ -30,6 +30,9 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
@Input
lateinit var swiftSources: List<String>
@Input
var swiftExtraOpts: List<String> = emptyList()
@Input
lateinit var frameworks: MutableList<Framework>
@@ -159,7 +162,7 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
"-F", frameworkParentDirPath,
"-Xcc", "-Werror" // To fail compilation on warnings in framework header.
)
compileSwift(project, project.testTarget, sources, options, Paths.get(executable), fullBitcode)
compileSwift(project, project.testTarget, sources, options + swiftExtraOpts, Paths.get(executable), fullBitcode)
}
@TaskAction

View File

@@ -408,22 +408,22 @@ runtimeDefinitions.watchos_x64 = KONAN_OBJC_INTEROP=1 KONAN_WATCHOS=1 \
llvmHome.linux_x64 = $llvm.linux_x64.dev
libffiDir.linux_x64 = libffi-3.2.1-2-linux-x86-64
gccToolchain.linux_x64 = x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9
gccToolchain.linux_x64 = x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2
targetToolchain.linux_x64 = $gccToolchain.linux_x64/x86_64-unknown-linux-gnu
dependencies.linux_x64 = \
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9 \
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-2-linux-x86-64 \
lldb-3-linux
targetToolchain.mingw_x64-linux_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
dependencies.mingw_x64-linux_x64 = \
libffi-3.2.1-mingw-w64-x86-64 \
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2
targetToolchain.macos_x64-linux_x64 = $llvmHome.macos_x64
dependencies.macos_x64-linux_x64 = \
libffi-3.2.1-3-darwin-macos \
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9
x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2
quadruple.linux_x64 = x86_64-unknown-linux-gnu
targetSysRoot.linux_x64 = $gccToolchain.linux_x64/x86_64-unknown-linux-gnu/sysroot
@@ -459,7 +459,7 @@ runtimeDefinitions.linux_x64 = USE_GCC_UNWIND=1 KONAN_LINUX=1 KONAN_X64=1 \
USE_ELF_SYMBOLS=1 ELFSIZE=64
# Raspberry Pi
gccToolchain.linux_arm32_hfp = arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9
gccToolchain.linux_arm32_hfp = arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9-2
targetToolchain.linux_x64-linux_arm32_hfp = $gccToolchain.linux_arm32_hfp/arm-unknown-linux-gnueabihf
targetToolchain.mingw_x64-linux_arm32_hfp = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
@@ -470,13 +470,13 @@ emulatorDependency.linux_x64-linux_arm32_hfp = qemu-arm-static-5.1.0-linux-2
emulatorExecutable.linux_x64-linux_arm32_hfp = qemu-arm-static-5.1.0-linux-2/qemu-arm
dependencies.linux_x64-linux_arm32_hfp = \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9 \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-2-linux-x86-64
dependencies.mingw_x64-linux_arm32_hfp = \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9 \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-mingw-w64-x86-64
dependencies.macos_x64-linux_arm32_hfp = \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9 \
arm-unknown-linux-gnueabihf-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-3-darwin-macos
quadruple.linux_arm32_hfp = arm-unknown-linux-gnueabihf
@@ -513,7 +513,7 @@ runtimeDefinitions.linux_arm32_hfp = USE_GCC_UNWIND=1 KONAN_LINUX=1 \
KONAN_ARM32=1 USE_ELF_SYMBOLS=1 ELFSIZE=32 KONAN_NO_UNALIGNED_ACCESS=1
# Linux arm64
gccToolchain.linux_arm64 = aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9
gccToolchain.linux_arm64 = aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2
targetToolchain.linux_x64-linux_arm64 = $gccToolchain.linux_arm64/aarch64-unknown-linux-gnu
targetToolchain.mingw_x64-linux_arm64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
@@ -523,13 +523,13 @@ emulatorDependency.linux_x64-linux_arm64 = qemu-aarch64-static-5.1.0-linux-2
emulatorExecutable.linux_x64-linux_arm64 = qemu-aarch64-static-5.1.0-linux-2/qemu-aarch64
dependencies.linux_x64-linux_arm64 = \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9 \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2 \
libffi-3.2.1-2-linux-x86-64
dependencies.mingw_x64-linux_arm64 = \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9 \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2 \
libffi-3.2.1-mingw-w64-x86-64
dependencies.macos_x64-linux_arm64 = \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9 \
aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2 \
libffi-3.2.1-3-darwin-macos
quadruple.linux_arm64 = aarch64-unknown-linux-gnu
@@ -565,14 +565,14 @@ runtimeDefinitions.linux_arm64 = USE_GCC_UNWIND=1 KONAN_LINUX=1 KONAN_ARM64=1 \
USE_ELF_SYMBOLS=1 ELFSIZE=64
# MIPS
gccToolchain.linux_mips32 = mips-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9
gccToolchain.linux_mips32 = mips-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2
targetToolchain.linux_x64-linux_mips32 = $gccToolchain.linux_mips32/mips-unknown-linux-gnu
emulatorDependency.linux_x64-linux_mips32 = qemu-mips-static-5.1.0-linux-2
emulatorExecutable.linux_x64-linux_mips32 = qemu-mips-static-5.1.0-linux-2/qemu-mips
dependencies.linux_x64-linux_mips32 = \
mips-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9 \
mips-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-2-linux-x86-64
quadruple.linux_mips32 = mips-unknown-linux-gnu
@@ -607,14 +607,14 @@ runtimeDefinitions.linux_mips32 = USE_GCC_UNWIND=1 KONAN_LINUX=1 KONAN_MIPS32=1
USE_ELF_SYMBOLS=1 ELFSIZE=32 KONAN_NO_64BIT_ATOMIC=1 KONAN_NO_UNALIGNED_ACCESS=1
# MIPSel
gccToolchain.linux_mipsel32 = mipsel-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9
gccToolchain.linux_mipsel32 = mipsel-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2
targetToolchain.linux_x64-linux_mipsel32 = $gccToolchain.linux_mipsel32/mipsel-unknown-linux-gnu
emulatorDependency.linux_x64-linux_mipsel32 = qemu-mipsel-static-5.1.0-linux-2
emulatorExecutable.linux_x64-linux_mipsel32 = qemu-mipsel-static-5.1.0-linux-2/qemu-mipsel
dependencies.linux_x64-linux_mipsel32 = \
mipsel-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9 \
mipsel-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2 \
libffi-3.2.1-2-linux-x86-64
quadruple.linux_mipsel32 = mipsel-unknown-linux-gnu

View File

@@ -1353,7 +1353,7 @@ inline void decrementRC(ContainerHeader* container) {
container->setBuffered();
if (state->toFree != nullptr) {
state->toFree->push_back(container);
MEMORY_LOG("toFree is now %d\n", state->toFree->size())
MEMORY_LOG("toFree is now %lu\n", state->toFree->size())
if (state->gcSuspendCount == 0 && state->toRelease->size() >= state->gcThreshold) {
GC_LOG("Calling GC from DecrementRC: %d\n", state->toRelease->size())
garbageCollect(state, false);
@@ -1396,7 +1396,7 @@ inline void enqueueDecrementRC(ContainerHeader* container) {
auto* state = memoryState;
if (CanCollect) {
if (state->toRelease->size() >= state->gcThreshold && state->gcSuspendCount == 0) {
GC_LOG("Calling GC from EnqueueDecrementRC: %d\n", state->toRelease->size())
GC_LOG("Calling GC from EnqueueDecrementRC: %zu\n", state->toRelease->size())
garbageCollect(state, false);
}
}
@@ -1856,7 +1856,7 @@ void garbageCollect(MemoryState* state, bool force) {
return;
}
GC_LOG(">>> %s GC: threshold = %d toFree %d toRelease %d alloc = %lld\n", \
GC_LOG(">>> %s GC: threshold = %zu toFree %zu toRelease %zu alloc = %lld\n", \
force ? "forced" : "regular", state->gcThreshold, state->toFree->size(),
state->toRelease->size(), allocSinceLastGc)
@@ -1892,10 +1892,10 @@ void garbageCollect(MemoryState* state, bool force) {
size_t stackReferences = afterDecrements - beforeDecrements;
if (state->gcErgonomics && stackReferences * 5 > state->gcThreshold) {
increaseGcThreshold(state);
GC_LOG("||| GC: too many stack references, increased threshold to %d\n", state->gcThreshold);
GC_LOG("||| GC: too many stack references, increased threshold to %zu\n", state->gcThreshold);
}
GC_LOG("||| GC: toFree %d toRelease %d\n", state->toFree->size(), state->toRelease->size())
GC_LOG("||| GC: toFree %zu toRelease %zu\n", state->toFree->size(), state->toRelease->size())
#if PROFILE_GC
auto processFinalizerQueueStartTime = konan::getTimeMicros();
#endif
@@ -1938,7 +1938,7 @@ void garbageCollect(MemoryState* state, bool force) {
auto gcToComputeRatio = double(gcEndTime - gcStartTime) / (gcStartTime - state->lastGcTimestamp + 1);
if (!force && gcToComputeRatio > kGcToComputeRatioThreshold) {
increaseGcThreshold(state);
GC_LOG("Adjusting GC threshold to %d\n", state->gcThreshold);
GC_LOG("Adjusting GC threshold to %zu\n", state->gcThreshold);
}
}
GC_LOG("GC: gcToComputeRatio=%f duration=%lld sinceLast=%lld\n", double(gcEndTime - gcStartTime) / (gcStartTime - state->lastGcTimestamp + 1), (gcEndTime - gcStartTime), gcStartTime - state->lastGcTimestamp);
@@ -1950,7 +1950,7 @@ void garbageCollect(MemoryState* state, bool force) {
}
#endif
GC_LOG("<<< GC: toFree %d toRelease %d\n", state->toFree->size(), state->toRelease->size())
GC_LOG("<<< GC: toFree %zu toRelease %zu\n", state->toFree->size(), state->toRelease->size())
}
void rememberNewContainer(ContainerHeader* container) {
@@ -2192,6 +2192,37 @@ void updateHeapRef(ObjHeader** location, const ObjHeader* object) {
}
}
template <bool Strict>
void updateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
// In case of coping inside same array number of decrements and increments of RC can be decreased.
auto countIndex = [=](int i) { return (fromIndex < toIndex) ? count - 1 - i : i; };
int rewrittenElementsNumber = std::abs(fromIndex - toIndex);
// Release rewritten elements.
for (int i = 0; i < rewrittenElementsNumber; i++) {
int index = countIndex(i);
ObjHeader* old = *ArrayAddressOfElementAt(array, toIndex + index);
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) =
*ArrayAddressOfElementAt(array, fromIndex + index);
if (old != nullptr) {
releaseHeapRef<Strict>(old);
}
}
for (int i = rewrittenElementsNumber; i < count - rewrittenElementsNumber; i++) {
int index = countIndex(i);
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) =
*ArrayAddressOfElementAt(array, fromIndex + index);
}
for (int i = count - rewrittenElementsNumber; i < count; i++) {
int index = countIndex(i);
ObjHeader* object = *ArrayAddressOfElementAt(array, fromIndex + index);
// Add extra heap ref for copied elements.
if (object != nullptr) {
addHeapRef(object);
}
*const_cast<const ObjHeader**>(ArrayAddressOfElementAt(array, toIndex + index)) = object;
}
}
template <bool Strict>
void updateStackRef(ObjHeader** location, const ObjHeader* object) {
UPDATE_REF_EVENT(memoryState, *location, object, location, 1)
@@ -2241,7 +2272,7 @@ inline void checkIfGcNeeded(MemoryState* state) {
if (state != nullptr && state->allocSinceLastGc > state->allocSinceLastGcThreshold && state->gcSuspendCount == 0) {
// To avoid GC trashing check that at least 10ms passed since last GC.
if (konan::getTimeMicros() - state->lastGcTimestamp > 10 * 1000) {
GC_LOG("Calling GC from checkIfGcNeeded: %d\n", state->toRelease->size())
GC_LOG("Calling GC from checkIfGcNeeded: %zu\n", state->toRelease->size())
garbageCollect(state, false);
}
}
@@ -2252,7 +2283,7 @@ inline void checkIfForceCyclicGcNeeded(MemoryState* state) {
&& state->gcSuspendCount == 0) {
// To avoid GC trashing check that at least 10ms passed since last GC.
if (konan::getTimeMicros() - state->lastGcTimestamp > 10 * 1000) {
GC_LOG("Calling GC from checkIfForceCyclicGcNeeded: %d\n", state->toFree->size())
GC_LOG("Calling GC from checkIfForceCyclicGcNeeded: %zu\n", state->toFree->size())
garbageCollect(state, true);
}
}
@@ -2585,7 +2616,7 @@ KInt getGCThreshold() {
}
void setGCCollectCyclesThreshold(KLong value) {
GC_LOG("setGCCollectCyclesThreshold %d\n", value)
GC_LOG("setGCCollectCyclesThreshold %lld\n", value)
if (value <= 0) {
ThrowIllegalArgumentException();
}
@@ -2617,7 +2648,7 @@ void setTuneGCThreshold(KBoolean value) {
}
KBoolean getTuneGCThreshold() {
GC_LOG("getTuneGCThreshold %d\n")
GC_LOG("getTuneGCThreshold %d\n", memoryState->gcErgonomics)
return memoryState->gcErgonomics;
}
@@ -3367,6 +3398,15 @@ RUNTIME_NOTHROW void UpdateHeapRefRelaxed(ObjHeader** location, const ObjHeader*
updateHeapRef<false>(location, object);
}
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArrayStrict(const ArrayHeader* array, int fromIndex, int toIndex,
int count) {
updateHeapRefsInsideOneArray<true>(array, fromIndex, toIndex, count);
}
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArrayRelaxed(const ArrayHeader* array, int fromIndex, int toIndex,
int count) {
updateHeapRefsInsideOneArray<false>(array, fromIndex, toIndex, count);
}
RUNTIME_NOTHROW void UpdateReturnRefStrict(ObjHeader** returnSlot, const ObjHeader* value) {
updateReturnRef<true>(returnSlot, value);
}

View File

@@ -322,6 +322,8 @@ MODEL_VARIANTS(void, UpdateStackRef, ObjHeader** location, const ObjHeader* obje
MODEL_VARIANTS(void, UpdateHeapRef, ObjHeader** location, const ObjHeader* object);
MODEL_VARIANTS(void, UpdateHeapRefIfNull, ObjHeader** location, const ObjHeader* object);
MODEL_VARIANTS(void, UpdateReturnRef, ObjHeader** returnSlot, const ObjHeader* object);
MODEL_VARIANTS(void, UpdateHeapRefsInsideOneArray, const ArrayHeader* array, int fromIndex, int toIndex,
int count);
MODEL_VARIANTS(void, EnterFrame, ObjHeader** start, int parameters, int count);
MODEL_VARIANTS(void, LeaveFrame, ObjHeader** start, int parameters, int count);

View File

@@ -133,15 +133,20 @@ void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(destination);
if (fromIndex >= toIndex) {
for (int index = 0; index < count; index++) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
}
if (CurrentMemoryModel != MemoryModel::kExperimental && array == destinationArray &&
std::abs(fromIndex - toIndex) < count) {
UpdateHeapRefsInsideOneArray(array, fromIndex, toIndex, count);
} else {
for (int index = count - 1; index >= 0; index--) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
if (fromIndex >= toIndex) {
for (int index = 0; index < count; index++) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
}
} else {
for (int index = count - 1; index >= 0; index--) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
}
}
}
}

View File

@@ -210,6 +210,8 @@ void ZeroStackRef(ObjHeader** location) RUNTIME_NOTHROW;
void UpdateStackRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates heap/static data location.
void UpdateHeapRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates heap/static data in one array.
void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) RUNTIME_NOTHROW;
// Updates location if it is null, atomically.
void UpdateHeapRefIfNull(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates reference in return slot.

View File

@@ -38,3 +38,20 @@ RUNTIME_WEAK void __throw_length_error(const char* __s __attribute__((unused)))
} // namespace std
#endif // KONAN_LINUX || KONAN_WINDOWS
#if KONAN_LINUX
#include <system_error>
// Since GCC 4.8.5 mangling for std::system_category has changed from _ZNSt3_V215system_categoryEv to _ZSt15system_categoryv.
// It causes linkage problems in case of kotlinx-datetime:0.1.1 usage, because its C++ dependency is compiled with old GCC 4.8.5.
// So to avoid nasty linkage problems when users migrate their projects with kotlinx-datetime:0.1.1 dependency from 1.4.x to 1.5.x
// we provide this compatibility layer.
RUNTIME_WEAK
const std::error_category& std_system_category_backward_compatibility_with_gcc_4_8_5() noexcept __asm("_ZSt15system_categoryv");
const std::error_category& std_system_category_backward_compatibility_with_gcc_4_8_5() noexcept {
return std::system_category();
}
#endif // KONAN_LINUX

View File

@@ -189,6 +189,11 @@ extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateHeapRefIfNull(ObjHeader** lo
mm::CompareAndSwapHeapRef(location, nullptr, const_cast<ObjHeader*>(object), &result);
}
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex,
int toIndex, int count) {
RuntimeFail("Only for legacy MM");
}
extern "C" ALWAYS_INLINE RUNTIME_NOTHROW void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) {
mm::SetStackRef(returnSlot, const_cast<ObjHeader*>(object));
}

View File

@@ -206,6 +206,71 @@ public:
Node* node_;
};
class Consumer : private MoveOnly {
public:
class Iterator {
public:
Node& operator*() noexcept { return *node_; }
Node* operator->() noexcept { return node_; }
Iterator& operator++() noexcept {
node_ = node_->next_.get();
return *this;
}
bool operator==(const Iterator& rhs) const noexcept { return node_ == rhs.node_; }
bool operator!=(const Iterator& rhs) const noexcept { return node_ != rhs.node_; }
private:
friend class Consumer;
explicit Iterator(Node* node) noexcept : node_(node) {}
Node* node_;
};
Consumer() noexcept = default;
Consumer(Consumer&&) noexcept = default;
Consumer& operator=(Consumer&&) noexcept = default;
~Consumer() {
// Make sure not to blow up the stack by nested `~Node` calls.
for (auto node = std::move(root_); node != nullptr; node = std::move(node->next_)) {
}
}
Iterator begin() noexcept { return Iterator(root_.get()); }
Iterator end() noexcept { return Iterator(nullptr); }
private:
friend class ObjectFactoryStorage;
void Insert(unique_ptr<Node> node) noexcept {
AssertCorrect();
auto* nodePtr = node.get();
if (!root_) {
root_ = std::move(node);
} else {
last_->next_ = std::move(node);
}
last_ = nodePtr;
AssertCorrect();
}
ALWAYS_INLINE void AssertCorrect() const noexcept {
if (root_ == nullptr) {
RuntimeAssert(last_ == nullptr, "last_ must be null");
} else {
RuntimeAssert(last_ != nullptr, "last_ must not be null");
RuntimeAssert(last_->next_ == nullptr, "last_ must not have next");
}
}
unique_ptr<Node> root_;
Node* last_ = nullptr;
};
class Iterable : private MoveOnly {
public:
explicit Iterable(ObjectFactoryStorage& owner) noexcept : owner_(owner), guard_(owner_.mutex_) {}
@@ -213,7 +278,16 @@ public:
Iterator begin() noexcept { return Iterator(nullptr, owner_.root_.get()); }
Iterator end() noexcept { return Iterator(owner_.last_, nullptr); }
void EraseAndAdvance(Iterator& iterator) noexcept { iterator.node_ = owner_.EraseUnsafe(iterator.previousNode_); }
void EraseAndAdvance(Iterator& iterator) noexcept {
auto result = owner_.ExtractUnsafe(iterator.previousNode_);
iterator.node_ = result.second;
}
void MoveAndAdvance(Consumer& consumer, Iterator& iterator) noexcept {
auto result = owner_.ExtractUnsafe(iterator.previousNode_);
iterator.node_ = result.second;
consumer.Insert(std::move(result.first));
}
private:
ObjectFactoryStorage& owner_; // weak
@@ -230,18 +304,19 @@ public:
private:
// Expects `mutex_` to be held by the current thread.
Node* EraseUnsafe(Node* previousNode) noexcept {
std::pair<unique_ptr<Node>, Node*> ExtractUnsafe(Node* previousNode) noexcept {
RuntimeAssert(root_ != nullptr, "Must not be empty");
AssertCorrectUnsafe();
if (previousNode == nullptr) {
// Deleting the root.
root_ = std::move(root_->next_);
// Extracting the root.
auto node = std::move(root_);
root_ = std::move(node->next_);
if (!root_) {
last_ = nullptr;
}
AssertCorrectUnsafe();
return root_.get();
return {std::move(node), root_.get()};
}
auto node = std::move(previousNode->next_);
@@ -251,7 +326,7 @@ private:
}
AssertCorrectUnsafe();
return previousNode->next_.get();
return {std::move(node), previousNode->next_.get()};
}
// Expects `mutex_` to be held by the current thread.
@@ -436,6 +511,38 @@ public:
typename Storage::Iterator iterator_;
};
class FinalizerQueue : private MoveOnly {
public:
class Iterator {
public:
NodeRef operator*() noexcept { return NodeRef(*iterator_); }
NodeRef operator->() noexcept { return NodeRef(*iterator_); }
Iterator& operator++() noexcept {
++iterator_;
return *this;
}
bool operator==(const Iterator& rhs) const noexcept { return iterator_ == rhs.iterator_; }
bool operator!=(const Iterator& rhs) const noexcept { return iterator_ != rhs.iterator_; }
private:
friend class ObjectFactory;
explicit Iterator(typename Storage::Consumer::Iterator iterator) noexcept : iterator_(std::move(iterator)) {}
typename Storage::Consumer::Iterator iterator_;
};
Iterator begin() noexcept { return Iterator(consumer_.begin()); }
Iterator end() noexcept { return Iterator(consumer_.end()); }
private:
friend class ObjectFactory;
typename Storage::Consumer consumer_;
};
class Iterable {
public:
Iterable(ObjectFactory& owner) noexcept : iter_(owner.storage_.Iter()) {}
@@ -445,6 +552,10 @@ public:
void EraseAndAdvance(Iterator& iterator) noexcept { iter_.EraseAndAdvance(iterator.iterator_); }
void MoveAndAdvance(FinalizerQueue& queue, Iterator& iterator) noexcept {
iter_.MoveAndAdvance(queue.consumer_, iterator.iterator_);
}
private:
typename Storage::Iterable iter_;
};

View File

@@ -32,6 +32,9 @@ using ObjectFactoryStorageRegular = ObjectFactoryStorage<alignof(void*)>;
template <typename Storage>
using Producer = typename Storage::Producer;
template <typename Storage>
using Consumer = typename Storage::Consumer;
template <size_t DataAlignment>
KStdVector<void*> Collect(ObjectFactoryStorage<DataAlignment>& storage) {
KStdVector<void*> result;
@@ -50,6 +53,15 @@ KStdVector<T> Collect(ObjectFactoryStorage<DataAlignment>& storage) {
return result;
}
template <typename T, size_t DataAlignment>
KStdVector<T> Collect(Consumer<ObjectFactoryStorage<DataAlignment>>& consumer) {
KStdVector<T> result;
for (auto& node : consumer) {
result.push_back(*static_cast<T*>(node.Data()));
}
return result;
}
struct MoveOnlyImpl : private MoveOnly {
MoveOnlyImpl(int value1, int value2) : value1(value1), value2(value2) {}
@@ -310,6 +322,7 @@ TEST(ObjectFactoryStorageTest, EraseTheOnlyElement) {
auto iter = storage.Iter();
auto it = iter.begin();
iter.EraseAndAdvance(it);
EXPECT_THAT(it, iter.end());
}
auto actual = Collect<int>(storage);
@@ -317,6 +330,174 @@ TEST(ObjectFactoryStorageTest, EraseTheOnlyElement) {
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ObjectFactoryStorageTest, MoveFirst) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Insert<int>(3);
producer.Publish();
{
auto iter = storage.Iter();
for (auto it = iter.begin(); it != iter.end();) {
if (it->Data<int>() == 1) {
iter.MoveAndAdvance(consumer, it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::ElementsAre(2, 3));
EXPECT_THAT(actualConsumer, testing::ElementsAre(1));
}
TEST(ObjectFactoryStorageTest, MoveMiddle) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Insert<int>(3);
producer.Publish();
{
auto iter = storage.Iter();
for (auto it = iter.begin(); it != iter.end();) {
if (it->Data<int>() == 2) {
iter.MoveAndAdvance(consumer, it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::ElementsAre(1, 3));
EXPECT_THAT(actualConsumer, testing::ElementsAre(2));
}
TEST(ObjectFactoryStorageTest, MoveLast) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Insert<int>(3);
producer.Publish();
{
auto iter = storage.Iter();
for (auto it = iter.begin(); it != iter.end();) {
if (it->Data<int>() == 3) {
iter.MoveAndAdvance(consumer, it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::ElementsAre(1, 2));
EXPECT_THAT(actualConsumer, testing::ElementsAre(3));
}
TEST(ObjectFactoryStorageTest, MoveAll) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Insert<int>(3);
producer.Publish();
{
auto iter = storage.Iter();
for (auto it = iter.begin(); it != iter.end();) {
iter.MoveAndAdvance(consumer, it);
}
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::IsEmpty());
EXPECT_THAT(actualConsumer, testing::ElementsAre(1, 2, 3));
}
TEST(ObjectFactoryStorageTest, MoveTheOnlyElement) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Publish();
{
auto iter = storage.Iter();
auto it = iter.begin();
iter.MoveAndAdvance(consumer, it);
EXPECT_THAT(it, iter.end());
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::IsEmpty());
EXPECT_THAT(actualConsumer, testing::ElementsAre(1));
}
TEST(ObjectFactoryStorageTest, MoveAndErase) {
ObjectFactoryStorageRegular storage;
Producer<ObjectFactoryStorageRegular> producer(storage, SimpleAllocator());
Consumer<ObjectFactoryStorageRegular> consumer;
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Insert<int>(3);
producer.Insert<int>(4);
producer.Insert<int>(5);
producer.Insert<int>(6);
producer.Insert<int>(7);
producer.Insert<int>(8);
producer.Insert<int>(9);
producer.Publish();
{
auto iter = storage.Iter();
for (auto it = iter.begin(); it != iter.end();) {
++it;
iter.EraseAndAdvance(it);
iter.MoveAndAdvance(consumer, it);
}
}
auto actual = Collect<int>(storage);
auto actualConsumer = Collect<int, alignof(void*)>(consumer);
EXPECT_THAT(actual, testing::ElementsAre(1, 4, 7));
EXPECT_THAT(actualConsumer, testing::ElementsAre(3, 6, 9));
}
TEST(ObjectFactoryStorageTest, ConcurrentPublish) {
ObjectFactoryStorageRegular storage;
constexpr int kThreadCount = kDefaultThreadCount;
@@ -657,6 +838,50 @@ TEST(ObjectFactoryTest, Erase) {
}
}
TEST(ObjectFactoryTest, Move) {
auto objectTypeInfo = MakeObjectTypeInfo(24);
auto arrayTypeInfo = MakeArrayTypeInfo(24);
GC::ThreadData gc;
ObjectFactory objectFactory;
ObjectFactory::ThreadQueue threadQueue(objectFactory, gc);
ObjectFactory::FinalizerQueue finalizerQueue;
for (int i = 0; i < 10; ++i) {
threadQueue.CreateObject(objectTypeInfo.get());
threadQueue.CreateArray(arrayTypeInfo.get(), 3);
}
threadQueue.Publish();
{
auto iter = objectFactory.Iter();
for (auto it = iter.begin(); it != iter.end();) {
if (it->IsArray()) {
iter.MoveAndAdvance(finalizerQueue, it);
} else {
++it;
}
}
}
{
auto iter = objectFactory.Iter();
int count = 0;
for (auto it = iter.begin(); it != iter.end(); ++it, ++count) {
EXPECT_FALSE(it->IsArray());
}
EXPECT_THAT(count, 10);
}
{
int count = 0;
for (auto it = finalizerQueue.begin(); it != finalizerQueue.end(); ++it, ++count) {
EXPECT_TRUE(it->IsArray());
}
EXPECT_THAT(count, 10);
}
}
TEST(ObjectFactoryTest, ConcurrentPublish) {
auto typeInfo = MakeObjectTypeInfo(24);
ObjectFactory objectFactory;

View File

@@ -67,4 +67,8 @@ RUNTIME_NOTHROW void UpdateStackRef(ObjHeader** location, const ObjHeader* objec
UpdateStackRefRelaxed(location, object);
}
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
UpdateHeapRefsInsideOneArrayRelaxed(array, fromIndex, toIndex, count);
}
} // extern "C"

View File

@@ -67,4 +67,8 @@ RUNTIME_NOTHROW void UpdateStackRef(ObjHeader** location, const ObjHeader* objec
UpdateStackRefStrict(location, object);
}
RUNTIME_NOTHROW void UpdateHeapRefsInsideOneArray(const ArrayHeader* array, int fromIndex, int toIndex, int count) {
UpdateHeapRefsInsideOneArrayStrict(array, fromIndex, toIndex, count);
}
} // extern "C"

View File

@@ -4,9 +4,8 @@ This example shows how to collect coverage information during execution of the t
Please note that this functionality will be incorporated into Gradle plugin so you won't need to do it by hand in the nearest future.
### Prerequisites
`createCoverageReport` task requires `llvm-profdata` and `llvm-cov` to be added to the `$PATH`.
They can be found in the Kotlin/Native dependencies dir. By default it should look like
`$HOME/.konan/dependencies/clang-llvm-6.0.1-darwin-macos/bin`
`createCoverageReport` task requires `llvm-profdata` and `llvm-cov` to be added to the `$PATH`.
In case of macOS, use tools from Xcode (`/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin`).
For Windows and Linux, use the ones from Kotlin/Native LLVM distribution (e.g. `$HOME/.konan/dependencies/clang-llvm-8.0.0-linux-x86-64/bin`).
### Usage
Just run `createCoverageReport` task.

View File

@@ -1,5 +1,5 @@
# We might want to switch to alpine, but it is not stable enough yet.
FROM ubuntu:20.04
FROM ubuntu:14.04
ENV TZ=Europe/Moscow
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
@@ -7,7 +7,7 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Install crosstool-ng deps.
RUN apt-get update
RUN apt-get install -y curl gcc git g++ gperf bison flex texinfo help2man make libncurses5-dev \
python3-dev autoconf automake libtool libtool-bin gawk wget bzip2 xz-utils unzip \
python3-dev autoconf automake libtool gawk wget bzip2 xz-utils unzip \
patch libstdc++6 rsync
# Put a fix for strip.
@@ -40,7 +40,8 @@ RUN mkdir src
ENV TARGET=x86_64-unknown-linux-gnu
ENV VERSION=gcc-8.3.0-glibc-2.19-kernel-4.9
ENV TOOLCHAIN_VERSION_SUFFIX=""
# Add entry point.
COPY build_toolchain.sh .
ENTRYPOINT "/bin/bash" "build_toolchain.sh" ${TARGET} ${VERSION}
ENTRYPOINT "/bin/bash" "build_toolchain.sh" ${TARGET} ${VERSION} ${TOOLCHAIN_VERSION_SUFFIX}

View File

@@ -8,8 +8,9 @@ This directory contains a set of scripts and configuration files that allow one
### Usage
1. First, you need to build a Docker image with crosstool-ng inside. Use `create_image.sh` for it.
2. Now you can build an actual toolchain. To pick one, take a look inside `toolchains` folder.
It is organized as `$TARGET/$VERSION`. Then run `./run_container.sh $TARGET $VERSION`. Building a toolchain might take a while (~17 minutes on Ryzen 5 3600).
It is organized as `$TARGET/$VERSION`. Then run `./run_container.sh $TARGET $VERSION $TOOLCHAIN_VERSION_SUFFIX`. Building a toolchain might take a while (~17 minutes on Ryzen 5 3600).
Once ready, an archive will be placed in `artifacts` folder.
`$TOOLCHAIN_VERSION_SUFFIX` is an optional argument that adds suffix to the end of toolchain name.
### Example
```bash

View File

@@ -4,6 +4,7 @@ set -eou pipefail
TARGET=$1
VERSION=$2
TOOLCHAIN_VERSION_SUFFIX=$3
HOME=/home/ct
ZLIB_VERSION=1.2.11
@@ -33,7 +34,12 @@ build_zlib() {
build_archive() {
cd $HOME/x-tools
FULL_NAME=$TARGET-$VERSION
if [ -z "$TOOLCHAIN_VERSION_SUFFIX" ]
then
FULL_NAME="$TARGET-$VERSION"
else
FULL_NAME="$TARGET-$VERSION-$TOOLCHAIN_VERSION_SUFFIX"
fi
mv "$TARGET" "$FULL_NAME"
ARCHIVE_NAME="$FULL_NAME.tar.gz"
tar -czvf "$ARCHIVE_NAME" "$FULL_NAME"

View File

@@ -5,11 +5,16 @@ CONTAINER_NAME=kotlin-toolchain-builder
IMAGE_NAME=kotlin-toolchain-builder
TARGET=$1
VERSION=$2
TOOLCHAIN_VERSION_SUFFIX="${3:-""}"
docker ps -a | grep $CONTAINER_NAME > /dev/null \
&& docker stop $CONTAINER_NAME > /dev/null \
&& docker rm $CONTAINER_NAME > /dev/null
echo "Running build script in container..."
docker run -it -v "$PWD"/artifacts:/artifacts --env TARGET="$TARGET" --env VERSION="$VERSION" --name=$CONTAINER_NAME $IMAGE_NAME
docker run -it -v "$PWD"/artifacts:/artifacts \
--env TARGET="$TARGET" \
--env VERSION="$VERSION" \
--env TOOLCHAIN_VERSION_SUFFIX="$TOOLCHAIN_VERSION_SUFFIX" \
--name=$CONTAINER_NAME $IMAGE_NAME
echo "Done."