diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-10 13:54:51 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-10 13:54:51 -0300 |
| commit | 7ca3c40b50b385ead6b8bc4c54de97b61d11a12a (patch) | |
| tree | 5c5998f39760b07e05135df56b8a828f2fb685c1 /testes | |
| parent | 8a3a49250ce4a7e46ec9e90810a61d9f97aece3d (diff) | |
| download | lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.tar.gz lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.tar.bz2 lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.zip | |
Another way to compile goto's
The compilation of a goto or a label just create an entry and generate
boilerplate code for the gotos. As we don't know yet whether it needs a
CLOSE, we code a jump followed by a CLOSE, which is then dead code.
When a block ends (and then we know for sure whether there are variables
that need to be closed), we check the goto's against the labels of that
block. When closing a goto against a label, if it needs a CLOSE, the
compiler swaps the order of the jump and the CLOSE, making the CLOSE
active.
Diffstat (limited to 'testes')
| -rw-r--r-- | testes/code.lua | 13 | ||||
| -rw-r--r-- | testes/db.lua | 2 | ||||
| -rw-r--r-- | testes/goto.lua | 35 |
3 files changed, 37 insertions, 13 deletions
diff --git a/testes/code.lua b/testes/code.lua index 08b3e23f..50ce7392 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
| @@ -412,13 +412,22 @@ checkequal(function (l) local a; return 0 <= a and a <= l end, | |||
| 412 | function (l) local a; return not (not(a >= 0) or not(a <= l)) end) | 412 | function (l) local a; return not (not(a >= 0) or not(a <= l)) end) |
| 413 | 413 | ||
| 414 | 414 | ||
| 415 | -- if-break optimizations | ||
| 416 | check(function (a, b) | 415 | check(function (a, b) |
| 417 | while a do | 416 | while a do |
| 418 | if b then break else a = a + 1 end | 417 | if b then break else a = a + 1 end |
| 419 | end | 418 | end |
| 420 | end, | 419 | end, |
| 421 | 'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0') | 420 | 'TEST', 'JMP', 'TEST', 'JMP', 'JMP', 'CLOSE', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0') |
| 421 | |||
| 422 | check(function () | ||
| 423 | do | ||
| 424 | goto exit -- don't need to close | ||
| 425 | local x <close> = nil | ||
| 426 | goto exit -- must close | ||
| 427 | end | ||
| 428 | ::exit:: | ||
| 429 | end, 'JMP', 'CLOSE', 'LOADNIL', 'TBC', | ||
| 430 | 'CLOSE', 'JMP', 'CLOSE', 'RETURN') | ||
| 422 | 431 | ||
| 423 | checkequal(function () return 6 or true or nil end, | 432 | checkequal(function () return 6 or true or nil end, |
| 424 | function () return k6 or kTrue or kNil end) | 433 | function () return k6 or kTrue or kNil end) |
diff --git a/testes/db.lua b/testes/db.lua index fc0db9ea..75730d27 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
| @@ -128,7 +128,7 @@ then | |||
| 128 | else | 128 | else |
| 129 | a=2 | 129 | a=2 |
| 130 | end | 130 | end |
| 131 | ]], {2,3,4,7}) | 131 | ]], {2,4,7}) |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | test([[ | 134 | test([[ |
diff --git a/testes/goto.lua b/testes/goto.lua index 4ac6d7d0..103cccef 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
| @@ -250,21 +250,36 @@ assert(testG(3) == "3") | |||
| 250 | assert(testG(4) == 5) | 250 | assert(testG(4) == 5) |
| 251 | assert(testG(5) == 10) | 251 | assert(testG(5) == 10) |
| 252 | 252 | ||
| 253 | do | 253 | do -- test goto's around to-be-closed variable |
| 254 | -- if x back goto out of scope of upvalue | 254 | |
| 255 | local X | 255 | -- set 'var' and return an object that will reset 'var' when |
| 256 | -- it goes out of scope | ||
| 257 | local function newobj (var) | ||
| 258 | _ENV[var] = true | ||
| 259 | return setmetatable({}, {__close = function () | ||
| 260 | _ENV[var] = nil | ||
| 261 | end}) | ||
| 262 | end | ||
| 263 | |||
| 256 | goto L1 | 264 | goto L1 |
| 257 | 265 | ||
| 258 | ::L2:: goto L3 | 266 | ::L4:: assert(not X); goto L5 -- varX dead here |
| 259 | 267 | ||
| 260 | ::L1:: do | 268 | ::L1:: |
| 261 | local a <close> = setmetatable({}, {__close = function () X = true end}) | 269 | local varX <close> = newobj("X") |
| 262 | assert(X == nil) | 270 | assert(X); goto L2 -- varX alive here |
| 263 | if a then goto L2 end -- jumping back out of scope of 'a' | ||
| 264 | end | ||
| 265 | 271 | ||
| 266 | ::L3:: assert(X == true) -- checks that 'a' was correctly closed | 272 | ::L3:: |
| 273 | assert(X); goto L4 -- varX alive here | ||
| 274 | |||
| 275 | ::L2:: assert(X); goto L3 -- varX alive here | ||
| 276 | |||
| 277 | ::L5:: -- return | ||
| 267 | end | 278 | end |
| 279 | |||
| 280 | |||
| 281 | |||
| 282 | foo() | ||
| 268 | -------------------------------------------------------------------------------- | 283 | -------------------------------------------------------------------------------- |
| 269 | 284 | ||
| 270 | 285 | ||
