https://github.com/akkartik/mu/blob/master/036abandon.cc
1
2
3 :(scenario new_reclaim)
4 def main [
5 10:&:num <- new number:type
6 20:num <- deaddress 10:&:num
7 abandon 10:&:num
8 30:&:num <- new number:type
9 40:num <- deaddress 30:&:num
10 50:bool <- equal 20:num, 40:num
11 ]
12
13 +mem: storing 1 in location 50
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 :(before "End routine Fields")
30 map<int, int> free_list;
31
32 :(before "End Primitive Recipe Declarations")
33 ABANDON,
34 :(before "End Primitive Recipe Numbers")
35 put(Recipe_ordinal, "abandon", ABANDON);
36 :(before "End Primitive Recipe Checks")
37 case ABANDON: {
38 if (!inst.products.empty()) {
39 raise << maybe(get(Recipe, r).name) << "'abandon' shouldn't write to any products in '" << to_original_string(inst) << "'\n" << end();
40 break;
41 }
42 for (int i = 0; i < SIZE(inst.ingredients); ++i) {
43 if (!is_mu_address(inst.ingredients.at(i)))
44 raise << maybe(get(Recipe, r).name) << "ingredients of 'abandon' should be addresses, but ingredient " << i << " is '" << to_string(inst.ingredients.at(i)) << '\n' << end();
45 break;
46 }
47 break;
48 }
49 :(before "End Primitive Recipe Implementations")
50 case ABANDON: {
51 for (int i = 0; i < SIZE(current_instruction().ingredients); ++i) {
52 reagent ingredient = current_instruction().ingredients.at(i);
53 canonize(ingredient);
54 abandon(get_or_insert(Memory, ingredient.value+1), payload_size(ingredient));
55
56 put(Memory, ingredient.value, -1);
57 put(Memory, ingredient.value+1, 0);
58 }
59 break;
60 }
61
62 :(code)
63 void abandon(int address, int payload_size) {
64 put(Memory, address, -1);
65
66
67 for (int curr = address+1; curr < address+payload_size; ++curr)
68 put(Memory, curr, 0);
69
70 trace("abandon") << "saving " << address << " in free-list of size " << payload_size << end();
71 put(Memory, address+1, get_or_insert(Current_routine->free_list, payload_size));
72 put(Current_routine->free_list, payload_size, address);
73 }
74
75 int payload_size(reagent x) {
76 x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
77 lookup_memory_core(x, false);
78 return size_of(x)+1;
79 }
80
81 :(after "Allocate Special-cases")
82 if (get_or_insert(Current_routine->free_list, size)) {
83 trace("abandon") << "picking up space from free-list of size " << size << end();
84 int result = get_or_insert(Current_routine->free_list, size);
85 trace("mem") << "new alloc from free list: " << result << end();
86 put(Current_routine->free_list, size, get_or_insert(Memory, result+1));
87
88 put(Memory, result, 0);
89
90 put(Memory, result+1, 0);
91 for (int curr = result; curr < result+size; ++curr) {
92 if (get_or_insert(Memory, curr) != 0) {
93 raise << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
94 break;
95 }
96 }
97 return result;
98 }
99
100 :(scenario new_differing_size_no_reclaim)
101 def main [
102 1:&:num <- new number:type
103 2:num <- deaddress 1:&:num
104 abandon 1:&:num
105 3:&:@:num <- new number:type, 2
106 4:num <- deaddress 3:&:@:num
107 5:bool <- equal 2:num, 4:num
108 ]
109
110 +mem: storing 0 in location 5
111
112 :(scenario new_reclaim_array)
113 def main [
114 10:&:@:num <- new number:type, 2
115 20:num <- deaddress 10:&:@:num
116 abandon 10:&:@:num
117 30:&:@:num <- new number:type, 2
118 40:num <- deaddress 30:&:@:num
119 50:bool <- equal 20:num, 40:num
120 ]
121
122 +mem: storing 1 in location 50
123
124 :(scenario lookup_of_abandoned_address_raises_error)
125 % Hide_errors = true;
126 def main [
127 1:&:num <- new num:type
128 3:&:num <- copy 1:&:num
129 abandon 1:&:num
130 5:num/raw <- copy *3:&:num
131 ]
132 +error: main: address is already abandoned in '5:num/raw <- copy *3:&:num'