about summary refs log tree commit diff stats
path: root/030container.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-06-15 22:12:03 -0700
committerKartik Agaram <vc@akkartik.com>2018-06-15 22:12:03 -0700
commit0edd9b9fc60440213e4df926ea511419ee291f1e (patch)
tree84b22f7afdeb9110ad7105c5fc070dacff178502 /030container.cc
parent3f34ac9369978b396d00a4fd02c9fb06b8eea621 (diff)
downloadmu-0edd9b9fc60440213e4df926ea511419ee291f1e.tar.gz
4257 - abortive attempt at safe fat pointers
I've been working on this slowly over several weeks, but it's too hard
to support 0 as the null value for addresses. I constantly have to add
exceptions for scalar value corresponding to an address type (now
occupying 2 locations). The final straw is the test for 'reload':

  x:num <- reload text

'reload' returns an address. But there's no way to know that for
arbitrary instructions.

New plan: let's put this off for a bit and first create support for
literals. Then use 'null' instead of '0' for addresses everywhere. Then
it'll be easy to just change what 'null' means.
Diffstat (limited to '030container.cc')
-rw-r--r--030container.cc49
1 files changed, 41 insertions, 8 deletions
diff --git a/030container.cc b/030container.cc
index f4aaafd4..b722e711 100644
--- a/030container.cc
+++ b/030container.cc
@@ -7,14 +7,16 @@ get_or_insert(Type, point);  // initialize
 get(Type, point).kind = CONTAINER;
 get(Type, point).name = "point";
 get(Type, point).elements.push_back(reagent("x:number"));
+get(Type, point).elements.back().set_value(0);
 get(Type, point).elements.push_back(reagent("y:number"));
+get(Type, point).elements.back().set_value(1);
 
 //: Containers can be copied around with a single instruction just like
 //: numbers, no matter how large they are.
 
 //: Tests in this layer often explicitly set up memory before reading it as a
-//: container. Don't do this in general. I'm tagging such cases with /unsafe;
-//: they'll be exceptions to later checks.
+//: container. Don't do this in general. I'm tagging exceptions with /unsafe to
+//: skip later checks.
 :(scenario copy_multiple_locations)
 def main [
   1:num <- copy 34
@@ -40,7 +42,9 @@ get_or_insert(Type, point_number);  // initialize
 get(Type, point_number).kind = CONTAINER;
 get(Type, point_number).name = "point-number";
 get(Type, point_number).elements.push_back(reagent("xy:point"));
+get(Type, point_number).elements.back().set_value(0);
 get(Type, point_number).elements.push_back(reagent("z:number"));
+get(Type, point_number).elements.back().set_value(1);
 
 :(scenario copy_handles_nested_container_elements)
 def main [
@@ -127,6 +131,10 @@ def main [
 //: 'get' takes a 'base' container and an 'offset' into it and returns the
 //: appropriate element of the container value.
 
+//: The offset is different from the distance (in memory locations) an element
+//: is at from the start. This is because elements can occupy multiple memory
+//: locations in the container.
+
 :(scenario get)
 def main [
   12:num <- copy 34
@@ -195,9 +203,7 @@ case GET: {
   // Update GET base_type in Run
   int offset = ingredients.at(1).at(0);
   if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break;  // copied from Check above
-  int src = base_address;
-  for (int i = 0; i < offset; ++i)
-    src += size_of(element_type(base.type, i));
+  int src = element_location(base_address, offset, base.type);
   trace(9998, "run") << "address to copy is " << src << end();
   //: use base.type rather than base_type because later layers will introduce compound types
   reagent/*copy*/ element = element_type(base.type, offset);
@@ -222,6 +228,12 @@ const reagent element_type(const type_tree* type, int offset_value) {
   // End element_type Special-cases
   return element;
 }
+int element_location(int base_address, int offset, const type_tree* type) {
+  int result = base_address;
+  for (int i = 0; i < offset; ++i)
+    result += size_of(element_type(type, i));
+  return result;
+}
 
 :(scenario get_handles_nested_container_elements)
 def main [
@@ -352,14 +364,17 @@ case PUT: {
   // Update PUT base_type in Run
   int offset = ingredients.at(1).at(0);
   if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break;  // copied from Check above
-  int address = base_address;
-  for (int i = 0; i < offset; ++i)
-    address += size_of(element_type(base.type, i));
+  int address = element_location(base_address, offset, base.type);
   trace(9998, "run") << "address to copy to is " << address << end();
   // optimization: directly write the element rather than updating 'product'
   // and writing the entire container
   // Write Memory in PUT in Run
   write_products = false;
+  if (is_mu_address(element_type(base.type, offset)) && is_literal(current_instruction().ingredients.at(2)) && current_instruction().ingredients.at(2).name == "0") {
+    trace("mem") << "storing 0 in location " << address << end();
+    put(Memory, address, /*alloc id*/0);
+    ++address;
+  }
   for (int i = 0;  i < SIZE(ingredients.at(2));  ++i) {
     trace("mem") << "storing " << no_scientific(ingredients.at(2).at(i)) << " in location " << address+i << end();
     put(Memory, address+i, ingredients.at(2).at(i));
@@ -377,6 +392,23 @@ def main [
 ]
 +error: main: product of 'put' must be first ingredient '1:point', but got '3:point'
 
+:(scenario put_null_address)
+container foo [
+  x:num
+  y:&:num
+  z:num
+]
+def main [
+  1:num <- copy 34
+  2:num <- copy 0  # alloc id
+  3:num <- copy 1000  # pretend address
+  4:num <- copy 36
+  put 1:foo, y:offset, 0
+]
++run: put {1: "foo"}, {y: "offset"}, {0: "literal"}
++mem: storing 0 in location 2
++mem: storing 0 in location 3
+
 //:: Allow containers to be defined in Mu code.
 
 :(scenarios load)
@@ -490,6 +522,7 @@ void insert_container(const string& command, kind_of_type kind, istream& in) {
       break;
     }
     info.elements.push_back(reagent(element));
+    info.elements.back().set_value(SIZE(info.elements)-1);
     expand_type_abbreviations(info.elements.back().type);  // todo: use abbreviation before declaration
     replace_unknown_types_with_unique_ordinals(info.elements.back().type, info);
     trace(9993, "parse") << "  element: " << to_string(info.elements.back()) << end();