Change soft-fail to use the config, rather than env
[rbx.git] / shotgun / lib / object_memory.c
blob88fc3331ad4ced8b21b4332ab1cab9e0eed0761c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <assert.h>
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) {
13 object_memory om;
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");
22 } else {
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));
35 void _stats() {
36 object_memory om;
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) {
46 object_memory om;
47 om = (object_memory)(current_machine->s->om);
48 OBJECT tmp;
49 int i, rs, refs;
50 gc_zone tz, vz;
52 printf("Verifying %p...\n", (void*)self);
53 if(self->StoresBytes) {
54 printf("Object stores bytes.\n");
55 return;
58 rs = self->Remember;
60 tz = self->gc_zone;
61 refs = 0;
63 for(i = 0; i < NUM_FIELDS(self); i++) {
64 tmp = NTH_FIELD(self, i);
65 if(!REFERENCE_P(tmp)) continue;
67 refs++;
68 vz = tmp->gc_zone;
69 if(tz < vz && !rs) {
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");
80 if(s) {
81 omsize = atoi(s);
82 /* fprintf(stderr, "OMSize set to: %d\n", omsize); */
84 assert(omsize > 0); /* general sanity */
85 assert((omsize & 7) == 0); /* alignment */
86 return omsize;
89 #define CONTEXT_SIZE (1024 * 1024)
91 object_memory object_memory_new() {
92 object_memory om;
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;
97 om->gc->om = 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;
108 // om->new_size = 0;
109 return om;
112 int object_memory_destroy(object_memory om) {
113 baker_gc_destroy(om->gc);
114 mark_sweep_destroy(om->ms);
115 free(om);
116 return TRUE;
119 void object_memory_formalize_contexts(STATE, object_memory om) {
120 OBJECT ctx;
122 EACH_CTX(om, ctx) {
123 methctx_reference(state, ctx);
124 } DONE_EACH_CTX(ctx);
128 void object_memory_mark_contexts(STATE, object_memory om) {
129 OBJECT ctx;
131 EACH_CTX(om, ctx) {
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;
141 /* reset the top */
142 om->contexts->current = om->contexts->address;
145 void object_memory_clear_marks(STATE, object_memory om) {
146 OBJECT ctx;
148 EACH_CTX(om, ctx) {
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) {
172 int i;
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;
178 om->collect_now = 0;
180 return i;
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) {
190 OBJECT dest;
191 object_memory om = (object_memory)data;
192 mark_sweep_gc ms = om->ms;
194 om->last_tenured++;
196 dest = mark_sweep_allocate(ms, NUM_FIELDS(obj));
198 // printf("Tenuring %p to %p (%d)\n", (void*)obj, (void*)dest, NUM_FIELDS(obj));
200 if(ms->enlarged) {
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));
208 return dest;
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) {
240 ptr_array refs;
241 int i;
242 OBJECT tup;
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));
256 return tup;
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;
275 OBJECT obj, tmp;
277 sz = object_memory_used(om);
278 start = (char*)om->gc->current->address;
279 end = start + sz;
280 cur = start;
282 num = 0;
284 while(cur < end) {
285 num++;
286 obj = (OBJECT)cur;
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));
299 assert(0);
304 cur += osz;
307 // printf("Checked %d objects.\n", num);
311 void object_memory_detect_cleanup(object_memory om) {
312 int sz, osz, num;
313 char *start, *end, *cur;
314 OBJECT obj;
316 sz = object_memory_used(om);
317 start = (char*)om->gc->current->address;
318 end = start + sz;
319 cur = start;
321 num = 0;
323 while(cur < end) {
324 num++;
325 obj = (OBJECT)cur;
326 osz = SIZE_IN_BYTES(cur);
328 if(!baker_gc_forwarded_p(obj)) {
329 printf("Found a %s that is garbage\n", _inspect(obj));
332 cur += osz;
337 void state_each_object(STATE, OBJECT kls, void (*cb)(STATE, OBJECT)) {
338 int sz, osz, num;
339 char *start, *end, *cur;
340 OBJECT obj;
341 object_memory om;
343 om = state->om;
345 sz = object_memory_used(om);
346 start = (char*)om->gc->current->address;
347 end = start + sz;
348 cur = start;
350 num = 0;
352 while(cur < end) {
353 num++;
354 obj = (OBJECT)cur;
355 osz = SIZE_IN_BYTES(obj);
357 (*cb)(state, obj);
359 cur += osz;
362 // printf("Checked %d objects.\n", num);
365 void object_memory_emit_details(STATE, object_memory om, FILE *stream) {
366 int sz, osz;
367 char *start, *end, *cur;
368 const char *kind;
369 OBJECT obj, kls;
371 sz = object_memory_used(om);
372 start = (char*)om->gc->current->address;
373 end = start + sz;
375 cur = start;
376 while(cur < end) {
377 obj = (OBJECT)cur;
378 osz = SIZE_IN_BYTES(obj);
379 if(NUM_FIELDS(obj) == 0) {
380 fprintf(stream, "%p %d free\n", obj, (int)(end - cur));
382 kls = obj->klass;
383 if(kls == state->global->cmethod) {
384 kind = "cmethod";
385 } else if(kls == state->global->bytearray) {
386 kind = "bytearray";
387 } else if(kls == state->global->string) {
388 kind = "string";
389 } else if(kls == state->global->tuple) {
390 kind = "tuple";
391 } else if(kls == state->global->methctx || kls == state->global->blokctx) {
392 kind = "context";
393 } else if(kls == state->global->class || kls == state->global->metaclass) {
394 kind = "class";
395 } else {
396 kind = "unknown";
399 fprintf(stream, "%p %d %s\n", obj, osz, kind);
400 cur += osz;
402 fclose(stream);
405 OBJECT object_memory_new_object_mature(object_memory om, OBJECT cls, unsigned int fields) {
406 int i;
407 OBJECT obj;
408 mark_sweep_gc ms;
410 ms = om->ms;
412 obj = mark_sweep_allocate(ms, fields);
413 if(ms->enlarged) {
414 om->collect_now |= OMCollectMature;
417 CLEAR_FLAGS(obj);
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);
431 return obj;
434 OBJECT object_memory_new_object_normal(object_memory om, OBJECT cls, unsigned int fields) {
435 int size, i;
436 OBJECT obj;
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);
446 } else {
447 obj = (OBJECT)baker_gc_allocate(om->gc, size);
450 CLEAR_FLAGS(obj);
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);
463 return obj;
466 OBJECT object_memory_new_opaque(STATE, OBJECT cls, unsigned int sz) {
467 unsigned int fel;
468 OBJECT obj;
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);
473 return obj;