about summary refs log tree commit diff stats
path: root/043space.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-03-12 20:41:35 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-03-12 20:41:35 -0800
commitd8f2d0b130afd96a4f4f3965686877aa0ad8c11a (patch)
tree991e34e707ae5aca2de631842d68326dd34e7b59 /043space.cc
parent194c4ed71d9f0843cddb61ee7235d8cba05e8855 (diff)
downloadmu-d8f2d0b130afd96a4f4f3965686877aa0ad8c11a.tar.gz
2767 - reclaim refcounts for local variables
This uncovered a second bug (besides 2766) -- I was manually doing the
work of 'new-fake-console' inside 'assume-console' but forgetting to
increment a refcount.
Diffstat (limited to '043space.cc')
-rw-r--r--043space.cc34
1 files changed, 34 insertions, 0 deletions
diff --git a/043space.cc b/043space.cc
index 9ccb287c..cd91bd8d 100644
--- a/043space.cc
+++ b/043space.cc
@@ -211,6 +211,14 @@ def foo [
 # both calls to foo should have received the same default-space
 +mem: storing 1 in location 3
 
+:(scenario local_scope_frees_up_allocations)
+def main [
+  local-scope
+  x:address:shared:array:character <- new [abc]
+]
++mem: clearing x:address:shared:array:character
+
+//: todo: do this in a transform, rather than magically in the reply instruction
 :(after "Falling Through End Of Recipe")
 try_reclaim_locals();
 :(after "Starting Reply")
@@ -231,10 +239,36 @@ void try_reclaim_locals() {
   if (exiting_recipe.steps.empty()) return;
   const instruction& inst = exiting_recipe.steps.at(0);
   if (inst.old_name != "local-scope") return;
+  // reclaim any local variables unless they're being returned
+  vector<double> zero;
+  zero.push_back(0);
+  for (long long int i = /*leave default space for last*/1; i < SIZE(exiting_recipe.steps); ++i) {
+    const instruction& inst = exiting_recipe.steps.at(i);
+    for (long long int i = 0; i < SIZE(inst.products); ++i) {
+      if (!is_mu_address(inst.products.at(i))) continue;
+      // local variables only
+      if (has_property(inst.products.at(i), "space")) continue;
+      if (has_property(inst.products.at(i), "lookup")) continue;
+      if (escaping(inst.products.at(i))) continue;
+      trace(9999, "mem") << "clearing " << inst.products.at(i).original_string << end();
+      write_memory(inst.products.at(i), zero);
+    }
+  }
   abandon(current_call().default_space,
           /*refcount*/1 + /*array length*/1 + /*number-of-locals*/Name[r][""]);
 }
 
+// is this reagent one of the values returned by the current (reply) instruction?
+bool escaping(const reagent& r) {
+  // nothing escapes when you fall through past end of recipe
+  if (current_step_index() >= SIZE(Current_routine->steps())) return false;
+  for (long long i = 0; i < SIZE(current_instruction().ingredients); ++i) {
+    if (r == current_instruction().ingredients.at(i))
+      return true;
+  }
+  return false;
+}
+
 void rewrite_default_space_instruction(instruction& curr) {
   if (!curr.ingredients.empty())
     raise << to_string(curr) << " can't take any ingredients\n" << end();