about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--071deep_copy.cc89
-rw-r--r--073scheduler.cc25
2 files changed, 84 insertions, 30 deletions
diff --git a/071deep_copy.cc b/071deep_copy.cc
index cc3a3424..d403200b 100644
--- a/071deep_copy.cc
+++ b/071deep_copy.cc
@@ -210,27 +210,33 @@ case DEEP_COPY: {
 }
 :(before "End Primitive Recipe Implementations")
 case DEEP_COPY: {
-  const reagent& input = current_instruction().ingredients.at(0);
+  products.push_back(deep_copy(current_instruction().ingredients.at(0)));
+  break;
+}
+
+:(code)
+vector<double> deep_copy(const reagent& in) {
   // allocate a tiny bit of temporary space for deep_copy()
   trace(9991, "run") << "deep-copy: allocating space for temporary" << end();
   reagent tmp("tmp:address:number");
   tmp.set_value(allocate(1));
-  products.push_back(deep_copy(input, tmp));
+  map<int, int> addresses_copied;
+  vector<double> result = deep_copy(in, addresses_copied, tmp);
   // reclaim Mu memory allocated for tmp
   trace(9991, "run") << "deep-copy: reclaiming temporary" << end();
   abandon(tmp.value, payload_type(tmp.type), payload_size(tmp));
   // reclaim host memory allocated for tmp.type when tmp goes out of scope
-  break;
-}
-
-:(code)
-vector<double> deep_copy(const reagent& in, const reagent& tmp) {
-  map<int, int> addresses_copied;
-  return deep_copy(in, addresses_copied, tmp);
+  return result;
 }
 
 vector<double> deep_copy(reagent/*copy*/ in, map<int, int>& addresses_copied, const reagent& tmp) {
   canonize(in);
+  if (is_mu_address(in)) {
+    // hack: skip primitive containers that do their own locking; they're designed to be shared between routines
+    type_tree* payload = in.type->right;
+    if (payload->left->name == "channel" || payload->left->name == "resources")
+      return read_memory(in);
+  }
   vector<double> result;
   if (is_mu_address(in))
     result.push_back(deep_copy_address(in, addresses_copied, tmp));
@@ -280,6 +286,11 @@ void deep_copy(const reagent& canonized_in, map<int, int>& addresses_copied, con
   for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin();  p != metadata.address.end();  ++p) {
     if (!all_match(data, p->first)) continue;
     for (set<address_element_info>::const_iterator info = p->second.begin();  info != p->second.end();  ++info) {
+      // hack: skip primitive containers that do their own locking; they're designed to be shared between routines
+      if (!info->payload_type->atom && info->payload_type->left->name == "channel")
+        continue;
+      if (info->payload_type->atom && info->payload_type->name == "resources")
+        continue;
       // construct a fake reagent that reads directly from the appropriate
       // field of the container
       reagent curr;
@@ -301,8 +312,6 @@ int payload_address(reagent/*copy*/ x) {
   return x.value;
 }
 
-//: moar tests, just because I can't believe it all works
-
 :(scenario deep_copy_stress_test_1)
 container foo1 [
   p:&:num
@@ -388,3 +397,61 @@ def main [
 +mem: storing 1 in location 2
 # but it's a completely different (disjoint) cycle
 +mem: storing 0 in location 3
+
+:(scenario deep_copy_skips_channel)
+# ugly! dummy 'channel' type if we happen to be building without that layer
+% if (!contains_key(Type_ordinal, "channel")) get_or_insert(Type, put(Type_ordinal, "channel", Next_type_ordinal++)).name = "channel";
+def main [
+  local-scope
+  x:&:channel:num <- new {(channel num): type}
+  y:&:channel:num <- deep-copy x
+  10:bool/raw <- equal x, y
+]
+# channels are never deep-copied
++mem: storing 1 in location 10
+
+:(scenario deep_copy_skips_nested_channel)
+# ugly! dummy 'channel' type if we happen to be building without that layer
+% if (!contains_key(Type_ordinal, "channel")) get_or_insert(Type, put(Type_ordinal, "channel", Next_type_ordinal++)).name = "channel";
+container foo [
+  c:&:channel:num
+]
+def main [
+  local-scope
+  x:&:foo <- new foo:type
+  y:&:foo <- deep-copy x
+  xc:&:channel:num <- get *x, c:offset
+  yc:&:channel:num <- get *y, c:offset
+  10:bool/raw <- equal xc, yc
+]
+# channels are never deep-copied
++mem: storing 1 in location 10
+
+:(scenario deep_copy_skips_resources)
+# ugly! dummy 'resources' type if we happen to be building without that layer
+% if (!contains_key(Type_ordinal, "resources")) get_or_insert(Type, put(Type_ordinal, "resources", Next_type_ordinal++)).name = "resources";
+def main [
+  local-scope
+  x:&:resources <- new resources:type
+  y:&:resources <- deep-copy x
+  10:bool/raw <- equal x, y
+]
+# resources are never deep-copied
++mem: storing 1 in location 10
+
+:(scenario deep_copy_skips_nested_resources)
+# ugly! dummy 'resources' type if we happen to be building without that layer
+% if (!contains_key(Type_ordinal, "resources")) get_or_insert(Type, put(Type_ordinal, "resources", Next_type_ordinal++)).name = "resources";
+container foo [
+  c:&:resources
+]
+def main [
+  local-scope
+  x:&:foo <- new foo:type
+  y:&:foo <- deep-copy x
+  xc:&:resources <- get *x, c:offset
+  yc:&:resources <- get *y, c:offset
+  10:bool/raw <- equal xc, yc
+]
+# resources are never deep-copied
++mem: storing 1 in location 10
diff --git a/073scheduler.cc b/073scheduler.cc
index 962ac915..fb1a3f51 100644
--- a/073scheduler.cc
+++ b/073scheduler.cc
@@ -179,9 +179,10 @@ case START_RUNNING: {
   new_routine->parent_index = Current_routine_index;
   // populate ingredients
   for (int i = /*skip callee*/1;  i < SIZE(current_instruction().ingredients);  ++i) {
-    new_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i));
     reagent/*copy*/ ingredient = current_instruction().ingredients.at(i);
     new_routine->calls.front().ingredients.push_back(ingredient);
+    vector<double> new_ingredient_atoms = deep_copy(ingredient);
+    new_routine->calls.front().ingredient_atoms.push_back(new_ingredient_atoms);
     // End Populate start-running Ingredient
   }
   Routines.push_back(new_routine);
@@ -252,7 +253,7 @@ def f2 n:&:num [
 :(before "End is_indirect_call_with_ingredients Special-cases")
 if (r == START_RUNNING) return true;
 
-//: more complex: refcounting management when starting up new routines
+//: refcounting management when starting up new routines
 
 :(scenario start_running_immediately_updates_refcounts_of_ingredients)
 % Scheduling_interval = 1;
@@ -275,24 +276,10 @@ def new-routine n:&:num [
   load-ingredients
   1:num/raw <- copy *n
 ]
-# check that n wasn't reclaimed when create-new-routine returned
+# check that n was successfully passed into new-routine before being reclaimed
 +mem: storing 34 in location 1
 
-//: to support the previous scenario we'll increment refcounts for all call
-//: ingredients right at call time, and stop incrementing refcounts inside
-//: next-ingredient
-:(before "End Populate Call Ingredient")
-increment_any_refcounts(ingredient, ingredients.at(i));
-:(before "End Populate start-running Ingredient")
-increment_any_refcounts(ingredient, ingredients.at(i));
-:(after "should_update_refcounts() Special-cases When Writing Products Of Primitive Instructions")
-if (inst.operation == NEXT_INGREDIENT || inst.operation == NEXT_INGREDIENT_WITHOUT_TYPECHECKING) {
-  if (space_index(inst.products.at(0)) > 0) return true;
-  if (has_property(inst.products.at(0), "raw")) return true;
-  return false;
-}
-
-// ensure this works with indirect calls using 'call' as well
+//: ensure this works with indirect calls using 'call' as well
 :(scenario start_running_immediately_updates_refcounts_of_ingredients_of_indirect_calls)
 % Scheduling_interval = 1;
 def main [
@@ -306,7 +293,7 @@ def f1 n:&:num [
   local-scope
   load-ingredients
 ]
-# check that n wasn't reclaimed when f1 returned
+# check that n was successfully passed into new-routine before being reclaimed
 +mem: storing 34 in location 1
 
 :(scenario next_ingredient_never_leaks_refcounts)