Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base: master
...
compare: gc_tuning
Checking mergeability… Don't worry, you can still create the pull request.
  • 17 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
View
79 include/parrot/pointer_array.h
@@ -41,6 +41,9 @@ typedef struct Parrot_Pointer_Array {
Parrot_Pointer_Array_Chunk **chunks;
} Parrot_Pointer_Array;
+/* Forward declaration of iterators */
+typedef struct Parrot_Pointer_Array_Iterator Parrot_Pointer_Array_Iterator;
+
/* Poor man C++ templating... */
#define POINTER_ARRAY_ITER(_array, _code) \
do { \
@@ -173,10 +176,24 @@ Parrot_pa_remove(PARROT_INTERP, ARGIN(Parrot_Pointer_Array *self), ARGIN(void *p
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+Parrot_Pointer_Array_Iterator* Parrot_pa_begin(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array *self))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
void Parrot_pa_destroy(PARROT_INTERP, ARGFREE(Parrot_Pointer_Array *self))
__attribute__nonnull__(1);
PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+Parrot_Pointer_Array_Iterator* Parrot_pa_end(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array *self))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
int Parrot_pa_is_owned(PARROT_INTERP,
ARGIN(Parrot_Pointer_Array *self),
ARGIN(void *orig),
@@ -186,6 +203,44 @@ int Parrot_pa_is_owned(PARROT_INTERP,
__attribute__nonnull__(3);
PARROT_EXPORT
+INTVAL Parrot_pa_iter_cmp(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *lhs),
+ ARGIN(Parrot_Pointer_Array_Iterator *rhs))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3);
+
+PARROT_EXPORT
+void Parrot_pa_iter_destroy(PARROT_INTERP,
+ ARGFREE(Parrot_Pointer_Array_Iterator *iter))
+ __attribute__nonnull__(1);
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+void ** Parrot_pa_iter_get(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *iter))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
+INTVAL Parrot_pa_iter_is_empty(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *iter))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
+void Parrot_pa_iter_next(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *iter))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
+void Parrot_pa_iter_prev(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *iter))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+PARROT_EXPORT
PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Parrot_Pointer_Array * Parrot_pa_new(PARROT_INTERP)
@@ -204,12 +259,36 @@ size_t Parrot_pa_count_used(PARROT_INTERP,
__attribute__nonnull__(1)
__attribute__nonnull__(2);
+#define ASSERT_ARGS_Parrot_pa_begin __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(self))
#define ASSERT_ARGS_Parrot_pa_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_pa_end __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(self))
#define ASSERT_ARGS_Parrot_pa_is_owned __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(self) \
, PARROT_ASSERT_ARG(orig))
+#define ASSERT_ARGS_Parrot_pa_iter_cmp __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(lhs) \
+ , PARROT_ASSERT_ARG(rhs))
+#define ASSERT_ARGS_Parrot_pa_iter_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_pa_iter_get __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(iter))
+#define ASSERT_ARGS_Parrot_pa_iter_is_empty __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(iter))
+#define ASSERT_ARGS_Parrot_pa_iter_next __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(iter))
+#define ASSERT_ARGS_Parrot_pa_iter_prev __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(iter))
#define ASSERT_ARGS_Parrot_pa_new __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_pa_count_allocated __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
View
332 src/gc/gc_gms.c
@@ -119,21 +119,6 @@ TBD
*/
#define MAX_GENERATIONS 4
-/* We allocate additional space in front of PObj* to store additional pointer */
-typedef struct pmc_alloc_struct {
- void *ptr;
- PMC pmc; /* NB: Value! */
-} pmc_alloc_struct;
-
-typedef struct string_alloc_struct {
- void *ptr;
- STRING str; /* NB: Value! */
-} string_alloc_struct;
-
-#define PMC2PAC(p) ((pmc_alloc_struct *)((char*)(p) - sizeof (void *)))
-#define STR2PAC(p) ((string_alloc_struct *)((char*)(p) - sizeof (void *)))
-
-
/* Get generation from PObj->flags */
#define POBJ2GEN(pobj) \
((size_t)(((pobj)->flags & PObj_GC_generation_0_FLAG) ? 1 : 0) \
@@ -730,10 +715,10 @@ Parrot_gc_gms_init(PARROT_INTERP, ARGIN(Parrot_GC_Init_Args *args))
self = mem_allocate_zeroed_typed(MarkSweep_GC);
self->pmc_allocator = Parrot_gc_pool_new(interp,
- sizeof (pmc_alloc_struct));
+ sizeof (PMC));
self->string_allocator = Parrot_gc_pool_new(interp,
- sizeof (string_alloc_struct));
+ sizeof (STRING));
/* Allocate list for gray objects */
self->work_list = NULL;
@@ -922,13 +907,15 @@ gc_gms_cleanup_dirty_list(PARROT_INTERP,
{
ASSERT_ARGS(gc_gms_cleanup_dirty_list)
+ /* Construct new dirty_list from "survival" objects */
+ Parrot_Pointer_Array *new_dirty_list = Parrot_pa_new(interp);
+
/* Override with special version of mark */
interp->gc_sys->mark_pmc_header = gc_gms_pmc_get_youngest_generation;
interp->gc_sys->mark_str_header = gc_gms_str_get_youngest_generation;
POINTER_ARRAY_ITER(dirty_list,
- pmc_alloc_struct *item = (pmc_alloc_struct *)ptr;
- PMC *pmc = &(item->pmc);
+ PMC *pmc = (PMC*)ptr;
size_t gen = POBJ2GEN(pmc);
self->youngest_child = gen;
@@ -943,8 +930,6 @@ gc_gms_cleanup_dirty_list(PARROT_INTERP,
if (self->youngest_child >= gen) {
PObj_live_CLEAR(pmc);
PObj_GC_on_dirty_list_CLEAR(pmc);
- Parrot_pa_remove(interp, dirty_list, item->ptr);
- item->ptr = Parrot_pa_insert(interp, self->objects[gen], item);
gc_gms_seal_object(interp, pmc);
}
else {
@@ -964,8 +949,12 @@ gc_gms_cleanup_dirty_list(PARROT_INTERP,
if (gen < MAX_GENERATIONS - 1) {
SET_GEN_FLAGS(pmc, gen + 1);
}
+ Parrot_pa_insert(interp, new_dirty_list, pmc);
};);
+ Parrot_pa_destroy(interp, self->dirty_list);
+ self->dirty_list = new_dirty_list;
+
interp->gc_sys->mark_pmc_header = gc_gms_mark_pmc_header;
interp->gc_sys->mark_str_header = gc_gms_mark_str_header;
}
@@ -989,7 +978,7 @@ gc_gms_process_dirty_list(PARROT_INTERP,
ASSERT_ARGS(gc_gms_process_dirty_list)
POINTER_ARRAY_ITER(dirty_list,
- PMC *pmc = &((pmc_alloc_struct *)ptr)->pmc;
+ PMC *pmc = (PMC *)ptr;
if (PObj_custom_mark_TEST(pmc))
VTABLE_mark(interp, pmc);
@@ -1016,7 +1005,7 @@ gc_gms_process_work_list(PARROT_INTERP,
ASSERT_ARGS(gc_gms_process_work_list)
POINTER_ARRAY_ITER(work_list,
- PMC *pmc = &((pmc_alloc_struct *)ptr)->pmc;
+ PMC *pmc = (PMC *)ptr;
if (PObj_custom_mark_TEST(pmc))
VTABLE_mark(interp, pmc);
@@ -1025,18 +1014,6 @@ gc_gms_process_work_list(PARROT_INTERP,
Parrot_gc_mark_PMC_alive(interp, PMC_metadata(pmc)););
gc_gms_print_stats(interp, "Before cleaning work_list");
-
- /* Move processed objects back to own generation */
- POINTER_ARRAY_ITER(work_list,
- pmc_alloc_struct *item = (pmc_alloc_struct *)ptr;
- PMC *pmc = &(item->pmc);
- size_t gen = POBJ2GEN(pmc);
-
- PARROT_ASSERT(!PObj_GC_on_dirty_list_TEST(pmc));
-
- Parrot_pa_remove(interp, work_list, item->ptr);
- item->ptr = Parrot_pa_insert(interp, self->objects[gen], item););
-
}
/*
@@ -1051,89 +1028,145 @@ Sweep generations starting from K:
=cut
*/
+
static void
-gc_gms_sweep_pools(PARROT_INTERP, ARGMOD(MarkSweep_GC *self))
+gc_gms_sweep_pmc(PARROT_INTERP,
+ MarkSweep_GC *self,
+ INTVAL i,
+ void *ptr,
+ int move_to_old,
+ Parrot_Pointer_Array *oldest)
{
- ASSERT_ARGS(gc_gms_sweep_pools)
+ PMC *pmc = (PMC *)ptr;
- INTVAL i;
+ /* It can be stale object which was pulled to dirty_list. Skip it */
+ if (POBJ2GEN(pmc) != i) {
+ return;
+ }
- for (i = self->gen_to_collect; i >= 0; i--) {
- /* Don't move to generation beyond last */
- int move_to_old = (i + 1) != MAX_GENERATIONS;
+ /* Paint live objects white */
+ if (PObj_live_TEST(pmc) || PObj_constant_TEST(pmc)) {
+ PObj_live_CLEAR(pmc);
- POINTER_ARRAY_ITER(self->objects[i],
- pmc_alloc_struct *item = (pmc_alloc_struct *)ptr;
- PMC *pmc = &(item->pmc);
-
- PARROT_ASSERT(PObj_constant_TEST(pmc) || POBJ2GEN(pmc) == i);
-
- /* Paint live objects white */
- if (PObj_live_TEST(pmc) || PObj_constant_TEST(pmc)) {
- PObj_live_CLEAR(pmc);
-
- if (move_to_old) {
- SET_GEN_FLAGS(pmc, i + 1);
-
- Parrot_pa_remove(interp, self->objects[i], item->ptr);
- /* If this was freshly allocated object in C stack - move it to dirty list */
- if (PObj_GC_soil_root_TEST(pmc)) {
- item->ptr = Parrot_pa_insert(interp, self->dirty_list, item);
- PObj_GC_soil_root_CLEAR(pmc);
- PObj_GC_on_dirty_list_SET(pmc);
- }
- else {
- item->ptr = Parrot_pa_insert(interp, self->objects[i + 1], item);
- gc_gms_seal_object(interp, pmc);
- }
- }
+ if (move_to_old) {
+ SET_GEN_FLAGS(pmc, i + 1);
+
+ Parrot_pa_insert(interp, self->objects[i + 1], pmc);
+
+ /* If this was freshly allocated object in C stack - move it to dirty list */
+ if (PObj_GC_soil_root_TEST(pmc)) {
+ Parrot_pa_insert(interp, self->dirty_list, pmc);
+ PObj_GC_soil_root_CLEAR(pmc);
+ PObj_GC_on_dirty_list_SET(pmc);
+ }
+ else {
+ gc_gms_seal_object(interp, pmc);
}
- else if (!PObj_constant_TEST(pmc)) {
- Parrot_pa_remove(interp, self->objects[i], item->ptr);
+ }
+ else {
+ Parrot_pa_insert(interp, oldest, pmc);
+ }
+ }
+ else if (!PObj_constant_TEST(pmc)) {
+ interp->gc_sys->stats.memory_used -= sizeof (PMC);
- interp->gc_sys->stats.memory_used -= sizeof (PMC);
+ /* this is manual inlining of Parrot_pmc_destroy() */
+ if (PObj_custom_destroy_TEST(pmc))
+ VTABLE_destroy(interp, pmc);
- /* this is manual inlining of Parrot_pmc_destroy() */
- if (PObj_custom_destroy_TEST(pmc))
- VTABLE_destroy(interp, pmc);
+ if (pmc->vtable->attr_size && PMC_data(pmc))
+ Parrot_gc_free_pmc_attributes(interp, pmc);
+ PMC_data(pmc) = NULL;
- if (pmc->vtable->attr_size && PMC_data(pmc))
- Parrot_gc_free_pmc_attributes(interp, pmc);
- PMC_data(pmc) = NULL;
+ PObj_on_free_list_SET(pmc);
+ PObj_gc_CLEAR(pmc);
- PObj_on_free_list_SET(pmc);
- PObj_gc_CLEAR(pmc);
+ Parrot_gc_pool_free(interp, self->pmc_allocator, ptr);
+ };
+}
- Parrot_gc_pool_free(interp, self->pmc_allocator, ptr);
- });
+static void
+gc_gms_sweep_string(PARROT_INTERP,
+ MarkSweep_GC *self,
+ INTVAL i,
+ void *ptr,
+ int move_to_old,
+ Parrot_Pointer_Array *oldest)
+{
+ STRING *str = (STRING *)ptr;
- POINTER_ARRAY_ITER(self->strings[i],
- string_alloc_struct *item = (string_alloc_struct *)ptr;
- STRING *str = &(item->str);
-
- PARROT_ASSERT(!PObj_on_free_list_TEST(str));
-
- /* Paint live objects white */
- if (PObj_live_TEST(str) || PObj_constant_TEST(str)) {
- PObj_live_CLEAR(str);
- if (move_to_old) {
- Parrot_pa_remove(interp, self->strings[i], item->ptr);
- item->ptr = Parrot_pa_insert(interp, self->strings[i + 1], item);
- SET_GEN_FLAGS(str, i + 1);
- }
- }
+ PARROT_ASSERT(!PObj_on_free_list_TEST(str));
+
+ /* Paint live objects white */
+ if (PObj_live_TEST(str) || PObj_constant_TEST(str)) {
+ PObj_live_CLEAR(str);
+ if (move_to_old) {
+ Parrot_pa_insert(interp, self->strings[i + 1], str);
+ SET_GEN_FLAGS(str, i + 1);
+ }
+ else {
+ Parrot_pa_insert(interp, oldest, str);
+ }
+ }
+
+ else if (!PObj_constant_TEST(str)) {
+ if (Buffer_bufstart(str) && !PObj_external_TEST(str))
+ Parrot_gc_str_free_buffer_storage(interp, &self->string_gc, (Buffer*)str);
- else if (!PObj_constant_TEST(str)) {
- Parrot_pa_remove(interp, self->strings[i], item->ptr);
- if (Buffer_bufstart(str) && !PObj_external_TEST(str))
- Parrot_gc_str_free_buffer_storage(interp, &self->string_gc, (Buffer*)str);
+ interp->gc_sys->stats.memory_used -= sizeof (STRING);
- interp->gc_sys->stats.memory_used -= sizeof (STRING);
+ PObj_on_free_list_SET(str);
+
+ Parrot_gc_pool_free(interp, self->string_allocator, ptr);
+ }
+}
- PObj_on_free_list_SET(str);
+static void
+gc_gms_sweep_pools(PARROT_INTERP, ARGMOD(MarkSweep_GC *self))
+{
+ ASSERT_ARGS(gc_gms_sweep_pools)
+
+ INTVAL i;
+
+ /* XXX We should use different codepath for collecting oldest generation */
+ Parrot_Pointer_Array *oldest = NULL;
+ if (self->gen_to_collect + 1 == MAX_GENERATIONS) {
+ oldest = Parrot_pa_new(interp);
+ }
+
+ for (i = self->gen_to_collect; i >= 0; i--) {
+ /* Don't move to generation beyond last */
+ int move_to_old = (i + 1) != MAX_GENERATIONS;
+
+ POINTER_ARRAY_ITER(self->objects[i], gc_gms_sweep_pmc(interp, self, i, ptr, move_to_old, oldest););
+
+ /* We processed not oldest generation. It's techically _empty_ now. */
+ /* XXX We need Parrot_pa_reset which will reuse allocated chunks */
+ if (move_to_old) {
+ Parrot_pa_destroy(interp, self->objects[i]);
+ self->objects[i] = Parrot_pa_new(interp);
+ }
+ else {
+ Parrot_pa_destroy(interp, self->objects[i]);
+ self->objects[i] = oldest;
+
+ /* For next usage with strings */
+ oldest = Parrot_pa_new(interp);
+ }
+
+ POINTER_ARRAY_ITER(self->strings[i], gc_gms_sweep_string(interp, self, i, ptr, move_to_old, oldest););
+
+ /* We processed not oldest generation. It's techically _empty_ now. */
+ /* XXX We need Parrot_pa_reset which will reuse allocated chunks */
+ if (move_to_old) {
+ Parrot_pa_destroy(interp, self->strings[i]);
+ self->strings[i] = Parrot_pa_new(interp);
+ }
+ else {
+ Parrot_pa_destroy(interp, self->strings[i]);
+ self->strings[i] = oldest;
+ }
- Parrot_gc_pool_free(interp, self->string_allocator, ptr);
- });
}
}
@@ -1154,7 +1187,6 @@ gc_gms_mark_pmc_header(PARROT_INTERP, ARGMOD(PMC *pmc))
{
ASSERT_ARGS(gc_gms_mark_pmc_header)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
- pmc_alloc_struct * const item = PMC2PAC(pmc);
const size_t gen = POBJ2GEN(pmc);
PARROT_ASSERT(!PObj_on_free_list_TEST(pmc)
@@ -1175,8 +1207,7 @@ gc_gms_mark_pmc_header(PARROT_INTERP, ARGMOD(PMC *pmc))
/* mark it live. */
PObj_live_SET(pmc);
- Parrot_pa_remove(interp, self->objects[gen], item->ptr);
- item->ptr = Parrot_pa_insert(interp, self->work_list, item);
+ Parrot_pa_insert(interp, self->work_list, pmc);
}
/*
@@ -1276,6 +1307,7 @@ static void
gc_gms_free_pmc_attributes(PARROT_INTERP, ARGMOD(PMC *pmc))
{
ASSERT_ARGS(gc_gms_free_pmc_attributes)
+
if (PMC_data(pmc)) {
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
Parrot_gc_fixed_allocator_free(interp, self->fixed_size_allocator,
@@ -1387,7 +1419,7 @@ gc_gms_allocate_pmc_header(PARROT_INTERP, UINTVAL flags)
ASSERT_ARGS(gc_gms_allocate_pmc_header)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
Pool_Allocator * const pool = self->pmc_allocator;
- pmc_alloc_struct *item;
+ PMC *pmc;
gc_gms_maybe_mark_and_sweep(interp);
@@ -1397,10 +1429,10 @@ gc_gms_allocate_pmc_header(PARROT_INTERP, UINTVAL flags)
interp->gc_sys->stats.memory_used += sizeof (PMC);
interp->gc_sys->stats.mem_used_last_collect += sizeof (PMC);
- item = (pmc_alloc_struct *)Parrot_gc_pool_allocate(interp, pool);
- item->ptr = Parrot_pa_insert(interp, self->objects[0], item);
+ pmc = (PMC *)Parrot_gc_pool_allocate(interp, pool);
+ Parrot_pa_insert(interp, self->objects[0], pmc);
- return &(item->pmc);
+ return pmc;
}
static void
@@ -1409,6 +1441,9 @@ gc_gms_free_pmc_header(PARROT_INTERP, ARGFREE(PMC *pmc))
ASSERT_ARGS(gc_gms_free_pmc_header)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
+ /* We can't do it cheaply enough. */
+ return;
+
if (pmc) {
size_t gen = POBJ2GEN(pmc);
@@ -1418,12 +1453,11 @@ gc_gms_free_pmc_header(PARROT_INTERP, ARGFREE(PMC *pmc))
if (PObj_on_free_list_TEST(pmc))
return;
- Parrot_pa_remove(interp, self->objects[gen], PMC2PAC(pmc)->ptr);
- PObj_on_free_list_SET(pmc);
+ PObj_flags_SETTO(pmc, b_PObj_on_free_list_FLAG);
Parrot_pmc_destroy(interp, pmc);
- Parrot_gc_pool_free(interp, self->pmc_allocator, PMC2PAC(pmc));
+ Parrot_gc_pool_free(interp, self->pmc_allocator, pmc);
--interp->gc_sys->stats.header_allocs_since_last_collect;
interp->gc_sys->stats.memory_used -= sizeof (PMC);
@@ -1447,35 +1481,12 @@ gc_gms_is_pmc_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
ASSERT_ARGS(gc_gms_is_pmc_ptr)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
PObj * const obj = (PObj *)ptr;
- pmc_alloc_struct * const item = PMC2PAC(ptr);
/* Not aligned pointers aren't pointers */
- if (!obj || !item || ((size_t)obj & 3) || ((size_t)item & 3))
- return 0;
-
- if (!Parrot_gc_pool_is_owned(interp, self->pmc_allocator, item))
- return 0;
-
- /* black or white objects marked already. */
- if (PObj_is_live_or_free_TESTALL(obj))
+ if (!ptr || ((size_t)ptr & 3))
return 0;
- /* If object too old - skip it */
- if (POBJ2GEN(obj) > self->gen_to_collect)
- return 0;
-
- /* Object is on dirty_list. */
- if (PObj_GC_on_dirty_list_TEST(obj))
- return 0;
-
- /* Pool.is_owned isn't precise enough (yet) */
- if (Parrot_pa_is_owned(interp, self->objects[POBJ2GEN(obj)], item, item->ptr)) {
- if (POBJ2GEN(obj) == 0)
- PObj_GC_soil_root_SET(obj);
- return 1;
- }
-
- return 0;
+ return Parrot_gc_pool_is_owned(interp, self->pmc_allocator, ptr);
}
/*
@@ -1502,7 +1513,6 @@ gc_gms_allocate_string_header(PARROT_INTERP, SHIM(UINTVAL flags))
ASSERT_ARGS(gc_gms_allocate_string_header)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
Pool_Allocator * const pool = self->string_allocator;
- string_alloc_struct *item;
STRING *ret;
gc_gms_maybe_mark_and_sweep(interp);
@@ -1512,11 +1522,11 @@ gc_gms_allocate_string_header(PARROT_INTERP, SHIM(UINTVAL flags))
interp->gc_sys->stats.memory_used += sizeof (STRING);
interp->gc_sys->stats.mem_used_last_collect += sizeof (STRING);
- item = (string_alloc_struct *)Parrot_gc_pool_allocate(interp, pool);
- item->ptr = Parrot_pa_insert(interp, self->strings[0], item);
-
- ret = &(item->str);
+ ret = (STRING *)Parrot_gc_pool_allocate(interp, pool);
memset(ret, 0, sizeof (STRING));
+
+ Parrot_pa_insert(interp, self->strings[0], ret);
+
return ret;
}
@@ -1525,19 +1535,20 @@ gc_gms_free_string_header(PARROT_INTERP, ARGFREE(STRING *s))
{
ASSERT_ARGS(gc_gms_free_string_header)
+ /* We can't do it cheaply enough. */
+ return;
+
if (s && !PObj_on_free_list_TEST(s)) {
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
const size_t gen = POBJ2GEN(s);
- Parrot_pa_remove(interp, self->strings[gen], STR2PAC(s)->ptr);
-
if (Buffer_bufstart(s) && !PObj_external_TEST(s))
Parrot_gc_str_free_buffer_storage(interp,
&self->string_gc, (Buffer *)s);
PObj_on_free_list_SET(s);
- Parrot_gc_pool_free(interp, self->string_allocator, STR2PAC(s));
+ Parrot_gc_pool_free(interp, self->string_allocator, s);
--interp->gc_sys->stats.header_allocs_since_last_collect;
interp->gc_sys->stats.memory_used -= sizeof (STRING);
@@ -1576,28 +1587,13 @@ gc_gms_is_string_ptr(PARROT_INTERP, ARGIN_NULLOK(void *ptr))
{
ASSERT_ARGS(gc_gms_is_string_ptr)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
- PObj * const obj = (PObj *)ptr;
- string_alloc_struct * const item = STR2PAC(ptr);
+ PObj *obj = (PObj *)ptr;
/* Not aligned pointers aren't pointers */
- if (!obj || !item || ((size_t)obj & 3) || ((size_t)item & 3))
- return 0;
-
- if (!Parrot_gc_pool_is_owned(interp, self->string_allocator, item))
- return 0;
-
- /* black or white objects marked already. */
- if (PObj_is_live_or_free_TESTALL(obj))
+ if (!ptr || ((size_t)ptr & 3))
return 0;
- /* If object too old - skip it */
- if (POBJ2GEN(&item->str) > self->gen_to_collect)
- return 0;
-
- if (Parrot_pa_is_owned(interp, self->strings[POBJ2GEN(obj)], item, item->ptr))
- return 1;
-
- return 0;
+ return Parrot_gc_pool_is_owned(interp, self->string_allocator, ptr);
}
/*
@@ -1680,7 +1676,7 @@ gc_gms_iterate_live_strings(PARROT_INTERP,
size_t i;
for (i = 0; i < MAX_GENERATIONS; i++) {
POINTER_ARRAY_ITER(self->strings[i],
- STRING *s = &((string_alloc_struct *)ptr)->str;
+ STRING *s = (STRING *)ptr;
callback(interp, (Buffer *)s, data););
}
}
@@ -1936,7 +1932,6 @@ gc_gms_write_barrier(PARROT_INTERP, ARGMOD(PMC *pmc))
ASSERT_ARGS(gc_gms_write_barrier)
MarkSweep_GC * const self = (MarkSweep_GC *)interp->gc_sys->gc_private;
const size_t gen = POBJ2GEN(pmc);
- pmc_alloc_struct * const item = PMC2PAC(pmc);
if (pmc->flags & PObj_GC_on_dirty_list_FLAG)
return;
@@ -1944,8 +1939,7 @@ gc_gms_write_barrier(PARROT_INTERP, ARGMOD(PMC *pmc))
if (!gen)
return;
- Parrot_pa_remove(interp, self->objects[gen], item->ptr);
- item->ptr = Parrot_pa_insert(interp, self->dirty_list, item);
+ Parrot_pa_insert(interp, self->dirty_list, pmc);
pmc->flags |= PObj_GC_on_dirty_list_FLAG;
@@ -2201,7 +2195,7 @@ gc_gms_print_stats(PARROT_INTERP, ARGIN(const char* header))
ASSERT_ARGS(gc_gms_print_stats)
#ifdef DETAIL_MEMORY_DEBUG
- gc_gms_print_stats_always(interp, header, gen);
+ gc_gms_print_stats_always(interp, header);
#else
UNUSED(interp);
UNUSED(header);
@@ -2269,7 +2263,7 @@ gc_gms_validate_objects(PARROT_INTERP)
for (i = 0; i < MAX_GENERATIONS; i++) {
POINTER_ARRAY_ITER(self->objects[i],
- PMC * const pmc = &((pmc_alloc_struct *)ptr)->pmc;
+ PMC * const pmc = (PMC *)ptr;
PObj_live_CLEAR(pmc););
}
#else
View
196 src/pointer_array.c
@@ -14,6 +14,18 @@ src/pointer_array.c - Implementation Pointer Array storage.
#include "parrot/parrot.h"
#include "parrot/pointer_array.h"
+/*
+Iterators for Pointer_Array. Forward and backward iterators share same struct.
+
+Declared here to maintain "opaque pointer" design pattern.
+*/
+struct Parrot_Pointer_Array_Iterator {
+ Parrot_Pointer_Array *array; /* Array to iterate */
+ size_t chunk_index; /* Index of current chunk processed */
+ size_t in_chunk_index; /* Position within chunk */
+ Parrot_Pointer_Array_Chunk *chunk; /* Current chunk */
+};
+
/* HEADERIZER HFILE: include/parrot/pointer_array.h */
@@ -152,6 +164,190 @@ Parrot_pa_is_owned(PARROT_INTERP, ARGIN(Parrot_Pointer_Array *self),
return 0;
}
+/*
+=item C<Parrot_Pointer_Array_Iterator* Parrot_pa_begin(PARROT_INTERP,
+Parrot_Pointer_Array *self)>
+
+Get iterator starting at first element.
+
+=cut
+*/
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+Parrot_Pointer_Array_Iterator*
+Parrot_pa_begin(PARROT_INTERP, ARGIN(Parrot_Pointer_Array *self))
+{
+ Parrot_Pointer_Array_Iterator *iter = mem_gc_allocate_typed(interp, Parrot_Pointer_Array_Iterator);
+ iter->array = self;
+ iter->chunk_index = 0;
+ iter->in_chunk_index = 0;
+ iter->chunk = self->total_chunks ? self->chunks[0] : NULL;
+
+ return iter;
+}
+
+/*
+=item C<Parrot_Pointer_Array_Iterator* Parrot_pa_end(PARROT_INTERP,
+Parrot_Pointer_Array *self)>
+
+Get iterator with position next-after-end.
+
+=cut
+*/
+
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+Parrot_Pointer_Array_Iterator*
+Parrot_pa_end(PARROT_INTERP, ARGIN(Parrot_Pointer_Array *self))
+{
+}
+
+/*
+=item C<void Parrot_pa_iter_destroy(PARROT_INTERP, Parrot_Pointer_Array_Iterator
+*iter)>
+
+Destroy iterator.
+
+=cut
+*/
+
+PARROT_EXPORT
+void
+Parrot_pa_iter_destroy(PARROT_INTERP, ARGFREE(Parrot_Pointer_Array_Iterator *iter))
+{
+ mem_gc_free(interp, iter);
+}
+
+/*
+=item C<void ** Parrot_pa_iter_get(PARROT_INTERP, Parrot_Pointer_Array_Iterator
+*iter)>
+
+Get I<pointer> to stored value.
+
+We return pointer to be able to update item in-place.
+
+=cut
+*/
+
+PARROT_EXPORT
+PARROT_CAN_RETURN_NULL
+void **
+Parrot_pa_iter_get(PARROT_INTERP, ARGIN(Parrot_Pointer_Array_Iterator *iter))
+{
+ return &(iter->chunk->data[iter->in_chunk_index]);
+}
+
+/*
+=item C<void Parrot_pa_iter_next(PARROT_INTERP, Parrot_Pointer_Array_Iterator
+*iter)>
+
+Advance iterator forward.
+
+=cut
+*/
+
+PARROT_EXPORT
+void
+Parrot_pa_iter_next(PARROT_INTERP, ARGIN(Parrot_Pointer_Array_Iterator *iter))
+{
+ PARROT_ASSERT(!Parrot_pa_iter_is_empty(interp, iter) && "Advance empty iterator");
+
+ /* Manual tail-call optimization. Just in case if compiler doesn't support it */
+ restart:
+
+ /* Advance with chunk */
+ iter->in_chunk_index++;
+
+ /* Chunk isn't finished yet */
+ if (iter->in_chunk_index < CELL_PER_CHUNK - iter->chunk->num_free) {
+ /* but it can reach removed element */
+ if ((UINTVAL)(iter->chunk->data[iter->in_chunk_index]) & 1)
+ goto restart;
+ return;
+ }
+
+ /* Switch to new chunk */
+ iter->chunk_index++;
+ iter->in_chunk_index = 0;
+
+ if (iter->chunk_index >= iter->array->total_chunks) {
+ /* Iterator is finished */
+ iter->chunk = NULL;
+ return;
+ }
+
+ /* Point to start of the chunk */
+ iter->chunk = iter->array->chunks[iter->chunk_index];
+
+ /* but it can reach removed element */
+ if ((UINTVAL)(iter->chunk->data[iter->in_chunk_index]) & 1)
+ goto restart;
+
+ return;
+}
+
+/*
+=item C<void Parrot_pa_iter_prev(PARROT_INTERP, Parrot_Pointer_Array_Iterator
+*iter)>
+
+Advance iterator backward.
+
+=cut
+*/
+
+PARROT_EXPORT
+void
+Parrot_pa_iter_prev(PARROT_INTERP, ARGIN(Parrot_Pointer_Array_Iterator *iter))
+{
+}
+
+/*
+=item C<INTVAL Parrot_pa_iter_cmp(PARROT_INTERP, Parrot_Pointer_Array_Iterator
+*lhs, Parrot_Pointer_Array_Iterator *rhs)>
+
+Compare iterators. Return 1 if iterators positioned to same element.
+
+=cut
+*/
+
+PARROT_EXPORT
+INTVAL
+Parrot_pa_iter_cmp(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *lhs),
+ ARGIN(Parrot_Pointer_Array_Iterator *rhs))
+{
+}
+
+/*
+=item C<INTVAL Parrot_pa_iter_is_empty(PARROT_INTERP,
+Parrot_Pointer_Array_Iterator *iter)>
+
+Check that iterator has some more elements to iterate. Returns 1 if yes.
+
+=cut
+*/
+
+PARROT_EXPORT
+INTVAL
+Parrot_pa_iter_is_empty(PARROT_INTERP,
+ ARGIN(Parrot_Pointer_Array_Iterator *iter))
+{
+ if (iter->chunk == NULL)
+ return 1;
+
+ if (iter->chunk_index > iter->array->total_chunks)
+ return 1;
+
+ if (iter->in_chunk_index >= CELL_PER_CHUNK - iter->chunk->num_free)
+ return 1;
+
+ return 0;
+}
+
+
+
+
/*
* Local variables:
View
99 t/src/pointer_array.t
@@ -29,7 +29,7 @@ Tests atomic operation support.
# generic tests
-plan tests => 2;
+plan tests => 3;
c_output_is( <<'CODE', <<'OUTPUT', "Pointer array" );
@@ -210,6 +210,103 @@ ok 6
ok 7
OUTPUT
+c_output_is( <<'CODE', <<'OUTPUT', "Pointer array (iterators)" );
+
+#include <parrot/parrot.h>
+#include <parrot/embed.h>
+#include <parrot/pointer_array.h>
+#include <stdio.h>
+
+static int test_no = 1;
+int
+ok(int check, const char *msg)
+{
+ int res = 1;
+ if (!check) {
+ printf("not ");
+ res = 0;
+ }
+ printf("ok %d - %s\n", test_no++, msg);
+ return res;
+}
+
+void
+is(int l, int r, const char *msg)
+{
+ if (!ok(l == r, msg)) {
+ printf("# %d != %d\n", l, r);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ Interp *interp = Parrot_new(NULL);
+ Parrot_Pointer_Array *pa = Parrot_pa_new(interp);
+ int i = 42, j = 115200, k = 26122012, count = 0;
+ void *pi, *pj, *pk;
+
+ /* Iterator for empty array */
+ Parrot_Pointer_Array_Iterator *forward = Parrot_pa_begin(interp, pa);
+
+ ok(forward != NULL, "Iterator created");
+ ok(Parrot_pa_iter_is_empty(interp, forward), "Iterator is empty");
+ Parrot_pa_iter_destroy(interp, forward);
+ ok(1, "Iterator destroyed");
+
+ /* Put _few_ values into PA and check it */
+ pi = Parrot_pa_insert(interp, pa, &i);
+ pj = Parrot_pa_insert(interp, pa, &j);
+ pk = Parrot_pa_insert(interp, pa, &k);
+
+ forward = Parrot_pa_begin(interp, pa);
+ ok(!Parrot_pa_iter_is_empty(interp, forward), "Iterator is not empty");
+
+ is(&i, *Parrot_pa_iter_get(interp, forward), "Got first item");
+
+ Parrot_pa_iter_next(interp, forward);
+ is(&j, *Parrot_pa_iter_get(interp, forward), "Got second item");
+
+ Parrot_pa_iter_next(interp, forward);
+ is(&k, *Parrot_pa_iter_get(interp, forward), "Got third item");
+
+ Parrot_pa_iter_next(interp, forward);
+ ok(Parrot_pa_iter_is_empty(interp, forward), "Iterator is now empty");
+
+ Parrot_pa_iter_destroy(interp, forward);
+
+ /* Iterate over deleted elements */
+ Parrot_pa_remove(interp, pa, pj);
+ forward = Parrot_pa_begin(interp, pa);
+ ok(forward != NULL, "Iterator created");
+
+ is(&i, *Parrot_pa_iter_get(interp, forward), "Got first item");
+
+ Parrot_pa_iter_next(interp, forward);
+ is(&k, *Parrot_pa_iter_get(interp, forward), "Got second item");
+
+ Parrot_pa_iter_next(interp, forward);
+ ok(Parrot_pa_iter_is_empty(interp, forward), "Iterator is now empty");
+
+ Parrot_pa_iter_destroy(interp, forward);
+
+
+ return EXIT_SUCCESS;
+}
+CODE
+ok 1 - Iterator created
+ok 2 - Iterator is empty
+ok 3 - Iterator destroyed
+ok 4 - Iterator is not empty
+ok 5 - Got first item
+ok 6 - Got second item
+ok 7 - Got third item
+ok 8 - Iterator is now empty
+ok 9 - Iterator created
+ok 10 - Got first item
+ok 11 - Got second item
+ok 12 - Iterator is now empty
+OUTPUT
+
# Local Variables:
# mode: cperl
# cperl-indent-level: 4

No commit comments for this range

Something went wrong with that request. Please try again.