about summary refs log tree commit diff stats
path: root/apps/tile/data.mu
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-10-06 00:36:28 -0700
committerKartik Agaram <vc@akkartik.com>2020-10-06 00:36:28 -0700
commitce094a5d827b82c48eb76b1b4c04cf899219c33b (patch)
tree5fe3a3ef14e3d7de3b291273378935500393ea80 /apps/tile/data.mu
parente41bc160a0dfee0c38ecf20b20ddaf7e6f3da408 (diff)
downloadmu-ce094a5d827b82c48eb76b1b4c04cf899219c33b.tar.gz
6968
Snapshot that requires a check in the Mu compiler.

Currently I don't spill a register if it could possibly be over-written
by a function output within. However, find-in-call-path is a good example
of where this constraint is too lenient and results in unsafe code. The
variable `curr` gets clobbered during loop update by the variable `match?`.

What's the answer? Perhaps we should ban all conditional updates to function
outputs? That'd be dashed inconvenient.
Diffstat (limited to 'apps/tile/data.mu')
-rw-r--r--apps/tile/data.mu146
1 files changed, 124 insertions, 22 deletions
diff --git a/apps/tile/data.mu b/apps/tile/data.mu
index 5c54f6f5..beceb7c7 100644
--- a/apps/tile/data.mu
+++ b/apps/tile/data.mu
@@ -3,7 +3,7 @@ type sandbox {
   data: (handle line)
   # display data
   cursor-word: (handle word)
-  cursor-word-index: int
+  cursor-call-path: (handle call-path-element)
   expanded-words: (handle call-path)
   #
   next: (handle sandbox)
@@ -55,10 +55,18 @@ type bind {
 # A call-path is a data structure that can unambiguously refer to any specific
 # call arbitrarily deep inside the call hierarchy of a program.
 type call-path {
-  data: int
+  data: (handle call-path-element)
   next: (handle call-path)
 }
 
+# A call-path is a list of elements, each of which corresponds to some call.
+# Calls are denoted by their position in the caller's body. They also include
+# the function being called.
+type call-path-element {
+  index-in-body: int
+  next: (handle call-path-element)
+}
+
 type result {
   data: value-stack
   error: (handle array byte)  # single error message for now
@@ -66,6 +74,8 @@ type result {
 
 fn initialize-sandbox _sandbox: (addr sandbox) {
   var sandbox/esi: (addr sandbox) <- copy _sandbox
+  var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path
+  allocate cursor-call-path-ah
   var line-ah/eax: (addr handle line) <- get sandbox, data
   allocate line-ah
   var line/eax: (addr line) <- lookup *line-ah
@@ -195,20 +205,22 @@ fn populate-text-with _out: (addr handle array byte), _in: (addr array byte) {
   }
 }
 
-fn find-in-call-path in: (addr handle call-path), _needle: int -> result/eax: boolean {
+fn find-in-call-path in: (addr handle call-path), needle: (addr handle call-path-element) -> result/eax: boolean {
 $find-in-call-path:body: {
   var curr-ah/esi: (addr handle call-path) <- copy in
-  var needle/ebx: int <- copy _needle
   {
     var curr/eax: (addr call-path) <- lookup *curr-ah
     compare curr, 0
     break-if-=
-    var curr-n/ecx: (addr int) <- get curr, data
-    compare needle, *curr-n
     {
-      break-if-!=
-      result <- copy 1  # true
-      break $find-in-call-path:body
+      var curr-data/eax: (addr handle call-path-element) <- get curr, data
+      var match?/eax: boolean <- call-path-element-match? curr-data, needle
+      compare match?, 0  # false
+      {
+        break-if-=
+        result <- copy 1  # true
+        break $find-in-call-path:body
+      }
     }
     curr-ah <- get curr, next
     loop
@@ -217,38 +229,128 @@ $find-in-call-path:body: {
 }
 }
 
+fn call-path-element-match? _x: (addr handle call-path-element), _y: (addr handle call-path-element) -> result/eax: boolean {
+$call-path-element-match?:body: {
+  var x-ah/eax: (addr handle call-path-element) <- copy _x
+  var x-a/eax: (addr call-path-element) <- lookup *x-ah
+  var x/esi: (addr call-path-element) <- copy x-a
+  var y-ah/eax: (addr handle call-path-element) <- copy _y
+  var y-a/eax: (addr call-path-element) <- lookup *y-ah
+  var y/edi: (addr call-path-element) <- copy y-a
+  compare x, y
+  {
+    break-if-!=
+    result <- copy 1  # true
+    break $call-path-element-match?:body
+  }
+  compare x, 0
+  {
+    break-if-!=
+    result <- copy 0  # false
+    break $call-path-element-match?:body
+  }
+  compare y, 0
+  {
+    break-if-!=
+    result <- copy 0  # false
+    break $call-path-element-match?:body
+  }
+  var x-data-a/ecx: (addr int) <- get x, index-in-body
+  var x-data/ecx: int <- copy *x-data-a
+  var y-data-a/eax: (addr int) <- get y, index-in-body
+  var y-data/eax: int <- copy *y-data-a
+  compare x-data, y-data
+  {
+    break-if-=
+    result <- copy 0  # false
+    break $call-path-element-match?:body
+  }
+  var x-next/ecx: (addr handle call-path-element) <- get x, next
+  var y-next/eax: (addr handle call-path-element) <- get y, next
+  result <- call-path-element-match? x-next, y-next
+}
+}
+
 # order is irrelevant
-fn insert-in-call-path list: (addr handle call-path), _n: int {
+fn insert-in-call-path list: (addr handle call-path), new: (addr handle call-path-element) {
   var new-path-storage: (handle call-path)
   var new-path-ah/edi: (addr handle call-path) <- address new-path-storage
   allocate new-path-ah
   var new-path/eax: (addr call-path) <- lookup *new-path-ah
   var next/ecx: (addr handle call-path) <- get new-path, next
   copy-object list, next
-  var data/ecx: (addr int) <- get new-path, data
-  var n/edx: int <- copy _n
-  copy-to *data, n
+  var dest/ecx: (addr handle call-path-element) <- get new-path, data
+  deep-copy-call-path-element new, dest
   copy-object new-path-ah, list
 }
 
-fn delete-in-call-path list: (addr handle call-path), _n: int {
+# assumes dest is initially clear
+fn deep-copy-call-path-element _src: (addr handle call-path-element), _dest: (addr handle call-path-element) {
+  var src/esi: (addr handle call-path-element) <- copy _src
+  # if src is null, return
+  var _src-addr/eax: (addr call-path-element) <- lookup *src
+  compare _src-addr, 0
+  break-if-=
+  # allocate
+  var src-addr/esi: (addr call-path-element) <- copy _src-addr
+  var dest/eax: (addr handle call-path-element) <- copy _dest
+  allocate dest
+  # copy data
+  var dest-addr/eax: (addr call-path-element) <- lookup *dest
+  {
+    var dest-data-addr/ecx: (addr int) <- get dest-addr, index-in-body
+    var tmp/eax: (addr int) <- get src-addr, index-in-body
+    var tmp2/eax: int <- copy *tmp
+    copy-to *dest-data-addr, tmp2
+  }
+  # recurse
+  var src-next/esi: (addr handle call-path-element) <- get src-addr, next
+  var dest-next/eax: (addr handle call-path-element) <- get dest-addr, next
+  deep-copy-call-path-element src-next, dest-next
+}
+
+fn delete-in-call-path list: (addr handle call-path), needle: (addr handle call-path-element) {
 $delete-in-call-path:body: {
   var curr-ah/esi: (addr handle call-path) <- copy list
-  var n/ebx: int <- copy _n
   $delete-in-call-path:loop: {
-    var curr/eax: (addr call-path) <- lookup *curr-ah
+    var _curr/eax: (addr call-path) <- lookup *curr-ah
+    var curr/ecx: (addr call-path) <- copy _curr
     compare curr, 0
     break-if-=
-    var curr-n/ecx: (addr int) <- get curr, data
-    compare n, *curr-n
     {
-      break-if-!=
-      var next-ah/ecx: (addr handle call-path) <- get curr, next
-      copy-object next-ah, curr-ah
-      loop $delete-in-call-path:loop
+      var curr-data/eax: (addr handle call-path-element) <- get curr, data
+      var match?/eax: boolean <- call-path-element-match? curr-data, needle
+      compare match?, 0  # false
+      {
+        break-if-=
+        var next-ah/ecx: (addr handle call-path) <- get curr, next
+        copy-object next-ah, curr-ah
+        loop $delete-in-call-path:loop
+      }
     }
     curr-ah <- get curr, next
     loop
   }
 }
 }
+
+fn increment-final-element list: (addr handle call-path-element) {
+  var final-ah/eax: (addr handle call-path-element) <- copy list
+  var final/eax: (addr call-path-element) <- lookup *final-ah
+  var val/eax: (addr int) <- get final, index-in-body
+  increment *val
+}
+
+fn decrement-final-element list: (addr handle call-path-element) {
+  var final-ah/eax: (addr handle call-path-element) <- copy list
+  var final/eax: (addr call-path-element) <- lookup *final-ah
+  var val/eax: (addr int) <- get final, index-in-body
+  decrement *val
+}
+
+fn final-element-value list: (addr handle call-path-element) -> result/eax: int {
+  var final-ah/eax: (addr handle call-path-element) <- copy list
+  var final/eax: (addr call-path-element) <- lookup *final-ah
+  var val/eax: (addr int) <- get final, index-in-body
+  result <- copy *val
+}