diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index d39003f3a..ed9b43526 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -559,7 +559,7 @@ obj_to_hmu(gc_object_t obj) /* Check for aligned allocation magic signature */ if (gc_is_aligned_allocation(obj)) { /* This is an aligned allocation, read offset */ - uint32_t *offset_ptr = (uint32_t *)((char *)obj - 8); + uint32_t *offset_ptr = ALIGNED_ALLOC_GET_OFFSET_PTR(obj); return (hmu_t *)((char *)obj - *offset_ptr); } @@ -581,7 +581,7 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, const char *file, int line) gc_size_t tot_size = 0, tot_size_unaligned; /* hmu header + prefix + obj + suffix */ - tot_size_unaligned = HMU_SIZE + OBJ_PREFIX_SIZE + size + OBJ_SUFFIX_SIZE; + tot_size_unaligned = size + OBJ_EXTRA_SIZE; /* aligned size*/ tot_size = GC_ALIGN_8(tot_size_unaligned); if (tot_size < size) @@ -668,8 +668,7 @@ gc_alloc_vo_aligned_internal(void *vheap, gc_size_t size, gc_size_t alignment, return NULL; } - if (size > SIZE_MAX - alignment - HMU_SIZE - OBJ_PREFIX_SIZE - - OBJ_SUFFIX_SIZE - 8) { + if (size > SIZE_MAX - GC_ALIGNED_SMALLEST_SIZE(alignment)) { /* Would overflow */ return NULL; } @@ -682,8 +681,8 @@ gc_alloc_vo_aligned_internal(void *vheap, gc_size_t size, gc_size_t alignment, #endif /* Calculate total size needed */ - tot_size_unaligned = - HMU_SIZE + OBJ_PREFIX_SIZE + size + OBJ_SUFFIX_SIZE + alignment - 1 + 8; + tot_size_unaligned = size + OBJ_EXTRA_SIZE + ALIGNED_ALLOC_EXTRA_OVERHEAD + + (alignment > 8 ? (alignment - 8) : 8); tot_size = GC_ALIGN_8(tot_size_unaligned); if (tot_size < size) { @@ -707,9 +706,10 @@ gc_alloc_vo_aligned_internal(void *vheap, gc_size_t size, gc_size_t alignment, /* Get base object pointer */ base_obj = (gc_uint8 *)hmu + HMU_SIZE + OBJ_PREFIX_SIZE; - /* Find next aligned address, leaving 8 bytes for metadata */ - aligned_addr = (((uintptr_t)base_obj + 8 + alignment - 1) - & ~(uintptr_t)(alignment - 1)); + /* Find next aligned address, reserving space for metadata */ + aligned_addr = + (((uintptr_t)base_obj + ALIGNED_ALLOC_METADATA_SIZE + alignment - 1) + & ~(uintptr_t)(alignment - 1)); ret = (gc_object_t)aligned_addr; /* Verify we have enough space */ @@ -725,11 +725,11 @@ gc_alloc_vo_aligned_internal(void *vheap, gc_size_t size, gc_size_t alignment, alignment_log2++; } - /* Store offset 8 bytes before returned pointer */ - *((uint32_t *)((char *)ret - 8)) = offset; + /* Store offset before returned pointer */ + *ALIGNED_ALLOC_GET_OFFSET_PTR(ret) = offset; /* Store magic with encoded alignment */ - *((uint32_t *)((char *)ret - 4)) = + *ALIGNED_ALLOC_GET_MAGIC_PTR(ret) = ALIGNED_ALLOC_MAGIC_VALUE | alignment_log2; /* Initialize HMU */ diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index f598f44c3..417364bab 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -86,11 +86,11 @@ hmu_verify(void *vheap, hmu_t *hmu); #define GC_MIN_ALIGNMENT 8 #endif -#define GC_SMALLEST_SIZE \ - GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE + 8) -#define GC_GET_REAL_SIZE(x) \ - GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE \ - + (((x) > 8) ? (x) : 8)) +/* Smallest allocation size for normal allocations + * The +8 ensures minimum allocation size for tree node structure */ +#define GC_SMALLEST_SIZE GC_ALIGN_8(OBJ_EXTRA_SIZE + 8) + +#define GC_GET_REAL_SIZE(x) GC_ALIGN_8(OBJ_EXTRA_SIZE + (((x) > 8) ? (x) : 8)) /* * ============================================================================ @@ -150,13 +150,17 @@ hmu_verify(void *vheap, hmu_t *hmu); * ---------------------- * * Low Address High Address - * ┌─────────────┬──────────┬────────────────┬──────────────┬─────────────┐ - * │ HMU Header │ Padding │ Magic + Offset │ Aligned Data │ Padding │ - * │ (meta) │ (0-align)│ (4 bytes) │ (size) │ (overhead) │ - * └─────────────┴──────────┴────────────────┴──────────────┴─────────────┘ - * ▲ ▲ - * │ │ - * magic_ptr user_ptr (returned, aligned) + * ┌─────────────┬──────────┬─────────┬─────────┬──────────────┬─────────────┐ + * │ HMU Header │ Padding │ Offset │ Magic │ Aligned Data │ Padding │ + * │ (4 bytes) │(variable)│(4 bytes)│(4 bytes)│ (size) │ (overhead) │ + * └─────────────┴──────────┴─────────┴─────────┴──────────────┴─────────────┘ + * ▲ └────8 bytes────┘ ▲ + * hmu user_ptr (returned, aligned) + * + * Padding is variable-length to satisfy alignment constraint: + * align_up(HMU_SIZE + ALIGNED_ALLOC_METADATA_SIZE, alignment) + * For alignment >= 12: HMU_SIZE + padding + 8 = alignment + * For alignment < 12: HMU_SIZE + padding + 8 = round_up(12, alignment) * * Constraints and Limitations: * ---------------------------- @@ -182,10 +186,35 @@ hmu_verify(void *vheap, hmu_t *hmu); * void *new_ptr = wasm_runtime_realloc(ptr, 512); // Returns NULL! */ +/* Aligned allocation constants */ +/* Size of offset field before aligned ptr */ +#define ALIGNED_ALLOC_OFFSET_SIZE 4 +/* Size of magic marker before aligned ptr */ +#define ALIGNED_ALLOC_MAGIC_SIZE 4 +/* Total: 8 bytes */ +#define ALIGNED_ALLOC_METADATA_SIZE \ + (ALIGNED_ALLOC_OFFSET_SIZE + ALIGNED_ALLOC_MAGIC_SIZE) + /* Aligned allocation magic markers */ #define ALIGNED_ALLOC_MAGIC_MASK 0xFFFF0000 #define ALIGNED_ALLOC_MAGIC_VALUE 0xA11C0000 +/* Get magic pointer from aligned object pointer */ +#define ALIGNED_ALLOC_GET_MAGIC_PTR(obj) \ + ((uint32_t *)((char *)(obj)-ALIGNED_ALLOC_MAGIC_SIZE)) + +/* Get offset pointer from aligned object pointer */ +#define ALIGNED_ALLOC_GET_OFFSET_PTR(obj) \ + ((uint32_t *)((char *)(obj)-ALIGNED_ALLOC_METADATA_SIZE)) + +/* Extra overhead for aligned allocations beyond normal OBJ_EXTRA_SIZE */ +#define ALIGNED_ALLOC_EXTRA_OVERHEAD ALIGNED_ALLOC_METADATA_SIZE + +/* Smallest allocation size for aligned allocations */ +#define GC_ALIGNED_SMALLEST_SIZE(alignment) \ + GC_ALIGN_8(OBJ_EXTRA_SIZE + ALIGNED_ALLOC_METADATA_SIZE \ + + ((alignment) > 8 ? (alignment - 8) : 8)) + /** * Check if a gc_object was allocated with alignment requirements. * @@ -202,7 +231,7 @@ gc_is_aligned_allocation(gc_object_t obj) if (!obj) return false; - uint32_t *magic_ptr = (uint32_t *)((char *)obj - 4); + uint32_t *magic_ptr = ALIGNED_ALLOC_GET_MAGIC_PTR(obj); return ((*magic_ptr & ALIGNED_ALLOC_MAGIC_MASK) == ALIGNED_ALLOC_MAGIC_VALUE); }