Index: src/pmc.c =================================================================== --- src/pmc.c (revision 41346) +++ src/pmc.c (working copy) @@ -42,7 +42,32 @@ UINTVAL flags) __attribute__nonnull__(1); +static void Parrot_pmc_free_clone_node(PARROT_INTERP, + ARGMOD(PMC_clone_node *root)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*root); + PARROT_CANNOT_RETURN_NULL +static PMC_clone_node * Parrot_pmc_insert_clone_node(PARROT_INTERP, + ARGMOD(PMC_clone_node * node), + ARGIN(PMC * data), + ARGIN(PMC *clone)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3) + __attribute__nonnull__(4) + FUNC_MODIFIES(* node); + +PARROT_CANNOT_RETURN_NULL +static PMC_clone_node * Parrot_pmc_new_clone_node(PARROT_INTERP, + ARGIN(PMC *self), + ARGIN(PMC *clone)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3); + +PARROT_CANNOT_RETURN_NULL static PMC* pmc_reuse_no_init(PARROT_INTERP, ARGIN(PMC *pmc), INTVAL new_type, @@ -56,6 +81,18 @@ PARROT_ASSERT_ARG(interp) #define ASSERT_ARGS_get_new_pmc_header __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) +#define ASSERT_ARGS_Parrot_pmc_free_clone_node __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(root) +#define ASSERT_ARGS_Parrot_pmc_insert_clone_node __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(node) \ + || PARROT_ASSERT_ARG(data) \ + || PARROT_ASSERT_ARG(clone) +#define ASSERT_ARGS_Parrot_pmc_new_clone_node __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(self) \ + || PARROT_ASSERT_ARG(clone) #define ASSERT_ARGS_pmc_reuse_no_init __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ || PARROT_ASSERT_ARG(pmc) @@ -938,6 +975,109 @@ /* +=item C + +=item C + + +*/ + +PARROT_CAN_RETURN_NULL +PMC_clone_node * +Parrot_pmc_create_clone_registry(PARROT_INTERP, ARGIN(PMC *self)) +{ + ASSERT_ARGS(Parrot_pmc_create_clone_registry) + + if(interp->clone_registry) + return NULL; + else { + PMC_clone_node * const root = + (PMC_clone_node *)Parrot_gc_allocate_fixed_size_storage(interp, sizeof (PMC_clone_node)); + root->old = self; + root->bigger = NULL; + root->smaller = NULL; + interp->clone_registry = root; + return root; + } +} + +void +Parrot_pmc_set_clone_node(PARROT_INTERP, ARGIN(PMC_clone_node * node), ARGIN(PMC * clone)) +{ + ASSERT_ARGS(Parrot_pmc_set_clone_node) + if(node == NULL) + return; + node->clone = clone; +} + +PARROT_CAN_RETURN_NULL +PMC * +Parrot_pmc_find_registered_clone(PARROT_INTERP, ARGIN(PMC *self)) +{ + ASSERT_ARGS(Parrot_pmc_find_registered_clone) + PMC_clone_node * node = interp->clone_registry; + while (node != NULL) { + PMC * const old = node->old; + if (old == self) + return node->clone; + else if (old < self) + node = node->bigger; + else + node = node->smaller; + } + return NULL; +} + +PARROT_CANNOT_RETURN_NULL +static PMC_clone_node * +Parrot_pmc_insert_clone_node(PARROT_INTERP, ARGMOD(PMC_clone_node * node), ARGIN(PMC * data), ARGIN(PMC *clone)) +{ + ASSERT_ARGS(Parrot_pmc_insert_clone_node) + if (node == NULL) + return Parrot_pmc_new_clone_node(interp, data, clone); + else { + PMC * const old = node->old; + if (data > old) + node->bigger = Parrot_pmc_insert_clone_node(interp, node->bigger, data, clone); + else + node->smaller = Parrot_pmc_insert_clone_node(interp, node->smaller, data, clone); + } +} + +PARROT_CANNOT_RETURN_NULL +static PMC_clone_node * +Parrot_pmc_new_clone_node(PARROT_INTERP, ARGIN(PMC *self), ARGIN(PMC *clone)) +{ + ASSERT_ARGS(Parrot_pmc_new_clone_node) + PMC_clone_node * const node = Parrot_gc_allocate_fixed_size_storage(interp, sizeof (PMC_clone_node)); + node->old = self; + node->clone = clone; + node->bigger = NULL; + node->smaller = NULL; + return node; +} + +void +Parrot_pmc_cleanup_clone_registry(PARROT_INTERP, ARGMOD(PMC_clone_node *root)) +{ + ASSERT_ARGS(Parrot_pmc_cleanup_clone_registry) + Parrot_pmc_free_clone_node(interp, root); + interp->clone_registry = NULL; +} + +static void +Parrot_pmc_free_clone_node(PARROT_INTERP, ARGMOD(PMC_clone_node *root)) +{ + ASSERT_ARGS(Parrot_pmc_free_clone_node) + if (root->bigger != NULL) + Parrot_pmc_free_clone_node(interp, root->bigger); + if (root->smaller != NULL) + Parrot_pmc_free_clone_node(interp, root->smaller); + Parrot_gc_free_fixed_size_storage(interp, sizeof (PMC_clone_node), root); +} + +/* + =back =head1 SEE ALSO Index: src/interp/inter_create.c =================================================================== --- src/interp/inter_create.c (revision 41346) +++ src/interp/inter_create.c (working copy) @@ -130,6 +130,7 @@ interp = mem_allocate_zeroed_typed(Interp); interp->lo_var_ptr = NULL; + interp->clone_registry = NULL; /* the last interpreter (w/o) parent has to cleanup globals * so remember parent if any */ Index: src/pmc/hash.pmc =================================================================== --- src/pmc/hash.pmc (revision 41346) +++ src/pmc/hash.pmc (working copy) @@ -434,11 +434,18 @@ */ VTABLE PMC *clone() { - PMC * const dest = pmc_new(INTERP, SELF->vtable->base_type); + PMC_clone_node * const node = Parrot_pmc_create_clone_registry(INTERP, SELF); + PMC * dest = Parrot_pmc_find_registered_clone(INTERP, SELF); + if (!dest) { + dest = pmc_new(INTERP, SELF->vtable->base_type); + if (node) + Parrot_pmc_set_clone_node(INTERP, node, dest); + parrot_hash_clone(INTERP, (Hash *)SELF.get_pointer(), + (Hash *)VTABLE_get_pointer(INTERP, dest)); + } + if (node) + Parrot_pmc_cleanup_clone_registry(INTERP, node); - parrot_hash_clone(INTERP, (Hash *)SELF.get_pointer(), - (Hash *)VTABLE_get_pointer(INTERP, dest)); - return dest; } Index: include/parrot/pmc.h =================================================================== --- include/parrot/pmc.h (revision 41346) +++ include/parrot/pmc.h (working copy) @@ -19,6 +19,7 @@ #define PARROT_MAX_CLASSES 100 + /* HEADERIZER BEGIN: src/pmc.c */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ @@ -132,6 +133,30 @@ INTVAL get_new_vtable_index(PARROT_INTERP) __attribute__nonnull__(1); +void Parrot_pmc_cleanup_clone_registry(PARROT_INTERP, + ARGMOD(PMC_clone_node *root)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*root); + +PARROT_CAN_RETURN_NULL +PMC_clone_node * Parrot_pmc_create_clone_registry(PARROT_INTERP, + ARGIN(PMC *self)) + __attribute__nonnull__(1) + __attribute__nonnull__(2); + +PARROT_CAN_RETURN_NULL +PMC * Parrot_pmc_find_registered_clone(PARROT_INTERP, ARGIN(PMC *self)) + __attribute__nonnull__(1) + __attribute__nonnull__(2); + +void Parrot_pmc_set_clone_node(PARROT_INTERP, + ARGIN(PMC_clone_node * node), + ARGIN(PMC * clone)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3); + void temporary_pmc_free(PARROT_INTERP, ARGMOD(PMC *pmc)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -187,6 +212,22 @@ || PARROT_ASSERT_ARG(name) #define ASSERT_ARGS_get_new_vtable_index __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) +#define ASSERT_ARGS_Parrot_pmc_cleanup_clone_registry \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(root) +#define ASSERT_ARGS_Parrot_pmc_create_clone_registry \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(self) +#define ASSERT_ARGS_Parrot_pmc_find_registered_clone \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(self) +#define ASSERT_ARGS_Parrot_pmc_set_clone_node __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(node) \ + || PARROT_ASSERT_ARG(clone) #define ASSERT_ARGS_temporary_pmc_free __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ || PARROT_ASSERT_ARG(pmc) Index: include/parrot/interpreter.h =================================================================== --- include/parrot/interpreter.h (revision 41346) +++ include/parrot/interpreter.h (working copy) @@ -177,6 +177,12 @@ */ #define CURRENT_CONTEXT(interp) ((interp)->ctx) +typedef struct _PMC_clone_node { + struct _PMC_clone_registry *bigger; + struct _PMC_clone_registry *smaller; + PMC* old; + PMC* clone; +} PMC_clone_node; typedef struct _context_mem { void **free_list; /* array of free-lists, per size free slots */ @@ -309,6 +315,7 @@ * inside the invoke these get moved to the context structure */ PMC *current_cont; /* the return continuation PMC */ PMC *current_object; /* invocant, if a method call */ + PMC_clone_node *clone_registry; /* registry to prevent cycles while cloning */ }; /* typedef struct parrot_interp_t Interp; done in parrot.h so that