Fixed coroutines for wasm
Replaced llvm indirectBr instruction with switch instruction.
This commit is contained in:
+2
@@ -46,6 +46,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
internal val targetManager = TargetManager(
|
internal val targetManager = TargetManager(
|
||||||
configuration.get(KonanConfigKeys.TARGET))
|
configuration.get(KonanConfigKeys.TARGET))
|
||||||
|
|
||||||
|
val indirectBranchesAreAllowed = targetManager.target != KonanTarget.WASM32
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val target = targetManager.target
|
val target = targetManager.target
|
||||||
if (!target.enabled) {
|
if (!target.enabled) {
|
||||||
|
|||||||
+8
@@ -461,6 +461,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
currentPositionHolder.setAfterTerminator()
|
currentPositionHolder.setAfterTerminator()
|
||||||
return indirectBr
|
return indirectBr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun switch(value: LLVMValueRef, cases: Collection<Pair<LLVMValueRef, LLVMBasicBlockRef>>, elseBB: LLVMBasicBlockRef): LLVMValueRef? {
|
||||||
|
val switch = LLVMBuildSwitch(builder, value, elseBB, cases.size)
|
||||||
|
cases.forEach { LLVMAddCase(switch, it.first, it.second) }
|
||||||
|
currentPositionHolder.setAfterTerminator()
|
||||||
|
return switch
|
||||||
|
}
|
||||||
|
|
||||||
fun resetDebugLocation() {
|
fun resetDebugLocation() {
|
||||||
if (!context.shouldContainDebugInfo()) return
|
if (!context.shouldContainDebugInfo()) return
|
||||||
if (!currentPositionHolder.isAfterTerminator)
|
if (!currentPositionHolder.isAfterTerminator)
|
||||||
|
|||||||
+24
-8
@@ -189,7 +189,7 @@ internal interface CodeContext {
|
|||||||
*/
|
*/
|
||||||
fun classScope(): CodeContext?
|
fun classScope(): CodeContext?
|
||||||
|
|
||||||
fun addResumePoint(bbLabel: LLVMBasicBlockRef)
|
fun addResumePoint(bbLabel: LLVMBasicBlockRef): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -1747,8 +1747,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private inner class SuspendableExpressionScope(val resumePoints: MutableList<LLVMBasicBlockRef>) : InnerScopeImpl() {
|
private inner class SuspendableExpressionScope(val resumePoints: MutableList<LLVMBasicBlockRef>) : InnerScopeImpl() {
|
||||||
override fun addResumePoint(bbLabel: LLVMBasicBlockRef) {
|
override fun addResumePoint(bbLabel: LLVMBasicBlockRef): Int {
|
||||||
|
val result = resumePoints.size
|
||||||
resumePoints.add(bbLabel)
|
resumePoints.add(bbLabel)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1765,26 +1767,40 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
val result = evaluateExpression(expression.result)
|
val result = evaluateExpression(expression.result)
|
||||||
|
|
||||||
functionGenerationContext.appendingTo(bbDispatch) {
|
functionGenerationContext.appendingTo(bbDispatch) {
|
||||||
functionGenerationContext.indirectBr(suspensionPointId, resumePoints)
|
if (context.config.indirectBranchesAreAllowed)
|
||||||
|
functionGenerationContext.indirectBr(suspensionPointId, resumePoints)
|
||||||
|
else {
|
||||||
|
val bbElse = functionGenerationContext.basicBlock("else", null) {
|
||||||
|
functionGenerationContext.unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
val cases = resumePoints.withIndex().map { Int32(it.index + 1).llvm to it.value }
|
||||||
|
functionGenerationContext.switch(functionGenerationContext.ptrToInt(suspensionPointId, int32Type), cases, bbElse)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SuspensionPointScope(val suspensionPointId: VariableDescriptor,
|
private inner class SuspensionPointScope(val suspensionPointId: VariableDescriptor,
|
||||||
val bbResume: LLVMBasicBlockRef): InnerScopeImpl() {
|
val bbResume: LLVMBasicBlockRef,
|
||||||
|
val bbResumeId: Int): InnerScopeImpl() {
|
||||||
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
||||||
if (descriptor == suspensionPointId)
|
if (descriptor == suspensionPointId) {
|
||||||
return functionGenerationContext.blockAddress(bbResume)
|
return if (context.config.indirectBranchesAreAllowed)
|
||||||
|
functionGenerationContext.blockAddress(bbResume)
|
||||||
|
else
|
||||||
|
functionGenerationContext.intToPtr(Int32(bbResumeId + 1).llvm, int8TypePtr)
|
||||||
|
}
|
||||||
return super.genGetValue(descriptor)
|
return super.genGetValue(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun evaluateSuspensionPoint(expression: IrSuspensionPoint): LLVMValueRef {
|
private fun evaluateSuspensionPoint(expression: IrSuspensionPoint): LLVMValueRef {
|
||||||
val bbResume = functionGenerationContext.basicBlock("resume", expression.resumeResult.startLocation)
|
val bbResume = functionGenerationContext.basicBlock("resume", expression.resumeResult.startLocation)
|
||||||
currentCodeContext.addResumePoint(bbResume)
|
val id = currentCodeContext.addResumePoint(bbResume)
|
||||||
|
|
||||||
using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume)) {
|
using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume, id)) {
|
||||||
continuationBlock(expression.type, expression.result.startLocation).run {
|
continuationBlock(expression.type, expression.result.startLocation).run {
|
||||||
val normalResult = evaluateExpression(expression.result)
|
val normalResult = evaluateExpression(expression.result)
|
||||||
jump(this, normalResult)
|
jump(this, normalResult)
|
||||||
|
|||||||
@@ -350,7 +350,6 @@ task codegen_controlflow_for_loops_nested(type: RunKonanTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task codegen_controlflow_for_loops_coroutines(type: RunKonanTest) {
|
task codegen_controlflow_for_loops_coroutines(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
source = "codegen/controlflow/for_loops_coroutines.kt"
|
source = "codegen/controlflow/for_loops_coroutines.kt"
|
||||||
goldValue = "before: 0 after: 0\n" +
|
goldValue = "before: 0 after: 0\n" +
|
||||||
"before: 2 after: 2\n" +
|
"before: 2 after: 2\n" +
|
||||||
@@ -938,151 +937,126 @@ task kclass1(type: RunKonanTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_simple(type: RunKonanTest) {
|
task coroutines_simple(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "42\n"
|
goldValue = "42\n"
|
||||||
source = "codegen/coroutines/simple.kt"
|
source = "codegen/coroutines/simple.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_degenerate1(type: RunKonanTest) {
|
task coroutines_degenerate1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\n"
|
goldValue = "s1\n"
|
||||||
source = "codegen/coroutines/degenerate1.kt"
|
source = "codegen/coroutines/degenerate1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_degenerate2(type: RunKonanTest) {
|
task coroutines_degenerate2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s2\ns1\n"
|
goldValue = "s2\ns1\n"
|
||||||
source = "codegen/coroutines/degenerate2.kt"
|
source = "codegen/coroutines/degenerate2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_withReceiver(type: RunKonanTest) {
|
task coroutines_withReceiver(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "42\n"
|
goldValue = "42\n"
|
||||||
source = "codegen/coroutines/withReceiver.kt"
|
source = "codegen/coroutines/withReceiver.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_correctOrder1(type: RunKonanTest) {
|
task coroutines_correctOrder1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\nf2\n160\n"
|
goldValue = "f1\ns1\nf2\n160\n"
|
||||||
source = "codegen/coroutines/correctOrder1.kt"
|
source = "codegen/coroutines/correctOrder1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_if1(type: RunKonanTest) {
|
task coroutines_controlFlow_if1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\nf3\n84\n"
|
goldValue = "f1\ns1\nf3\n84\n"
|
||||||
source = "codegen/coroutines/controlFlow_if1.kt"
|
source = "codegen/coroutines/controlFlow_if1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_if2(type: RunKonanTest) {
|
task coroutines_controlFlow_if2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\nf2\n43\n"
|
goldValue = "f1\ns1\nf2\n43\n"
|
||||||
source = "codegen/coroutines/controlFlow_if2.kt"
|
source = "codegen/coroutines/controlFlow_if2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally1(type: RunKonanTest) {
|
task coroutines_controlFlow_finally1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\n117\n"
|
goldValue = "f1\ns1\n117\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally1.kt"
|
source = "codegen/coroutines/controlFlow_finally1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally2(type: RunKonanTest) {
|
task coroutines_controlFlow_finally2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\n117\n"
|
goldValue = "f1\ns1\n117\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally2.kt"
|
source = "codegen/coroutines/controlFlow_finally2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally3(type: RunKonanTest) {
|
task coroutines_controlFlow_finally3(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\n117\n"
|
goldValue = "f1\ns1\n117\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally3.kt"
|
source = "codegen/coroutines/controlFlow_finally3.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally4(type: RunKonanTest) {
|
task coroutines_controlFlow_finally4(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\nfinally\n42\n"
|
goldValue = "s1\nfinally\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally4.kt"
|
source = "codegen/coroutines/controlFlow_finally4.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally5(type: RunKonanTest) {
|
task coroutines_controlFlow_finally5(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\nf2\nfinally\n1\n"
|
goldValue = "s1\nf2\nfinally\n1\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally5.kt"
|
source = "codegen/coroutines/controlFlow_finally5.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally6(type: RunKonanTest) {
|
task coroutines_controlFlow_finally6(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\nfinally\nerror\n0\n"
|
goldValue = "s1\nfinally\nerror\n0\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally6.kt"
|
source = "codegen/coroutines/controlFlow_finally6.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_finally7(type: RunKonanTest) {
|
task coroutines_controlFlow_finally7(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n"
|
goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_finally7.kt"
|
source = "codegen/coroutines/controlFlow_finally7.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_inline1(type: RunKonanTest) {
|
task coroutines_controlFlow_inline1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "42\n"
|
goldValue = "42\n"
|
||||||
source = "codegen/coroutines/controlFlow_inline1.kt"
|
source = "codegen/coroutines/controlFlow_inline1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_inline2(type: RunKonanTest) {
|
task coroutines_controlFlow_inline2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\n42\n"
|
goldValue = "s1\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_inline2.kt"
|
source = "codegen/coroutines/controlFlow_inline2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_inline3(type: RunKonanTest) {
|
task coroutines_controlFlow_inline3(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "f1\ns1\n42\n"
|
goldValue = "f1\ns1\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_inline3.kt"
|
source = "codegen/coroutines/controlFlow_inline3.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_tryCatch1(type: RunKonanTest) {
|
task coroutines_controlFlow_tryCatch1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\n42\n"
|
goldValue = "s1\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_tryCatch1.kt"
|
source = "codegen/coroutines/controlFlow_tryCatch1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_tryCatch2(type: RunKonanTest) {
|
task coroutines_controlFlow_tryCatch2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s1\n42\n"
|
goldValue = "s1\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_tryCatch2.kt"
|
source = "codegen/coroutines/controlFlow_tryCatch2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_tryCatch3(type: RunKonanTest) {
|
task coroutines_controlFlow_tryCatch3(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s2\nf2\n1\n"
|
goldValue = "s2\nf2\n1\n"
|
||||||
source = "codegen/coroutines/controlFlow_tryCatch3.kt"
|
source = "codegen/coroutines/controlFlow_tryCatch3.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_tryCatch4(type: RunKonanTest) {
|
task coroutines_controlFlow_tryCatch4(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s2\nf2\n1\n"
|
goldValue = "s2\nf2\n1\n"
|
||||||
source = "codegen/coroutines/controlFlow_tryCatch4.kt"
|
source = "codegen/coroutines/controlFlow_tryCatch4.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_tryCatch5(type: RunKonanTest) {
|
task coroutines_controlFlow_tryCatch5(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s2\ns1\nError\n42\n"
|
goldValue = "s2\ns1\nError\n42\n"
|
||||||
source = "codegen/coroutines/controlFlow_tryCatch5.kt"
|
source = "codegen/coroutines/controlFlow_tryCatch5.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_while1(type: RunKonanTest) {
|
task coroutines_controlFlow_while1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s3\ns3\ns3\ns3\n3\n"
|
goldValue = "s3\ns3\ns3\ns3\n3\n"
|
||||||
source = "codegen/coroutines/controlFlow_while1.kt"
|
source = "codegen/coroutines/controlFlow_while1.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_controlFlow_while2(type: RunKonanTest) {
|
task coroutines_controlFlow_while2(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "s3\ns3\ns3\n3\n"
|
goldValue = "s3\ns3\ns3\n3\n"
|
||||||
source = "codegen/coroutines/controlFlow_while2.kt"
|
source = "codegen/coroutines/controlFlow_while2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
task coroutines_returnsUnit1(type: RunKonanTest) {
|
task coroutines_returnsUnit1(type: RunKonanTest) {
|
||||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
|
||||||
goldValue = "117\ns1\n0\n"
|
goldValue = "117\ns1\n0\n"
|
||||||
source = "codegen/coroutines/returnsUnit1.kt"
|
source = "codegen/coroutines/returnsUnit1.kt"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user