diff options
author | Kartik Agaram <vc@akkartik.com> | 2020-06-21 16:56:57 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2020-06-21 17:08:03 -0700 |
commit | 6bfb565819288770eea9b0cfe1f7a44abd8a45d1 (patch) | |
tree | 39f562f657ffb4d4f3c4bbda7df4e802db4d7cad | |
parent | 6883b8d1c71a939b1378422f4c0f66982698d725 (diff) | |
download | mu-6bfb565819288770eea9b0cfe1f7a44abd8a45d1.tar.gz |
6570 - error on use of a clobbered var
All tests now passing, and factorial.mu and all other apps now working. The new checks caught one problem in a few prototypes.
-rwxr-xr-x | apps/mu | bin | 319197 -> 323388 bytes | |||
-rw-r--r-- | apps/mu.subx | 195 | ||||
-rw-r--r-- | prototypes/browse/16-screen-state-broken.mu | 2 | ||||
-rw-r--r-- | prototypes/browse/17-file-state-broken/main.mu | 2 | ||||
-rw-r--r-- | prototypes/browse/26-headers/main.mu | 16 | ||||
-rw-r--r-- | prototypes/browse/27/main.mu | 16 | ||||
-rw-r--r-- | prototypes/browse/28/main.mu | 16 | ||||
-rw-r--r-- | prototypes/browse/29/main.mu | 16 |
8 files changed, 195 insertions, 68 deletions
diff --git a/apps/mu b/apps/mu index 9e94861d..48425fe1 100755 --- a/apps/mu +++ b/apps/mu Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx index f6d48793..e2628d99 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -2488,12 +2488,12 @@ test-fn-output-written-in-inner-block: # convert (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) (flush _test-output-buffered-file) - # dump _test-output-stream {{{ - (write 2 "^") - (write-stream 2 _test-output-stream) - (write 2 "$\n") - (rewind-stream _test-output-stream) - # }}} +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} # no error; defining 'out' didn't interfere with the reclamation of 'b' # check output (check-next-stream-line-equal _test-output-stream "foo:" "F - test-fn-output-written-in-inner-block/0") @@ -11453,62 +11453,173 @@ $same-register-spilled-before?:end: 5d/pop-to-ebp c3/return -# clean up global state for 'vars' until some block depth (inclusive) +# Clean up global state for 'vars' until some block depth (inclusive). +# +# This would be a simple series of pops, if it wasn't for fn outputs, which +# can occur anywhere in the stack. +# So we have to _compact_ the entire array underlying the stack. +# +# We want to allow a fn output register to be written to by locals before the +# output is set. +# So fn outputs can't just be pushed at the start of the function. +# +# We want to allow other locals to shadow a fn output register after the +# output is set. +# So the output can't just always override anything in the stack. Sequence matters. clean-up-blocks: # vars: (addr stack live-var), until-block-depth: int, fn: (addr function) + # pseudocode: + # to = vars->top (which points outside the stack) + # while true + # if to <= 0 + # break + # var v = vars->data[to-1] + # if v.depth < until and !in-function-outputs?(fn, v) + # break + # --to + # from = to + # while true + # if from >= vars->top + # break + # assert(from >= to) + # v = vars->data[from] + # if in-function-outputs?(fn, v) + # if from > to + # vars->data[to] = vars->data[from] + # ++to + # ++from + # vars->top = to + # # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax - 51/push-ecx + 52/push-edx + 53/push-ebx 56/push-esi - # esi = vars - 8b/-> *(ebp+8) 6/r32/esi - # ecx = until-block-depth - 8b/-> *(ebp+0xc) 1/r32/ecx + 57/push-edi + # ebx = vars + 8b/-> *(ebp+8) 3/r32/ebx + # edx = until-block-depth + 8b/-> *(ebp+0xc) 2/r32/edx +$clean-up-blocks:phase1: + # var to/edi: int = vars->top + 8b/-> *ebx 7/r32/edi { -$clean-up-blocks:reclaim-loop: - # if (vars->top <= 0) break - 8b/-> *esi 0/r32/eax # Stack-top - 3d/compare-eax-and 0/imm32 - 0f 8e/jump-if-<= break/disp32 - # var v/eax: (addr var) = lookup(vars[vars->top-12]) -#? (print-int32-buffered Stderr %eax) -#? (write-buffered Stderr ": ") -#? (print-int32-buffered Stderr *(esi+eax-4)) -#? (write-buffered Stderr " ") -#? (print-int32-buffered Stderr *(esi+eax)) -#? (write-buffered Stderr " ") -#? (print-int32-buffered Stderr *(esi+eax+4)) -#? (write-buffered Stderr Newline) -#? (flush Stderr) - (lookup *(esi+eax-4) *(esi+eax)) # vars + 8 + vars->top - 12 => eax - # if (v->block-depth < until-block-depth) break - 39/compare *(eax+0x10) 1/r32/ecx # Var-block-depth - 7c/jump-if-< break/disp8 - # if v is on the stack, update Curr-local-stack-offset - 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register +$clean-up-blocks:loop1: + # if (to <= 0) break + 81 7/subop/compare %edi 0/imm32 + 7e/jump-if-<= break/disp8 + # var v/eax: (addr var) = lookup(vars->data[to-1]->var) + 8d/copy-address *(ebx+edi-4) 0/r32/eax # vars + 8 + to - 12 + (lookup *eax *(eax+4)) # => eax + # if (v->block-depth >= until-block-depth) continue + 39/compare *(eax+0x10) 2/r32/edx # Var-block-depth { - 75/jump-if-!= break/disp8 -$clean-up-blocks:reclaim-var-on-stack: - (size-of %eax) # => eax - 01/add-to *Curr-local-stack-offset 0/r32/eax + 7d/jump-if->= break/disp8 + # if (!in-function-outputs?(fn, v)) break + (in-function-outputs? *(ebp+0x10) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $clean-up-blocks:phase2/disp8 } - (pop %esi) # => eax - (pop %esi) # => eax - (pop %esi) # => eax - e9/jump loop/disp32 +$clean-up-blocks:loop1-continue: + # --to + 81 5/subop/subtract %edi 0xc/imm32 + # + eb/jump loop/disp8 + } +$clean-up-blocks:phase2: + # var from/esi: int = to + 89/<- %esi 7/r32/edi + { +$clean-up-blocks:loop2: + # if (from >= vars->top) break + 3b/compare 6/r32/esi *ebx + 7d/jump-if->= break/disp8 + # var v/eax: (addr var) = lookup(vars->data[from]->var) + 8d/copy-address *(ebx+esi+8) 0/r32/eax + (lookup *eax *(eax+4)) # => eax + # if !in-function-outputs?(fn, v) continue + (in-function-outputs? *(ebp+0x10) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $clean-up-blocks:loop2-continue/disp8 + # invariant: from >= to + # if (from > to) vars->data[to] = vars->data[from] + { + 39/compare %esi 7/r32/edi + 7e/jump-if-<= break/disp8 + 56/push-esi + 57/push-edi + # . var from/esi: (addr byte) = &vars->data[from] + 8d/copy-address *(ebx+esi+8) 6/r32/esi + # . var to/edi: (addr byte) = &vars->data[to] + 8d/copy-address *(ebx+edi+8) 7/r32/edi + # . + 8b/-> *esi 0/r32/eax + 89/<- *edi 0/r32/eax + 8b/-> *(esi+4) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + 8b/-> *(esi+8) 0/r32/eax + 89/<- *(edi+8) 0/r32/eax + 5f/pop-to-edi + 5e/pop-to-esi + } + # ++to + 81 0/subop/add %edi 0xc/imm32 +$clean-up-blocks:loop2-continue: + # ++from + 81 0/subop/add %esi 0xc/imm32 + # + eb/jump loop/disp8 } + 89/<- *ebx 7/r32/edi $clean-up-blocks:end: # . restore registers + 5f/pop-to-edi 5e/pop-to-esi - 59/pop-to-ecx + 5b/pop-to-ebx + 5a/pop-to-edx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return +in-function-outputs?: # fn: (addr function), target: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr list var) = lookup(fn->outputs) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax + 89/<- %ecx 0/r32/eax + # while curr != null + { + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # var v/eax: (addr var) = lookup(curr->value) + (lookup *ecx *(ecx+4)) # List-value List-value => eax + # if (v == target) return true + 39/compare *(ebp+0xc) 0/r32/eax + b8/copy-to-eax 1/imm32/true + 74/jump-if-= $in-function-outputs?:end/disp8 + # curr = curr->next + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } + b8/copy-to-eax 0/imm32 +$in-function-outputs?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt) # . prologue 55/push-ebp diff --git a/prototypes/browse/16-screen-state-broken.mu b/prototypes/browse/16-screen-state-broken.mu index 7ab40060..6fe7f3eb 100644 --- a/prototypes/browse/16-screen-state-broken.mu +++ b/prototypes/browse/16-screen-state-broken.mu @@ -28,7 +28,7 @@ fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { var ncols/ecx: int <- copy 0 nrows, ncols <- screen-size var screen-position-state-storage: screen-position-state - var screen-position-state: (addr screen-position-state) = address screen-position-state-storage + var screen-position-state: (addr screen-position-state) init-screen-position-state screen-position-state, nrows, ncols { render file, screen-position-state diff --git a/prototypes/browse/17-file-state-broken/main.mu b/prototypes/browse/17-file-state-broken/main.mu index e95aff73..fc22d9ea 100644 --- a/prototypes/browse/17-file-state-broken/main.mu +++ b/prototypes/browse/17-file-state-broken/main.mu @@ -12,7 +12,7 @@ fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { var ncols/ecx: int <- copy 0 nrows, ncols <- screen-size var screen-position-state-storage: screen-position-state - var screen-position-state: (addr screen-position-state) = address screen-position-state-storage + var screen-position-state: (addr screen-position-state) init-screen-position-state screen-position-state, nrows, ncols { var done?/eax: boolean <- done-reading? fs diff --git a/prototypes/browse/26-headers/main.mu b/prototypes/browse/26-headers/main.mu index 4f6b53e3..8ce29b8e 100644 --- a/prototypes/browse/26-headers/main.mu +++ b/prototypes/browse/26-headers/main.mu @@ -126,9 +126,11 @@ $render-header-line:body: { var c/eax: byte <- copy 0 { # if done-drawing?(state) return - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= $render-header-line:body + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= $render-header-line:body + } # c <- next-char fs # if (c != '#') break @@ -142,9 +144,11 @@ $render-header-line:body: { start-heading header-level { # if done-drawing?(state) break - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= + } # c <- next-char fs # if (c == EOF) break diff --git a/prototypes/browse/27/main.mu b/prototypes/browse/27/main.mu index 13764211..ea471c8b 100644 --- a/prototypes/browse/27/main.mu +++ b/prototypes/browse/27/main.mu @@ -133,9 +133,11 @@ $render-header-line:body: { var c/eax: byte <- copy 0 { # if done-drawing?(state) return - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= $render-header-line:body + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= $render-header-line:body + } # c <- next-char fs # if (c != '#') break @@ -149,9 +151,11 @@ $render-header-line:body: { start-heading header-level { # if done-drawing?(state) break - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= + } # c <- next-char fs # if (c == EOF) break diff --git a/prototypes/browse/28/main.mu b/prototypes/browse/28/main.mu index 0f7458e6..398890f3 100644 --- a/prototypes/browse/28/main.mu +++ b/prototypes/browse/28/main.mu @@ -135,9 +135,11 @@ $render-header-line:body: { var c/eax: byte <- copy 0 { # if done-drawing?(state) return - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= $render-header-line:body + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= $render-header-line:body + } # c <- next-char fs # if (c != '#') break @@ -151,9 +153,11 @@ $render-header-line:body: { start-heading header-level { # if done-drawing?(state) break - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= + } # c <- next-char fs # if (c == EOF) break diff --git a/prototypes/browse/29/main.mu b/prototypes/browse/29/main.mu index ea9cdf02..5bbb0586 100644 --- a/prototypes/browse/29/main.mu +++ b/prototypes/browse/29/main.mu @@ -145,9 +145,11 @@ $render-header-line:body: { var c/eax: byte <- copy 0 { # if done-drawing?(state) return - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= $render-header-line:body + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= $render-header-line:body + } # c <- next-char fs # if (c != '#') break @@ -161,9 +163,11 @@ $render-header-line:body: { start-heading header-level { # if done-drawing?(state) break - var done?/eax: boolean <- done-drawing? state - compare done?, 0 # false - break-if-!= + { + var done?/eax: boolean <- done-drawing? state + compare done?, 0 # false + break-if-!= + } # c <- next-char fs # if (c == EOF) break |