Skip to content

Commit 3b1dbc6

Browse files
gc: comments
1 parent 2b4b2ad commit 3b1dbc6

File tree

2 files changed

+28
-29
lines changed

2 files changed

+28
-29
lines changed

src/classfile.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ struct field_info {
246246
[[nodiscard]] inline bool is_static() const {
247247
return (access_flags & static_cast<u2>(FieldInfoAccessFlags::ACC_STATIC)) != 0;
248248
}
249+
250+
[[nodiscard]] inline bool is_reference_type() const {
251+
auto const &descriptor = descriptor_index->value;
252+
return descriptor.starts_with("L") || descriptor.starts_with("[");
253+
}
249254
};
250255

251256
enum class MethodInfoAccessFlags : u2 {

src/memory.cpp

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ bool Heap::all_objects_are_unmarked() {
135135
namespace {
136136
void mark_recursively(std::queue<Object *> &queue, bool gc_bit_marked, Reference to_mark,
137137
std::unordered_set<Object *> const &all_object_pointers) {
138-
auto mark = [&queue, gc_bit_marked, &all_object_pointers](Reference reference) {
138+
auto enqueue = [&queue, gc_bit_marked, &all_object_pointers](Reference reference) {
139139
if (reference != JAVA_NULL) {
140140
Object *object = reference.object();
141141
(void) all_object_pointers;
@@ -148,65 +148,56 @@ void mark_recursively(std::queue<Object *> &queue, bool gc_bit_marked, Reference
148148
}
149149
};
150150

151-
mark(to_mark);
151+
enqueue(to_mark);
152152

153153
while (!queue.empty()) {
154154
Object *object = queue.front();
155155
queue.pop();
156156

157157
ClassFile *clazz = object->clazz;
158-
mark(Reference{clazz});
158+
enqueue(Reference{clazz});
159159

160+
// Mark fields of instances and array elements.
161+
// Keep in mind that classes are also instances that have fields.
160162
if (!clazz->is_array()) {
161163
// TODO we might have to initializes more classes
162164
assert(clazz->resolved);
163165

166+
// we only need to check superclasses because interfaces don't have instance fields
164167
for (ClassFile *current = clazz; current != nullptr; current = current->super_class) {
165168
for (const auto &field : current->fields) {
166-
auto const &descriptor = field.descriptor_index->value;
167-
if (descriptor.starts_with("L") || descriptor.starts_with("[")) {
168-
if (field.is_static()) {
169-
// static fields are handled when the class itself is marked
170-
} else {
171-
Reference reference{object};
172-
mark(reference.data<Value>()[field.index].reference);
173-
}
169+
if (!field.is_static() && field.is_reference_type()) {
170+
enqueue(Reference{object}.data<Value>()[field.index].reference);
174171
}
175172
}
176173
}
177-
} else {
178-
if (!clazz->array_element_type->is_primitive()) {
179-
Reference reference{object};
180-
for (s4 i = 0; i < object->length; ++i) {
181-
mark(reference.data<Reference>()[i]);
182-
}
174+
} else if (!clazz->array_element_type->is_primitive()) {
175+
for (s4 i = 0; i < object->length; ++i) {
176+
enqueue(Reference{object}.data<Reference>()[i]);
183177
}
184178
}
185179

180+
// Classes are also objects. When they are marked we also need to
181+
// enqueue references that are stored in their C++ representation:
186182
if (clazz->name() == Names::java_lang_Class) {
187183
auto class_instance = reinterpret_cast<ClassFile *> (object);
188184

189-
// TODO check if ClassFile references other objects (e.g. inside constant pool entries)
190-
191185
// TODO this would not be necessary if classloaders keep a list of loaded clases
192-
mark(Reference{class_instance->super_class});
186+
enqueue(Reference{class_instance->super_class});
193187
for (const auto &item : class_instance->interfaces) {
194-
mark(Reference{item->clazz});
188+
enqueue(Reference{item->clazz});
195189
}
196190

191+
// resolved classes can have static variables:
197192
if (class_instance->resolved) {
198193
for (const auto &field : class_instance->fields) {
199-
auto const &descriptor = field.descriptor_index->value;
200-
if (descriptor.starts_with("L") || descriptor.starts_with("[")) {
201-
if (field.is_static()) {
202-
mark(class_instance->static_field_values[field.index].reference);
203-
} else {
204-
// These would be the fields of an instance of class_instance.
205-
// The real fields (from java/lang/Class) have been marked in the loop above.
206-
}
194+
if (field.is_static() && field.is_reference_type()) {
195+
enqueue(class_instance->static_field_values[field.index].reference);
207196
}
208197
}
209198
}
199+
200+
// TODO check if ClassFile references any other objects (e.g. inside constant pool entries)
210201
}
211202
}
212203
};
@@ -219,6 +210,9 @@ void Heap::mark(std::vector<Thread *> &threads, bool gc_bit_marked) {
219210
return value != 0 && (value % alignof(std::max_align_t)) == 0;
220211
};
221212

213+
// Build a hashmap of all known allocations to determine out which
214+
// values on the operand stack and in local variables are pointers.
215+
// TODO statically determine the types instead (see StackMapTable Attribute)
222216
std::unordered_set<Object *> all_object_pointers;
223217
for (const auto &clazz : classes) {
224218
auto *object = reinterpret_cast<Object *>(clazz.get());

0 commit comments

Comments
 (0)