[K/N] Fix cleaning stack-local primitive array
^KT-55984
This commit is contained in:
committed by
Space Team
parent
9f850c1179
commit
2843c0ad1e
+6
@@ -1173,6 +1173,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
fun box() : String{
|
||||
for (iter in 0 until 10) {
|
||||
val destination = ByteArray(8)
|
||||
if (destination[0] != 0.toByte()) return "FAIL"
|
||||
destination[0] = 1
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -1065,6 +1065,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+6
@@ -1173,6 +1173,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+5
@@ -934,6 +934,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt594.kt");
|
||||
|
||||
+6
@@ -549,6 +549,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
Generated
+6
@@ -331,6 +331,12 @@ public class JsLegacyPrimitiveArraysBoxTestGenerated extends AbstractJsLegacyPri
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+6
@@ -603,6 +603,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+6
@@ -603,6 +603,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+6
@@ -603,6 +603,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+5
@@ -549,6 +549,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt594.kt");
|
||||
|
||||
+38
-16
@@ -238,20 +238,35 @@ private inline fun <T : FunctionGenerationContext> generateFunctionBody(
|
||||
internal data class LocationInfoRange(var start: LocationInfo, var end: LocationInfo?)
|
||||
|
||||
internal interface StackLocalsManager {
|
||||
fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef
|
||||
fun alloc(irClass: IrClass): LLVMValueRef
|
||||
|
||||
fun allocArray(irClass: IrClass, count: LLVMValueRef): LLVMValueRef
|
||||
|
||||
fun clean(refsOnly: Boolean)
|
||||
|
||||
fun enterScope()
|
||||
fun exitScope()
|
||||
}
|
||||
|
||||
internal class StackLocalsManagerImpl(
|
||||
val functionGenerationContext: FunctionGenerationContext,
|
||||
val bbInitStackLocals: LLVMBasicBlockRef
|
||||
) : StackLocalsManager {
|
||||
private class StackLocal(val isArray: Boolean, val irClass: IrClass,
|
||||
val bodyPtr: LLVMValueRef, val objHeaderPtr: LLVMValueRef,
|
||||
val gcRootSetSlot: LLVMValueRef?)
|
||||
private var scopeDepth = 0
|
||||
override fun enterScope() { scopeDepth++ }
|
||||
override fun exitScope() { scopeDepth-- }
|
||||
private fun isRootScope() = scopeDepth == 0
|
||||
|
||||
private class StackLocal(
|
||||
val arraySize: Int?,
|
||||
val irClass: IrClass,
|
||||
val stackAllocationPtr: LLVMValueRef,
|
||||
val objHeaderPtr: LLVMValueRef,
|
||||
val gcRootSetSlot: LLVMValueRef?
|
||||
) {
|
||||
val isArray
|
||||
get() = arraySize != null
|
||||
}
|
||||
|
||||
private val stackLocals = mutableListOf<StackLocal>()
|
||||
|
||||
@@ -260,7 +275,7 @@ internal class StackLocalsManagerImpl(
|
||||
private fun FunctionGenerationContext.createRootSetSlot() =
|
||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL) alloca(kObjHeaderPtr) else null
|
||||
|
||||
override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) {
|
||||
override fun alloc(irClass: IrClass): LLVMValueRef = with(functionGenerationContext) {
|
||||
val classInfo = llvmDeclarations.forClass(irClass)
|
||||
val type = classInfo.bodyType
|
||||
val stackLocal = appendingTo(bbInitStackLocals) {
|
||||
@@ -273,12 +288,13 @@ internal class StackLocalsManagerImpl(
|
||||
val typeInfo = codegen.typeInfoForAllocation(irClass)
|
||||
setTypeInfoForLocalObject(objectHeader, typeInfo)
|
||||
val gcRootSetSlot = createRootSetSlot()
|
||||
StackLocal(false, irClass, stackSlot, objectHeader, gcRootSetSlot)
|
||||
StackLocal(null, irClass, stackSlot, objectHeader, gcRootSetSlot)
|
||||
}
|
||||
|
||||
stackLocals += stackLocal
|
||||
if (cleanFieldsExplicitly)
|
||||
if (!isRootScope()) {
|
||||
clean(stackLocal, false)
|
||||
}
|
||||
if (stackLocal.gcRootSetSlot != null) {
|
||||
storeStackRef(stackLocal.objHeaderPtr, stackLocal.gcRootSetSlot)
|
||||
}
|
||||
@@ -332,11 +348,14 @@ internal class StackLocalsManagerImpl(
|
||||
constCount * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[irClass.symbol]).toInt() / 8
|
||||
)
|
||||
val gcRootSetSlot = createRootSetSlot()
|
||||
StackLocal(true, irClass, arraySlot, arrayHeaderSlot, gcRootSetSlot)
|
||||
StackLocal(constCount, irClass, arraySlot, arrayHeaderSlot, gcRootSetSlot)
|
||||
}
|
||||
|
||||
stackLocals += stackLocal
|
||||
val result = bitcast(kObjHeaderPtr, stackLocal.objHeaderPtr)
|
||||
if (!isRootScope()) {
|
||||
clean(stackLocal, false)
|
||||
}
|
||||
if (stackLocal.gcRootSetSlot != null) {
|
||||
storeStackRef(result, stackLocal.gcRootSetSlot)
|
||||
}
|
||||
@@ -347,8 +366,14 @@ internal class StackLocalsManagerImpl(
|
||||
|
||||
private fun clean(stackLocal: StackLocal, refsOnly: Boolean) = with(functionGenerationContext) {
|
||||
if (stackLocal.isArray) {
|
||||
if (stackLocal.irClass.symbol == context.ir.symbols.array)
|
||||
if (stackLocal.irClass.symbol == context.ir.symbols.array) {
|
||||
call(llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
|
||||
} else if (!refsOnly) {
|
||||
memset(bitcast(llvm.int8PtrType, structGep(stackLocal.stackAllocationPtr, 1, "arrayBody")),
|
||||
0,
|
||||
stackLocal.arraySize!! * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[stackLocal.irClass.symbol]).toInt() / 8
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val info = llvmDeclarations.forClass(stackLocal.irClass)
|
||||
val type = info.bodyType
|
||||
@@ -356,7 +381,7 @@ internal class StackLocalsManagerImpl(
|
||||
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
|
||||
|
||||
if (isObjectType(fieldType)) {
|
||||
val fieldPtr = LLVMBuildStructGEP(builder, stackLocal.bodyPtr, fieldIndex, "")!!
|
||||
val fieldPtr = LLVMBuildStructGEP(builder, stackLocal.stackAllocationPtr, fieldIndex, "")!!
|
||||
if (refsOnly)
|
||||
storeHeapRef(kNullObjHeaderPtr, fieldPtr)
|
||||
else
|
||||
@@ -365,7 +390,7 @@ internal class StackLocalsManagerImpl(
|
||||
}
|
||||
|
||||
if (!refsOnly) {
|
||||
val bodyPtr = ptrToInt(stackLocal.bodyPtr, codegen.intPtrType)
|
||||
val bodyPtr = ptrToInt(stackLocal.stackAllocationPtr, codegen.intPtrType)
|
||||
val bodySize = LLVMSizeOfTypeInBits(codegen.llvmTargetData, type).toInt() / 8
|
||||
val serviceInfoSize = runtime.pointerSize
|
||||
val serviceInfoSizeLlvm = LLVMConstInt(codegen.intPtrType, serviceInfoSize.toLong(), 1)!!
|
||||
@@ -778,12 +803,9 @@ internal abstract class FunctionGenerationContext(
|
||||
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime, resultSlot: LLVMValueRef?) : LLVMValueRef =
|
||||
call(llvm.allocInstanceFunction, listOf(typeInfo), lifetime, resultSlot = resultSlot)
|
||||
|
||||
fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager, resultSlot: LLVMValueRef?) =
|
||||
fun allocInstance(irClass: IrClass, lifetime: Lifetime, resultSlot: LLVMValueRef?) =
|
||||
if (lifetime == Lifetime.STACK)
|
||||
stackLocalsManager.alloc(irClass,
|
||||
// In case the allocation is not from the root scope, fields must be cleaned up explicitly,
|
||||
// as the object might be being reused.
|
||||
cleanFieldsExplicitly = stackLocalsManager != this.stackLocalsManager)
|
||||
stackLocalsManager.alloc(irClass)
|
||||
else
|
||||
allocInstance(codegen.typeInfoForAllocation(irClass), lifetime, resultSlot)
|
||||
|
||||
|
||||
+1
-3
@@ -117,8 +117,6 @@ internal interface IntrinsicGeneratorEnvironment {
|
||||
|
||||
val exceptionHandler: ExceptionHandler
|
||||
|
||||
val stackLocalsManager: StackLocalsManager
|
||||
|
||||
fun calculateLifetime(element: IrElement): Lifetime
|
||||
|
||||
fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime,
|
||||
@@ -418,7 +416,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
|
||||
val enumClass = callSite.getTypeArgument(typeParameterT)!!
|
||||
val enumIrClass = enumClass.getClass()!!
|
||||
return allocInstance(enumIrClass, environment.calculateLifetime(callSite), environment.stackLocalsManager, resultSlot)
|
||||
return allocInstance(enumIrClass, environment.calculateLifetime(callSite), resultSlot)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetPointerSize(): LLVMValueRef =
|
||||
|
||||
+23
-16
@@ -130,8 +130,6 @@ private interface CodeContext {
|
||||
|
||||
val exceptionHandler: ExceptionHandler
|
||||
|
||||
val stackLocalsManager: StackLocalsManager
|
||||
|
||||
/**
|
||||
* Declares the variable.
|
||||
* @return index of declared variable.
|
||||
@@ -189,6 +187,16 @@ private interface CodeContext {
|
||||
* Returns [DIScopeOpaqueRef] instance for corresponding scope.
|
||||
*/
|
||||
fun scope(): DIScopeOpaqueRef?
|
||||
|
||||
/**
|
||||
* Called, when context is pushed on stack
|
||||
*/
|
||||
fun onEnter() {}
|
||||
|
||||
/**
|
||||
* Called, when context is removed from stack
|
||||
*/
|
||||
fun onExit() {}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -217,9 +225,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
override val exceptionHandler: ExceptionHandler
|
||||
get() = currentCodeContext.exceptionHandler
|
||||
|
||||
override val stackLocalsManager: StackLocalsManager
|
||||
get() = currentCodeContext.stackLocalsManager
|
||||
|
||||
override fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass?, resultSlot: LLVMValueRef?) =
|
||||
evaluateSimpleFunctionCall(function, args, resultLifetime, superClass, resultSlot)
|
||||
|
||||
@@ -256,8 +261,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
override val exceptionHandler get() = unsupported()
|
||||
|
||||
override val stackLocalsManager: StackLocalsManager get() = unsupported()
|
||||
|
||||
override fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?) = unsupported(variable)
|
||||
|
||||
override fun getDeclaredValue(value: IrValueDeclaration) = -1
|
||||
@@ -295,10 +298,12 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
val oldCodeContext = currentCodeContext
|
||||
if (codeContext != null) {
|
||||
currentCodeContext = codeContext
|
||||
codeContext.onEnter()
|
||||
}
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
codeContext?.onExit()
|
||||
currentCodeContext = oldCodeContext
|
||||
}
|
||||
}
|
||||
@@ -570,7 +575,16 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private inner class LoopScope(val loop: IrLoop) : InnerScopeImpl() {
|
||||
private open inner class StackLocalsScope() : InnerScopeImpl() {
|
||||
override fun onEnter() {
|
||||
functionGenerationContext.stackLocalsManager.enterScope()
|
||||
}
|
||||
override fun onExit() {
|
||||
functionGenerationContext.stackLocalsManager.exitScope()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class LoopScope(val loop: IrLoop) : StackLocalsScope() {
|
||||
val loopExit = functionGenerationContext.basicBlock("loop_exit", loop.endLocation)
|
||||
val loopCheck = functionGenerationContext.basicBlock("loop_check", loop.condition.startLocation)
|
||||
|
||||
@@ -587,9 +601,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
} else
|
||||
super.genContinue(destination)
|
||||
}
|
||||
|
||||
override val stackLocalsManager: StackLocalsManager =
|
||||
object : StackLocalsManager by functionGenerationContext.stackLocalsManager { }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -730,8 +741,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
override val exceptionHandler: ExceptionHandler
|
||||
get() = ExceptionHandler.Caller
|
||||
|
||||
override val stackLocalsManager get() = functionGenerationContext.stackLocalsManager
|
||||
|
||||
override fun functionScope(): CodeContext = this
|
||||
|
||||
|
||||
@@ -1326,7 +1335,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
functionGenerationContext.br(loopScope.loopCheck)
|
||||
functionGenerationContext.positionAtEnd(loopScope.loopExit)
|
||||
|
||||
}
|
||||
|
||||
assert(loop.type.isUnit())
|
||||
@@ -2490,8 +2498,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
constructedClass.isObjCClass() -> error("Call should've been lowered: ${callee.dump()}")
|
||||
|
||||
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee),
|
||||
currentCodeContext.stackLocalsManager, resultSlot = resultSlot)
|
||||
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee), resultSlot = resultSlot)
|
||||
}
|
||||
evaluateSimpleFunctionCall(callee.symbol.owner,
|
||||
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
|
||||
|
||||
+6
@@ -641,6 +641,12 @@ public class K2NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTes
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
+6
@@ -631,6 +631,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
||||
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt55984.kt")
|
||||
public void testKt55984() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/arrays/kt55984.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt594.kt")
|
||||
public void testKt594() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user