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