From 4945e77a58f3ab10069461e86e5e10c06e91e489 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 29 May 2017 02:25:10 -0700 Subject: 3895 --- html/036refcount.cc.html | 2005 +++++++++++++++++++++++----------------------- 1 file changed, 1023 insertions(+), 982 deletions(-) (limited to 'html/036refcount.cc.html') diff --git a/html/036refcount.cc.html b/html/036refcount.cc.html index 7062c73c..1be5a322 100644 --- a/html/036refcount.cc.html +++ b/html/036refcount.cc.html @@ -97,7 +97,7 @@ if ('onhashchange' in window) { 32 if (!Reclaim_memory) return; 33 if (!should_update_refcounts()) return; 34 increment_any_refcounts(canonized_x, data); // increment first so we don't reclaim on x <- copy x - 35 decrement_any_refcounts(canonized_x); + 35 decrement_any_refcounts(canonized_x); 36 } 37 38 //: escape hatch for a later layer @@ -118,989 +118,1030 @@ if ('onhashchange' in window) { 53 void increment_refcount(int new_address) { 54 assert(new_address >= 0); 55 if (new_address == 0) return; - 56 int new_refcount = get_or_insert(Memory, new_address); - 57 trace(9999, "mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end(); - 58 put(Memory, new_address, new_refcount+1); - 59 } - 60 - 61 void decrement_any_refcounts(const reagent& canonized_x) { - 62 if (is_mu_address(canonized_x)) { - 63 ¦ assert(canonized_x.value); - 64 ¦ assert(!canonized_x.metadata.size); - 65 ¦ decrement_refcount(get_or_insert(Memory, canonized_x.value), payload_type(canonized_x.type), payload_size(canonized_x)); - 66 } - 67 // End Decrement Refcounts(canonized_x) - 68 } - 69 - 70 void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) { - 71 assert(old_address >= 0); - 72 if (old_address == 0) return; - 73 int old_refcount = get_or_insert(Memory, old_address); - 74 trace(9999, "mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end(); - 75 --old_refcount; - 76 put(Memory, old_address, old_refcount); - 77 if (old_refcount < 0) { - 78 ¦ tb_shutdown(); - 79 ¦ cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n'; - 80 ¦ if (Trace_stream) { - 81 ¦ ¦ cerr << "Saving trace to last_trace.\n"; - 82 ¦ ¦ ofstream fout("last_trace"); - 83 ¦ ¦ fout << Trace_stream->readable_contents(""); - 84 ¦ ¦ fout.close(); - 85 ¦ } - 86 ¦ exit(0); - 87 } - 88 // End Decrement Refcount(old_address, payload_type, payload_size) - 89 } - 90 - 91 int payload_size(reagent/*copy*/ x) { - 92 x.properties.push_back(pair<string, string_tree*>("lookup", NULL)); - 93 lookup_memory_core(x, /*check for nulls*/false); - 94 return size_of(x) + /*refcount*/1; - 95 } - 96 - 97 :(scenario refcounts_reflexive) - 98 def main [ - 99 1:address:num <- new number:type - 100 # idempotent copies leave refcount unchanged - 101 1:address:num <- copy 1:address:num - 102 ] - 103 +run: {1: ("address" "number")} <- new {number: "type"} - 104 +mem: incrementing refcount of 1000: 0 -> 1 - 105 +run: {1: ("address" "number")} <- copy {1: ("address" "number")} - 106 +mem: incrementing refcount of 1000: 1 -> 2 - 107 +mem: decrementing refcount of 1000: 2 -> 1 - 108 - 109 :(scenario refcounts_call) - 110 def main [ - 111 1:address:num <- new number:type - 112 # passing in addresses to recipes increments refcount - 113 foo 1:address:num - 114 # return does NOT yet decrement refcount; memory must be explicitly managed - 115 1:address:num <- new number:type - 116 ] - 117 def foo [ - 118 2:address:num <- next-ingredient - 119 ] - 120 +run: {1: ("address" "number")} <- new {number: "type"} - 121 +mem: incrementing refcount of 1000: 0 -> 1 - 122 +run: foo {1: ("address" "number")} - 123 # leave ambiguous precisely when the next increment happens - 124 +mem: incrementing refcount of 1000: 1 -> 2 - 125 +run: {1: ("address" "number")} <- new {number: "type"} - 126 +mem: decrementing refcount of 1000: 2 -> 1 - 127 - 128 //: fix up any instructions that don't follow the usual flow of read_memory - 129 //: before the RUN switch, and write_memory after - 130 - 131 :(scenario refcounts_put) - 132 container foo [ - 133 x:address:num - 134 ] - 135 def main [ - 136 1:address:num <- new number:type - 137 2:address:foo <- new foo:type - 138 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num - 139 ] - 140 +run: {1: ("address" "number")} <- new {number: "type"} - 141 +mem: incrementing refcount of 1000: 0 -> 1 - 142 +run: {2: ("address" "foo")} <- new {foo: "type"} - 143 +mem: incrementing refcount of 1002: 0 -> 1 - 144 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} - 145 # put increments refcount - 146 +mem: incrementing refcount of 1000: 1 -> 2 - 147 - 148 :(after "Write Memory in PUT in Run") - 149 reagent/*copy*/ element = element_type(base.type, offset); - 150 assert(!has_property(element, "lookup")); - 151 element.set_value(address); - 152 update_any_refcounts(element, ingredients.at(2)); - 153 - 154 :(scenario refcounts_put_index) - 155 def main [ - 156 1:address:num <- new number:type - 157 2:address:array:address:num <- new {(address number): type}, 3 - 158 *2:address:array:address:num <- put-index *2:address:array:address:num, 0, 1:address:num - 159 ] - 160 +run: {1: ("address" "number")} <- new {number: "type"} - 161 +mem: incrementing refcount of 1000: 0 -> 1 - 162 +run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"} - 163 +mem: incrementing refcount of 1002: 0 -> 1 - 164 +run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")} - 165 # put-index increments refcount - 166 +mem: incrementing refcount of 1000: 1 -> 2 - 167 - 168 :(after "Write Memory in PUT_INDEX in Run") - 169 reagent/*local*/ element; - 170 element.set_value(address); - 171 element.type = copy_array_element(base.type); - 172 update_any_refcounts(element, value); - 173 - 174 :(scenario refcounts_maybe_convert) - 175 exclusive-container foo [ - 176 x:num - 177 p:address:num - 178 ] - 179 def main [ - 180 1:address:num <- new number:type - 181 2:foo <- merge 1/p, 1:address:num - 182 4:address:num, 5:bool <- maybe-convert 2:foo, 1:variant/p - 183 ] - 184 +run: {1: ("address" "number")} <- new {number: "type"} - 185 +mem: incrementing refcount of 1000: 0 -> 1 - 186 # merging in an address increments refcount - 187 +run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")} - 188 +mem: incrementing refcount of 1000: 1 -> 2 - 189 +run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()} - 190 # maybe-convert increments refcount on success - 191 +mem: incrementing refcount of 1000: 2 -> 3 - 192 - 193 :(after "Write Memory in Successful MAYBE_CONVERT") - 194 // todo: double-check data here as well - 195 vector<double> data; - 196 for (int i = 0; i < size_of(product); ++i) - 197 data.push_back(get_or_insert(Memory, base_address+/*skip tag*/1+i)); - 198 update_any_refcounts(product, data); - 199 - 200 //:: manage refcounts in instructions that copy multiple locations at a time + 56 ++Total_refcount_updates; + 57 int new_refcount = get_or_insert(Memory, new_address); + 58 trace(9999, "mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end(); + 59 put(Memory, new_address, new_refcount+1); + 60 } + 61 + 62 void decrement_any_refcounts(const reagent& canonized_x) { + 63 if (is_mu_address(canonized_x)) { + 64 ¦ assert(canonized_x.value); + 65 ¦ assert(!canonized_x.metadata.size); + 66 ¦ decrement_refcount(get_or_insert(Memory, canonized_x.value), payload_type(canonized_x.type), payload_size(canonized_x)); + 67 } + 68 // End Decrement Refcounts(canonized_x) + 69 } + 70 + 71 void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) { + 72 assert(old_address >= 0); + 73 if (old_address == 0) return; + 74 ++Total_refcount_updates; + 75 int old_refcount = get_or_insert(Memory, old_address); + 76 trace(9999, "mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end(); + 77 --old_refcount; + 78 put(Memory, old_address, old_refcount); + 79 if (old_refcount < 0) { + 80 ¦ tb_shutdown(); + 81 ¦ cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n'; + 82 ¦ if (Trace_stream) { + 83 ¦ ¦ cerr << "Saving trace to last_trace.\n"; + 84 ¦ ¦ ofstream fout("last_trace"); + 85 ¦ ¦ fout << Trace_stream->readable_contents(""); + 86 ¦ ¦ fout.close(); + 87 ¦ } + 88 ¦ exit(0); + 89 } + 90 // End Decrement Refcount(old_address, payload_type, payload_size) + 91 } + 92 + 93 int payload_size(reagent/*copy*/ x) { + 94 x.properties.push_back(pair<string, string_tree*>("lookup", NULL)); + 95 lookup_memory_core(x, /*check for nulls*/false); + 96 return size_of(x) + /*refcount*/1; + 97 } + 98 + 99 :(scenario refcounts_reflexive) + 100 def main [ + 101 1:address:num <- new number:type + 102 # idempotent copies leave refcount unchanged + 103 1:address:num <- copy 1:address:num + 104 ] + 105 +run: {1: ("address" "number")} <- new {number: "type"} + 106 +mem: incrementing refcount of 1000: 0 -> 1 + 107 +run: {1: ("address" "number")} <- copy {1: ("address" "number")} + 108 +mem: incrementing refcount of 1000: 1 -> 2 + 109 +mem: decrementing refcount of 1000: 2 -> 1 + 110 + 111 :(scenario refcounts_call) + 112 def main [ + 113 1:address:num <- new number:type + 114 # passing in addresses to recipes increments refcount + 115 foo 1:address:num + 116 # return does NOT yet decrement refcount; memory must be explicitly managed + 117 1:address:num <- new number:type + 118 ] + 119 def foo [ + 120 2:address:num <- next-ingredient + 121 ] + 122 +run: {1: ("address" "number")} <- new {number: "type"} + 123 +mem: incrementing refcount of 1000: 0 -> 1 + 124 +run: foo {1: ("address" "number")} + 125 # leave ambiguous precisely when the next increment happens + 126 +mem: incrementing refcount of 1000: 1 -> 2 + 127 +run: {1: ("address" "number")} <- new {number: "type"} + 128 +mem: decrementing refcount of 1000: 2 -> 1 + 129 + 130 //: fix up any instructions that don't follow the usual flow of read_memory + 131 //: before the RUN switch, and write_memory after + 132 + 133 :(scenario refcounts_put) + 134 container foo [ + 135 x:address:num + 136 ] + 137 def main [ + 138 1:address:num <- new number:type + 139 2:address:foo <- new foo:type + 140 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num + 141 ] + 142 +run: {1: ("address" "number")} <- new {number: "type"} + 143 +mem: incrementing refcount of 1000: 0 -> 1 + 144 +run: {2: ("address" "foo")} <- new {foo: "type"} + 145 +mem: incrementing refcount of 1002: 0 -> 1 + 146 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} + 147 # put increments refcount + 148 +mem: incrementing refcount of 1000: 1 -> 2 + 149 + 150 :(after "Write Memory in PUT in Run") + 151 reagent/*copy*/ element = element_type(base.type, offset); + 152 assert(!has_property(element, "lookup")); + 153 element.set_value(address); + 154 update_any_refcounts(element, ingredients.at(2)); + 155 + 156 :(scenario refcounts_put_index) + 157 def main [ + 158 1:address:num <- new number:type + 159 2:address:array:address:num <- new {(address number): type}, 3 + 160 *2:address:array:address:num <- put-index *2:address:array:address:num, 0, 1:address:num + 161 ] + 162 +run: {1: ("address" "number")} <- new {number: "type"} + 163 +mem: incrementing refcount of 1000: 0 -> 1 + 164 +run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"} + 165 +mem: incrementing refcount of 1002: 0 -> 1 + 166 +run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")} + 167 # put-index increments refcount + 168 +mem: incrementing refcount of 1000: 1 -> 2 + 169 + 170 :(after "Write Memory in PUT_INDEX in Run") + 171 reagent/*local*/ element; + 172 element.set_value(address); + 173 element.type = copy_array_element(base.type); + 174 update_any_refcounts(element, value); + 175 + 176 :(scenario refcounts_maybe_convert) + 177 exclusive-container foo [ + 178 x:num + 179 p:address:num + 180 ] + 181 def main [ + 182 1:address:num <- new number:type + 183 2:foo <- merge 1/p, 1:address:num + 184 4:address:num, 5:bool <- maybe-convert 2:foo, 1:variant/p + 185 ] + 186 +run: {1: ("address" "number")} <- new {number: "type"} + 187 +mem: incrementing refcount of 1000: 0 -> 1 + 188 # merging in an address increments refcount + 189 +run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")} + 190 +mem: incrementing refcount of 1000: 1 -> 2 + 191 +run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()} + 192 # maybe-convert increments refcount on success + 193 +mem: incrementing refcount of 1000: 2 -> 3 + 194 + 195 :(after "Write Memory in Successful MAYBE_CONVERT") + 196 // todo: double-check data here as well + 197 vector<double> data; + 198 for (int i = 0; i < size_of(product); ++i) + 199 data.push_back(get_or_insert(Memory, base_address+/*skip tag*/1+i)); + 200 update_any_refcounts(product, data); 201 - 202 :(scenario refcounts_copy_nested) - 203 container foo [ - 204 x:address:num # address inside container - 205 ] - 206 def main [ - 207 1:address:num <- new number:type - 208 2:address:foo <- new foo:type - 209 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num - 210 3:foo <- copy *2:address:foo - 211 ] - 212 +transform: compute address offsets for container foo - 213 +transform: checking container foo, element 0 - 214 +transform: address at offset 0 - 215 +run: {1: ("address" "number")} <- new {number: "type"} - 216 +mem: incrementing refcount of 1000: 0 -> 1 - 217 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} - 218 +mem: incrementing refcount of 1000: 1 -> 2 - 219 # copying a container increments refcounts of any contained addresses - 220 +run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()} - 221 +mem: incrementing refcount of 1000: 2 -> 3 - 222 - 223 :(before "End type_tree Definition") - 224 struct address_element_info { - 225 // Where inside a container type (after flattening nested containers!) the - 226 // address lies - 227 int offset; - 228 - 229 // All the information we need to compute sizes of items inside an address - 230 // inside a container. `payload_type` Doesn't need to be a full-scale - 231 // reagent, since an address inside a container can never be an array, and - 232 // arrays are the only type that need to know their location to compute their - 233 // size. - 234 const type_tree* payload_type; - 235 - 236 address_element_info(int o, const type_tree* p); - 237 address_element_info(const address_element_info& other); - 238 ~address_element_info(); - 239 address_element_info& operator=(const address_element_info& other); - 240 }; - 241 :(code) - 242 address_element_info::address_element_info(int o, const type_tree* p) { - 243 offset = o; - 244 payload_type = p; - 245 } - 246 address_element_info::address_element_info(const address_element_info& other) { - 247 offset = other.offset; - 248 payload_type = copy(other.payload_type); - 249 } - 250 address_element_info::~address_element_info() { - 251 if (payload_type) { - 252 ¦ delete payload_type; - 253 ¦ payload_type = NULL; - 254 } - 255 } - 256 address_element_info& address_element_info::operator=(const address_element_info& other) { - 257 offset = other.offset; - 258 if (payload_type) delete payload_type; - 259 payload_type = copy(other.payload_type); - 260 return *this; - 261 } - 262 - 263 :(before "End type_tree Definition") - 264 // For exclusive containers we might sometimes have an address at some offset - 265 // if some other offset has a specific tag. This struct encapsulates such - 266 // guards. - 267 struct tag_condition_info { - 268 int offset; - 269 int tag; - 270 tag_condition_info(int o, int t) :offset(o), tag(t) {} - 271 }; - 272 - 273 :(before "End container_metadata Fields") - 274 // a list of facts of the form: - 275 // - 276 // IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN - 277 // for all address_element_infos: - 278 // you need to update refcounts for the address at offset pointing to a payload of type payload_type (just in case we need to abandon something in the process) - 279 map<set<tag_condition_info>, set<address_element_info> > address; - 280 :(code) - 281 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) { - 282 if (a.size() != b.size()) return a.size() < b.size(); - 283 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { - 284 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; - 285 ¦ if (pa->tag != pb->tag) return pa->tag < pb->tag; - 286 } - 287 return false; // equal - 288 } - 289 bool operator<(const tag_condition_info& a, const tag_condition_info& b) { - 290 if (a.offset != b.offset) return a.offset < b.offset; - 291 if (a.tag != b.tag) return a.tag < b.tag; - 292 return false; // equal - 293 } - 294 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) { - 295 if (a.size() != b.size()) return a.size() < b.size(); - 296 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { - 297 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; - 298 } - 299 return false; // equal - 300 } - 301 bool operator<(const address_element_info& a, const address_element_info& b) { - 302 if (a.offset != b.offset) return a.offset < b.offset; - 303 return false; // equal - 304 } - 305 - 306 //: populate metadata.address in a separate transform, because it requires - 307 //: already knowing the sizes of all types - 308 - 309 :(after "Transform.push_back(compute_container_sizes)") - 310 Transform.push_back(compute_container_address_offsets); // idempotent - 311 :(code) - 312 void compute_container_address_offsets(const recipe_ordinal r) { - 313 recipe& caller = get(Recipe, r); - 314 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end(); - 315 for (int i = 0; i < SIZE(caller.steps); ++i) { - 316 ¦ instruction& inst = caller.steps.at(i); - 317 ¦ trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end(); - 318 ¦ for (int i = 0; i < SIZE(inst.ingredients); ++i) - 319 ¦ ¦ compute_container_address_offsets(inst.ingredients.at(i), " in '"+inst.original_string+"'"); - 320 ¦ for (int i = 0; i < SIZE(inst.products); ++i) - 321 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+inst.original_string+"'"); - 322 } - 323 } - 324 - 325 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) { - 326 if (is_literal(r) || is_dummy(r)) return; - 327 compute_container_address_offsets(r.type, location_for_error_messages); - 328 if (contains_key(Container_metadata, r.type)) - 329 ¦ r.metadata = get(Container_metadata, r.type); - 330 } - 331 - 332 // the recursive structure of this function needs to exactly match - 333 // compute_container_sizes - 334 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) { - 335 if (!type) return; - 336 if (!type->atom) { - 337 ¦ if (!type->left->atom) { - 338 ¦ ¦ raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end(); - 339 ¦ ¦ return; - 340 ¦ } - 341 ¦ if (type->left->name == "address") - 342 ¦ ¦ compute_container_address_offsets(payload_type(type), location_for_error_messages); - 343 ¦ else if (type->left->name == "array") - 344 ¦ ¦ compute_container_address_offsets(array_element(type), location_for_error_messages); - 345 ¦ // End compute_container_address_offsets Non-atom Special-cases - 346 } - 347 const type_tree* base_type = type; - 348 // Update base_type in compute_container_address_offsets - 349 if (!contains_key(Type, base_type->value)) return; // error raised elsewhere - 350 type_info& info = get(Type, base_type->value); - 351 if (info.kind == CONTAINER) { - 352 ¦ compute_container_address_offsets(info, type, location_for_error_messages); - 353 } - 354 if (info.kind == EXCLUSIVE_CONTAINER) { - 355 ¦ compute_exclusive_container_address_offsets(info, type, location_for_error_messages); - 356 } - 357 } - 358 - 359 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) { - 360 container_metadata& metadata = get(Container_metadata, full_type); - 361 if (!metadata.address.empty()) return; - 362 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end(); - 363 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages); - 364 } - 365 - 366 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) { - 367 container_metadata& metadata = get(Container_metadata, full_type); - 368 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end(); - 369 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) { - 370 ¦ set<tag_condition_info> key; - 371 ¦ key.insert(tag_condition_info(/*tag is at offset*/0, tag)); - 372 ¦ append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages); - 373 } - 374 } - 375 - 376 void append_addresses(int base_offset, const type_tree* type, map<set<tag_condition_info>, set<address_element_info> >& out, const set<tag_condition_info>& key, const string& location_for_error_messages) { - 377 if (is_mu_address(type)) { - 378 ¦ get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type)))); - 379 ¦ return; - 380 } - 381 const type_tree* base_type = type; - 382 // Update base_type in append_container_address_offsets - 383 const type_info& info = get(Type, base_type->value); - 384 if (info.kind == CONTAINER) { - 385 ¦ for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) { - 386 ¦ ¦ trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end(); - 387 ¦ ¦ reagent/*copy*/ element = element_type(type, curr_index); // not base_type - 388 ¦ ¦ // Compute Container Address Offset(element) - 389 ¦ ¦ if (is_mu_address(element)) { - 390 ¦ ¦ ¦ trace(9993, "transform") << "address at offset " << curr_offset << end(); - 391 ¦ ¦ ¦ get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type)))); - 392 ¦ ¦ ¦ ++curr_offset; - 393 ¦ ¦ } - 394 ¦ ¦ else if (is_mu_array(element)) { - 395 ¦ ¦ ¦ curr_offset += /*array length*/1; - 396 ¦ ¦ ¦ const type_tree* array_element_type = array_element(element.type); - 397 ¦ ¦ ¦ int array_element_size = size_of(array_element_type); - 398 ¦ ¦ ¦ for (int i = 0; i < static_array_length(element.type); ++i) { - 399 ¦ ¦ ¦ ¦ append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages); - 400 ¦ ¦ ¦ ¦ curr_offset += array_element_size; - 401 ¦ ¦ ¦ } - 402 ¦ ¦ } - 403 ¦ ¦ else if (is_mu_container(element)) { - 404 ¦ ¦ ¦ append_addresses(curr_offset, element.type, out, key, location_for_error_messages); - 405 ¦ ¦ ¦ curr_offset += size_of(element); - 406 ¦ ¦ } - 407 ¦ ¦ else if (is_mu_exclusive_container(element)) { - 408 ¦ ¦ ¦ const type_tree* element_base_type = element.type; - 409 ¦ ¦ ¦ // Update element_base_type For Exclusive Container in append_addresses - 410 ¦ ¦ ¦ const type_info& element_info = get(Type, element_base_type->value); - 411 ¦ ¦ ¦ for (int tag = 0; tag < SIZE(element_info.elements); ++tag) { - 412 ¦ ¦ ¦ ¦ set<tag_condition_info> new_key = key; - 413 ¦ ¦ ¦ ¦ new_key.insert(tag_condition_info(curr_offset, tag)); - 414 ¦ ¦ ¦ ¦ if (!contains_key(out, new_key)) - 415 ¦ ¦ ¦ ¦ ¦ append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages); - 416 ¦ ¦ ¦ } - 417 ¦ ¦ ¦ curr_offset += size_of(element); - 418 ¦ ¦ } - 419 ¦ ¦ else { - 420 ¦ ¦ ¦ // non-address primitive - 421 ¦ ¦ ¦ ++curr_offset; - 422 ¦ ¦ } - 423 ¦ } - 424 } - 425 else if (info.kind == EXCLUSIVE_CONTAINER) { - 426 ¦ for (int tag = 0; tag < SIZE(info.elements); ++tag) { - 427 ¦ ¦ set<tag_condition_info> new_key = key; - 428 ¦ ¦ new_key.insert(tag_condition_info(base_offset, tag)); - 429 ¦ ¦ if (!contains_key(out, new_key)) - 430 ¦ ¦ ¦ append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key, location_for_error_messages); - 431 ¦ } - 432 } - 433 } - 434 - 435 //: for the following unit tests we'll do the work of the transform by hand + 202 //:: manage refcounts in instructions that copy multiple locations at a time + 203 + 204 :(scenario refcounts_copy_nested) + 205 container foo [ + 206 x:address:num # address inside container + 207 ] + 208 def main [ + 209 1:address:num <- new number:type + 210 2:address:foo <- new foo:type + 211 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num + 212 3:foo <- copy *2:address:foo + 213 ] + 214 +transform: compute address offsets for container foo + 215 +transform: checking container foo, element 0 + 216 +transform: address at offset 0 + 217 +run: {1: ("address" "number")} <- new {number: "type"} + 218 +mem: incrementing refcount of 1000: 0 -> 1 + 219 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} + 220 +mem: incrementing refcount of 1000: 1 -> 2 + 221 # copying a container increments refcounts of any contained addresses + 222 +run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()} + 223 +mem: incrementing refcount of 1000: 2 -> 3 + 224 + 225 :(before "End type_tree Definition") + 226 struct address_element_info { + 227 // Where inside a container type (after flattening nested containers!) the + 228 // address lies + 229 int offset; + 230 + 231 // All the information we need to compute sizes of items inside an address + 232 // inside a container. `payload_type` Doesn't need to be a full-scale + 233 // reagent, since an address inside a container can never be an array, and + 234 // arrays are the only type that need to know their location to compute their + 235 // size. + 236 const type_tree* payload_type; + 237 + 238 address_element_info(int o, const type_tree* p); + 239 address_element_info(const address_element_info& other); + 240 ~address_element_info(); + 241 address_element_info& operator=(const address_element_info& other); + 242 }; + 243 :(code) + 244 address_element_info::address_element_info(int o, const type_tree* p) { + 245 offset = o; + 246 payload_type = p; + 247 } + 248 address_element_info::address_element_info(const address_element_info& other) { + 249 offset = other.offset; + 250 payload_type = copy(other.payload_type); + 251 } + 252 address_element_info::~address_element_info() { + 253 if (payload_type) { + 254 ¦ delete payload_type; + 255 ¦ payload_type = NULL; + 256 } + 257 } + 258 address_element_info& address_element_info::operator=(const address_element_info& other) { + 259 offset = other.offset; + 260 if (payload_type) delete payload_type; + 261 payload_type = copy(other.payload_type); + 262 return *this; + 263 } + 264 + 265 :(before "End type_tree Definition") + 266 // For exclusive containers we might sometimes have an address at some offset + 267 // if some other offset has a specific tag. This struct encapsulates such + 268 // guards. + 269 struct tag_condition_info { + 270 int offset; + 271 int tag; + 272 tag_condition_info(int o, int t) :offset(o), tag(t) {} + 273 }; + 274 + 275 :(before "End container_metadata Fields") + 276 // a list of facts of the form: + 277 // + 278 // IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN + 279 // for all address_element_infos: + 280 // you need to update refcounts for the address at offset pointing to a payload of type payload_type (just in case we need to abandon something in the process) + 281 map<set<tag_condition_info>, set<address_element_info> > address; + 282 :(code) + 283 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) { + 284 if (a.size() != b.size()) return a.size() < b.size(); + 285 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { + 286 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; + 287 ¦ if (pa->tag != pb->tag) return pa->tag < pb->tag; + 288 } + 289 return false; // equal + 290 } + 291 bool operator<(const tag_condition_info& a, const tag_condition_info& b) { + 292 if (a.offset != b.offset) return a.offset < b.offset; + 293 if (a.tag != b.tag) return a.tag < b.tag; + 294 return false; // equal + 295 } + 296 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) { + 297 if (a.size() != b.size()) return a.size() < b.size(); + 298 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { + 299 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; + 300 } + 301 return false; // equal + 302 } + 303 bool operator<(const address_element_info& a, const address_element_info& b) { + 304 if (a.offset != b.offset) return a.offset < b.offset; + 305 return false; // equal + 306 } + 307 + 308 //: populate metadata.address in a separate transform, because it requires + 309 //: already knowing the sizes of all types + 310 + 311 :(after "Transform.push_back(compute_container_sizes)") + 312 Transform.push_back(compute_container_address_offsets); // idempotent + 313 :(code) + 314 void compute_container_address_offsets(const recipe_ordinal r) { + 315 recipe& caller = get(Recipe, r); + 316 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end(); + 317 for (int i = 0; i < SIZE(caller.steps); ++i) { + 318 ¦ instruction& inst = caller.steps.at(i); + 319 ¦ trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end(); + 320 ¦ for (int i = 0; i < SIZE(inst.ingredients); ++i) + 321 ¦ ¦ compute_container_address_offsets(inst.ingredients.at(i), " in '"+inst.original_string+"'"); + 322 ¦ for (int i = 0; i < SIZE(inst.products); ++i) + 323 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+inst.original_string+"'"); + 324 } + 325 } + 326 + 327 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) { + 328 if (is_literal(r) || is_dummy(r)) return; + 329 compute_container_address_offsets(r.type, location_for_error_messages); + 330 if (contains_key(Container_metadata, r.type)) + 331 ¦ r.metadata = get(Container_metadata, r.type); + 332 } + 333 + 334 // the recursive structure of this function needs to exactly match + 335 // compute_container_sizes + 336 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) { + 337 if (!type) return; + 338 if (!type->atom) { + 339 ¦ if (!type->left->atom) { + 340 ¦ ¦ raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end(); + 341 ¦ ¦ return; + 342 ¦ } + 343 ¦ if (type->left->name == "address") + 344 ¦ ¦ compute_container_address_offsets(payload_type(type), location_for_error_messages); + 345 ¦ else if (type->left->name == "array") + 346 ¦ ¦ compute_container_address_offsets(array_element(type), location_for_error_messages); + 347 ¦ // End compute_container_address_offsets Non-atom Special-cases + 348 } + 349 const type_tree* base_type = type; + 350 // Update base_type in compute_container_address_offsets + 351 if (!contains_key(Type, base_type->value)) return; // error raised elsewhere + 352 type_info& info = get(Type, base_type->value); + 353 if (info.kind == CONTAINER) { + 354 ¦ compute_container_address_offsets(info, type, location_for_error_messages); + 355 } + 356 if (info.kind == EXCLUSIVE_CONTAINER) { + 357 ¦ compute_exclusive_container_address_offsets(info, type, location_for_error_messages); + 358 } + 359 } + 360 + 361 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) { + 362 container_metadata& metadata = get(Container_metadata, full_type); + 363 if (!metadata.address.empty()) return; + 364 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end(); + 365 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages); + 366 } + 367 + 368 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) { + 369 container_metadata& metadata = get(Container_metadata, full_type); + 370 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end(); + 371 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) { + 372 ¦ set<tag_condition_info> key; + 373 ¦ key.insert(tag_condition_info(/*tag is at offset*/0, tag)); + 374 ¦ append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages); + 375 } + 376 } + 377 + 378 void append_addresses(int base_offset, const type_tree* type, map<set<tag_condition_info>, set<address_element_info> >& out, const set<tag_condition_info>& key, const string& location_for_error_messages) { + 379 if (is_mu_address(type)) { + 380 ¦ get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type)))); + 381 ¦ return; + 382 } + 383 const type_tree* base_type = type; + 384 // Update base_type in append_container_address_offsets + 385 const type_info& info = get(Type, base_type->value); + 386 if (info.kind == CONTAINER) { + 387 ¦ for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) { + 388 ¦ ¦ trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end(); + 389 ¦ ¦ reagent/*copy*/ element = element_type(type, curr_index); // not base_type + 390 ¦ ¦ // Compute Container Address Offset(element) + 391 ¦ ¦ if (is_mu_address(element)) { + 392 ¦ ¦ ¦ trace(9993, "transform") << "address at offset " << curr_offset << end(); + 393 ¦ ¦ ¦ get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type)))); + 394 ¦ ¦ ¦ ++curr_offset; + 395 ¦ ¦ } + 396 ¦ ¦ else if (is_mu_array(element)) { + 397 ¦ ¦ ¦ curr_offset += /*array length*/1; + 398 ¦ ¦ ¦ const type_tree* array_element_type = array_element(element.type); + 399 ¦ ¦ ¦ int array_element_size = size_of(array_element_type); + 400 ¦ ¦ ¦ for (int i = 0; i < static_array_length(element.type); ++i) { + 401 ¦ ¦ ¦ ¦ append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages); + 402 ¦ ¦ ¦ ¦ curr_offset += array_element_size; + 403 ¦ ¦ ¦ } + 404 ¦ ¦ } + 405 ¦ ¦ else if (is_mu_container(element)) { + 406 ¦ ¦ ¦ append_addresses(curr_offset, element.type, out, key, location_for_error_messages); + 407 ¦ ¦ ¦ curr_offset += size_of(element); + 408 ¦ ¦ } + 409 ¦ ¦ else if (is_mu_exclusive_container(element)) { + 410 ¦ ¦ ¦ const type_tree* element_base_type = element.type; + 411 ¦ ¦ ¦ // Update element_base_type For Exclusive Container in append_addresses + 412 ¦ ¦ ¦ const type_info& element_info = get(Type, element_base_type->value); + 413 ¦ ¦ ¦ for (int tag = 0; tag < SIZE(element_info.elements); ++tag) { + 414 ¦ ¦ ¦ ¦ set<tag_condition_info> new_key = key; + 415 ¦ ¦ ¦ ¦ new_key.insert(tag_condition_info(curr_offset, tag)); + 416 ¦ ¦ ¦ ¦ if (!contains_key(out, new_key)) + 417 ¦ ¦ ¦ ¦ ¦ append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages); + 418 ¦ ¦ ¦ } + 419 ¦ ¦ ¦ curr_offset += size_of(element); + 420 ¦ ¦ } + 421 ¦ ¦ else { + 422 ¦ ¦ ¦ // non-address primitive + 423 ¦ ¦ ¦ ++curr_offset; + 424 ¦ ¦ } + 425 ¦ } + 426 } + 427 else if (info.kind == EXCLUSIVE_CONTAINER) { + 428 ¦ for (int tag = 0; tag < SIZE(info.elements); ++tag) { + 429 ¦ ¦ set<tag_condition_info> new_key = key; + 430 ¦ ¦ new_key.insert(tag_condition_info(base_offset, tag)); + 431 ¦ ¦ if (!contains_key(out, new_key)) + 432 ¦ ¦ ¦ append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key, location_for_error_messages); + 433 ¦ } + 434 } + 435 } 436 - 437 :(before "End Unit Tests") - 438 void test_container_address_offsets_empty() { - 439 int old_size = SIZE(Container_metadata); - 440 // define a container with no addresses - 441 reagent r("x:point"); - 442 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 443 // scan - 444 compute_container_address_offsets(r, ""); - 445 // global metadata contains just the entry for foo - 446 // no entries for non-container types or other junk - 447 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 448 // the reagent we scanned knows it has no addresses - 449 CHECK(r.metadata.address.empty()); - 450 // the global table contains an identical entry - 451 CHECK(contains_key(Container_metadata, r.type)); - 452 CHECK(get(Container_metadata, r.type).address.empty()); - 453 // compute_container_address_offsets creates no new entries - 454 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 455 } - 456 - 457 void test_container_address_offsets() { - 458 int old_size = SIZE(Container_metadata); - 459 // define a container with an address at offset 0 that we have the size for - 460 run("container foo [\n" - 461 ¦ ¦ " x:address:num\n" - 462 ¦ ¦ "]\n"); - 463 reagent r("x:foo"); - 464 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 465 // scan - 466 compute_container_address_offsets(r, ""); - 467 // global metadata contains just the entry for foo - 468 // no entries for non-container types or other junk - 469 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 470 // the reagent we scanned knows it has an address at offset 0 - 471 CHECK_EQ(SIZE(r.metadata.address), 1); - 472 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 473 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); // unconditional for containers - 474 CHECK_EQ(SIZE(address_offsets), 1); - 475 CHECK_EQ(address_offsets.begin()->offset, 0); - 476 CHECK(address_offsets.begin()->payload_type->atom); - 477 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 478 // the global table contains an identical entry - 479 CHECK(contains_key(Container_metadata, r.type)); - 480 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 481 CHECK_EQ(SIZE(address_offsets2), 1); - 482 CHECK_EQ(address_offsets2.begin()->offset, 0); - 483 CHECK(address_offsets2.begin()->payload_type->atom); - 484 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 485 // compute_container_address_offsets creates no new entries - 486 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 487 } - 488 - 489 void test_container_address_offsets_2() { - 490 int old_size = SIZE(Container_metadata); - 491 // define a container with an address at offset 1 that we have the size for - 492 run("container foo [\n" - 493 ¦ ¦ " x:num\n" - 494 ¦ ¦ " y:address:num\n" - 495 ¦ ¦ "]\n"); - 496 reagent r("x:foo"); - 497 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 498 // global metadata contains just the entry for foo - 499 // no entries for non-container types or other junk - 500 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 501 // scan - 502 compute_container_address_offsets(r, ""); - 503 // compute_container_address_offsets creates no new entries - 504 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 505 // the reagent we scanned knows it has an address at offset 1 - 506 CHECK_EQ(SIZE(r.metadata.address), 1); - 507 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 508 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); - 509 CHECK_EQ(SIZE(address_offsets), 1); - 510 CHECK_EQ(address_offsets.begin()->offset, 1); // - 511 CHECK(address_offsets.begin()->payload_type->atom); - 512 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 513 // the global table contains an identical entry - 514 CHECK(contains_key(Container_metadata, r.type)); - 515 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 516 CHECK_EQ(SIZE(address_offsets2), 1); - 517 CHECK_EQ(address_offsets2.begin()->offset, 1); // - 518 CHECK(address_offsets2.begin()->payload_type->atom); - 519 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 520 } - 521 - 522 void test_container_address_offsets_nested() { - 523 int old_size = SIZE(Container_metadata); - 524 // define a container with a nested container containing an address - 525 run("container foo [\n" - 526 ¦ ¦ " x:address:num\n" - 527 ¦ ¦ " y:num\n" - 528 ¦ ¦ "]\n" - 529 ¦ ¦ "container bar [\n" - 530 ¦ ¦ " p:point\n" - 531 ¦ ¦ " f:foo\n" // nested container containing address - 532 ¦ ¦ "]\n"); - 533 reagent r("x:bar"); - 534 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 535 // global metadata contains entries for bar and included types: point and foo - 536 // no entries for non-container types or other junk - 537 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); - 538 // scan - 539 compute_container_address_offsets(r, ""); - 540 // the reagent we scanned knows it has an address at offset 2 - 541 CHECK_EQ(SIZE(r.metadata.address), 1); - 542 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 543 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); - 544 CHECK_EQ(SIZE(address_offsets), 1); - 545 CHECK_EQ(address_offsets.begin()->offset, 2); // - 546 CHECK(address_offsets.begin()->payload_type->atom); - 547 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 548 // the global table also knows its address offset - 549 CHECK(contains_key(Container_metadata, r.type)); - 550 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 551 CHECK_EQ(SIZE(address_offsets2), 1); - 552 CHECK_EQ(address_offsets2.begin()->offset, 2); // - 553 CHECK(address_offsets2.begin()->payload_type->atom); - 554 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 555 // compute_container_address_offsets creates no new entries - 556 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); - 557 } - 558 - 559 void test_container_address_offsets_from_address() { - 560 int old_size = SIZE(Container_metadata); - 561 // define a container with an address at offset 0 - 562 run("container foo [\n" - 563 ¦ ¦ " x:address:num\n" - 564 ¦ ¦ "]\n"); - 565 reagent r("x:address:foo"); - 566 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 567 // global metadata contains just the entry for foo - 568 // no entries for non-container types or other junk - 569 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 570 // scan an address to the container - 571 compute_container_address_offsets(r, ""); - 572 // compute_container_address_offsets creates no new entries - 573 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 574 // scanning precomputed metadata for the container - 575 reagent container("x:foo"); - 576 CHECK(contains_key(Container_metadata, container.type)); - 577 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 578 CHECK_EQ(SIZE(address_offsets2), 1); - 579 CHECK_EQ(address_offsets2.begin()->offset, 0); - 580 CHECK(address_offsets2.begin()->payload_type->atom); - 581 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 582 } - 583 - 584 void test_container_address_offsets_from_array() { - 585 int old_size = SIZE(Container_metadata); - 586 // define a container with an address at offset 0 - 587 run("container foo [\n" - 588 ¦ ¦ " x:address:num\n" - 589 ¦ ¦ "]\n"); - 590 reagent r("x:array:foo"); - 591 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 592 // global metadata contains just the entry for foo - 593 // no entries for non-container types or other junk - 594 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 595 // scan an array of the container - 596 compute_container_address_offsets(r, ""); - 597 // compute_container_address_offsets creates no new entries - 598 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 599 // scanning precomputed metadata for the container - 600 reagent container("x:foo"); - 601 CHECK(contains_key(Container_metadata, container.type)); - 602 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 603 CHECK_EQ(SIZE(address_offsets2), 1); - 604 CHECK_EQ(address_offsets2.begin()->offset, 0); - 605 CHECK(address_offsets2.begin()->payload_type->atom); - 606 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 607 } - 608 - 609 void test_container_address_offsets_from_address_to_array() { - 610 int old_size = SIZE(Container_metadata); - 611 // define a container with an address at offset 0 - 612 run("container foo [\n" - 613 ¦ ¦ " x:address:num\n" - 614 ¦ ¦ "]\n"); - 615 reagent r("x:address:array:foo"); - 616 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 617 // global metadata contains just the entry for foo - 618 // no entries for non-container types or other junk - 619 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 620 // scan an address to an array of the container - 621 compute_container_address_offsets(r, ""); - 622 // compute_container_address_offsets creates no new entries - 623 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 624 // scanning precomputed metadata for the container - 625 reagent container("x:foo"); - 626 CHECK(contains_key(Container_metadata, container.type)); - 627 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 628 CHECK_EQ(SIZE(address_offsets2), 1); - 629 CHECK_EQ(address_offsets2.begin()->offset, 0); - 630 CHECK(address_offsets2.begin()->payload_type->atom); - 631 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 632 } - 633 - 634 void test_container_address_offsets_from_static_array() { - 635 int old_size = SIZE(Container_metadata); - 636 // define a container with an address at offset 0 - 637 run("container foo [\n" - 638 ¦ ¦ " x:address:num\n" - 639 ¦ ¦ "]\n"); - 640 reagent r("x:array:foo:10"); - 641 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 642 // global metadata contains just the entry for foo - 643 // no entries for non-container types or other junk - 644 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 645 // scan a static array of the container - 646 compute_container_address_offsets(r, ""); - 647 // compute_container_address_offsets creates no new entries - 648 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 649 // scanning precomputed metadata for the container - 650 reagent container("x:foo"); - 651 CHECK(contains_key(Container_metadata, container.type)); - 652 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 653 CHECK_EQ(SIZE(address_offsets2), 1); - 654 CHECK_EQ(address_offsets2.begin()->offset, 0); - 655 CHECK(address_offsets2.begin()->payload_type->atom); - 656 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 657 } - 658 - 659 void test_container_address_offsets_from_address_to_static_array() { - 660 int old_size = SIZE(Container_metadata); - 661 // define a container with an address at offset 0 - 662 run("container foo [\n" - 663 ¦ ¦ " x:address:num\n" - 664 ¦ ¦ "]\n"); - 665 reagent r("x:address:array:foo:10"); - 666 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 667 // global metadata contains just the entry for foo - 668 // no entries for non-container types or other junk - 669 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 670 // scan an address to a static array of the container - 671 compute_container_address_offsets(r, ""); - 672 // compute_container_address_offsets creates no new entries - 673 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 674 // scanning precomputed metadata for the container - 675 reagent container("x:foo"); - 676 CHECK(contains_key(Container_metadata, container.type)); - 677 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 678 CHECK_EQ(SIZE(address_offsets2), 1); - 679 CHECK_EQ(address_offsets2.begin()->offset, 0); - 680 CHECK(address_offsets2.begin()->payload_type->atom); - 681 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 682 } - 683 - 684 void test_container_address_offsets_from_repeated_address_and_array_types() { - 685 int old_size = SIZE(Container_metadata); - 686 // define a container with an address at offset 0 - 687 run("container foo [\n" - 688 ¦ ¦ " x:address:num\n" - 689 ¦ ¦ "]\n"); - 690 // scan a deep nest of 'address' and 'array' types modifying a container - 691 reagent r("x:address:array:address:address:array:foo:10"); - 692 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 693 // global metadata contains just the entry for foo - 694 // no entries for non-container types or other junk - 695 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 696 compute_container_address_offsets(r, ""); - 697 // compute_container_address_offsets creates no new entries - 698 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 699 // scanning precomputed metadata for the container - 700 reagent container("x:foo"); - 701 CHECK(contains_key(Container_metadata, container.type)); - 702 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 703 CHECK_EQ(SIZE(address_offsets2), 1); - 704 CHECK_EQ(address_offsets2.begin()->offset, 0); - 705 CHECK(address_offsets2.begin()->payload_type->atom); - 706 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 707 } - 708 - 709 //: use metadata.address to update refcounts within containers, arrays and - 710 //: exclusive containers - 711 - 712 :(before "End Increment Refcounts(canonized_x)") - 713 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - 714 const container_metadata& metadata = get(Container_metadata, canonized_x.type); - 715 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - 716 ¦ if (!all_match(data, p->first)) continue; - 717 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) - 718 ¦ ¦ increment_refcount(data.at(info->offset)); - 719 } - 720 } - 721 - 722 :(before "End Decrement Refcounts(canonized_x)") - 723 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - 724 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end(); - 725 // read from canonized_x but without canonizing again - 726 // todo: inline without running canonize all over again - 727 reagent/*copy*/ tmp = canonized_x; - 728 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL)); - 729 vector<double> data = read_memory(tmp); - 730 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end(); - 731 const container_metadata& metadata = get(Container_metadata, canonized_x.type); - 732 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - 733 ¦ if (!all_match(data, p->first)) continue; - 734 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) { - 735 ¦ ¦ int element_address = get_or_insert(Memory, canonized_x.value + info->offset); - 736 ¦ ¦ reagent/*local*/ element; - 737 ¦ ¦ element.set_value(element_address+/*skip refcount*/1); - 738 ¦ ¦ element.type = new type_tree(*info->payload_type); - 739 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+/*refcount*/1); - 740 ¦ } - 741 } - 742 } - 743 - 744 :(code) - 745 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) { - 746 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { - 747 ¦ if (data.at(p->offset) != p->tag) - 748 ¦ ¦ return false; - 749 } - 750 return true; - 751 } - 752 - 753 :(scenario refcounts_put_container) - 754 container foo [ - 755 a:bar # contains an address - 756 ] - 757 container bar [ - 758 x:address:num - 759 ] - 760 def main [ - 761 1:address:num <- new number:type - 762 2:bar <- merge 1:address:num - 763 3:address:foo <- new foo:type - 764 *3:address:foo <- put *3:address:foo, a:offset, 2:bar - 765 ] - 766 +run: {1: ("address" "number")} <- new {number: "type"} - 767 +mem: incrementing refcount of 1000: 0 -> 1 - 768 +run: {2: "bar"} <- merge {1: ("address" "number")} - 769 +mem: incrementing refcount of 1000: 1 -> 2 - 770 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} - 771 # put increments refcount inside container - 772 +mem: incrementing refcount of 1000: 2 -> 3 - 773 - 774 :(scenario refcounts_put_index_array) - 775 container bar [ - 776 x:address:num - 777 ] - 778 def main [ - 779 1:address:num <- new number:type - 780 2:bar <- merge 1:address:num - 781 3:address:array:bar <- new bar:type, 3 - 782 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar - 783 ] - 784 +run: {1: ("address" "number")} <- new {number: "type"} - 785 +mem: incrementing refcount of 1000: 0 -> 1 - 786 +run: {2: "bar"} <- merge {1: ("address" "number")} - 787 +mem: incrementing refcount of 1000: 1 -> 2 - 788 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} - 789 # put-index increments refcount inside container - 790 +mem: incrementing refcount of 1000: 2 -> 3 - 791 - 792 :(scenario refcounts_maybe_convert_container) - 793 exclusive-container foo [ - 794 a:num - 795 b:bar # contains an address - 796 ] - 797 container bar [ - 798 x:address:num - 799 ] - 800 def main [ - 801 1:address:num <- new number:type - 802 2:bar <- merge 1:address:num - 803 3:foo <- merge 1/b, 2:bar - 804 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b - 805 ] - 806 +run: {1: ("address" "number")} <- new {number: "type"} - 807 +mem: incrementing refcount of 1000: 0 -> 1 - 808 +run: {2: "bar"} <- merge {1: ("address" "number")} - 809 +mem: incrementing refcount of 1000: 1 -> 2 - 810 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} - 811 +mem: incrementing refcount of 1000: 2 -> 3 - 812 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} - 813 +mem: incrementing refcount of 1000: 3 -> 4 - 814 - 815 :(scenario refcounts_copy_doubly_nested) - 816 container foo [ - 817 a:bar # no addresses - 818 b:curr # contains addresses - 819 ] - 820 container bar [ - 821 x:num - 822 y:num - 823 ] - 824 container curr [ - 825 x:num - 826 y:address:num # address inside container inside container - 827 ] - 828 def main [ - 829 1:address:num <- new number:type - 830 2:address:curr <- new curr:type - 831 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num - 832 3:address:foo <- new foo:type - 833 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr - 834 4:foo <- copy *3:address:foo - 835 ] - 836 +transform: compute address offsets for container foo - 837 +transform: checking container foo, element 1 - 838 +transform: address at offset 3 - 839 +run: {1: ("address" "number")} <- new {number: "type"} - 840 +mem: incrementing refcount of 1000: 0 -> 1 - 841 # storing an address in a container updates its refcount - 842 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} - 843 +mem: incrementing refcount of 1000: 1 -> 2 - 844 # storing a container in a container updates refcounts of any contained addresses - 845 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} - 846 +mem: incrementing refcount of 1000: 2 -> 3 - 847 # copying a container containing a container containing an address updates refcount - 848 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} - 849 +mem: incrementing refcount of 1000: 3 -> 4 - 850 - 851 :(scenario refcounts_copy_exclusive_container_within_container) - 852 container foo [ - 853 a:num - 854 b:bar - 855 ] - 856 exclusive-container bar [ - 857 x:num - 858 y:num - 859 z:address:num - 860 ] - 861 def main [ - 862 1:address:num <- new number:type - 863 2:bar <- merge 0/x, 34 - 864 3:foo <- merge 12, 2:bar - 865 5:bar <- merge 1/y, 35 - 866 6:foo <- merge 13, 5:bar - 867 8:bar <- merge 2/z, 1:address:num - 868 9:foo <- merge 14, 8:bar - 869 11:foo <- copy 9:foo - 870 ] - 871 +run: {1: ("address" "number")} <- new {number: "type"} - 872 +mem: incrementing refcount of 1000: 0 -> 1 - 873 # no change while merging items of other types - 874 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} - 875 +mem: incrementing refcount of 1000: 1 -> 2 - 876 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} - 877 +mem: incrementing refcount of 1000: 2 -> 3 - 878 +run: {11: "foo"} <- copy {9: "foo"} - 879 +mem: incrementing refcount of 1000: 3 -> 4 - 880 - 881 :(scenario refcounts_copy_container_within_exclusive_container) - 882 exclusive-container foo [ - 883 a:num - 884 b:bar - 885 ] - 886 container bar [ - 887 x:num - 888 y:num - 889 z:address:num - 890 ] - 891 def main [ - 892 1:address:num <- new number:type - 893 2:foo <- merge 0/a, 34 - 894 6:foo <- merge 0/a, 35 - 895 10:bar <- merge 2/x, 15/y, 1:address:num - 896 13:foo <- merge 1/b, 10:bar - 897 17:foo <- copy 13:foo - 898 ] - 899 +run: {1: ("address" "number")} <- new {number: "type"} - 900 +mem: incrementing refcount of 1000: 0 -> 1 - 901 # no change while merging items of other types - 902 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} - 903 +mem: incrementing refcount of 1000: 1 -> 2 - 904 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} - 905 +mem: incrementing refcount of 1000: 2 -> 3 - 906 +run: {17: "foo"} <- copy {13: "foo"} - 907 +mem: incrementing refcount of 1000: 3 -> 4 - 908 - 909 :(scenario refcounts_copy_exclusive_container_within_exclusive_container) - 910 exclusive-container foo [ - 911 a:num - 912 b:bar - 913 ] - 914 exclusive-container bar [ - 915 x:num - 916 y:address:num - 917 ] - 918 def main [ - 919 1:address:num <- new number:type - 920 10:foo <- merge 1/b, 1/y, 1:address:num - 921 20:foo <- copy 10:foo - 922 ] - 923 +run: {1: ("address" "number")} <- new {number: "type"} - 924 +mem: incrementing refcount of 1000: 0 -> 1 - 925 # no change while merging items of other types - 926 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} - 927 +mem: incrementing refcount of 1000: 1 -> 2 - 928 +run: {20: "foo"} <- copy {10: "foo"} - 929 +mem: incrementing refcount of 1000: 2 -> 3 - 930 - 931 :(scenario refcounts_copy_array_within_container) - 932 container foo [ - 933 x:address:array:num - 934 ] - 935 def main [ - 936 1:address:array:num <- new number:type, 3 - 937 2:foo <- merge 1:address:array:num - 938 3:address:array:num <- new number:type, 5 - 939 2:foo <- merge 3:address:array:num - 940 ] - 941 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} - 942 +mem: incrementing refcount of 1000: 0 -> 1 - 943 +run: {2: "foo"} <- merge {1: ("address" "array" "number")} - 944 +mem: incrementing refcount of 1000: 1 -> 2 - 945 +run: {2: "foo"} <- merge {3: ("address" "array" "number")} - 946 +mem: decrementing refcount of 1000: 2 -> 1 - 947 - 948 :(scenario refcounts_copy_address_within_static_array_within_container) - 949 container foo [ - 950 a:array:bar:3 - 951 b:address:num - 952 ] - 953 container bar [ - 954 y:num - 955 z:address:num - 956 ] - 957 def main [ - 958 1:address:num <- new number:type - 959 2:bar <- merge 34, 1:address:num - 960 10:array:bar:3 <- create-array - 961 put-index 10:array:bar:3, 1, 2:bar - 962 20:foo <- merge 10:array:bar:3, 1:address:num - 963 1:address:num <- copy 0 - 964 2:bar <- merge 34, 1:address:num - 965 put-index 10:array:bar:3, 1, 2:bar - 966 20:foo <- merge 10:array:bar:3, 1:address:num - 967 ] - 968 +run: {1: ("address" "number")} <- new {number: "type"} - 969 +mem: incrementing refcount of 1000: 0 -> 1 - 970 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} - 971 +mem: incrementing refcount of 1000: 1 -> 2 - 972 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} - 973 +mem: incrementing refcount of 1000: 2 -> 3 - 974 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} - 975 +mem: incrementing refcount of 1000: 3 -> 4 - 976 +mem: incrementing refcount of 1000: 4 -> 5 - 977 +run: {1: ("address" "number")} <- copy {0: "literal"} - 978 +mem: decrementing refcount of 1000: 5 -> 4 - 979 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} - 980 +mem: decrementing refcount of 1000: 4 -> 3 - 981 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} - 982 +mem: decrementing refcount of 1000: 3 -> 2 - 983 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} - 984 +mem: decrementing refcount of 1000: 2 -> 1 - 985 +mem: decrementing refcount of 1000: 1 -> 0 - 986 - 987 :(scenario refcounts_handle_exclusive_containers_with_different_tags) - 988 container foo1 [ - 989 x:address:num - 990 y:num - 991 ] - 992 container foo2 [ - 993 x:num - 994 y:address:num - 995 ] - 996 exclusive-container bar [ - 997 a:foo1 - 998 b:foo2 - 999 ] -1000 def main [ -1001 1:address:num <- copy 12000/unsafe # pretend allocation -1002 *1:address:num <- copy 34 -1003 2:bar <- merge 0/foo1, 1:address:num, 97 -1004 5:address:num <- copy 13000/unsafe # pretend allocation -1005 *5:address:num <- copy 35 -1006 6:bar <- merge 1/foo2, 98, 5:address:num -1007 2:bar <- copy 6:bar -1008 ] -1009 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} -1010 +mem: incrementing refcount of 12000: 1 -> 2 -1011 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} -1012 +mem: incrementing refcount of 13000: 1 -> 2 -1013 +run: {2: "bar"} <- copy {6: "bar"} -1014 +mem: incrementing refcount of 13000: 2 -> 3 -1015 +mem: decrementing refcount of 12000: 2 -> 1 -1016 -1017 :(code) -1018 bool is_mu_container(const reagent& r) { -1019 return is_mu_container(r.type); -1020 } -1021 bool is_mu_container(const type_tree* type) { -1022 if (!type) return false; -1023 // End is_mu_container(type) Special-cases -1024 if (type->value == 0) return false; -1025 type_info& info = get(Type, type->value); -1026 return info.kind == CONTAINER; -1027 } -1028 -1029 bool is_mu_exclusive_container(const reagent& r) { -1030 return is_mu_exclusive_container(r.type); -1031 } -1032 bool is_mu_exclusive_container(const type_tree* type) { -1033 if (!type) return false; -1034 // End is_mu_exclusive_container(type) Special-cases -1035 if (type->value == 0) return false; -1036 type_info& info = get(Type, type->value); -1037 return info.kind == EXCLUSIVE_CONTAINER; -1038 } + 437 //: for the following unit tests we'll do the work of the transform by hand + 438 + 439 :(before "End Unit Tests") + 440 void test_container_address_offsets_empty() { + 441 int old_size = SIZE(Container_metadata); + 442 // define a container with no addresses + 443 reagent r("x:point"); + 444 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 445 // scan + 446 compute_container_address_offsets(r, ""); + 447 // global metadata contains just the entry for foo + 448 // no entries for non-container types or other junk + 449 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 450 // the reagent we scanned knows it has no addresses + 451 CHECK(r.metadata.address.empty()); + 452 // the global table contains an identical entry + 453 CHECK(contains_key(Container_metadata, r.type)); + 454 CHECK(get(Container_metadata, r.type).address.empty()); + 455 // compute_container_address_offsets creates no new entries + 456 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 457 } + 458 + 459 void test_container_address_offsets() { + 460 int old_size = SIZE(Container_metadata); + 461 // define a container with an address at offset 0 that we have the size for + 462 run("container foo [\n" + 463 ¦ ¦ " x:address:num\n" + 464 ¦ ¦ "]\n"); + 465 reagent r("x:foo"); + 466 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 467 // scan + 468 compute_container_address_offsets(r, ""); + 469 // global metadata contains just the entry for foo + 470 // no entries for non-container types or other junk + 471 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 472 // the reagent we scanned knows it has an address at offset 0 + 473 CHECK_EQ(SIZE(r.metadata.address), 1); + 474 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 475 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); // unconditional for containers + 476 CHECK_EQ(SIZE(address_offsets), 1); + 477 CHECK_EQ(address_offsets.begin()->offset, 0); + 478 CHECK(address_offsets.begin()->payload_type->atom); + 479 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 480 // the global table contains an identical entry + 481 CHECK(contains_key(Container_metadata, r.type)); + 482 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 483 CHECK_EQ(SIZE(address_offsets2), 1); + 484 CHECK_EQ(address_offsets2.begin()->offset, 0); + 485 CHECK(address_offsets2.begin()->payload_type->atom); + 486 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 487 // compute_container_address_offsets creates no new entries + 488 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 489 } + 490 + 491 void test_container_address_offsets_2() { + 492 int old_size = SIZE(Container_metadata); + 493 // define a container with an address at offset 1 that we have the size for + 494 run("container foo [\n" + 495 ¦ ¦ " x:num\n" + 496 ¦ ¦ " y:address:num\n" + 497 ¦ ¦ "]\n"); + 498 reagent r("x:foo"); + 499 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 500 // global metadata contains just the entry for foo + 501 // no entries for non-container types or other junk + 502 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 503 // scan + 504 compute_container_address_offsets(r, ""); + 505 // compute_container_address_offsets creates no new entries + 506 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 507 // the reagent we scanned knows it has an address at offset 1 + 508 CHECK_EQ(SIZE(r.metadata.address), 1); + 509 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 510 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); + 511 CHECK_EQ(SIZE(address_offsets), 1); + 512 CHECK_EQ(address_offsets.begin()->offset, 1); // + 513 CHECK(address_offsets.begin()->payload_type->atom); + 514 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 515 // the global table contains an identical entry + 516 CHECK(contains_key(Container_metadata, r.type)); + 517 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 518 CHECK_EQ(SIZE(address_offsets2), 1); + 519 CHECK_EQ(address_offsets2.begin()->offset, 1); // + 520 CHECK(address_offsets2.begin()->payload_type->atom); + 521 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 522 } + 523 + 524 void test_container_address_offsets_nested() { + 525 int old_size = SIZE(Container_metadata); + 526 // define a container with a nested container containing an address + 527 run("container foo [\n" + 528 ¦ ¦ " x:address:num\n" + 529 ¦ ¦ " y:num\n" + 530 ¦ ¦ "]\n" + 531 ¦ ¦ "container bar [\n" + 532 ¦ ¦ " p:point\n" + 533 ¦ ¦ " f:foo\n" // nested container containing address + 534 ¦ ¦ "]\n"); + 535 reagent r("x:bar"); + 536 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 537 // global metadata contains entries for bar and included types: point and foo + 538 // no entries for non-container types or other junk + 539 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); + 540 // scan + 541 compute_container_address_offsets(r, ""); + 542 // the reagent we scanned knows it has an address at offset 2 + 543 CHECK_EQ(SIZE(r.metadata.address), 1); + 544 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 545 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); + 546 CHECK_EQ(SIZE(address_offsets), 1); + 547 CHECK_EQ(address_offsets.begin()->offset, 2); // + 548 CHECK(address_offsets.begin()->payload_type->atom); + 549 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 550 // the global table also knows its address offset + 551 CHECK(contains_key(Container_metadata, r.type)); + 552 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 553 CHECK_EQ(SIZE(address_offsets2), 1); + 554 CHECK_EQ(address_offsets2.begin()->offset, 2); // + 555 CHECK(address_offsets2.begin()->payload_type->atom); + 556 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 557 // compute_container_address_offsets creates no new entries + 558 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); + 559 } + 560 + 561 void test_container_address_offsets_from_address() { + 562 int old_size = SIZE(Container_metadata); + 563 // define a container with an address at offset 0 + 564 run("container foo [\n" + 565 ¦ ¦ " x:address:num\n" + 566 ¦ ¦ "]\n"); + 567 reagent r("x:address:foo"); + 568 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 569 // global metadata contains just the entry for foo + 570 // no entries for non-container types or other junk + 571 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 572 // scan an address to the container + 573 compute_container_address_offsets(r, ""); + 574 // compute_container_address_offsets creates no new entries + 575 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 576 // scanning precomputed metadata for the container + 577 reagent container("x:foo"); + 578 CHECK(contains_key(Container_metadata, container.type)); + 579 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 580 CHECK_EQ(SIZE(address_offsets2), 1); + 581 CHECK_EQ(address_offsets2.begin()->offset, 0); + 582 CHECK(address_offsets2.begin()->payload_type->atom); + 583 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 584 } + 585 + 586 void test_container_address_offsets_from_array() { + 587 int old_size = SIZE(Container_metadata); + 588 // define a container with an address at offset 0 + 589 run("container foo [\n" + 590 ¦ ¦ " x:address:num\n" + 591 ¦ ¦ "]\n"); + 592 reagent r("x:array:foo"); + 593 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 594 // global metadata contains just the entry for foo + 595 // no entries for non-container types or other junk + 596 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 597 // scan an array of the container + 598 compute_container_address_offsets(r, ""); + 599 // compute_container_address_offsets creates no new entries + 600 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 601 // scanning precomputed metadata for the container + 602 reagent container("x:foo"); + 603 CHECK(contains_key(Container_metadata, container.type)); + 604 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 605 CHECK_EQ(SIZE(address_offsets2), 1); + 606 CHECK_EQ(address_offsets2.begin()->offset, 0); + 607 CHECK(address_offsets2.begin()->payload_type->atom); + 608 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 609 } + 610 + 611 void test_container_address_offsets_from_address_to_array() { + 612 int old_size = SIZE(Container_metadata); + 613 // define a container with an address at offset 0 + 614 run("container foo [\n" + 615 ¦ ¦ " x:address:num\n" + 616 ¦ ¦ "]\n"); + 617 reagent r("x:address:array:foo"); + 618 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 619 // global metadata contains just the entry for foo + 620 // no entries for non-container types or other junk + 621 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 622 // scan an address to an array of the container + 623 compute_container_address_offsets(r, ""); + 624 // compute_container_address_offsets creates no new entries + 625 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 626 // scanning precomputed metadata for the container + 627 reagent container("x:foo"); + 628 CHECK(contains_key(Container_metadata, container.type)); + 629 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 630 CHECK_EQ(SIZE(address_offsets2), 1); + 631 CHECK_EQ(address_offsets2.begin()->offset, 0); + 632 CHECK(address_offsets2.begin()->payload_type->atom); + 633 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 634 } + 635 + 636 void test_container_address_offsets_from_static_array() { + 637 int old_size = SIZE(Container_metadata); + 638 // define a container with an address at offset 0 + 639 run("container foo [\n" + 640 ¦ ¦ " x:address:num\n" + 641 ¦ ¦ "]\n"); + 642 reagent r("x:array:foo:10"); + 643 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 644 // global metadata contains just the entry for foo + 645 // no entries for non-container types or other junk + 646 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 647 // scan a static array of the container + 648 compute_container_address_offsets(r, ""); + 649 // compute_container_address_offsets creates no new entries + 650 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 651 // scanning precomputed metadata for the container + 652 reagent container("x:foo"); + 653 CHECK(contains_key(Container_metadata, container.type)); + 654 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 655 CHECK_EQ(SIZE(address_offsets2), 1); + 656 CHECK_EQ(address_offsets2.begin()->offset, 0); + 657 CHECK(address_offsets2.begin()->payload_type->atom); + 658 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 659 } + 660 + 661 void test_container_address_offsets_from_address_to_static_array() { + 662 int old_size = SIZE(Container_metadata); + 663 // define a container with an address at offset 0 + 664 run("container foo [\n" + 665 ¦ ¦ " x:address:num\n" + 666 ¦ ¦ "]\n"); + 667 reagent r("x:address:array:foo:10"); + 668 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 669 // global metadata contains just the entry for foo + 670 // no entries for non-container types or other junk + 671 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 672 // scan an address to a static array of the container + 673 compute_container_address_offsets(r, ""); + 674 // compute_container_address_offsets creates no new entries + 675 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 676 // scanning precomputed metadata for the container + 677 reagent container("x:foo"); + 678 CHECK(contains_key(Container_metadata, container.type)); + 679 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 680 CHECK_EQ(SIZE(address_offsets2), 1); + 681 CHECK_EQ(address_offsets2.begin()->offset, 0); + 682 CHECK(address_offsets2.begin()->payload_type->atom); + 683 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 684 } + 685 + 686 void test_container_address_offsets_from_repeated_address_and_array_types() { + 687 int old_size = SIZE(Container_metadata); + 688 // define a container with an address at offset 0 + 689 run("container foo [\n" + 690 ¦ ¦ " x:address:num\n" + 691 ¦ ¦ "]\n"); + 692 // scan a deep nest of 'address' and 'array' types modifying a container + 693 reagent r("x:address:array:address:address:array:foo:10"); + 694 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 695 // global metadata contains just the entry for foo + 696 // no entries for non-container types or other junk + 697 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 698 compute_container_address_offsets(r, ""); + 699 // compute_container_address_offsets creates no new entries + 700 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 701 // scanning precomputed metadata for the container + 702 reagent container("x:foo"); + 703 CHECK(contains_key(Container_metadata, container.type)); + 704 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 705 CHECK_EQ(SIZE(address_offsets2), 1); + 706 CHECK_EQ(address_offsets2.begin()->offset, 0); + 707 CHECK(address_offsets2.begin()->payload_type->atom); + 708 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 709 } + 710 + 711 //: use metadata.address to update refcounts within containers, arrays and + 712 //: exclusive containers + 713 + 714 :(before "End Increment Refcounts(canonized_x)") + 715 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { + 716 const container_metadata& metadata = get(Container_metadata, canonized_x.type); + 717 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { + 718 ¦ if (!all_match(data, p->first)) continue; + 719 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) + 720 ¦ ¦ increment_refcount(data.at(info->offset)); + 721 } + 722 } + 723 + 724 :(before "End Decrement Refcounts(canonized_x)") + 725 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { + 726 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end(); + 727 // read from canonized_x but without canonizing again + 728 reagent/*copy*/ tmp = canonized_x; + 729 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL)); + 730 vector<double> data = read_memory(tmp); + 731 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end(); + 732 const container_metadata& metadata = get(Container_metadata, canonized_x.type); + 733 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { + 734 ¦ if (!all_match(data, p->first)) continue; + 735 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) { + 736 ¦ ¦ int element_address = get_or_insert(Memory, canonized_x.value + info->offset); + 737 ¦ ¦ reagent/*local*/ element; + 738 ¦ ¦ element.set_value(element_address+/*skip refcount*/1); + 739 ¦ ¦ element.type = new type_tree(*info->payload_type); + 740 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+/*refcount*/1); + 741 ¦ } + 742 } + 743 } + 744 + 745 :(code) + 746 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) { + 747 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { + 748 ¦ if (data.at(p->offset) != p->tag) + 749 ¦ ¦ return false; + 750 } + 751 return true; + 752 } + 753 + 754 :(scenario refcounts_put_container) + 755 container foo [ + 756 a:bar # contains an address + 757 ] + 758 container bar [ + 759 x:address:num + 760 ] + 761 def main [ + 762 1:address:num <- new number:type + 763 2:bar <- merge 1:address:num + 764 3:address:foo <- new foo:type + 765 *3:address:foo <- put *3:address:foo, a:offset, 2:bar + 766 ] + 767 +run: {1: ("address" "number")} <- new {number: "type"} + 768 +mem: incrementing refcount of 1000: 0 -> 1 + 769 +run: {2: "bar"} <- merge {1: ("address" "number")} + 770 +mem: incrementing refcount of 1000: 1 -> 2 + 771 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} + 772 # put increments refcount inside container + 773 +mem: incrementing refcount of 1000: 2 -> 3 + 774 + 775 :(scenario refcounts_put_index_array) + 776 container bar [ + 777 x:address:num + 778 ] + 779 def main [ + 780 1:address:num <- new number:type + 781 2:bar <- merge 1:address:num + 782 3:address:array:bar <- new bar:type, 3 + 783 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar + 784 ] + 785 +run: {1: ("address" "number")} <- new {number: "type"} + 786 +mem: incrementing refcount of 1000: 0 -> 1 + 787 +run: {2: "bar"} <- merge {1: ("address" "number")} + 788 +mem: incrementing refcount of 1000: 1 -> 2 + 789 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} + 790 # put-index increments refcount inside container + 791 +mem: incrementing refcount of 1000: 2 -> 3 + 792 + 793 :(scenario refcounts_maybe_convert_container) + 794 exclusive-container foo [ + 795 a:num + 796 b:bar # contains an address + 797 ] + 798 container bar [ + 799 x:address:num + 800 ] + 801 def main [ + 802 1:address:num <- new number:type + 803 2:bar <- merge 1:address:num + 804 3:foo <- merge 1/b, 2:bar + 805 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b + 806 ] + 807 +run: {1: ("address" "number")} <- new {number: "type"} + 808 +mem: incrementing refcount of 1000: 0 -> 1 + 809 +run: {2: "bar"} <- merge {1: ("address" "number")} + 810 +mem: incrementing refcount of 1000: 1 -> 2 + 811 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} + 812 +mem: incrementing refcount of 1000: 2 -> 3 + 813 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} + 814 +mem: incrementing refcount of 1000: 3 -> 4 + 815 + 816 :(scenario refcounts_copy_doubly_nested) + 817 container foo [ + 818 a:bar # no addresses + 819 b:curr # contains addresses + 820 ] + 821 container bar [ + 822 x:num + 823 y:num + 824 ] + 825 container curr [ + 826 x:num + 827 y:address:num # address inside container inside container + 828 ] + 829 def main [ + 830 1:address:num <- new number:type + 831 2:address:curr <- new curr:type + 832 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num + 833 3:address:foo <- new foo:type + 834 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr + 835 4:foo <- copy *3:address:foo + 836 ] + 837 +transform: compute address offsets for container foo + 838 +transform: checking container foo, element 1 + 839 +transform: address at offset 3 + 840 +run: {1: ("address" "number")} <- new {number: "type"} + 841 +mem: incrementing refcount of 1000: 0 -> 1 + 842 # storing an address in a container updates its refcount + 843 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} + 844 +mem: incrementing refcount of 1000: 1 -> 2 + 845 # storing a container in a container updates refcounts of any contained addresses + 846 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} + 847 +mem: incrementing refcount of 1000: 2 -> 3 + 848 # copying a container containing a container containing an address updates refcount + 849 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} + 850 +mem: incrementing refcount of 1000: 3 -> 4 + 851 + 852 :(scenario refcounts_copy_exclusive_container_within_container) + 853 container foo [ + 854 a:num + 855 b:bar + 856 ] + 857 exclusive-container bar [ + 858 x:num + 859 y:num + 860 z:address:num + 861 ] + 862 def main [ + 863 1:address:num <- new number:type + 864 2:bar <- merge 0/x, 34 + 865 3:foo <- merge 12, 2:bar + 866 5:bar <- merge 1/y, 35 + 867 6:foo <- merge 13, 5:bar + 868 8:bar <- merge 2/z, 1:address:num + 869 9:foo <- merge 14, 8:bar + 870 11:foo <- copy 9:foo + 871 ] + 872 +run: {1: ("address" "number")} <- new {number: "type"} + 873 +mem: incrementing refcount of 1000: 0 -> 1 + 874 # no change while merging items of other types + 875 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} + 876 +mem: incrementing refcount of 1000: 1 -> 2 + 877 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} + 878 +mem: incrementing refcount of 1000: 2 -> 3 + 879 +run: {11: "foo"} <- copy {9: "foo"} + 880 +mem: incrementing refcount of 1000: 3 -> 4 + 881 + 882 :(scenario refcounts_copy_container_within_exclusive_container) + 883 exclusive-container foo [ + 884 a:num + 885 b:bar + 886 ] + 887 container bar [ + 888 x:num + 889 y:num + 890 z:address:num + 891 ] + 892 def main [ + 893 1:address:num <- new number:type + 894 2:foo <- merge 0/a, 34 + 895 6:foo <- merge 0/a, 35 + 896 10:bar <- merge 2/x, 15/y, 1:address:num + 897 13:foo <- merge 1/b, 10:bar + 898 17:foo <- copy 13:foo + 899 ] + 900 +run: {1: ("address" "number")} <- new {number: "type"} + 901 +mem: incrementing refcount of 1000: 0 -> 1 + 902 # no change while merging items of other types + 903 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} + 904 +mem: incrementing refcount of 1000: 1 -> 2 + 905 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} + 906 +mem: incrementing refcount of 1000: 2 -> 3 + 907 +run: {17: "foo"} <- copy {13: "foo"} + 908 +mem: incrementing refcount of 1000: 3 -> 4 + 909 + 910 :(scenario refcounts_copy_exclusive_container_within_exclusive_container) + 911 exclusive-container foo [ + 912 a:num + 913 b:bar + 914 ] + 915 exclusive-container bar [ + 916 x:num + 917 y:address:num + 918 ] + 919 def main [ + 920 1:address:num <- new number:type + 921 10:foo <- merge 1/b, 1/y, 1:address:num + 922 20:foo <- copy 10:foo + 923 ] + 924 +run: {1: ("address" "number")} <- new {number: "type"} + 925 +mem: incrementing refcount of 1000: 0 -> 1 + 926 # no change while merging items of other types + 927 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} + 928 +mem: incrementing refcount of 1000: 1 -> 2 + 929 +run: {20: "foo"} <- copy {10: "foo"} + 930 +mem: incrementing refcount of 1000: 2 -> 3 + 931 + 932 :(scenario refcounts_copy_array_within_container) + 933 container foo [ + 934 x:address:array:num + 935 ] + 936 def main [ + 937 1:address:array:num <- new number:type, 3 + 938 2:foo <- merge 1:address:array:num + 939 3:address:array:num <- new number:type, 5 + 940 2:foo <- merge 3:address:array:num + 941 ] + 942 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} + 943 +mem: incrementing refcount of 1000: 0 -> 1 + 944 +run: {2: "foo"} <- merge {1: ("address" "array" "number")} + 945 +mem: incrementing refcount of 1000: 1 -> 2 + 946 +run: {2: "foo"} <- merge {3: ("address" "array" "number")} + 947 +mem: decrementing refcount of 1000: 2 -> 1 + 948 + 949 :(scenario refcounts_copy_address_within_static_array_within_container) + 950 container foo [ + 951 a:array:bar:3 + 952 b:address:num + 953 ] + 954 container bar [ + 955 y:num + 956 z:address:num + 957 ] + 958 def main [ + 959 1:address:num <- new number:type + 960 2:bar <- merge 34, 1:address:num + 961 10:array:bar:3 <- create-array + 962 put-index 10:array:bar:3, 1, 2:bar + 963 20:foo <- merge 10:array:bar:3, 1:address:num + 964 1:address:num <- copy 0 + 965 2:bar <- merge 34, 1:address:num + 966 put-index 10:array:bar:3, 1, 2:bar + 967 20:foo <- merge 10:array:bar:3, 1:address:num + 968 ] + 969 +run: {1: ("address" "number")} <- new {number: "type"} + 970 +mem: incrementing refcount of 1000: 0 -> 1 + 971 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} + 972 +mem: incrementing refcount of 1000: 1 -> 2 + 973 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} + 974 +mem: incrementing refcount of 1000: 2 -> 3 + 975 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} + 976 +mem: incrementing refcount of 1000: 3 -> 4 + 977 +mem: incrementing refcount of 1000: 4 -> 5 + 978 +run: {1: ("address" "number")} <- copy {0: "literal"} + 979 +mem: decrementing refcount of 1000: 5 -> 4 + 980 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} + 981 +mem: decrementing refcount of 1000: 4 -> 3 + 982 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} + 983 +mem: decrementing refcount of 1000: 3 -> 2 + 984 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} + 985 +mem: decrementing refcount of 1000: 2 -> 1 + 986 +mem: decrementing refcount of 1000: 1 -> 0 + 987 + 988 :(scenario refcounts_handle_exclusive_containers_with_different_tags) + 989 container foo1 [ + 990 x:address:num + 991 y:num + 992 ] + 993 container foo2 [ + 994 x:num + 995 y:address:num + 996 ] + 997 exclusive-container bar [ + 998 a:foo1 + 999 b:foo2 +1000 ] +1001 def main [ +1002 1:address:num <- copy 12000/unsafe # pretend allocation +1003 *1:address:num <- copy 34 +1004 2:bar <- merge 0/foo1, 1:address:num, 97 +1005 5:address:num <- copy 13000/unsafe # pretend allocation +1006 *5:address:num <- copy 35 +1007 6:bar <- merge 1/foo2, 98, 5:address:num +1008 2:bar <- copy 6:bar +1009 ] +1010 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} +1011 +mem: incrementing refcount of 12000: 1 -> 2 +1012 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} +1013 +mem: incrementing refcount of 13000: 1 -> 2 +1014 +run: {2: "bar"} <- copy {6: "bar"} +1015 +mem: incrementing refcount of 13000: 2 -> 3 +1016 +mem: decrementing refcount of 12000: 2 -> 1 +1017 +1018 :(code) +1019 bool is_mu_container(const reagent& r) { +1020 return is_mu_container(r.type); +1021 } +1022 bool is_mu_container(const type_tree* type) { +1023 if (!type) return false; +1024 // End is_mu_container(type) Special-cases +1025 if (type->value == 0) return false; +1026 type_info& info = get(Type, type->value); +1027 return info.kind == CONTAINER; +1028 } +1029 +1030 bool is_mu_exclusive_container(const reagent& r) { +1031 return is_mu_exclusive_container(r.type); +1032 } +1033 bool is_mu_exclusive_container(const type_tree* type) { +1034 if (!type) return false; +1035 // End is_mu_exclusive_container(type) Special-cases +1036 if (type->value == 0) return false; +1037 type_info& info = get(Type, type->value); +1038 return info.kind == EXCLUSIVE_CONTAINER; +1039 } +1040 +1041 //:: Counters for trying to understand where Mu programs are spending time +1042 //:: updating refcounts. +1043 +1044 :(before "End Globals") +1045 int Total_refcount_updates = 0; +1046 map<recipe_ordinal, map</*step index*/int, /*num refcount updates*/int> > Num_refcount_updates; +1047 :(after "Running One Instruction") +1048 int initial_num_refcount_updates = Total_refcount_updates; +1049 :(before "End Running One Instruction") +1050 if (Run_profiler) { +1051 Num_refcount_updates[current_call().running_recipe][current_call().running_step_index] +1052 ¦ ¦ += (Total_refcount_updates - initial_num_refcount_updates); +1053 initial_num_refcount_updates = Total_refcount_updates; +1054 } +1055 :(before "End Non-primitive Call(caller_frame)") +1056 Num_refcount_updates[caller_frame.running_recipe][caller_frame.running_step_index] +1057 ¦ += (Total_refcount_updates - initial_num_refcount_updates); +1058 initial_num_refcount_updates = Total_refcount_updates; +1059 :(after "Starting Reply") +1060 if (Run_profiler) { +1061 Num_refcount_updates[current_call().running_recipe][current_call().running_step_index] +1062 ¦ ¦ += (Total_refcount_updates - initial_num_refcount_updates); +1063 initial_num_refcount_updates = Total_refcount_updates; +1064 } +1065 :(before "End dump_profile") +1066 fout.open("profile.refcounts"); +1067 if (fout) { +1068 for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) +1069 ¦ dump_recipe_profile(p->first, p->second, fout); +1070 } +1071 fout.close(); +1072 :(code) +1073 void dump_recipe_profile(recipe_ordinal ridx, const recipe& r, ostream& out) { +1074 out << "recipe " << r.name << " [\n"; +1075 for (int i = 0; i < SIZE(r.steps); ++i) { +1076 ¦ out << std::setw(6) << Num_refcount_updates[ridx][i] << ' ' << to_string(r.steps.at(i)) << '\n'; +1077 } +1078 out << "]\n\n"; +1079 } -- cgit 1.4.1-2-gfad0