summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dbg_mlc.c40
-rw-r--r--include/gc_mark.h24
-rw-r--r--mallocx.c11
-rw-r--r--tests/test.c22
4 files changed, 96 insertions, 1 deletions
diff --git a/dbg_mlc.c b/dbg_mlc.c
index a0423e97..da4b86f3 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -565,6 +565,23 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
return (GC_store_debug_info(result, (word)lb, s, i));
}
+STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
+{
+ void * result = GC_generic_malloc(lb + DEBUG_BYTES, knd);
+
+ if (NULL == result) {
+ GC_err_printf(
+ "GC_debug_generic_malloc(%lu, %d) returning NULL (%s:%d)\n",
+ (unsigned long)lb, knd, s, i);
+ return NULL;
+ }
+ if (!GC_debugging_started) {
+ GC_start_debugging();
+ }
+ ADD_CALL_CHAIN(result, ra);
+ return GC_store_debug_info(result, (word)lb, s, i);
+}
+
#ifdef DBG_HDRS_ALL
/* An allocation function for internal use. Normally internally */
/* allocated objects do not have debug information. But in this */
@@ -924,6 +941,29 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
return(result);
}
+GC_API void * GC_CALL GC_debug_generic_or_special_malloc(size_t lb, int knd,
+ GC_EXTRA_PARAMS)
+{
+ switch (knd) {
+# ifdef STUBBORN_ALLOC
+ case STUBBORN:
+ return GC_debug_malloc_stubborn(lb, OPT_RA s, i);
+# endif
+ case PTRFREE:
+ return GC_debug_malloc_atomic(lb, OPT_RA s, i);
+ case NORMAL:
+ return GC_debug_malloc(lb, OPT_RA s, i);
+ case UNCOLLECTABLE:
+ return GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
+# ifdef ATOMIC_UNCOLLECTABLE
+ case AUNCOLLECTABLE:
+ return GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
+# endif
+ default:
+ return GC_debug_generic_malloc(lb, knd, OPT_RA s, i);
+ }
+}
+
#ifndef SHORT_DBG_HDRS
/* List of smashed (clobbered) locations. We defer printing these, */
diff --git a/include/gc_mark.h b/include/gc_mark.h
index 56bee583..dcadf42e 100644
--- a/include/gc_mark.h
+++ b/include/gc_mark.h
@@ -204,6 +204,30 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
/* first page of the resulting object */
/* are ignored. */
+/* Same as above but primary for allocating an object of the same kind */
+/* as an existing one (kind obtained by GC_get_kind_and_size). */
+/* Not suitable for GCJ and typed-malloc kinds. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_generic_or_special_malloc(
+ size_t /* size */, int /* knd */);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_generic_or_special_malloc(
+ size_t /* size */, int /* knd */,
+ GC_EXTRA_PARAMS);
+
+#ifdef GC_DEBUG
+# define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
+ GC_debug_generic_or_special_malloc(sz, knd, GC_EXTRAS)
+#else
+# define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
+ GC_generic_or_special_malloc(sz, knd)
+#endif /* !GC_DEBUG */
+
+/* Similar to GC_size but returns object kind. Size is returned too */
+/* if psize is not NULL. */
+GC_API int GC_CALL GC_get_kind_and_size(const void *, size_t * /* psize */)
+ GC_ATTR_NONNULL(1);
+
typedef void (GC_CALLBACK * GC_describe_type_fn)(void * /* p */,
char * /* out_buf */);
/* A procedure which */
diff --git a/mallocx.c b/mallocx.c
index de9fd931..75ee0e28 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -46,8 +46,17 @@ void ** const GC_uobjfreelist_ptr = GC_uobjfreelist;
void ** const GC_auobjfreelist_ptr = GC_auobjfreelist;
# endif
+GC_API int GC_CALL GC_get_kind_and_size(const void * p, size_t * psize)
+{
+ hdr * hhdr = HDR(p);
+
+ if (psize != NULL) {
+ *psize = hhdr -> hb_sz;
+ }
+ return hhdr -> hb_obj_kind;
+}
-STATIC void * GC_generic_or_special_malloc(size_t lb, int knd)
+GC_API void * GC_CALL GC_generic_or_special_malloc(size_t lb, int knd)
{
switch(knd) {
# ifdef STUBBORN_ALLOC
diff --git a/tests/test.c b/tests/test.c
index 34c6307b..6f412c8f 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -548,6 +548,25 @@ void check_marks_int_list(sexpr x)
#endif
+void test_generic_malloc_or_special(void *p) {
+ size_t size;
+ int kind = GC_get_kind_and_size(p, &size);
+ void *p2;
+
+ if (size != GC_size(p)) {
+ GC_printf("GC_get_kind_and_size returned size not matching GC_size\n");
+ FAIL;
+ }
+ p2 = GC_GENERIC_OR_SPECIAL_MALLOC(10, kind);
+ CHECK_OUT_OF_MEMORY(p2);
+ if (GC_get_kind_and_size(p2, NULL) != kind) {
+ GC_printf("GC_generic_or_special_malloc:"
+ " unexpected kind of returned object\n");
+ FAIL;
+ }
+ GC_FREE(p2);
+}
+
/* Try to force a to be strangely aligned */
struct {
char dummy;
@@ -596,6 +615,7 @@ void *GC_CALLBACK reverse_test_inner(void *data)
b = ints(1, 50);
c = ints(1, BIG);
d = uncollectable_ints(1, 100);
+ test_generic_malloc_or_special(d);
e = uncollectable_ints(1, 1);
/* Check that realloc updates object descriptors correctly */
collectable_count++;
@@ -606,6 +626,7 @@ void *GC_CALLBACK reverse_test_inner(void *data)
f[5] = ints(1,17);
collectable_count++;
g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
+ test_generic_malloc_or_special(g);
realloc_count++;
g = (sexpr *)GC_REALLOC((void *)g, 800 * sizeof(sexpr));
CHECK_OUT_OF_MEMORY(g);
@@ -1283,6 +1304,7 @@ void run_one_test(void)
GC_FREE(GC_MALLOC(0));
(void)GC_MALLOC_ATOMIC(0);
GC_FREE(GC_MALLOC_ATOMIC(0));
+ test_generic_malloc_or_special(GC_malloc_atomic(1));
}
}
# ifdef GC_GCJ_SUPPORT