mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
vm: fix nested label prefixing
This commit is contained in:
parent
c26e116f0e
commit
0e1886e6bd
@ -36,10 +36,10 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
|
||||
val filename = programNameWithPath.name
|
||||
if(filename.endsWith(".p8virt")) {
|
||||
vm.runProgram(programNameWithPath.readText(), true)
|
||||
vm.runProgram(programNameWithPath.readText())
|
||||
} else if(File("$filename.p8virt").isFile) {
|
||||
val source = File("$filename.p8virt").readText()
|
||||
vm.runProgram(source, true)
|
||||
vm.runProgram(source)
|
||||
}
|
||||
else
|
||||
throw IllegalArgumentException("vm can only run .p8virt or .p8ir files")
|
||||
@ -53,5 +53,5 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||
}
|
||||
|
||||
interface IVirtualMachineRunner {
|
||||
fun runProgram(source: String, throttle: Boolean)
|
||||
fun runProgram(source: String)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ class IRCodeGen(
|
||||
internal val vmRegisters = RegisterPool()
|
||||
|
||||
fun generate(): IRProgram {
|
||||
flattenLabelNames()
|
||||
flattenNestedSubroutines()
|
||||
|
||||
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
|
||||
@ -101,9 +102,31 @@ class IRCodeGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenLabelNames() {
|
||||
val renameLabels = mutableListOf<Pair<PtNode, PtLabel>>()
|
||||
|
||||
fun flattenRecurse(node: PtNode) {
|
||||
node.children.forEach {
|
||||
if (it is PtLabel)
|
||||
renameLabels += Pair(it.parent, it)
|
||||
else
|
||||
flattenRecurse(it)
|
||||
}
|
||||
}
|
||||
|
||||
flattenRecurse(program)
|
||||
|
||||
renameLabels.forEach { (parent, label) ->
|
||||
val renamedLabel = PtLabel(label.scopedName.joinToString("."), label.position)
|
||||
val idx = parent.children.indexOf(label)
|
||||
parent.children.removeAt(idx)
|
||||
parent.children.add(idx, renamedLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenNestedSubroutines() {
|
||||
// this moves all nested subroutines up to the block scope.
|
||||
// also changes the name to be the fully scoped one so it becomes unique at the top level.
|
||||
// also changes the name to be the fully scoped one, so it becomes unique at the top level.
|
||||
// also moves the start() entrypoint as first subroutine.
|
||||
val flattenedSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
||||
val flattenedAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
|
||||
@ -111,10 +134,9 @@ class IRCodeGen(
|
||||
val removalsAsmSubs = mutableListOf<Pair<PtSub, PtAsmSub>>()
|
||||
val renameSubs = mutableListOf<Pair<PtBlock, PtSub>>()
|
||||
val renameAsmSubs = mutableListOf<Pair<PtBlock, PtAsmSub>>()
|
||||
val renameLabels = mutableListOf<Pair<PtNode, PtLabel>>()
|
||||
val entrypoint = program.entrypoint()
|
||||
|
||||
fun flattenNestedAsm(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) {
|
||||
fun flattenNestedAsmSub(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) {
|
||||
val flattened = PtAsmSub(asmsub.scopedName.joinToString("."),
|
||||
asmsub.address,
|
||||
asmsub.clobbers,
|
||||
@ -128,9 +150,9 @@ class IRCodeGen(
|
||||
removalsAsmSubs += Pair(parentSub, asmsub)
|
||||
}
|
||||
|
||||
fun flattenNested(block: PtBlock, parentSub: PtSub, sub: PtSub) {
|
||||
sub.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, sub, subsub) }
|
||||
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, sub, asmsubsub) }
|
||||
fun flattenNestedSub(block: PtBlock, parentSub: PtSub, sub: PtSub) {
|
||||
sub.children.filterIsInstance<PtSub>().forEach { subsub->flattenNestedSub(block, sub, subsub) }
|
||||
sub.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsmSub(block, sub, asmsubsub) }
|
||||
val flattened = PtSub(sub.scopedName.joinToString("."),
|
||||
sub.parameters,
|
||||
sub.returntype,
|
||||
@ -145,24 +167,15 @@ class IRCodeGen(
|
||||
block.children.forEach {
|
||||
if(it is PtSub) {
|
||||
// Only regular subroutines can have nested subroutines.
|
||||
it.children.filterIsInstance<PtSub>().forEach { subsub->flattenNested(block, it, subsub)}
|
||||
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsm(block, it, asmsubsub)}
|
||||
it.children.filterIsInstance<PtLabel>().forEach { label->renameLabels.add(Pair(it, label))}
|
||||
it.children.filterIsInstance<PtSub>().forEach { subsub->flattenNestedSub(block, it, subsub)}
|
||||
it.children.filterIsInstance<PtAsmSub>().forEach { asmsubsub->flattenNestedAsmSub(block, it, asmsubsub)}
|
||||
renameSubs += Pair(block, it)
|
||||
}
|
||||
if(it is PtAsmSub)
|
||||
renameAsmSubs += Pair(block, it)
|
||||
if(it is PtLabel)
|
||||
renameLabels += Pair(block, it)
|
||||
}
|
||||
}
|
||||
|
||||
renameLabels.forEach { (parent, label) ->
|
||||
val renamedLabel = PtLabel(label.scopedName.joinToString("."), label.position)
|
||||
val idx = parent.children.indexOf(label)
|
||||
parent.children.removeAt(idx)
|
||||
parent.children.add(idx, renamedLabel)
|
||||
}
|
||||
removalsSubs.forEach { (parent, sub) -> parent.children.remove(sub) }
|
||||
removalsAsmSubs.forEach { (parent, asmsub) -> parent.children.remove(asmsub) }
|
||||
flattenedSubs.forEach { (block, sub) -> block.add(sub) }
|
||||
|
@ -26,7 +26,7 @@ main {
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText(), false)
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: array with pointers") {
|
||||
@ -44,7 +44,7 @@ main {
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText(), false)
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: str args and return type") {
|
||||
@ -62,7 +62,7 @@ main {
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText(), false)
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: nested labels") {
|
||||
@ -72,6 +72,10 @@ main {
|
||||
uword i
|
||||
uword k
|
||||
|
||||
while k <= 10 {
|
||||
k++
|
||||
}
|
||||
|
||||
mylabel_outside:
|
||||
for i in 0 to 10 {
|
||||
mylabel_inside:
|
||||
@ -98,7 +102,7 @@ mylabel_inside:
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true, keepIR=true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8virt")
|
||||
VmRunner().runProgram(virtfile.readText(), false)
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
})
|
@ -3,9 +3,7 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- fix vm crash in TestCompilerVirtual: while loop
|
||||
- fix vm crash in TestCompilerVirtual: array with pointers
|
||||
- fix vm crash (while loop) in examples/vm/bsieve.p8 (Assembler)
|
||||
- fix vm crash (parseValue error) in examples/vm/textelite.p8 (Assembler)
|
||||
|
||||
...
|
||||
|
@ -27,7 +27,7 @@ main {
|
||||
k += prime
|
||||
}
|
||||
txt.print_uw(prime)
|
||||
txt.spc()
|
||||
txt.nl()
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class Assembler {
|
||||
if(binarymatch!=null) {
|
||||
val hex = binarymatch.groups[1]!!.value
|
||||
val binary = hex.windowed(size=2, step=2).map {
|
||||
it.toString().toByte(16)
|
||||
it.toByte(16)
|
||||
}.toByteArray()
|
||||
program.add(Instruction(Opcode.BINARYDATA, binaryData = binary))
|
||||
} else {
|
||||
|
@ -47,7 +47,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>, val cx16vir
|
||||
throw IllegalArgumentException("program cannot contain more than 65536 instructions")
|
||||
}
|
||||
|
||||
fun run(throttle: Boolean = true) {
|
||||
fun run() {
|
||||
try {
|
||||
var before = System.nanoTime()
|
||||
var numIns = 0
|
||||
@ -55,9 +55,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>, val cx16vir
|
||||
step()
|
||||
numIns++
|
||||
|
||||
if(throttle && stepCount and 32767 == 0) {
|
||||
Thread.sleep(1) // avoid 100% cpu core usage
|
||||
}
|
||||
// if(stepCount and 32767 == 0) {
|
||||
// Thread.sleep(1) // avoid 100% cpu core usage
|
||||
// }
|
||||
|
||||
if(stepCount and 0xffffff == 0) {
|
||||
val now = System.nanoTime()
|
||||
@ -2105,13 +2105,13 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>, val cx16vir
|
||||
|
||||
// probably called via reflection
|
||||
class VmRunner: IVirtualMachineRunner {
|
||||
override fun runProgram(source: String, throttle: Boolean) {
|
||||
override fun runProgram(source: String) {
|
||||
val (memsrc, programsrc) = source.split("------PROGRAM------".toRegex(), 2)
|
||||
val memory = Memory()
|
||||
val assembler = Assembler()
|
||||
assembler.initializeMemory(memsrc, memory)
|
||||
val program = assembler.assembleProgram(programsrc)
|
||||
val vm = VirtualMachine(memory, program, assembler.cx16virtualregBaseAdress)
|
||||
vm.run(throttle = throttle)
|
||||
vm.run()
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ class TestVm: FunSpec( {
|
||||
vm.valueStack.shouldBeEmpty()
|
||||
vm.pc shouldBe 0
|
||||
vm.stepCount shouldBe 0
|
||||
vm.run(throttle = false)
|
||||
vm.run()
|
||||
vm.callStack.shouldBeEmpty()
|
||||
vm.valueStack.shouldBeEmpty()
|
||||
vm.pc shouldBe 0
|
||||
@ -37,7 +37,7 @@ class TestVm: FunSpec( {
|
||||
vm.valueStack.shouldBeEmpty()
|
||||
vm.pc shouldBe 0
|
||||
vm.stepCount shouldBe 0
|
||||
vm.run(throttle = false)
|
||||
vm.run()
|
||||
memory.getUW(1000) shouldBe 12345u
|
||||
vm.callStack.shouldBeEmpty()
|
||||
vm.valueStack.shouldBeEmpty()
|
||||
@ -47,6 +47,6 @@ class TestVm: FunSpec( {
|
||||
|
||||
test("vmrunner") {
|
||||
val runner = VmRunner()
|
||||
runner.runProgram(";comment\n------PROGRAM------\n;comment\n", false)
|
||||
runner.runProgram(";comment\n------PROGRAM------\n;comment\n")
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user