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 :(code)
24 void update_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
25 if (!should_update_refcounts()) return;
26 increment_any_refcounts(canonized_x, data);
27 decrement_any_refcounts(canonized_x);
28 }
29
30
31 bool should_update_refcounts() {
32
33 return true;
34 }
35
36 void increment_any_refcounts(const reagent& canonized_x, const vector<double>& data) {
37 if (is_mu_address(canonized_x)) {
38 ¦ assert(scalar(data));
39 ¦ assert(!canonized_x.metadata.size);
40 ¦ increment_refcount(data.at(0));
41 }
42
43 }
44
45 void increment_refcount(int new_address) {
46 assert(new_address >= 0);
47 if (new_address == 0) return;
48 int new_refcount = get_or_insert(Memory, new_address);
49 trace(9999, "mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end();
50 put(Memory, new_address, new_refcount+1);
51 }
52
53 void decrement_any_refcounts(const reagent& canonized_x) {
54 if (is_mu_address(canonized_x)) {
55 ¦ assert(canonized_x.value);
56 ¦ assert(!canonized_x.metadata.size);
57 ¦ decrement_refcount(get_or_insert(Memory, canonized_x.value), payload_type(canonized_x.type), payload_size(canonized_x));
58 }
59
60 }
61
62 void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) {
63 assert(old_address >= 0);
64 if (old_address) {
65 ¦ int old_refcount = get_or_insert(Memory, old_address);
66 ¦ trace(9999, "mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end();
67 ¦ --old_refcount;
68 ¦ put(Memory, old_address, old_refcount);
69 ¦ if (old_refcount < 0) {
70 ¦ ¦ tb_shutdown();
71 ¦ ¦ cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n';
72 ¦ ¦ if (Trace_stream) {
73 ¦ ¦ ¦ cerr << "Saving trace to last_trace.\n";
74 ¦ ¦ ¦ ofstream fout("last_trace");
75 ¦ ¦ ¦ fout << Trace_stream->readable_contents("");
76 ¦ ¦ ¦ fout.close();
77 ¦ ¦ }
78 ¦ ¦ exit(0);
79 ¦ }
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 '"+to_original_string(inst)+"'");
313 ¦ for (int i = 0; i < SIZE(inst.products); ++i)
314 ¦ ¦ compute_container_address_offsets(inst.products.at(i), " in '"+to_original_string(inst)+"'");
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(9999, "mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end();
718
719
720 reagent tmp = canonized_x;
721 tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
722 vector<double> data = read_memory(tmp);
723 trace(9999, "mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end();
724 const container_metadata& metadata = get(Container_metadata, canonized_x.type);
725 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) {
726 ¦ if (!all_match(data, p->first)) continue;
727 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) {
728 ¦ ¦ int element_address = get_or_insert(Memory, canonized_x.value + info->offset);
729 ¦ ¦ reagent element;
730 ¦ ¦ element.set_value(element_address+1);
731 ¦ ¦ element.type = new type_tree(*info->payload_type);
732 ¦ ¦ decrement_refcount(element_address, info->payload_type, size_of(element)+1);
733 ¦ }
734 }
735 }
736
737 :(code)
738 bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) {
739 for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) {
740 ¦ if (data.at(p->offset) != p->tag)
741 ¦ ¦ return false;
742 }
743 return true;
744 }
745
746 :(scenario refcounts_put_container)
747 container foo [
748 a:bar
749 ]
750 container bar [
751 x:address:num
752 ]
753 def main [
754 1:address:num <- new number:type
755 2:bar <- merge 1:address:num
756 3:address:foo <- new foo:type
757 *3:address:foo <- put *3:address:foo, a:offset, 2:bar
758 ]
759 +run: {1: ("address" "number")} <- new {number: "type"}
760 +mem: incrementing refcount of 1000: 0 -> 1
761 +run: {2: "bar"} <- merge {1: ("address" "number")}
762 +mem: incrementing refcount of 1000: 1 -> 2
763 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"}
764
765 +mem: incrementing refcount of 1000: 2 -> 3
766
767 :(scenario refcounts_put_index_array)
768 container bar [
769 x:address:num
770 ]
771 def main [
772 1:address:num <- new number:type
773 2:bar <- merge 1:address:num
774 3:address:array:bar <- new bar:type, 3
775 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar
776 ]
777 +run: {1: ("address" "number")} <- new {number: "type"}
778 +mem: incrementing refcount of 1000: 0 -> 1
779 +run: {2: "bar"} <- merge {1: ("address" "number")}
780 +mem: incrementing refcount of 1000: 1 -> 2
781 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"}
782
783 +mem: incrementing refcount of 1000: 2 -> 3
784
785 :(scenario refcounts_maybe_convert_container)
786 exclusive-container foo [
787 a:num
788 b:bar
789 ]
790 container bar [
791 x:address:num
792 ]
793 def main [
794 1:address:num <- new number:type
795 2:bar <- merge 1:address:num
796 3:foo <- merge 1/b, 2:bar
797 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b
798 ]
799 +run: {1: ("address" "number")} <- new {number: "type"}
800 +mem: incrementing refcount of 1000: 0 -> 1
801 +run: {2: "bar"} <- merge {1: ("address" "number")}
802 +mem: incrementing refcount of 1000: 1 -> 2
803 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"}
804 +mem: incrementing refcount of 1000: 2 -> 3
805 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()}
806 +mem: incrementing refcount of 1000: 3 -> 4
807
808 :(scenario refcounts_copy_doubly_nested)
809 container foo [
810 a:bar
811 b:curr
812 ]
813 container bar [
814 x:num
815 y:num
816 ]
817 container curr [
818 x:num
819 y:address:num
820 ]
821 def main [
822 1:address:num <- new number:type
823 2:address:curr <- new curr:type
824 *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num
825 3:address:foo <- new foo:type
826 *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr
827 4:foo <- copy *3:address:foo
828 ]
829 +transform: compute address offsets for container foo
830 +transform: checking container foo, element 1
831 +transform: address at offset 3
832 +run: {1: ("address" "number")} <- new {number: "type"}
833 +mem: incrementing refcount of 1000: 0 -> 1
834
835 +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")}
836 +mem: incrementing refcount of 1000: 1 -> 2
837
838 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()}
839 +mem: incrementing refcount of 1000: 2 -> 3
840
841 +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()}
842 +mem: incrementing refcount of 1000: 3 -> 4
843
844 :(scenario refcounts_copy_exclusive_container_within_container)
845 container foo [
846 a:num
847 b:bar
848 ]
849 exclusive-container bar [
850 x:num
851 y:num
852 z:address:num
853 ]
854 def main [
855 1:address:num <- new number:type
856 2:bar <- merge 0/x, 34
857 3:foo <- merge 12, 2:bar
858 5:bar <- merge 1/y, 35
859 6:foo <- merge 13, 5:bar
860 8:bar <- merge 2/z, 1:address:num
861 9:foo <- merge 14, 8:bar
862 11:foo <- copy 9:foo
863 ]
864 +run: {1: ("address" "number")} <- new {number: "type"}
865 +mem: incrementing refcount of 1000: 0 -> 1
866
867 +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")}
868 +mem: incrementing refcount of 1000: 1 -> 2
869 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"}
870 +mem: incrementing refcount of 1000: 2 -> 3
871 +run: {11: "foo"} <- copy {9: "foo"}
872 +mem: incrementing refcount of 1000: 3 -> 4
873
874 :(scenario refcounts_copy_container_within_exclusive_container)
875 exclusive-container foo [
876 a:num
877 b:bar
878 ]
879 container bar [
880 x:num
881 y:num
882 z:address:num
883 ]
884 def main [
885 1:address:num <- new number:type
886 2:foo <- merge 0/a, 34
887 6:foo <- merge 0/a, 35
888 10:bar <- merge 2/x, 15/y, 1:address:num
889 13:foo <- merge 1/b, 10:bar
890 17:foo <- copy 13:foo
891 ]
892 +run: {1: ("address" "number")} <- new {number: "type"}
893 +mem: incrementing refcount of 1000: 0 -> 1
894
895 +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")}
896 +mem: incrementing refcount of 1000: 1 -> 2
897 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"}
898 +mem: incrementing refcount of 1000: 2 -> 3
899 +run: {17: "foo"} <- copy {13: "foo"}
900 +mem: incrementing refcount of 1000: 3 -> 4
901
902 :(scenario refcounts_copy_exclusive_container_within_exclusive_container)
903 exclusive-container foo [
904 a:num
905 b:bar
906 ]
907 exclusive-container bar [
908 x:num
909 y:address:num
910 ]
911 def main [
912 1:address:num <- new number:type
913 10:foo <- merge 1/b, 1/y, 1:address:num
914 20:foo <- copy 10:foo
915 ]
916 +run: {1: ("address" "number")} <- new {number: "type"}
917 +mem: incrementing refcount of 1000: 0 -> 1
918
919 +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")}
920 +mem: incrementing refcount of 1000: 1 -> 2
921 +run: {20: "foo"} <- copy {10: "foo"}
922 +mem: incrementing refcount of 1000: 2 -> 3
923
924 :(scenario refcounts_copy_array_within_container)
925 container foo [
926 x:address:array:num
927 ]
928 def main [
929 1:address:array:num <- new number:type, 3
930 2:foo <- merge 1:address:array:num
931 3:address:array:num <- new number:type, 5
932 2:foo <- merge 3:address:array:num
933 ]
934 +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"}
935 +mem: incrementing refcount of 1000: 0 -> 1
936 +run: {2: "foo"} <- merge {1: ("address" "array" "number")}
937 +mem: incrementing refcount of 1000: 1 -> 2
938 +run: {2: "foo"} <- merge {3: ("address" "array" "number")}
939 +mem: decrementing refcount of 1000: 2 -> 1
940
941 :(scenario refcounts_copy_address_within_static_array_within_container)
942 container foo [
943 a:array:bar:3
944 b:address:num
945 ]
946 container bar [
947 y:num
948 z:address:num
949 ]
950 def main [
951 1:address:num <- new number:type
952 2:bar <- merge 34, 1:address:num
953 10:array:bar:3 <- create-array
954 put-index 10:array:bar:3, 1, 2:bar
955 20:foo <- merge 10:array:bar:3, 1:address:num
956 1:address:num <- copy 0
957 2:bar <- merge 34, 1:address:num
958 put-index 10:array:bar:3, 1, 2:bar
959 20:foo <- merge 10:array:bar:3, 1:address:num
960 ]
961 +run: {1: ("address" "number")} <- new {number: "type"}
962 +mem: incrementing refcount of 1000: 0 -> 1
963 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")}
964 +mem: incrementing refcount of 1000: 1 -> 2
965 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"}
966 +mem: incrementing refcount of 1000: 2 -> 3
967 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")}
968 +mem: incrementing refcount of 1000: 3 -> 4
969 +mem: incrementing refcount of 1000: 4 -> 5
970 +run: {1: ("address" "number")} <- copy {0: "literal"}
971 +mem: decrementing refcount of 1000: 5 -> 4
972 +run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")}
973 +mem: decrementing refcount of 1000: 4 -> 3
974 +run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"}
975 +mem: decrementing refcount of 1000: 3 -> 2
976 +run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")}
977 +mem: decrementing refcount of 1000: 2 -> 1
978 +mem: decrementing refcount of 1000: 1 -> 0
979
980 :(scenario refcounts_handle_exclusive_containers_with_different_tags)
981 container foo1 [
982 x:address:num
983 y:num
984 ]
985 container foo2 [
986 x:num
987 y:address:num
988 ]
989 exclusive-container bar [
990 a:foo1
991 b:foo2
992 ]
993 def main [
994 1:address:num <- copy 12000/unsafe
995 *1:address:num <- copy 34
996 2:bar <- merge 0/foo1, 1:address:num, 97
997 5:address:num <- copy 13000/unsafe
998 *5:address:num <- copy 35
999 6:bar <- merge 1/foo2, 98, 5:address:num
1000 2:bar <- copy 6:bar
1001 ]
1002 +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"}
1003 +mem: incrementing refcount of 12000: 1 -> 2
1004 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")}
1005 +mem: incrementing refcount of 13000: 1 -> 2
1006 +run: {2: "bar"} <- copy {6: "bar"}
1007 +mem: incrementing refcount of 13000: 2 -> 3
1008 +mem: decrementing refcount of 12000: 2 -> 1
1009
1010 :(code)
1011 bool is_mu_container(const reagent& r) {
1012 return is_mu_container(r.type);
1013 }
1014 bool is_mu_container(const type_tree* type) {
1015 if (!type) return false;
1016
1017 if (type->value == 0) 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 type_info& info = get(Type, type->value);
1030 return info.kind == EXCLUSIVE_CONTAINER;
1031 }