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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
+8
-18
@@ -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()!!
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -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 {
|
||||
|
||||
+4
-10
@@ -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")
|
||||
|
||||
+6
-15
@@ -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(
|
||||
|
||||
+2
-8
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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",
|
||||
|
||||
+6
-18
@@ -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
|
||||
}
|
||||
|
||||
+2
-8
@@ -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)
|
||||
|
||||
+8
-12
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -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)
|
||||
|
||||
+2
-2
@@ -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())
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+3
-9
@@ -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").
|
||||
|
||||
+6
-12
@@ -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
|
||||
|
||||
+2
-5
@@ -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
-23
@@ -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)
|
||||
|
||||
+5
-30
@@ -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) {
|
||||
|
||||
+6
-15
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -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 {
|
||||
|
||||
+18
-28
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-18
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+8
-19
@@ -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
|
||||
|
||||
+1
-5
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+16
-26
@@ -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())
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user