Skip to content

Commit 1ec7dcd

Browse files
committed
Add support for custom allocators to DeeDeepCopyContext
1 parent 0c615d0 commit 1ec7dcd

File tree

4 files changed

+114
-14
lines changed

4 files changed

+114
-14
lines changed

include/deemon/deepcopy.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,27 @@ struct Dee_deepcopy_mapitem {
6060
__BYTE_TYPE__ *dcmi_new; /* [1..1] New pointer */
6161
};
6262

63+
struct Dee_deepcopy_uheap {
64+
struct Dee_deepcopy_uheap *ddcuh_next; /* [0..1][owned] Next user-heap chunk */
65+
DeeObject *ddcuh_base; /* [1..1][owned(ddcuh_free)] Heap item base address */
66+
NONNULL_T((1)) void (DCALL *ddcuh_free)(void *__restrict ob); /* [1..1][const] Free function for `ddcuh_base' */
67+
};
68+
#ifdef __INTELLISENSE__
69+
#define Dee_deepcopy_uheap_alloc() ((struct Dee_deepcopy_uheap *)sizeof(struct Dee_deepcopy_uheap))
70+
#define Dee_deepcopy_uheap_free(self) (void)Dee_REQUIRES_TYPE(struct Dee_deepcopy_uheap *, self)
71+
#define Dee_deepcopy_uheap_destroy(self) \
72+
((*(self)->ddcuh_free)((self)->ddcuh_base), \
73+
Dee_deepcopy_uheap_free(self))
74+
#else /* __INTELLISENSE__ */
75+
#define Dee_deepcopy_uheap_alloc() DeeObject_MALLOC(struct Dee_deepcopy_uheap)
76+
#define Dee_deepcopy_uheap_free(self) DeeObject_FREE(Dee_REQUIRES_TYPE(struct Dee_deepcopy_uheap *, self))
77+
#define Dee_deepcopy_uheap_destroy(self) \
78+
(Dee_Decref_unlikely((self)->ddcuh_base->ob_type), \
79+
(*(self)->ddcuh_free)((self)->ddcuh_base), \
80+
Dee_deepcopy_uheap_free(self))
81+
#endif /* !__INTELLISENSE__ */
82+
83+
6384
#ifdef CONFIG_EXPERIMENTAL_CUSTOM_HEAP
6485
typedef void Dee_deepcopy_heap_t;
6586
#define Dee_deepcopy_heap_getbase(self) (self)
@@ -129,6 +150,7 @@ typedef struct {
129150
Dee_deepcopy_heap_t *dcc_heap; /* [0..N][owned] Deepcopy heap */
130151
Dee_deepcopy_heap_t *dcc_obheap; /* [0..N][owned] Deepcopy heap for objects */
131152
Dee_deepcopy_heap_t *dcc_gcheap; /* [0..N][owned] Deepcopy heap for gc objects */
153+
struct Dee_deepcopy_uheap *dcc_uheap; /* [0..N][owned] Deepcopy heap for objects with custom allocators */
132154
struct Dee_deepcopy_mapitem *dcc_ptrmapv; /* [0..dcc_ptrmapc][owned][SORT(dcmi_old_minaddr ASC)] mapping of source range to target ranges. */
133155
size_t dcc_ptrmapc; /* # of used elements in `dcc_ptrmapv' */
134156
size_t dcc_ptrmapa; /* # of allocated elements in `dcc_ptrmapv' */

include/deemon/object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,8 +1804,8 @@ struct Dee_type_constructor {
18041804
* were created using regular heap allocations (`DeeObject_Malloc'). */
18051805
NONNULL_T((1)) void (DCALL *tp_free)(void *__restrict ob);
18061806
union {
1807-
size_t tp_instance_size; /* [valid_if(tp_free == NULL)] */
1808-
void *(DCALL *tp_alloc)(void); /* [valid_if(tp_free != NULL)] */
1807+
size_t tp_instance_size; /* [valid_if(tp_free == NULL)] */
1808+
void *(DCALL *tp_alloc)(void); /* [1..1][valid_if(tp_free != NULL)] */
18091809
}
18101810
#ifndef __COMPILER_HAVE_TRANSPARENT_UNION
18111811
_dee_aunion

src/deemon/objects/object.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4950,8 +4950,7 @@ PUBLIC ATTR_PURE WUNUSED NONNULL((1)) size_t
49504950
return self->tp_init.tp_alloc.tp_instance_size;
49514951
/* FIXME: This right here doesn't work in DEX modules when PLT symbols are used.
49524952
*
4953-
* This currently breaks "deepcopy" for stuff like "collections.UniqueSet" when
4954-
* deemon was built with "CONFIG_EXPERIMENTAL_SERIALIZED_DEEPCOPY".
4953+
* This currently breaks serialization for stuff like "collections.UniqueSet".
49554954
*
49564955
* The only solution I can see here is to just always disable slab-based alloc
49574956
* functions in DEX modules, but then the deemon core should be able to lazily

src/deemon/runtime/deepcopy.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <deemon/types.h> /* DREF, DeeObject, DeeTypeObject, Dee_TYPE, Dee_funptr_t, Dee_unlockinfo, OBJECT_HEAD */
3333

3434
#include <hybrid/typecore.h> /* __BYTE_TYPE__ */
35+
#include <hybrid/overflow.h> /* __BYTE_TYPE__ */
3536

3637
#include <stdbool.h> /* bool, false, true */
3738
#include <stddef.h> /* NULL, offsetof, ptrdiff_t, size_t */
@@ -317,7 +318,8 @@ deepcopy_gcobject_malloc_impl(DeeDeepCopyContext *__restrict self,
317318
struct Dee_gc_head *result_head, *next;
318319
ASSERT_OBJECT(ref);
319320
ASSERTF(DeeType_IsGC(Dee_TYPE(ref)), "Use deepcopy_object_malloc_impl()");
320-
num_bytes += Dee_GC_HEAD_SIZE;
321+
if (OVERFLOW_UADD(num_bytes, Dee_GC_HEAD_SIZE, &num_bytes))
322+
num_bytes = (size_t)-1;
321323
result_head = (struct Dee_gc_head *)deepcopy_heap_malloc(&self->dcc_gcheap, num_bytes, do_try, do_bzero);
322324
if unlikely(!result_head)
323325
goto err;
@@ -466,6 +468,8 @@ deepcopy_putpointer(DeeDeepCopyContext *__restrict self,
466468
}
467469
}
468470

471+
/* TODO: Only allow this part for static pointers! */
472+
469473
/* Assign pointer... */
470474
*deepcopy_ser2ptr(self, addrof_pointer, void const *) = pointer;
471475
return 0;
@@ -519,6 +523,7 @@ DeeDeepCopy_Init(DeeDeepCopyContext *__restrict self) {
519523
self->dcc_heap = NULL;
520524
self->dcc_obheap = NULL;
521525
self->dcc_gcheap = NULL;
526+
self->dcc_uheap = NULL;
522527
self->dcc_ptrmapv = NULL;
523528
self->dcc_ptrmapc = 0;
524529
self->dcc_ptrmapa = 0;
@@ -552,6 +557,16 @@ destroy_obheap(Dee_deepcopy_heap_t *heap, ptrdiff_t offsetof_object) {
552557
}
553558
}
554559

560+
PRIVATE void DCALL
561+
destroy_uheap(struct Dee_deepcopy_uheap *heap) {
562+
while (heap) {
563+
struct Dee_deepcopy_uheap *next;
564+
next = heap->ddcuh_next;
565+
Dee_deepcopy_uheap_destroy(heap);
566+
heap = next;
567+
}
568+
}
569+
555570
PUBLIC NONNULL((1)) void DCALL
556571
DeeDeepCopy_Fini(DeeDeepCopyContext *__restrict self) {
557572
size_t i;
@@ -574,7 +589,9 @@ DeeDeepCopy_Fini(DeeDeepCopyContext *__restrict self) {
574589
destroy_heap(self->dcc_heap);
575590
destroy_obheap(self->dcc_obheap, 0);
576591
destroy_obheap(self->dcc_gcheap, offsetof(struct Dee_gc_head, gc_object));
592+
destroy_uheap(self->dcc_uheap);
577593

594+
/* For safety... */
578595
DBG_memset(self, 0xcc, sizeof(*self));
579596
}
580597

@@ -676,15 +693,66 @@ DeeDeepCopy_CopyObject(DeeDeepCopyContext *__restrict self,
676693
} else {
677694
int status;
678695
size_t instance_size = DeeType_GetInstanceSize(tp);
679-
if unlikely(!instance_size)
680-
goto cannot_serialize;
681-
682-
/* Allocate buffer for object. */
683-
out_addr = DeeType_IsGC(tp)
684-
? deepcopy_gcobject_malloc(self, instance_size, ob)
685-
: deepcopy_object_malloc(self, instance_size, ob);
686-
if unlikely(!out_addr)
687-
goto err;
696+
if unlikely(!instance_size) {
697+
GenericObject *object_buffer;
698+
struct Dee_deepcopy_uheap *uheap;
699+
if (!tp->tp_init.tp_alloc.tp_free) {
700+
/* tp_instance_size == 0 + tp_free == NULL
701+
* -> probably a singleton
702+
* -> cannot serialize */
703+
goto cannot_serialize;
704+
}
705+
uheap = Dee_deepcopy_uheap_alloc();
706+
if unlikely(!uheap)
707+
goto err;
708+
709+
/* Support custom allocators... */
710+
ASSERT(tp->tp_init.tp_alloc.tp_alloc);
711+
object_buffer = (GenericObject *)((*tp->tp_init.tp_alloc.tp_alloc)());
712+
if unlikely(!object_buffer) {
713+
Dee_deepcopy_uheap_free(uheap);
714+
goto err;
715+
}
716+
uheap->ddcuh_base = Dee_AsObject(object_buffer);
717+
uheap->ddcuh_free = tp->tp_init.tp_alloc.tp_free;
718+
uheap->ddcuh_next = self->dcc_uheap;
719+
self->dcc_uheap = uheap;
720+
DeeObject_Init(object_buffer, tp);
721+
722+
if (DeeType_IsGC(tp)) {
723+
/* Insert GC head */
724+
struct Dee_gc_head *result_head, *next;
725+
result_head = DeeGC_Head(object_buffer);
726+
result_head->gc_pself = NULL;
727+
if ((next = self->dcc_gc_head) != NULL) {
728+
ASSERT(self->dcc_gc_tail != NULL);
729+
next->gc_pself = &result_head->gc_next;
730+
} else {
731+
ASSERT(self->dcc_gc_tail == NULL);
732+
self->dcc_gc_tail = result_head;
733+
}
734+
result_head->gc_next = next;
735+
self->dcc_gc_head = result_head;
736+
/* Only able to map the object's basic header */
737+
instance_size = Dee_GC_OBJECT_OFFSET + sizeof(DeeObject);
738+
if unlikely(deepcopy_mappointer(self, DeeGC_Head(ob),
739+
result_head, instance_size, false))
740+
goto err;
741+
} else {
742+
/* Only able to map the object's basic header */
743+
instance_size = sizeof(DeeObject);
744+
if unlikely(deepcopy_mappointer(self, ob, object_buffer, instance_size, false))
745+
goto err;
746+
}
747+
out_addr = deepcopy_ptr2ser(self, object_buffer);
748+
} else {
749+
/* Allocate buffer for object. */
750+
out_addr = DeeType_IsGC(tp)
751+
? deepcopy_gcobject_malloc(self, instance_size, ob)
752+
: deepcopy_object_malloc(self, instance_size, ob);
753+
if unlikely(!Dee_SERADDR_ISOK(out_addr))
754+
goto err;
755+
}
688756

689757
/* NOTE: Standard fields have already been initialized by "deepcopy_[gc]object_malloc" */
690758
status = (*(Dee_tp_serialize_obj_t)tp_serialize)(ob, (DeeSerial *)self, out_addr);
@@ -719,6 +787,16 @@ cleanup_heap(Dee_deepcopy_heap_t *heap) {
719787
}
720788
#endif /* !CONFIG_EXPERIMENTAL_CUSTOM_HEAP */
721789

790+
PRIVATE void DCALL
791+
cleanup_uheap(struct Dee_deepcopy_uheap *heap) {
792+
while (heap) {
793+
struct Dee_deepcopy_uheap *next;
794+
next = heap->ddcuh_next;
795+
Dee_deepcopy_uheap_free(heap);
796+
heap = next;
797+
}
798+
}
799+
722800
/* Finalize "self" in the sense of doing a COMMIT.
723801
*
724802
* This function behaves similar to `DeeDeepCopy_Fini()', but will also
@@ -737,6 +815,7 @@ DeeDeepCopy_Pack(/*inherit(always)*/DeeDeepCopyContext *__restrict self) {
737815
cleanup_heap(self->dcc_obheap);
738816
cleanup_heap(self->dcc_gcheap);
739817
#endif /* !CONFIG_EXPERIMENTAL_CUSTOM_HEAP */
818+
cleanup_uheap(self->dcc_uheap);
740819

741820
/* Free map tables. */
742821
Dee_Free(self->dcc_ptrmapv);

0 commit comments

Comments
 (0)