5 #include "shotgun/lib/shotgun.h"
6 #include "shotgun/lib/machine.h"
7 #include "shotgun/lib/baker.h"
8 #include "shotgun/lib/marksweep.h"
9 #include "shotgun/lib/tuple.h"
10 #include "shotgun/lib/methctx.h"
12 void _describe(OBJECT ptr
) {
14 om
= (object_memory
)(current_machine
->s
->om
);
15 printf("Address: %p (%lu)\n", (void*)ptr
, (unsigned long int)ptr
);
16 printf("Contained in baker?: %d/%d\n", baker_gc_contains_p(om
->gc
, ptr
), baker_gc_contains_spill_p(om
->gc
, ptr
));
17 printf("Contained in m/s?: %d\n", ptr
->gc_zone
== MatureObjectZone
);
18 if(heap_contains_p(om
->contexts
, ptr
)) {
19 printf("Is a context.\n");
20 if(ptr
< om
->context_bottom
) {
21 printf(" Referenced (below bottom)\n");
23 printf(" Normal on stack (not referenced)\n");
26 printf("stack_context_p: %d / %d\n", om_stack_context_p(om
, ptr
), stack_context_p(ptr
));
27 printf("nil klass: %d\n", ptr
->klass
== Qnil
);
28 printf("context_refd_p: %d\n", om_context_referenced_p(om
, ptr
));
29 printf("in_heap: %d\n", om_in_heap(om
, ptr
));
30 printf("methctx_fast: %d\n", methctx_is_fast_p(current_machine
->s
, ptr
));
31 printf("blokctx_p: %d\n", block_context_p(current_machine
->s
, ptr
));
32 printf("valid_ctx_p: %d\n", om_valid_context_p(current_machine
->s
, ptr
));
37 om
= (object_memory
)(current_machine
->s
->om
);
39 printf("Baker Info:\n");
40 baker_gc_describe(om
->gc
);
41 printf("MarkSweep Info:\n");
42 mark_sweep_describe(om
->ms
);
45 void _verify(OBJECT self
) {
47 om
= (object_memory
)(current_machine
->s
->om
);
52 printf("Verifying %p...\n", (void*)self
);
53 if(self
->StoresBytes
) {
54 printf("Object stores bytes.\n");
63 for(i
= 0; i
< NUM_FIELDS(self
); i
++) {
64 tmp
= NTH_FIELD(self
, i
);
65 if(!REFERENCE_P(tmp
)) continue;
70 printf("ERROR: Object %p (at %i) is IG, but no RS mark!\n", (void*)tmp
, i
);
74 printf("Done verifying %p: %d fields, %d refs\n", (void*)self
, NUM_FIELDS(self
), refs
);
77 int object_memory_actual_omsize() {
78 int omsize
= OMDefaultSize
;
79 char *s
= getenv("RUBINIUS_OMSIZE");
82 /* fprintf(stderr, "OMSize set to: %d\n", omsize); */
84 assert(omsize
> 0); /* general sanity */
85 assert((omsize
& 7) == 0); /* alignment */
89 #define CONTEXT_SIZE (1024 * 1024)
91 object_memory
object_memory_new() {
93 om
= (object_memory
)calloc(1, sizeof(struct object_memory_struct
));
94 om
->gc
= baker_gc_new(object_memory_actual_omsize());
95 om
->gc
->tenure
= (OBJECT (*)(void*,OBJECT
))object_memory_tenure_object
;
96 om
->gc
->tenure_data
= om
;
99 om
->ms
= mark_sweep_new();
101 om
->contexts
= heap_new(CONTEXT_SIZE
);
102 om
->context_bottom
= (OBJECT
)(om
->contexts
->address
);
103 om
->context_last
= (OBJECT
)((uintptr_t)om
->contexts
->address
+ CONTEXT_SIZE
- (CTX_SIZE
* 10));
105 om
->last_object_id
= 0;
106 om
->bootstrap_loaded
= 0;
107 // om->enlarge_new = 0;
112 int object_memory_destroy(object_memory om
) {
113 baker_gc_destroy(om
->gc
);
114 mark_sweep_destroy(om
->ms
);
119 void object_memory_formalize_contexts(STATE
, object_memory om
) {
123 methctx_reference(state
, ctx
);
124 } DONE_EACH_CTX(ctx
);
128 void object_memory_mark_contexts(STATE
, object_memory om
) {
132 mark_sweep_mark_context(state
, om
->ms
, ctx
);
133 } DONE_EACH_CTX(ctx
);
137 void object_memory_reset_contexts(STATE
, object_memory om
) {
138 /* reset the virtual bottom */
139 om
->context_bottom
= (OBJECT
)om
->contexts
->address
;
142 om
->contexts
->current
= om
->contexts
->address
;
145 void object_memory_clear_marks(STATE
, object_memory om
) {
149 mark_sweep_clear_mark(state
, ctx
);
150 } DONE_EACH_CTX(ctx
);
153 size_t object_memory_used(object_memory om
) {
154 return baker_gc_used(om
->gc
);
157 void object_memory_setup_become(STATE
, object_memory om
, OBJECT from
, OBJECT to
) {
158 om
->gc
->become_from
= from
;
159 om
->gc
->become_to
= to
;
160 om
->ms
->become_from
= from
;
161 om
->ms
->become_to
= to
;
164 void object_memory_clear_become(STATE
, object_memory om
) {
165 om
->gc
->become_from
= Qnil
;
166 om
->gc
->become_to
= Qnil
;
167 om
->ms
->become_from
= Qnil
;
168 om
->ms
->become_to
= Qnil
;
171 int object_memory_collect(STATE
, object_memory om
, ptr_array roots
) {
173 om
->gc
->tenure_now
= om
->tenure_now
;
174 om
->last_tenured
= 0;
175 i
= baker_gc_collect(state
, om
->gc
, roots
);
176 // object_memory_check_memory(om);
177 om
->gc
->tenure_now
= om
->tenure_now
= 0;
183 void object_memory_major_collect(STATE
, object_memory om
, ptr_array roots
) {
184 mark_sweep_collect(state
, om
->ms
, roots
);
185 baker_gc_clear_marked(om
->gc
);
186 object_memory_clear_marks(state
, om
);
189 OBJECT
object_memory_tenure_object(void *data
, OBJECT obj
) {
191 object_memory om
= (object_memory
)data
;
192 mark_sweep_gc ms
= om
->ms
;
196 dest
= mark_sweep_allocate(ms
, NUM_FIELDS(obj
));
198 // printf("Tenuring %p to %p (%d)\n", (void*)obj, (void*)dest, NUM_FIELDS(obj));
201 om
->collect_now
|= OMCollectMature
;
204 fast_memcpy((void*)dest
, (void*)obj
, SIZE_IN_WORDS_FIELDS(NUM_FIELDS(obj
)));
205 dest
->gc_zone
= MatureObjectZone
;
206 //printf("Allocated %d fields to %p\n", NUM_FIELDS(obj), obj);
207 // printf(" :: %p => %p (%d / %d )\n", obj, dest, NUM_FIELDS(obj), SIZE_IN_BYTES(obj));
211 void object_memory_print_stats(object_memory om
) {
212 printf("Memory: %zd used, %zd total.\n", object_memory_used(om
), om
->gc
->current
->size
);
215 void object_memory_check_ptr(void *ptr
, OBJECT obj
) {
216 object_memory om
= (object_memory
)ptr
;
217 if(REFERENCE_P(obj
)) {
218 assert(baker_gc_contains_spill_p(om
->gc
, obj
) ||
219 mark_sweep_contains_p(om
->ms
, obj
) ||
220 heap_contains_p(om
->contexts
, obj
));
221 assert(obj
->klass
!= Qnil
);
222 } else if(SYMBOL_P(obj
)) {
223 assert((uintptr_t)obj
< 10000000);
227 void object_memory_update_rs(object_memory om
, OBJECT target
, OBJECT val
) {
228 if(!target
->Remember
) {
229 // printf("[Tracking %p in baker RS]\n", (void*)target);
230 ptr_array_append(om
->gc
->remember_set
, (xpointer
)target
);
231 target
->Remember
= TRUE
;
235 int object_memory_is_reference_p(object_memory om
, OBJECT tmp
) {
236 return baker_gc_contains_p(om
->gc
, tmp
) || mark_sweep_contains_p(om
->ms
, tmp
);
239 OBJECT
object_memory_collect_references(STATE
, object_memory om
, OBJECT mark
) {
244 refs
= ptr_array_new(8);
246 baker_gc_collect_references(state
, om
->gc
, mark
, refs
);
247 mark_sweep_collect_references(state
, om
->ms
, mark
, refs
);
249 if(ptr_array_length(refs
) == 0) return Qnil
;
251 tup
= tuple_new(state
, ptr_array_length(refs
));
252 for(i
= 0; i
< ptr_array_length(refs
); i
++) {
253 tuple_put(state
, tup
, i
, (OBJECT
)ptr_array_get_index(refs
, i
));
260 int _object_stores_bytes(OBJECT self
);
263 * consistency check the object_memory: all objects either store bytes
264 * (in which case we don't care about their contents) or they store
265 * fields that are valid objects.
267 * object_memory_check_memory only works correctly if om->collect_now
268 * is false; as the function object_memory_is_reference_p assumes
269 * there haven't been any spills yet. [Bug or feature?]
272 void object_memory_check_memory(object_memory om
) {
273 int i
, sz
, osz
, fel
, num
;
274 char *start
, *end
, *cur
;
277 sz
= object_memory_used(om
);
278 start
= (char*)om
->gc
->current
->address
;
287 osz
= SIZE_IN_BYTES(obj
);
289 fel
= NUM_FIELDS(obj
);
290 if(!_object_stores_bytes(obj
)) {
291 for(i
= 0; i
< fel
; i
++) {
292 tmp
= NTH_FIELD_DIRECT(obj
, i
);
293 if(REFERENCE_P(tmp
) && !object_memory_is_reference_p(om
,tmp
)) {
294 printf("(%p-%p) %d: %s (%d of %d) contains a bad field (%p)!!\n",
295 (void*)om
->gc
->current
->address
, (void*)om
->gc
->current
->last
,
296 num
, _inspect(obj
), i
, fel
, (void*)tmp
);
297 /* separate printf as this one might segfault: */
298 printf("bad field is: %s\n", _inspect(tmp
));
307 // printf("Checked %d objects.\n", num);
311 void object_memory_detect_cleanup(object_memory om) {
313 char *start, *end, *cur;
316 sz = object_memory_used(om);
317 start = (char*)om->gc->current->address;
326 osz = SIZE_IN_BYTES(cur);
328 if(!baker_gc_forwarded_p(obj)) {
329 printf("Found a %s that is garbage\n", _inspect(obj));
337 void state_each_object(STATE
, OBJECT kls
, void (*cb
)(STATE
, OBJECT
)) {
339 char *start
, *end
, *cur
;
345 sz
= object_memory_used(om
);
346 start
= (char*)om
->gc
->current
->address
;
355 osz
= SIZE_IN_BYTES(obj
);
362 // printf("Checked %d objects.\n", num);
365 void object_memory_emit_details(STATE
, object_memory om
, FILE *stream
) {
367 char *start
, *end
, *cur
;
371 sz
= object_memory_used(om
);
372 start
= (char*)om
->gc
->current
->address
;
378 osz
= SIZE_IN_BYTES(obj
);
379 if(NUM_FIELDS(obj
) == 0) {
380 fprintf(stream
, "%p %d free\n", obj
, (int)(end
- cur
));
383 if(kls
== state
->global
->cmethod
) {
385 } else if(kls
== state
->global
->bytearray
) {
387 } else if(kls
== state
->global
->string
) {
389 } else if(kls
== state
->global
->tuple
) {
391 } else if(kls
== state
->global
->methctx
|| kls
== state
->global
->blokctx
) {
393 } else if(kls
== state
->global
->class || kls
== state
->global
->metaclass
) {
399 fprintf(stream
, "%p %d %s\n", obj
, osz
, kind
);
405 OBJECT
object_memory_new_object_mature(object_memory om
, OBJECT cls
, unsigned int fields
) {
412 obj
= mark_sweep_allocate(ms
, fields
);
414 om
->collect_now
|= OMCollectMature
;
419 obj
->gc_zone
= MatureObjectZone
;
421 rbs_set_class(om
, obj
, cls
);
422 SET_NUM_FIELDS(obj
, fields
);
423 if(cls
&& REFERENCE_P(cls
)) {
424 _om_apply_class_flags(obj
, cls
);
426 for(i
= 0; i
< fields
; i
++) {
427 rbs_set_field(om
, obj
, i
, Qnil
);
434 OBJECT
object_memory_new_object_normal(object_memory om
, OBJECT cls
, unsigned int fields
) {
438 //fields += 4; /* PAD */
439 size
= SIZE_IN_BYTES_FIELDS(fields
);
440 if(!heap_enough_space_p(om
->gc
->current
, size
)) {
441 obj
= (OBJECT
)baker_gc_allocate_spilled(om
->gc
, size
);
442 xassert(heap_enough_space_p(om
->gc
->next
, size
));
443 // DEBUG("Ran out of space! spilled into %p\n", obj);
444 om
->collect_now
|= OMCollectYoung
;
445 // baker_gc_enlarge_next(om->gc, om->gc->current->size * GC_SCALING_FACTOR);
447 obj
= (OBJECT
)baker_gc_allocate(om
->gc
, size
);
451 obj
->gc_zone
= YoungObjectZone
;
453 rbs_set_class(om
, obj
, cls
);
454 SET_NUM_FIELDS(obj
, fields
);
455 if(cls
&& REFERENCE_P(cls
)) {
456 _om_apply_class_flags(obj
, cls
);
459 for(i
= 0; i
< fields
; i
++) {
460 rbs_set_field(om
, obj
, i
, Qnil
);
466 OBJECT
object_memory_new_opaque(STATE
, OBJECT cls
, unsigned int sz
) {
469 fel
= sz
/ SIZE_OF_OBJECT
;
470 if(sz
% SIZE_OF_OBJECT
) fel
++;
471 obj
= object_memory_new_object(state
->om
, cls
, fel
);
472 object_make_byte_storage(state
, obj
);