[K/N] Changed condition for adding EnterFrame/LeaveFrame
This commit is contained in:
+44
-41
@@ -475,10 +475,12 @@ internal abstract class FunctionGenerationContext(
|
|||||||
private val entryBb = basicBlockInFunction("entry", startLocation)
|
private val entryBb = basicBlockInFunction("entry", startLocation)
|
||||||
protected val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation)
|
protected val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation)
|
||||||
|
|
||||||
// Functions that can be exported and called not only from Kotlin code should have `LeaveFrame`
|
// Functions that can be exported and called not only from Kotlin code should have cleanup_landingpad and `LeaveFrame`
|
||||||
// because there is no guarantee of catching Kotlin exception in Kotlin code.
|
// because there is no guarantee of catching Kotlin exception in Kotlin code.
|
||||||
protected open val needLeaveFrame: Boolean
|
protected open val needCleanupLandingpadAndLeaveFrame: Boolean
|
||||||
get() = irFunction?.annotations?.hasAnnotation(RuntimeNames.exportForCppRuntime) == true
|
get() = irFunction?.annotations?.hasAnnotation(RuntimeNames.exportForCppRuntime) == true || // Exported to foreign code
|
||||||
|
(!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) ||
|
||||||
|
(context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable)
|
||||||
|
|
||||||
private var setCurrentFrameIsCalled: Boolean = false
|
private var setCurrentFrameIsCalled: Boolean = false
|
||||||
|
|
||||||
@@ -908,7 +910,11 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
call(context.llvm.setCurrentFrameFunction, listOf(slotsPhi!!))
|
call(context.llvm.setCurrentFrameFunction, listOf(slotsPhi!!))
|
||||||
setCurrentFrameIsCalled = true
|
setCurrentFrameIsCalled = true
|
||||||
//handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
|
if (context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||||
|
if (!forbidRuntime) {
|
||||||
|
call(context.llvm.Kotlin_mm_safePointExceptionUnwind, emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return landingpad
|
return landingpad
|
||||||
}
|
}
|
||||||
@@ -1426,14 +1432,14 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun epilogue() {
|
internal fun epilogue() {
|
||||||
val needLeaveFrame = this.needLeaveFrame
|
val needCleanupLandingpadAndLeaveFrame = this.needCleanupLandingpadAndLeaveFrame
|
||||||
|
|
||||||
appendingTo(prologueBb) {
|
appendingTo(prologueBb) {
|
||||||
val slots = if (needSlotsPhi || needLeaveFrame)
|
val slots = if (needSlotsPhi || needCleanupLandingpadAndLeaveFrame)
|
||||||
LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!!
|
LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!!
|
||||||
else
|
else
|
||||||
kNullObjHeaderPtrPtr
|
kNullObjHeaderPtrPtr
|
||||||
if (needSlots || needLeaveFrame) {
|
if (needSlots || needCleanupLandingpadAndLeaveFrame) {
|
||||||
check(!forbidRuntime) { "Attempt to start a frame where runtime usage is forbidden" }
|
check(!forbidRuntime) { "Attempt to start a frame where runtime usage is forbidden" }
|
||||||
// Zero-init slots.
|
// Zero-init slots.
|
||||||
val slotsMem = bitcast(kInt8Ptr, slots)
|
val slotsMem = bitcast(kInt8Ptr, slots)
|
||||||
@@ -1461,38 +1467,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
br(stackLocalsInitBb)
|
br(stackLocalsInitBb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needCleanupLandingpadAndLeaveFrame) {
|
||||||
appendingTo(stackLocalsInitBb) {
|
|
||||||
/**
|
|
||||||
* Function calls need to have !dbg, otherwise llvm rejects full module debug information
|
|
||||||
* On the other hand, we don't want prologue to have debug info, because it can lead to debugger stops in
|
|
||||||
* places with inconsistent stack layout. So we setup debug info only for this part of bb.
|
|
||||||
*/
|
|
||||||
startLocation?.let { debugLocation(it, it) }
|
|
||||||
val needStateSwitch = context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable
|
|
||||||
if (needsRuntimeInit || needStateSwitch) {
|
|
||||||
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
|
|
||||||
call(context.llvm.initRuntimeIfNeeded, emptyList())
|
|
||||||
}
|
|
||||||
if (needStateSwitch) {
|
|
||||||
switchThreadState(Runnable)
|
|
||||||
}
|
|
||||||
if (needSlots || needLeaveFrame) {
|
|
||||||
call(context.llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
|
||||||
} else {
|
|
||||||
check(!setCurrentFrameIsCalled)
|
|
||||||
}
|
|
||||||
resetDebugLocation()
|
|
||||||
br(entryBb)
|
|
||||||
}
|
|
||||||
|
|
||||||
processReturns()
|
|
||||||
|
|
||||||
val shouldHaveCleanupLandingpad = needLeaveFrame ||
|
|
||||||
(!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) ||
|
|
||||||
(context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable)
|
|
||||||
|
|
||||||
if (shouldHaveCleanupLandingpad) {
|
|
||||||
appendingTo(cleanupLandingpad) {
|
appendingTo(cleanupLandingpad) {
|
||||||
val landingpad = gxxLandingpad(numClauses = 0)
|
val landingpad = gxxLandingpad(numClauses = 0)
|
||||||
LLVMSetCleanup(landingpad, 1)
|
LLVMSetCleanup(landingpad, 1)
|
||||||
@@ -1529,7 +1504,35 @@ internal abstract class FunctionGenerationContext(
|
|||||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
|
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
|
||||||
LLVMBuildResume(builder, landingpad)
|
LLVMBuildResume(builder, landingpad)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
appendingTo(stackLocalsInitBb) {
|
||||||
|
/**
|
||||||
|
* Function calls need to have !dbg, otherwise llvm rejects full module debug information
|
||||||
|
* On the other hand, we don't want prologue to have debug info, because it can lead to debugger stops in
|
||||||
|
* places with inconsistent stack layout. So we setup debug info only for this part of bb.
|
||||||
|
*/
|
||||||
|
startLocation?.let { debugLocation(it, it) }
|
||||||
|
val needStateSwitch = context.memoryModel == MemoryModel.EXPERIMENTAL && switchToRunnable
|
||||||
|
if (needsRuntimeInit || needStateSwitch) {
|
||||||
|
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
|
||||||
|
call(context.llvm.initRuntimeIfNeeded, emptyList())
|
||||||
|
}
|
||||||
|
if (needStateSwitch) {
|
||||||
|
switchThreadState(Runnable)
|
||||||
|
}
|
||||||
|
if (needSlots || needCleanupLandingpadAndLeaveFrame) {
|
||||||
|
call(context.llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
||||||
|
} else {
|
||||||
|
check(!setCurrentFrameIsCalled)
|
||||||
|
}
|
||||||
|
resetDebugLocation()
|
||||||
|
br(entryBb)
|
||||||
|
}
|
||||||
|
|
||||||
|
processReturns()
|
||||||
|
|
||||||
|
if (!needCleanupLandingpadAndLeaveFrame) {
|
||||||
// Replace invokes with calls and branches.
|
// Replace invokes with calls and branches.
|
||||||
invokeInstructions.forEach { functionInvokeInfo ->
|
invokeInstructions.forEach { functionInvokeInfo ->
|
||||||
positionBefore(functionInvokeInfo.invokeInstruction)
|
positionBefore(functionInvokeInfo.invokeInstruction)
|
||||||
@@ -1715,7 +1718,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun releaseVars() {
|
private fun releaseVars() {
|
||||||
if (needLeaveFrame || needSlots) {
|
if (needCleanupLandingpadAndLeaveFrame || needSlots) {
|
||||||
check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" }
|
check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" }
|
||||||
call(context.llvm.leaveFrameFunction,
|
call(context.llvm.leaveFrameFunction,
|
||||||
listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ internal class ObjCExportFunctionGenerationContext(
|
|||||||
|
|
||||||
// All generated bridges by ObjCExport should have `LeaveFrame`
|
// All generated bridges by ObjCExport should have `LeaveFrame`
|
||||||
// because there is no guarantee of catching Kotlin exception in Kotlin code.
|
// because there is no guarantee of catching Kotlin exception in Kotlin code.
|
||||||
override val needLeaveFrame: Boolean
|
override val needCleanupLandingpadAndLeaveFrame: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
// Note: we could generate single "epilogue" and make all [ret]s just branch to it (like [DefaultFunctionGenerationContext]),
|
// Note: we could generate single "epilogue" and make all [ret]s just branch to it (like [DefaultFunctionGenerationContext]),
|
||||||
|
|||||||
Reference in New Issue
Block a user