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