about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-07-03 03:02:37 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-07-03 03:02:37 -0700
commit26965dd683137d3f8cf2fab62f02a8dbf5991a68 (patch)
tree6a0a999ef021416d1d9f42aab6ff21a8c2844759
parent830c0371b9169adb8a461bc323e0cea61ced63c7 (diff)
downloadmu-26965dd683137d3f8cf2fab62f02a8dbf5991a68.tar.gz
3093
Another bug, this time in cycle detection, which had been present from
the start but hadn't actually been tested until now. Turns out it had
two bugs, one with the map not being passed into a recursive call, and a
more subtle one: I wasn't actually saving the right input address.
-rw-r--r--073deep_copy.cc52
1 files changed, 44 insertions, 8 deletions
diff --git a/073deep_copy.cc b/073deep_copy.cc
index bf5675db..7c67425b 100644
--- a/073deep_copy.cc
+++ b/073deep_copy.cc
@@ -213,31 +213,38 @@ case DEEP_COPY: {
 }
 
 :(code)
-vector<double> deep_copy(reagent/*copy*/ in, const reagent& tmp) {
+vector<double> deep_copy(const reagent& in, const reagent& tmp) {
+  map<int, int> addresses_copied;
+  return deep_copy(in, addresses_copied, tmp);
+}
+
+vector<double> deep_copy(reagent/*copy*/ in, map<int, int>& addresses_copied, const reagent& tmp) {
   canonize(in);
   vector<double> result;
-  map<int, int> addresses_copied;
   if (is_mu_address(in))
     result.push_back(deep_copy_address(in, addresses_copied, tmp));
   else
     deep_copy(in, addresses_copied, tmp, result);
-  trace(9991, "run") << "deep-copy: done" << end();
   return result;
 }
 
 // deep-copy an address and return a new address
 int deep_copy_address(const reagent& canonized_in, map<int, int>& addresses_copied, const reagent& tmp) {
-  int in_address = canonized_in.value;
-  if (in_address == 0) return 0;
+  if (canonized_in.value == 0) return 0;
+  int in_address = payload_address(canonized_in);
   trace(9991, "run") << "deep-copy: copying address " << in_address << end();
-  if (contains_key(addresses_copied, in_address))
-    return get(addresses_copied, in_address);
+  if (contains_key(addresses_copied, in_address)) {
+    int out = get(addresses_copied, in_address);
+    trace(9991, "run") << "deep-copy: copy already exists: " << out << end();
+    return out;
+  }
   int out = allocate(payload_size(canonized_in));
+  trace(9991, "run") << "deep-copy: new address is " << out << end();
   put(addresses_copied, in_address, out);
   reagent/*copy*/ payload = canonized_in;
   payload.properties.push_back(pair<string, string_tree*>("lookup", NULL));
   trace(9991, "run") << "recursing on payload " << payload.value << ' ' << to_string(payload) << end();
-  vector<double> data = deep_copy(payload, tmp);
+  vector<double> data = deep_copy(payload, addresses_copied, tmp);
   trace(9991, "run") << "deep-copy: writing result " << out << ": " << to_string(data) << end();
   // HACK: write_memory interface isn't ideal for this situation; we need
   // a temporary location to help copy the payload.
@@ -274,6 +281,12 @@ void deep_copy(const reagent& canonized_in, map<int, int>& addresses_copied, con
   }
 }
 
+int payload_address(reagent/*copy*/ x) {
+  x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
+  canonize(x);
+  return x.value;
+}
+
 //: moar tests, just because I can't believe it all works
 
 :(scenario deep_copy_stress_test_1)
@@ -338,3 +351,26 @@ def main [
   1:number/raw <- copy *y
 ]
 +mem: storing 34 in location 1
+
+:(scenario deep_copy_cycles)
+container foo [
+  p:number
+  q:address:foo
+]
+def main [
+  local-scope
+  x:address:foo <- new foo:type
+  *x <- put *x, p:offset, 34
+  *x <- put *x, q:offset, x  # create a cycle
+  y:address:foo <- deep-copy x
+  1:number/raw <- get *y, p:offset
+  y2:address:foo <- get *y, q:offset
+  stash y [vs] y2
+  2:boolean/raw <- equal y, y2  # is it still a cycle?
+  3:boolean/raw <- equal x, y  # is it the same cycle?
+]
++mem: storing 34 in location 1
+# deep copy also contains a cycle
++mem: storing 1 in location 2
+# but it's a completely different (disjoint) cycle
++mem: storing 0 in location 3