about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--026call.cc47
-rw-r--r--039location_array.cc46
-rw-r--r--042name.cc7
-rw-r--r--043space.cc70
-rw-r--r--045closure_name.cc4
-rw-r--r--046check_type_by_name.cc17
-rw-r--r--057immutable.cc6
-rw-r--r--073scheduler.cc2
8 files changed, 128 insertions, 71 deletions
diff --git a/026call.cc b/026call.cc
index a82917f1..6b7a14f7 100644
--- a/026call.cc
+++ b/026call.cc
@@ -69,6 +69,8 @@ routine::routine(recipe_ordinal r) {
 
 //:: now update routine's helpers
 
+//: macro versions for a slight speedup
+
 :(delete{} "int& current_step_index()")
 :(delete{} "recipe_ordinal currently_running_recipe()")
 :(delete{} "const string& current_recipe_name()")
@@ -84,6 +86,51 @@ routine::routine(recipe_ordinal r) {
 #define to_instruction(call) get(Recipe, (call).running_recipe).steps.at((call).running_step_index)
 #define current_instruction() to_instruction(current_call())
 
+//: function versions for debugging
+
+:(code)
+//? :(before "End Globals")
+//? bool Foo2 = false;
+//? :(code)
+//? call& current_call() {
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return Current_routine->calls.front();
+//? }
+//? :(replace{} "int& current_step_index()")
+//? int& current_step_index() {
+//?   assert(!Current_routine->calls.empty());
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return current_call().running_step_index;
+//? }
+//? :(replace{} "recipe_ordinal currently_running_recipe()")
+//? recipe_ordinal currently_running_recipe() {
+//?   assert(!Current_routine->calls.empty());
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return current_call().running_recipe;
+//? }
+//? :(replace{} "const string& current_recipe_name()")
+//? const string& current_recipe_name() {
+//?   assert(!Current_routine->calls.empty());
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return get(Recipe, current_call().running_recipe).name;
+//? }
+//? :(replace{} "const recipe& current_recipe()")
+//? const recipe& current_recipe() {
+//?   assert(!Current_routine->calls.empty());
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return get(Recipe, current_call().running_recipe);
+//? }
+//? :(replace{} "const instruction& current_instruction()")
+//? const instruction& current_instruction() {
+//?   assert(!Current_routine->calls.empty());
+//?   if (Foo2) cerr << __FUNCTION__ << '\n';
+//?   return to_instruction(current_call());
+//? }
+//? :(code)
+//? const instruction& to_instruction(const call& call) {
+//?   return get(Recipe, call.running_recipe).steps.at(call.running_step_index);
+//? }
+
 :(after "Defined Recipe Checks")
 // not a primitive; check that it's present in the book of recipes
 if (!contains_key(Recipe, inst.operation)) {
diff --git a/039location_array.cc b/039location_array.cc
deleted file mode 100644
index 1c12d316..00000000
--- a/039location_array.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-:(before "End Primitive Recipe Declarations")
-TO_LOCATION_ARRAY,
-:(before "End Primitive Recipe Numbers")
-put(Recipe_ordinal, "to-location-array", TO_LOCATION_ARRAY);
-:(before "End Primitive Recipe Checks")
-case TO_LOCATION_ARRAY: {
-  const recipe& caller = get(Recipe, r);
-  if (!is_address_of_array_of_numbers(inst.products.at(0))) {
-    raise << maybe(caller.name) << "product of 'to-location-array' has incorrect type: '" << to_original_string(inst) << "'\n" << end();
-    break;
-  }
-  break;
-}
-:(code)
-bool is_address_of_array_of_numbers(reagent/*copy*/ x) {
-  canonize_type(x);
-  if (!is_compound_type_starting_with(x.type, "address")) return false;
-  drop_from_type(x, "address");
-  if (!is_compound_type_starting_with(x.type, "array")) return false;
-  drop_from_type(x, "array");
-  return x.type && x.type->atom && x.type->value == get(Type_ordinal, "number");
-}
-bool is_compound_type_starting_with(const type_tree* type, const string& expected_name) {
-  if (!type) return false;
-  if (type->atom) return false;
-  if (!type->left->atom) return false;
-  return type->left->value == get(Type_ordinal, expected_name);
-}
-
-:(before "End Primitive Recipe Implementations")
-case TO_LOCATION_ARRAY: {
-  int array_size = SIZE(ingredients.at(0));
-  int allocation_size = array_size + /*refcount and length*/2;
-  ensure_space(allocation_size);
-  const int result = Current_routine->alloc;
-  products.resize(1);
-  products.at(0).push_back(result);
-  // initialize array refcount
-  put(Memory, result, 0);
-  // initialize array length
-  put(Memory, result+1, array_size);
-  // now copy over data
-  for (int i = 0;  i < array_size;  ++i)
-    put(Memory, result+2+i, ingredients.at(0).at(i));
-  break;
-}
diff --git a/042name.cc b/042name.cc
index 34e3efe0..6aaf6066 100644
--- a/042name.cc
+++ b/042name.cc
@@ -130,6 +130,13 @@ type_ordinal skip_addresses(type_tree* type) {
   return base_type->left->value;
 }
 
+bool is_compound_type_starting_with(const type_tree* type, const string& expected_name) {
+  if (!type) return false;
+  if (type->atom) return false;
+  if (!type->left->atom) return false;
+  return type->left->value == get(Type_ordinal, expected_name);
+}
+
 int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) {
   const type_info& container = get(Type, t);
   for (int i = 0;  i < SIZE(container.elements);  ++i)
diff --git a/043space.cc b/043space.cc
index 2f11c6c2..ce6e5623 100644
--- a/043space.cc
+++ b/043space.cc
@@ -86,7 +86,9 @@ int address(int offset, int base) {
   int size = get_or_insert(Memory, base);
   if (offset >= size) {
     // todo: test
-    raise << "location " << offset << " is out of bounds " << size << " at " << base << '\n' << end();
+    raise << current_recipe_name() << ": location " << offset << " is out of bounds " << size << " at " << base << '\n' << end();
+    DUMP("");
+    exit(1);
     return 0;
   }
   return base + /*skip length*/1 + offset;
@@ -96,14 +98,19 @@ int address(int offset, int base) {
 
 :(after "Begin Preprocess write_memory(x, data)")
 if (x.name == "default-space") {
-  if (!scalar(data) || !is_space(x))
+  if (!scalar(data) || !is_mu_space(x))
     raise << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but is " << to_string(x.type) << '\n' << end();
   current_call().default_space = data.at(0);
   return;
 }
 :(code)
-bool is_space(const reagent& r) {
-  return is_address_of_array_of_numbers(r);
+bool is_mu_space(reagent/*copy*/ x) {
+  canonize_type(x);
+  if (!is_compound_type_starting_with(x.type, "address")) return false;
+  drop_from_type(x, "address");
+  if (!is_compound_type_starting_with(x.type, "array")) return false;
+  drop_from_type(x, "array");
+  return x.type && x.type->atom && x.type->name == "location";
 }
 
 :(scenario get_default_space)
@@ -237,14 +244,34 @@ reclaim_default_space();
 :(code)
 void reclaim_default_space() {
   if (!Reclaim_memory) return;
-  const recipe_ordinal r = get(Recipe_ordinal, current_recipe_name());
-  const recipe& exiting_recipe = get(Recipe, r);
-  if (!starts_by_setting_default_space(exiting_recipe)) return;
-  // Reclaim default-space
-  decrement_refcount(current_call().default_space,
-      exiting_recipe.steps.at(0).products.at(0).type->right,
-      /*refcount*/1 + /*array length*/1 + /*number-of-locals*/Name[r][""]);
+  reagent default_space("default-space:address:array:location");
+  decrement_any_refcounts(default_space);
 }
+:(after "Begin Decrement Refcounts(canonized_x)")
+if (is_mu_space(canonized_x)) {
+  int space_address = (canonized_x.name == "default-space") ? current_call().default_space : get_or_insert(Memory, canonized_x.value);
+  if (space_address == 0) return;
+  // this branch relies on global state
+  string recipe_name;
+  if (has_property(canonized_x, "names")) {
+    assert(property(canonized_x, "names")->atom);
+    recipe_name = property(canonized_x, "names")->value;
+  }
+  else {
+    if (canonized_x.name != "default-space")
+      cerr << current_recipe_name() << ": " << to_string(canonized_x) << '\n';
+    assert(canonized_x.name == "default-space");
+    recipe_name = current_recipe_name();
+  }
+  const recipe_ordinal space_recipe_ordinal = get(Recipe_ordinal, recipe_name);
+  const recipe& space_recipe = get(Recipe, space_recipe_ordinal);
+  if (canonized_x.name == "default-space" && !has_property(canonized_x, "names") && !starts_by_setting_default_space(space_recipe)) return;
+  // Reclaim Space(space_address, space_recipe_ordinal, space_recipe)
+  decrement_refcount(space_address, canonized_x.type->right,
+      /*refcount*/1 + /*array length*/1 + /*number-of-locals*/Name[space_recipe_ordinal][""]);
+  return;
+}
+:(code)
 bool starts_by_setting_default_space(const recipe& r) {
   return !r.steps.empty()
       && !r.steps.at(0).products.empty()
@@ -263,12 +290,16 @@ def main [
 # local-scope
 +mem: automatically abandoning 1000
 
-:(before "Reclaim default-space")
-if (get_or_insert(Memory, current_call().default_space) <= 1) {
+:(before "Reclaim Space(space_address, space_recipe_ordinal, space_recipe)")
+if (get_or_insert(Memory, space_address) <= 1) {
   set<string> reclaimed_locals;
   trace(9999, "mem") << "trying to reclaim locals" << end();
-  for (int i = /*leave default space for last*/1;  i < SIZE(exiting_recipe.steps);  ++i) {
-    const instruction& inst = exiting_recipe.steps.at(i);
+  // update any refcounts for variables in the space -- in the context of the space
+  call_stack calls_stash = save_call_stack(space_address, space_recipe_ordinal);
+  Current_routine->calls.swap(calls_stash);
+  // no early returns until we restore 'calls' below
+  for (int i = /*leave default space for last*/1;  i < SIZE(space_recipe.steps);  ++i) {
+    const instruction& inst = space_recipe.steps.at(i);
     for (int i = 0;  i < SIZE(inst.products);  ++i) {
       reagent/*copy*/ product = inst.products.at(i);
       if (reclaimed_locals.find(product.name) != reclaimed_locals.end()) continue;
@@ -282,6 +313,15 @@ if (get_or_insert(Memory, current_call().default_space) <= 1) {
       decrement_any_refcounts(product);
     }
   }
+  Current_routine->calls.swap(calls_stash);  // restore
+}
+:(code)
+call_stack save_call_stack(int space_address, recipe_ordinal space_recipe_ordinal) {
+  call dummy_call(space_recipe_ordinal);
+  dummy_call.default_space = space_address;
+  call_stack result;
+  result.push_front(dummy_call);
+  return result;
 }
 
 :(scenario local_variables_can_outlive_call)
diff --git a/045closure_name.cc b/045closure_name.cc
index f7c0082f..0f67e2d2 100644
--- a/045closure_name.cc
+++ b/045closure_name.cc
@@ -47,7 +47,7 @@ void collect_surrounding_spaces(const recipe_ordinal r) {
     for (int j = 0;  j < SIZE(inst.products);  ++j) {
       if (is_literal(inst.products.at(j))) continue;
       if (inst.products.at(j).name != "0") continue;
-      if (!is_space(inst.products.at(j))) {
+      if (!is_mu_space(inst.products.at(j))) {
         raise << "slot 0 should always have type address:array:location, but is '" << to_string(inst.products.at(j)) << "'\n" << end();
         continue;
       }
@@ -159,7 +159,7 @@ def new-scope [
 ]
 def use-scope [
   local-scope
-  outer:space <- next-ingredient
+  outer:space/names:new-scope <- next-ingredient
   0:space/names:new-scope <- copy outer:space
   return *x:&:num/space:1
 ]
diff --git a/046check_type_by_name.cc b/046check_type_by_name.cc
index 83b80571..3fd3fdd6 100644
--- a/046check_type_by_name.cc
+++ b/046check_type_by_name.cc
@@ -25,25 +25,34 @@ void check_or_set_types_by_name(const recipe_ordinal r) {
   for (int i = 0;  i < SIZE(caller.steps);  ++i) {
     instruction& inst = caller.steps.at(i);
     for (int in = 0;  in < SIZE(inst.ingredients);  ++in) {
-      deduce_missing_type(known, inst.ingredients.at(in));
+      deduce_missing_type(known, inst.ingredients.at(in), caller);
       check_type(known, inst.ingredients.at(in), caller);
     }
     for (int out = 0;  out < SIZE(inst.products);  ++out) {
-      deduce_missing_type(known, inst.products.at(out));
+      deduce_missing_type(known, inst.products.at(out), caller);
       check_type(known, inst.products.at(out), caller);
     }
   }
 }
 
-void deduce_missing_type(set<reagent>& known, reagent& x) {
+void deduce_missing_type(set<reagent>& known, reagent& x, const recipe& caller) {
   if (x.type) return;
   if (is_jump_target(x.name)) {
     x.type = new type_tree("label");
     return;
   }
   if (known.find(x) == known.end()) return;
-  x.type = new type_tree(*known.find(x)->type);
+  const reagent& exemplar = *known.find(x);
+  x.type = new type_tree(*exemplar.type);
   trace(9992, "transform") << x.name << " <= " << names_to_string(x.type) << end();
+  // spaces are special; their type includes their /names property
+  if (is_mu_space(x) && !has_property(x, "names")) {
+    if (!has_property(exemplar, "names")) {
+      raise << maybe(caller.name) << "missing /names property for space variable '" << exemplar.name << "'\n" << end();
+      return;
+    }
+    x.properties.push_back(pair<string, string_tree*>("names", new string_tree(*property(exemplar, "names"))));
+  }
 }
 
 void check_type(set<reagent>& known, const reagent& x, const recipe& caller) {
diff --git a/057immutable.cc b/057immutable.cc
index 4657ade0..6cfcacef 100644
--- a/057immutable.cc
+++ b/057immutable.cc
@@ -316,16 +316,16 @@ def bar [
 //: when checking for immutable ingredients, remember to take space into account
 :(scenario check_space_of_reagents_in_immutability_checks)
 def main [
-  a:space <- new-closure
+  a:space/names:new-closure <- new-closure
   b:&:num <- new number:type
   run-closure b:&:num, a:space
 ]
 def new-closure [
   local-scope
   x:&:num <- new number:type
-  return default-space
+  return default-space/names:new-closure
 ]
-def run-closure x:&:num, s:space [
+def run-closure x:&:num, s:space/names:new-closure [
   local-scope
   load-ingredients
   0:space/names:new-closure <- copy s
diff --git a/073scheduler.cc b/073scheduler.cc
index fb1a3f51..d9ebef51 100644
--- a/073scheduler.cc
+++ b/073scheduler.cc
@@ -313,7 +313,7 @@ def main [
   local-scope
   n:&:num <- copy 12000/unsafe  # pretend allocation with a known address
   *n <- copy 23
-  space:space <- create-space n
+  space:space/names:create-space <- create-space n
   n2:&:num <- copy 13000/unsafe
   n3:num <- use-space space, n2
 ]