Merge commits from both masters and update to 1.5.0-dev-1023

Kotlin/Native base commit: 858a1d77dd0f92d5f926a1ab3d5ab61230758714

Merge branches 'to-native-merge' and 'tmp_branch4merge' into native-merge
This commit is contained in:
Nikolay Krasko
2020-12-29 00:15:37 +03:00
1142 changed files with 18279 additions and 12466 deletions
+26 -1
View File
@@ -1,3 +1,28 @@
# 1.4.30-M1 (Dec 2020)
* [KT-43597](https://youtrack.jetbrains.com/issue/KT-43597) Xcode 12.2 support
* [KT-43276](https://youtrack.jetbrains.com/issue/KT-43276) Add watchos_x64 target
* [KT-43198](https://youtrack.jetbrains.com/issue/KT-43198) Init blocks inside of inline classes
* [KT-42649](https://youtrack.jetbrains.com/issue/KT-42649) Fix secondary constructors of generic inline classes
* [KT-38772](https://youtrack.jetbrains.com/issue/KT-38772) Support non-reified type parameters in typeOf
* Compiler customization
* [KT-40584](https://youtrack.jetbrains.com/issue/KT-40584) Untie Kotlin/Native from the fixed LLVM distribution
* [KT-42234](https://youtrack.jetbrains.com/issue/KT-42234) Move LLVM optimization parameters into konan.properties
* [KT-40670](https://youtrack.jetbrains.com/issue/KT-40670) Allow to override konan.properties via CLI
* Runtime
* [KT-42822](https://youtrack.jetbrains.com/issue/KT-42822) Kotlin/Native Worker leaks ObjC/Swift autorelease references (and indirectly bridged K/N references) on Darwin targets
* [KT-42397](https://youtrack.jetbrains.com/issue/KT-42397) Reverse-C interop usage of companion object reports spurious leaks
* [GH-4482](https://github.com/JetBrains/kotlin-native/pull/4482) Add a switch to destroy runtime only on shutdown
* [GH-4575](https://github.com/JetBrains/kotlin-native/pull/4575) Fix unchecked runtime shutdown
* [GH-4194](https://github.com/JetBrains/kotlin-native/pull/4194) Fix possible race in terminate handler
* C-interop
* [KT-42412](https://youtrack.jetbrains.com/issue/KT-42412) Modality of generated property accessors is always FINAL
* [KT-38530](https://youtrack.jetbrains.com/issue/KT-38530) values() method of enum classes is not exposed to Objective-C/Swift
* [GH-4572](https://github.com/JetBrains/kotlin-native/pull/4572) Fix for interop enum and struct generation
* Optimizations
* [KT-42294](https://youtrack.jetbrains.com/issue/KT-42294) Significantly improved compilation time
* [KT-42942](https://youtrack.jetbrains.com/issue/KT-42942) Optimize peak backend memory by clearing BindingContext after psi2ir
* [KT-31072](https://youtrack.jetbrains.com/issue/KT-31072) Don't use non-reified arguments to specialize type operations in IR inliner
# 1.4.21 (Dec 2020)
* Fixed [KT-43517](https://youtrack.jetbrains.com/issue/KT-43517)
* Fixed [KT-43530](https://youtrack.jetbrains.com/issue/KT-43530)
@@ -12,7 +37,7 @@
* equals/hashCode support for fun interfaces ([KT-39798](https://youtrack.jetbrains.com/issue/KT-39798))
* IR-level optimizations
* Constant folding
* String concatenation flattenning
* String concatenation flattening
* Various fixes/improvements to compiler caches
* Some fixes to samples (calculator, tensorflow)
* Bug fixes
+2 -2
View File
@@ -36,7 +36,7 @@ Install libgit2 and prepare stubs for the git library:
```bash
cd samples/gitchurn
../../dist/bin/cinterop -def src/main/c_interop/libgit2.def \
../../dist/bin/cinterop -def src/nativeInterop/cinterop/libgit2.def \
-compiler-option -I/usr/local/include -o libgit2
```
@@ -47,7 +47,7 @@ Compile the client:
<div class="sample" markdown="1" theme="idea" mode="shell">
```bash
../../dist/bin/kotlinc src/main/kotlin \
../../dist/bin/kotlinc src/gitChurnMain/kotlin \
-library libgit2 -o GitChurn
```
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
@@ -59,11 +57,10 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
Name.special("<${inlinedClass.name}-box>"),
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
@@ -77,11 +74,11 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
isOperator = false,
isInfix = false
).also { function ->
function.valueParameters = listOf(WrappedValueParameterDescriptor().let {
function.valueParameters = listOf(
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
IrValueParameterSymbolImpl(),
Name.identifier("value"),
index = 0,
varargElementType = null,
@@ -91,11 +88,8 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
isHidden = false,
isAssignable = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
})
function.parent = inlinedClass.getContainingFile()!!
}
}
@@ -116,11 +110,10 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_INLINE_CLASS_SPECIAL_FUNCTION,
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
Name.special("<${inlinedClass.name}-unbox>"),
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
@@ -134,11 +127,11 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
isOperator = false,
isInfix = false
).also { function ->
function.valueParameters = listOf(WrappedValueParameterDescriptor().let {
function.valueParameters = listOf(
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
IrValueParameterSymbolImpl(),
Name.identifier("value"),
index = 0,
varargElementType = null,
@@ -148,11 +141,8 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
isHidden = false,
isAssignable = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
})
function.parent = inlinedClass.getContainingFile()!!
}
}
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.name.FqName
@@ -138,7 +137,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
return bridges.getOrPut(key) { createBridge(key) }
}
private fun createBridge(key: BridgeKey): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let { descriptor ->
private fun createBridge(key: BridgeKey): IrSimpleFunction {
val (function, bridgeDirections) = key
val startOffset = function.startOffset
val endOffset = function.endOffset
@@ -148,10 +147,10 @@ internal class SpecialDeclarationsFactory(val context: Context) {
null
else this.irClass?.defaultType ?: context.irBuiltIns.anyNType
IrFunctionImpl(
return IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD(function),
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
"<bridge-$bridgeDirections>${function.computeFunctionName()}".synthesizedName,
function.visibility,
function.modality,
@@ -166,7 +165,6 @@ internal class SpecialDeclarationsFactory(val context: Context) {
isInfix = false
).apply {
val bridge = this
descriptor.bind(bridge)
parent = function.parent
dispatchReceiverParameter = function.dispatchReceiverParameter?.let {
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
@@ -25,13 +23,12 @@ import org.jetbrains.kotlin.ir.util.irCatch
import org.jetbrains.kotlin.name.Name
internal fun makeEntryPoint(context: Context): IrFunction {
val entryPointDescriptor = WrappedSimpleFunctionDescriptor()
val actualMain = context.ir.symbols.entryPoint!!.owner
val entryPoint = IrFunctionImpl(
actualMain.startOffset,
actualMain.startOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(entryPointDescriptor),
IrSimpleFunctionSymbolImpl(),
Name.identifier("Konan_start"),
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -45,11 +42,11 @@ internal fun makeEntryPoint(context: Context): IrFunction {
isOperator = false,
isInfix = false
).also { function ->
function.valueParameters = listOf(WrappedValueParameterDescriptor().let {
function.valueParameters = listOf(
IrValueParameterImpl(
actualMain.startOffset, actualMain.startOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
IrValueParameterSymbolImpl(),
Name.identifier("args"),
index = 0,
varargElementType = null,
@@ -59,12 +56,9 @@ internal fun makeEntryPoint(context: Context): IrFunction {
isHidden = false,
isAssignable = false
).apply {
it.bind(this)
parent = function
}
})
})
}
entryPointDescriptor.bind(entryPoint)
entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns,
actualMain.startOffset, actualMain.startOffset,
context.ir.symbols.exportForCppRuntime.owner, "Konan_start")
@@ -22,9 +22,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
@@ -135,11 +132,11 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
val startOffset = enumClass.startOffset
val endOffset = enumClass.endOffset
val implObject = WrappedClassDescriptor().let {
val implObject =
IrClassImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrClassSymbolImpl(it),
IrClassSymbolImpl(),
"OBJECT".synthesizedName,
ClassKind.OBJECT,
DescriptorVisibilities.PUBLIC,
@@ -152,18 +149,16 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
isExpect = false,
isFun = false
).apply {
it.bind(this)
parent = enumClass
createParameterDeclarations()
}
}
val valuesType = valuesArrayType(enumClass)
val valuesField = WrappedFieldDescriptor().let {
val valuesField =
IrFieldImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrFieldSymbolImpl(it),
IrFieldSymbolImpl(),
"VALUES".synthesizedName,
valuesType,
DescriptorVisibilities.PRIVATE,
@@ -171,16 +166,14 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
isExternal = false,
isStatic = false,
).apply {
it.bind(this)
parent = implObject
}
}
val valuesGetter = WrappedSimpleFunctionDescriptor().let {
val valuesGetter =
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
"get-VALUES".synthesizedName,
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
@@ -194,10 +187,8 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
isOperator = false,
isInfix = false
).apply {
it.bind(this)
parent = implObject
}
}
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
implObject.addSimpleDelegatingConstructor(
@@ -124,11 +124,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
MemoryModel.STRICT -> MemoryModel.STRICT
MemoryModel.RELAXED -> MemoryModel.RELAXED
MemoryModel.EXPERIMENTAL -> {
if (!target.supportsMimallocAllocator()) {
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
"Experimental memory model requires mimalloc allocator. Used strict memory model.")
MemoryModel.STRICT
} else if (!target.supportsThreads()) {
if (!target.supportsThreads()) {
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
"Experimental memory model requires threads, which are not supported on target ${target.name}. Used strict memory model.")
MemoryModel.STRICT
@@ -141,9 +137,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
}
}
}
val useMimalloc = if (effectiveMemoryModel == MemoryModel.EXPERIMENTAL) {
true // we already checked that target supports mimalloc.
} else if (configuration.get(KonanConfigKeys.ALLOCATION_MODE) == "mimalloc") {
val useMimalloc = if (configuration.get(KonanConfigKeys.ALLOCATION_MODE) == "mimalloc") {
if (target.supportsMimallocAllocator()) {
true
} else {
@@ -180,7 +180,7 @@ internal val serializerPhase = konanUnitPhase(
this.config.configuration.languageVersionSettings,
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!,
config.project,
!expectActualLinker)
!expectActualLinker, includeOnlyModuleContent = true)
serializedMetadata = serializer.serializeModule(moduleDescriptor)
},
name = "Serializer",
@@ -549,12 +549,11 @@ private fun KotlinStubs.createFakeKotlinExternalFunction(
cFunctionName: String,
isObjCMethod: Boolean
): IrSimpleFunction {
val bridgeDescriptor = WrappedSimpleFunctionDescriptor()
val bridge = IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(bridgeDescriptor),
IrSimpleFunctionSymbolImpl(),
Name.identifier(cFunctionName),
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -568,7 +567,6 @@ private fun KotlinStubs.createFakeKotlinExternalFunction(
isOperator = false,
isInfix = false
)
bridgeDescriptor.bind(bridge)
bridge.annotations += buildSimpleAnnotation(irBuiltIns, UNDEFINED_OFFSET, UNDEFINED_OFFSET,
symbols.symbolName.owner, cFunctionName)
@@ -1098,16 +1096,14 @@ private class ObjCBlockPointerValuePassing(
private fun IrBuilderWithScope.generateKotlinFunctionClass(): IrConstructor {
val symbols = stubs.symbols
val classDescriptor = WrappedClassDescriptor()
val irClass = IrClassImpl(
startOffset, endOffset,
OBJC_BLOCK_FUNCTION_IMPL, IrClassSymbolImpl(classDescriptor),
OBJC_BLOCK_FUNCTION_IMPL, IrClassSymbolImpl(),
Name.identifier(stubs.getUniqueKotlinFunctionReferenceClassName("BlockFunctionImpl")),
ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL,
isCompanion = false, isInner = false, isData = false, isExternal = false,
isInline = false, isExpect = false, isFun = false
)
classDescriptor.bind(irClass)
irClass.createParameterDeclarations()
irClass.superTypes += stubs.irBuiltIns.anyType
@@ -1121,24 +1117,21 @@ private class ObjCBlockPointerValuePassing(
isMutable = false, owner = irClass
)
val constructorDescriptor = WrappedClassConstructorDescriptor()
val constructor = IrConstructorImpl(
startOffset, endOffset,
OBJC_BLOCK_FUNCTION_IMPL,
IrConstructorSymbolImpl(constructorDescriptor),
IrConstructorSymbolImpl(),
Name.special("<init>"),
DescriptorVisibilities.PUBLIC,
irClass.defaultType,
isInline = false, isExternal = false, isPrimary = true, isExpect = false
)
constructorDescriptor.bind(constructor)
irClass.addChild(constructor)
val constructorParameterDescriptor = WrappedValueParameterDescriptor()
val constructorParameter = IrValueParameterImpl(
startOffset, endOffset,
OBJC_BLOCK_FUNCTION_IMPL,
IrValueParameterSymbolImpl(constructorParameterDescriptor),
IrValueParameterSymbolImpl(),
Name.identifier("blockPointer"),
0,
symbols.nativePtrType,
@@ -1148,7 +1141,6 @@ private class ObjCBlockPointerValuePassing(
isHidden = false,
isAssignable = false
)
constructorParameterDescriptor.bind(constructorParameter)
constructor.valueParameters += constructorParameter
constructorParameter.parent = constructor
@@ -1166,28 +1158,25 @@ private class ObjCBlockPointerValuePassing(
val overriddenInvokeMethod = (functionType.classifier.owner as IrClass).simpleFunctions()
.single { it.name == OperatorNameConventions.INVOKE }
val invokeMethodDescriptor = WrappedSimpleFunctionDescriptor()
val invokeMethod = IrFunctionImpl(
startOffset, endOffset,
OBJC_BLOCK_FUNCTION_IMPL,
IrSimpleFunctionSymbolImpl(invokeMethodDescriptor),
IrSimpleFunctionSymbolImpl(),
overriddenInvokeMethod.name,
DescriptorVisibilities.PUBLIC, Modality.FINAL,
returnType = functionType.arguments.last().typeOrNull!!,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isExpect = false,
isFakeOverride = false, isOperator = false, isInfix = false
)
invokeMethodDescriptor.bind(invokeMethod)
invokeMethod.overriddenSymbols += overriddenInvokeMethod.symbol
irClass.addChild(invokeMethod)
invokeMethod.createDispatchReceiverParameter()
invokeMethod.valueParameters += (0 until parameterCount).map { index ->
val parameterDescriptor = WrappedValueParameterDescriptor()
val parameter = IrValueParameterImpl(
startOffset, endOffset,
OBJC_BLOCK_FUNCTION_IMPL,
IrValueParameterSymbolImpl(parameterDescriptor),
IrValueParameterSymbolImpl(),
Name.identifier("p$index"),
index,
functionType.arguments[index].typeOrNull!!,
@@ -1197,7 +1186,6 @@ private class ObjCBlockPointerValuePassing(
isHidden = false,
isAssignable = false
)
parameterDescriptor.bind(parameter)
parameter.parent = invokeMethod
parameter
}
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
@@ -81,11 +79,10 @@ internal class KotlinBridgeBuilder(
fun addParameter(type: IrType): IrValueParameter {
val index = counter++
val descriptor = WrappedValueParameterDescriptor()
return IrValueParameterImpl(
bridge.startOffset, bridge.endOffset, bridge.origin,
IrValueParameterSymbolImpl(descriptor),
IrValueParameterSymbolImpl(),
Name.identifier("p$index"), index, type,
null,
isCrossinline = false,
@@ -93,7 +90,6 @@ internal class KotlinBridgeBuilder(
isHidden = false,
isAssignable = false
).apply {
descriptor.bind(this)
parent = bridge
bridge.valueParameters += this
}
@@ -114,12 +110,11 @@ private fun createKotlinBridge(
isExternal: Boolean,
foreignExceptionMode: ForeignExceptionMode.Mode
): IrFunction {
val bridgeDescriptor = WrappedSimpleFunctionDescriptor()
val bridge = IrFunctionImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(bridgeDescriptor),
IrSimpleFunctionSymbolImpl(),
Name.identifier(cBridgeName),
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -133,7 +128,6 @@ private fun createKotlinBridge(
isOperator = false,
isInfix = false
)
bridgeDescriptor.bind(bridge)
if (isExternal) {
bridge.annotations += buildSimpleAnnotation(stubs.irBuiltIns, startOffset, endOffset,
stubs.symbols.symbolName.owner, cBridgeName)
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
@@ -44,17 +43,14 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
}
return with(originalDeclaration) {
WrappedVariableDescriptor().let {
IrVariableImpl(
startOffset, endOffset, origin,
IrVariableSymbolImpl(it), name, refConstructorCall.type,
isVar = false,
isConst = false,
isLateinit = false
).apply {
it.bind(this)
initializer = refConstructorCall
}
IrVariableImpl(
startOffset, endOffset, origin,
IrVariableSymbolImpl(), name, refConstructorCall.type,
isVar = false,
isConst = false,
isLateinit = false
).apply {
initializer = refConstructorCall
}
}
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
@@ -126,10 +127,13 @@ fun AnnotationDescriptor.getStringValue(name: String): String = this.getStringVa
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
val packageFragmentProvider = (module as? ModuleDescriptorImpl)?.packageFragmentProviderForModuleContentWithoutDependencies
fun getSubPackages(fqName: FqName) {
result.add(fqName)
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
val subPackages = packageFragmentProvider?.getSubPackagesOf(fqName) { true }
?: module.getSubPackagesOf(fqName) { true }
subPackages.forEach { getSubPackages(it) }
}
getSubPackages(FqName.ROOT)
@@ -60,7 +60,7 @@ internal interface DescriptorToIrTranslationMixin {
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, it, descriptor
)
}.also { irClass ->
symbolTable.withScope(descriptor) {
symbolTable.withScope(irClass) {
irClass.superTypes += descriptor.typeConstructor.supertypes.map {
it.toIrType()
}
@@ -133,7 +133,7 @@ internal interface DescriptorToIrTranslationMixin {
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
): IrSimpleFunction {
val irFunction = symbolTable.declareSimpleFunctionWithOverrides(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, origin, functionDescriptor)
symbolTable.withScope(functionDescriptor) {
symbolTable.withScope(irFunction) {
irFunction.returnType = functionDescriptor.returnType!!.toIrType()
irFunction.valueParameters += functionDescriptor.valueParameters.map {
symbolTable.declareValueParameter(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrDeclarationOrigin.DEFINED, it, it.type.toIrType())
@@ -93,7 +93,7 @@ internal class CEnumClassGenerator(
.findDeclarationByName<PropertyDescriptor>("value")
?: error("No `value` property in ${irClass.name}")
val irProperty = createProperty(propertyDescriptor)
symbolTable.withScope(propertyDescriptor) {
symbolTable.withScope(irProperty) {
irProperty.backingField = symbolTable.declareField(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
propertyDescriptor, propertyDescriptor.type.toIrType(), DescriptorVisibilities.PRIVATE
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedPropertyDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.*
@@ -414,13 +412,12 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
private fun buildBoxField(declaration: IrClass) {
val startOffset = declaration.startOffset
val endOffset = declaration.endOffset
val descriptor = WrappedPropertyDescriptor()
val irField = IrFieldImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
IrFieldSymbolImpl(descriptor),
IrFieldSymbolImpl(),
Name.identifier("value"),
declaration.defaultType,
DescriptorVisibilities.PRIVATE,
@@ -434,7 +431,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
IrPropertySymbolImpl(descriptor),
IrPropertySymbolImpl(),
irField.name,
irField.visibility,
Modality.FINAL,
@@ -444,7 +441,6 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
isDelegated = false,
isExternal = false
)
descriptor.bind(irProperty)
irProperty.backingField = irField
declaration.addChild(irProperty)
@@ -553,11 +549,10 @@ private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpl
irConstructor.returnType
}
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
irConstructor.startOffset, irConstructor.endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
Name.special("<constructor>"),
irConstructor.visibility,
Modality.FINAL,
@@ -571,7 +566,6 @@ private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpl
isOperator = false,
isInfix = false
).apply {
descriptor.bind(this)
parent = irConstructor.parent
// Note: technically speaking, this function doesn't have access to class type parameters (since it is "static").
@@ -19,8 +19,6 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -71,11 +69,11 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
val arg = jobFunction.valueParameters[0]
val startOffset = jobFunction.startOffset
val endOffset = jobFunction.endOffset
runtimeJobFunction = WrappedSimpleFunctionDescriptor().let {
runtimeJobFunction =
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
jobFunction.name,
jobFunction.visibility,
jobFunction.modality,
@@ -88,16 +86,13 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
isFakeOverride = false,
isOperator = false,
isInfix = false
).apply {
it.bind(this)
}
}
)
runtimeJobFunction.valueParameters += WrappedValueParameterDescriptor().let {
runtimeJobFunction.valueParameters +=
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
IrValueParameterSymbolImpl(),
arg.name,
arg.index,
type = context.irBuiltIns.anyNType,
@@ -106,8 +101,7 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
isNoinline = arg.isNoinline,
isHidden = arg.isHidden,
isAssignable = arg.isAssignable
).apply { it.bind(this) }
}
)
}
val overriddenJobDescriptor = OverriddenFunctionInfo(jobFunction, runtimeJobFunction)
if (!overriddenJobDescriptor.needBridge) return expression
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
@@ -84,11 +83,11 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = WrappedFieldDescriptor().let {
val kPropertiesField =
IrFieldImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
IrFieldSymbolImpl(it),
IrFieldSymbolImpl(),
"KPROPERTIES".synthesizedName,
kPropertiesFieldType,
DescriptorVisibilities.PRIVATE,
@@ -96,11 +95,9 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
isExternal = false,
isStatic = true,
).apply {
it.bind(this)
parent = irFile
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.sharedImmutable.owner)
}
}
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
@@ -109,11 +107,11 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructor {
val startOffset = constructor.startOffset
val endOffset = constructor.endOffset
val loweredConstructor = WrappedClassConstructorDescriptor().let {
val loweredConstructor =
IrConstructorImpl(
startOffset, endOffset,
constructor.origin,
IrConstructorSymbolImpl(it),
IrConstructorSymbolImpl(),
constructor.name,
DescriptorVisibilities.PROTECTED,
constructor.returnType,
@@ -122,32 +120,27 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
isPrimary = constructor.isPrimary,
isExpect = false
).apply {
it.bind(this)
parent = constructor.parent
val body = constructor.body!!
this.body = body // Will be transformed later.
body.setDeclarationsParent(this)
}
}
fun createSynthesizedValueParameter(index: Int, name: String, type: IrType): IrValueParameter =
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(it),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false,
isHidden = false,
isAssignable = false
).apply {
it.bind(this)
parent = loweredConstructor
}
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false,
isHidden = false,
isAssignable = false
).apply {
parent = loweredConstructor
}
loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType)
@@ -9,8 +9,8 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
@@ -173,27 +171,6 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
else -> error("Unknown ReturnTarget: $this")
}
private fun createSyntheticFunctionDescriptor(name: String): SimpleFunctionDescriptor {
val descriptor = WrappedSimpleFunctionDescriptor()
descriptor.bind(IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
Name.identifier(name),
DescriptorVisibilities.PUBLIC,
Modality.FINAL,
context.irBuiltIns.unitType,
false,
false,
false,
false,
false,
false,
false)
)
return descriptor
}
private fun performHighLevelJump(tryScopes: List<TryScope>,
index: Int,
jump: HighLevelJump,
@@ -206,7 +183,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) {
val type = (jump as? Return)?.target?.owner?.returnType ?: value.type
val symbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Finally$index"))
val symbol = IrReturnableBlockSymbolImpl()
with(currentTryScope) {
irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
@@ -245,21 +222,19 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
type = context.irBuiltIns.nothingType
)
val transformedFinallyExpression = finallyExpression.transform(transformer, null)
val catchParameter = WrappedVariableDescriptor().let {
val catchParameter =
IrVariableImpl(
startOffset, endOffset,
IrDeclarationOrigin.CATCH_PARAMETER,
IrVariableSymbolImpl(it),
IrVariableSymbolImpl(),
Name.identifier("t"),
symbols.throwable.owner.defaultType,
isVar = false,
isConst = false,
isLateinit = false
).apply {
it.bind(this)
parent = this@run.parent
}
}
val syntheticTry = IrTryImpl(
startOffset = startOffset,
@@ -276,7 +251,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
)
using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughType = aTry.type
val fallThroughSymbol = IrReturnableBlockSymbolImpl(createSyntheticFunctionDescriptor("\$Fallthrough"))
val fallThroughSymbol = IrReturnableBlockSymbolImpl()
val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) {
@@ -25,9 +25,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -224,11 +221,11 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
private val adaptedReferenceOriginalTarget: IrFunction? = adapteeCall?.symbol?.owner
private val functionReferenceTarget = adaptedReferenceOriginalTarget ?: referencedFunction
private val functionReferenceClass: IrClass = WrappedClassDescriptor().let {
private val functionReferenceClass: IrClass =
IrClassImpl(
startOffset,endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrClassSymbolImpl(it),
IrClassSymbolImpl(),
"${functionReferenceTarget.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName,
ClassKind.CLASS,
DescriptorVisibilities.PRIVATE,
@@ -241,11 +238,9 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
isExpect = false,
isFun = false
).apply {
it.bind(this)
parent = this@FunctionReferenceBuilder.parent
createParameterDeclarations()
}
}
private val functionReferenceThis = functionReferenceClass.thisReceiver!!
@@ -337,11 +332,11 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
return BuiltFunctionReference(functionReferenceClass, constructor)
}
private fun buildConstructor(): IrConstructor = WrappedClassConstructorDescriptor().let {
private fun buildConstructor(): IrConstructor =
IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrConstructorSymbolImpl(it),
IrConstructorSymbolImpl(),
Name.special("<init>"),
DescriptorVisibilities.PUBLIC,
functionReferenceClass.defaultType,
@@ -350,7 +345,6 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
isPrimary = true,
isExpect = false
).apply {
it.bind(this)
parent = functionReferenceClass
functionReferenceClass.declarations += this
@@ -387,7 +381,6 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
}
}
}
}
private fun getFlags() =
(if (referencedFunction.isSuspend) 1 else 0) + getAdaptedCallableReferenceFlags() shl 1
@@ -418,11 +411,11 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
return false
}
private fun buildInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let {
private fun buildInvokeMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
superFunction.name,
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -436,7 +429,6 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
isOperator = false,
isInfix = false
).apply {
it.bind(this)
val function = this
parent = functionReferenceClass
functionReferenceClass.declarations += function
@@ -486,6 +478,5 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
)
}
}
}
}
}
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
@@ -108,11 +107,11 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val initializeFun = WrappedSimpleFunctionDescriptor().let {
val initializeFun =
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
"INITIALIZER".synthesizedName,
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -126,7 +125,6 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
isOperator = false,
isInfix = false
).apply {
it.bind(this)
parent = irClass
irClass.declarations.add(this)
@@ -134,7 +132,6 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
body = IrBlockBodyImpl(startOffset, endOffset, initializers)
}
}
for (initializer in initializers) {
initializer.transformChildrenVoid(object : IrElementTransformerVoid() {
@@ -175,7 +172,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
val blockBody = declaration.body as? IrBlockBody
val body = declaration.body ?: return declaration
val blockBody = body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
blockBody.statements.transformFlat {
@@ -27,8 +27,6 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
@@ -225,11 +223,10 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
// Generate `override fun init...(...) = this.initBy(...)`:
val resultDescriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
constructor.startOffset, constructor.endOffset,
OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
IrSimpleFunctionSymbolImpl(resultDescriptor),
IrSimpleFunctionSymbolImpl(),
initMethod.name,
DescriptorVisibilities.PUBLIC,
Modality.OPEN,
@@ -243,7 +240,6 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
isOperator = false,
isInfix = false
).also { result ->
resultDescriptor.bind(result)
result.parent = irClass
result.createDispatchReceiverParameter()
result.valueParameters += constructor.valueParameters.map { it.copyTo(result) }
@@ -323,11 +319,11 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
function.valueParameters.mapTo(parameterTypes) { nativePtrType }
val newFunction = WrappedSimpleFunctionDescriptor().let {
val newFunction =
IrFunctionImpl(
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
("imp:$selector").synthesizedName,
DescriptorVisibilities.PRIVATE,
Modality.FINAL,
@@ -340,29 +336,23 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
isFakeOverride = false,
isOperator = false,
isInfix = false
).apply {
it.bind(this)
}
}
)
newFunction.valueParameters += parameterTypes.mapIndexed { index, type ->
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
Name.identifier("p$index"),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false,
isHidden = false,
isAssignable = false
).apply {
it.bind(this)
parent = newFunction
}
IrValueParameterImpl(
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(),
Name.identifier("p$index"),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false,
isHidden = false,
isAssignable = false
).apply {
parent = newFunction
}
}
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetValueImpl
@@ -478,11 +476,11 @@ internal class NativeSuspendFunctionsLowering(ctx: Context): AbstractSuspendFunc
}
// These are marker functions to split up the lowering on two parts.
private val saveState = WrappedSimpleFunctionDescriptor().let {
private val saveState =
IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
"saveState".synthesizedName,
DescriptorVisibilities.PRIVATE,
Modality.ABSTRACT,
@@ -495,16 +493,13 @@ internal class NativeSuspendFunctionsLowering(ctx: Context): AbstractSuspendFunc
isFakeOverride = false,
isOperator = false,
isInfix = false
).apply {
it.bind(this)
}
}
)
private val restoreState = WrappedSimpleFunctionDescriptor().let {
private val restoreState =
IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
IrSimpleFunctionSymbolImpl(),
"restoreState".synthesizedName,
DescriptorVisibilities.PRIVATE,
Modality.ABSTRACT,
@@ -517,29 +512,24 @@ internal class NativeSuspendFunctionsLowering(ctx: Context): AbstractSuspendFunc
isFakeOverride = false,
isOperator = false,
isInfix = false
).apply {
it.bind(this)
}
}
)
private fun IrBuilderWithScope.irVar(name: Name, type: IrType,
isMutable: Boolean = false,
initializer: IrExpression? = null) = WrappedVariableDescriptor().let {
initializer: IrExpression? = null) =
IrVariableImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_COROUTINE_IMPL,
IrVariableSymbolImpl(it),
IrVariableSymbolImpl(),
name,
type,
isMutable,
isConst = false,
isLateinit = false
).apply {
it.bind(this)
this.initializer = initializer
this.parent = this@irVar.parent
}
}
private fun IrBuilderWithScope.irGetOrThrow(result: IrExpression): IrExpression =
irCall(symbols.kotlinResultGetOrThrow.owner).apply {
@@ -150,7 +150,7 @@ internal class RedundantCoercionsCleaner(val context: Context) : FileLoweringPas
expression
else {
val oldSymbol = expression.symbol
val newSymbol = IrReturnableBlockSymbolImpl(expression.descriptor)
val newSymbol = IrReturnableBlockSymbolImpl()
val transformedReturnableBlock = with(expression) {
IrReturnableBlockImpl(
startOffset = startOffset,
@@ -22,9 +22,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
@@ -335,11 +332,11 @@ internal class TestProcessor (val context: Context) {
*/
private fun buildObjectGetter(objectSymbol: IrClassSymbol,
owner: IrClass,
getterName: Name): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let { descriptor ->
getterName: Name): IrSimpleFunction =
IrFunctionImpl(
owner.startOffset, owner.endOffset,
TEST_SUITE_GENERATED_MEMBER,
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
getterName,
DescriptorVisibilities.PROTECTED,
Modality.FINAL,
@@ -353,7 +350,6 @@ internal class TestProcessor (val context: Context) {
isOperator = false,
isInfix = false
).apply {
descriptor.bind(this)
parent = owner
val superFunction = baseClassSuite.simpleFunctions()
@@ -367,7 +363,6 @@ internal class TestProcessor (val context: Context) {
)
}
}
}
/**
* Builds a method in `[testSuite]` class with name `[getterName]`
@@ -375,11 +370,11 @@ internal class TestProcessor (val context: Context) {
*/
private fun buildInstanceGetter(classSymbol: IrClassSymbol,
owner: IrClass,
getterName: Name): IrSimpleFunction = WrappedSimpleFunctionDescriptor().let { descriptor ->
getterName: Name): IrSimpleFunction =
IrFunctionImpl(
owner.startOffset, owner.endOffset,
TEST_SUITE_GENERATED_MEMBER,
IrSimpleFunctionSymbolImpl(descriptor),
IrSimpleFunctionSymbolImpl(),
getterName,
DescriptorVisibilities.PROTECTED,
Modality.FINAL,
@@ -393,7 +388,6 @@ internal class TestProcessor (val context: Context) {
isOperator = false,
isInfix = false
).apply {
descriptor.bind(this)
parent = owner
val superFunction = baseClassSuite.simpleFunctions()
@@ -407,7 +401,6 @@ internal class TestProcessor (val context: Context) {
+irReturn(irCall(constructor))
}
}
}
private val baseClassSuiteConstructor = baseClassSuite.constructors.single {
it.valueParameters.size == 2
@@ -426,11 +419,11 @@ internal class TestProcessor (val context: Context) {
testSuite: IrClassSymbol,
owner: IrClass,
functions: Collection<TestFunction>,
ignored: Boolean): IrConstructor = WrappedClassConstructorDescriptor().let { descriptor ->
ignored: Boolean): IrConstructor =
IrConstructorImpl(
testSuite.owner.startOffset, testSuite.owner.endOffset,
TEST_SUITE_GENERATED_MEMBER,
IrConstructorSymbolImpl(descriptor),
IrConstructorSymbolImpl(),
Name.special("<init>"),
DescriptorVisibilities.PUBLIC,
testSuite.typeWithStarProjections,
@@ -439,7 +432,6 @@ internal class TestProcessor (val context: Context) {
isPrimary = true,
isExpect = false
).apply {
descriptor.bind(this)
parent = owner
fun IrClass.getFunction(name: String, predicate: (IrSimpleFunction) -> Boolean) =
@@ -469,7 +461,6 @@ internal class TestProcessor (val context: Context) {
registerTestCase, registerFunction, functions)
}
}
}
private val IrClass.ignored: Boolean get() = annotations.hasAnnotation(IGNORE_FQ_NAME)
@@ -479,11 +470,11 @@ internal class TestProcessor (val context: Context) {
*/
private fun buildClassSuite(testClass: IrClass,
testCompanion: IrClass?,
functions: Collection<TestFunction>): IrClass = WrappedClassDescriptor().let { descriptor ->
functions: Collection<TestFunction>): IrClass =
IrClassImpl(
testClass.startOffset, testClass.endOffset,
TEST_SUITE_CLASS,
IrClassSymbolImpl(descriptor),
IrClassSymbolImpl(),
testClass.name.synthesizeSuiteClassName(),
ClassKind.CLASS,
DescriptorVisibilities.PRIVATE,
@@ -496,7 +487,6 @@ internal class TestProcessor (val context: Context) {
isExpect = false,
isFun = false
).apply {
descriptor.bind(this)
createParameterDeclarations()
val testClassType = testClass.defaultType
@@ -531,7 +521,6 @@ internal class TestProcessor (val context: Context) {
superTypes += symbols.baseClassSuite.typeWith(listOf(testClassType, testCompanionType))
addFakeOverrides(context.irBuiltIns)
}
}
//endregion
// region IR generation methods
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
@@ -1318,13 +1317,10 @@ internal object Devirtualization {
}
fun <T : IrElement> IrStatementsBuilder<T>.irTemporary(value: IrExpression, tempName: String, type: IrType): IrVariable {
val descriptor = WrappedVariableDescriptor()
val temporary = IrVariableImpl(
value.startOffset, value.endOffset, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(descriptor),
value.startOffset, value.endOffset, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(),
Name.identifier(tempName), type, isVar = false, isConst = false, isLateinit = false
).apply {
descriptor.bind(this)
this.initializer = value
}
@@ -210,7 +210,7 @@ internal class KonanIrLinker(
if (actualModule !== moduleDescriptor) {
val moduleDeserializer = deserializersForModules[actualModule] ?: error("No module deserializer for $actualModule")
moduleDeserializer.addModuleReachableTopLevel(idSig)
return symbolTable.referenceClassFromLinker(descriptor, idSig)
return symbolTable.referenceClassFromLinker(idSig)
}
return declaredDeclaration.getOrPut(idSig) { buildForwardDeclarationStub(descriptor) }.symbol
@@ -25,8 +25,6 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -69,11 +67,10 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC
private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val descriptor = WrappedFieldDescriptor()
val irField = IrFieldImpl(
expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED,
IrFieldSymbolImpl(descriptor),
IrFieldSymbolImpl(),
"topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
expression.type,
DescriptorVisibilities.PRIVATE,
@@ -81,8 +78,6 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: Ko
isExternal = false,
isStatic = true,
).apply {
descriptor.bind(this)
expression.setDeclarationsParent(this)
if (threadLocal)
@@ -264,21 +259,18 @@ fun IrBuilderWithScope.irSetVar(variable: IrVariable, value: IrExpression) =
fun IrBuilderWithScope.irCatch(type: IrType) =
IrCatchImpl(
startOffset, endOffset,
WrappedVariableDescriptor().let { descriptor ->
IrVariableImpl(
startOffset,
endOffset,
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
IrVariableSymbolImpl(descriptor),
Name.identifier("e"),
type,
false,
false,
false
).apply {
descriptor.bind(this)
parent = this@irCatch.parent
}
IrVariableImpl(
startOffset,
endOffset,
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
IrVariableSymbolImpl(),
Name.identifier("e"),
type,
false,
false,
false
).apply {
parent = this@irCatch.parent
}
)
@@ -345,11 +337,11 @@ fun createField(
name: Name,
isMutable: Boolean,
owner: IrClass
) = WrappedFieldDescriptor().let {
) =
IrFieldImpl(
startOffset, endOffset,
origin,
IrFieldSymbolImpl(it),
IrFieldSymbolImpl(),
name,
type,
DescriptorVisibilities.PRIVATE,
@@ -357,14 +349,12 @@ fun createField(
false,
false,
).apply {
it.bind(this)
owner.declarations += this
parent = owner
}
}
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
// Aggressive use of WrappedDescriptors during deserialization
// Aggressive use of IrBasedDescriptors during deserialization
// makes these types different.
// Let's hope they not really used afterwards.
//assert(this.descriptor.type == newDescriptor.type) {
@@ -448,6 +448,7 @@ task run_external () {
// Set up dependencies.
dependsOn(tasksOf(RunExternalTestGroup))
dependsOn("stdlibTest")
dependsOn("stdlibTestInWorker")
}
task daily() {
@@ -4922,10 +4923,22 @@ task override_konan_properties0(type: KonanDriverTest) {
}
}
createStdlibTest('stdlibTest', /* inWorker = */ false)
createStdlibTest('stdlibTestInWorker', /*inWorker = */ true)
/**
* Creates tasks to build and execute stdlib tests.
*/
KotlinNativeTestKt.createTest(project, 'stdlibTest', KonanGTest) { task ->
private void createStdlibTest(String name, boolean inWorker) {
KotlinNativeTestKt.createTest(project, name, KonanGTest) { task ->
configureStdlibTest(task, inWorker)
}
}
/**
* Configures tasks to build and execute stdlib tests.
*/
private void configureStdlibTest(KonanGTest task, boolean inWorker) {
def sources = UtilsKt.getFilesToCompile(project,
[ 'build/stdlib_external/stdlib', 'stdlib_external/utils.kt',
'stdlib_external/collections',
@@ -4934,11 +4947,11 @@ KotlinNativeTestKt.createTest(project, 'stdlibTest', KonanGTest) { task ->
[ 'build/stdlib_external/stdlib/test/internalAnnotations.kt' ])
konanArtifacts {
program('stdlibTest', targets: [target.name]) {
program(task.name, targets: [target.name]) {
srcFiles sources
baseDir "$testOutputStdlib/stdlibTest"
baseDir "$testOutputStdlib/$task.name"
enableMultiplatform true
extraOpts '-tr',
extraOpts inWorker ? '-trw' : '-tr',
'-Xverify-ir',
'-Xopt-in=kotlin.RequiresOptIn,kotlin.ExperimentalStdlibApi',
"-friend-modules", project.rootProject.file("${project.properties['konan.home']}/klib/common/stdlib").absolutePath
@@ -6,6 +6,8 @@
package test.text
@SharedImmutable
internal actual val surrogateCodePointDecoding: String = "\uFFFD".repeat(3)
@SharedImmutable
internal actual val surrogateCharEncoding: ByteArray = byteArrayOf(0xEF.toByte(), 0xBF.toByte(), 0xBD.toByte())
+6 -6
View File
@@ -18,12 +18,12 @@
buildKotlinVersion=1.4.20-dev-2167
buildKotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.4.20-dev-2167,branch:default:any,pinned:true/artifacts/content/maven
remoteRoot=konan_tests
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.5.0-dev-805,branch:default:any,pinned:true/artifacts/content/maven
kotlinVersion=1.5.0-dev-805
kotlinStdlibRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.5.0-dev-805,branch:default:any,pinned:true/artifacts/content/maven
kotlinStdlibVersion=1.5.0-dev-805
kotlinStdlibTestsVersion=1.5.0-dev-805
testKotlinCompilerVersion=1.5.0-dev-805
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.5.0-dev-1023,branch:default:any,pinned:true/artifacts/content/maven
kotlinVersion=1.5.0-dev-1023
kotlinStdlibRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.5.0-dev-1023,branch:default:any,pinned:true/artifacts/content/maven
kotlinStdlibVersion=1.5.0-dev-1023
kotlinStdlibTestsVersion=1.5.0-dev-1023
testKotlinCompilerVersion=1.5.0-dev-1023
konanVersion=1.5.0
# A version of Xcode required to build the Kotlin/Native compiler.
+24 -5
View File
@@ -140,8 +140,8 @@ targetList.forEach { targetName ->
createTestTask(
project,
"ExperimentalMM",
"${targetName}ExperimentalMMRuntimeTests",
"ExperimentalMMMimalloc",
"${targetName}ExperimentalMMMimallocRuntimeTests",
listOf(
"${targetName}Runtime",
"${targetName}ExperimentalMemoryManager",
@@ -153,10 +153,25 @@ targetList.forEach { targetName ->
includeRuntime()
}
createTestTask(
project,
"ExperimentalMMStdAlloc",
"${targetName}ExperimentalMMStdAllocRuntimeTests",
listOf(
"${targetName}Runtime",
"${targetName}ExperimentalMemoryManager",
"${targetName}Release",
"${targetName}StdAlloc"
)
) {
includeRuntime()
}
tasks.register("${targetName}RuntimeTests") {
dependsOn("${targetName}StdAllocRuntimeTests")
dependsOn("${targetName}MimallocRuntimeTests")
dependsOn("${targetName}ExperimentalMMRuntimeTests")
dependsOn("${targetName}ExperimentalMMStdAllocRuntimeTests")
dependsOn("${targetName}ExperimentalMMMimallocRuntimeTests")
}
}
@@ -176,8 +191,12 @@ val hostMimallocRuntimeTests by tasks.registering {
dependsOn("${hostName}MimallocRuntimeTests")
}
val hostExperimentalMMRuntimeTests by tasks.registering {
dependsOn("${hostName}ExperimentalMMRuntimeTests")
val hostExperimentalMMStdAllocRuntimeTests by tasks.registering {
dependsOn("${hostName}ExperimentalMMStdAllocRuntimeTests")
}
val hostExperimentalMMMimallocRuntimeTests by tasks.registering {
dependsOn("${hostName}ExperimentalMMMimallocRuntimeTests")
}
val assemble by tasks.registering {
@@ -1218,7 +1218,7 @@ ALWAYS_INLINE void runDeallocationHooks(ContainerHeader* container) {
CycleDetector::removeCandidateIfNeeded(obj);
#endif // USE_CYCLE_DETECTOR
if (obj->has_meta_object()) {
ObjHeader::destroyMetaObject(&obj->typeInfoOrMeta_);
ObjHeader::destroyMetaObject(obj);
}
obj = reinterpret_cast<ObjHeader*>(reinterpret_cast<uintptr_t>(obj) + objectSize(obj));
}
@@ -3102,7 +3102,8 @@ OBJ_GETTER(findCycle, KRef root) {
} // namespace
MetaObjHeader* ObjHeader::createMetaObject(TypeInfo** location) {
MetaObjHeader* ObjHeader::createMetaObject(ObjHeader* object) {
TypeInfo** location = &object->typeInfoOrMeta_;
TypeInfo* typeInfo = *location;
RuntimeCheck(!hasPointerBits(typeInfo, OBJECT_TAG_MASK), "Object must not be tagged");
@@ -3128,7 +3129,8 @@ MetaObjHeader* ObjHeader::createMetaObject(TypeInfo** location) {
return meta;
}
void ObjHeader::destroyMetaObject(TypeInfo** location) {
void ObjHeader::destroyMetaObject(ObjHeader* object) {
TypeInfo** location = &object->typeInfoOrMeta_;
MetaObjHeader* meta = clearPointerBits(*(reinterpret_cast<MetaObjHeader**>(location)), OBJECT_TAG_MASK);
*const_cast<const TypeInfo**>(location) = meta->typeInfo_;
if (meta->WeakReference.counter_ != nullptr) {
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2020 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.
*/
#ifndef RUNTIME_ALIGNMENT_H
#define RUNTIME_ALIGNMENT_H
#include <cstddef>
#include <cstdint>
namespace kotlin {
constexpr size_t kObjectAlignment = 8;
constexpr inline size_t AlignUp(size_t size, size_t alignment) {
return (size + alignment - 1) & ~(alignment - 1);
}
inline void* AlignUp(void* ptr, size_t alignment) {
static_assert(sizeof(void*) == sizeof(size_t), "size_t size must be equal to pointer size for this to work");
return reinterpret_cast<void*>(AlignUp(reinterpret_cast<size_t>(ptr), alignment));
}
constexpr inline bool IsValidAlignment(size_t alignment) {
return alignment != 0 && (alignment & (alignment - 1)) == 0;
}
constexpr inline bool IsAligned(size_t size, size_t alignment) {
return size % alignment == 0;
}
inline bool IsAligned(void* ptr, size_t alignment) {
return reinterpret_cast<uintptr_t>(ptr) % alignment == 0;
}
} // namespace kotlin
#endif // RUNTIME_ALIGNMENT_H
@@ -0,0 +1,157 @@
/*
* Copyright 2010-2020 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.
*/
#include "Alignment.hpp"
#include <cstddef>
#include <tuple>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "Types.h"
using namespace kotlin;
namespace {
template <typename... Args>
class NamedTestWithParam : public testing::TestWithParam<std::tuple<const char*, Args...>> {
public:
using Param = std::tuple<const char*, Args...>;
static std::string Print(const testing::TestParamInfo<Param>& info) { return std::string(std::get<0>(info.param)); }
template <size_t I>
static const typename std::tuple_element<I + 1, Param>::type& Get() {
const auto& param = testing::TestWithParam<Param>::GetParam();
return std::get<I + 1>(param);
}
};
#define INSTANTIATE_NAMED_TEST(testName, ...) INSTANTIATE_TEST_SUITE_P(, testName, testing::Values(__VA_ARGS__), &testName::Print)
} // namespace
using IsValidAlignmentTest = NamedTestWithParam<size_t, bool>;
TEST_P(IsValidAlignmentTest, Test) {
const auto& alignment = Get<0>();
const auto& expected = Get<1>();
EXPECT_THAT(IsValidAlignment(alignment), expected);
}
INSTANTIATE_NAMED_TEST(
IsValidAlignmentTest,
std::make_tuple("0", 0, false),
std::make_tuple("1", 1, true),
std::make_tuple("2", 2, true),
std::make_tuple("3", 3, false),
std::make_tuple("4", 4, true),
std::make_tuple("5", 5, false),
std::make_tuple("6", 6, false),
std::make_tuple("7", 7, false),
std::make_tuple("8", 8, true),
std::make_tuple("9", 9, false),
std::make_tuple("10", 10, false),
std::make_tuple("11", 11, false),
std::make_tuple("12", 12, false),
std::make_tuple("13", 13, false),
std::make_tuple("14", 14, false),
std::make_tuple("15", 15, false),
std::make_tuple("16", 16, true),
std::make_tuple("int", alignof(int), true),
std::make_tuple("ptr", alignof(void*), true),
std::make_tuple("max", alignof(std::max_align_t), true));
using IsAlignedSizeTest = NamedTestWithParam<size_t, size_t, bool>;
TEST_P(IsAlignedSizeTest, Test) {
const auto& size = Get<0>();
const auto& alignment = Get<1>();
const auto& expected = Get<2>();
EXPECT_THAT(IsAligned(size, alignment), expected);
}
INSTANTIATE_NAMED_TEST(
IsAlignedSizeTest,
std::make_tuple("1_1", 1, 1, true),
std::make_tuple("2_1", 2, 1, true),
std::make_tuple("3_1", 3, 1, true),
std::make_tuple("4_1", 4, 1, true),
std::make_tuple("1_2", 1, 2, false),
std::make_tuple("2_2", 2, 2, true),
std::make_tuple("3_2", 3, 2, false),
std::make_tuple("4_2", 4, 2, true));
using IsAlignedPointerTest = NamedTestWithParam<uintptr_t, size_t, bool>;
TEST_P(IsAlignedPointerTest, Test) {
const auto& ptr = Get<0>();
const auto& alignment = Get<1>();
const auto& expected = Get<2>();
EXPECT_THAT(IsAligned(reinterpret_cast<void*>(ptr), alignment), expected);
}
INSTANTIATE_NAMED_TEST(
IsAlignedPointerTest,
std::make_tuple("0_1", 0, 1, true),
std::make_tuple("1_1", 1, 1, true),
std::make_tuple("2_1", 2, 1, true),
std::make_tuple("3_1", 3, 1, true),
std::make_tuple("4_1", 4, 1, true),
std::make_tuple("0_2", 0, 2, true),
std::make_tuple("1_2", 1, 2, false),
std::make_tuple("2_2", 2, 2, true),
std::make_tuple("3_2", 3, 2, false),
std::make_tuple("4_2", 4, 2, true));
using AlignUpSizeTest = NamedTestWithParam<size_t, size_t, size_t>;
TEST_P(AlignUpSizeTest, Test) {
const auto& size = Get<0>();
const auto& alignment = Get<1>();
const auto& expected = Get<2>();
EXPECT_THAT(AlignUp(size, alignment), expected);
}
INSTANTIATE_NAMED_TEST(
AlignUpSizeTest,
std::make_tuple("1_1", 1, 1, 1),
std::make_tuple("2_1", 2, 1, 2),
std::make_tuple("3_1", 3, 1, 3),
std::make_tuple("4_1", 4, 1, 4),
std::make_tuple("1_2", 1, 2, 2),
std::make_tuple("2_2", 2, 2, 2),
std::make_tuple("3_2", 3, 2, 4),
std::make_tuple("4_2", 4, 2, 4));
using AlignUpPointerTest = NamedTestWithParam<uintptr_t, size_t, uintptr_t>;
TEST_P(AlignUpPointerTest, Test) {
const auto& ptr = Get<0>();
const auto& alignment = Get<1>();
const auto& expected = Get<2>();
EXPECT_THAT(AlignUp(reinterpret_cast<void*>(ptr), alignment), reinterpret_cast<void*>(expected));
}
INSTANTIATE_NAMED_TEST(
AlignUpPointerTest,
std::make_tuple("0_1", 0, 1, 0),
std::make_tuple("1_1", 1, 1, 1),
std::make_tuple("2_1", 2, 1, 2),
std::make_tuple("3_1", 3, 1, 3),
std::make_tuple("4_1", 4, 1, 4),
std::make_tuple("0_2", 0, 2, 0),
std::make_tuple("1_2", 1, 2, 2),
std::make_tuple("2_2", 2, 2, 2),
std::make_tuple("3_2", 3, 2, 4),
std::make_tuple("4_2", 4, 2, 4));
TEST(AlignmentTest, ObjectAlignment) {
static_assert(IsValidAlignment(kObjectAlignment), "kObjectAlignment must be a valid alignment");
static_assert(kObjectAlignment % alignof(KLong) == 0, "");
static_assert(kObjectAlignment % alignof(KDouble) == 0, "");
}
@@ -29,6 +29,10 @@ inline void* konanAllocMemory(size_t size) {
return konan::calloc(1, size);
}
inline void* konanAllocAlignedMemory(size_t size, size_t alignment) {
return konan::calloc_aligned(1, size, alignment);
}
inline void konanFreeMemory(void* memory) {
konan::free(memory);
}
@@ -30,3 +30,16 @@ RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* form
// TODO: Write the stacktrace.
konan::abort();
}
// TODO: this function is not used by runtime, but apparently there are
// third-party libraries that use it (despite the fact it is not a public API).
// Keeping the function here for now for backward compatibility, to be removed later.
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* message) {
char buf[1024];
if (location != nullptr)
konan::snprintf(buf, sizeof(buf), "%s: runtime assert: %s\n", location, message);
else
konan::snprintf(buf, sizeof(buf), "runtime assert: %s\n", message);
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf)));
konan::abort();
}
+17 -7
View File
@@ -38,19 +38,29 @@ struct MetaObjHeader;
struct ObjHeader {
TypeInfo* typeInfoOrMeta_;
// Returns `nullptr` if it's not a meta object.
static MetaObjHeader* AsMetaObject(TypeInfo* typeInfo) noexcept {
auto* typeInfoOrMeta = clearPointerBits(typeInfo, OBJECT_TAG_MASK);
if (typeInfoOrMeta != typeInfoOrMeta->typeInfo_) {
return reinterpret_cast<MetaObjHeader*>(typeInfoOrMeta);
} else {
return nullptr;
}
}
const TypeInfo* type_info() const {
return clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK)->typeInfo_;
}
bool has_meta_object() const {
auto* typeInfoOrMeta = clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK);
return (typeInfoOrMeta != typeInfoOrMeta->typeInfo_);
return AsMetaObject(typeInfoOrMeta_) != nullptr;
}
MetaObjHeader* meta_object() {
return has_meta_object() ?
reinterpret_cast<MetaObjHeader*>(clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK)) :
createMetaObject(&typeInfoOrMeta_);
if (auto* metaObject = AsMetaObject(typeInfoOrMeta_)) {
return metaObject;
}
return createMetaObject(this);
}
ALWAYS_INLINE ObjHeader** GetWeakCounterLocation();
@@ -75,8 +85,8 @@ struct ObjHeader {
return hasPointerBits(typeInfoOrMeta_, OBJECT_TAG_PERMANENT_CONTAINER);
}
static MetaObjHeader* createMetaObject(TypeInfo** location);
static void destroyMetaObject(TypeInfo** location);
static MetaObjHeader* createMetaObject(ObjHeader* object);
static void destroyMetaObject(ObjHeader* object);
};
// Header of value type array objects. Keep layout in sync with that of object header.
@@ -157,6 +157,8 @@ struct TypeInfo {
inline VTableElement* vtable() {
return reinterpret_cast<VTableElement*>(this + 1);
}
inline bool IsArray() const { return instanceSize_ < 0; }
#endif
};
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2020 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.
*/
#include "ExtraObjectData.hpp"
#include "PointerBits.h"
#include "Weak.h"
#ifdef KONAN_OBJC_INTEROP
#include "ObjCMMAPI.h"
#endif
using namespace kotlin;
// static
mm::ExtraObjectData& mm::ExtraObjectData::Install(ObjHeader* object) noexcept {
TypeInfo* typeInfo = object->typeInfoOrMeta_;
if (auto* metaObject = ObjHeader::AsMetaObject(typeInfo)) {
return mm::ExtraObjectData::FromMetaObjHeader(metaObject);
}
RuntimeCheck(!hasPointerBits(typeInfo, OBJECT_TAG_MASK), "Object must not be tagged");
auto* data = new ExtraObjectData(typeInfo);
TypeInfo* old = __sync_val_compare_and_swap(&object->typeInfoOrMeta_, typeInfo, reinterpret_cast<TypeInfo*>(data));
if (old != typeInfo) {
// Somebody else created `mm::ExtraObjectData` for this object
delete data;
return *reinterpret_cast<mm::ExtraObjectData*>(old);
}
return *data;
}
// static
void mm::ExtraObjectData::Uninstall(ObjHeader* object) noexcept {
RuntimeAssert(object->has_meta_object(), "Object must have a meta object set");
auto& data = ExtraObjectData::FromMetaObjHeader(object->meta_object());
*const_cast<const TypeInfo**>(&object->typeInfoOrMeta_) = data.typeInfo_;
delete &data;
}
mm::ExtraObjectData::~ExtraObjectData() {
if (weakReferenceCounter_) {
WeakReferenceCounterClear(weakReferenceCounter_);
ZeroHeapRef(&weakReferenceCounter_);
}
#ifdef KONAN_OBJC_INTEROP
Kotlin_ObjCExport_releaseAssociatedObject(associatedObject_);
#endif
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2020 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.
*/
#ifndef RUNTIME_MM_EXTRA_OBJECT_DATA_H
#define RUNTIME_MM_EXTRA_OBJECT_DATA_H
#include <cstddef>
#include <cstdint>
#include "Memory.h"
#include "TypeInfo.h"
#include "Utils.hpp"
namespace kotlin {
namespace mm {
// Optional data that's lazily allocated only for objects that need it.
class ExtraObjectData : private Pinned {
public:
MetaObjHeader* AsMetaObjHeader() noexcept { return reinterpret_cast<MetaObjHeader*>(this); }
static ExtraObjectData& FromMetaObjHeader(MetaObjHeader* header) noexcept { return *reinterpret_cast<ExtraObjectData*>(header); }
static ExtraObjectData& Install(ObjHeader* object) noexcept;
static void Uninstall(ObjHeader* object) noexcept;
#ifdef KONAN_OBJC_INTEROP
void** GetAssociatedObjectLocation() noexcept { return &associatedObject_; }
#endif
ObjHeader** GetWeakCounterLocation() noexcept { return &weakReferenceCounter_; }
private:
explicit ExtraObjectData(const TypeInfo* typeInfo) noexcept : typeInfo_(typeInfo) {}
~ExtraObjectData();
// Must be first to match `TypeInfo` layout.
const TypeInfo* typeInfo_;
#ifdef KONAN_OBJC_INTEROP
void* associatedObject_ = nullptr;
#endif
// TODO: Need to respect when marking.
ObjHeader* weakReferenceCounter_ = nullptr;
};
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_EXTRA_OBJECT_DATA_H
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2020 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.
*/
#include "ExtraObjectData.hpp"
#include <atomic>
#include <thread>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "TestSupport.hpp"
using namespace kotlin;
TEST(ExtraObjectDataTest, Install) {
TypeInfo typeInfo;
typeInfo.typeInfo_ = &typeInfo;
ObjHeader object;
object.typeInfoOrMeta_ = &typeInfo;
ASSERT_FALSE(object.has_meta_object());
auto& extraData = mm::ExtraObjectData::Install(&object);
EXPECT_TRUE(object.has_meta_object());
EXPECT_THAT(object.meta_object(), extraData.AsMetaObjHeader());
EXPECT_THAT(object.type_info(), &typeInfo);
mm::ExtraObjectData::Uninstall(&object);
EXPECT_FALSE(object.has_meta_object());
EXPECT_THAT(object.type_info(), &typeInfo);
}
TEST(ExtraObjectDataTest, ConcurrentInstall) {
TypeInfo typeInfo;
typeInfo.typeInfo_ = &typeInfo;
ObjHeader object;
object.typeInfoOrMeta_ = &typeInfo;
constexpr int kThreadCount = kDefaultThreadCount;
std::atomic<bool> canStart(false);
std::atomic<int> readyCount(0);
std::vector<std::thread> threads;
std::vector<mm::ExtraObjectData*> actual(kThreadCount, nullptr);
for (int i = 0; i < kThreadCount; ++i) {
threads.emplace_back([i, &actual, &object, &canStart, &readyCount]() {
++readyCount;
while (!canStart) {
}
auto& extraData = mm::ExtraObjectData::Install(&object);
actual[i] = &extraData;
});
}
while (readyCount < kThreadCount) {
}
canStart = true;
for (auto& t : threads) {
t.join();
}
std::vector<mm::ExtraObjectData*> expected(kThreadCount, actual[0]);
EXPECT_THAT(actual, testing::ElementsAreArray(expected));
mm::ExtraObjectData::Uninstall(&object);
}
@@ -6,6 +6,7 @@
#ifndef RUNTIME_MM_GLOBAL_DATA_H
#define RUNTIME_MM_GLOBAL_DATA_H
#include "ObjectFactory.hpp"
#include "GlobalsRegistry.hpp"
#include "StableRefRegistry.hpp"
#include "ThreadRegistry.hpp"
@@ -19,9 +20,10 @@ class GlobalData : private Pinned {
public:
static GlobalData& Instance() noexcept { return instance_; }
ThreadRegistry& threadRegistry() { return threadRegistry_; }
GlobalsRegistry& globalsRegistry() { return globalsRegistry_; }
StableRefRegistry& stableRefRegistry() { return stableRefRegistry_; }
ThreadRegistry& threadRegistry() noexcept { return threadRegistry_; }
GlobalsRegistry& globalsRegistry() noexcept { return globalsRegistry_; }
StableRefRegistry& stableRefRegistry() noexcept { return stableRefRegistry_; }
ObjectFactory& objectFactory() noexcept { return objectFactory_; }
private:
GlobalData();
@@ -32,6 +34,7 @@ private:
ThreadRegistry threadRegistry_;
GlobalsRegistry globalsRegistry_;
StableRefRegistry stableRefRegistry_;
ObjectFactory objectFactory_;
};
} // namespace mm
@@ -5,6 +5,8 @@
#include "Memory.h"
#include "Exceptions.h"
#include "ExtraObjectData.hpp"
#include "GlobalsRegistry.hpp"
#include "KAssert.h"
#include "Porting.h"
@@ -57,6 +59,39 @@ ALWAYS_INLINE mm::ThreadData* GetThreadData(MemoryState* state) {
} // namespace
ObjHeader** ObjHeader::GetWeakCounterLocation() {
return mm::ExtraObjectData::FromMetaObjHeader(this->meta_object()).GetWeakCounterLocation();
}
#ifdef KONAN_OBJC_INTEROP
void* ObjHeader::GetAssociatedObject() {
if (!has_meta_object()) {
return nullptr;
}
return *GetAssociatedObjectLocation();
}
void** ObjHeader::GetAssociatedObjectLocation() {
return mm::ExtraObjectData::FromMetaObjHeader(this->meta_object()).GetAssociatedObjectLocation();
}
void ObjHeader::SetAssociatedObject(void* obj) {
*GetAssociatedObjectLocation() = obj;
}
#endif // KONAN_OBJC_INTEROP
// static
MetaObjHeader* ObjHeader::createMetaObject(ObjHeader* object) {
return mm::ExtraObjectData::Install(object).AsMetaObjHeader();
}
// static
void ObjHeader::destroyMetaObject(ObjHeader* object) {
mm::ExtraObjectData::Uninstall(object);
}
ALWAYS_INLINE bool isShareable(const ObjHeader* obj) {
// TODO: Remove when legacy MM is gone.
return true;
@@ -74,6 +109,22 @@ extern "C" void RestoreMemory(MemoryState*) {
// TODO: Remove when legacy MM is gone.
}
extern "C" RUNTIME_NOTHROW OBJ_GETTER(AllocInstance, const TypeInfo* typeInfo) {
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
auto* object = threadData->objectFactoryThreadQueue().CreateObject(typeInfo);
RETURN_OBJ(object);
}
extern "C" OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elements) {
if (elements < 0) {
ThrowIllegalArgumentException();
}
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
auto* array = threadData->objectFactoryThreadQueue().CreateArray(typeInfo, static_cast<uint32_t>(elements));
// `ArrayHeader` and `ObjHeader` are expected to be compatible.
RETURN_OBJ(reinterpret_cast<ObjHeader*>(array));
}
extern "C" OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
// TODO: This should only be called if singleton is actually created here. It's possible that the
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2020 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.
*/
#include "ObjectFactory.hpp"
#include "Alignment.hpp"
#include "Alloc.h"
#include "GlobalData.hpp"
#include "Types.h"
using namespace kotlin;
ObjHeader* mm::ObjectFactory::ThreadQueue::CreateObject(const TypeInfo* typeInfo) noexcept {
RuntimeAssert(!typeInfo->IsArray(), "Must not be an array");
size_t allocSize = typeInfo->instanceSize_;
auto& node = producer_.Insert(allocSize);
auto* object = static_cast<ObjHeader*>(node.Data());
object->typeInfoOrMeta_ = const_cast<TypeInfo*>(typeInfo);
return object;
}
ArrayHeader* mm::ObjectFactory::ThreadQueue::CreateArray(const TypeInfo* typeInfo, uint32_t count) noexcept {
RuntimeAssert(typeInfo->IsArray(), "Must be an array");
uint32_t arraySize = static_cast<uint32_t>(-typeInfo->instanceSize_) * count;
// Note: array body is aligned, but for size computation it is enough to align the sum.
size_t allocSize = AlignUp(sizeof(ArrayHeader) + arraySize, kObjectAlignment);
auto& node = producer_.Insert(allocSize);
auto* array = static_cast<ArrayHeader*>(node.Data());
array->typeInfoOrMeta_ = const_cast<TypeInfo*>(typeInfo);
array->count_ = count;
return array;
}
bool mm::ObjectFactory::Iterator::IsArray() noexcept {
// `ArrayHeader` and `ObjHeader` are kept compatible, so the former can
// be always casted to the other.
auto* object = static_cast<ObjHeader*>((*iterator_).Data());
return object->type_info()->IsArray();
}
ObjHeader* mm::ObjectFactory::Iterator::GetObjHeader() noexcept {
auto* object = static_cast<ObjHeader*>((*iterator_).Data());
RuntimeAssert(!object->type_info()->IsArray(), "Must not be an array");
return object;
}
ArrayHeader* mm::ObjectFactory::Iterator::GetArrayHeader() noexcept {
auto* array = static_cast<ArrayHeader*>((*iterator_).Data());
RuntimeAssert(array->type_info()->IsArray(), "Must be an array");
return array;
}
mm::ObjectFactory::ObjectFactory() noexcept = default;
mm::ObjectFactory::~ObjectFactory() = default;
// static
mm::ObjectFactory& mm::ObjectFactory::Instance() noexcept {
return GlobalData::Instance().objectFactory();
}
@@ -0,0 +1,316 @@
/*
* Copyright 2010-2020 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.
*/
#ifndef RUNTIME_MM_OBJECT_FACTORY_H
#define RUNTIME_MM_OBJECT_FACTORY_H
#include <algorithm>
#include <memory>
#include <mutex>
#include "Alignment.hpp"
#include "Alloc.h"
#include "CppSupport.hpp"
#include "Memory.h"
#include "Mutex.hpp"
#include "Utils.hpp"
namespace kotlin {
namespace mm {
namespace internal {
// A queue that is constructed by collecting subqueues from several `Producer`s.
// This is essentially a heterogeneous `MultiSourceQueue` on top of a singly linked list that
// uses `konanAllocMemory` and `konanFreeMemory`
// TODO: Consider merging with `MultiSourceQueue` somehow.
template <size_t DataAlignment>
class ObjectFactoryStorage : private Pinned {
static_assert(IsValidAlignment(DataAlignment), "DataAlignment is not a valid alignment");
public:
// This class does not know its size at compile-time.
class Node : private Pinned {
constexpr static size_t DataOffset() noexcept { return AlignUp(sizeof(Node), DataAlignment); }
public:
~Node() = default;
static void operator delete(void* ptr) noexcept { konanFreeMemory(ptr); }
// Note: This can only be trivially destructible data, as nobody can invoke its destructor.
void* Data() noexcept {
constexpr size_t kDataOffset = DataOffset();
void* ptr = reinterpret_cast<uint8_t*>(this) + kDataOffset;
RuntimeAssert(IsAligned(ptr, DataAlignment), "Data=%p is not aligned to %zu", ptr, DataAlignment);
return ptr;
}
// It's a caller responsibility to know if the underlying data is `T`.
template <typename T>
T& Data() noexcept {
return *static_cast<T*>(Data());
}
private:
friend class ObjectFactoryStorage;
Node() noexcept = default;
static void* operator new(size_t size, size_t dataSize) noexcept {
size_t dataSizeAligned = AlignUp(dataSize, DataAlignment);
size_t totalAlignment = std::max(alignof(Node), DataAlignment);
size_t totalSize = AlignUp(sizeof(Node) + dataSizeAligned, totalAlignment);
RuntimeAssert(
DataOffset() + dataSize <= totalSize, "totalSize %zu is not enough to fit data %zu at offset %zu", totalSize, dataSize,
DataOffset());
void* ptr = konanAllocAlignedMemory(totalSize, totalAlignment);
if (!ptr) {
// TODO: Try doing GC first.
konan::consoleErrorf("Out of memory trying to allocate %zu. Aborting.\n", totalSize);
konan::abort();
}
RuntimeAssert(IsAligned(ptr, totalAlignment), "Allocator returned unaligned to %zu pointer %p", totalAlignment, ptr);
return ptr;
}
std::unique_ptr<Node> next_;
// There's some more data of an unknown (at compile-time) size here, but it cannot be represented
// with C++ members.
};
class Producer : private MoveOnly {
public:
explicit Producer(ObjectFactoryStorage& owner) noexcept : owner_(owner) {}
~Producer() { Publish(); }
Node& Insert(size_t dataSize) noexcept {
AssertCorrect();
auto* nodePtr = new (dataSize) Node();
std::unique_ptr<Node> node(nodePtr);
if (!root_) {
RuntimeAssert(last_ == nullptr, "Unsynchronized root_ and last_");
root_ = std::move(node);
} else {
RuntimeAssert(last_ != nullptr, "Unsynchronized root_ and last_");
last_->next_ = std::move(node);
}
last_ = nodePtr;
RuntimeAssert(root_ != nullptr, "Must not be empty");
AssertCorrect();
return *nodePtr;
}
template <typename T, typename... Args>
Node& Insert(Args&&... args) noexcept {
static_assert(alignof(T) <= DataAlignment, "Cannot insert type with alignment bigger than DataAlignment");
static_assert(std_support::is_trivially_destructible_v<T>, "Type must be trivially destructible");
auto& node = Insert(sizeof(T));
new (node.Data()) T(std::forward<Args>(args)...);
return node;
}
// Merge `this` queue with owning `ObjectFactoryStorage`.
// `this` will have empty queue after the call.
// This call is performed without heap allocations. TODO: Test that no allocations are happening.
void Publish() noexcept {
AssertCorrect();
if (!root_) {
return;
}
std::lock_guard<SpinLock> guard(owner_.mutex_);
owner_.AssertCorrectUnsafe();
if (!owner_.root_) {
owner_.root_ = std::move(root_);
} else {
owner_.last_->next_ = std::move(root_);
}
owner_.last_ = last_;
last_ = nullptr;
RuntimeAssert(root_ == nullptr, "Must be empty");
AssertCorrect();
RuntimeAssert(owner_.root_ != nullptr, "Must not be empty");
owner_.AssertCorrectUnsafe();
}
private:
friend class ObjectFactoryStorage;
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");
}
}
ObjectFactoryStorage& owner_; // weak
std::unique_ptr<Node> root_;
Node* last_ = nullptr;
};
class Iterator {
public:
Node& operator*() noexcept { return *node_; }
Node* operator->() noexcept { return node_; }
Iterator& operator++() noexcept {
previousNode_ = node_;
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 ObjectFactoryStorage;
Iterator(Node* previousNode, Node* node) noexcept : previousNode_(previousNode), node_(node) {}
Node* previousNode_; // Kept for `Iterable::EraseAndAdvance`.
Node* node_;
};
class Iterable : private MoveOnly {
public:
explicit Iterable(ObjectFactoryStorage& owner) noexcept : owner_(owner), guard_(owner_.mutex_) {}
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_); }
private:
ObjectFactoryStorage& owner_; // weak
std::unique_lock<SpinLock> guard_;
};
// Lock `ObjectFactoryStorage` for safe iteration.
Iterable Iter() noexcept { return Iterable(*this); }
private:
// Expects `mutex_` to be held by the current thread.
Node* EraseUnsafe(Node* previousNode) noexcept {
RuntimeAssert(root_ != nullptr, "Must not be empty");
AssertCorrectUnsafe();
if (previousNode == nullptr) {
// Deleting the root.
root_ = std::move(root_->next_);
if (!root_) {
last_ = nullptr;
}
AssertCorrectUnsafe();
return root_.get();
}
auto node = std::move(previousNode->next_);
previousNode->next_ = std::move(node->next_);
if (!previousNode->next_) {
last_ = previousNode;
}
AssertCorrectUnsafe();
return previousNode->next_.get();
}
// Expects `mutex_` to be held by the current thread.
ALWAYS_INLINE void AssertCorrectUnsafe() 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");
}
}
std::unique_ptr<Node> root_;
Node* last_ = nullptr;
SpinLock mutex_;
};
} // namespace internal
class ObjectFactory : private Pinned {
public:
using Storage = internal::ObjectFactoryStorage<kObjectAlignment>;
class ThreadQueue : private MoveOnly {
public:
explicit ThreadQueue(ObjectFactory& owner) noexcept : producer_(owner.storage_) {}
ObjHeader* CreateObject(const TypeInfo* typeInfo) noexcept;
ArrayHeader* CreateArray(const TypeInfo* typeInfo, uint32_t count) noexcept;
void Publish() noexcept { producer_.Publish(); }
private:
Storage::Producer producer_;
};
class Iterator {
public:
Storage::Node& operator*() noexcept { return *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_; }
bool IsArray() noexcept;
ObjHeader* GetObjHeader() noexcept;
ArrayHeader* GetArrayHeader() noexcept;
private:
friend class ObjectFactory;
explicit Iterator(Storage::Iterator iterator) noexcept : iterator_(std::move(iterator)) {}
Storage::Iterator iterator_;
};
class Iterable {
public:
Iterable(ObjectFactory& owner) noexcept : iter_(owner.storage_.Iter()) {}
Iterator begin() noexcept { return Iterator(iter_.begin()); }
Iterator end() noexcept { return Iterator(iter_.end()); }
void EraseAndAdvance(Iterator& iterator) noexcept { iter_.EraseAndAdvance(iterator.iterator_); }
private:
Storage::Iterable iter_;
};
ObjectFactory() noexcept;
~ObjectFactory();
static ObjectFactory& Instance() noexcept;
Iterable Iter() noexcept { return Iterable(*this); }
private:
Storage storage_;
};
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_OBJECT_FACTORY_H
@@ -0,0 +1,573 @@
/*
* Copyright 2010-2020 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.
*/
#include "ObjectFactory.hpp"
#include <atomic>
#include <thread>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "CppSupport.hpp"
#include "TestSupport.hpp"
using namespace kotlin;
template <size_t DataAlignment>
using ObjectFactoryStorage = mm::internal::ObjectFactoryStorage<DataAlignment>;
using ObjectFactoryStorageRegular = ObjectFactoryStorage<alignof(void*)>;
namespace {
template <size_t DataAlignment>
std::vector<void*> Collect(ObjectFactoryStorage<DataAlignment>& storage) {
std::vector<void*> result;
for (auto& node : storage.Iter()) {
result.push_back(node.Data());
}
return result;
}
template <typename T, size_t DataAlignment>
std::vector<T> Collect(ObjectFactoryStorage<DataAlignment>& storage) {
std::vector<T> result;
for (auto& node : storage.Iter()) {
result.push_back(*static_cast<T*>(node.Data()));
}
return result;
}
struct MoveOnlyImpl : private MoveOnly {
MoveOnlyImpl(int value1, int value2) : value1(value1), value2(value2) {}
int value1;
int value2;
};
struct PinnedImpl : private Pinned {
PinnedImpl(int value1, int value2, int value3) : value1(value1), value2(value2), value3(value3) {}
int value1;
int value2;
int value3;
};
struct MaxAlignedData {
explicit MaxAlignedData(int value) : value(value) {}
std::max_align_t padding;
int value;
};
} // namespace
TEST(ObjectFactoryStorageTest, Empty) {
ObjectFactoryStorageRegular storage;
auto actual = Collect(storage);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ObjectFactoryStorageTest, DoNotPublish) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(1);
producer.Insert<int>(2);
auto actual = Collect(storage);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ObjectFactoryStorageTest, Publish) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer1(storage);
ObjectFactoryStorageRegular::Producer producer2(storage);
producer1.Insert<int>(1);
producer1.Insert<int>(2);
producer2.Insert<int>(10);
producer2.Insert<int>(20);
producer1.Publish();
producer2.Publish();
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 10, 20));
}
TEST(ObjectFactoryStorageTest, PublishDifferentTypes) {
ObjectFactoryStorage<alignof(MaxAlignedData)> storage;
ObjectFactoryStorage<alignof(MaxAlignedData)>::Producer producer(storage);
producer.Insert<int>(1);
producer.Insert<size_t>(2);
producer.Insert<MoveOnlyImpl>(3, 4);
producer.Insert<PinnedImpl>(5, 6, 7);
producer.Insert<MaxAlignedData>(8);
producer.Publish();
auto actual = storage.Iter();
auto it = actual.begin();
EXPECT_THAT(it->Data<int>(), 1);
++it;
EXPECT_THAT(it->Data<size_t>(), 2);
++it;
auto& moveOnly = it->Data<MoveOnlyImpl>();
EXPECT_THAT(moveOnly.value1, 3);
EXPECT_THAT(moveOnly.value2, 4);
++it;
auto& pinned = it->Data<PinnedImpl>();
EXPECT_THAT(pinned.value1, 5);
EXPECT_THAT(pinned.value2, 6);
EXPECT_THAT(pinned.value3, 7);
++it;
auto& maxAlign = it->Data<MaxAlignedData>();
EXPECT_THAT(maxAlign.value, 8);
++it;
EXPECT_THAT(it, actual.end());
}
TEST(ObjectFactoryStorageTest, PublishSeveralTimes) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
// Add 2 elements and publish.
producer.Insert<int>(1);
producer.Insert<int>(2);
producer.Publish();
// Add another element and publish.
producer.Insert<int>(3);
producer.Publish();
// Publish without adding elements.
producer.Publish();
// Add yet another two elements and publish.
producer.Insert<int>(4);
producer.Insert<int>(5);
producer.Publish();
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 3, 4, 5));
}
TEST(ObjectFactoryStorageTest, PublishInDestructor) {
ObjectFactoryStorageRegular storage;
{
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(1);
producer.Insert<int>(2);
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(1, 2));
}
TEST(ObjectFactoryStorageTest, EraseFirst) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
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.EraseAndAdvance(it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(2, 3));
}
TEST(ObjectFactoryStorageTest, EraseMiddle) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
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.EraseAndAdvance(it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(1, 3));
}
TEST(ObjectFactoryStorageTest, EraseLast) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
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.EraseAndAdvance(it);
} else {
++it;
}
}
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::ElementsAre(1, 2));
}
TEST(ObjectFactoryStorageTest, EraseAll) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
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.EraseAndAdvance(it);
}
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ObjectFactoryStorageTest, EraseTheOnlyElement) {
ObjectFactoryStorageRegular storage;
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(1);
producer.Publish();
{
auto iter = storage.Iter();
auto it = iter.begin();
iter.EraseAndAdvance(it);
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ObjectFactoryStorageTest, ConcurrentPublish) {
ObjectFactoryStorageRegular storage;
constexpr int kThreadCount = kDefaultThreadCount;
std::atomic<bool> canStart(false);
std::atomic<int> readyCount(0);
std::vector<std::thread> threads;
std::vector<int> expected;
for (int i = 0; i < kThreadCount; ++i) {
expected.push_back(i);
threads.emplace_back([i, &storage, &canStart, &readyCount]() {
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(i);
++readyCount;
while (!canStart) {
}
producer.Publish();
});
}
while (readyCount < kThreadCount) {
}
canStart = true;
for (auto& t : threads) {
t.join();
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected));
}
TEST(ObjectFactoryStorageTest, IterWhileConcurrentPublish) {
ObjectFactoryStorageRegular storage;
constexpr int kStartCount = 50;
constexpr int kThreadCount = kDefaultThreadCount;
std::vector<int> expectedBefore;
std::vector<int> expectedAfter;
ObjectFactoryStorageRegular::Producer producer(storage);
for (int i = 0; i < kStartCount; ++i) {
expectedBefore.push_back(i);
expectedAfter.push_back(i);
producer.Insert<int>(i);
}
producer.Publish();
std::atomic<bool> canStart(false);
std::atomic<int> readyCount(0);
std::atomic<int> startedCount(0);
std::vector<std::thread> threads;
for (int i = 0; i < kThreadCount; ++i) {
int j = i + kStartCount;
expectedAfter.push_back(j);
threads.emplace_back([j, &storage, &canStart, &startedCount, &readyCount]() {
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(j);
++readyCount;
while (!canStart) {
}
++startedCount;
producer.Publish();
});
}
std::vector<int> actualBefore;
{
auto iter = storage.Iter();
while (readyCount < kThreadCount) {
}
canStart = true;
while (startedCount < kThreadCount) {
}
for (auto& node : iter) {
int element = *static_cast<int*>(node.Data());
actualBefore.push_back(element);
}
}
for (auto& t : threads) {
t.join();
}
EXPECT_THAT(actualBefore, testing::ElementsAreArray(expectedBefore));
auto actualAfter = Collect<int>(storage);
EXPECT_THAT(actualAfter, testing::UnorderedElementsAreArray(expectedAfter));
}
TEST(ObjectFactoryStorageTest, EraseWhileConcurrentPublish) {
ObjectFactoryStorageRegular storage;
constexpr int kStartCount = 50;
constexpr int kThreadCount = kDefaultThreadCount;
std::vector<int> expectedAfter;
ObjectFactoryStorageRegular::Producer producer(storage);
for (int i = 0; i < kStartCount; ++i) {
if (i % 2 == 0) {
expectedAfter.push_back(i);
}
producer.Insert<int>(i);
}
producer.Publish();
std::atomic<bool> canStart(false);
std::atomic<int> readyCount(0);
std::atomic<int> startedCount(0);
std::vector<std::thread> threads;
for (int i = 0; i < kThreadCount; ++i) {
int j = i + kStartCount;
expectedAfter.push_back(j);
threads.emplace_back([j, &storage, &canStart, &startedCount, &readyCount]() {
ObjectFactoryStorageRegular::Producer producer(storage);
producer.Insert<int>(j);
++readyCount;
while (!canStart) {
}
++startedCount;
producer.Publish();
});
}
{
auto iter = storage.Iter();
while (readyCount < kThreadCount) {
}
canStart = true;
while (startedCount < kThreadCount) {
}
for (auto it = iter.begin(); it != iter.end();) {
if (it->Data<int>() % 2 != 0) {
iter.EraseAndAdvance(it);
} else {
++it;
}
}
}
for (auto& t : threads) {
t.join();
}
auto actual = Collect<int>(storage);
EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expectedAfter));
}
using mm::ObjectFactory;
namespace {
std::unique_ptr<TypeInfo> MakeObjectTypeInfo(int32_t size) {
auto typeInfo = std_support::make_unique<TypeInfo>();
typeInfo->typeInfo_ = typeInfo.get();
typeInfo->instanceSize_ = size;
return typeInfo;
}
std::unique_ptr<TypeInfo> MakeArrayTypeInfo(int32_t elementSize) {
auto typeInfo = std_support::make_unique<TypeInfo>();
typeInfo->typeInfo_ = typeInfo.get();
typeInfo->instanceSize_ = -elementSize;
return typeInfo;
}
} // namespace
TEST(ObjectFactoryTest, CreateObject) {
auto typeInfo = MakeObjectTypeInfo(24);
ObjectFactory objectFactory;
ObjectFactory::ThreadQueue threadQueue(objectFactory);
auto* object = threadQueue.CreateObject(typeInfo.get());
threadQueue.Publish();
auto iter = objectFactory.Iter();
auto it = iter.begin();
EXPECT_FALSE(it.IsArray());
EXPECT_THAT(it.GetObjHeader(), object);
++it;
EXPECT_THAT(it, iter.end());
}
TEST(ObjectFactoryTest, CreateArray) {
auto typeInfo = MakeArrayTypeInfo(24);
ObjectFactory objectFactory;
ObjectFactory::ThreadQueue threadQueue(objectFactory);
auto* array = threadQueue.CreateArray(typeInfo.get(), 3);
threadQueue.Publish();
auto iter = objectFactory.Iter();
auto it = iter.begin();
EXPECT_TRUE(it.IsArray());
EXPECT_THAT(it.GetArrayHeader(), array);
++it;
EXPECT_THAT(it, iter.end());
}
TEST(ObjectFactoryTest, Erase) {
auto objectTypeInfo = MakeObjectTypeInfo(24);
auto arrayTypeInfo = MakeArrayTypeInfo(24);
ObjectFactory objectFactory;
ObjectFactory::ThreadQueue threadQueue(objectFactory);
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.EraseAndAdvance(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);
}
}
TEST(ObjectFactoryTest, ConcurrentPublish) {
auto typeInfo = MakeObjectTypeInfo(24);
ObjectFactory objectFactory;
constexpr int kThreadCount = kDefaultThreadCount;
std::atomic<bool> canStart(false);
std::atomic<int> readyCount(0);
std::vector<std::thread> threads;
std::mutex expectedMutex;
std::vector<ObjHeader*> expected;
for (int i = 0; i < kThreadCount; ++i) {
threads.emplace_back([&typeInfo, &objectFactory, &canStart, &readyCount, &expected, &expectedMutex]() {
ObjectFactory::ThreadQueue threadQueue(objectFactory);
auto* object = threadQueue.CreateObject(typeInfo.get());
{
std::lock_guard<std::mutex> guard(expectedMutex);
expected.push_back(object);
}
++readyCount;
while (!canStart) {
}
threadQueue.Publish();
});
}
while (readyCount < kThreadCount) {
}
canStart = true;
for (auto& t : threads) {
t.join();
}
auto iter = objectFactory.Iter();
std::vector<ObjHeader*> actual;
for (auto it = iter.begin(); it != iter.end(); ++it) {
actual.push_back(it.GetObjHeader());
}
EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected));
}
@@ -15,44 +15,8 @@ ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj) {
TODO();
}
ObjHeader** ObjHeader::GetWeakCounterLocation() {
TODO();
}
#ifdef KONAN_OBJC_INTEROP
void* ObjHeader::GetAssociatedObject() {
TODO();
}
void** ObjHeader::GetAssociatedObjectLocation() {
TODO();
}
void ObjHeader::SetAssociatedObject(void* obj) {
TODO();
}
#endif // KONAN_OBJC_INTEROP
static MetaObjHeader* createMetaObject(TypeInfo** location) {
TODO();
}
static void destroyMetaObject(TypeInfo** location) {
TODO();
}
extern "C" {
RUNTIME_NOTHROW OBJ_GETTER(AllocInstance, const TypeInfo* type_info) {
TODO();
}
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements) {
TODO();
}
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
TODO();
}
@@ -9,6 +9,7 @@
#include <atomic>
#include <pthread.h>
#include "ObjectFactory.hpp"
#include "GlobalsRegistry.hpp"
#include "StableRefRegistry.hpp"
#include "ThreadLocalStorage.hpp"
@@ -26,7 +27,8 @@ public:
threadId_(threadId),
globalsThreadQueue_(GlobalsRegistry::Instance()),
stableRefThreadQueue_(StableRefRegistry::Instance()),
state_(ThreadState::kRunnable) {}
state_(ThreadState::kRunnable),
objectFactoryThreadQueue_(ObjectFactory::Instance()) {}
~ThreadData() = default;
@@ -42,12 +44,15 @@ public:
ThreadState setState(ThreadState state) noexcept { return state_.exchange(state); }
ObjectFactory::ThreadQueue& objectFactoryThreadQueue() noexcept { return objectFactoryThreadQueue_; }
private:
const pthread_t threadId_;
GlobalsRegistry::ThreadQueue globalsThreadQueue_;
ThreadLocalStorage tls_;
StableRefRegistry::ThreadQueue stableRefThreadQueue_;
std::atomic<ThreadState> state_;
ObjectFactory::ThreadQueue objectFactoryThreadQueue_;
};
} // namespace mm