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