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