mirror of
https://github.com/fluencelabs/asmble
synced 2025-04-24 22:32:19 +00:00
Few unreachable/unwind fixes
This commit is contained in:
parent
e87b96752b
commit
004c0c4618
@ -454,28 +454,33 @@ open class FuncBuilder {
|
|||||||
java.lang.Double::class.invokeStatic("longBitsToDouble", Double::class, Long::class))
|
java.lang.Double::class.invokeStatic("longBitsToDouble", Double::class, Long::class))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyBr(ctx: FuncContext, fn: Func, i: Node.Instr.Br) =
|
fun popForBlockEscape(ctx: FuncContext, fn: Func, block: Func.Block) =
|
||||||
fn.blockAtDepth(i.relativeDepth).let { block ->
|
popUntilStackSize(ctx, fn, block, block.origStack.size + block.labelTypes.size, block.labelTypes.isNotEmpty())
|
||||||
// We have to pop all unnecessary values per the spec
|
|
||||||
val type = block.labelTypes.firstOrNull()
|
fun popUntilStackSize(
|
||||||
fun pop(fn: Func): Func {
|
ctx: FuncContext,
|
||||||
// Have to swap first if there is a type expected
|
fn: Func,
|
||||||
// Note, we check stack size because dead code is allowed to do some crazy
|
block: Func.Block,
|
||||||
// things.
|
untilStackSize: Int,
|
||||||
return (if (type != null && fn.stack.size > 1) fn.stackSwap(block) else fn).let { fn ->
|
keepLast: Boolean
|
||||||
fn.pop().let { (fn, poppedType) ->
|
): Func {
|
||||||
fn.addInsns(InsnNode(if (poppedType.stackSize == 2) Opcodes.POP2 else Opcodes.POP))
|
ctx.debug { "For block ${block.insn}, popping until stack size $untilStackSize, keeping last? $keepLast" }
|
||||||
}
|
// Just get the latest, don't actually pop...
|
||||||
|
val type = if (keepLast) fn.pop().second else null
|
||||||
|
return (0 until Math.max(0, fn.stack.size - untilStackSize)).fold(fn) { fn, _ ->
|
||||||
|
// Essentially swap and pop if they want to keep the latest
|
||||||
|
(if (type != null && fn.stack.size > 1) fn.stackSwap(block) else fn).let { fn ->
|
||||||
|
fn.pop(block).let { (fn, poppedType) ->
|
||||||
|
fn.addInsns(InsnNode(if (poppedType.stackSize == 2) Opcodes.POP2 else Opcodes.POP))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// How many do we have to pop to get back to expected block size
|
}
|
||||||
val currBlockStackSize = fn.stack.size - block.origStack.size
|
}
|
||||||
val needToPop = Math.max(0, if (type == null) currBlockStackSize else currBlockStackSize - 1)
|
|
||||||
ctx.debug {
|
fun applyBr(ctx: FuncContext, fn: Func, i: Node.Instr.Br) =
|
||||||
"Unconditional branch on ${block.insn}, curr stack ${fn.stack}, " +
|
fn.blockAtDepth(i.relativeDepth).let { block ->
|
||||||
" orig stack ${block.origStack}, need to pop $needToPop"
|
ctx.debug { "Unconditional branch on ${block.insn}, curr stack ${fn.stack}, orig stack ${block.origStack}" }
|
||||||
}
|
popForBlockEscape(ctx, fn, block).
|
||||||
(0 until needToPop).fold(fn) { fn, _ -> pop(fn) }.
|
|
||||||
popExpectingMulti(block.labelTypes, block).
|
popExpectingMulti(block.labelTypes, block).
|
||||||
addInsns(JumpInsnNode(Opcodes.GOTO, block.requiredLabel)).
|
addInsns(JumpInsnNode(Opcodes.GOTO, block.requiredLabel)).
|
||||||
markUnreachable()
|
markUnreachable()
|
||||||
@ -1162,20 +1167,25 @@ open class FuncBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyReturnInsn(ctx: FuncContext, fn: Func) = when (ctx.node.type.ret) {
|
fun applyReturnInsn(ctx: FuncContext, fn: Func): Func {
|
||||||
null ->
|
val block = fn.blockStack.first()
|
||||||
fn.addInsns(InsnNode(Opcodes.RETURN))
|
popForBlockEscape(ctx, fn, block).let { fn ->
|
||||||
Node.Type.Value.I32 ->
|
return when (ctx.node.type.ret) {
|
||||||
fn.popExpecting(Int::class.ref).addInsns(InsnNode(Opcodes.IRETURN))
|
null ->
|
||||||
Node.Type.Value.I64 ->
|
fn.addInsns(InsnNode(Opcodes.RETURN))
|
||||||
fn.popExpecting(Long::class.ref).addInsns(InsnNode(Opcodes.LRETURN))
|
Node.Type.Value.I32 ->
|
||||||
Node.Type.Value.F32 ->
|
fn.popExpecting(Int::class.ref, block).addInsns(InsnNode(Opcodes.IRETURN))
|
||||||
fn.popExpecting(Float::class.ref).addInsns(InsnNode(Opcodes.FRETURN))
|
Node.Type.Value.I64 ->
|
||||||
Node.Type.Value.F64 ->
|
fn.popExpecting(Long::class.ref, block).addInsns(InsnNode(Opcodes.LRETURN))
|
||||||
fn.popExpecting(Double::class.ref).addInsns(InsnNode(Opcodes.DRETURN))
|
Node.Type.Value.F32 ->
|
||||||
}.let { fn ->
|
fn.popExpecting(Float::class.ref, block).addInsns(InsnNode(Opcodes.FRETURN))
|
||||||
if (fn.stack.isNotEmpty()) throw CompileErr.UnusedStackOnReturn(fn.stack)
|
Node.Type.Value.F64 ->
|
||||||
fn.markUnreachable()
|
fn.popExpecting(Double::class.ref, block).addInsns(InsnNode(Opcodes.DRETURN))
|
||||||
|
}.let { fn ->
|
||||||
|
if (fn.stack.isNotEmpty()) throw CompileErr.UnusedStackOnReturn(fn.stack)
|
||||||
|
fn.markUnreachable()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : FuncBuilder()
|
companion object : FuncBuilder()
|
||||||
|
@ -126,7 +126,7 @@ data class ScriptContext(
|
|||||||
private fun assertFailure(a: Script.Cmd.Assertion, e: Throwable, expectedString: String) {
|
private fun assertFailure(a: Script.Cmd.Assertion, e: Throwable, expectedString: String) {
|
||||||
val innerEx = exceptionFromCatch(e)
|
val innerEx = exceptionFromCatch(e)
|
||||||
val msg = exceptionTranslator.translate(innerEx) ?: "<unrecognized error>"
|
val msg = exceptionTranslator.translate(innerEx) ?: "<unrecognized error>"
|
||||||
if (msg != expectedString)
|
if (!msg.contains(expectedString))
|
||||||
throw ScriptAssertionError(a, "Expected failure '$expectedString' got '$msg'", cause = innerEx)
|
throw ScriptAssertionError(a, "Expected failure '$expectedString' got '$msg'", cause = innerEx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,8 @@ class CoreTestUnit(val name: String, val wast: String, val expectedOutput: Strin
|
|||||||
// "switch.wast" TODO: we are in trouble here on the "argument switch"
|
// "switch.wast" TODO: we are in trouble here on the "argument switch"
|
||||||
"tee_local.wast",
|
"tee_local.wast",
|
||||||
"traps.wast",
|
"traps.wast",
|
||||||
"unreached-invalid.wast"
|
"unreached-invalid.wast",
|
||||||
|
"unwind.wast"
|
||||||
)
|
)
|
||||||
|
|
||||||
val testsWithErrorToWarningPredicates: Map<String, (Throwable) -> Boolean> = mapOf(
|
val testsWithErrorToWarningPredicates: Map<String, (Throwable) -> Boolean> = mapOf(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user