117
117
* 1. Maximum number is 8 due limit number of bits in PMC.flags.
118
118
* 2. Don't forget to update gc_gms_select_generation_to_collect after changing it!
120
#define MAX_GENERATIONS 8
120
#define MAX_GENERATIONS 4
122
122
/* We allocate additional space in front of PObj* to store additional pointer */
123
123
typedef struct pmc_alloc_struct {
212
212
PARROT_CAN_RETURN_NULL
213
static Buffer* gc_gms_allocate_buffer_header(PARROT_INTERP,
213
static Buffer* gc_gms_allocate_buffer_header(PARROT_INTERP, size_t size)
215
214
__attribute__nonnull__(1);
217
216
static void gc_gms_allocate_buffer_storage(PARROT_INTERP,
228
227
PARROT_CAN_RETURN_NULL
229
static void * gc_gms_allocate_memory_chunk(SHIM_INTERP, size_t size);
228
static void * gc_gms_allocate_memory_chunk(PARROT_INTERP, size_t size);
232
231
PARROT_CAN_RETURN_NULL
233
static void * gc_gms_allocate_memory_chunk_zeroed(SHIM_INTERP, size_t size);
232
static void * gc_gms_allocate_memory_chunk_zeroed(PARROT_INTERP,
236
236
PARROT_CAN_RETURN_NULL
248
248
PARROT_CAN_RETURN_NULL
249
static STRING* gc_gms_allocate_string_header(PARROT_INTERP,
249
static STRING* gc_gms_allocate_string_header(PARROT_INTERP, UINTVAL flags)
251
250
__attribute__nonnull__(1);
253
252
static void gc_gms_allocate_string_storage(PARROT_INTERP,
300
299
__attribute__nonnull__(3)
301
300
FUNC_MODIFIES(*data);
303
static void gc_gms_free_memory_chunk(SHIM_INTERP, ARGFREE(void *data));
302
static void gc_gms_free_memory_chunk(PARROT_INTERP, ARGFREE(void *data));
304
303
static void gc_gms_free_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
305
304
__attribute__nonnull__(1)
306
305
__attribute__nonnull__(2)
361
360
__attribute__nonnull__(2)
362
361
FUNC_MODIFIES(*str);
364
static void gc_gms_maybe_mark_and_sweep(PARROT_INTERP)
365
__attribute__nonnull__(1);
367
363
static void gc_gms_pmc_get_youngest_generation(PARROT_INTERP,
369
365
__attribute__nonnull__(1)
403
399
PARROT_CAN_RETURN_NULL
404
static void * gc_gms_reallocate_memory_chunk(SHIM_INTERP,
400
static void * gc_gms_reallocate_memory_chunk(PARROT_INTERP,
405
401
ARGFREE(void *from),
409
405
PARROT_CAN_RETURN_NULL
410
static void * gc_gms_reallocate_memory_chunk_zeroed(SHIM_INTERP,
406
static void * gc_gms_reallocate_memory_chunk_zeroed(PARROT_INTERP,
411
407
ARGFREE(void *data),
425
421
static size_t gc_gms_select_generation_to_collect(PARROT_INTERP)
426
422
__attribute__nonnull__(1);
428
static void gc_gms_soil_pmc(PARROT_INTERP, ARGIN(PMC *pmc))
429
__attribute__nonnull__(1)
430
__attribute__nonnull__(2);
432
static void gc_gms_soil_roots(PARROT_INTERP, ARGIN(MarkSweep_GC *self))
433
__attribute__nonnull__(1)
434
__attribute__nonnull__(2);
436
424
static void gc_gms_str_get_youngest_generation(PARROT_INTERP,
437
425
ARGIN(STRING *str))
438
426
__attribute__nonnull__(1)
439
427
__attribute__nonnull__(2);
441
static void gc_gms_sweep_pmc_cb(PARROT_INTERP, ARGIN(PObj *obj))
442
__attribute__nonnull__(1)
443
__attribute__nonnull__(2);
445
429
static void gc_gms_sweep_pools(PARROT_INTERP, ARGMOD(MarkSweep_GC *self))
446
430
__attribute__nonnull__(1)
447
431
__attribute__nonnull__(2)
448
432
FUNC_MODIFIES(*self);
450
static void gc_gms_sweep_string_cb(PARROT_INTERP, ARGIN(PObj *obj))
451
__attribute__nonnull__(1)
452
__attribute__nonnull__(2);
454
434
static void gc_gms_unblock_GC_mark(PARROT_INTERP)
455
435
__attribute__nonnull__(1);
468
448
__attribute__nonnull__(1)
469
449
__attribute__nonnull__(2);
471
static void gc_gms_validate_str(SHIM_INTERP, ARGIN(STRING *str))
451
static void gc_gms_validate_str(PARROT_INTERP, ARGIN(STRING *str))
472
452
__attribute__nonnull__(2);
474
454
static void gc_gms_write_barrier(PARROT_INTERP, ARGMOD(PMC *pmc))
565
545
#define ASSERT_ARGS_gc_gms_mark_str_header __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
566
546
PARROT_ASSERT_ARG(interp) \
567
547
, PARROT_ASSERT_ARG(str))
568
#define ASSERT_ARGS_gc_gms_maybe_mark_and_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
569
PARROT_ASSERT_ARG(interp))
570
548
#define ASSERT_ARGS_gc_gms_pmc_get_youngest_generation \
571
549
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
572
550
PARROT_ASSERT_ARG(interp) \
604
582
#define ASSERT_ARGS_gc_gms_select_generation_to_collect \
605
583
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
606
584
PARROT_ASSERT_ARG(interp))
607
#define ASSERT_ARGS_gc_gms_soil_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
608
PARROT_ASSERT_ARG(interp) \
609
, PARROT_ASSERT_ARG(pmc))
610
#define ASSERT_ARGS_gc_gms_soil_roots __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
611
PARROT_ASSERT_ARG(interp) \
612
, PARROT_ASSERT_ARG(self))
613
585
#define ASSERT_ARGS_gc_gms_str_get_youngest_generation \
614
586
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
615
587
PARROT_ASSERT_ARG(interp) \
616
588
, PARROT_ASSERT_ARG(str))
617
#define ASSERT_ARGS_gc_gms_sweep_pmc_cb __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
618
PARROT_ASSERT_ARG(interp) \
619
, PARROT_ASSERT_ARG(obj))
620
589
#define ASSERT_ARGS_gc_gms_sweep_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
621
590
PARROT_ASSERT_ARG(interp) \
622
591
, PARROT_ASSERT_ARG(self))
623
#define ASSERT_ARGS_gc_gms_sweep_string_cb __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
624
PARROT_ASSERT_ARG(interp) \
625
, PARROT_ASSERT_ARG(obj))
626
592
#define ASSERT_ARGS_gc_gms_unblock_GC_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
627
593
PARROT_ASSERT_ARG(interp))
628
594
#define ASSERT_ARGS_gc_gms_unblock_GC_sweep __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
681
647
ASSERT_ARGS(Parrot_gc_gms_init)
682
648
struct MarkSweep_GC *self;
649
const Parrot_Float4 nursery_size = (args->nursery_size > 0)
651
: GC_DEFAULT_NURSERY_SIZE;
684
653
/* We have to transfer ownership of memory to parent interp in threaded parrot */
685
654
interp->gc_sys->finalize_gc_system = NULL; /* gc_gms_finalize; */
772
741
self->fixed_size_allocator = Parrot_gc_fixed_allocator_new(interp);
775
* Collect every 1/100 of avaliable memory.
744
* Collect every nursery_size/100 of system memory.
777
* Will be configured/dynamically adjusted in future. For now it gives
778
* good performance overrall.
746
* Configured by runtime parameter (default 2%).
780
self->gc_threshold = Parrot_sysmem_amount(interp) / 100;
748
self->gc_threshold = Parrot_sysmem_amount(interp) * nursery_size / 100;
782
750
Parrot_gc_str_initialize(interp, &self->string_gc);
818
784
gc_gms_check_sanity(interp);
820
2. Choose K - how many collections we want to collect. Collections [0..K] will
821
be collected. Remember K in C<self->gen_to_collect>.
786
2. Choose K - how many collections we want to collect. Collections [0..K]
787
will be collected. Remember K in C<self->gen_to_collect>.
823
789
self->gen_to_collect = gen = gc_gms_select_generation_to_collect(interp);
838
804
gc_gms_mark_pmc_header(interp, PMCNULL);
839
805
Parrot_gc_trace_root(interp, NULL, GC_TRACE_FULL);
840
if (interp->pdb && interp->pdb->debugger) {
807
if (interp->pdb && interp->pdb->debugger)
841
808
Parrot_gc_trace_root(interp->pdb->debugger, NULL, GC_TRACE_FULL);
843
810
gc_gms_print_stats(interp, "After trace_roots");
844
811
gc_gms_check_sanity(interp);
859
826
gc_gms_check_sanity(interp);
862
* Before sweeping pools move all _root_ objects from Gen0 into dirty_list.
864
* Main reason for it:
865
* PMC *res = Parrot_pmc_new(interp);
866
* <do something to fill a lot of guts. E.g. Hash.clone>
869
* C<Hash.clone> can trigger GC. C<res> _will_ not be sealed by any automatic
870
* methods (e.g. pmc2c vtable overrides).
872
* We will soil objects only from C stack.
874
gc_gms_soil_roots(interp, self);
877
829
7. Sweep generations starting from K:
878
830
- Destroy all dead objects
879
831
- Move live objects into generation max(K+1, N)
882
834
gc_gms_sweep_pools(interp, self);
883
835
gc_gms_check_sanity(interp);
886
837
/* Update some stats */
887
838
interp->gc_sys->stats.header_allocs_since_last_collect = 0;
888
839
interp->gc_sys->stats.mem_used_last_collect = 0;
991
if ((gen <= self->gen_to_collect) && (gen < MAX_GENERATIONS - 1)) {
944
/* This check used to be
945
* if ((gen <= self->gen_to_collect) && (gen < MAX_GENERATIONS - 1))
946
* Unfortunatelly it's wrong.
948
* A1* -> B1* -> C0. (Object in generation notation. Star denotes "dirt
949
* During gen0 collecting will "sink" A object, but not B. This picture
951
* After collecting gen1 we'll sink all of them:
953
* And after collecting of gen2 we'll collect B and C incorrectly.
954
* Because A(3) will be in older generation than B and C.
956
if (gen < MAX_GENERATIONS - 1) {
992
957
SET_GEN_FLAGS(pmc, gen + 1);
1071
=item C<static void gc_gms_soil_pmc(PARROT_INTERP, PMC *pmc)>
1073
Mark single nursery PMC as dirty. Part of Step 7.
1080
gc_gms_soil_pmc(PARROT_INTERP, ARGIN(PMC *pmc))
1082
ASSERT_ARGS(gc_gms_soil_pmc)
1083
MarkSweep_GC *self = (MarkSweep_GC *)interp->gc_sys->gc_private;
1084
pmc_alloc_struct *item = PMC2PAC(pmc);
1085
size_t gen = POBJ2GEN(pmc);
1087
/* If object is dirty already */
1088
if (PObj_GC_on_dirty_list_TEST(pmc))
1091
/* Older objects are covered by other steps */
1095
Parrot_pa_remove(interp, self->objects[0], item->ptr);
1096
item->ptr = Parrot_pa_insert(interp, self->dirty_list, item);
1098
/* Move to next generation */
1099
SET_GEN_FLAGS(pmc, 1);
1100
PObj_GC_on_dirty_list_SET(pmc);
1101
PObj_live_CLEAR(pmc);
1106
=item C<static void gc_gms_soil_roots(PARROT_INTERP, MarkSweep_GC *self)>
1108
Mark all nursery PMCs on C-stack as durty. Part of Step 7.
1113
gc_gms_soil_roots(PARROT_INTERP, ARGIN(MarkSweep_GC *self))
1115
ASSERT_ARGS(gc_gms_soil_roots)
1116
interp->gc_sys->mark_pmc_header = gc_gms_soil_pmc;
1117
Parrot_gc_trace_root(interp, NULL, GC_TRACE_SYSTEM_ONLY);
1118
interp->gc_sys->mark_pmc_header = gc_gms_mark_pmc_header;
1123
1036
=item C<static void gc_gms_sweep_pools(PARROT_INTERP, MarkSweep_GC *self)>
1125
1038
Sweep generations starting from K:
1145
1058
pmc_alloc_struct *item = (pmc_alloc_struct *)ptr;
1146
1059
PMC *pmc = &(item->pmc);
1148
PARROT_ASSERT(PObj_constant_TEST(pmc) || POBJ2GEN(pmc) == i);
1061
PARROT_ASSERT(PObj_constant_TEST(pmc) || (int)POBJ2GEN(pmc) == i);
1150
1063
/* Paint live objects white */
1151
1064
if (PObj_live_TEST(pmc) || PObj_constant_TEST(pmc)) {
1152
1065
PObj_live_CLEAR(pmc);
1154
1067
if (move_to_old) {
1068
SET_GEN_FLAGS(pmc, i + 1);
1155
1070
Parrot_pa_remove(interp, self->objects[i], item->ptr);
1156
item->ptr = Parrot_pa_insert(interp, self->objects[i + 1], item);
1157
SET_GEN_FLAGS(pmc, i + 1);
1158
gc_gms_seal_object(interp, pmc);
1071
/* If this was freshly allocated object in C stack - move it to dirty list */
1072
if (PObj_GC_soil_root_TEST(pmc)) {
1073
item->ptr = Parrot_pa_insert(interp, self->dirty_list, item);
1074
PObj_GC_soil_root_CLEAR(pmc);
1075
PObj_GC_on_dirty_list_SET(pmc);
1078
item->ptr = Parrot_pa_insert(interp, self->objects[i + 1], item);
1079
gc_gms_seal_object(interp, pmc);
1161
1083
else if (!PObj_constant_TEST(pmc)) {
1440
1362
Parrot_gc_str_finalize(interp, &self->string_gc);
1442
1364
for (i = 0; i < MAX_GENERATIONS; i++) {
1443
Parrot_pa_destroy(interp, self->objects[0]);
1444
Parrot_pa_destroy(interp, self->strings[0]);
1365
Parrot_pa_destroy(interp, self->objects[i]);
1366
Parrot_pa_destroy(interp, self->strings[i]);
1447
1369
Parrot_gc_pool_destroy(interp, self->pmc_allocator);
1449
1371
Parrot_gc_fixed_allocator_destroy(interp, self->fixed_size_allocator);
1376
=item C<gc_gms_maybe_mark_and_sweep(PARROT_INTERP)>
1378
Maybe M&S. Depends on total allocated memory, memory allocated since last alloc
1379
and phase of the Moon.
1385
#define gc_gms_maybe_mark_and_sweep(i) \
1387
MarkSweep_GC * const self = (MarkSweep_GC *)(i)->gc_sys->gc_private; \
1389
/* Collect every gc_threshold. */ \
1390
if (!self->gc_mark_block_level \
1391
&& (i)->gc_sys->stats.mem_used_last_collect > self->gc_threshold) \
1392
gc_gms_mark_and_sweep(interp, 0); \
1453
1396
PARROT_CAN_RETURN_NULL
1518
1461
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
1519
1462
PObj * const obj = (PObj *)ptr;
1520
1463
pmc_alloc_struct * const item = PMC2PAC(ptr);
1465
/* Not aligned pointers aren't pointers */
1466
if (!obj || !item || ((size_t)obj & 3) || ((size_t)item & 3))
1526
1469
if (!Parrot_gc_pool_is_owned(interp, self->pmc_allocator, item))
1533
1476
/* If object too old - skip it */
1534
if (POBJ2GEN(&item->pmc) > self->gen_to_collect)
1477
if (POBJ2GEN(obj) > self->gen_to_collect)
1537
1480
/* Object is on dirty_list. */
1538
if (PObj_GC_on_dirty_list_TEST(&item->pmc))
1481
if (PObj_GC_on_dirty_list_TEST(obj))
1541
for (i = 0; i < MAX_GENERATIONS; i++) {
1542
/* Pool.is_owned isn't precise enough (yet) */
1543
if (Parrot_pa_is_owned(interp, self->objects[i], item, item->ptr))
1484
/* Pool.is_owned isn't precise enough (yet) */
1485
if (Parrot_pa_is_owned(interp, self->objects[POBJ2GEN(obj)], item, item->ptr)) {
1486
if (POBJ2GEN(obj) == 0)
1487
PObj_GC_soil_root_SET(obj);
1552
=item C<static void gc_gms_sweep_pmc_cb(PARROT_INTERP, PObj *obj)>
1561
gc_gms_sweep_pmc_cb(PARROT_INTERP, ARGIN(PObj *obj))
1563
ASSERT_ARGS(gc_gms_sweep_pmc_cb)
1564
PMC *pmc = (PMC *)obj;
1565
Parrot_pmc_destroy(interp, pmc);
1570
1496
=item C<gc_gms_allocate_string_header(PARROT_INTERP, STRING *str)>
1572
1498
=item C<gc_gms_free_string_header(PARROT_INTERP, STRING *s)>
1590
1516
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
1591
1517
Pool_Allocator * const pool = self->string_allocator;
1592
1518
string_alloc_struct *item;
1595
1521
gc_gms_maybe_mark_and_sweep(interp);
1597
/* Increase used memory. Not precisely accurate due Pool_Allocator paging */
1523
/* Increase used memory.
1524
* Not precisely accurate due to Pool_Allocator paging. */
1598
1525
++interp->gc_sys->stats.header_allocs_since_last_collect;
1599
1526
interp->gc_sys->stats.memory_used += sizeof (STRING);
1600
1527
interp->gc_sys->stats.mem_used_last_collect += sizeof (STRING);
1665
1592
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
1666
1593
PObj * const obj = (PObj *)ptr;
1667
1594
string_alloc_struct * const item = STR2PAC(ptr);
1596
/* Not aligned pointers aren't pointers */
1597
if (!obj || !item || ((size_t)obj & 3) || ((size_t)item & 3))
1673
1600
if (!Parrot_gc_pool_is_owned(interp, self->string_allocator, item))
1681
1608
if (POBJ2GEN(&item->str) > self->gen_to_collect)
1684
/* Pool.is_owned isn't precise enough (yet) */
1685
for (i = 0; i < MAX_GENERATIONS; i++) {
1686
if (Parrot_pa_is_owned(interp, self->strings[i], item, item->ptr))
1611
if (Parrot_pa_is_owned(interp, self->strings[POBJ2GEN(obj)], item, item->ptr))
1753
=item C<static void gc_gms_sweep_string_cb(PARROT_INTERP, PObj *obj)>
1762
gc_gms_sweep_string_cb(PARROT_INTERP, ARGIN(PObj *obj))
1764
ASSERT_ARGS(gc_gms_sweep_string_cb)
1765
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
1766
Buffer * const str = (Buffer *)obj;
1767
/* Compact string pool here. Or get rid of "shared buffers" and just free storage */
1768
if (Buffer_bufstart(str) && !PObj_external_TEST(str))
1769
Parrot_gc_str_free_buffer_storage(interp, &self->string_gc, str);
1775
1678
=item C<static void gc_gms_iterate_live_strings(PARROT_INTERP,
1776
1679
string_iterator_callback callback, void *data)>
2014
=item C<static void gc_gms_maybe_mark_and_sweep(PARROT_INTERP)>
2016
Maybe M&S. Depends on total allocated memory, memory allocated since last alloc
2017
and phase of the Moon.
2023
gc_gms_maybe_mark_and_sweep(PARROT_INTERP)
2025
ASSERT_ARGS(gc_gms_maybe_mark_and_sweep)
2027
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
2029
/* Collect every gc_threshold. */
2030
if (interp->gc_sys->stats.mem_used_last_collect > self->gc_threshold) {
2031
gc_gms_mark_and_sweep(interp, 0);
2036
1916
=item C<static void gc_gms_write_barrier(PARROT_INTERP, PMC *pmc)>
2038
1918
WriteBarrier for PMC. Add to root_objects list for mandatory next collecting.