Top level values can be only accessed from the main thread. (#1922)

This commit is contained in:
Nikolay Igotti
2018-08-24 12:37:59 +03:00
committed by GitHub
parent 1d015e1fc8
commit 066429831e
14 changed files with 104 additions and 18 deletions
@@ -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())
@@ -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))
}
@@ -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") }
@@ -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)
@@ -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)
}
@@ -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 {