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 Globals")
21
22 bool Update_refcounts_in_write_memory = true;
23
24 :(before "End write_memory(x) Special-cases")
25 if (Update_refcounts_in_write_memory)
26 update_any_refcounts(x, data);
27
28 :(code)
29 void update_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
30 increment_any_refcounts(canonized_x, data);
31 decrement_any_refcounts(canonized_x);
32 }
33
34 void increment_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
35 if (is_mu_address(canonized_x)) {
36 assert(scalar(data));
37 assert(!canonized_x.metadata.size);
38 increment_refcount(data.at(0));
39 }
40
41 }
42
43 void increment_refcount(int new_address) {
44 assert(new_address >= 0);
45 if (new_address == 0) return;
46 int new_refcount = get_or_insert(Memory, new_address);
47 trace(9999, "mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end();
48 put(Memory, new_address, new_refcount+1);
49 }
50
51 void decrement_any_refcounts(const reagent& canonized_x) {
52 if (is_mu_address(canonized_x)) {
53 assert(canonized_x.value);
54 assert(!canonized_x.metadata.size);
55 decrement_refcount(get_or_insert(Memory, canonized_x.value), payload_type(canonized_x.type), payload_size(canonized_x));
56 }
57
58 }
59
60 void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) {
61 assert(old_address >= 0);
62 if (old_address) {
63 int old_refcount = get_or_insert(Memory, old_address);
64 trace(9999, "mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end();
65 --old_refcount;
66 put(Memory, old_address, old_refcount);
67 if (old_refcount < 0) {
68 tb_shutdown();
69 cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n';
70 if (Trace_stream) {
71 cerr << "Saving trace to last_trace.\n";
72 ofstream fout("last_trace");
73 fout << Trace_stream->readable_contents("");
74 fout.close();
75 }
76 exit(0);
77 }
78
79 }
80 }
81
82 int payload_size(reagent x) {
83 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
84 lookup_memory_core(x, false);
85 return size_of(x) + 1;
86 }
87
88 :(scenario refcounts_reflexive)
89 def main [
90 1:address:num <- new number:type
91
92 1:address:num <- copy 1:address:num
93 ]
94 +run: {1: ("address" "number")} <- new {number: "type"}
95 +mem: incrementing refcount of 1000: 0 -> 1
96 +run: {1: ("address" "number")} <- copy {1: ("address" "number")}
97 +mem: incrementing refcount of 1000: 1 -> 2
98 +mem: decrementing refcount of 1000: 2 -> 1
99
100 :(scenario refcounts_call)
101 def main [
102 1:address:num <- new number:type
103
104 foo 1:address:num
105
106 1:address:num <- new number:type
107 ]
108 def foo [
109 2:address:num <- next-ingredient
110 ]
111 +run: {1: ("address" "number")} <- new {number: "type"}
112 +mem: incrementing refcount of 1000: 0 -> 1
113 +run: foo {1: ("address" "number")}
114
115 +mem: incrementing refcount of 1000: 1 -> 2
116 +run: {1: ("address" "number")} <- new {number: "type"}
117 +mem: decrementing refcount of 1000: 2 -> 1
118
119
120
121
122 :(scenario refcounts_put)
123 container foo [
124 x:address:num
125 ]
126 def main [
127 1:address:num <- new number:type
128 2:address:foo <- new foo:type
129 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num
130 ]
131 +run: {1: ("address" "number")} <- new {number: "type"}
132 +mem: incrementing refcount of 1000: 0 -> 1
133 +run: {2: ("address" "foo")} <- new {foo: "type"}
134 +mem: incrementing refcount of 1002: 0 -> 1
135 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
136
137 +mem: incrementing refcount of 1000: 1 -> 2
138
139 :(after "Write Memory in PUT in Run")
140 reagent element = element_type(base.type, offset);
141 assert(!has_property(element, "lookup"));
142 element.set_value(address);
143 update_any_refcounts(element, ingredients.at(2));
144
145 :(scenario refcounts_put_index)
146 def main [
147 1:address:num <- new number:type
148 2:address:array:address:num <- new {(address number): type}, 3
149 *2:address:array:address:num <- put-index *2:address:array:address:num, 0, 1:address:num
150 ]
151 +run: {1: ("address" "number")} <- new {number: "type"}
152 +mem: incrementing refcount of 1000: 0 -> 1
153 +run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"}
154 +mem: incrementing refcount of 1002: 0 -> 1
155 +run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")}
156
157 +mem: incrementing refcount of 1000: 1 -> 2
158
159 :(after "Write Memory in PUT_INDEX in Run")
160 reagent element;
161 element.set_value(address);
162 element.type = copy_array_element(base.type);
163 update_any_refcounts(element, value);
164
165 :(scenario refcounts_maybe_convert)
166 exclusive-container foo [
167 x:num
168 p:address:num
169 ]
170 def main [
171 1:address:num <- new number:type
172 2:foo <- merge 1/p, 1:address:num
173 4:address:num, 5:bool <- maybe-convert 2:foo, 1:variant/p
174 ]
175 +run: {1: ("address" "number")} <- new {number: "type"}
176 +mem: incrementing refcount of 1000: 0 -> 1
177
178 +run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")}
179 +mem: incrementing refcount of 1000: 1 -> 2
180 +run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()}
181
182 +mem: incrementing refcount of 1000: 2 -> 3
183
184 :(after "Write Memory in Successful MAYBE_CONVERT")
185
186 vector<double> data;
187 for (int i = 0; i < size_of(product); ++i)
188 data.push_back(get_or_insert(Memory, base_address+1+i));
189 update_any_refcounts(product, data);
190
191
192
193 :(scenario refcounts_copy_nested)
194 container foo [
195 x:address:num
196 ]
197 def main [
198 1:address:num <- new number:type
199 2:address:foo <- new foo:type
200 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num
201 3:foo <- copy *2:address:foo
202 ]
203 +transform: compute address offsets for container foo
204 +transform: checking container foo, element 0
205 +transform: address at offset 0
206 +run: {1: ("address" "number")} <- new {number: "type"}
207 +mem: incrementing refcount of 1000: 0 -> 1
208 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
209 +mem: incrementing refcount of 1000: 1 -> 2
210
211 +run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()}
212 +mem: incrementing refcount of 1000: 2 -> 3
213
214 :(after "End type_tree Definition")
215 struct address_element_info {
216 int offset;
217 const type_tree* payload_type;
218 address_element_info(int o, const type_tree* p) {
219 offset = o;
220 payload_type = p;
221 }
222 address_element_info(const address_element_info& other) {
223 offset = other.offset;
224 payload_type = other.payload_type ? new type_tree(*other.payload_type) : NULL;
225 }
226 ~address_element_info() {
227 if (payload_type) {
228 delete payload_type;
229 payload_type = NULL;
230 }
231 }
232 address_element_info& operator=(const address_element_info& other) {
233 offset = other.offset;
234 if (payload_type) delete payload_type;
235 payload_type = other.payload_type ? new type_tree(*other.payload_type) : NULL;
236 return *this;
237 }
238 };
239
240
241
242
243 struct tag_condition_info {
244 int offset;
245 int tag;
246 tag_condition_info(int o, int t) :offset(o), tag(t) {}
247 };
248
249 :(before "End container_metadata Fields")
250
251
252
253
254
255 map<set<tag_condition_info>, set<address_element_info> > address;
256 :(code)
257 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) {
258 if (a.size() != b.size()) return a.size() < b.size();
259 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
260 if (pa->offset != pb->offset) return pa->offset < pb->offset;
261 if (pa->tag != pb->tag) return pa->tag < pb->tag;
262 }
263 return false;
264 }
265 bool operator<(const tag_condition_info& a, const tag_condition_info& b) {
266 if (a.offset != b.offset) return a.offset < b.offset;
267 if (a.tag != b.tag) return a.tag < b.tag;
268 return false;
269 }
270 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) {
271 if (a.size() != b.size()) return a.size() < b.size();
272 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
273 if (pa->offset != pb->offset) return pa->offset < pb->offset;
274 }
275 return false;
276 }
277 bool operator<(const address_element_info& a, const address_element_info& b) {
278 if (a.offset != b.offset) return a.offset < b.offset;
279 return false;
280 }
281
282
283
284
285 :(after "Transform.push_back(compute_container_sizes)")
286 Transform.push_back(compute_container_address_offsets);
287 :(code)
288 void compute_container_address_offsets(const recipe_ordinal r) {
289 recipe& caller = get(Recipe, r);
290 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end();
291 for (int i = 0; i < SIZE(caller.steps); ++i) {
292 instruction& inst = caller.steps.at(i);
293 trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end();
294 for (int i = 0; i < SIZE(inst.ingredients); ++i)
295 compute_container_address_offsets(inst.ingredients.at(i), " in '"+to_original_string(inst)+"'");
296 for (int i = 0; i < SIZE(inst.products); ++i)
297 compute_container_address_offsets(inst.products.at(i), " in '"+to_original_string(inst)+"'");
298 }
299 }
300
301 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) {
302 if (is_literal(r) || is_dummy(r)) return;
303 compute_container_address_offsets(r.type, location_for_error_messages);
304 if (contains_key(Container_metadata, r.type))
305 r.metadata = get(Container_metadata, r.type);
306 }
307
308
309
310 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) {
311 if (!type) return;
312 if (!type->atom) {
313 if (!type->left->atom) {
314 raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end();
315 return;
316 }
317 if (type->left->name == "address")
318 compute_container_address_offsets(payload_type(type), location_for_error_messages);
319 else if (type->left->name == "array")
320 compute_container_address_offsets(array_element(type), location_for_error_messages);
321
322 }
323 const type_tree* base_type = type;
324
325 if (!contains_key(Type, base_type->value)) return;
326 type_info& info = get(Type, base_type->value);
327 if (info.kind == CONTAINER) {
328 compute_container_address_offsets(info, type, location_for_error_messages);
329 }
330 if (info.kind == EXCLUSIVE_CONTAINER) {
331 compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
332 }
333 }
334
335 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) {
336 container_metadata& metadata = get(Container_metadata, full_type);
337 if (!metadata.address.empty()) return;
338 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end();
339 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages);
340 }
341
342 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) {
343 container_metadata& metadata = get(Container_metadata, full_type);
344 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end();
345 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) {
346 set<tag_condition_info> key;
347 key.insert(tag_condition_info(0, tag));
348 append_addresses(1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages);
349 }
350 }
351
352 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) {
353 if (is_mu_address(type)) {
354 get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type))));
355 return;
356 }
357 const type_tree* base_type = type;
358
359 const type_info& info = get(Type, base_type->value);
360 if (info.kind == CONTAINER) {
361 for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) {
362 trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end();
363 reagent element = element_type(type, curr_index);
364
365 if (is_mu_address(element)) {
366 trace(9993, "transform") << "address at offset " << curr_offset << end();
367 get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type))));
368 ++curr_offset;
369 }
370 else if (is_mu_array(element)) {
371 curr_offset += 1;
372 const type_tree* array_element_type = array_element(element.type);
373 int array_element_size = size_of(array_element_type);
374 for (int i = 0; i < static_array_length(element.type); ++i) {
375 append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages);
376 curr_offset += array_element_size;
377 }
378 }
379 else if (is_mu_container(element)) {
380 append_addresses(curr_offset, element.type, out, key, location_for_error_messages);
381 curr_offset += size_of(element);
382 }
383 else if (is_mu_exclusive_container(element)) {
384 const type_tree* element_base_type = element.type;
385
386 const type_info& element_info = get(Type, element_base_type->value);
387 for (int tag = 0; tag < SIZE(element_info.elements); ++tag) {
388 set<tag_condition_info> new_key = key;
389 new_key.insert(tag_condition_info(curr_offset, tag));
390 if (!contains_key(out, new_key))
391 append_addresses(curr_offset+1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages);
392 }
393 curr_offset += size_of(element);
394 }
395 else {
396
397 ++curr_offset;
398 }
399 }
400 }
401 else if (info.kind == EXCLUSIVE_CONTAINER) {
402 for (int tag = 0; tag < SIZE(info.elements); ++tag) {
403 set<tag_condition_info> new_key = key;
404 new_key.insert(tag_condition_info(base_offset, tag));
405 if (!contains_key(out, new_key))
406 append_addresses(base_offset+1, variant_type(type, tag).type, out, new_key, location_for_error_messages);
407 }
408 }
409 }
410
411
412
413 :(before "End Unit Tests")
414 void test_container_address_offsets_empty() {
415 int old_size = SIZE(Container_metadata);
416
417 reagent r("x:point");
418 compute_container_sizes(r, "");
419
420 compute_container_address_offsets(r, "");
421
422
423 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
424
425 CHECK(r.metadata.address.empty());
426
427 CHECK(contains_key(Container_metadata, r.type));
428 CHECK(get(Container_metadata, r.type).address.empty());
429
430 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
431 }
432
433 void test_container_address_offsets() {
434 int old_size = SIZE(Container_metadata);
435
436 run("container foo [\n"
437 " x:address:num\n"
438 "]\n");
439 reagent r("x:foo");
440 compute_container_sizes(r, "");
441
442 compute_container_address_offsets(r, "");
443
444
445 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
446
447 CHECK_EQ(SIZE(r.metadata.address), 1);
448 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
449 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
450 CHECK_EQ(SIZE(address_offsets), 1);
451 CHECK_EQ(address_offsets.begin()->offset, 0);
452 CHECK(address_offsets.begin()->payload_type->atom);
453 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
454
455 CHECK(contains_key(Container_metadata, r.type));
456 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
457 CHECK_EQ(SIZE(address_offsets2), 1);
458 CHECK_EQ(address_offsets2.begin()->offset, 0);
459 CHECK(address_offsets2.begin()->payload_type->atom);
460 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
461
462 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
463 }
464
465 void test_container_address_offsets_2() {
466 int old_size = SIZE(Container_metadata);
467
468 run("container foo [\n"
469 " x:num\n"
470 " y:address:num\n"
471 "]\n");
472 reagent r("x:foo");
473 compute_container_sizes(r, "");
474
475
476 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
477
478 compute_container_address_offsets(r, "");
479
480 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
481
482 CHECK_EQ(SIZE(r.metadata.address), 1);
483 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
484 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
485 CHECK_EQ(SIZE(address_offsets), 1);
486 CHECK_EQ(address_offsets.begin()->offset, 1);
487 CHECK(address_offsets.begin()->payload_type->atom);
488 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
489
490 CHECK(contains_key(Container_metadata, r.type));
491 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
492 CHECK_EQ(SIZE(address_offsets2), 1);
493 CHECK_EQ(address_offsets2.begin()->offset, 1);
494 CHECK(address_offsets2.begin()->payload_type->atom);
495 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
496 }
497
498 void test_container_address_offsets_nested() {
499 int old_size = SIZE(Container_metadata);
500
501 run("container foo [\n"
502 " x:address:num\n"
503 " y:num\n"
504 "]\n"
505 "container bar [\n"
506 " p:point\n"
507 " f:foo\n"
508 "]\n");
509 reagent r("x:bar");
510 compute_container_sizes(r, "");
511
512
513 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
514
515 compute_container_address_offsets(r, "");
516
517 CHECK_EQ(SIZE(r.metadata.address), 1);
518 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
519 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
520 CHECK_EQ(SIZE(address_offsets), 1);
521 CHECK_EQ(address_offsets.begin()->offset, 2);
522 CHECK(address_offsets.begin()->payload_type->atom);
523 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
524
525 CHECK(contains_key(Container_metadata, r.type));
526 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
527 CHECK_EQ(SIZE(address_offsets2), 1);
528 CHECK_EQ(address_offsets2.begin()->offset, 2);
529 CHECK(address_offsets2.begin()->payload_type->atom);
530 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
531
532 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
533 }
534
535 void test_container_address_offsets_from_address() {
536 int old_size = SIZE(Container_metadata);
537
538 run("container foo [\n"
539 " x:address:num\n"
540 "]\n");
541 reagent r("x:address:foo");
542 compute_container_sizes(r, "");
543
544
545 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
546
547 compute_container_address_offsets(r, "");
548
549 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
550
551 reagent container("x:foo");
552 CHECK(contains_key(Container_metadata, container.type));
553 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
554 CHECK_EQ(SIZE(address_offsets2), 1);
555 CHECK_EQ(address_offsets2.begin()->offset, 0);
556 CHECK(address_offsets2.begin()->payload_type->atom);
557 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
558 }
559
560 void test_container_address_offsets_from_array() {
561 int old_size = SIZE(Container_metadata);
562
563 run("container foo [\n"
564 " x:address:num\n"
565 "]\n");
566 reagent r("x:array:foo");
567 compute_container_sizes(r, "");
568
569
570 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
571
572 compute_container_address_offsets(r, "");
573
574 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
575
576 reagent container("x:foo");
577 CHECK(contains_key(Container_metadata, container.type));
578 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
579 CHECK_EQ(SIZE(address_offsets2), 1);
580 CHECK_EQ(address_offsets2.begin()->offset, 0);
581 CHECK(address_offsets2.begin()->payload_type->atom);
582 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
583 }
584
585 void test_container_address_offsets_from_address_to_array() {
586 int old_size = SIZE(Container_metadata);
587
588 run("container foo [\n"
589 " x:address:num\n"
590 "]\n");
591 reagent r("x:address:array:foo");
592 compute_container_sizes(r, "");
593
594
595 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
596
597 compute_container_address_offsets(r, "");
598
599 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
600
601 reagent container("x:foo");
602 CHECK(contains_key(Container_metadata, container.type));
603 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
604 CHECK_EQ(SIZE(address_offsets2), 1);
605 CHECK_EQ(address_offsets2.begin()->offset, 0);
606 CHECK(address_offsets2.begin()->payload_type->atom);
607 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
608 }
609
610 void test_container_address_offsets_from_static_array() {
611 int old_size = SIZE(Container_metadata);
612
613 run("container foo [\n"
614 " x:address:num\n"
615 "]\n");
616 reagent r("x:array:foo:10");
617 compute_container_sizes(r, "");
618
619
620 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
621
622 compute_container_address_offsets(r, "");
623
624 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
625
626 reagent container("x:foo");
627 CHECK(contains_key(Container_metadata, container.type));
628 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
629 CHECK_EQ(SIZE(address_offsets2), 1);
630 CHECK_EQ(address_offsets2.begin()->offset, 0);
631 CHECK(address_offsets2.begin()->payload_type->atom);
632 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
633 }
634
635 void test_container_address_offsets_from_address_to_static_array() {
636 int old_size = SIZE(Container_metadata);
637
638 run("container foo [\n"
639 " x:address:num\n"
640 "]\n");
641 reagent r("x:address:array:foo:10");
642 compute_container_sizes(r, "");
643
644
645 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
646
647 compute_container_address_offsets(r, "");
648
649 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
650
651 reagent container("x:foo");
652 CHECK(contains_key(Container_metadata, container.type));
653 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
654 CHECK_EQ(SIZE(address_offsets2), 1);
655 CHECK_EQ(address_offsets2.begin()->offset, 0);
656 CHECK(address_offsets2.begin()->payload_type->atom);
657 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
658 }
659
660 void test_container_address_offsets_from_repeated_address_and_array_types() {
661 int old_size = SIZE(Container_metadata);
662
663 run("container foo [\n"
664 " x:address:num\n"
665 "]\n");
666
667 reagent r("x:address:array:address:address:array:foo:10");
668 compute_container_sizes(r, "");
669
670
671 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
672 compute_container_address_offsets(r, "");
673
674 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
675
676 reagent container("x:foo");
677 CHECK(contains_key(Container_metadata, container.type));
678 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
679 CHECK_EQ(SIZE(address_offsets2), 1);
680 CHECK_EQ(address_offsets2.begin()->offset, 0);
681 CHECK(address_offsets2.begin()->payload_type->atom);
682 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
683 }
684
685
686
687
688 :(before "End Increment Refcounts(canonized_x)")
689 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) {
690 const container_metadata& metadata = get(Container_metadata, canonized_x.type);
691 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) {
692 if (!all_match(data, p->first)) continue;
693 for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info)
694 increment_refcount(data.at(info->offset));
695 }
696 }
697
698 :(before "End Decrement Refcounts(canonized_x)")
699 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) {
700 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end();
701
702
703 reagent tmp = canonized_x;
704 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
705 vector<double> data = read_memory(tmp);
706 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end();
707 const container_metadata& metadata = get(Container_metadata, canonized_x.type);
708 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) {
709 if (!all_match(data, p->first)) continue;
710 for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) {
711 int element_address = get_or_insert(Memory, canonized_x.value + info->offset);
712 reagent element;
713 element.set_value(element_address+1);
714 element.type = new type_tree(*info->payload_type);
715 decrement_refcount(element_address, info->payload_type, size_of(element)+1);
716 }
717 }
718 }
719
720 :(code)
721 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) {
722 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) {
723 if (data.at(p->offset) != p->tag)
724 return false;
725 }
726 return true;
727 }
728
729 :(scenario refcounts_put_container)
730 container foo [
731 a:bar
732 ]
733 container bar [
734 x:address:num
735 ]
736 def main [
737 1:address:num <- new number:type
738 2:bar <- merge 1:address:num
739 3:address:foo <- new foo:type
740 *3:address:foo <- put *3:address:foo, a:offset, 2:bar
741 ]
742 +run: {1: ("address" "number")} <- new {number: "type"}
743 +mem: incrementing refcount of 1000: 0 -> 1
744 +run: {2: "bar"} <- merge {1: ("address" "number")}
745 +mem: incrementing refcount of 1000: 1 -> 2
746 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"}
747
748 +mem: incrementing refcount of 1000: 2 -> 3
749
750 :(scenario refcounts_put_index_array)
751 container bar [
752 x:address:num
753 ]
754 def main [
755 1:address:num <- new number:type
756 2:bar <- merge 1:address:num
757 3:address:array:bar <- new bar:type, 3
758 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar
759 ]
760 +run: {1: ("address" "number")} <- new {number: "type"}
761 +mem: incrementing refcount of 1000: 0 -> 1
762 +run: {2: "bar"} <- merge {1: ("address" "number")}
763 +mem: incrementing refcount of 1000: 1 -> 2
764 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"}
765
766 +mem: incrementing refcount of 1000: 2 -> 3
767
768 :(scenario refcounts_maybe_convert_container)
769 exclusive-container foo [
770 a:num
771 b:bar
772 ]
773 container bar [
774 x:address:num
775 ]
776 def main [
777 1:address:num <- new number:type
778 2:bar <- merge 1:address:num
779 3:foo <- merge 1/b, 2:bar
780 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b
781 ]
782 +run: {1: ("address" "number")} <- new {number: "type"}
783 +mem: incrementing refcount of 1000: 0 -> 1
784 +run: {2: "bar"} <- merge {1: ("address" "number")}
785 +mem: incrementing refcount of 1000: 1 -> 2
786 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"}
787 +mem: incrementing refcount of 1000: 2 -> 3
788 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()}
789 +mem: incrementing refcount of 1000: 3 -> 4
790
791 :(scenario refcounts_copy_doubly_nested)
792 container foo [
793 a:bar
794 b:curr
795 ]
796 container bar [
797 x:num
798 y:num
799 ]
800 container curr [
801 x:num
802 y:address:num
803 ]
804 def main [
805 1:address:num <- new number:type
806 2:address:curr <- new curr:type
807 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num
808 3:address:foo <- new foo:type
809 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr
810 4:foo <- copy *3:address:foo
811 ]
812 +transform: compute address offsets for container foo
813 +transform: checking container foo, element 1
814 +transform: address at offset 3
815 +run: {1: ("address" "number")} <- new {number: "type"}
816 +mem: incrementing refcount of 1000: 0 -> 1
817
818 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")}
819 +mem: incrementing refcount of 1000: 1 -> 2
820
821 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()}
822 +mem: incrementing refcount of 1000: 2 -> 3
823
824 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()}
825 +mem: incrementing refcount of 1000: 3 -> 4
826
827 :(scenario refcounts_copy_exclusive_container_within_container)
828 container foo [
829 a:num
830 b:bar
831 ]
832 exclusive-container bar [
833 x:num
834 y:num
835 z:address:num
836 ]
837 def main [
838 1:address:num <- new number:type
839 2:bar <- merge 0/x, 34
840 3:foo <- merge 12, 2:bar
841 5:bar <- merge 1/y, 35
842 6:foo <- merge 13, 5:bar
843 8:bar <- merge 2/z, 1:address:num
844 9:foo <- merge 14, 8:bar
845 11:foo <- copy 9:foo
846 ]
847 +run: {1: ("address" "number")} <- new {number: "type"}
848 +mem: incrementing refcount of 1000: 0 -> 1
849
850 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")}
851 +mem: incrementing refcount of 1000: 1 -> 2
852 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"}
853 +mem: incrementing refcount of 1000: 2 -> 3
854 +run: {11: "foo"} <- copy {9: "foo"}
855 +mem: incrementing refcount of 1000: 3 -> 4
856
857 :(scenario refcounts_copy_container_within_exclusive_container)
858 exclusive-container foo [
859 a:num
860 b:bar
861 ]
862 container bar [
863 x:num
864 y:num
865 z:address:num
866 ]
867 def main [
868 1:address:num <- new number:type
869 2:foo <- merge 0/a, 34
870 6:foo <- merge 0/a, 35
871 10:bar <- merge 2/x, 15/y, 1:address:num
872 13:foo <- merge 1/b, 10:bar
873 17:foo <- copy 13:foo
874 ]
875 +run: {1: ("address" "number")} <- new {number: "type"}
876 +mem: incrementing refcount of 1000: 0 -> 1
877
878 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")}
879 +mem: incrementing refcount of 1000: 1 -> 2
880 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"}
881 +mem: incrementing refcount of 1000: 2 -> 3
882 +run: {17: "foo"} <- copy {13: "foo"}
883 +mem: incrementing refcount of 1000: 3 -> 4
884
885 :(scenario refcounts_copy_exclusive_container_within_exclusive_container)
886 exclusive-container foo [
887 a:num
888 b:bar
889 ]
890 exclusive-container bar [
891 x:num
892 y:address:num
893 ]
894 def main [
895 1:address:num <- new number:type
896 10:foo <- merge 1/b, 1/y, 1:address:num
897 20:foo <- copy 10:foo
898 ]
899 +run: {1: ("address" "number")} <- new {number: "type"}
900 +mem: incrementing refcount of 1000: 0 -> 1
901
902 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")}
903 +mem: incrementing refcount of 1000: 1 -> 2
904 +run: {20: "foo"} <- copy {10: "foo"}
905 +mem: incrementing refcount of 1000: 2 -> 3
906
907 :(scenario refcounts_copy_array_within_container)
908 container foo [
909 x:address:array:num
910 ]
911 def main [
912 1:address:array:num <- new number:type, 3
913 2:foo <- merge 1:address:array:num
914 3:address:array:num <- new number:type, 5
915 2:foo <- merge 3:address:array:num
916 ]
917 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"}
918 +mem: incrementing refcount of 1000: 0 -> 1
919 +run: {2: "foo"} <- merge {1: ("address" "array" "number")}
920 +mem: incrementing refcount of 1000: 1 -> 2
921 +run: {2: "foo"} <- merge {3: ("address" "array" "number")}
922 +mem: decrementing refcount of 1000: 2 -> 1
923
924 :(scenario refcounts_copy_address_within_static_array_within_container)
925 container foo [
926 a:array:bar:3
927 b:address:num
928 ]
929 container bar [
930 y:num
931 z:address:num
932 ]
933 def main [
934 1:address:num <- new number:type
935 2:bar <- merge 34, 1:address:num
936 10:array:bar:3 <- create-array
937 put-index 10:array:bar:3, 1, 2:bar
938 20:foo <- merge 10:array:bar:3, 1:address:num
939 1:address:num <- copy 0
940 2:bar <- merge 34, 1:address:num
941 put-index 10:array:bar:3, 1, 2:bar
942 20:foo <- merge 10:array:bar:3, 1:address:num
943 ]
944 +run: {1: ("address" "number")} <- new {number: "type"}
945 +mem: incrementing refcount of 1000: 0 -> 1
946 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")}
947 +mem: incrementing refcount of 1000: 1 -> 2
948 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"}
949 +mem: incrementing refcount of 1000: 2 -> 3
950 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")}
951 +mem: incrementing refcount of 1000: 3 -> 4
952 +mem: incrementing refcount of 1000: 4 -> 5
953 +run: {1: ("address" "number")} <- copy {0: "literal"}
954 +mem: decrementing refcount of 1000: 5 -> 4
955 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")}
956 +mem: decrementing refcount of 1000: 4 -> 3
957 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"}
958 +mem: decrementing refcount of 1000: 3 -> 2
959 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")}
960 +mem: decrementing refcount of 1000: 2 -> 1
961 +mem: decrementing refcount of 1000: 1 -> 0
962
963 :(scenario refcounts_handle_exclusive_containers_with_different_tags)
964 container foo1 [
965 x:address:num
966 y:num
967 ]
968 container foo2 [
969 x:num
970 y:address:num
971 ]
972 exclusive-container bar [
973 a:foo1
974 b:foo2
975 ]
976 def main [
977 1:address:num <- copy 12000/unsafe
978 *1:address:num <- copy 34
979 2:bar <- merge 0/foo1, 1:address:num, 97
980 5:address:num <- copy 13000/unsafe
981 *5:address:num <- copy 35
982 6:bar <- merge 1/foo2, 98, 5:address:num
983 2:bar <- copy 6:bar
984 ]
985 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"}
986 +mem: incrementing refcount of 12000: 1 -> 2
987 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")}
988 +mem: incrementing refcount of 13000: 1 -> 2
989 +run: {2: "bar"} <- copy {6: "bar"}
990 +mem: incrementing refcount of 13000: 2 -> 3
991 +mem: decrementing refcount of 12000: 2 -> 1
992
993 :(code)
994 bool is_mu_container(const reagent& r) {
995 return is_mu_container(r.type);
996 }
997 bool is_mu_container(const type_tree* type) {
998 if (!type) return false;
999
1000 if (type->value == 0) return false;
1001 type_info& info = get(Type, type->value);
1002 return info.kind == CONTAINER;
1003 }
1004
1005 bool is_mu_exclusive_container(const reagent& r) {
1006 return is_mu_exclusive_container(r.type);
1007 }
1008 bool is_mu_exclusive_container(const type_tree* type) {
1009 if (!type) return false;
1010
1011 if (type->value == 0) return false;
1012 type_info& info = get(Type, type->value);
1013 return info.kind == EXCLUSIVE_CONTAINER;
1014 }