[K/N] Make atomic ordering weaker for less performance harm
This commit is contained in:
+3
-2
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
@@ -52,6 +52,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
private val platformManager = PlatformManager(distribution)
|
private val platformManager = PlatformManager(distribution)
|
||||||
internal val targetManager = platformManager.targetManager(configuration.get(KonanConfigKeys.TARGET))
|
internal val targetManager = platformManager.targetManager(configuration.get(KonanConfigKeys.TARGET))
|
||||||
internal val target = targetManager.target
|
internal val target = targetManager.target
|
||||||
|
val targetHasAddressDependency get() = target.hasAddressDependencyInMemoryModel()
|
||||||
internal val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)!!
|
internal val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)!!
|
||||||
|
|
||||||
// TODO: debug info generation mode and debug/release variant selection probably requires some refactoring.
|
// TODO: debug info generation mode and debug/release variant selection probably requires some refactoring.
|
||||||
|
|||||||
+15
-4
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the LICENSE file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.llvm
|
package org.jetbrains.kotlin.backend.konan.llvm
|
||||||
@@ -1144,13 +1144,24 @@ internal abstract class FunctionGenerationContext(
|
|||||||
|
|
||||||
fun loadTypeInfo(objPtr: LLVMValueRef): LLVMValueRef {
|
fun loadTypeInfo(objPtr: LLVMValueRef): LLVMValueRef {
|
||||||
val typeInfoOrMetaPtr = structGep(objPtr, 0 /* typeInfoOrMeta_ */)
|
val typeInfoOrMetaPtr = structGep(objPtr, 0 /* typeInfoOrMeta_ */)
|
||||||
val typeInfoOrMetaWithFlags = load(typeInfoOrMetaPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingAcquire)
|
|
||||||
|
val memoryOrder = if (context.config.targetHasAddressDependency) {
|
||||||
|
/**
|
||||||
|
* Formally, this ordering is too weak, and doesn't prevent data race with installing extra object.
|
||||||
|
* Check comment in ObjHeader::type_info for details.
|
||||||
|
*/
|
||||||
|
LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic
|
||||||
|
} else {
|
||||||
|
LLVMAtomicOrdering.LLVMAtomicOrderingAcquire
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeInfoOrMetaWithFlags = load(typeInfoOrMetaPtr, memoryOrder = memoryOrder)
|
||||||
// Clear two lower bits.
|
// Clear two lower bits.
|
||||||
val typeInfoOrMetaWithFlagsRaw = ptrToInt(typeInfoOrMetaWithFlags, codegen.intPtrType)
|
val typeInfoOrMetaWithFlagsRaw = ptrToInt(typeInfoOrMetaWithFlags, codegen.intPtrType)
|
||||||
val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlagsRaw, codegen.immTypeInfoMask)
|
val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlagsRaw, codegen.immTypeInfoMask)
|
||||||
val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr)
|
val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr)
|
||||||
val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */)
|
val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */)
|
||||||
return load(typeInfoPtrPtr)
|
return load(typeInfoPtrPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lookupInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
fun lookupInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
||||||
|
|||||||
@@ -52,4 +52,9 @@
|
|||||||
#define KONAN_TYPE_INFO_HAS_WRITABLE_PART 1
|
#define KONAN_TYPE_INFO_HAS_WRITABLE_PART 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// should be consistent with hasAddressDependencyInMemoryModel function
|
||||||
|
#if defined(KONAN_X64) || defined(KONAN_X86) || defined(KONAN_ARM32) || defined(KONAN_ARM64)
|
||||||
|
#define KONAN_TARGET_HAS_ADDRESS_DEPENDENCY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RUNTIME_COMMON_H
|
#endif // RUNTIME_COMMON_H
|
||||||
|
|||||||
@@ -62,8 +62,24 @@ struct ObjHeader {
|
|||||||
TypeInfo* typeInfoOrMetaRelaxed() const { return atomicGetRelaxed(&typeInfoOrMeta_);}
|
TypeInfo* typeInfoOrMetaRelaxed() const { return atomicGetRelaxed(&typeInfoOrMeta_);}
|
||||||
TypeInfo* typeInfoOrMetaAcquire() const { return atomicGetAcquire(&typeInfoOrMeta_);}
|
TypeInfo* typeInfoOrMetaAcquire() const { return atomicGetAcquire(&typeInfoOrMeta_);}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formally, this code data races with installing ExtraObject. Even though, we are okey, with reading
|
||||||
|
* both typeInfo and meta-object pointer, llvm memory model doesn't guarantee, that if we are able to
|
||||||
|
* see metaObject, written by other thread, we would be able to see metaObject->typeInfo.
|
||||||
|
*
|
||||||
|
* To make this correct with llvm memory model we need to use [LLVMAtomicOrdering.LLVMAtomicOrderingAcquire] here.
|
||||||
|
* Unfortunately, this is dramatically harmful for performance on arm architecture. So, we are using
|
||||||
|
* [LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic] for both this read and following load of metaObject->typeInfo.
|
||||||
|
* At this point, we have no data race, but llvm memory model allows uninitialized value to be read from metaObject->typeInfo.
|
||||||
|
*
|
||||||
|
* Hardware guaranties on many supported platforms doesn't allow this to happen.
|
||||||
|
*/
|
||||||
const TypeInfo* type_info() const {
|
const TypeInfo* type_info() const {
|
||||||
return clearPointerBits(typeInfoOrMetaAcquire(), OBJECT_TAG_MASK)->typeInfo_;
|
#ifdef KONAN_TARGET_HAS_ADDRESS_DEPENDENCY
|
||||||
|
return atomicGetRelaxed(&clearPointerBits(typeInfoOrMetaRelaxed(), OBJECT_TAG_MASK)->typeInfo_);
|
||||||
|
#else
|
||||||
|
return atomicGetRelaxed(&clearPointerBits(typeInfoOrMetaAcquire(), OBJECT_TAG_MASK)->typeInfo_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_meta_object() const {
|
bool has_meta_object() const {
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ public:
|
|||||||
|
|
||||||
// info must be equal to objHeader->type_info(), but it needs to be loaded in advance to avoid data races
|
// info must be equal to objHeader->type_info(), but it needs to be loaded in advance to avoid data races
|
||||||
explicit ExtraObjectData(ObjHeader* objHeader, const TypeInfo *info) noexcept :
|
explicit ExtraObjectData(ObjHeader* objHeader, const TypeInfo *info) noexcept :
|
||||||
typeInfo_(info), weakReferenceCounterOrBaseObject_(objHeader) {
|
typeInfo_(nullptr), weakReferenceCounterOrBaseObject_(objHeader) {
|
||||||
|
atomicSetRelease(&typeInfo_, info);
|
||||||
}
|
}
|
||||||
~ExtraObjectData();
|
~ExtraObjectData();
|
||||||
private:
|
private:
|
||||||
|
|||||||
+13
-1
@@ -1,3 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.konan.target
|
package org.jetbrains.kotlin.konan.target
|
||||||
|
|
||||||
// TODO: This all needs to go to konan.properties
|
// TODO: This all needs to go to konan.properties
|
||||||
@@ -17,7 +22,7 @@ fun KonanTarget.supportsMimallocAllocator(): Boolean =
|
|||||||
is KonanTarget.MINGW_X86 -> true
|
is KonanTarget.MINGW_X86 -> true
|
||||||
is KonanTarget.MINGW_X64 -> true
|
is KonanTarget.MINGW_X64 -> true
|
||||||
is KonanTarget.MACOS_X64 -> true
|
is KonanTarget.MACOS_X64 -> true
|
||||||
is KonanTarget.MACOS_ARM64 -> true
|
is KonanTarget.MACOS_ARM64 -> true
|
||||||
is KonanTarget.LINUX_ARM64 -> true
|
is KonanTarget.LINUX_ARM64 -> true
|
||||||
is KonanTarget.LINUX_ARM32_HFP -> true
|
is KonanTarget.LINUX_ARM32_HFP -> true
|
||||||
is KonanTarget.ANDROID_X64 -> true
|
is KonanTarget.ANDROID_X64 -> true
|
||||||
@@ -59,3 +64,10 @@ fun KonanTarget.supportedSanitizers(): List<SanitizerKind> =
|
|||||||
// TODO: Support macOS arm64
|
// TODO: Support macOS arm64
|
||||||
else -> listOf()
|
else -> listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be consistent with KONAN_TARGET_HAS_ADDRESS_DEPENDENCY macro
|
||||||
|
fun KonanTarget.hasAddressDependencyInMemoryModel(): Boolean =
|
||||||
|
when (this.architecture) {
|
||||||
|
Architecture.X86, Architecture.X64, Architecture.ARM32, Architecture.ARM64 -> true
|
||||||
|
Architecture.MIPS32, Architecture.MIPSEL32, Architecture.WASM32 -> false
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user