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 ¦ cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n';
81 ¦ if (Trace_stream) {
82 ¦ ¦ cerr << "Saving trace to last_trace.\n";
83 ¦ ¦ ofstream fout("last_trace");
84 ¦ ¦ fout << Trace_stream->readable_contents("");
85 ¦ ¦ fout.close();
86 ¦ }
87 ¦ exit(1);
88 }
89
90 }
91
92 int payload_size(reagent x) {
93 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
94 lookup_memory_core(x, false);
95 return size_of(x) + 1;
96 }
97
98 :(scenario refcounts_reflexive)
99 def main [
100 1:address:num <- new number:type
101
102 1:address:num <- copy 1:address:num
103 ]
104 +run: {1: ("address" "number")} <- new {number: "type"}
105 +mem: incrementing refcount of 1000: 0 -> 1
106 +run: {1: ("address" "number")} <- copy {1: ("address" "number")}
107 +mem: incrementing refcount of 1000: 1 -> 2
108 +mem: decrementing refcount of 1000: 2 -> 1
109
110 :(scenario refcounts_call)
111 def main [
112 1:address:num <- new number:type
113
114 foo 1:address:num
115
116 1:address:num <- new number:type
117 ]
118 def foo [
119 2:address:num <- next-ingredient
120 ]
121 +run: {1: ("address" "number")} <- new {number: "type"}
122 +mem: incrementing refcount of 1000: 0 -> 1
123 +run: foo {1: ("address" "number")}
124
125 +mem: incrementing refcount of 1000: 1 -> 2
126 +run: {1: ("address" "number")} <- new {number: "type"}
127 +mem: decrementing refcount of 1000: 2 -> 1
128
129
130
131
132 :(scenario refcounts_put)
133 container foo [
134 x:address:num
135 ]
136 def main [
137 1:address:num <- new number:type
138 2:address:foo <- new foo:type
139 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num
140 ]
141 +run: {1: ("address" "number")} <- new {number: "type"}
142 +mem: incrementing refcount of 1000: 0 -> 1
143 +run: {2: ("address" "foo")} <- new {foo: "type"}
144 +mem: incrementing refcount of 1002: 0 -> 1
145 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
146
147 +mem: incrementing refcount of 1000: 1 -> 2
148
149 :(after "Write Memory in PUT in Run")
150 reagent element = element_type(base.type, offset);
151 assert(!has_property(element, "lookup"));
152 element.set_value(address);
153 update_any_refcounts(element, ingredients.at(2));
154
155 :(scenario refcounts_put_index)
156 def main [
157 1:address:num <- new number:type
158 2:address:array:address:num <- new {(address number): type}, 3
159 *2:address:array:address:num <- put-index *2:address:array:address:num, 0, 1:address:num
160 ]
161 +run: {1: ("address" "number")} <- new {number: "type"}
162 +mem: incrementing refcount of 1000: 0 -> 1
163 +run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"}
164 +mem: incrementing refcount of 1002: 0 -> 1
165 +run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")}
166
167 +mem: incrementing refcount of 1000: 1 -> 2
168
169 :(after "Write Memory in PUT_INDEX in Run")
170 reagent element;
171 element.set_value(address);
172 element.type = copy_array_element(base.type);
173 update_any_refcounts(element, value);
174
175 :(scenario refcounts_maybe_convert)
176 exclusive-container foo [
177 x:num
178 p:address:num
179 ]
180 def main [
181 1:address:num <- new number:type
182 2:foo <- merge 1/p, 1:address:num
183 4:address:num, 5:bool <- maybe-convert 2:foo, 1:variant/p
184 ]
185 +run: {1: ("address" "number")} <- new {number: "type"}
186 +mem: incrementing refcount of 1000: 0 -> 1
187
188 +run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")}
189 +mem: incrementing refcount of 1000: 1 -> 2
190 +run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()}
191
192 +mem: incrementing refcount of 1000: 2 -> 3
193
194 :(after "Write Memory in Successful MAYBE_CONVERT")
195
196 vector<double> data;
197 for (int i = 0; i < size_of(product); ++i)
198 data.push_back(get_or_insert(Memory, base_address+1+i));
199 update_any_refcounts(product, data);
200
201
202
203 :(scenario refcounts_copy_nested)
204 container foo [
205 x:address:num
206 ]
207 def main [
208 1:address:num <- new number:type
209 2:address:foo <- new foo:type
210 *2:address:foo <- put *2:address:foo, x:offset, 1:address:num
211 3:foo <- copy *2:address:foo
212 ]
213 +transform: compute address offsets for container foo
214 +transform: checking container foo, element 0
215 +transform: address at offset 0
216 +run: {1: ("address" "number")} <- new {number: "type"}
217 +mem: incrementing refcount of 1000: 0 -> 1
218 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}
219 +mem: incrementing refcount of 1000: 1 -> 2
220
221 +run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()}
222 +mem: incrementing refcount of 1000: 2 -> 3
223
224 :(before "End type_tree Definition")
225 struct address_element_info {
226
227
228 int offset;
229
230
231
232
233
234
235 const type_tree* payload_type;
236
237 address_element_info(int o, const type_tree* p);
238 address_element_info(const address_element_info& other);
239 ~address_element_info();
240 address_element_info& operator=(const address_element_info& other);
241 };
242 :(code)
243 address_element_info::address_element_info(int o, const type_tree* p) {
244 offset = o;
245 payload_type = p;
246 }
247 address_element_info::address_element_info(const address_element_info& other) {
248 offset = other.offset;
249 payload_type = copy(other.payload_type);
250 }
251 address_element_info::~address_element_info() {
252 if (payload_type) {
253 ¦ delete payload_type;
254 ¦ payload_type = NULL;
255 }
256 }
257 address_element_info& address_element_info::operator=(const address_element_info& other) {
258 offset = other.offset;
259 if (payload_type) delete payload_type;
260 payload_type = copy(other.payload_type);
261 return *this;
262 }
263
264 :(before "End type_tree Definition")
265
266
267
268 struct tag_condition_info {
269 int offset;
270 int tag;
271 tag_condition_info(int o, int t) :offset(o), tag(t) {}
272 };
273
274 :(before "End container_metadata Fields")
275
276
277
278
279
280 map<set<tag_condition_info>, set<address_element_info> > address;
281 :(code)
282 bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) {
283 if (a.size() != b.size()) return a.size() < b.size();
284 for (set<tag_condition_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
285 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset;
286 ¦ if (pa->tag != pb->tag) return pa->tag < pb->tag;
287 }
288 return false;
289 }
290 bool operator<(const tag_condition_info& a, const tag_condition_info& b) {
291 if (a.offset != b.offset) return a.offset < b.offset;
292 if (a.tag != b.tag) return a.tag < b.tag;
293 return false;
294 }
295 bool operator<(const set<address_element_info>& a, const set<address_element_info>& b) {
296 if (a.size() != b.size()) return a.size() < b.size();
297 for (set<address_element_info>::const_iterator pa = a.begin(), pb = b.begin(); pa != a.end(); ++pa, ++pb) {
298 ¦ if (pa->offset != pb->offset) return pa->offset < pb->offset;
299 }
300 return false;
301 }
302 bool operator<(const address_element_info& a, const address_element_info& b) {
303 if (a.offset != b.offset) return a.offset < b.offset;
304 return false;
305 }
306
307
308
309
310 :(after "Transform.push_back(compute_container_sizes)")
311 Transform.push_back(compute_container_address_offsets);
312 :(code)
313 void compute_container_address_offsets(const recipe_ordinal r) {
314 recipe& caller = get(Recipe, r);
315 trace(9992, "transform") << "--- compute address offsets for " << caller.name << end();
316 for (int i = 0; i < SIZE(caller.steps); ++i) {
317 ¦ instruction& inst = caller.steps.at(i);
318 ¦ trace(9993, "transform") << "- compute address offsets for " << to_string(inst) << end();
319 ¦ for (int i = 0; i < SIZE(inst.ingredients); ++i)
320 ¦ ¦ compute_container_address_offsets(inst.ingredients.at(i), " in '"+inst.original_string+"'");
321 ¦ for (int i = 0; i < SIZE(inst.products); ++i)
322 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+inst.original_string+"'");
323 }
324 }
325
326 void compute_container_address_offsets(reagent& r, const string& location_for_error_messages) {
327 if (is_literal(r) || is_dummy(r)) return;
328 compute_container_address_offsets(r.type, location_for_error_messages);
329 if (contains_key(Container_metadata, r.type))
330 ¦ r.metadata = get(Container_metadata, r.type);
331 }
332
333
334
335 void compute_container_address_offsets(const type_tree* type, const string& location_for_error_messages) {
336 if (!type) return;
337 if (!type->atom) {
338 ¦ if (!type->left->atom) {
339 ¦ ¦ raise << "invalid type " << to_string(type) << location_for_error_messages << '\n' << end();
340 ¦ ¦ return;
341 ¦ }
342 ¦ if (type->left->name == "address")
343 ¦ ¦ compute_container_address_offsets(payload_type(type), location_for_error_messages);
344 ¦ else if (type->left->name == "array")
345 ¦ ¦ compute_container_address_offsets(array_element(type), location_for_error_messages);
346 ¦
347 }
348 const type_tree* base_type = type;
349
350 if (!contains_key(Type, base_type->value)) return;
351 type_info& info = get(Type, base_type->value);
352 if (info.kind == CONTAINER) {
353 ¦ compute_container_address_offsets(info, type, location_for_error_messages);
354 }
355 if (info.kind == EXCLUSIVE_CONTAINER) {
356 ¦ compute_exclusive_container_address_offsets(info, type, location_for_error_messages);
357 }
358 }
359
360 void compute_container_address_offsets(const type_info& container_info, const type_tree* full_type, const string& location_for_error_messages) {
361 container_metadata& metadata = get(Container_metadata, full_type);
362 if (!metadata.address.empty()) return;
363 trace(9994, "transform") << "compute address offsets for container " << container_info.name << end();
364 append_addresses(0, full_type, metadata.address, set<tag_condition_info>(), location_for_error_messages);
365 }
366
367 void compute_exclusive_container_address_offsets(const type_info& exclusive_container_info, const type_tree* full_type, const string& location_for_error_messages) {
368 container_metadata& metadata = get(Container_metadata, full_type);
369 trace(9994, "transform") << "compute address offsets for exclusive container " << exclusive_container_info.name << end();
370 for (int tag = 0; tag < SIZE(exclusive_container_info.elements); ++tag) {
371 ¦ set<tag_condition_info> key;
372 ¦ key.insert(tag_condition_info(0, tag));
373 ¦ append_addresses(1, variant_type(full_type, tag).type, metadata.address, key, location_for_error_messages);
374 }
375 }
376
377 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) {
378 if (is_mu_address(type)) {
379 ¦ get_or_insert(out, key).insert(address_element_info(base_offset, new type_tree(*payload_type(type))));
380 ¦ return;
381 }
382 const type_tree* base_type = type;
383
384 const type_info& info = get(Type, base_type->value);
385 if (info.kind == CONTAINER) {
386 ¦ for (int curr_index = 0, curr_offset = base_offset; curr_index < SIZE(info.elements); ++curr_index) {
387 ¦ ¦ trace(9993, "transform") << "checking container " << base_type->name << ", element " << curr_index << end();
388 ¦ ¦ reagent element = element_type(type, curr_index);
389 ¦ ¦
390 ¦ ¦ if (is_mu_address(element)) {
391 ¦ ¦ ¦ trace(9993, "transform") << "address at offset " << curr_offset << end();
392 ¦ ¦ ¦ get_or_insert(out, key).insert(address_element_info(curr_offset, new type_tree(*payload_type(element.type))));
393 ¦ ¦ ¦ ++curr_offset;
394 ¦ ¦ }
395 ¦ ¦ else if (is_mu_array(element)) {
396 ¦ ¦ ¦ curr_offset += 1;
397 ¦ ¦ ¦ const type_tree* array_element_type = array_element(element.type);
398 ¦ ¦ ¦ int array_element_size = size_of(array_element_type);
399 ¦ ¦ ¦ for (int i = 0; i < static_array_length(element.type); ++i) {
400 ¦ ¦ ¦ ¦ append_addresses(curr_offset, array_element_type, out, key, location_for_error_messages);
401 ¦ ¦ ¦ ¦ curr_offset += array_element_size;
402 ¦ ¦ ¦ }
403 ¦ ¦ }
404 ¦ ¦ else if (is_mu_container(element)) {
405 ¦ ¦ ¦ append_addresses(curr_offset, element.type, out, key, location_for_error_messages);
406 ¦ ¦ ¦ curr_offset += size_of(element);
407 ¦ ¦ }
408 ¦ ¦ else if (is_mu_exclusive_container(element)) {
409 ¦ ¦ ¦ const type_tree* element_base_type = element.type;
410 ¦ ¦ ¦
411 ¦ ¦ ¦ const type_info& element_info = get(Type, element_base_type->value);
412 ¦ ¦ ¦ for (int tag = 0; tag < SIZE(element_info.elements); ++tag) {
413 ¦ ¦ ¦ ¦ set<tag_condition_info> new_key = key;
414 ¦ ¦ ¦ ¦ new_key.insert(tag_condition_info(curr_offset, tag));
415 ¦ ¦ ¦ ¦ if (!contains_key(out, new_key))
416 ¦ ¦ ¦ ¦ ¦ append_addresses(curr_offset+1, variant_type(element.type, tag).type, out, new_key, location_for_error_messages);
417 ¦ ¦ ¦ }
418 ¦ ¦ ¦ curr_offset += size_of(element);
419 ¦ ¦ }
420 ¦ ¦ else {
421 ¦ ¦ ¦
422 ¦ ¦ ¦ ++curr_offset;
423 ¦ ¦ }
424 ¦ }
425 }
426 else if (info.kind == EXCLUSIVE_CONTAINER) {
427 ¦ for (int tag = 0; tag < SIZE(info.elements); ++tag) {
428 ¦ ¦ set<tag_condition_info> new_key = key;
429 ¦ ¦ new_key.insert(tag_condition_info(base_offset, tag));
430 ¦ ¦ if (!contains_key(out, new_key))
431 ¦ ¦ ¦ append_addresses(base_offset+1, variant_type(type, tag).type, out, new_key, location_for_error_messages);
432 ¦ }
433 }
434 }
435
436
437
438 :(before "End Unit Tests")
439 void test_container_address_offsets_empty() {
440 int old_size = SIZE(Container_metadata);
441
442 reagent r("x:point");
443 compute_container_sizes(r, "");
444
445 compute_container_address_offsets(r, "");
446
447
448 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
449
450 CHECK(r.metadata.address.empty());
451
452 CHECK(contains_key(Container_metadata, r.type));
453 CHECK(get(Container_metadata, r.type).address.empty());
454
455 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
456 }
457
458 void test_container_address_offsets() {
459 int old_size = SIZE(Container_metadata);
460
461 run("container foo [\n"
462 ¦ ¦ " x:address:num\n"
463 ¦ ¦ "]\n");
464 reagent r("x:foo");
465 compute_container_sizes(r, "");
466
467 compute_container_address_offsets(r, "");
468
469
470 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
471
472 CHECK_EQ(SIZE(r.metadata.address), 1);
473 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
474 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
475 CHECK_EQ(SIZE(address_offsets), 1);
476 CHECK_EQ(address_offsets.begin()->offset, 0);
477 CHECK(address_offsets.begin()->payload_type->atom);
478 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
479
480 CHECK(contains_key(Container_metadata, r.type));
481 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
482 CHECK_EQ(SIZE(address_offsets2), 1);
483 CHECK_EQ(address_offsets2.begin()->offset, 0);
484 CHECK(address_offsets2.begin()->payload_type->atom);
485 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
486
487 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
488 }
489
490 void test_container_address_offsets_2() {
491 int old_size = SIZE(Container_metadata);
492
493 run("container foo [\n"
494 ¦ ¦ " x:num\n"
495 ¦ ¦ " y:address:num\n"
496 ¦ ¦ "]\n");
497 reagent r("x:foo");
498 compute_container_sizes(r, "");
499
500
501 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
502
503 compute_container_address_offsets(r, "");
504
505 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
506
507 CHECK_EQ(SIZE(r.metadata.address), 1);
508 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
509 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
510 CHECK_EQ(SIZE(address_offsets), 1);
511 CHECK_EQ(address_offsets.begin()->offset, 1);
512 CHECK(address_offsets.begin()->payload_type->atom);
513 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
514
515 CHECK(contains_key(Container_metadata, r.type));
516 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
517 CHECK_EQ(SIZE(address_offsets2), 1);
518 CHECK_EQ(address_offsets2.begin()->offset, 1);
519 CHECK(address_offsets2.begin()->payload_type->atom);
520 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
521 }
522
523 void test_container_address_offsets_nested() {
524 int old_size = SIZE(Container_metadata);
525
526 run("container foo [\n"
527 ¦ ¦ " x:address:num\n"
528 ¦ ¦ " y:num\n"
529 ¦ ¦ "]\n"
530 ¦ ¦ "container bar [\n"
531 ¦ ¦ " p:point\n"
532 ¦ ¦ " f:foo\n"
533 ¦ ¦ "]\n");
534 reagent r("x:bar");
535 compute_container_sizes(r, "");
536
537
538 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
539
540 compute_container_address_offsets(r, "");
541
542 CHECK_EQ(SIZE(r.metadata.address), 1);
543 CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
544 const set<address_element_info>& address_offsets = get(r.metadata.address, set<tag_condition_info>());
545 CHECK_EQ(SIZE(address_offsets), 1);
546 CHECK_EQ(address_offsets.begin()->offset, 2);
547 CHECK(address_offsets.begin()->payload_type->atom);
548 CHECK_EQ(address_offsets.begin()->payload_type->name, "number");
549
550 CHECK(contains_key(Container_metadata, r.type));
551 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, r.type).address, set<tag_condition_info>());
552 CHECK_EQ(SIZE(address_offsets2), 1);
553 CHECK_EQ(address_offsets2.begin()->offset, 2);
554 CHECK(address_offsets2.begin()->payload_type->atom);
555 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
556
557 CHECK_EQ(SIZE(Container_metadata)-old_size, 3);
558 }
559
560 void test_container_address_offsets_from_address() {
561 int old_size = SIZE(Container_metadata);
562
563 run("container foo [\n"
564 ¦ ¦ " x:address:num\n"
565 ¦ ¦ "]\n");
566 reagent r("x:address: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_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: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_address_to_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:address:array:foo");
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_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: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_address_to_static_array() {
661 int old_size = SIZE(Container_metadata);
662
663 run("container foo [\n"
664 ¦ ¦ " x:address:num\n"
665 ¦ ¦ "]\n");
666 reagent r("x:address:array:foo:10");
667 compute_container_sizes(r, "");
668
669
670 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
671
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 void test_container_address_offsets_from_repeated_address_and_array_types() {
686 int old_size = SIZE(Container_metadata);
687
688 run("container foo [\n"
689 ¦ ¦ " x:address:num\n"
690 ¦ ¦ "]\n");
691
692 reagent r("x:address:array:address:address:array:foo:10");
693 compute_container_sizes(r, "");
694
695
696 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
697 compute_container_address_offsets(r, "");
698
699 CHECK_EQ(SIZE(Container_metadata)-old_size, 1);
700
701 reagent container("x:foo");
702 CHECK(contains_key(Container_metadata, container.type));
703 const set<address_element_info>& address_offsets2 = get(get(Container_metadata, container.type).address, set<tag_condition_info>());
704 CHECK_EQ(SIZE(address_offsets2), 1);
705 CHECK_EQ(address_offsets2.begin()->offset, 0);
706 CHECK(address_offsets2.begin()->payload_type->atom);
707 CHECK_EQ(address_offsets2.begin()->payload_type->name, "number");
708 }
709
710
711
712
713 :(before "End Increment Refcounts(canonized_x)")
714 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) {
715 const container_metadata& metadata = get(Container_metadata, canonized_x.type);
716 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) {
717 ¦ if (!all_match(data, p->first)) continue;
718 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info)
719 ¦ ¦ increment_refcount(data.at(info->offset));
720 }
721 }
722
723 :(before "End Decrement Refcounts(canonized_x)")
724 if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) {
725 trace(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end();
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 if (!contains_key(Type, type->value)) 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 if (!contains_key(Type, type->value)) return false;
1038 type_info& info = get(Type, type->value);
1039 return info.kind == EXCLUSIVE_CONTAINER;
1040 }
1041
1042
1043
1044
1045 :(before "End Globals")
1046 int Total_refcount_updates = 0;
1047 map<recipe_ordinal, map<int, int> > Num_refcount_updates;
1048 :(after "Running One Instruction")
1049 int initial_num_refcount_updates = Total_refcount_updates;
1050 :(before "End Running One Instruction")
1051 if (Run_profiler) {
1052 Num_refcount_updates[current_call().running_recipe][current_call().running_step_index]
1053 ¦ ¦ += (Total_refcount_updates - initial_num_refcount_updates);
1054 initial_num_refcount_updates = Total_refcount_updates;
1055 }
1056 :(before "End Non-primitive Call(caller_frame)")
1057 Num_refcount_updates[caller_frame.running_recipe][caller_frame.running_step_index]
1058 ¦ += (Total_refcount_updates - initial_num_refcount_updates);
1059 initial_num_refcount_updates = Total_refcount_updates;
1060 :(after "Starting Reply")
1061 if (Run_profiler) {
1062 Num_refcount_updates[current_call().running_recipe][current_call().running_step_index]
1063 ¦ ¦ += (Total_refcount_updates - initial_num_refcount_updates);
1064 initial_num_refcount_updates = Total_refcount_updates;
1065 }
1066 :(before "End dump_profile")
1067 fout.open("profile.refcounts");
1068 if (fout) {
1069 for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p)
1070 ¦ dump_recipe_profile(p->first, p->second, fout);
1071 }
1072 fout.close();
1073 :(code)
1074 void dump_recipe_profile(recipe_ordinal ridx, const recipe& r, ostream& out) {
1075 out << "recipe " << r.name << " [\n";
1076 for (int i = 0; i < SIZE(r.steps); ++i) {
1077 ¦ out << std::setw(6) << Num_refcount_updates[ridx][i] << ' ' << to_string(r.steps.at(i)) << '\n';
1078 }
1079 out << "]\n\n";
1080 }