about summary refs log tree commit diff stats
path: root/037abandon.cc
diff options
context:
space:
mode:
Diffstat (limited to '037abandon.cc')
-rw-r--r--037abandon.cc210
1 files changed, 30 insertions, 180 deletions
diff --git a/037abandon.cc b/037abandon.cc
index 4a1517c5..b60fd946 100644
--- a/037abandon.cc
+++ b/037abandon.cc
@@ -1,11 +1,10 @@
 //: Reclaiming memory when it's no longer used.
-//: The top of the address layer has the complete life cycle of memory.
 
 :(scenario new_reclaim)
 def main [
   1:address:num <- new number:type
   2:num <- copy 1:address:num  # because 1 will get reset during abandon below
-  1:address:num <- copy 0  # abandon
+  abandon 1:address:num
   3:address:num <- new number:type  # must be same size as abandoned memory to reuse
   4:num <- copy 3:address:num
   5:bool <- equal 2:num, 4:num
@@ -13,41 +12,40 @@ def main [
 # both allocations should have returned the same address
 +mem: storing 1 in location 5
 
-:(before "End Decrement Refcount(old_address, payload_type, payload_size)")
-if (old_refcount == 0) {
-  trace("mem") << "automatically abandoning " << old_address << end();
-  abandon(old_address, payload_type, payload_size);
-}
-
 //: When abandoning addresses we'll save them to a 'free list', segregated by size.
 
 :(before "End routine Fields")
 map<int, int> free_list;
 
-:(code)
-void abandon(int address, const type_tree* payload_type, int payload_size) {
-  trace("abandon") << "updating refcounts inside " << address << ": " << to_string(payload_type) << end();
-//?   Total_free += size;
-//?   ++Num_free;
-//?   cerr << "abandon: " << size << '\n';
-  // decrement any contained refcounts
-  if (is_mu_array(payload_type)) {
-    reagent/*local*/ element;
-    element.type = copy_array_element(payload_type);
-    int array_length = get_or_insert(Memory, address+/*skip refcount*/1);
-    assert(element.type->name != "array");
-    int element_size = size_of(element);
-    for (int i = 0;  i < array_length;  ++i) {
-      element.set_value(address + /*skip refcount and length*/2 + i*element_size);
-      decrement_any_refcounts(element);
-    }
+:(before "End Primitive Recipe Declarations")
+ABANDON,
+:(before "End Primitive Recipe Numbers")
+put(Recipe_ordinal, "abandon", ABANDON);
+:(before "End Primitive Recipe Checks")
+case ABANDON: {
+  if (!inst.products.empty()) {
+    raise << maybe(get(Recipe, r).name) << "'abandon' shouldn't write to any products in '" << to_original_string(inst) << "'\n" << end();
+    break;
+  }
+  for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
+    if (!is_mu_address(inst.ingredients.at(i)))
+      raise << maybe(get(Recipe, r).name) << "ingredients of 'abandon' should be addresses, but ingredient " << i << " is '" << to_string(inst.ingredients.at(i)) << '\n' << end();
+    break;
   }
-  else if (is_mu_container(payload_type) || is_mu_exclusive_container(payload_type)) {
-    reagent tmp;
-    tmp.type = new type_tree(*payload_type);
-    tmp.set_value(address + /*skip refcount*/1);
-    decrement_any_refcounts(tmp);
+  break;
+}
+:(before "End Primitive Recipe Implementations")
+case ABANDON: {
+  for (int i = 0;  i < SIZE(current_instruction().ingredients);  ++i) {
+    reagent/*copy*/ ingredient = current_instruction().ingredients.at(i);
+    canonize(ingredient);
+    abandon(get_or_insert(Memory, ingredient.value), payload_size(ingredient));
   }
+  break;
+}
+
+:(code)
+void abandon(int address, int payload_size) {
   // clear memory
   for (int curr = address;  curr < address+payload_size;  ++curr)
     put(Memory, curr, 0);
@@ -77,7 +75,7 @@ if (get_or_insert(Current_routine->free_list, size)) {
 def main [
   1:address:num <- new number:type
   2:num <- copy 1:address:num
-  1:address:num <- copy 0  # abandon
+  abandon 1:address:num
   3:address:array:num <- new number:type, 2  # different size
   4:num <- copy 3:address:array:num
   5:bool <- equal 2:num, 4:num
@@ -89,158 +87,10 @@ def main [
 def main [
   1:address:array:num <- new number:type, 2
   2:num <- copy 1:address:array:num
-  1:address:array:num <- copy 0  # abandon
+  abandon 1:address:array:num
   3:address:array:num <- new number:type, 2  # same size
   4:num <- copy 3:address:array:num
   5:bool <- equal 2:num, 4:num
 ]
 # both calls to new returned identical addresses
 +mem: storing 1 in location 5
-
-:(scenario abandon_on_overwrite)
-def main [
-  1:address:num <- new number:type
-  # over-writing one allocation with another
-  1:address:num <- new number:type
-  1:address:num <- copy 0
-]
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: automatically abandoning 1000
-
-:(scenario abandon_after_call)
-def main [
-  1:address:num <- new number:type
-  # passing in addresses to recipes increments refcount
-  foo 1:address:num
-  1:address:num <- copy 0
-]
-def foo [
-  2:address:num <- next-ingredient
-  # return does NOT yet decrement refcount; memory must be explicitly managed
-  2:address:num <- copy 0
-]
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: foo {1: ("address" "number")}
-# leave ambiguous precisely when the next increment happens
-+mem: incrementing refcount of 1000: 1 -> 2
-+run: {2: ("address" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 2 -> 1
-+run: {1: ("address" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 1 -> 0
-+mem: automatically abandoning 1000
-
-:(scenario abandon_on_overwrite_array)
-def main [
-  1:num <- copy 30
-  # allocate an array
-  10:address:array:num <- new number:type, 20
-  11:num <- copy 10:address:array:num  # doesn't increment refcount
-  # allocate another array in its place, implicitly freeing the previous allocation
-  10:address:array:num <- new number:type, 25
-]
-+run: {10: ("address" "array" "number")} <- new {number: "type"}, {25: "literal"}
-# abandoned array is of old size (20, not 25)
-+abandon: saving 1000 in free-list of size 22
-
-:(scenario refcounts_abandon_address_in_container)
-# container containing an address
-container foo [
-  x:address:num
-]
-def main [
-  1:address:num <- new number:type
-  2:address:foo <- new foo:type
-  *2:address:foo <- put *2:address:foo, x:offset, 1:address:num
-  1:address:num <- copy 0
-  2:address:foo <- copy 0
-]
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: {2: ("address" "foo")} <- new {foo: "type"}
-+mem: incrementing refcount of 1002: 0 -> 1
-+run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
-+mem: incrementing refcount of 1000: 1 -> 2
-+run: {1: ("address" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 2 -> 1
-+run: {2: ("address" "foo")} <- copy {0: "literal"}
-# start abandoning container containing address
-+mem: decrementing refcount of 1002: 1 -> 0
-# nested abandon
-+mem: decrementing refcount of 1000: 1 -> 0
-+abandon: saving 1000 in free-list of size 2
-# actually abandon the container containing address
-+abandon: saving 1002 in free-list of size 2
-
-# todo: move past dilated reagent
-:(scenario refcounts_abandon_address_in_array)
-def main [
-  1:address:num <- new number:type
-  2:address:array:address:num <- new {(address number): type}, 3
-  *2:address:array:address:num <- put-index *2:address:array:address:num, 1, 1:address:num
-  1:address:num <- copy 0
-  2:address:array:address:num <- copy 0
-]
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {1: "literal"}, {1: ("address" "number")}
-+mem: incrementing refcount of 1000: 1 -> 2
-+run: {1: ("address" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 2 -> 1
-+run: {2: ("address" "array" "address" "number")} <- copy {0: "literal"}
-# nested abandon
-+mem: decrementing refcount of 1000: 1 -> 0
-+abandon: saving 1000 in free-list of size 2
-
-:(scenario refcounts_abandon_address_in_container_in_array)
-# container containing an address
-container foo [
-  x:address:num
-]
-def main [
-  1:address:num <- new number:type
-  2:address:array:foo <- new foo:type, 3
-  3:foo <- merge 1:address:num
-  *2:address:array:foo <- put-index *2:address:array:foo, 1, 3:foo
-  1:address:num <- copy 0
-  3:foo <- merge 0
-  2:address:array:foo <- copy 0
-]
-+run: {1: ("address" "number")} <- new {number: "type"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: {3: "foo"} <- merge {1: ("address" "number")}
-+mem: incrementing refcount of 1000: 1 -> 2
-+run: {2: ("address" "array" "foo"), "lookup": ()} <- put-index {2: ("address" "array" "foo"), "lookup": ()}, {1: "literal"}, {3: "foo"}
-+mem: incrementing refcount of 1000: 2 -> 3
-+run: {1: ("address" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 3 -> 2
-+run: {3: "foo"} <- merge {0: "literal"}
-+mem: decrementing refcount of 1000: 2 -> 1
-+run: {2: ("address" "array" "foo")} <- copy {0: "literal"}
-# nested abandon
-+mem: decrementing refcount of 1000: 1 -> 0
-+abandon: saving 1000 in free-list of size 2
-
-:(scenario refcounts_abandon_array_within_container)
-container foo [
-  x:address:array:num
-]
-def main [
-  1:address:array:num <- new number:type, 3
-  2:foo <- merge 1:address:array:num
-  1:address:array:num <- copy 0
-  2:foo <- copy 0
-]
-+run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"}
-+mem: incrementing refcount of 1000: 0 -> 1
-+run: {2: "foo"} <- merge {1: ("address" "array" "number")}
-+mem: incrementing refcount of 1000: 1 -> 2
-+run: {1: ("address" "array" "number")} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 2 -> 1
-+run: {2: "foo"} <- copy {0: "literal"}
-+mem: decrementing refcount of 1000: 1 -> 0
-+mem: automatically abandoning 1000
-# make sure we save it in a free-list of the appropriate size
-+abandon: saving 1000 in free-list of size 5