about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--030container.cc30
-rw-r--r--033exclusive_container.cc6
-rw-r--r--035lookup.cc4
-rw-r--r--036refcount.cc108
-rw-r--r--042name.cc2
-rw-r--r--057shape_shifting_container.cc6
-rw-r--r--078hash.cc12
7 files changed, 133 insertions, 35 deletions
diff --git a/030container.cc b/030container.cc
index d340e131..91fb6407 100644
--- a/030container.cc
+++ b/030container.cc
@@ -169,53 +169,53 @@ if (t.kind == CONTAINER) {
 //: also store a copy in each reagent in each instruction in each recipe
 
 :(after "Begin Instruction Modifying Transforms")  // needs to happen before transform_names, therefore after "End Type Modifying Transforms" below
-Transform.push_back(compute_container_metadata);
+Transform.push_back(compute_container_sizes);
 :(code)
-void compute_container_metadata(recipe_ordinal r) {
+void compute_container_sizes(recipe_ordinal r) {
   recipe& caller = get(Recipe, r);
   for (int i = 0; i < SIZE(caller.steps); ++i) {
     instruction& inst = caller.steps.at(i);
     for (int i = 0; i < SIZE(inst.ingredients); ++i)
-      compute_container_metadata(inst.ingredients.at(i));
+      compute_container_sizes(inst.ingredients.at(i));
     for (int i = 0; i < SIZE(inst.products); ++i)
-      compute_container_metadata(inst.products.at(i));
+      compute_container_sizes(inst.products.at(i));
   }
 }
 
-void compute_container_metadata(reagent& r) {
+void compute_container_sizes(reagent& r) {
   if (is_literal(r) || is_dummy(r)) return;
   reagent rcopy = r;
-  // Compute Container Metadata(reagent rcopy)
+  // Compute Container Size(reagent rcopy)
   set<type_ordinal> pending_metadata;
-  compute_container_metadata(rcopy.type, pending_metadata);
+  compute_container_sizes(rcopy.type, pending_metadata);
   if (contains_key(Container_metadata, rcopy.type))
     r.metadata = get(Container_metadata, rcopy.type);
 }
 
-void compute_container_metadata(const type_tree* type, set<type_ordinal>& pending_metadata) {
+void compute_container_sizes(const type_tree* type, set<type_ordinal>& pending_metadata) {
   if (!type) return;
   if (contains_key(pending_metadata, type->value)) return;
-  pending_metadata.insert(type->value);
+  if (type->value) pending_metadata.insert(type->value);
   if (contains_key(Container_metadata, type)) return;
-  if (type->left) compute_container_metadata(type->left, pending_metadata);
-  if (type->right) compute_container_metadata(type->right, pending_metadata);
+  if (type->left) compute_container_sizes(type->left, pending_metadata);
+  if (type->right) compute_container_sizes(type->right, pending_metadata);
   if (!contains_key(Type, type->value)) return;  // error raised elsewhere
   type_info& info = get(Type, type->value);
   if (info.kind == CONTAINER) {
     container_metadata metadata;
     for (int i = 0; i < SIZE(info.elements); ++i) {
       reagent/*copy*/ element = info.elements.at(i);
-      // Compute Container Metadata(element)
-      compute_container_metadata(element.type, pending_metadata);
+      // Compute Container Size(element)
+      compute_container_sizes(element.type, pending_metadata);
       metadata.offset.push_back(metadata.size);  // save previous size as offset
       metadata.size += size_of(element.type);
     }
     Container_metadata.push_back(pair<type_tree*, container_metadata>(new type_tree(*type), metadata));
   }
-  // End compute_container_metadata Cases
+  // End compute_container_sizes Cases
 }
 
-const container_metadata& get(const vector<pair<type_tree*, container_metadata> >& all, const type_tree* key) {
+container_metadata& get(vector<pair<type_tree*, container_metadata> >& all, const type_tree* key) {
   for (int i = 0; i < SIZE(all); ++i) {
     if (matches(all.at(i).first, key))
       return all.at(i).second;
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index cf55598e..3811fd03 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -35,7 +35,7 @@ if (t.kind == EXCLUSIVE_CONTAINER) {
   // Compute size_of Exclusive Container
   return get(Container_metadata, type).size;
 }
-:(before "End compute_container_metadata Cases")
+:(before "End compute_container_sizes Cases")
 if (info.kind == EXCLUSIVE_CONTAINER) {
   container_metadata metadata;
   // size of an exclusive container is the size of its largest variant
@@ -43,8 +43,8 @@ if (info.kind == EXCLUSIVE_CONTAINER) {
   int size = 0;
   for (int i = 0; i < SIZE(info.elements); ++i) {
     reagent/*copy*/ element = info.elements.at(i);
-    // Compute Exclusive Container Metadata(element)
-    compute_container_metadata(element);
+    // Compute Exclusive Container Size(element)
+    compute_container_sizes(element.type, pending_metadata);
     int variant_size = size_of(element);
     if (variant_size > size) size = variant_size;
   }
diff --git a/035lookup.cc b/035lookup.cc
index 505b4ab7..cc83c9c9 100644
--- a/035lookup.cc
+++ b/035lookup.cc
@@ -143,10 +143,10 @@ canonize_type(product);
 canonize_type(lhs);
 canonize_type(rhs);
 
-:(before "Compute Container Metadata(reagent rcopy)")
+:(before "Compute Container Size(reagent rcopy)")
 if (!canonize_type(rcopy)) return;
 
-:(before "Compute Container Metadata(element)")
+:(before "Compute Container Size(element)")
 assert(!has_property(element, "lookup"));
 
 :(code)
diff --git a/036refcount.cc b/036refcount.cc
index e7d3efc1..9d2f8c99 100644
--- a/036refcount.cc
+++ b/036refcount.cc
@@ -160,3 +160,111 @@ def main [
 :(after "Write Memory in Successful MAYBE_CONVERT")
 if (is_mu_address(product))
   update_refcounts(get_or_insert(Memory, product.value), get_or_insert(Memory, base_address+/*skip tag*/1), payload_size(product));
+
+//: manage refcounts in instructions that copy multiple locations at a time
+
+:(code)
+:(scenario refcounts_copy_nested)
+container foo [
+  x:address:number
+]
+def main [
+  1:address:number <- new number:type
+  2:address:foo <- new foo:type
+  *2:address:foo <- put *2:address:foo, x:offset, 1:address:number
+  3:foo <- copy *2:address:foo
+]
++run: {1: ("address" "number")} <- new {number: "type"}
++mem: incrementing refcount of 1000: 0 -> 1
++run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
++mem: incrementing refcount of 1000: 1 -> 2
+# copying a container increments refcounts of any contained addresses
++run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()}
++mem: incrementing refcount of 1000: 2 -> 3
+
+:(after "Types")
+struct address_element_info {
+  int offset;  // where inside a container type (after flattening nested containers!) the address lies
+  int payload_size;  // size of type it points to
+  address_element_info(int o, int p) {
+    offset = o;
+    payload_size = p;
+  }
+};
+:(before "End container_metadata Fields")
+vector<address_element_info> address;  // list of offsets containing addresses, and the sizes of their corresponding payloads
+
+//: populate metadata.address in a separate transform, because it requires
+//: already knowing the sizes of all types
+
+:(after "Transform.push_back(compute_container_sizes)")
+Transform.push_back(compute_container_address_offsets);
+:(code)
+void compute_container_address_offsets(const recipe_ordinal r) {
+  recipe& caller = get(Recipe, r);
+//?   cerr << "compute offsets " << caller.name <<'\n';
+  for (int i = 0; i < SIZE(caller.steps); ++i) {
+    instruction& inst = caller.steps.at(i);
+    for (int i = 0; i < SIZE(inst.ingredients); ++i)
+      compute_container_address_offsets(inst.ingredients.at(i));
+    for (int i = 0; i < SIZE(inst.products); ++i)
+      compute_container_address_offsets(inst.products.at(i));
+  }
+}
+void compute_container_address_offsets(reagent& r) {
+  if (is_literal(r) || is_dummy(r)) return;
+  compute_container_address_offsets(r.type);
+  if (contains_key(Container_metadata, r.type))
+    r.metadata = get(Container_metadata, r.type);
+}
+void compute_container_address_offsets(type_tree* type) {
+  if (!type) return;
+  if (type->left) compute_container_address_offsets(type->left);
+  if (type->right) compute_container_address_offsets(type->right);
+  if (!contains_key(Type, type->value)) return;  // error raised elsewhere
+  type_info& info = get(Type, type->value);
+  if (info.kind == CONTAINER) {
+//?     cerr << "  " << to_string(type) << '\n';
+    container_metadata& metadata = get(Container_metadata, type);
+    if (!metadata.address.empty()) return;
+    for (int i = 0; i < SIZE(info.elements); ++i) {
+      reagent/*copy*/ element = info.elements.at(i);
+      // Compute Container Address Offset(element)
+      if (is_mu_address(element)) {
+        metadata.address.push_back(address_element_info(metadata.offset.at(i), payload_size(element)));
+//?         cerr << info.name << " has address at offset " << metadata.address.back().offset << '\n';
+      }
+    }
+  }
+}
+
+:(before "End write_memory(x) Special-cases")
+if (is_mu_container(x)) {
+  // Can't recurse here because we have to worry about shape-shifting
+  // containers. Always go off of x.metadata rather than the global
+  // Container_metadata.
+  assert(x.metadata.size);
+  for (int i = 0; i < SIZE(x.metadata.address); ++i) {
+    const address_element_info& info = x.metadata.address.at(i);
+    update_refcounts(get_or_insert(Memory, x.value + info.offset), data.at(info.offset), info.payload_size);
+  }
+}
+
+:(code)
+bool is_mu_container(const reagent& r) {
+  if (r.type->value == 0) return false;
+  type_info& info = get(Type, r.type->value);
+  return info.kind == CONTAINER;
+}
+
+bool is_mu_exclusive_container(const reagent& r) {
+  if (r.type->value == 0) return false;
+  type_info& info = get(Type, r.type->value);
+  return info.kind == EXCLUSIVE_CONTAINER;
+}
+
+// todo:
+//  container containing container containing address
+//  exclusive container sometimes containing address
+//  container containing exclusive container sometimes containing address
+//  ensure the original unguarded write_memory loop is never run
diff --git a/042name.cc b/042name.cc
index 583cd1dc..4857a3c5 100644
--- a/042name.cc
+++ b/042name.cc
@@ -18,7 +18,7 @@ def main [
 +error: main: use before set: y
 # todo: detect conditional defines
 
-:(after "Transform.push_back(compute_container_metadata)")  // we need sizes for all types
+:(after "Transform.push_back(compute_container_sizes)")
 Transform.push_back(transform_names);  // idempotent
 
 :(before "End Globals")
diff --git a/057shape_shifting_container.cc b/057shape_shifting_container.cc
index 183ec36b..07848600 100644
--- a/057shape_shifting_container.cc
+++ b/057shape_shifting_container.cc
@@ -247,9 +247,11 @@ def main [
 
 :(before "End element_type Special-cases")
 replace_type_ingredients(element, type, info);
-:(before "Compute Container Metadata(element)")
+:(before "Compute Container Size(element)")
 replace_type_ingredients(element, type, info);
-:(before "Compute Exclusive Container Metadata(element)")
+:(before "Compute Exclusive Container Size(element)")
+replace_type_ingredients(element, type, info);
+:(before "Compute Container Address Offset(element)")
 replace_type_ingredients(element, type, info);
 :(code)
 void replace_type_ingredients(reagent& element, const type_tree* caller_type, const type_info& info) {
diff --git a/078hash.cc b/078hash.cc
index 6577373d..ce63a87d 100644
--- a/078hash.cc
+++ b/078hash.cc
@@ -88,12 +88,6 @@ size_t hash_mu_array(size_t h, const reagent& r) {
   return h;
 }
 
-bool is_mu_container(const reagent& r) {
-  if (r.type->value == 0) return false;
-  type_info& info = get(Type, r.type->value);
-  return info.kind == CONTAINER;
-}
-
 size_t hash_mu_container(size_t h, const reagent& r) {
   assert(r.type->value);
   type_info& info = get(Type, r.type->value);
@@ -110,12 +104,6 @@ size_t hash_mu_container(size_t h, const reagent& r) {
   return h;
 }
 
-bool is_mu_exclusive_container(const reagent& r) {
-  if (r.type->value == 0) return false;
-  type_info& info = get(Type, r.type->value);
-  return info.kind == EXCLUSIVE_CONTAINER;
-}
-
 size_t hash_mu_exclusive_container(size_t h, const reagent& r) {
   assert(r.type->value);
   int tag = get(Memory, r.value);