-
Notifications
You must be signed in to change notification settings - Fork 0
/
garbage.py
98 lines (70 loc) · 2.33 KB
/
garbage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
'''
TODO:
* garbage collection!
* mark-sweep
* Xstop-copyX
* figure out a better gc trigger
* memory limit?
'''
from mem import \
load_memory, write_memory, next_free_address,\
convert_str_address, convert_num_address, ROOT, PREFIX
MEM_LEN = 16
def collect_garbage_if_needed():
free_address = next_free_address(load_memory())
if convert_str_address(free_address) >= MEM_LEN:
print('Collecting gargage...')
collect_garbage()
BROKEN_HEART = '</3'
# stop and copy
def collect_garbage():
from_space = load_memory()
reachable_addresses = get_reachable_addresses(from_space, ROOT)
forwarding = {
old: convert_num_address(i)
for i, old in enumerate(reachable_addresses)
}
to_space = {
forwarding[address]:
update_env_pointers(
from_space[address], forwarding)
for address in reachable_addresses
}
write_memory(to_space)
def update_env_pointers(old_env, forwarding):
old_frame, old_enclosure = old_env
new_frame = {
key: (val if not is_function(val)
else [forwarding[val[0]]] + val[1:])
for key, val in old_frame.items()
}
new_enclosure = (forwarding[old_enclosure]
if old_enclosure is not None
else None)
new_env = [new_frame, new_enclosure]
return new_env
# Would this be easier or harder to understand
# if this was written recursively? (TODO)
def get_reachable_addresses(from_space, root):
reachable_addresses = [root]
for address in reachable_addresses:
env = from_space[address]
pointers = gather_pointers(env)
for pointer in pointers:
if pointer not in reachable_addresses:
reachable_addresses.append(pointer)
return reachable_addresses
def gather_pointers(env):
frame, enclosure = env
functions = [val for val in frame.values() if is_function(val)]
# functions have the form [address, params, body]
addresses = set([address for address, _, _ in functions])
if enclosure is not None:
addresses.add(enclosure)
return addresses
def is_function(entry):
try:
address, _, _ = entry
return address[:len(PREFIX)] == PREFIX
except (TypeError, ValueError):
return False