5 #include "shotgun/lib/shotgun.h"
6 #include "shotgun/lib/cpu.h"
7 #include "shotgun/lib/cleanup_hash.h"
8 #include "shotgun/lib/config_hash.h"
9 #include "shotgun/lib/machine.h"
12 #include <mach/mach_time.h>
15 static size_t _gc_current_limit
= 0;
16 #define GC_EXTERNAL_LIMIT 10000000
18 static void inc_mem(size_t n
) {
19 _gc_current_limit
+= n
;
21 if(_gc_current_limit
> GC_EXTERNAL_LIMIT
) {
22 _gc_current_limit
= 0;
23 current_machine
->s
->om
->collect_now
= OMCollectYoung
;
27 void *XMALLOC(size_t n
) {
32 void *XREALLOC(void *p
, size_t n
) {
37 void *XCALLOC(size_t n
, size_t s
) {
46 rstate
rubinius_state_new() {
48 st
= (rstate
)calloc(1, sizeof(struct rubinius_state
));
49 st
->om
= object_memory_new();
50 st
->global
= (struct rubinius_globals
*)calloc(1, sizeof(struct rubinius_globals
));
51 st
->cleanup
= ht_cleanup_create(11);
52 st
->config
= ht_config_create(11);
54 st
->system_start
= mach_absolute_time();
60 void state_destroy(STATE
) {
61 object_memory_destroy(state
->om
);
64 ht_cleanup_destroy(state
->cleanup
);
65 ht_config_destroy(state
->config
);
70 static ptr_array
_gather_roots(STATE
, cpu c
) {
72 roots
= ptr_array_new(NUM_OF_GLOBALS
+ 100);
74 memcpy(roots
->array
, state
->global
, sizeof(struct rubinius_globals
));
75 roots
->length
= NUM_OF_GLOBALS
;
77 cpu_add_roots(state
, c
, roots
);
78 /* truncate the free_context list since we don't care about them
79 after we've collected anyway */
83 void cpu_sampler_suspend(STATE
);
84 void cpu_sampler_resume(STATE
);
85 void cpu_hard_cache(STATE
, cpu c
);
87 void state_collect(STATE
, cpu c
) {
89 int stats
= state
->gc_stats
;
90 struct timeval start
, fin
;
94 cpu_task_flush(state
, c
);
97 gettimeofday(&start
, NULL
);
103 state
->current_stack
= c
->stack_top
;
104 state
->current_sp
= c
->sp_ptr
;
106 /* HACK: external_ivars needs to be moved out of being a generic
107 global and being a special case one so that it's references
108 can't keep objects alive. */
110 cpu_sampler_suspend(state
);
111 object_memory_formalize_contexts(state
, state
->om
);
112 roots
= _gather_roots(state
, c
);
113 object_memory_collect(state
, state
->om
, roots
);
114 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
115 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
117 object_memory_reset_contexts(state
, state
->om
);
119 ptr_array_free(roots
);
121 baker_gc_find_lost_souls(state
, state
->om
->gc
);
122 cpu_sampler_resume(state
);
126 gettimeofday(&fin
, NULL
);
127 elapse
= (fin
.tv_sec
- start
.tv_sec
);
128 elapse
+= (((double)fin
.tv_usec
- start
.tv_usec
) / 1000000);
129 printf("[GC Y %f secs, %ldK total, %3dK used, %4d tenured, %d]\n",
131 (long int)(state
->om
->gc
->current
->size
/ 1024),
132 (unsigned int)(((uintptr_t)state
->om
->gc
->current
->current
- (uintptr_t)state
->om
->gc
->current
->address
) / 1024),
133 state
->om
->last_tenured
,
134 state
->om
->gc
->num_collection
138 cpu_task_flush(state
, c
);
139 cpu_hard_cache(state
, c
);
146 void state_major_collect(STATE
, cpu c
) {
148 int stats
= state
->gc_stats
;
149 struct timeval start
, fin
;
152 cpu_task_flush(state
, c
);
154 state_collect(state
, c
);
157 gettimeofday(&start
, NULL
);
163 /* HACK: external_ivars needs to be moved out of being a generic
164 global and being a special case one so that it's references
165 can't keep objects alive. */
167 state
->current_stack
= c
->stack_top
;
168 state
->current_sp
= c
->sp_ptr
;
170 cpu_sampler_suspend(state
);
171 roots
= _gather_roots(state
, c
);
172 object_memory_major_collect(state
, state
->om
, roots
);
173 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
174 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
176 ptr_array_free(roots
);
177 cpu_sampler_suspend(state
);
181 gettimeofday(&fin
, NULL
);
182 elapse
= (fin
.tv_sec
- start
.tv_sec
);
183 elapse
+= (((double)fin
.tv_usec
- start
.tv_usec
) / 1000000);
185 printf("[GC M %f secs, %d freed, %d total, %d segments, %6dK total]\n",
187 state
->om
->ms
->last_freed
, state
->om
->ms
->last_marked
,
188 state
->om
->ms
->num_chunks
,
189 state
->om
->ms
->allocated_bytes
/ 1024
193 cpu_task_flush(state
, c
);
194 cpu_hard_cache(state
, c
);
199 void state_object_become(STATE
, cpu c
, OBJECT from
, OBJECT to
) {
202 state
->current_stack
= c
->stack_top
;
203 state
->current_sp
= c
->sp_ptr
;
205 roots
= _gather_roots(state
, c
);
207 object_memory_setup_become(state
, state
->om
, from
, to
);
209 /* If from is young, then all the refs are from other young objects
210 or the remember set, so we just need to mutate in the young space. */
211 if(from
->gc_zone
== YoungObjectZone
) {
212 object_memory_collect(state
, state
->om
, roots
);
214 object_memory_major_collect(state
, state
->om
, roots
);
217 object_memory_clear_become(state
, state
->om
);
219 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
220 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
222 ptr_array_free(roots
);
226 void state_add_cleanup(STATE
, OBJECT cls
, state_cleanup_func func
) {
227 int type
= N2I(class_get_object_type(cls
));
229 state
->type_info
[type
].cleanup
= func
;
230 // printf("Registered cleanup for %p\n", module_get_name(cls));
231 class_set_needs_cleanup(cls
, Qtrue
);
234 void state_run_cleanup(STATE
, OBJECT obj
) {
235 state_cleanup_func func
;
237 func
= state
->type_info
[obj
->obj_type
].cleanup
;
239 if(func
) func(state
, obj
);
242 void state_setup_type(STATE
, int type
, struct type_info
*info
) {
243 state
->type_info
[type
] = *info
;