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
;
92 cpu_task_flush(state
, c
);
95 gettimeofday(&start
, NULL
);
101 state
->current_stack
= c
->stack_top
;
102 state
->current_sp
= c
->sp_ptr
;
104 /* HACK: external_ivars needs to be moved out of being a generic
105 global and being a special case one so that it's references
106 can't keep objects alive. */
108 cpu_sampler_suspend(state
);
109 object_memory_formalize_contexts(state
, state
->om
);
110 roots
= _gather_roots(state
, c
);
111 object_memory_collect(state
, state
->om
, roots
);
112 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
113 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
115 object_memory_reset_contexts(state
, state
->om
);
117 ptr_array_free(roots
);
119 baker_gc_find_lost_souls(state
, state
->om
->gc
);
120 cpu_sampler_resume(state
);
124 gettimeofday(&fin
, NULL
);
125 elapse
= (fin
.tv_sec
- start
.tv_sec
);
126 elapse
+= (((double)fin
.tv_usec
- start
.tv_usec
) / 1000000);
127 printf("[GC Y %f secs, %ldK total, %3dK used, %4d tenured, %d]\n",
129 (long int)(state
->om
->gc
->current
->size
/ 1024),
130 (unsigned int)(((uintptr_t)state
->om
->gc
->current
->current
- (uintptr_t)state
->om
->gc
->current
->address
) / 1024),
131 state
->om
->last_tenured
,
132 state
->om
->gc
->num_collection
136 cpu_task_flush(state
, c
);
137 cpu_hard_cache(state
, c
);
142 void state_major_collect(STATE
, cpu c
) {
144 int stats
= state
->gc_stats
;
145 struct timeval start
, fin
;
147 cpu_task_flush(state
, c
);
149 state_collect(state
, c
);
152 gettimeofday(&start
, NULL
);
158 /* HACK: external_ivars needs to be moved out of being a generic
159 global and being a special case one so that it's references
160 can't keep objects alive. */
162 state
->current_stack
= c
->stack_top
;
163 state
->current_sp
= c
->sp_ptr
;
165 cpu_sampler_suspend(state
);
166 roots
= _gather_roots(state
, c
);
167 object_memory_major_collect(state
, state
->om
, roots
);
168 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
169 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
171 ptr_array_free(roots
);
172 cpu_sampler_suspend(state
);
176 gettimeofday(&fin
, NULL
);
177 elapse
= (fin
.tv_sec
- start
.tv_sec
);
178 elapse
+= (((double)fin
.tv_usec
- start
.tv_usec
) / 1000000);
180 printf("[GC M %f secs, %d freed, %d total, %d segments, %6dK total]\n",
182 state
->om
->ms
->last_freed
, state
->om
->ms
->last_marked
,
183 state
->om
->ms
->num_chunks
,
184 state
->om
->ms
->allocated_bytes
/ 1024
188 cpu_task_flush(state
, c
);
189 cpu_hard_cache(state
, c
);
193 void state_object_become(STATE
, cpu c
, OBJECT from
, OBJECT to
) {
196 state
->current_stack
= c
->stack_top
;
197 state
->current_sp
= c
->sp_ptr
;
199 roots
= _gather_roots(state
, c
);
201 object_memory_setup_become(state
, state
->om
, from
, to
);
203 /* If from is young, then all the refs are from other young objects
204 or the remember set, so we just need to mutate in the young space. */
205 if(from
->gc_zone
== YoungObjectZone
) {
206 object_memory_collect(state
, state
->om
, roots
);
208 object_memory_major_collect(state
, state
->om
, roots
);
211 object_memory_clear_become(state
, state
->om
);
213 memcpy(state
->global
, roots
->array
, sizeof(struct rubinius_globals
));
214 cpu_update_roots(state
, c
, roots
, NUM_OF_GLOBALS
);
216 ptr_array_free(roots
);
220 void state_add_cleanup(STATE
, OBJECT cls
, state_cleanup_func func
) {
221 int type
= N2I(class_get_object_type(cls
));
223 state
->type_info
[type
].cleanup
= func
;
224 // printf("Registered cleanup for %p\n", module_get_name(cls));
225 class_set_needs_cleanup(cls
, Qtrue
);
228 void state_run_cleanup(STATE
, OBJECT obj
) {
229 state_cleanup_func func
;
231 func
= state
->type_info
[obj
->obj_type
].cleanup
;
233 if(func
) func(state
, obj
);
236 void state_setup_type(STATE
, int type
, struct type_info
*info
) {
237 state
->type_info
[type
] = *info
;