2025-12-12 06:52:14 +09:00
|
|
|
// smallobject_mid_v35.c
|
|
|
|
|
// Phase v11a-3: MID v3.5 HotBox implementation
|
|
|
|
|
//
|
|
|
|
|
// Design:
|
|
|
|
|
// - TLS-cached page for fast allocation
|
|
|
|
|
// - Refill via ColdIface when page exhausted
|
|
|
|
|
// - Retire via ColdIface when page is full
|
|
|
|
|
// - Stats/Learner integration for observability
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include "box/smallobject_mid_v35_box.h"
|
|
|
|
|
#include "box/smallobject_segment_mid_v3_box.h"
|
|
|
|
|
#include "box/smallobject_cold_iface_mid_v3_box.h"
|
2025-12-12 19:19:25 +09:00
|
|
|
#include "box/smallobject_mid_v35_geom_box.h" // Phase MID-V35-HOTPATH-OPT-1: geometry SSOT
|
|
|
|
|
#include "box/mid_v35_hotpath_env_box.h" // Phase MID-V35-HOTPATH-OPT-1: Step 1-3 ENV gates
|
2025-12-12 06:52:14 +09:00
|
|
|
#include "tiny_region_id.h" // For tiny_region_id_write_header
|
|
|
|
|
|
2025-12-12 07:12:24 +09:00
|
|
|
// SmallPageMeta is defined in smallobject_segment_mid_v3_box.h
|
|
|
|
|
// (included via smallobject_cold_iface_mid_v3_box.h)
|
2025-12-12 06:52:14 +09:00
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// TLS Context (per-thread fast path state)
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
void *page[8]; // Current page per class
|
|
|
|
|
uint32_t offset[8]; // Allocation offset (slot index)
|
|
|
|
|
uint32_t capacity[8]; // Slots per page per class
|
2025-12-12 07:12:24 +09:00
|
|
|
SmallPageMeta_MID_v3 *meta[8]; // Page metadata for retire check
|
2025-12-12 06:52:14 +09:00
|
|
|
} SmallMidV35TlsCtx;
|
|
|
|
|
|
|
|
|
|
static __thread SmallMidV35TlsCtx tls_mid_v35_ctx = {0};
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// Slot Configuration (C5/C6/C7)
|
|
|
|
|
// ============================================================================
|
2025-12-12 19:19:25 +09:00
|
|
|
// Phase MID-V35-HOTPATH-OPT-1: Use geom_box as Single Source of Truth
|
|
|
|
|
// See: core/box/smallobject_mid_v35_geom_box.h
|
2025-12-12 06:52:14 +09:00
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// Init
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void small_mid_v35_init(void) {
|
|
|
|
|
// Initialize any global state if needed
|
|
|
|
|
// For v11a-3: nothing to do (TLS is zero-initialized)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// Alloc
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void* small_mid_v35_alloc(uint32_t class_idx, size_t size) {
|
2025-12-12 07:12:24 +09:00
|
|
|
(void)size; // Unused for now
|
2025-12-12 06:52:14 +09:00
|
|
|
if (class_idx < 5 || class_idx > 7) return NULL; // Only C5-C7
|
|
|
|
|
|
|
|
|
|
SmallMidV35TlsCtx *ctx = &tls_mid_v35_ctx;
|
|
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// ========================================================================
|
|
|
|
|
// Step 3: C6 specialized fast path (constant slot size = 512)
|
|
|
|
|
// ========================================================================
|
|
|
|
|
if (mid_v35_c6_fastpath_enabled() && class_idx == 6) {
|
|
|
|
|
void *page = ctx->page[6];
|
|
|
|
|
uint32_t off = ctx->offset[6];
|
|
|
|
|
if (page && off < ctx->capacity[6]) {
|
|
|
|
|
// C6: slot_size = 512 (constant, compiler can optimize)
|
|
|
|
|
void *base = (char*)page + off * 512;
|
|
|
|
|
ctx->offset[6] = off + 1;
|
|
|
|
|
|
|
|
|
|
// Step 2: HOT_COUNTS gate
|
|
|
|
|
if (mid_v35_hot_counts_enabled() && ctx->meta[6]) {
|
|
|
|
|
ctx->meta[6]->alloc_count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: HEADER_PREFILL gate
|
|
|
|
|
if (!mid_v35_header_prefill_enabled()) {
|
|
|
|
|
tiny_region_id_write_header(base, 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (char*)base + 1;
|
|
|
|
|
}
|
|
|
|
|
// Fall through to slow path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ========================================================================
|
|
|
|
|
// Generic fast path: allocate from TLS cached page
|
|
|
|
|
// ========================================================================
|
2025-12-12 06:52:14 +09:00
|
|
|
if (ctx->page[class_idx] && ctx->offset[class_idx] < ctx->capacity[class_idx]) {
|
2025-12-12 19:19:25 +09:00
|
|
|
size_t slot_size = mid_v35_slot_size(class_idx);
|
2025-12-12 06:52:14 +09:00
|
|
|
void *base = (char*)ctx->page[class_idx] + ctx->offset[class_idx] * slot_size;
|
|
|
|
|
ctx->offset[class_idx]++;
|
|
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// Step 2: HOT_COUNTS gate - Update page metadata
|
|
|
|
|
if (mid_v35_hot_counts_enabled() && ctx->meta[class_idx]) {
|
2025-12-12 06:52:14 +09:00
|
|
|
ctx->meta[class_idx]->alloc_count++;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// Step 1: HEADER_PREFILL gate - Write header if not prefilled
|
|
|
|
|
if (!mid_v35_header_prefill_enabled()) {
|
|
|
|
|
tiny_region_id_write_header(base, class_idx);
|
|
|
|
|
}
|
2025-12-12 06:52:14 +09:00
|
|
|
|
|
|
|
|
// Return USER pointer (BASE + 1 byte header)
|
|
|
|
|
return (char*)base + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// ========================================================================
|
2025-12-12 06:52:14 +09:00
|
|
|
// Slow path: need new page via ColdIface
|
2025-12-12 19:19:25 +09:00
|
|
|
// ========================================================================
|
2025-12-12 07:12:24 +09:00
|
|
|
SmallPageMeta_MID_v3 *page = small_cold_mid_v3_refill_page(class_idx);
|
2025-12-12 06:52:14 +09:00
|
|
|
if (!page) {
|
|
|
|
|
// Fallback to legacy or return NULL
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update TLS cache
|
|
|
|
|
ctx->page[class_idx] = page->ptr;
|
|
|
|
|
ctx->offset[class_idx] = 1; // First slot already allocated
|
2025-12-12 19:19:25 +09:00
|
|
|
ctx->capacity[class_idx] = mid_v35_slots_per_page(class_idx);
|
2025-12-12 06:52:14 +09:00
|
|
|
ctx->meta[class_idx] = page;
|
|
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// Step 2: HOT_COUNTS gate - Record first allocation in page metadata
|
|
|
|
|
if (mid_v35_hot_counts_enabled()) {
|
|
|
|
|
page->alloc_count = 1;
|
|
|
|
|
}
|
2025-12-12 06:52:14 +09:00
|
|
|
|
2025-12-12 19:19:25 +09:00
|
|
|
// Step 1: HEADER_PREFILL gate - Write header for first slot if not prefilled
|
|
|
|
|
if (!mid_v35_header_prefill_enabled()) {
|
|
|
|
|
tiny_region_id_write_header(page->ptr, class_idx);
|
|
|
|
|
}
|
2025-12-12 06:52:14 +09:00
|
|
|
|
|
|
|
|
// Return first slot (USER pointer)
|
|
|
|
|
return (char*)page->ptr + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// Free (Simplified: just count, no freelist yet)
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void small_mid_v35_free(void *ptr, uint32_t class_idx) {
|
|
|
|
|
if (!ptr || class_idx < 5 || class_idx > 7) return;
|
|
|
|
|
|
|
|
|
|
// For v11a-3: simplified free (just increment free_count)
|
|
|
|
|
// In future phases: implement freelist for reuse
|
|
|
|
|
|
|
|
|
|
// Calculate BASE from USER pointer
|
|
|
|
|
void *base = (char*)ptr - 1;
|
|
|
|
|
|
|
|
|
|
// Find page metadata via simple calculation
|
|
|
|
|
// Note: Assumes 64KB pages aligned to 64KB boundary
|
|
|
|
|
size_t page_size = 64 * 1024; // 64KB
|
|
|
|
|
void *page_base = (void*)((uintptr_t)base & ~(page_size - 1));
|
|
|
|
|
|
|
|
|
|
// Check if this is the current TLS page
|
|
|
|
|
SmallMidV35TlsCtx *ctx = &tls_mid_v35_ctx;
|
2025-12-12 07:12:24 +09:00
|
|
|
SmallPageMeta_MID_v3 *meta = ctx->meta[class_idx];
|
2025-12-12 06:52:14 +09:00
|
|
|
|
|
|
|
|
if (meta && meta->ptr == page_base) {
|
|
|
|
|
// Free to current TLS page
|
|
|
|
|
meta->free_count++;
|
|
|
|
|
|
|
|
|
|
// Check if page is fully empty
|
|
|
|
|
if (meta->free_count >= meta->capacity) {
|
|
|
|
|
// Retire page via ColdIface
|
|
|
|
|
small_cold_mid_v3_retire_page(meta);
|
|
|
|
|
|
|
|
|
|
// Clear TLS cache for this class
|
|
|
|
|
ctx->page[class_idx] = NULL;
|
|
|
|
|
ctx->offset[class_idx] = 0;
|
|
|
|
|
ctx->meta[class_idx] = NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Different page: need RegionIdBox lookup
|
|
|
|
|
// For v11a-3: simple fallback - just count the free
|
|
|
|
|
// Real implementation needs proper page lookup
|
|
|
|
|
// TODO: Implement cross-page free via RegionIdBox in v11b
|
|
|
|
|
}
|
|
|
|
|
}
|