diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-05-03 10:15:17 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-05-03 10:15:17 -0700 |
commit | dc9afcbd7d7f1dcfae7b9ae659ccea4944b95a29 (patch) | |
tree | 90141172495d4f607d2ac03da912b98556b6686f /036abandon.cc | |
parent | 02909fecf6fba87604ff73fe3067e43e0ad068ee (diff) | |
download | mu-dc9afcbd7d7f1dcfae7b9ae659ccea4944b95a29.tar.gz |
2894
Reorganize the 'address' layer and split it up before we start greatly expanding them to manage refcounts in nested objects.
Diffstat (limited to '036abandon.cc')
-rw-r--r-- | 036abandon.cc | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/036abandon.cc b/036abandon.cc new file mode 100644 index 00000000..22d93ec9 --- /dev/null +++ b/036abandon.cc @@ -0,0 +1,143 @@ +//: Reclaiming memory when it's no longer used. +//: The top of layer 34 has the complete life cycle of memory. + +:(scenario new_reclaim) +def main [ + 1:address:number <- new number:type + 2:number <- copy 1:address:number # because 1 will get reset during abandon below + 1:address:number <- copy 0 # abandon + 3:address:number <- new number:type # must be same size as abandoned memory to reuse + 4:boolean <- equal 2:number, 3:address:number +] +# both allocations should have returned the same address ++mem: storing 1 in location 4 + +:(before "End Update Reference Count") +// abandon old address if necessary +// do this after all refcount updates are done, just in case old and new are identical +assert(old_address >= 0); +if (old_address == 0) return; +if (get_or_insert(Memory, old_address) < 0) { + tb_shutdown(); + DUMP(""); + cerr << "Negative refcount: " << old_address << ' ' << get_or_insert(Memory, old_address) << '\n'; + exit(0); +} +if (get_or_insert(Memory, old_address) > 0) return; +// old_address has a 0 refcount +// lookup_memory without drop_one_lookup { +trace(9999, "mem") << "automatically abandoning " << old_address << end(); +trace(9999, "mem") << "computing size to abandon at " << x.value << end(); +x.set_value(old_address+/*skip refcount*/1); +drop_from_type(x, "address"); +// } +abandon(old_address, size_of(x)+/*refcount*/1); + +//: When abandoning addresses we'll save them to a 'free list', segregated by size. + +:(before "End routine Fields") +map<int, int> free_list; + +:(code) +void abandon(int address, int size) { + trace(9999, "abandon") << "saving in free-list of size " << size << end(); +//? Total_free += size; +//? Num_free++; +//? cerr << "abandon: " << size << '\n'; + // clear memory + for (int curr = address; curr < address+size; ++curr) + put(Memory, curr, 0); + // append existing free list to address + put(Memory, address, get_or_insert(Current_routine->free_list, size)); + put(Current_routine->free_list, size, address); +} + +:(before "ensure_space(size)" following "case ALLOCATE") +if (get_or_insert(Current_routine->free_list, size)) { + trace(9999, "abandon") << "picking up space from free-list of size " << size << end(); + int result = get_or_insert(Current_routine->free_list, size); + trace(9999, "mem") << "new alloc from free list: " << result << end(); + put(Current_routine->free_list, size, get_or_insert(Memory, result)); + for (int curr = result+1; curr < result+size; ++curr) { + if (get_or_insert(Memory, curr) != 0) { + raise << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end(); + break; // always fatal + } + } + if (SIZE(current_instruction().ingredients) > 1) + put(Memory, result+/*skip refcount*/1, ingredients.at(1).at(0)); + else + put(Memory, result, 0); + products.resize(1); + products.at(0).push_back(result); + break; +} + +:(scenario new_differing_size_no_reclaim) +def main [ + 1:address:number <- new number:type + 2:number <- copy 1:address:number + 1:address:number <- copy 0 # abandon + 3:address:array:number <- new number:type, 2 # different size + 4:boolean <- equal 2:number, 3:address:array:number +] +# no reuse ++mem: storing 0 in location 4 + +:(scenario new_reclaim_array) +def main [ + 1:address:array:number <- new number:type, 2 + 2:number <- copy 1:address:array:number + 1:address:array:number <- copy 0 # abandon + 3:address:array:number <- new number:type, 2 # same size + 4:boolean <- equal 2:number, 3:address:array:number +] +# reuse ++mem: storing 1 in location 4 + +:(scenario refcounts_2) +def main [ + 1:address:number <- new number:type + # over-writing one allocation with another + 1:address:number <- new number:type + 1:address:number <- copy 0 +] ++run: {1: ("address" "number")} <- new {number: "type"} ++mem: incrementing refcount of 1000: 0 -> 1 ++run: {1: ("address" "number")} <- new {number: "type"} ++mem: automatically abandoning 1000 + +:(scenario refcounts_3) +def main [ + 1:address:number <- new number:type + # passing in addresses to recipes increments refcount + foo 1:address:number + 1:address:number <- copy 0 +] +def foo [ + 2:address:number <- next-ingredient + # return does NOT yet decrement refcount; memory must be explicitly managed + 2:address:number <- copy 0 +] ++run: {1: ("address" "number")} <- new {number: "type"} ++mem: incrementing refcount of 1000: 0 -> 1 ++run: {2: ("address" "number")} <- next-ingredient ++mem: incrementing refcount of 1000: 1 -> 2 ++run: {2: ("address" "number")} <- copy {0: "literal"} ++mem: decrementing refcount of 1000: 2 -> 1 ++run: {1: ("address" "number")} <- copy {0: "literal"} ++mem: decrementing refcount of 1000: 1 -> 0 ++mem: automatically abandoning 1000 + +:(scenario refcounts_array) +def main [ + 1:number <- copy 30 + # allocate an array + 10:address:array:number <- new number:type, 20 + 11:number <- copy 10:address:array:number # doesn't increment refcount + # allocate another array in its place, implicitly freeing the previous allocation + 10:address:array:number <- new number:type, 25 +] ++run: {10: ("address" "array" "number")} <- new {number: "type"}, {25: "literal"} +# abandoned array is of old size (20, not 25) ++abandon: saving in free-list of size 22 |