1
2
3
4
5
6
7
8
9
10
11
12
13 :(scenario deep_copy_number)
14 def main [
15 local-scope
16 x:num <- copy 34
17 y:num <- deep-copy x
18 10:bool/raw <- equal x, y
19 ]
20
21 +mem: storing 1 in location 10
22
23 :(scenario deep_copy_null_pointer)
24 def main [
25 local-scope
26 x:&:num <- copy 0
27 y:&:num <- deep-copy x
28 10:bool/raw <- equal x, y
29 ]
30
31 +mem: storing 1 in location 10
32
33 :(scenario deep_copy_container_without_address)
34 container foo [
35 x:num
36 y:num
37 ]
38 def main [
39 local-scope
40 a:foo <- merge 34, 35
41 b:foo <- deep-copy a
42 10:bool/raw <- equal a, b
43 ]
44
45 +mem: storing 1 in location 10
46
47 :(scenario deep_copy_address)
48 % Memory_allocated_until = 200;
49 def main [
50
51
52 1:&:num <- copy 100/unsafe
53 *1:&:num <- copy 34
54 2:&:num <- deep-copy 1:&:num
55 10:bool <- equal 1:&:num, 2:&:num
56 11:bool <- equal *1:&:num, *2:&:num
57 2:&:num <- copy 0
58 ]
59
60 +mem: storing 0 in location 10
61
62 +mem: storing 1 in location 11
63
64
65 +run: {2: ("address" "number")} <- copy {0: "literal"}
66 +mem: decrementing refcount of 202: 1 -> 0
67 +abandon: saving 202 in free-list of size 2
68
69 :(scenario deep_copy_address_to_container)
70 % Memory_allocated_until = 200;
71 def main [
72
73
74 1:&:point <- copy 100/unsafe
75 *1:&:point <- merge 34, 35
76 2:&:point <- deep-copy 1:&:point
77 10:bool <- equal 1:&:point, 2:&:point
78 11:bool <- equal *1:&:point, *2:&:point
79 ]
80
81 +mem: storing 0 in location 10
82
83 +mem: storing 1 in location 11
84
85 :(scenario deep_copy_address_to_address)
86 % Memory_allocated_until = 200;
87 def main [
88
89
90 1:&:&:num <- copy 100/unsafe
91 *1:&:&:num <- copy 150/unsafe
92 **1:&:&:num <- copy 34
93 2:&:&:num <- deep-copy 1:&:&:num
94 10:bool <- equal 1:&:&:num, 2:&:&:num
95 11:bool <- equal *1:&:&:num, *2:&:&:num
96 12:bool <- equal **1:&:&:num, **2:&:&:num
97 ]
98
99 +mem: storing 0 in location 10
100
101 +mem: storing 0 in location 11
102
103 +mem: storing 1 in location 12
104
105 :(scenario deep_copy_array)
106 % Memory_allocated_until = 200;
107 def main [
108
109
110 100:num <- copy 1
111 101:num <- copy 3
112 1:&:@:num <- copy 100/unsafe
113 put-index *1:&:@:num, 0, 34
114 put-index *1:&:@:num, 1, 35
115 put-index *1:&:@:num, 2, 36
116 stash [old:], *1:&:@:num
117 2:&:@:num <- deep-copy 1:&:@:num
118 stash 2:&:@:num
119 stash [new:], *2:&:@:num
120 10:bool <- equal 1:&:@:num, 2:&:@:num
121 11:bool <- equal *1:&:@:num, *2:&:@:num
122 ]
123 +app: old: 3 34 35 36
124 +app: new: 3 34 35 36
125
126 +mem: storing 0 in location 10
127
128 +mem: storing 1 in location 11
129
130 :(scenario deep_copy_container_with_address)
131 container foo [
132 x:num
133 y:&:num
134 ]
135 def main [
136 local-scope
137 y0:&:num <- new number:type
138 *y0 <- copy 35
139 a:foo <- merge 34, y0
140 b:foo <- deep-copy a
141 10:bool/raw <- equal a, b
142 y1:&:num <- get b, y:offset
143 11:bool/raw <- equal y0, y1
144 12:num/raw <- copy *y1
145 ]
146
147 +mem: storing 0 in location 10
148
149 +mem: storing 0 in location 11
150 +mem: storing 35 in location 12
151
152 :(scenario deep_copy_exclusive_container_with_address)
153 exclusive-container foo [
154 x:num
155 y:&:num
156 ]
157 def main [
158 local-scope
159 y0:&:num <- new number:type
160 *y0 <- copy 34
161 a:foo <- merge 1/y, y0
162 b:foo <- deep-copy a
163 10:bool/raw <- equal a, b
164 y1:&:num, z:bool <- maybe-convert b, y:variant
165 11:bool/raw <- equal y0, y1
166 12:num/raw <- copy *y1
167 ]
168
169 +mem: storing 0 in location 10
170
171 +mem: storing 0 in location 11
172 +mem: storing 34 in location 12
173
174 :(scenario deep_copy_exclusive_container_with_container_with_address)
175 exclusive-container foo [
176 x:num
177 y:bar
178 ]
179 container bar [
180 x:&:num
181 ]
182 def main [
183 local-scope
184 y0:&:num <- new number:type
185 *y0 <- copy 34
186 a:bar <- merge y0
187 b:foo <- merge 1/y, a
188 c:foo <- deep-copy b
189 10:bool/raw <- equal b, c
190 d:bar, z:bool <- maybe-convert c, y:variant
191 y1:&:num <- get d, x:offset
192 11:bool/raw <- equal y0, y1
193 12:num/raw <- copy *y1
194 ]
195
196 +mem: storing 0 in location 10
197
198 +mem: storing 0 in location 11
199 +mem: storing 34 in location 12
200
201 :(before "End Primitive Recipe Declarations")
202 DEEP_COPY,
203 :(before "End Primitive Recipe Numbers")
204 put(Recipe_ordinal, "deep-copy", DEEP_COPY);
205 :(before "End Primitive Recipe Checks")
206 case DEEP_COPY: {
207 if (SIZE(inst.ingredients) != 1) {
208 ¦ raise << maybe(get(Recipe, r).name) << "'deep-copy' takes exactly one ingredient rather than '" << to_original_string(inst) << "'\n" << end();
209 ¦ break;
210 }
211 if (SIZE(inst.products) != 1) {
212 ¦ raise << maybe(get(Recipe, r).name) << "'deep-copy' takes exactly one ingredient rather than '" << to_original_string(inst) << "'\n" << end();
213 ¦ break;
214 }
215 if (!types_strictly_match(inst.ingredients.at(0), inst.products.at(0))) {
216 ¦ raise << maybe(get(Recipe, r).name) << "'deep-copy' requires its ingredient and product to be the same type, but got '" << to_original_string(inst) << "'\n" << end();
217 ¦ break;
218 }
219 break;
220 }
221 :(before "End Primitive Recipe Implementations")
222 case DEEP_COPY: {
223 products.push_back(deep_copy(current_instruction().ingredients.at(0)));
224 break;
225 }
226
227 :(code)
228 vector<double> deep_copy(const reagent& in) {
229
230 trace(9991, "run") << "deep-copy: allocating space for temporary" << end();
231 reagent tmp("tmp:address:number");
232 tmp.set_value(allocate(1));
233 map<int, int> addresses_copied;
234 vector<double> result = deep_copy(in, addresses_copied, tmp);
235
236 trace(9991, "run") << "deep-copy: reclaiming temporary" << end();
237 abandon(tmp.value, payload_type(tmp.type), payload_size(tmp));
238
239 return result;
240 }
241
242 vector<double> deep_copy(reagent in, map<int, int>& addresses_copied, const reagent& tmp) {
243 canonize(in);
244 if (is_mu_address(in)) {
245 ¦
246 ¦ type_tree* payload = in.type->right;
247 ¦ if (payload->left->name == "channel" || payload->left->name == "screen" || payload->left->name == "console" || payload->left->name == "resources")
248 ¦ ¦ return read_memory(in);
249 }
250 vector<double> result;
251 if (is_mu_address(in))
252 ¦ result.push_back(deep_copy_address(in, addresses_copied, tmp));
253 else
254 ¦ deep_copy(in, addresses_copied, tmp, result);
255 return result;
256 }
257
258
259 int deep_copy_address(const reagent& canonized_in, map<int, int>& addresses_copied, const reagent& tmp) {
260 if (address_value(canonized_in) == 0) return 0;
261 int in_address = payload_address(canonized_in);
262 trace(9991, "run") << "deep-copy: copying address " << in_address << end();
263 if (contains_key(addresses_copied, in_address)) {
264 ¦ int out = get(addresses_copied, in_address);
265 ¦ trace(9991, "run") << "deep-copy: copy already exists: " << out << end();
266 ¦ return out;
267 }
268 int out = allocate(payload_size(canonized_in));
269 trace(9991, "run") << "deep-copy: new address is " << out << end();
270 put(addresses_copied, in_address, out);
271 reagent payload = canonized_in;
272 payload.properties.push_back(pair<string, string_tree*>("lookup", NULL));
273 trace(9991, "run") << "recursing on payload " << payload.value << ' ' << to_string(payload) << end();
274 vector<double> data = deep_copy(payload, addresses_copied, tmp);
275 trace(9991, "run") << "deep-copy: writing result " << out << ": " << to_string(data) << end();
276
277
278 trace(9991, "run") << "deep-copy: writing temporary " << tmp.value << ": " << out << end();
279 put(Memory, tmp.value, out);
280 payload.set_value(tmp.value);
281 vector<double> old_data = read_memory(payload);
282 trace(9991, "run") << "deep-copy: really writing to " << payload.value << ' ' << to_string(payload) << " (old value " << to_string(old_data) << " new value " << to_string(data) << ")" << end();
283 write_memory(payload, data);
284 trace(9991, "run") << "deep-copy: output is " << to_string(data) << end();
285 return out;
286 }
287
288
289 void deep_copy(const reagent& canonized_in, map<int, int>& addresses_copied, const reagent& tmp, vector<double>& out) {
290 assert(!is_mu_address(canonized_in));
291 vector<double> data = read_memory(canonized_in);
292 out.insert(out.end(), data.begin(), data.end());
293 if (!contains_key(Container_metadata, canonized_in.type)) return;
294 trace(9991, "run") << "deep-copy: scanning for addresses in " << to_string(data) << end();
295 const container_metadata& metadata = get(Container_metadata, canonized_in.type);
296 for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) {
297 ¦ if (!all_match(data, p->first)) continue;
298 ¦ for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) {
299 ¦ ¦
300 ¦ ¦ if (!info->payload_type->atom && info->payload_type->left->name == "channel")
301 ¦ ¦ ¦ continue;
302 ¦ ¦ if (info->payload_type->name == "screen" || info->payload_type->name == "console" || info->payload_type->name == "resources")
303 ¦ ¦ ¦ continue;
304 ¦ ¦
305 ¦ ¦
306 ¦ ¦ reagent curr;
307 ¦ ¦ if (info->payload_type->atom)
308 ¦ ¦ ¦ curr.type = new type_tree(new type_tree("address"), new type_tree(new type_tree(info->payload_type->name), NULL));
309 ¦ ¦ else
310 ¦ ¦ ¦ curr.type = new type_tree(new type_tree("address"), new type_tree(*info->payload_type));
311 ¦ ¦ curr.set_value(canonized_in.value + info->offset);
312 ¦ ¦ curr.properties.push_back(pair<string, string_tree*>("raw", NULL));
313 ¦ ¦ trace(9991, "run") << "deep-copy: copying address " << curr.value << end();
314 ¦ ¦ out.at(info->offset) = deep_copy_address(curr, addresses_copied, tmp);
315 ¦ }
316 }
317 }
318
319 int payload_address(reagent x) {
320 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
321 canonize(x);
322 return x.value;
323 }
324
325 int address_value(const reagent& x) {
326 assert(is_mu_address(x));
327 vector<double> result = read_memory(x);
328 assert(SIZE(result) == 1);
329 return static_cast<int>(result.at(0));
330 }
331
332 :(scenario deep_copy_stress_test_1)
333 container foo1 [
334 p:&:num
335 ]
336 container foo2 [
337 p:&:foo1
338 ]
339 exclusive-container foo3 [
340 p:&:foo1
341 q:&:foo2
342 ]
343 def main [
344 local-scope
345 x:&:num <- new number:type
346 *x <- copy 34
347 a:&:foo1 <- new foo1:type
348 *a <- merge x
349 b:&:foo2 <- new foo2:type
350 *b <- merge a
351 c:foo3 <- merge 1/q, b
352 d:foo3 <- deep-copy c
353 e:&:foo2, z:bool <- maybe-convert d, q:variant
354 f:&:foo1 <- get *e, p:offset
355 g:&:num <- get *f, p:offset
356 1:num/raw <- copy *g
357 ]
358 +mem: storing 34 in location 1
359
360 :(scenario deep_copy_stress_test_2)
361 container foo1 [
362 p:&:num
363 ]
364 container foo2 [
365 p:&:foo1
366 ]
367 exclusive-container foo3 [
368 p:&:foo1
369 q:&:foo2
370 ]
371 container foo4 [
372 p:num
373 q:&:foo3
374 ]
375 def main [
376 local-scope
377 x:&:num <- new number:type
378 *x <- copy 34
379 a:&:foo1 <- new foo1:type
380 *a <- merge x
381 b:&:foo2 <- new foo2:type
382 *b <- merge a
383 c:&:foo3 <- new foo3:type
384 *c <- merge 1/q, b
385 d:foo4 <- merge 35, c
386 e:foo4 <- deep-copy d
387 f:&:foo3 <- get e, q:offset
388 g:&:foo2, z:bool <- maybe-convert *f, q:variant
389 h:&:foo1 <- get *g, p:offset
390 y:&:num <- get *h, p:offset
391 1:num/raw <- copy *y
392 ]
393 +mem: storing 34 in location 1
394
395 :(scenario deep_copy_cycles)
396 container foo [
397 p:num
398 q:&:foo
399 ]
400 def main [
401 local-scope
402 x:&:foo <- new foo:type
403 *x <- put *x, p:offset, 34
404 *x <- put *x, q:offset, x
405 y:&:foo <- deep-copy x
406 1:num/raw <- get *y, p:offset
407 y2:&:foo <- get *y, q:offset
408 stash y [vs] y2
409 2:bool/raw <- equal y, y2
410 3:bool/raw <- equal x, y
411 ]
412 +mem: storing 34 in location 1
413
414 +mem: storing 1 in location 2
415
416 +mem: storing 0 in location 3
417
418 :(scenario deep_copy_skips_channel)
419
420 % if (!contains_key(Type_ordinal, "channel")) get_or_insert(Type, put(Type_ordinal, "channel", Next_type_ordinal++)).name = "channel";
421 def main [
422 local-scope
423 x:&:channel:num <- new {(channel num): type}
424 y:&:channel:num <- deep-copy x
425 10:bool/raw <- equal x, y
426 ]
427
428 +mem: storing 1 in location 10
429
430 :(scenario deep_copy_skips_nested_channel)
431
432 % if (!contains_key(Type_ordinal, "channel")) get_or_insert(Type, put(Type_ordinal, "channel", Next_type_ordinal++)).name = "channel";
433 container foo [
434 c:&:channel:num
435 ]
436 def main [
437 local-scope
438 x:&:foo <- new foo:type
439 y:&:foo <- deep-copy x
440 xc:&:channel:num <- get *x, c:offset
441 yc:&:channel:num <- get *y, c:offset
442 10:bool/raw <- equal xc, yc
443 ]
444
445 +mem: storing 1 in location 10
446
447 :(scenario deep_copy_skips_resources)
448
449 % if (!contains_key(Type_ordinal, "resources")) get_or_insert(Type, put(Type_ordinal, "resources", Next_type_ordinal++)).name = "resources";
450 def main [
451 local-scope
452 x:&:resources <- new resources:type
453 y:&:resources <- deep-copy x
454 10:bool/raw <- equal x, y
455 ]
456
457 +mem: storing 1 in location 10
458
459 :(scenario deep_copy_skips_nested_resources)
460
461 % if (!contains_key(Type_ordinal, "resources")) get_or_insert(Type, put(Type_ordinal, "resources", Next_type_ordinal++)).name = "resources";
462 container foo [
463 c:&:resources
464 ]
465 def main [
466 local-scope
467 x:&:foo <- new foo:type
468 y:&:foo <- deep-copy x
469 xc:&:resources <- get *x, c:offset
470 yc:&:resources <- get *y, c:offset
471 10:bool/raw <- equal xc, yc
472 ]
473
474 +mem: storing 1 in location 10