diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt index 27889c008f6..cb17e0b35c6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EnumSpecialDescriptorsFactory.kt @@ -70,7 +70,7 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) { val constructorDescriptor = implObjectDescriptor.createSimpleDelegatingConstructorDescriptor(constructorOfAny, true) implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor) - val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply { + val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply { createParameterDeclarations() addFakeOverrides() setSuperSymbols(listOf(context.ir.symbols.any.owner)) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 24c3021ee71..1e5b2314096 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -62,6 +62,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val clang = platform.clang val indirectBranchesAreAllowed = target != KonanTarget.WASM32 + val threadsAreAllowed = (target != KonanTarget.WASM32) && (target !is KonanTarget.ZEPHYR) internal val produce get() = configuration.get(KonanConfigKeys.PRODUCE)!! diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 12af4d91a58..508a208ab2b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -252,7 +252,7 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym context.getInternalFunctions("initInstance").single()) val freeze = symbolTable.referenceSimpleFunction( - builtInsPackage("konan", "worker").getContributedFunctions(Name.identifier("freeze"), NoLookupLocation.FROM_BACKEND).single()) + builtInsPackage("konan", "worker").getContributedFunctions(Name.identifier("freezeAllowCycles"), NoLookupLocation.FROM_BACKEND).single()) val getContinuation = symbolTable.referenceSimpleFunction( context.getInternalFunctions("getContinuation").single()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 7fff720874e..ea87da39212 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -56,7 +56,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { descriptor.objectInstanceFieldSymbolName, llvmType, origin = descriptor.llvmSymbolOrigin, - threadLocal = true + threadLocal = !descriptor.symbol.objectIsShared ) } context.llvm.objects += llvmGlobal @@ -450,6 +450,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, fun icmpLt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, name)!! fun icmpLe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, name)!! fun icmpNe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, name)!! + fun icmpUGt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntUGT, arg0, arg1, name)!! /* floating-point comparisons */ fun fcmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildFCmp(builder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, name)!! @@ -566,6 +567,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, fun getObjectValue( descriptor: ClassDescriptor, + shared: Boolean, exceptionHandler: ExceptionHandler, locationInfo: LocationInfo? ): LLVMValueRef { @@ -578,15 +580,16 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, val bbInit = basicBlock("label_init", locationInfo) val bbExit = basicBlock("label_continue", locationInfo) val objectVal = loadSlot(objectPtr, false) - val condition = icmpNe(objectVal, codegen.kNullObjHeaderPtr) + val condition = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType) condBr(condition, bbExit, bbInit) positionAtEnd(bbInit) val typeInfo = codegen.typeInfoForAllocation(descriptor) - val initFunction = descriptor.constructors.first { it.valueParameters.size == 0 } - val ctor = codegen.llvmFunction(initFunction) + val defaultConstructor = descriptor.constructors.first { it.valueParameters.size == 0 } + val ctor = codegen.llvmFunction(defaultConstructor) val args = listOf(objectPtr, typeInfo, ctor) - val newValue = call(context.llvm.initInstanceFunction, args, Lifetime.GLOBAL, exceptionHandler) + val initFunction = if (shared) context.llvm.initSharedInstanceFunction else context.llvm.initInstanceFunction + val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler) val bbInitResult = currentBlock br(bbExit) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 9ac188e0060..f73729cf3e5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -398,6 +398,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val allocInstanceFunction = importRtFunction("AllocInstance") val allocArrayFunction = importRtFunction("AllocArrayInstance") val initInstanceFunction = importRtFunction("InitInstance") + val initSharedInstanceFunction = importRtFunction("InitSharedInstance") val updateReturnRefFunction = importRtFunction("UpdateReturnRef") val updateRefFunction = importRtFunction("UpdateRef") val enterFrameFunction = importRtFunction("EnterFrame") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index cc1a0f23c08..9bcadae8a62 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -35,10 +35,7 @@ import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl -import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueSymbol -import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol +import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid @@ -52,6 +49,8 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import org.jetbrains.kotlin.types.typeUtil.isUnit +val IrClassSymbol.objectIsShared get() = owner.origin == DECLARATION_ORIGIN_ENUM + internal fun emitLLVM(context: Context) { val irModule = context.irModule!! @@ -777,6 +776,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map): IrAnonymousInitializerImpl { val startOffset = irClass.startOffset val endOffset = irClass.endOffset - val symbol = IrAnonymousInitializerSymbolImpl(loweredEnum.implObject.descriptor) - val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) - return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, symbol).apply { - body = irBuilder.irBlockBody(irClass) { + return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply { + body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!.symbol), loweredEnum.valuesField.symbol)) enumEntries .sortedBy { it.descriptor.name } @@ -398,8 +395,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { putValueArgument(1, initializer) } } - +irCall(genericFreezeSymbol, listOf(arrayType)).apply { - extensionReceiver = irGet(instances.symbol) + +irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply { + extensionReceiver = irGet(loweredEnum.implObject.thisReceiver!!.symbol) } } } diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 37c8fc2bedb..aeb4d73b011 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -1103,6 +1103,47 @@ OBJ_GETTER(InitInstance, #endif } +OBJ_GETTER(InitSharedInstance, + ObjHeader** location, const TypeInfo* type_info, void (*ctor)(ObjHeader*)) { +#if KONAN_NO_THREADS + return InitInstance(location, type_info, ctor); +#else + ObjHeader* initializing = reinterpret_cast(1); + ObjHeader* value; + + // Spin lock. + while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing); + if (value != nullptr) { + // OK'ish, inited by someone else. + RETURN_OBJ(value); + } + + ObjHeader* object = AllocInstance(type_info, OBJ_RESULT); + MEMORY_LOG("Calling UpdateRef from InitInstance\n") + UpdateRef(location, object); + __sync_synchronize(); +#if KONAN_NO_EXCEPTIONS + ctor(object); + // TODO: uncomment as soon as cycles are correctly handled during freezing. + //if (!object->container()->frozen()) + //ThrowFreezingException(); + return object; +#else + try { + ctor(object); + //if (!object->container()->frozen()) + //ThrowFreezingException(); + return object; + } catch (...) { + UpdateRef(OBJ_RESULT, nullptr); + UpdateRef(location, nullptr); + __sync_synchronize(); + throw; + } +#endif +#endif +} + bool HasReservedObjectTail(ObjHeader* obj) { return kObjectReservedTailSize != 0 && !obj->permanent(); } @@ -1151,7 +1192,7 @@ void UpdateRef(ObjHeader** location, const ObjHeader* object) { AddRef(object); } *const_cast(location) = object; - if (old != nullptr) { + if (reinterpret_cast(old) > 1) { ReleaseRef(old); } } diff --git a/runtime/src/main/kotlin/konan/worker/Freezing.kt b/runtime/src/main/kotlin/konan/worker/Freezing.kt index 40e14cd90d4..49925a2f318 100644 --- a/runtime/src/main/kotlin/konan/worker/Freezing.kt +++ b/runtime/src/main/kotlin/konan/worker/Freezing.kt @@ -37,6 +37,16 @@ fun T.freeze(): T { return this } +// TODO: Remove. +fun T.freezeAllowCycles(): T { + try { + freezeInternal(this) + } catch (t: FreezingException) { + return this + } + return this +} + val Any?.isFrozen get() = isFrozenInternal(this)