forked from rubinius/rubinius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
code_manager.cpp
168 lines (141 loc) · 3.88 KB
/
code_manager.cpp
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <string.h>
#include "vm.hpp"
#include "gc/code_manager.hpp"
#include "gc/code_resource.hpp"
namespace rubinius {
CodeManager::Chunk::Chunk(int size)
: next(0)
{
resources = new CodeResource*[size];
memset(resources, 0, sizeof(CodeResource*) * size);
}
CodeManager::Chunk::~Chunk() {
delete[] resources;
}
CodeManager::CodeManager(SharedState* shared, int chunk_size)
: shared_(shared)
, chunk_size_(chunk_size)
, first_chunk_(0)
, last_chunk_(0)
, current_chunk_(0)
, current_index_(0)
, freed_resources_(0)
, total_allocated_(0)
, total_freed_(0)
, bytes_used_(0)
{
first_chunk_ = new Chunk(chunk_size_);
last_chunk_ = first_chunk_;
current_chunk_ = first_chunk_;
}
CodeManager::~CodeManager() {
Chunk* chunk = first_chunk_;
while(chunk) {
for(int i = 0; i < chunk_size_; i++) {
if(CodeResource* cr = chunk->resources[i]) {
delete cr;
chunk->resources[i] = 0;
}
}
Chunk* next = chunk->next;
delete chunk;
chunk = next;
}
}
void CodeManager::add_chunk() {
Chunk* c = new Chunk(chunk_size_);
current_index_ = 0;
last_chunk_->next = c;
last_chunk_ = c;
current_chunk_ = c;
}
void CodeManager::add_resource(CodeResource* cr) {
utilities::thread::Mutex::LockGuard guard(mutex_);
total_allocated_ += cr->size();
bytes_used_ += cr->size();
for(;;) {
while(current_index_ < chunk_size_) {
if(current_chunk_->resources[current_index_] == 0) {
current_chunk_->resources[current_index_] = cr;
return;
}
current_index_++;
}
// Move on to the next one or add a new one
current_index_ = 0;
current_chunk_ = current_chunk_->next;
if(!current_chunk_) add_chunk();
}
}
void CodeManager::sweep() {
Chunk* chunk = first_chunk_;
Chunk* prev = NULL;
freed_resources_ = 0;
State state(shared_->root_vm());
while(chunk) {
bool chunk_used = false;
for(int i = 0; i < chunk_size_; i++) {
if(CodeResource* cr = chunk->resources[i]) {
if(!cr->marked()) {
total_freed_ += cr->size();
bytes_used_ -= cr->size();
freed_resources_++;
cr->cleanup(&state, this);
delete cr;
chunk->resources[i] = 0;
} else {
chunk_used = true;
cr->clear_mark();
}
}
}
// Cleanup unused chunks. We can never cleanup the first
// chunk in the list, but that will be always used anyway
// with references to boot up code etc.
if(!chunk_used && prev) {
prev->next = chunk->next;
// If we clean up the last chunk, set the last chunk
// to the previous one we've seen.
if(last_chunk_ == chunk) {
last_chunk_ = prev;
}
// If we clean up the current chunk, set the current
// to the previous one. The code will scan the chunk then
// and might allocate a new one of the previous is
// already completely full.
if(current_chunk_ == chunk) {
current_chunk_ = prev;
}
delete chunk;
chunk = prev->next;
} else {
prev = chunk;
chunk = chunk->next;
}
}
}
int CodeManager::calculate_size() {
Chunk* chunk = first_chunk_;
int total = 0;
while(chunk) {
for(int i = 0; i < chunk_size_; i++) {
if(CodeResource* cr = chunk->resources[i]) {
total += cr->size();
}
}
chunk = chunk->next;
}
return total;
}
void CodeManager::clear_marks() {
Chunk* chunk = first_chunk_;
while(chunk) {
for(int i = 0; i < chunk_size_; i++) {
if(CodeResource* cr = chunk->resources[i]) {
cr->clear_mark();
}
}
chunk = chunk->next;
}
}
}