1
2
3
4 :(scenario refcounts)
5 def main [
6 1:address:num <- copy 1000/unsafe
7 2:address:num <- copy 1:address:num
8 1:address:num <- copy 0
9 2:address:num <- copy 0
10 ]
11 +run: {1: ("address" "number")} <- copy {1000: "literal", "unsafe": ()}
12 +mem: incrementing refcount of 1000: 0 -> 1
13 +run: {2: ("address" "number")} <- copy {1: ("address" "number")}
14 +mem: incrementing refcount of 1000: 1 -> 2
15 +run: {1: ("address" "number")} <- copy {0: "literal"}
16 +mem: decrementing refcount of 1000: 2 -> 1
17 +run: {2: ("address" "number")} <- copy {0: "literal"}
18 +mem: decrementing refcount of 1000: 1 -> 0
19
20 :(before "End write_memory(x) Special-cases")
21 update_any_refcounts(x, data);
22
23 :(before "End Globals")
24 bool Reclaim_memory = true;
25 :(before "End Commandline Options(*arg)")
26 else if (is_equal(*arg, "--no-reclaim")) {
27 cerr << "Disabling memory reclamation. Some tests will fail.\n";
28 Reclaim_memory = false;
29 }
30 :(code)
31 void update_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
32 if (!Reclaim_memory) return;
33 if (!should_update_refcounts()) return;
34 increment_any_refcounts(canonized_x, data);
35 decrement_any_refcounts(canonized_x);
36 }
37
38
39 bool should_update_refcounts() {
40
41 return true;
42 }
43
44 void increment_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
45 if (is_mu_address(canonized_x)) {
46 ¦ assert(scalar(data));
47 ¦ assert(!canonized_x.metadata.size);
48 ¦ increment_refcount(data.at(0));
49 }
50
51 }
52
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
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
89 }
90
91 int payload_size(reagent x) {
92 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
93 lookup_memory_core(x, false);
94 return size_of(x) + 1;
95 }
96
97 :(scenario refcounts_reflexive)
98 def main [
99 1:address:num <- new number:type
100
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
113 foo 1:address:num
114
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
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
129
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
146 +mem: incrementing refcount of 1000: 1 -> 2
147
148 :(after "Write Memory in PUT in Run")
149 reagent 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
166 +mem: incrementing refcount of 1000: 1 -> 2
167
168 :(after "Write Memory in PUT_INDEX in Run")
169 reagent 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
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
191 +mem: incrementing refcount of 1000: 2 -> 3
192
193 :(after "Write Memory in Successful MAYBE_CONVERT")
194
195 vector<double> data;
196 for (int i = 0; i < size_of(product); ++i)
197 data.push_back(get_or_insert(Memory, base_address+1+i));
198 update_any_refcounts(product, data);
199
200
201
202 :(scenario refcounts_copy_nested)
203 container foo [
204 x:address:num
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
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
226
227 int offset;
228
229
230
231
232
233
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
265
266
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
275
276
277
278
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;
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;
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;
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;
304 }
305
306
307
308
309 :(after "Transform.push_back(compute_container_sizes)")
310 Transform.push_back(compute_container_address_offsets);
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
333
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 ¦
346 }
347 const type_tree* base_type = type;
348
349 if (!contains_key(Type, base_type->value)) return;
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(0, tag));
372 ¦ append_addresses(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
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 element = element_type(type, curr_index);
388 ¦ ¦
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 += 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 ¦ ¦ ¦
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+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 ¦ ¦ ¦
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+1, variant_type(type, tag).type, out, new_key, location_for_error_messages);
431 ¦ }
432 }
433 }
434
435
436
437 :(before "End Unit Tests")
438 void test_container_address_offsets_empty() {
439 int old_size = SIZE(Container_metadata);
440
441 reagent r("x:point");
442 compute_container_sizes(r, "");
443
444 compute_container_address_offsets(r, "");
445
446
447 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
448
449 CHECK(r.metadata.address.empty());
450
451 CHECK(contains_key(Container_metadata, r.type));
452 CHECK(get(Container_metadata, r.type).address.empty());
453
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
460 run("container foo [\n"
461 ¦ ¦ " x:address:num\n"
462 ¦ ¦ "]\n");
463 reagent r("x:foo");
464 compute_container_sizes(r, "");
465
466 compute_container_address_offsets(r, "");
467
468
469 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
470
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>());
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
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
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
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, "");
498
499
500 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
501
502 compute_container_address_offsets(r, "");
503
504 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
505
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
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
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"
532 ¦ ¦ "]\n");
533 reagent r("x:bar");
534 compute_container_sizes(r, "");
535
536
537 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
538
539 compute_container_address_offsets(r, "");
540
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
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
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
562 run("container foo [\n"
563 ¦ ¦ " x:address:num\n"
564 ¦ ¦ "]\n");
565 reagent r("x:address:foo");
566 compute_container_sizes(r, "");
567
568
569 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
570
571 compute_container_address_offsets(r, "");
572
573 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
574
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
587 run("container foo [\n"
588 ¦ ¦ " x:address:num\n"
589 ¦ ¦ "]\n");
590 reagent r("x:array:foo");
591 compute_container_sizes(r, "");
592
593
594 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
595
596 compute_container_address_offsets(r, "");
597
598 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
599
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
612 run("container foo [\n"
613 ¦ ¦ " x:address:num\n"
614 ¦ ¦ "]\n");
615 reagent r("x:address:array:foo");
616 compute_container_sizes(r, "");
617
618
619 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
620
621 compute_container_address_offsets(r, "");
622
623 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
624
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
637 run("container foo [\n"
638 ¦ ¦ " x:address:num\n"
639 ¦ ¦ "]\n");
640 reagent r("x:array:foo:10");
641 compute_container_sizes(r, "");
642
643
644 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
645
646 compute_container_address_offsets(r, "");
647
648 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
649
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
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, "");
667
668
669 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
670
671 compute_container_address_offsets(r, "");
672
673 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
674
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
687 run("container foo [\n"
688 ¦ ¦ " x:address:num\n"
689 ¦ ¦ "]\n");
690
691 reagent r("x:address:array:address:address:array:foo:10");
692 compute_container_sizes(r, "");
693
694
695 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
696 compute_container_address_offsets(r, "");
697
698 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
699
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
710
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
726
727 reagent 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 element;
737 ¦ ¦ element.set_value(element_address+1);
738 ¦ ¦ element.type = new type_tree(*info->payload_type);
739 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+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
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
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
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
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
818 b:curr
819 ]
820 container bar [
821 x:num
822 y:num
823 ]
824 container curr [
825 x:num
826 y:address:num
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
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
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
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
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
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
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
1002 *1:address:num <- copy 34
1003 2:bar <- merge 0/foo1, 1:address:num, 97
1004 5:address:num <- copy 13000/unsafe
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
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
1035 if (type->value == 0) return false;
1036 type_info& info = get(Type, type->value);
1037 return info.kind == EXCLUSIVE_CONTAINER;
1038 }