mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 17:16:33 +00:00
fix defer() with the arena allocator ("return values are evaluated before the defer is executed")
This commit is contained in:
@@ -185,7 +185,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
|
||||
is PtNumber,
|
||||
is PtRange,
|
||||
is PtString -> true
|
||||
is PtIdentifier -> true // actually PtIdentifier IS "complex" this time (it's a variable that might change) but it's kinda annoying to give a warning message for this very common case
|
||||
// note that PtIdentifier als is "complex" this time (it's a variable that might change)
|
||||
else -> false
|
||||
}
|
||||
|
||||
@@ -202,7 +202,6 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
|
||||
}
|
||||
|
||||
// complex return value, need to store it before calling the defer block
|
||||
errors.warn("using defer with nontrivial return value(s) incurs stack overhead", ret.children.first { !notComplex(it as PtExpression)}.position)
|
||||
val pushAndPopCalls = ret.children.map { makePushPopFunctionCalls(it as PtExpression) }
|
||||
val pushCalls = pushAndPopCalls.map { it.first }.reversed() // push in reverse order
|
||||
val popCalls = pushAndPopCalls.map { it.second }
|
||||
|
||||
@@ -1303,6 +1303,11 @@ It's possible to write a defer for a block of statements, but the advice is to k
|
||||
If a piece of inlined assembly somehow causes the routine to exit, the compiler cannot detect this,
|
||||
and defers won't be handled in such cases.
|
||||
|
||||
.. attention::
|
||||
Using defer always has a slight code overhead.
|
||||
If you are returning non-constant values in a routine that uses defer, the compiler even has to insert some additional
|
||||
code that uses the cpu stack to save some temporary values.
|
||||
|
||||
|
||||
Library routines and builtin functions
|
||||
--------------------------------------
|
||||
|
||||
@@ -241,9 +241,8 @@ An example of how a super simple dynamic allocator could look like::
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
|
||||
sub freeall() {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
fix defer() with the arena allocator ("return values are evaluated before the defer is executed")
|
||||
|
||||
|
||||
not all source lines are correctly reported in the IR file,
|
||||
for example the below subroutine only shows the sub() line::
|
||||
|
||||
|
||||
@@ -141,8 +141,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,8 +227,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,8 +106,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,8 +225,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,7 @@ arena {
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
uword result = next
|
||||
next += size
|
||||
return result
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
+25
-36
@@ -3,48 +3,37 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
txt.print("expected: 0 10 30\n")
|
||||
counter = 0
|
||||
txt.print_ub(nodefer(10))
|
||||
txt.print_uw(allocator.alloc(10))
|
||||
txt.spc()
|
||||
txt.print_ub(nodefer(20))
|
||||
txt.print_uw(allocator.alloc(20))
|
||||
txt.spc()
|
||||
txt.print_ub(nodefer(30))
|
||||
txt.print_uw(allocator.alloc(30))
|
||||
txt.nl()
|
||||
|
||||
counter = 0
|
||||
txt.print_ub(add(10))
|
||||
allocator.freeall()
|
||||
|
||||
txt.print_uw(allocator.alloc(10))
|
||||
txt.spc()
|
||||
txt.print_ub(add(20))
|
||||
txt.print_uw(allocator.alloc(20))
|
||||
txt.spc()
|
||||
txt.print_ub(add(30))
|
||||
txt.print_uw(allocator.alloc(30))
|
||||
txt.nl()
|
||||
|
||||
counter = 0
|
||||
txt.print_ub(add2(10))
|
||||
txt.spc()
|
||||
txt.print_ub(add2(20))
|
||||
txt.spc()
|
||||
txt.print_ub(add2(30))
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
ubyte counter = 0
|
||||
|
||||
sub nodefer(ubyte amount) -> ubyte {
|
||||
ubyte result = counter
|
||||
counter += amount
|
||||
return result
|
||||
}
|
||||
|
||||
sub add(ubyte amount) -> ubyte {
|
||||
defer counter += amount ; TODO FIX : BORKED!
|
||||
return counter
|
||||
}
|
||||
|
||||
sub add2(ubyte amount) -> ubyte {
|
||||
cx16.r0L = 0
|
||||
defer counter += amount
|
||||
return counter + cx16.r0L
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
allocator {
|
||||
; extremely trivial allocator allocator
|
||||
uword buffer = memory("allocator", 2000, 0)
|
||||
uword next = buffer
|
||||
|
||||
sub alloc(ubyte size) -> uword {
|
||||
defer next += size
|
||||
return next
|
||||
}
|
||||
|
||||
sub freeall() {
|
||||
; cannot free individual allocations only the whole allocator at once
|
||||
next = buffer
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user