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