1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-09-27 12:57:41 +00:00

#11 Fix allocation of variables in functions with trampolines

This commit is contained in:
Karol Stasiak 2019-10-22 01:39:11 +02:00
parent f65651f2c0
commit ff46129c4e
3 changed files with 119 additions and 0 deletions

View File

@ -119,6 +119,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
if (forZpOnly && !options.platform.hasZeroPage) {
return
}
if (nf.exists(_.name.endsWith(".trampoline"))) {
return
}
if (log.traceEnabled) log.trace("Allocating variables in " + nf.map(f => "function " + f.name).getOrElse("global scope"))
val b = get[Type]("byte")
val p = get[Type]("pointer")
val params = nf.fold(List[String]()) { f =>
@ -146,6 +150,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} else 3
val toAdd = things.values.flatMap {
case m: UninitializedMemory if passForAlloc(m.alloc) == pass && nf.isDefined == isLocalVariableName(m.name) && !m.name.endsWith(".addr") && maybeGet[Thing](m.name + ".array").isEmpty =>
if (log.traceEnabled) log.trace("Allocating " + m.name)
val vertex = if (options.flag(CompilationFlag.VariableOverlap)) {
nf.fold[VariableVertex](GlobalVertex) { f =>
if (m.alloc == VariableAllocationMethod.Static) {

View File

@ -182,6 +182,12 @@ class StandardCallGraph(program: Program, log: Logger) extends CallGraph(program
if (multiaccessibleFunctions(a.function) || multiaccessibleFunctions(b.function)) {
return false
}
if (a.function + ".trampoline" == b.function) {
return false
}
if (a.function == b.function + ".trampoline") {
return false
}
if (callEdges(a.function -> b.function) || callEdges(b.function -> a.function)) {
return false
}

View File

@ -0,0 +1,108 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCmosRun}
import org.scalatest.{FunSuite, Matchers}
/**
* @author Karol Stasiak
*/
class Issue11Test extends FunSuite with Matchers {
test("Test issue 11") {
val src =
"""
|import c64_basic
|import stdio
|
|struct Box {
| byte x,
| byte y,
| byte width,
| byte height
|}
|
|struct Phys_Obj {
| Box pos,
| byte xfrac,
| byte yfrac,
| sbyte xvel,
| sbyte yvel,
| byte xaccel,
| byte yaccel,
| byte xspeed,
| bool on_ground,
| bool jumping,
| bool can_jump
|}
|
|Phys_Obj player1
|byte output @$c000
|
|inline pointer get_metatile_column(word metatiles_column) {
| //This is the function where the original player pointer
| //gets corrupted.
| return pointer(metatiles_column)
|}
|
|byte get_tile(byte column, byte row) {
| byte tile
| pointer metatiles_column
|
| metatiles_column = get_metatile_column($0000)
| tile = $00
| return tile
|}
|
|void check_background_collis(byte screenx, byte screeny, byte spritewidth, byte spriteheight) {
| byte new_column1
| byte new_column2
| byte new_row1
| byte new_row2
| byte i
| byte limit
| byte current_tile
|
| current_tile = get_tile(0,0)
|}
|
|void check_player_collis_and_update_player_loc(pointer.Phys_Obj player) {
| sbyte temp_vel
| byte old_playerx
| byte old_playerx_frac
| byte old_playery
| byte old_playery_frac
|
| old_playerx = player1.pos.x
| old_playery = player1.pos.y
| old_playerx_frac = player1.xfrac
| old_playery_frac = player1.yfrac
|
| check_background_collis(player1.pos.x, player1.pos.y, player1.pos.width, player1.pos.height)
|}
|
|inline void game_logic(pointer.Phys_Obj player) {
| player->pos.x = 15
|
| //comment out this function call and the player
| //pointer should still point to the correct location
| check_player_collis_and_update_player_loc(player)
| //after the function call, player points to garbage
|
| //expected val: 15
| //if player no longer points to player1: garbage
| output = player->pos.x
|}
|
|void main() {
| pointer.Phys_Obj player
| player = pointer.Phys_Obj(player1.addr)
| game_logic(player)
|}
|""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos)(src) { m =>
m.readByte(0xc000) should equal(15)
}
}
}