Top level values can be only accessed from the main thread. (#1922)
This commit is contained in:
+6
-1
@@ -370,7 +370,12 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
|
||||
val listOfInternal = internalFunction("listOfInternal")
|
||||
|
||||
val threadLocal =
|
||||
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("kotlin.native.ThreadLocal")))!!
|
||||
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(
|
||||
ClassId.topLevel(FqName("kotlin.native.ThreadLocal")))!!
|
||||
|
||||
val sharedImmutable =
|
||||
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(
|
||||
ClassId.topLevel(FqName("kotlin.native.SharedImmutable")))!!
|
||||
|
||||
private fun internalFunction(name: String): IrSimpleFunctionSymbol =
|
||||
symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
|
||||
|
||||
+4
@@ -305,6 +305,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
call(context.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler)
|
||||
}
|
||||
|
||||
fun checkMainThread(exceptionHandler: ExceptionHandler) {
|
||||
call(context.llvm.checkMainThread, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
|
||||
}
|
||||
|
||||
private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
|
||||
call(context.llvm.updateReturnRefFunction, listOf(address, value))
|
||||
}
|
||||
|
||||
+1
@@ -395,6 +395,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val initRuntimeIfNeeded = importRtFunction("Kotlin_initRuntimeIfNeeded")
|
||||
val mutationCheck = importRtFunction("MutationCheck")
|
||||
val freezeSubgraph = importRtFunction("FreezeSubgraph")
|
||||
val checkMainThread = importRtFunction("CheckIsMainThread")
|
||||
|
||||
val createKotlinObjCClass by lazy { importRtFunction("CreateKotlinObjCClass") }
|
||||
val getObjCKotlinTypeInfo by lazy { importRtFunction("GetObjCKotlinTypeInfo") }
|
||||
|
||||
+27
-6
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -49,12 +50,27 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
|
||||
private val threadLocalAnnotationFqName = FqName("kotlin.native.ThreadLocal")
|
||||
private val sharedAnnotationFqName = FqName("kotlin.native.SharedImmutable")
|
||||
|
||||
// TODO: maybe unannotated singleton objects shall be accessed from main thread only as well?
|
||||
val IrClass.objectIsShared get() =
|
||||
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName)
|
||||
|
||||
val IrField.isThreadLocal get() =
|
||||
descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName)
|
||||
|
||||
val IrField.isShared get() =
|
||||
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) && !descriptor.isVar
|
||||
descriptor.annotations.hasAnnotation(sharedAnnotationFqName)
|
||||
|
||||
val IrField.isMainOnly get() =
|
||||
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) &&
|
||||
!descriptor.annotations.hasAnnotation(sharedAnnotationFqName) &&
|
||||
!descriptor.isDelegated
|
||||
|
||||
val IrField.isMainOnlyNonPrimitive get() = when {
|
||||
KotlinBuiltIns.isPrimitiveType(descriptor.type) -> false
|
||||
else -> isMainOnly
|
||||
}
|
||||
|
||||
internal fun emitLLVM(context: Context, phaser: PhaseManager) {
|
||||
val irModule = context.irModule!!
|
||||
@@ -404,7 +420,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
context.llvm.fileInitializers
|
||||
.forEach {
|
||||
if (it.initializer?.expression !is IrConst<*>?) {
|
||||
if (it.isShared) {
|
||||
if (!it.isThreadLocal) {
|
||||
val initialization = evaluateExpression(it.initializer!!.expression)
|
||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||
freeze(initialization, currentCodeContext.exceptionHandler)
|
||||
@@ -419,7 +435,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
context.llvm.fileInitializers
|
||||
.forEach {
|
||||
if (it.initializer?.expression !is IrConst<*>?) {
|
||||
if (!it.isShared) {
|
||||
if (it.isThreadLocal) {
|
||||
val initialization = evaluateExpression(it.initializer!!.expression)
|
||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||
storeAny(initialization, address)
|
||||
@@ -432,7 +448,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
appendingTo(bbLocalDeinit) {
|
||||
context.llvm.fileInitializers.forEach {
|
||||
// Only if a subject for memory management.
|
||||
if (it.type.binaryTypeIsReference() && !it.isShared) {
|
||||
if (it.type.binaryTypeIsReference() && it.isThreadLocal) {
|
||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||
storeAny(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
@@ -445,7 +461,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
context.llvm.fileInitializers
|
||||
// Only if a subject for memory management.
|
||||
.forEach {
|
||||
if (it.type.binaryTypeIsReference() && it.isShared) {
|
||||
if (it.type.binaryTypeIsReference() && !it.isThreadLocal) {
|
||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||
storeAny(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
@@ -1428,7 +1444,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return functionGenerationContext.loadSlot(
|
||||
fieldPtrOfClass(thisPtr, value.symbol.owner), value.descriptor.isVar())
|
||||
} else {
|
||||
assert (value.receiver == null)
|
||||
assert(value.receiver == null)
|
||||
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive) {
|
||||
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
||||
}
|
||||
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
||||
return functionGenerationContext.loadSlot(ptr, value.descriptor.isVar())
|
||||
}
|
||||
@@ -1459,6 +1478,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
} else {
|
||||
assert(value.receiver == null)
|
||||
val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
||||
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive)
|
||||
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
||||
if (value.symbol.owner.isShared)
|
||||
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
||||
functionGenerationContext.storeAny(valueToAssign, globalValue)
|
||||
|
||||
+3
-6
@@ -376,21 +376,18 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
|
||||
val containingClass = descriptor.containingClass
|
||||
if (containingClass != null) {
|
||||
val classDeclarations = this.classes[containingClass] ?: error(containingClass.descriptor.toString())
|
||||
|
||||
val classDeclarations = this.classes[containingClass] ?:
|
||||
error(containingClass.descriptor.toString())
|
||||
val allFields = classDeclarations.fields
|
||||
|
||||
this.fields[descriptor] = FieldLlvmDeclarations(
|
||||
allFields.indexOf(descriptor),
|
||||
classDeclarations.bodyType
|
||||
)
|
||||
} else {
|
||||
|
||||
// Fields are module-private, so we use internal name:
|
||||
val name = "kvar:" + qualifyInternalName(descriptor)
|
||||
|
||||
val storage = addGlobal(
|
||||
name, getLLVMType(descriptor.type), isExported = false, threadLocal = !declaration.isShared)
|
||||
name, getLLVMType(descriptor.type), isExported = false, threadLocal = declaration.isThreadLocal)
|
||||
|
||||
this.staticFields[descriptor] = StaticFieldLlvmDeclarations(storage)
|
||||
}
|
||||
|
||||
+5
-1
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -317,7 +319,9 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
|
||||
IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
|
||||
|
||||
private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: KotlinType): PropertyDescriptorImpl {
|
||||
return PropertyDescriptorImpl.create(containingDeclaration, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
|
||||
return PropertyDescriptorImpl.create(containingDeclaration,
|
||||
AnnotationsImpl(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
|
||||
emptyMap(), SourceElement.NO_SOURCE))), Modality.FINAL, Visibilities.PRIVATE,
|
||||
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
|
||||
false, false, false, false, false, false).apply {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user