#include #include #include /* Custom Memory Allocator Implementacion custom de un memory allocator que opera sobre un array de bytes usandolo como "heap" */ #define JLANG_OK 0 #define JLANG_ERR 1 #define JLANG_FREE 0 #define JLANG_HEADER 1 #define JLANG_PAYLOAD 2 /* La estructura de Metadata se encarga de almacenar el tamaño del bloque y si está en uso. Se añadirá al principio de cada bloque [BLOCK_METADATA] + [BLOCK_BYTES] */ typedef struct { size_t size; // 8 bytes int in_use; // 4 bytes // --- aquí el compilador mete 4 bytes invisibles --- } JLANG_metadata; /* La estructura de Memory Allocator se encarga de almancenar el array de memoria y el tamaño de esta. */ typedef struct { char *memory; // 8 bytes size_t size; // 8 bytes } JLANG_memory_allocator; void *JLANG_CreateAllocator() { // Allocate memory in heap for JLANG_memory_allocator JLANG_memory_allocator *allocator = (JLANG_memory_allocator *)malloc(sizeof(JLANG_memory_allocator)); // Assign default free bytes allocator->memory = (char *)malloc(1 * 1024); allocator->size = 1 * 1024; // ensure all memory is zero for (int i = 0; i < 1 * 1024; i++) { allocator->memory[i] = 0; } return allocator; } size_t JLANG_used(void *ptr) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; // Iterate memory parsing only metadata JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory; size_t used = 0; while (currentHeader->size != 0 && used < allocPtr->size) { used += sizeof(JLANG_metadata) + currentHeader->size; // Current block is in_use, jump to next block currentHeader = (JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) + currentHeader->size); } return used; } void *JLANG_last_free(void *ptr) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; // Iterate memory parsing only metadata JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory; size_t used = 0; while (currentHeader->size != 0 && used < allocPtr->size) { used += sizeof(JLANG_metadata) + currentHeader->size; // Current block is in_use, jump to next block currentHeader = (JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) + currentHeader->size); } return currentHeader; } // JLANG_malloc devuelve un offset a la memoria del heap. No un absoluto a la // memoria del proceso size_t JLANG_malloc(void *ptr, size_t size) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; // 1. Hay bloques disponibles?? size_t used = JLANG_used(ptr); size_t available = allocPtr->size - used; // chequear si hay suficiente espacio libre if (available > size + sizeof(JLANG_metadata)) { JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr); freeHeader->size = size; freeHeader->in_use = 1; void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata); return (char *)payloadPtr - allocPtr->memory; } /* Se necesita más espacio.. De momento vamos a pedir otro array más grande y liberar el antiguo Mantenemos toda la memoria contigua */ int newSize = allocPtr->size + 1024; char *newBuffer = (char *)malloc(newSize); // Otro 1KB memset(newBuffer, 0, newSize); memcpy(newBuffer, allocPtr->memory, allocPtr->size); // Copiamos al nuevo buffer allocPtr->size = newSize; free(allocPtr->memory); // Liberamos el buffer antiguo allocPtr->memory = newBuffer; // Seteamos el nuevo buffer JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr); freeHeader->size = size; freeHeader->in_use = 1; void *payloadPtr = (char *) freeHeader + sizeof(JLANG_metadata); return (char *)payloadPtr - allocPtr->memory; } void JLANG_free(void *ptr, size_t blockOffset) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; // Get block header void *blockPtr = allocPtr->memory + blockOffset; JLANG_metadata *blockHeader = (JLANG_metadata *)((char *)blockPtr - sizeof(JLANG_metadata)); // Set block as not_used blockHeader->in_use = 0; } /* Debug Visualization [FF FF FF FF FF FF FF ] */ int _ceil(float v) { int n = (int)v; float r = v - n; if (r > 0) { return n + 1; } return n; } void JLANG_visualize(void *ptr) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; // Step 1. Get byte type char *byteMapPtr = (char *)malloc(allocPtr->size); memset(byteMapPtr, 0, allocPtr->size); JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory; long used = 0; while (used < allocPtr->size) { long blockIndex = (char *)currentHeader - (char *)allocPtr->memory; used += sizeof(JLANG_metadata) + currentHeader->size; /* HEADER blockIndex + sizeof(JLANG_metadata) */ if (currentHeader->size > 0) { byteMapPtr[blockIndex] = JLANG_HEADER; for (int i = 0; i < sizeof(JLANG_metadata); i++) { byteMapPtr[blockIndex + i] = JLANG_HEADER; } /* PAYLOAD */ for (int i = 0; i < currentHeader->size; i++) { byteMapPtr[blockIndex + sizeof(JLANG_metadata) + i] = JLANG_PAYLOAD; } } else { break; } // Jump to next block currentHeader = (JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) + currentHeader->size); } // Step 2. Draw int bytePerRow = 40; int totalRows = _ceil(allocPtr->size / bytePerRow); printf("totalRows=%d\n", totalRows); char *currentMemPtr = allocPtr->memory; for (int i = 0; i < totalRows; i++) { printf("["); for (int n = 0; n < bytePerRow; n++) { int index = n + i * bytePerRow; switch (byteMapPtr[index]) { case JLANG_HEADER: printf("\033[46m"); break; case JLANG_FREE: printf("\033[32m"); break; default: printf("\033[41m"); break; } printf("%.2x", (unsigned char)*(currentMemPtr + (n + i * bytePerRow))); if (n < bytePerRow - 1) { printf(" "); } printf("\033[0m"); } printf("]\n"); } }