From 465229a22a68f9c5cb94ba7853c44328f1bf85c1 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 12 Mar 2017 00:08:47 -0800 Subject: 3788 --- html/036refcount.cc.html | 1599 +++++++++++++++--------------- html/055shape_shifting_container.cc.html | 2 +- 2 files changed, 805 insertions(+), 796 deletions(-) diff --git a/html/036refcount.cc.html b/html/036refcount.cc.html index 1ef47a04..cf23c02a 100644 --- a/html/036refcount.cc.html +++ b/html/036refcount.cc.html @@ -278,811 +278,820 @@ if ('onhashchange' in window) { 213 214 :(before "End type_tree Definition") 215 struct address_element_info { - 216 int offset; // where inside a container type (after flattening nested containers!) the address lies - 217 const type_tree* payload_type; // all the information we need to compute sizes of items inside an address inside a container. Doesn't need to be a full-scale reagent, since an address inside a container can never be an array, and arrays are the only type that need to know their location to compute their size. - 218 address_element_info(int o, const type_tree* p); - 219 address_element_info(const address_element_info& other); - 220 ~address_element_info(); - 221 address_element_info& operator=(const address_element_info& other); - 222 }; - 223 :(code) - 224 address_element_info::address_element_info(int o, const type_tree* p) { - 225 offset = o; - 226 payload_type = p; - 227 } - 228 address_element_info::address_element_info(const address_element_info& other) { - 229 offset = other.offset; - 230 payload_type = copy(other.payload_type); - 231 } - 232 address_element_info::~address_element_info() { - 233 if (payload_type) { - 234 ¦ delete payload_type; - 235 ¦ payload_type = NULL; - 236 } - 237 } - 238 address_element_info& address_element_info::operator=(const address_element_info& other) { - 239 offset = other.offset; - 240 if (payload_type) delete payload_type; - 241 payload_type = copy(other.payload_type); - 242 return *this; - 243 } - 244 - 245 :(before "End type_tree Definition") - 246 // For exclusive containers we might sometimes have an address at some offset - 247 // if some other offset has a specific tag. This struct encapsulates such - 248 // guards. - 249 struct tag_condition_info { - 250 int offset; - 251 int tag; - 252 tag_condition_info(int o, int t) :offset(o), tag(t) {} - 253 }; - 254 - 255 :(before "End container_metadata Fields") - 256 // a list of facts of the form: - 257 // - 258 // IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN - 259 // for all address_element_infos: - 260 // 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) - 261 map<set<tag_condition_info>, set<address_element_info> > address; - 262 :(code) - 263 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) { - 264 if (a.size() != b.size()) return a.size() < b.size(); - 265 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { - 266 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; - 267 ¦ if (pa->tag != pb->tag) return pa->tag < pb->tag; - 268 } - 269 return false; // equal - 270 } - 271 bool operator<(const tag_condition_info& a, const tag_condition_info& b) { - 272 if (a.offset != b.offset) return a.offset < b.offset; - 273 if (a.tag != b.tag) return a.tag < b.tag; - 274 return false; // equal - 275 } - 276 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) { - 277 if (a.size() != b.size()) return a.size() < b.size(); - 278 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { - 279 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; - 280 } - 281 return false; // equal - 282 } - 283 bool operator<(const address_element_info& a, const address_element_info& b) { - 284 if (a.offset != b.offset) return a.offset < b.offset; - 285 return false; // equal - 286 } - 287 - 288 //: populate metadata.address in a separate transform, because it requires - 289 //: already knowing the sizes of all types - 290 - 291 :(after "Transform.push_back(compute_container_sizes)") - 292 Transform.push_back(compute_container_address_offsets); // idempotent - 293 :(code) - 294 void compute_container_address_offsets(const recipe_ordinal r) { - 295 recipe& caller = get(Recipe, r); - 296 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end(); - 297 for (int i = 0; i < SIZE(caller.steps); ++i) { - 298 ¦ instruction& inst = caller.steps.at(i); - 299 ¦ trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end(); - 300 ¦ for (int i = 0; i < SIZE(inst.ingredients); ++i) - 301 ¦ ¦ compute_container_address_offsets(inst.ingredients.at(i), " in '"+to_original_string(inst)+"'"); - 302 ¦ for (int i = 0; i < SIZE(inst.products); ++i) - 303 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+to_original_string(inst)+"'"); - 304 } - 305 } - 306 - 307 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) { - 308 if (is_literal(r) || is_dummy(r)) return; - 309 compute_container_address_offsets(r.type, location_for_error_messages); - 310 if (contains_key(Container_metadata, r.type)) - 311 ¦ r.metadata = get(Container_metadata, r.type); - 312 } - 313 - 314 // the recursive structure of this function needs to exactly match - 315 // compute_container_sizes - 316 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) { - 317 if (!type) return; - 318 if (!type->atom) { - 319 ¦ if (!type->left->atom) { - 320 ¦ ¦ raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end(); - 321 ¦ ¦ return; - 322 ¦ } - 323 ¦ if (type->left->name == "address") - 324 ¦ ¦ compute_container_address_offsets(payload_type(type), location_for_error_messages); - 325 ¦ else if (type->left->name == "array") - 326 ¦ ¦ compute_container_address_offsets(array_element(type), location_for_error_messages); - 327 ¦ // End compute_container_address_offsets Non-atom Special-cases - 328 } - 329 const type_tree* base_type = type; - 330 // Update base_type in compute_container_address_offsets - 331 if (!contains_key(Type, base_type->value)) return; // error raised elsewhere - 332 type_info& info = get(Type, base_type->value); - 333 if (info.kind == CONTAINER) { - 334 ¦ compute_container_address_offsets(info, type, location_for_error_messages); - 335 } - 336 if (info.kind == EXCLUSIVE_CONTAINER) { - 337 ¦ compute_exclusive_container_address_offsets(info, type, location_for_error_messages); - 338 } - 339 } - 340 - 341 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) { - 342 container_metadata& metadata = get(Container_metadata, full_type); - 343 if (!metadata.address.empty()) return; - 344 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end(); - 345 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages); - 346 } - 347 - 348 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) { - 349 container_metadata& metadata = get(Container_metadata, full_type); - 350 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end(); - 351 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) { - 352 ¦ set<tag_condition_info> key; - 353 ¦ key.insert(tag_condition_info(/*tag is at offset*/0, tag)); - 354 ¦ append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages); - 355 } - 356 } - 357 - 358 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) { - 359 if (is_mu_address(type)) { - 360 ¦ get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type)))); - 361 ¦ return; - 362 } - 363 const type_tree* base_type = type; - 364 // Update base_type in append_container_address_offsets - 365 const type_info& info = get(Type, base_type->value); - 366 if (info.kind == CONTAINER) { - 367 ¦ for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) { - 368 ¦ ¦ trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end(); - 369 ¦ ¦ reagent/*copy*/ element = element_type(type, curr_index); // not base_type - 370 ¦ ¦ // Compute Container Address Offset(element) - 371 ¦ ¦ if (is_mu_address(element)) { - 372 ¦ ¦ ¦ trace(9993, "transform") << "address at offset " << curr_offset << end(); - 373 ¦ ¦ ¦ get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type)))); - 374 ¦ ¦ ¦ ++curr_offset; - 375 ¦ ¦ } - 376 ¦ ¦ else if (is_mu_array(element)) { - 377 ¦ ¦ ¦ curr_offset += /*array length*/1; - 378 ¦ ¦ ¦ const type_tree* array_element_type = array_element(element.type); - 379 ¦ ¦ ¦ int array_element_size = size_of(array_element_type); - 380 ¦ ¦ ¦ for (int i = 0; i < static_array_length(element.type); ++i) { - 381 ¦ ¦ ¦ ¦ append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages); - 382 ¦ ¦ ¦ ¦ curr_offset += array_element_size; - 383 ¦ ¦ ¦ } + 216 // Where inside a container type (after flattening nested containers!) the + 217 // address lies + 218 int offset; + 219 + 220 // All the information we need to compute sizes of items inside an address + 221 // inside a container. `payload_type` Doesn't need to be a full-scale + 222 // reagent, since an address inside a container can never be an array, and + 223 // arrays are the only type that need to know their location to compute their + 224 // size. + 225 const type_tree* payload_type; + 226 + 227 address_element_info(int o, const type_tree* p); + 228 address_element_info(const address_element_info& other); + 229 ~address_element_info(); + 230 address_element_info& operator=(const address_element_info& other); + 231 }; + 232 :(code) + 233 address_element_info::address_element_info(int o, const type_tree* p) { + 234 offset = o; + 235 payload_type = p; + 236 } + 237 address_element_info::address_element_info(const address_element_info& other) { + 238 offset = other.offset; + 239 payload_type = copy(other.payload_type); + 240 } + 241 address_element_info::~address_element_info() { + 242 if (payload_type) { + 243 ¦ delete payload_type; + 244 ¦ payload_type = NULL; + 245 } + 246 } + 247 address_element_info& address_element_info::operator=(const address_element_info& other) { + 248 offset = other.offset; + 249 if (payload_type) delete payload_type; + 250 payload_type = copy(other.payload_type); + 251 return *this; + 252 } + 253 + 254 :(before "End type_tree Definition") + 255 // For exclusive containers we might sometimes have an address at some offset + 256 // if some other offset has a specific tag. This struct encapsulates such + 257 // guards. + 258 struct tag_condition_info { + 259 int offset; + 260 int tag; + 261 tag_condition_info(int o, int t) :offset(o), tag(t) {} + 262 }; + 263 + 264 :(before "End container_metadata Fields") + 265 // a list of facts of the form: + 266 // + 267 // IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN + 268 // for all address_element_infos: + 269 // 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) + 270 map<set<tag_condition_info>, set<address_element_info> > address; + 271 :(code) + 272 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) { + 273 if (a.size() != b.size()) return a.size() < b.size(); + 274 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { + 275 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; + 276 ¦ if (pa->tag != pb->tag) return pa->tag < pb->tag; + 277 } + 278 return false; // equal + 279 } + 280 bool operator<(const tag_condition_info& a, const tag_condition_info& b) { + 281 if (a.offset != b.offset) return a.offset < b.offset; + 282 if (a.tag != b.tag) return a.tag < b.tag; + 283 return false; // equal + 284 } + 285 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) { + 286 if (a.size() != b.size()) return a.size() < b.size(); + 287 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) { + 288 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset; + 289 } + 290 return false; // equal + 291 } + 292 bool operator<(const address_element_info& a, const address_element_info& b) { + 293 if (a.offset != b.offset) return a.offset < b.offset; + 294 return false; // equal + 295 } + 296 + 297 //: populate metadata.address in a separate transform, because it requires + 298 //: already knowing the sizes of all types + 299 + 300 :(after "Transform.push_back(compute_container_sizes)") + 301 Transform.push_back(compute_container_address_offsets); // idempotent + 302 :(code) + 303 void compute_container_address_offsets(const recipe_ordinal r) { + 304 recipe& caller = get(Recipe, r); + 305 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end(); + 306 for (int i = 0; i < SIZE(caller.steps); ++i) { + 307 ¦ instruction& inst = caller.steps.at(i); + 308 ¦ trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end(); + 309 ¦ for (int i = 0; i < SIZE(inst.ingredients); ++i) + 310 ¦ ¦ compute_container_address_offsets(inst.ingredients.at(i), " in '"+to_original_string(inst)+"'"); + 311 ¦ for (int i = 0; i < SIZE(inst.products); ++i) + 312 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+to_original_string(inst)+"'"); + 313 } + 314 } + 315 + 316 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) { + 317 if (is_literal(r) || is_dummy(r)) return; + 318 compute_container_address_offsets(r.type, location_for_error_messages); + 319 if (contains_key(Container_metadata, r.type)) + 320 ¦ r.metadata = get(Container_metadata, r.type); + 321 } + 322 + 323 // the recursive structure of this function needs to exactly match + 324 // compute_container_sizes + 325 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) { + 326 if (!type) return; + 327 if (!type->atom) { + 328 ¦ if (!type->left->atom) { + 329 ¦ ¦ raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end(); + 330 ¦ ¦ return; + 331 ¦ } + 332 ¦ if (type->left->name == "address") + 333 ¦ ¦ compute_container_address_offsets(payload_type(type), location_for_error_messages); + 334 ¦ else if (type->left->name == "array") + 335 ¦ ¦ compute_container_address_offsets(array_element(type), location_for_error_messages); + 336 ¦ // End compute_container_address_offsets Non-atom Special-cases + 337 } + 338 const type_tree* base_type = type; + 339 // Update base_type in compute_container_address_offsets + 340 if (!contains_key(Type, base_type->value)) return; // error raised elsewhere + 341 type_info& info = get(Type, base_type->value); + 342 if (info.kind == CONTAINER) { + 343 ¦ compute_container_address_offsets(info, type, location_for_error_messages); + 344 } + 345 if (info.kind == EXCLUSIVE_CONTAINER) { + 346 ¦ compute_exclusive_container_address_offsets(info, type, location_for_error_messages); + 347 } + 348 } + 349 + 350 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) { + 351 container_metadata& metadata = get(Container_metadata, full_type); + 352 if (!metadata.address.empty()) return; + 353 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end(); + 354 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages); + 355 } + 356 + 357 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) { + 358 container_metadata& metadata = get(Container_metadata, full_type); + 359 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end(); + 360 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) { + 361 ¦ set<tag_condition_info> key; + 362 ¦ key.insert(tag_condition_info(/*tag is at offset*/0, tag)); + 363 ¦ append_addresses(/*skip tag offset*/1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages); + 364 } + 365 } + 366 + 367 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) { + 368 if (is_mu_address(type)) { + 369 ¦ get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type)))); + 370 ¦ return; + 371 } + 372 const type_tree* base_type = type; + 373 // Update base_type in append_container_address_offsets + 374 const type_info& info = get(Type, base_type->value); + 375 if (info.kind == CONTAINER) { + 376 ¦ for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) { + 377 ¦ ¦ trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end(); + 378 ¦ ¦ reagent/*copy*/ element = element_type(type, curr_index); // not base_type + 379 ¦ ¦ // Compute Container Address Offset(element) + 380 ¦ ¦ if (is_mu_address(element)) { + 381 ¦ ¦ ¦ trace(9993, "transform") << "address at offset " << curr_offset << end(); + 382 ¦ ¦ ¦ get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type)))); + 383 ¦ ¦ ¦ ++curr_offset; 384 ¦ ¦ } - 385 ¦ ¦ else if (is_mu_container(element)) { - 386 ¦ ¦ ¦ append_addresses(curr_offset, element.type, out, key, location_for_error_messages); - 387 ¦ ¦ ¦ curr_offset += size_of(element); - 388 ¦ ¦ } - 389 ¦ ¦ else if (is_mu_exclusive_container(element)) { - 390 ¦ ¦ ¦ const type_tree* element_base_type = element.type; - 391 ¦ ¦ ¦ // Update element_base_type For Exclusive Container in append_addresses - 392 ¦ ¦ ¦ const type_info& element_info = get(Type, element_base_type->value); - 393 ¦ ¦ ¦ for (int tag = 0; tag < SIZE(element_info.elements); ++tag) { - 394 ¦ ¦ ¦ ¦ set<tag_condition_info> new_key = key; - 395 ¦ ¦ ¦ ¦ new_key.insert(tag_condition_info(curr_offset, tag)); - 396 ¦ ¦ ¦ ¦ if (!contains_key(out, new_key)) - 397 ¦ ¦ ¦ ¦ ¦ append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages); - 398 ¦ ¦ ¦ } - 399 ¦ ¦ ¦ curr_offset += size_of(element); - 400 ¦ ¦ } - 401 ¦ ¦ else { - 402 ¦ ¦ ¦ // non-address primitive - 403 ¦ ¦ ¦ ++curr_offset; - 404 ¦ ¦ } - 405 ¦ } - 406 } - 407 else if (info.kind == EXCLUSIVE_CONTAINER) { - 408 ¦ for (int tag = 0; tag < SIZE(info.elements); ++tag) { - 409 ¦ ¦ set<tag_condition_info> new_key = key; - 410 ¦ ¦ new_key.insert(tag_condition_info(base_offset, tag)); - 411 ¦ ¦ if (!contains_key(out, new_key)) - 412 ¦ ¦ ¦ append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key, location_for_error_messages); - 413 ¦ } - 414 } - 415 } - 416 - 417 //: for the following unit tests we'll do the work of the transform by hand - 418 - 419 :(before "End Unit Tests") - 420 void test_container_address_offsets_empty() { - 421 int old_size = SIZE(Container_metadata); - 422 // define a container with no addresses - 423 reagent r("x:point"); - 424 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 425 // scan - 426 compute_container_address_offsets(r, ""); - 427 // global metadata contains just the entry for foo - 428 // no entries for non-container types or other junk - 429 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 430 // the reagent we scanned knows it has no addresses - 431 CHECK(r.metadata.address.empty()); - 432 // the global table contains an identical entry - 433 CHECK(contains_key(Container_metadata, r.type)); - 434 CHECK(get(Container_metadata, r.type).address.empty()); - 435 // compute_container_address_offsets creates no new entries - 436 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 437 } - 438 - 439 void test_container_address_offsets() { - 440 int old_size = SIZE(Container_metadata); - 441 // define a container with an address at offset 0 that we have the size for - 442 run("container foo [\n" - 443 ¦ ¦ " x:address:num\n" - 444 ¦ ¦ "]\n"); - 445 reagent r("x:foo"); - 446 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 447 // scan - 448 compute_container_address_offsets(r, ""); - 449 // global metadata contains just the entry for foo - 450 // no entries for non-container types or other junk - 451 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 452 // the reagent we scanned knows it has an address at offset 0 - 453 CHECK_EQ(SIZE(r.metadata.address), 1); - 454 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 455 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); // unconditional for containers - 456 CHECK_EQ(SIZE(address_offsets), 1); - 457 CHECK_EQ(address_offsets.begin()->offset, 0); - 458 CHECK(address_offsets.begin()->payload_type->atom); - 459 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 460 // the global table contains an identical entry - 461 CHECK(contains_key(Container_metadata, r.type)); - 462 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 463 CHECK_EQ(SIZE(address_offsets2), 1); - 464 CHECK_EQ(address_offsets2.begin()->offset, 0); - 465 CHECK(address_offsets2.begin()->payload_type->atom); - 466 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 467 // compute_container_address_offsets creates no new entries - 468 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 469 } - 470 - 471 void test_container_address_offsets_2() { - 472 int old_size = SIZE(Container_metadata); - 473 // define a container with an address at offset 1 that we have the size for - 474 run("container foo [\n" - 475 ¦ ¦ " x:num\n" - 476 ¦ ¦ " y:address:num\n" - 477 ¦ ¦ "]\n"); - 478 reagent r("x:foo"); - 479 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 480 // global metadata contains just the entry for foo - 481 // no entries for non-container types or other junk - 482 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 483 // scan - 484 compute_container_address_offsets(r, ""); - 485 // compute_container_address_offsets creates no new entries - 486 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 487 // the reagent we scanned knows it has an address at offset 1 - 488 CHECK_EQ(SIZE(r.metadata.address), 1); - 489 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 490 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); - 491 CHECK_EQ(SIZE(address_offsets), 1); - 492 CHECK_EQ(address_offsets.begin()->offset, 1); // - 493 CHECK(address_offsets.begin()->payload_type->atom); - 494 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 495 // the global table contains an identical entry - 496 CHECK(contains_key(Container_metadata, r.type)); - 497 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 498 CHECK_EQ(SIZE(address_offsets2), 1); - 499 CHECK_EQ(address_offsets2.begin()->offset, 1); // - 500 CHECK(address_offsets2.begin()->payload_type->atom); - 501 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 502 } - 503 - 504 void test_container_address_offsets_nested() { - 505 int old_size = SIZE(Container_metadata); - 506 // define a container with a nested container containing an address - 507 run("container foo [\n" - 508 ¦ ¦ " x:address:num\n" - 509 ¦ ¦ " y:num\n" - 510 ¦ ¦ "]\n" - 511 ¦ ¦ "container bar [\n" - 512 ¦ ¦ " p:point\n" - 513 ¦ ¦ " f:foo\n" // nested container containing address - 514 ¦ ¦ "]\n"); - 515 reagent r("x:bar"); - 516 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 517 // global metadata contains entries for bar and included types: point and foo - 518 // no entries for non-container types or other junk - 519 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); - 520 // scan - 521 compute_container_address_offsets(r, ""); - 522 // the reagent we scanned knows it has an address at offset 2 - 523 CHECK_EQ(SIZE(r.metadata.address), 1); - 524 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); - 525 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); - 526 CHECK_EQ(SIZE(address_offsets), 1); - 527 CHECK_EQ(address_offsets.begin()->offset, 2); // - 528 CHECK(address_offsets.begin()->payload_type->atom); - 529 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); - 530 // the global table also knows its address offset - 531 CHECK(contains_key(Container_metadata, r.type)); - 532 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); - 533 CHECK_EQ(SIZE(address_offsets2), 1); - 534 CHECK_EQ(address_offsets2.begin()->offset, 2); // - 535 CHECK(address_offsets2.begin()->payload_type->atom); - 536 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 537 // compute_container_address_offsets creates no new entries - 538 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); - 539 } - 540 - 541 void test_container_address_offsets_from_address() { - 542 int old_size = SIZE(Container_metadata); - 543 // define a container with an address at offset 0 - 544 run("container foo [\n" - 545 ¦ ¦ " x:address:num\n" - 546 ¦ ¦ "]\n"); - 547 reagent r("x:address:foo"); - 548 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 549 // global metadata contains just the entry for foo - 550 // no entries for non-container types or other junk - 551 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 552 // scan an address to the container - 553 compute_container_address_offsets(r, ""); - 554 // compute_container_address_offsets creates no new entries - 555 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 556 // scanning precomputed metadata for the container - 557 reagent container("x:foo"); - 558 CHECK(contains_key(Container_metadata, container.type)); - 559 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 560 CHECK_EQ(SIZE(address_offsets2), 1); - 561 CHECK_EQ(address_offsets2.begin()->offset, 0); - 562 CHECK(address_offsets2.begin()->payload_type->atom); - 563 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 564 } - 565 - 566 void test_container_address_offsets_from_array() { - 567 int old_size = SIZE(Container_metadata); - 568 // define a container with an address at offset 0 - 569 run("container foo [\n" - 570 ¦ ¦ " x:address:num\n" - 571 ¦ ¦ "]\n"); - 572 reagent r("x:array:foo"); - 573 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 574 // global metadata contains just the entry for foo - 575 // no entries for non-container types or other junk - 576 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 577 // scan an array of the container - 578 compute_container_address_offsets(r, ""); - 579 // compute_container_address_offsets creates no new entries - 580 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 581 // scanning precomputed metadata for the container - 582 reagent container("x:foo"); - 583 CHECK(contains_key(Container_metadata, container.type)); - 584 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 585 CHECK_EQ(SIZE(address_offsets2), 1); - 586 CHECK_EQ(address_offsets2.begin()->offset, 0); - 587 CHECK(address_offsets2.begin()->payload_type->atom); - 588 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 589 } - 590 - 591 void test_container_address_offsets_from_address_to_array() { - 592 int old_size = SIZE(Container_metadata); - 593 // define a container with an address at offset 0 - 594 run("container foo [\n" - 595 ¦ ¦ " x:address:num\n" - 596 ¦ ¦ "]\n"); - 597 reagent r("x:address:array:foo"); - 598 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 599 // global metadata contains just the entry for foo - 600 // no entries for non-container types or other junk - 601 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 602 // scan an address to an array of the container - 603 compute_container_address_offsets(r, ""); - 604 // compute_container_address_offsets creates no new entries - 605 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 606 // scanning precomputed metadata for the container - 607 reagent container("x:foo"); - 608 CHECK(contains_key(Container_metadata, container.type)); - 609 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 610 CHECK_EQ(SIZE(address_offsets2), 1); - 611 CHECK_EQ(address_offsets2.begin()->offset, 0); - 612 CHECK(address_offsets2.begin()->payload_type->atom); - 613 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 614 } - 615 - 616 void test_container_address_offsets_from_static_array() { - 617 int old_size = SIZE(Container_metadata); - 618 // define a container with an address at offset 0 - 619 run("container foo [\n" - 620 ¦ ¦ " x:address:num\n" - 621 ¦ ¦ "]\n"); - 622 reagent r("x:array:foo:10"); - 623 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 624 // global metadata contains just the entry for foo - 625 // no entries for non-container types or other junk - 626 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 627 // scan a static array of the container - 628 compute_container_address_offsets(r, ""); - 629 // compute_container_address_offsets creates no new entries - 630 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 631 // scanning precomputed metadata for the container - 632 reagent container("x:foo"); - 633 CHECK(contains_key(Container_metadata, container.type)); - 634 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 635 CHECK_EQ(SIZE(address_offsets2), 1); - 636 CHECK_EQ(address_offsets2.begin()->offset, 0); - 637 CHECK(address_offsets2.begin()->payload_type->atom); - 638 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 639 } - 640 - 641 void test_container_address_offsets_from_address_to_static_array() { - 642 int old_size = SIZE(Container_metadata); - 643 // define a container with an address at offset 0 - 644 run("container foo [\n" - 645 ¦ ¦ " x:address:num\n" - 646 ¦ ¦ "]\n"); - 647 reagent r("x:address:array:foo:10"); - 648 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 649 // global metadata contains just the entry for foo - 650 // no entries for non-container types or other junk - 651 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 652 // scan an address to a static array of the container - 653 compute_container_address_offsets(r, ""); - 654 // compute_container_address_offsets creates no new entries - 655 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 656 // scanning precomputed metadata for the container - 657 reagent container("x:foo"); - 658 CHECK(contains_key(Container_metadata, container.type)); - 659 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 660 CHECK_EQ(SIZE(address_offsets2), 1); - 661 CHECK_EQ(address_offsets2.begin()->offset, 0); - 662 CHECK(address_offsets2.begin()->payload_type->atom); - 663 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 664 } - 665 - 666 void test_container_address_offsets_from_repeated_address_and_array_types() { - 667 int old_size = SIZE(Container_metadata); - 668 // define a container with an address at offset 0 - 669 run("container foo [\n" - 670 ¦ ¦ " x:address:num\n" - 671 ¦ ¦ "]\n"); - 672 // scan a deep nest of 'address' and 'array' types modifying a container - 673 reagent r("x:address:array:address:address:array:foo:10"); - 674 compute_container_sizes(r, ""); // need to first pre-populate the metadata - 675 // global metadata contains just the entry for foo - 676 // no entries for non-container types or other junk - 677 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 678 compute_container_address_offsets(r, ""); - 679 // compute_container_address_offsets creates no new entries - 680 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); - 681 // scanning precomputed metadata for the container - 682 reagent container("x:foo"); - 683 CHECK(contains_key(Container_metadata, container.type)); - 684 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); - 685 CHECK_EQ(SIZE(address_offsets2), 1); - 686 CHECK_EQ(address_offsets2.begin()->offset, 0); - 687 CHECK(address_offsets2.begin()->payload_type->atom); - 688 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); - 689 } - 690 - 691 //: use metadata.address to update refcounts within containers, arrays and - 692 //: exclusive containers - 693 - 694 :(before "End Increment Refcounts(canonized_x)") - 695 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - 696 const container_metadata& metadata = get(Container_metadata, canonized_x.type); - 697 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - 698 ¦ if (!all_match(data, p->first)) continue; - 699 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) - 700 ¦ ¦ increment_refcount(data.at(info->offset)); - 701 } - 702 } - 703 - 704 :(before "End Decrement Refcounts(canonized_x)") - 705 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - 706 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end(); - 707 // read from canonized_x but without canonizing again - 708 // todo: inline without running canonize all over again - 709 reagent/*copy*/ tmp = canonized_x; - 710 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL)); - 711 vector<double> data = read_memory(tmp); - 712 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end(); - 713 const container_metadata& metadata = get(Container_metadata, canonized_x.type); - 714 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - 715 ¦ if (!all_match(data, p->first)) continue; - 716 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) { - 717 ¦ ¦ int element_address = get_or_insert(Memory, canonized_x.value + info->offset); - 718 ¦ ¦ reagent/*local*/ element; - 719 ¦ ¦ element.set_value(element_address+/*skip refcount*/1); - 720 ¦ ¦ element.type = new type_tree(*info->payload_type); - 721 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+/*refcount*/1); - 722 ¦ } - 723 } - 724 } - 725 - 726 :(code) - 727 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) { - 728 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { - 729 ¦ if (data.at(p->offset) != p->tag) - 730 ¦ ¦ return false; - 731 } - 732 return true; + 385 ¦ ¦ else if (is_mu_array(element)) { + 386 ¦ ¦ ¦ curr_offset += /*array length*/1; + 387 ¦ ¦ ¦ const type_tree* array_element_type = array_element(element.type); + 388 ¦ ¦ ¦ int array_element_size = size_of(array_element_type); + 389 ¦ ¦ ¦ for (int i = 0; i < static_array_length(element.type); ++i) { + 390 ¦ ¦ ¦ ¦ append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages); + 391 ¦ ¦ ¦ ¦ curr_offset += array_element_size; + 392 ¦ ¦ ¦ } + 393 ¦ ¦ } + 394 ¦ ¦ else if (is_mu_container(element)) { + 395 ¦ ¦ ¦ append_addresses(curr_offset, element.type, out, key, location_for_error_messages); + 396 ¦ ¦ ¦ curr_offset += size_of(element); + 397 ¦ ¦ } + 398 ¦ ¦ else if (is_mu_exclusive_container(element)) { + 399 ¦ ¦ ¦ const type_tree* element_base_type = element.type; + 400 ¦ ¦ ¦ // Update element_base_type For Exclusive Container in append_addresses + 401 ¦ ¦ ¦ const type_info& element_info = get(Type, element_base_type->value); + 402 ¦ ¦ ¦ for (int tag = 0; tag < SIZE(element_info.elements); ++tag) { + 403 ¦ ¦ ¦ ¦ set<tag_condition_info> new_key = key; + 404 ¦ ¦ ¦ ¦ new_key.insert(tag_condition_info(curr_offset, tag)); + 405 ¦ ¦ ¦ ¦ if (!contains_key(out, new_key)) + 406 ¦ ¦ ¦ ¦ ¦ append_addresses(curr_offset+/*skip tag*/1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages); + 407 ¦ ¦ ¦ } + 408 ¦ ¦ ¦ curr_offset += size_of(element); + 409 ¦ ¦ } + 410 ¦ ¦ else { + 411 ¦ ¦ ¦ // non-address primitive + 412 ¦ ¦ ¦ ++curr_offset; + 413 ¦ ¦ } + 414 ¦ } + 415 } + 416 else if (info.kind == EXCLUSIVE_CONTAINER) { + 417 ¦ for (int tag = 0; tag < SIZE(info.elements); ++tag) { + 418 ¦ ¦ set<tag_condition_info> new_key = key; + 419 ¦ ¦ new_key.insert(tag_condition_info(base_offset, tag)); + 420 ¦ ¦ if (!contains_key(out, new_key)) + 421 ¦ ¦ ¦ append_addresses(base_offset+/*skip tag*/1, variant_type(type, tag).type, out, new_key, location_for_error_messages); + 422 ¦ } + 423 } + 424 } + 425 + 426 //: for the following unit tests we'll do the work of the transform by hand + 427 + 428 :(before "End Unit Tests") + 429 void test_container_address_offsets_empty() { + 430 int old_size = SIZE(Container_metadata); + 431 // define a container with no addresses + 432 reagent r("x:point"); + 433 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 434 // scan + 435 compute_container_address_offsets(r, ""); + 436 // global metadata contains just the entry for foo + 437 // no entries for non-container types or other junk + 438 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 439 // the reagent we scanned knows it has no addresses + 440 CHECK(r.metadata.address.empty()); + 441 // the global table contains an identical entry + 442 CHECK(contains_key(Container_metadata, r.type)); + 443 CHECK(get(Container_metadata, r.type).address.empty()); + 444 // compute_container_address_offsets creates no new entries + 445 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 446 } + 447 + 448 void test_container_address_offsets() { + 449 int old_size = SIZE(Container_metadata); + 450 // define a container with an address at offset 0 that we have the size for + 451 run("container foo [\n" + 452 ¦ ¦ " x:address:num\n" + 453 ¦ ¦ "]\n"); + 454 reagent r("x:foo"); + 455 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 456 // scan + 457 compute_container_address_offsets(r, ""); + 458 // global metadata contains just the entry for foo + 459 // no entries for non-container types or other junk + 460 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 461 // the reagent we scanned knows it has an address at offset 0 + 462 CHECK_EQ(SIZE(r.metadata.address), 1); + 463 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 464 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); // unconditional for containers + 465 CHECK_EQ(SIZE(address_offsets), 1); + 466 CHECK_EQ(address_offsets.begin()->offset, 0); + 467 CHECK(address_offsets.begin()->payload_type->atom); + 468 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 469 // the global table contains an identical entry + 470 CHECK(contains_key(Container_metadata, r.type)); + 471 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 472 CHECK_EQ(SIZE(address_offsets2), 1); + 473 CHECK_EQ(address_offsets2.begin()->offset, 0); + 474 CHECK(address_offsets2.begin()->payload_type->atom); + 475 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 476 // compute_container_address_offsets creates no new entries + 477 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 478 } + 479 + 480 void test_container_address_offsets_2() { + 481 int old_size = SIZE(Container_metadata); + 482 // define a container with an address at offset 1 that we have the size for + 483 run("container foo [\n" + 484 ¦ ¦ " x:num\n" + 485 ¦ ¦ " y:address:num\n" + 486 ¦ ¦ "]\n"); + 487 reagent r("x:foo"); + 488 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 489 // global metadata contains just the entry for foo + 490 // no entries for non-container types or other junk + 491 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 492 // scan + 493 compute_container_address_offsets(r, ""); + 494 // compute_container_address_offsets creates no new entries + 495 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 496 // the reagent we scanned knows it has an address at offset 1 + 497 CHECK_EQ(SIZE(r.metadata.address), 1); + 498 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 499 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); + 500 CHECK_EQ(SIZE(address_offsets), 1); + 501 CHECK_EQ(address_offsets.begin()->offset, 1); // + 502 CHECK(address_offsets.begin()->payload_type->atom); + 503 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 504 // the global table contains an identical entry + 505 CHECK(contains_key(Container_metadata, r.type)); + 506 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 507 CHECK_EQ(SIZE(address_offsets2), 1); + 508 CHECK_EQ(address_offsets2.begin()->offset, 1); // + 509 CHECK(address_offsets2.begin()->payload_type->atom); + 510 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 511 } + 512 + 513 void test_container_address_offsets_nested() { + 514 int old_size = SIZE(Container_metadata); + 515 // define a container with a nested container containing an address + 516 run("container foo [\n" + 517 ¦ ¦ " x:address:num\n" + 518 ¦ ¦ " y:num\n" + 519 ¦ ¦ "]\n" + 520 ¦ ¦ "container bar [\n" + 521 ¦ ¦ " p:point\n" + 522 ¦ ¦ " f:foo\n" // nested container containing address + 523 ¦ ¦ "]\n"); + 524 reagent r("x:bar"); + 525 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 526 // global metadata contains entries for bar and included types: point and foo + 527 // no entries for non-container types or other junk + 528 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); + 529 // scan + 530 compute_container_address_offsets(r, ""); + 531 // the reagent we scanned knows it has an address at offset 2 + 532 CHECK_EQ(SIZE(r.metadata.address), 1); + 533 CHECK(contains_key(r.metadata.address, set<tag_condition_info>())); + 534 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>()); + 535 CHECK_EQ(SIZE(address_offsets), 1); + 536 CHECK_EQ(address_offsets.begin()->offset, 2); // + 537 CHECK(address_offsets.begin()->payload_type->atom); + 538 CHECK_EQ(address_offsets.begin()->payload_type->name, "number"); + 539 // the global table also knows its address offset + 540 CHECK(contains_key(Container_metadata, r.type)); + 541 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>()); + 542 CHECK_EQ(SIZE(address_offsets2), 1); + 543 CHECK_EQ(address_offsets2.begin()->offset, 2); // + 544 CHECK(address_offsets2.begin()->payload_type->atom); + 545 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 546 // compute_container_address_offsets creates no new entries + 547 CHECK_EQ(SIZE(Container_metadata)-old_size, 3); + 548 } + 549 + 550 void test_container_address_offsets_from_address() { + 551 int old_size = SIZE(Container_metadata); + 552 // define a container with an address at offset 0 + 553 run("container foo [\n" + 554 ¦ ¦ " x:address:num\n" + 555 ¦ ¦ "]\n"); + 556 reagent r("x:address:foo"); + 557 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 558 // global metadata contains just the entry for foo + 559 // no entries for non-container types or other junk + 560 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 561 // scan an address to the container + 562 compute_container_address_offsets(r, ""); + 563 // compute_container_address_offsets creates no new entries + 564 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 565 // scanning precomputed metadata for the container + 566 reagent container("x:foo"); + 567 CHECK(contains_key(Container_metadata, container.type)); + 568 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 569 CHECK_EQ(SIZE(address_offsets2), 1); + 570 CHECK_EQ(address_offsets2.begin()->offset, 0); + 571 CHECK(address_offsets2.begin()->payload_type->atom); + 572 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 573 } + 574 + 575 void test_container_address_offsets_from_array() { + 576 int old_size = SIZE(Container_metadata); + 577 // define a container with an address at offset 0 + 578 run("container foo [\n" + 579 ¦ ¦ " x:address:num\n" + 580 ¦ ¦ "]\n"); + 581 reagent r("x:array:foo"); + 582 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 583 // global metadata contains just the entry for foo + 584 // no entries for non-container types or other junk + 585 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 586 // scan an array of the container + 587 compute_container_address_offsets(r, ""); + 588 // compute_container_address_offsets creates no new entries + 589 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 590 // scanning precomputed metadata for the container + 591 reagent container("x:foo"); + 592 CHECK(contains_key(Container_metadata, container.type)); + 593 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 594 CHECK_EQ(SIZE(address_offsets2), 1); + 595 CHECK_EQ(address_offsets2.begin()->offset, 0); + 596 CHECK(address_offsets2.begin()->payload_type->atom); + 597 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 598 } + 599 + 600 void test_container_address_offsets_from_address_to_array() { + 601 int old_size = SIZE(Container_metadata); + 602 // define a container with an address at offset 0 + 603 run("container foo [\n" + 604 ¦ ¦ " x:address:num\n" + 605 ¦ ¦ "]\n"); + 606 reagent r("x:address:array:foo"); + 607 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 608 // global metadata contains just the entry for foo + 609 // no entries for non-container types or other junk + 610 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 611 // scan an address to an array of the container + 612 compute_container_address_offsets(r, ""); + 613 // compute_container_address_offsets creates no new entries + 614 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 615 // scanning precomputed metadata for the container + 616 reagent container("x:foo"); + 617 CHECK(contains_key(Container_metadata, container.type)); + 618 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 619 CHECK_EQ(SIZE(address_offsets2), 1); + 620 CHECK_EQ(address_offsets2.begin()->offset, 0); + 621 CHECK(address_offsets2.begin()->payload_type->atom); + 622 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 623 } + 624 + 625 void test_container_address_offsets_from_static_array() { + 626 int old_size = SIZE(Container_metadata); + 627 // define a container with an address at offset 0 + 628 run("container foo [\n" + 629 ¦ ¦ " x:address:num\n" + 630 ¦ ¦ "]\n"); + 631 reagent r("x:array:foo:10"); + 632 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 633 // global metadata contains just the entry for foo + 634 // no entries for non-container types or other junk + 635 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 636 // scan a static array of the container + 637 compute_container_address_offsets(r, ""); + 638 // compute_container_address_offsets creates no new entries + 639 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 640 // scanning precomputed metadata for the container + 641 reagent container("x:foo"); + 642 CHECK(contains_key(Container_metadata, container.type)); + 643 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 644 CHECK_EQ(SIZE(address_offsets2), 1); + 645 CHECK_EQ(address_offsets2.begin()->offset, 0); + 646 CHECK(address_offsets2.begin()->payload_type->atom); + 647 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 648 } + 649 + 650 void test_container_address_offsets_from_address_to_static_array() { + 651 int old_size = SIZE(Container_metadata); + 652 // define a container with an address at offset 0 + 653 run("container foo [\n" + 654 ¦ ¦ " x:address:num\n" + 655 ¦ ¦ "]\n"); + 656 reagent r("x:address:array:foo:10"); + 657 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 658 // global metadata contains just the entry for foo + 659 // no entries for non-container types or other junk + 660 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 661 // scan an address to a static array of the container + 662 compute_container_address_offsets(r, ""); + 663 // compute_container_address_offsets creates no new entries + 664 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 665 // scanning precomputed metadata for the container + 666 reagent container("x:foo"); + 667 CHECK(contains_key(Container_metadata, container.type)); + 668 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 669 CHECK_EQ(SIZE(address_offsets2), 1); + 670 CHECK_EQ(address_offsets2.begin()->offset, 0); + 671 CHECK(address_offsets2.begin()->payload_type->atom); + 672 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 673 } + 674 + 675 void test_container_address_offsets_from_repeated_address_and_array_types() { + 676 int old_size = SIZE(Container_metadata); + 677 // define a container with an address at offset 0 + 678 run("container foo [\n" + 679 ¦ ¦ " x:address:num\n" + 680 ¦ ¦ "]\n"); + 681 // scan a deep nest of 'address' and 'array' types modifying a container + 682 reagent r("x:address:array:address:address:array:foo:10"); + 683 compute_container_sizes(r, ""); // need to first pre-populate the metadata + 684 // global metadata contains just the entry for foo + 685 // no entries for non-container types or other junk + 686 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 687 compute_container_address_offsets(r, ""); + 688 // compute_container_address_offsets creates no new entries + 689 CHECK_EQ(SIZE(Container_metadata)-old_size, 1); + 690 // scanning precomputed metadata for the container + 691 reagent container("x:foo"); + 692 CHECK(contains_key(Container_metadata, container.type)); + 693 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>()); + 694 CHECK_EQ(SIZE(address_offsets2), 1); + 695 CHECK_EQ(address_offsets2.begin()->offset, 0); + 696 CHECK(address_offsets2.begin()->payload_type->atom); + 697 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); + 698 } + 699 + 700 //: use metadata.address to update refcounts within containers, arrays and + 701 //: exclusive containers + 702 + 703 :(before "End Increment Refcounts(canonized_x)") + 704 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { + 705 const container_metadata& metadata = get(Container_metadata, canonized_x.type); + 706 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { + 707 ¦ if (!all_match(data, p->first)) continue; + 708 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) + 709 ¦ ¦ increment_refcount(data.at(info->offset)); + 710 } + 711 } + 712 + 713 :(before "End Decrement Refcounts(canonized_x)") + 714 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { + 715 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end(); + 716 // read from canonized_x but without canonizing again + 717 // todo: inline without running canonize all over again + 718 reagent/*copy*/ tmp = canonized_x; + 719 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL)); + 720 vector<double> data = read_memory(tmp); + 721 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end(); + 722 const container_metadata& metadata = get(Container_metadata, canonized_x.type); + 723 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { + 724 ¦ if (!all_match(data, p->first)) continue; + 725 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) { + 726 ¦ ¦ int element_address = get_or_insert(Memory, canonized_x.value + info->offset); + 727 ¦ ¦ reagent/*local*/ element; + 728 ¦ ¦ element.set_value(element_address+/*skip refcount*/1); + 729 ¦ ¦ element.type = new type_tree(*info->payload_type); + 730 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+/*refcount*/1); + 731 ¦ } + 732 } 733 } 734 - 735 :(scenario refcounts_put_container) - 736 container foo [ - 737 a:bar # contains an address - 738 ] - 739 container bar [ - 740 x:address:num - 741 ] - 742 def main [ - 743 1:address:num <- new number:type - 744 2:bar <- merge 1:address:num - 745 3:address:foo <- new foo:type - 746 *3:address:foo <- put *3:address:foo, a:offset, 2:bar + 735 :(code) + 736 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) { + 737 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { + 738 ¦ if (data.at(p->offset) != p->tag) + 739 ¦ ¦ return false; + 740 } + 741 return true; + 742 } + 743 + 744 :(scenario refcounts_put_container) + 745 container foo [ + 746 a:bar # contains an address 747 ] - 748 +run: {1: ("address" "number")} <- new {number: "type"} - 749 +mem: incrementing refcount of 1000: 0 -> 1 - 750 +run: {2: "bar"} <- merge {1: ("address" "number")} - 751 +mem: incrementing refcount of 1000: 1 -> 2 - 752 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} - 753 # put increments refcount inside container - 754 +mem: incrementing refcount of 1000: 2 -> 3 - 755 - 756 :(scenario refcounts_put_index_array) - 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:array:bar <- new bar:type, 3 - 764 *3:address:array:bar <- put-index *3:address:array:bar, 0, 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" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} - 771 # put-index increments refcount inside container - 772 +mem: incrementing refcount of 1000: 2 -> 3 - 773 - 774 :(scenario refcounts_maybe_convert_container) - 775 exclusive-container foo [ - 776 a:num - 777 b:bar # contains an address - 778 ] - 779 container bar [ - 780 x:address:num - 781 ] - 782 def main [ - 783 1:address:num <- new number:type - 784 2:bar <- merge 1:address:num - 785 3:foo <- merge 1/b, 2:bar - 786 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b + 748 container bar [ + 749 x:address:num + 750 ] + 751 def main [ + 752 1:address:num <- new number:type + 753 2:bar <- merge 1:address:num + 754 3:address:foo <- new foo:type + 755 *3:address:foo <- put *3:address:foo, a:offset, 2:bar + 756 ] + 757 +run: {1: ("address" "number")} <- new {number: "type"} + 758 +mem: incrementing refcount of 1000: 0 -> 1 + 759 +run: {2: "bar"} <- merge {1: ("address" "number")} + 760 +mem: incrementing refcount of 1000: 1 -> 2 + 761 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} + 762 # put increments refcount inside container + 763 +mem: incrementing refcount of 1000: 2 -> 3 + 764 + 765 :(scenario refcounts_put_index_array) + 766 container bar [ + 767 x:address:num + 768 ] + 769 def main [ + 770 1:address:num <- new number:type + 771 2:bar <- merge 1:address:num + 772 3:address:array:bar <- new bar:type, 3 + 773 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar + 774 ] + 775 +run: {1: ("address" "number")} <- new {number: "type"} + 776 +mem: incrementing refcount of 1000: 0 -> 1 + 777 +run: {2: "bar"} <- merge {1: ("address" "number")} + 778 +mem: incrementing refcount of 1000: 1 -> 2 + 779 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} + 780 # put-index increments refcount inside container + 781 +mem: incrementing refcount of 1000: 2 -> 3 + 782 + 783 :(scenario refcounts_maybe_convert_container) + 784 exclusive-container foo [ + 785 a:num + 786 b:bar # contains an address 787 ] - 788 +run: {1: ("address" "number")} <- new {number: "type"} - 789 +mem: incrementing refcount of 1000: 0 -> 1 - 790 +run: {2: "bar"} <- merge {1: ("address" "number")} - 791 +mem: incrementing refcount of 1000: 1 -> 2 - 792 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} - 793 +mem: incrementing refcount of 1000: 2 -> 3 - 794 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} - 795 +mem: incrementing refcount of 1000: 3 -> 4 - 796 - 797 :(scenario refcounts_copy_doubly_nested) - 798 container foo [ - 799 a:bar # no addresses - 800 b:curr # contains addresses - 801 ] - 802 container bar [ - 803 x:num - 804 y:num - 805 ] - 806 container curr [ - 807 x:num - 808 y:address:num # address inside container inside container - 809 ] - 810 def main [ - 811 1:address:num <- new number:type - 812 2:address:curr <- new curr:type - 813 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num - 814 3:address:foo <- new foo:type - 815 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr - 816 4:foo <- copy *3:address:foo - 817 ] - 818 +transform: compute address offsets for container foo - 819 +transform: checking container foo, element 1 - 820 +transform: address at offset 3 - 821 +run: {1: ("address" "number")} <- new {number: "type"} - 822 +mem: incrementing refcount of 1000: 0 -> 1 - 823 # storing an address in a container updates its refcount - 824 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} - 825 +mem: incrementing refcount of 1000: 1 -> 2 - 826 # storing a container in a container updates refcounts of any contained addresses - 827 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} - 828 +mem: incrementing refcount of 1000: 2 -> 3 - 829 # copying a container containing a container containing an address updates refcount - 830 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} - 831 +mem: incrementing refcount of 1000: 3 -> 4 - 832 - 833 :(scenario refcounts_copy_exclusive_container_within_container) - 834 container foo [ - 835 a:num - 836 b:bar - 837 ] - 838 exclusive-container bar [ - 839 x:num - 840 y:num - 841 z:address:num - 842 ] - 843 def main [ - 844 1:address:num <- new number:type - 845 2:bar <- merge 0/x, 34 - 846 3:foo <- merge 12, 2:bar - 847 5:bar <- merge 1/y, 35 - 848 6:foo <- merge 13, 5:bar - 849 8:bar <- merge 2/z, 1:address:num - 850 9:foo <- merge 14, 8:bar - 851 11:foo <- copy 9:foo - 852 ] - 853 +run: {1: ("address" "number")} <- new {number: "type"} - 854 +mem: incrementing refcount of 1000: 0 -> 1 - 855 # no change while merging items of other types - 856 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} - 857 +mem: incrementing refcount of 1000: 1 -> 2 - 858 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} - 859 +mem: incrementing refcount of 1000: 2 -> 3 - 860 +run: {11: "foo"} <- copy {9: "foo"} - 861 +mem: incrementing refcount of 1000: 3 -> 4 - 862 - 863 :(scenario refcounts_copy_container_within_exclusive_container) - 864 exclusive-container foo [ - 865 a:num - 866 b:bar - 867 ] - 868 container bar [ - 869 x:num - 870 y:num - 871 z:address:num - 872 ] - 873 def main [ - 874 1:address:num <- new number:type - 875 2:foo <- merge 0/a, 34 - 876 6:foo <- merge 0/a, 35 - 877 10:bar <- merge 2/x, 15/y, 1:address:num - 878 13:foo <- merge 1/b, 10:bar - 879 17:foo <- copy 13:foo - 880 ] - 881 +run: {1: ("address" "number")} <- new {number: "type"} - 882 +mem: incrementing refcount of 1000: 0 -> 1 - 883 # no change while merging items of other types - 884 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} - 885 +mem: incrementing refcount of 1000: 1 -> 2 - 886 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} - 887 +mem: incrementing refcount of 1000: 2 -> 3 - 888 +run: {17: "foo"} <- copy {13: "foo"} - 889 +mem: incrementing refcount of 1000: 3 -> 4 - 890 - 891 :(scenario refcounts_copy_exclusive_container_within_exclusive_container) - 892 exclusive-container foo [ - 893 a:num - 894 b:bar - 895 ] - 896 exclusive-container bar [ - 897 x:num - 898 y:address:num - 899 ] - 900 def main [ - 901 1:address:num <- new number:type - 902 10:foo <- merge 1/b, 1/y, 1:address:num - 903 20:foo <- copy 10:foo + 788 container bar [ + 789 x:address:num + 790 ] + 791 def main [ + 792 1:address:num <- new number:type + 793 2:bar <- merge 1:address:num + 794 3:foo <- merge 1/b, 2:bar + 795 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b + 796 ] + 797 +run: {1: ("address" "number")} <- new {number: "type"} + 798 +mem: incrementing refcount of 1000: 0 -> 1 + 799 +run: {2: "bar"} <- merge {1: ("address" "number")} + 800 +mem: incrementing refcount of 1000: 1 -> 2 + 801 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} + 802 +mem: incrementing refcount of 1000: 2 -> 3 + 803 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} + 804 +mem: incrementing refcount of 1000: 3 -> 4 + 805 + 806 :(scenario refcounts_copy_doubly_nested) + 807 container foo [ + 808 a:bar # no addresses + 809 b:curr # contains addresses + 810 ] + 811 container bar [ + 812 x:num + 813 y:num + 814 ] + 815 container curr [ + 816 x:num + 817 y:address:num # address inside container inside container + 818 ] + 819 def main [ + 820 1:address:num <- new number:type + 821 2:address:curr <- new curr:type + 822 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num + 823 3:address:foo <- new foo:type + 824 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr + 825 4:foo <- copy *3:address:foo + 826 ] + 827 +transform: compute address offsets for container foo + 828 +transform: checking container foo, element 1 + 829 +transform: address at offset 3 + 830 +run: {1: ("address" "number")} <- new {number: "type"} + 831 +mem: incrementing refcount of 1000: 0 -> 1 + 832 # storing an address in a container updates its refcount + 833 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} + 834 +mem: incrementing refcount of 1000: 1 -> 2 + 835 # storing a container in a container updates refcounts of any contained addresses + 836 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} + 837 +mem: incrementing refcount of 1000: 2 -> 3 + 838 # copying a container containing a container containing an address updates refcount + 839 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} + 840 +mem: incrementing refcount of 1000: 3 -> 4 + 841 + 842 :(scenario refcounts_copy_exclusive_container_within_container) + 843 container foo [ + 844 a:num + 845 b:bar + 846 ] + 847 exclusive-container bar [ + 848 x:num + 849 y:num + 850 z:address:num + 851 ] + 852 def main [ + 853 1:address:num <- new number:type + 854 2:bar <- merge 0/x, 34 + 855 3:foo <- merge 12, 2:bar + 856 5:bar <- merge 1/y, 35 + 857 6:foo <- merge 13, 5:bar + 858 8:bar <- merge 2/z, 1:address:num + 859 9:foo <- merge 14, 8:bar + 860 11:foo <- copy 9:foo + 861 ] + 862 +run: {1: ("address" "number")} <- new {number: "type"} + 863 +mem: incrementing refcount of 1000: 0 -> 1 + 864 # no change while merging items of other types + 865 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} + 866 +mem: incrementing refcount of 1000: 1 -> 2 + 867 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} + 868 +mem: incrementing refcount of 1000: 2 -> 3 + 869 +run: {11: "foo"} <- copy {9: "foo"} + 870 +mem: incrementing refcount of 1000: 3 -> 4 + 871 + 872 :(scenario refcounts_copy_container_within_exclusive_container) + 873 exclusive-container foo [ + 874 a:num + 875 b:bar + 876 ] + 877 container bar [ + 878 x:num + 879 y:num + 880 z:address:num + 881 ] + 882 def main [ + 883 1:address:num <- new number:type + 884 2:foo <- merge 0/a, 34 + 885 6:foo <- merge 0/a, 35 + 886 10:bar <- merge 2/x, 15/y, 1:address:num + 887 13:foo <- merge 1/b, 10:bar + 888 17:foo <- copy 13:foo + 889 ] + 890 +run: {1: ("address" "number")} <- new {number: "type"} + 891 +mem: incrementing refcount of 1000: 0 -> 1 + 892 # no change while merging items of other types + 893 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} + 894 +mem: incrementing refcount of 1000: 1 -> 2 + 895 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} + 896 +mem: incrementing refcount of 1000: 2 -> 3 + 897 +run: {17: "foo"} <- copy {13: "foo"} + 898 +mem: incrementing refcount of 1000: 3 -> 4 + 899 + 900 :(scenario refcounts_copy_exclusive_container_within_exclusive_container) + 901 exclusive-container foo [ + 902 a:num + 903 b:bar 904 ] - 905 +run: {1: ("address" "number")} <- new {number: "type"} - 906 +mem: incrementing refcount of 1000: 0 -> 1 - 907 # no change while merging items of other types - 908 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} - 909 +mem: incrementing refcount of 1000: 1 -> 2 - 910 +run: {20: "foo"} <- copy {10: "foo"} - 911 +mem: incrementing refcount of 1000: 2 -> 3 - 912 - 913 :(scenario refcounts_copy_array_within_container) - 914 container foo [ - 915 x:address:array:num - 916 ] - 917 def main [ - 918 1:address:array:num <- new number:type, 3 - 919 2:foo <- merge 1:address:array:num - 920 3:address:array:num <- new number:type, 5 - 921 2:foo <- merge 3:address:array:num - 922 ] - 923 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} - 924 +mem: incrementing refcount of 1000: 0 -> 1 - 925 +run: {2: "foo"} <- merge {1: ("address" "array" "number")} - 926 +mem: incrementing refcount of 1000: 1 -> 2 - 927 +run: {2: "foo"} <- merge {3: ("address" "array" "number")} - 928 +mem: decrementing refcount of 1000: 2 -> 1 - 929 - 930 :(scenario refcounts_copy_address_within_static_array_within_container) - 931 container foo [ - 932 a:array:bar:3 - 933 b:address:num - 934 ] - 935 container bar [ - 936 y:num - 937 z:address:num - 938 ] - 939 def main [ - 940 1:address:num <- new number:type - 941 2:bar <- merge 34, 1:address:num - 942 10:array:bar:3 <- create-array - 943 put-index 10:array:bar:3, 1, 2:bar - 944 20:foo <- merge 10:array:bar:3, 1:address:num - 945 1:address:num <- copy 0 - 946 2:bar <- merge 34, 1:address:num - 947 put-index 10:array:bar:3, 1, 2:bar - 948 20:foo <- merge 10:array:bar:3, 1:address:num - 949 ] - 950 +run: {1: ("address" "number")} <- new {number: "type"} - 951 +mem: incrementing refcount of 1000: 0 -> 1 - 952 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} - 953 +mem: incrementing refcount of 1000: 1 -> 2 - 954 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} - 955 +mem: incrementing refcount of 1000: 2 -> 3 - 956 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} - 957 +mem: incrementing refcount of 1000: 3 -> 4 - 958 +mem: incrementing refcount of 1000: 4 -> 5 - 959 +run: {1: ("address" "number")} <- copy {0: "literal"} - 960 +mem: decrementing refcount of 1000: 5 -> 4 + 905 exclusive-container bar [ + 906 x:num + 907 y:address:num + 908 ] + 909 def main [ + 910 1:address:num <- new number:type + 911 10:foo <- merge 1/b, 1/y, 1:address:num + 912 20:foo <- copy 10:foo + 913 ] + 914 +run: {1: ("address" "number")} <- new {number: "type"} + 915 +mem: incrementing refcount of 1000: 0 -> 1 + 916 # no change while merging items of other types + 917 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} + 918 +mem: incrementing refcount of 1000: 1 -> 2 + 919 +run: {20: "foo"} <- copy {10: "foo"} + 920 +mem: incrementing refcount of 1000: 2 -> 3 + 921 + 922 :(scenario refcounts_copy_array_within_container) + 923 container foo [ + 924 x:address:array:num + 925 ] + 926 def main [ + 927 1:address:array:num <- new number:type, 3 + 928 2:foo <- merge 1:address:array:num + 929 3:address:array:num <- new number:type, 5 + 930 2:foo <- merge 3:address:array:num + 931 ] + 932 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} + 933 +mem: incrementing refcount of 1000: 0 -> 1 + 934 +run: {2: "foo"} <- merge {1: ("address" "array" "number")} + 935 +mem: incrementing refcount of 1000: 1 -> 2 + 936 +run: {2: "foo"} <- merge {3: ("address" "array" "number")} + 937 +mem: decrementing refcount of 1000: 2 -> 1 + 938 + 939 :(scenario refcounts_copy_address_within_static_array_within_container) + 940 container foo [ + 941 a:array:bar:3 + 942 b:address:num + 943 ] + 944 container bar [ + 945 y:num + 946 z:address:num + 947 ] + 948 def main [ + 949 1:address:num <- new number:type + 950 2:bar <- merge 34, 1:address:num + 951 10:array:bar:3 <- create-array + 952 put-index 10:array:bar:3, 1, 2:bar + 953 20:foo <- merge 10:array:bar:3, 1:address:num + 954 1:address:num <- copy 0 + 955 2:bar <- merge 34, 1:address:num + 956 put-index 10:array:bar:3, 1, 2:bar + 957 20:foo <- merge 10:array:bar:3, 1:address:num + 958 ] + 959 +run: {1: ("address" "number")} <- new {number: "type"} + 960 +mem: incrementing refcount of 1000: 0 -> 1 961 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} - 962 +mem: decrementing refcount of 1000: 4 -> 3 + 962 +mem: incrementing refcount of 1000: 1 -> 2 963 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} - 964 +mem: decrementing refcount of 1000: 3 -> 2 + 964 +mem: incrementing refcount of 1000: 2 -> 3 965 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} - 966 +mem: decrementing refcount of 1000: 2 -> 1 - 967 +mem: decrementing refcount of 1000: 1 -> 0 - 968 - 969 :(scenario refcounts_handle_exclusive_containers_with_different_tags) - 970 container foo1 [ - 971 x:address:num - 972 y:num - 973 ] - 974 container foo2 [ - 975 x:num - 976 y:address:num - 977 ] - 978 exclusive-container bar [ - 979 a:foo1 - 980 b:foo2 - 981 ] - 982 def main [ - 983 1:address:num <- copy 12000/unsafe # pretend allocation - 984 *1:address:num <- copy 34 - 985 2:bar <- merge 0/foo1, 1:address:num, 97 - 986 5:address:num <- copy 13000/unsafe # pretend allocation - 987 *5:address:num <- copy 35 - 988 6:bar <- merge 1/foo2, 98, 5:address:num - 989 2:bar <- copy 6:bar + 966 +mem: incrementing refcount of 1000: 3 -> 4 + 967 +mem: incrementing refcount of 1000: 4 -> 5 + 968 +run: {1: ("address" "number")} <- copy {0: "literal"} + 969 +mem: decrementing refcount of 1000: 5 -> 4 + 970 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} + 971 +mem: decrementing refcount of 1000: 4 -> 3 + 972 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} + 973 +mem: decrementing refcount of 1000: 3 -> 2 + 974 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} + 975 +mem: decrementing refcount of 1000: 2 -> 1 + 976 +mem: decrementing refcount of 1000: 1 -> 0 + 977 + 978 :(scenario refcounts_handle_exclusive_containers_with_different_tags) + 979 container foo1 [ + 980 x:address:num + 981 y:num + 982 ] + 983 container foo2 [ + 984 x:num + 985 y:address:num + 986 ] + 987 exclusive-container bar [ + 988 a:foo1 + 989 b:foo2 990 ] - 991 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} - 992 +mem: incrementing refcount of 12000: 1 -> 2 - 993 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} - 994 +mem: incrementing refcount of 13000: 1 -> 2 - 995 +run: {2: "bar"} <- copy {6: "bar"} - 996 +mem: incrementing refcount of 13000: 2 -> 3 - 997 +mem: decrementing refcount of 12000: 2 -> 1 - 998 - 999 :(code) -1000 bool is_mu_container(const reagent& r) { -1001 return is_mu_container(r.type); -1002 } -1003 bool is_mu_container(const type_tree* type) { -1004 if (!type) return false; -1005 // End is_mu_container(type) Special-cases -1006 if (type->value == 0) return false; -1007 type_info& info = get(Type, type->value); -1008 return info.kind == CONTAINER; -1009 } -1010 -1011 bool is_mu_exclusive_container(const reagent& r) { -1012 return is_mu_exclusive_container(r.type); -1013 } -1014 bool is_mu_exclusive_container(const type_tree* type) { -1015 if (!type) return false; -1016 // End is_mu_exclusive_container(type) Special-cases -1017 if (type->value == 0) return false; -1018 type_info& info = get(Type, type->value); -1019 return info.kind == EXCLUSIVE_CONTAINER; -1020 } + 991 def main [ + 992 1:address:num <- copy 12000/unsafe # pretend allocation + 993 *1:address:num <- copy 34 + 994 2:bar <- merge 0/foo1, 1:address:num, 97 + 995 5:address:num <- copy 13000/unsafe # pretend allocation + 996 *5:address:num <- copy 35 + 997 6:bar <- merge 1/foo2, 98, 5:address:num + 998 2:bar <- copy 6:bar + 999 ] +1000 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} +1001 +mem: incrementing refcount of 12000: 1 -> 2 +1002 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} +1003 +mem: incrementing refcount of 13000: 1 -> 2 +1004 +run: {2: "bar"} <- copy {6: "bar"} +1005 +mem: incrementing refcount of 13000: 2 -> 3 +1006 +mem: decrementing refcount of 12000: 2 -> 1 +1007 +1008 :(code) +1009 bool is_mu_container(const reagent& r) { +1010 return is_mu_container(r.type); +1011 } +1012 bool is_mu_container(const type_tree* type) { +1013 if (!type) return false; +1014 // End is_mu_container(type) Special-cases +1015 if (type->value == 0) return false; +1016 type_info& info = get(Type, type->value); +1017 return info.kind == CONTAINER; +1018 } +1019 +1020 bool is_mu_exclusive_container(const reagent& r) { +1021 return is_mu_exclusive_container(r.type); +1022 } +1023 bool is_mu_exclusive_container(const type_tree* type) { +1024 if (!type) return false; +1025 // End is_mu_exclusive_container(type) Special-cases +1026 if (type->value == 0) return false; +1027 type_info& info = get(Type, type->value); +1028 return info.kind == EXCLUSIVE_CONTAINER; +1029 } diff --git a/html/055shape_shifting_container.cc.html b/html/055shape_shifting_container.cc.html index c6fcd7de..df067253 100644 --- a/html/055shape_shifting_container.cc.html +++ b/html/055shape_shifting_container.cc.html @@ -687,7 +687,7 @@ if ('onhashchange' in window) { 621 return; 622 } 623 if (info.kind == EXCLUSIVE_CONTAINER) { -624 compute_exclusive_container_address_offsets(info, type, location_for_error_messages); +624 compute_exclusive_container_address_offsets(info, type, location_for_error_messages); 625 return; 626 } 627 -- cgit 1.4.1-2-gfad0