summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2023-04-26 09:27:50 +0300
committerIvan Maidanski <ivmai@mail.ru>2023-04-26 17:31:27 +0300
commitfef1ce084af6dc3a0051025c12e04a1eaa5eb1b0 (patch)
treec69e8c606525325489f605aa6e7a488d1bb63d27
parent3e93d05a20d0da777765078836c69cc60472187d (diff)
downloadbdwgc-fef1ce084af6dc3a0051025c12e04a1eaa5eb1b0.tar.gz
New API for more optimal usage of GC_calloc_explicitly_typed
If the client needs to allocate many typed object arrays of same layout and amount of elements, then "calloc" descriptor could be created once (by GC_calloc_prepare_explicitly_typed) followed by multiple allocations (by GC_calloc_do_explicitly_typed) referring to the same descriptor. * include/gc/gc_typed.h (GC_CALLOC_TYPED_DESCR_WORDS): New macro. * include/gc/gc_typed.h (GC_calloc_typed_descr_s): New struct type. * include/gc/gc_typed.h (GC_calloc_prepare_explicitly_typed, GC_calloc_do_explicitly_typed): New function declaration. * tests/gctest.c [!NO_TYPED_TEST && !GC_DEBUG] (typed_test): Define ctd_l local variable; call GC_calloc_prepare_explicitly_typed() before loop; call GC_calloc_do_explicitly_typed() instead of GC_CALLOC_EXPLICITLY_TYPED(1001). * typd_mlc.c (GC_calloc_typed_descr_s.alloc_lb): Change type from size_t to word. * typd_mlc.c (GC_calloc_typed_descr_s.descr_type): Change type from int to signed_word. * typd_mlc.c (GC_calloc_prepare_explicitly_typed, GC_calloc_do_explicitly_typed): Change from STATIC to GC_API; add ctd_sz argument; check ctd_sz in assertion; add casts for alloc_lb field. * typd_mlc.c (GC_calloc_prepare_explicitly_typed): Add static assertion about size of GC_calloc_typed_descr_s and GC_CALLOC_TYPED_DESCR_WORDS; change return type from void to it. * typd_mlc.c (GC_calloc_explicitly_typed): Pass sizeof(ctd) to GC_calloc_prepare_explicitly_typed(), GC_calloc_do_explicitly_typed().
-rw-r--r--include/gc/gc_typed.h31
-rw-r--r--tests/gctest.c19
-rw-r--r--typd_mlc.c43
3 files changed, 75 insertions, 18 deletions
diff --git a/include/gc/gc_typed.h b/include/gc/gc_typed.h
index 1de355fe..a9a82931 100644
--- a/include/gc/gc_typed.h
+++ b/include/gc/gc_typed.h
@@ -104,6 +104,37 @@ GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL
/* bitmap of d multiplied by sizeof GC_word. */
/* Returned object is cleared. */
+#define GC_CALLOC_TYPED_DESCR_WORDS 8
+
+#ifdef GC_BUILD
+ struct GC_calloc_typed_descr_s;
+#else
+ struct GC_calloc_typed_descr_s {
+ GC_word opaque[GC_CALLOC_TYPED_DESCR_WORDS];
+ };
+#endif
+
+GC_API int GC_CALL GC_calloc_prepare_explicitly_typed(
+ struct GC_calloc_typed_descr_s * /* pctd */,
+ size_t /* sizeof_ctd */, size_t /* nelements */,
+ size_t /* element_size_in_bytes */, GC_descr);
+ /* This is same as GC_calloc_explicitly_typed but more optimal */
+ /* in terms of the performance and memory usage if the client */
+ /* needs to allocate multiple typed object arrays with the */
+ /* same layout and number of elements. The client should call */
+ /* it to be prepared for the subsequent allocations by */
+ /* GC_calloc_do_explicitly_typed, one or many. The result of */
+ /* the preparation is stored to *pctd, even in case of */
+ /* a failure. The prepared structure could be just dropped */
+ /* when no longer needed. Returns 0 on failure, 1 on success; */
+ /* the result could be ignored (as it is also stored to *pctd */
+ /* and checked later by GC_calloc_do_explicitly_typed). */
+
+GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_do_explicitly_typed(
+ const struct GC_calloc_typed_descr_s * /* pctd */,
+ size_t /* sizeof_ctd */);
+ /* The actual object allocation for the prepared description. */
+
#ifdef GC_DEBUG
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes))
# define GC_MALLOC_EXPLICITLY_TYPED_IGNORE_OFF_PAGE(bytes, d) \
diff --git a/tests/gctest.c b/tests/gctest.c
index 9c5fe9d2..126f5c1c 100644
--- a/tests/gctest.c
+++ b/tests/gctest.c
@@ -1331,6 +1331,9 @@ void typed_test(void)
GC_descr d4 = GC_make_descriptor(bm_huge, 320);
GC_word * x = (GC_word *)GC_MALLOC_EXPLICITLY_TYPED(
320 * sizeof(GC_word) + 123, d4);
+# ifndef GC_DEBUG
+ struct GC_calloc_typed_descr_s ctd_l;
+# endif
int i;
AO_fetch_and_add1(&collectable_count);
@@ -1345,6 +1348,13 @@ void typed_test(void)
d1 = GC_make_descriptor(bm3, 2);
GC_set_bit(bm2, 1);
d2 = GC_make_descriptor(bm2, 2);
+# ifndef GC_DEBUG
+ if (GC_calloc_prepare_explicitly_typed(&ctd_l, sizeof(ctd_l), 1001,
+ 3 * sizeof(GC_word), d2) != 1) {
+ GC_printf("Out of memory in calloc typed prepare\n");
+ exit(1);
+ }
+# endif
old = 0;
for (i = 0; i < 4000; i++) {
if ((i & 0xff) != 0) {
@@ -1386,9 +1396,12 @@ void typed_test(void)
newP = (GC_word *)GC_CALLOC_EXPLICITLY_TYPED(7, 3 * sizeof(GC_word),
d2);
} else {
- newP = (GC_word *)GC_CALLOC_EXPLICITLY_TYPED(1001,
- 3 * sizeof(GC_word),
- d2);
+# ifdef GC_DEBUG
+ newP = (GC_word *)GC_CALLOC_EXPLICITLY_TYPED(1001,
+ 3 * sizeof(GC_word), d2);
+# else
+ newP = GC_calloc_do_explicitly_typed(&ctd_l, sizeof(ctd_l));
+# endif
if (newP != NULL && (newP[0] != 0 || newP[1] != 0)) {
GC_printf("Bad initialization by GC_calloc_explicitly_typed\n");
FAIL;
diff --git a/typd_mlc.c b/typd_mlc.c
index 97fc2980..e0325535 100644
--- a/typd_mlc.c
+++ b/typd_mlc.c
@@ -473,23 +473,28 @@ struct GC_calloc_typed_descr_s {
struct LeafDescriptor leaf;
GC_descr simple_d;
complex_descriptor *complex_d;
- size_t alloc_lb;
- int descr_type;
+ word alloc_lb; /* size_t actually */
+ signed_word descr_type; /* int actually */
};
-STATIC void GC_calloc_prepare_explicitly_typed(
+GC_API int GC_CALL GC_calloc_prepare_explicitly_typed(
struct GC_calloc_typed_descr_s *pctd,
+ size_t ctd_sz,
size_t n, size_t lb, GC_descr d)
{
GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
+ GC_STATIC_ASSERT(sizeof(struct GC_calloc_typed_descr_s)
+ == GC_CALLOC_TYPED_DESCR_WORDS * sizeof(word));
GC_ASSERT(GC_explicit_typing_initialized);
+ GC_ASSERT(sizeof(struct GC_calloc_typed_descr_s) == ctd_sz);
+ (void)ctd_sz; /* unused currently */
if (EXPECT(0 == lb || 0 == n, FALSE)) lb = n = 1;
if (EXPECT((lb | n) > GC_SQRT_SIZE_MAX, FALSE) /* fast initial check */
&& n > GC_SIZE_MAX / lb) {
pctd -> alloc_lb = GC_SIZE_MAX; /* n*lb overflow */
pctd -> descr_type = NO_MEM;
/* The rest of the fields are unset. */
- return;
+ return 0; /* failure */
}
pctd -> descr_type = GC_make_array_descriptor((word)n, (word)lb, d,
@@ -498,34 +503,42 @@ STATIC void GC_calloc_prepare_explicitly_typed(
switch (pctd -> descr_type) {
case NO_MEM:
case SIMPLE:
- pctd -> alloc_lb = lb * n;
+ pctd -> alloc_lb = (word)lb * n;
break;
case LEAF:
- pctd -> alloc_lb = SIZET_SAT_ADD(lb * n,
+ pctd -> alloc_lb = (word)SIZET_SAT_ADD(lb * n,
sizeof(struct LeafDescriptor) + TYPD_EXTRA_BYTES);
break;
case COMPLEX:
- pctd -> alloc_lb = SIZET_SAT_ADD(lb * n, TYPD_EXTRA_BYTES);
+ pctd -> alloc_lb = (word)SIZET_SAT_ADD(lb * n, TYPD_EXTRA_BYTES);
break;
}
+ return 1; /* success */
}
-STATIC GC_ATTR_MALLOC void * GC_calloc_do_explicitly_typed(
- const struct GC_calloc_typed_descr_s *pctd)
+GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_do_explicitly_typed(
+ const struct GC_calloc_typed_descr_s *pctd,
+ size_t ctd_sz)
{
void *op;
size_t nwords;
+ GC_ASSERT(sizeof(struct GC_calloc_typed_descr_s) == ctd_sz);
+ (void)ctd_sz; /* unused currently */
switch (pctd -> descr_type) {
case NO_MEM:
- return (*GC_get_oom_fn())(pctd -> alloc_lb);
+ return (*GC_get_oom_fn())((size_t)(pctd -> alloc_lb));
case SIMPLE:
- return GC_malloc_explicitly_typed(pctd -> alloc_lb, pctd -> simple_d);
+ return GC_malloc_explicitly_typed((size_t)(pctd -> alloc_lb),
+ pctd -> simple_d);
case LEAF:
case COMPLEX:
break;
+ default:
+ ABORT_RET("Bad descriptor type");
+ return NULL;
}
- op = GC_malloc_kind(pctd -> alloc_lb, GC_array_kind);
+ op = GC_malloc_kind((size_t)(pctd -> alloc_lb), GC_array_kind);
if (EXPECT(NULL == op, FALSE))
return NULL;
@@ -567,7 +580,7 @@ STATIC GC_ATTR_MALLOC void * GC_calloc_do_explicitly_typed(
# endif
{
/* Couldn't register it due to lack of memory. Punt. */
- return (*GC_get_oom_fn())(pctd -> alloc_lb);
+ return (*GC_get_oom_fn())((size_t)(pctd -> alloc_lb));
}
}
return op;
@@ -579,8 +592,8 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_explicitly_typed(size_t n,
{
struct GC_calloc_typed_descr_s ctd;
- GC_calloc_prepare_explicitly_typed(&ctd, n, lb, d);
- return GC_calloc_do_explicitly_typed(&ctd);
+ (void)GC_calloc_prepare_explicitly_typed(&ctd, sizeof(ctd), n, lb, d);
+ return GC_calloc_do_explicitly_typed(&ctd, sizeof(ctd));
}
/* Return the size of the object described by complex_d. It would be */