Introduce libc/mem/tinymalloc.inc

This allocator shaves ~20kb off single-threaded tool programs and is
slightly faster than proper malloc for simple non-demanding programs
pull/1171/head
Justine Tunney 2024-05-07 00:37:41 -07:00
parent 3bf95ae7ec
commit a6ecbb747d
No known key found for this signature in database
GPG Key ID: BE714B4575D6E328
17 changed files with 201 additions and 37 deletions

View File

@ -8,6 +8,7 @@ LIBC_MEM = $(LIBC_MEM_A_DEPS) $(LIBC_MEM_A)
LIBC_MEM_A = o/$(MODE)/libc/mem/mem.a
LIBC_MEM_A_FILES := $(wildcard libc/mem/*)
LIBC_MEM_A_HDRS = $(filter %.h,$(LIBC_MEM_A_FILES))
LIBC_MEM_A_INCS = $(filter %.inc,$(LIBC_MEM_A_FILES))
LIBC_MEM_A_SRCS = $(filter %.c,$(LIBC_MEM_A_FILES))
LIBC_MEM_A_OBJS = $(LIBC_MEM_A_SRCS:%.c=o/$(MODE)/%.o)
@ -46,6 +47,7 @@ $(LIBC_MEM_A_OBJS): private \
LIBC_MEM_LIBS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)))
LIBC_MEM_SRCS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_SRCS))
LIBC_MEM_HDRS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_HDRS))
LIBC_MEM_INCS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_INCS))
LIBC_MEM_BINS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_BINS))
LIBC_MEM_CHECKS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_CHECKS))
LIBC_MEM_OBJS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_OBJS))

160
libc/mem/tinymalloc.inc Normal file
View File

@ -0,0 +1,160 @@
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#ifndef MODE_DBG /* don't interfere with asan dlmalloc hooking */
_Alignas(65536) static struct {
char memory[1024 * 1024 * 1024];
unsigned used, last, free;
} heap;
static inline bool isheap(char *mem) {
return heap.memory <= mem && mem < heap.memory + heap.used;
}
void free(void *ptr) {
char *mem;
unsigned base;
if (ptr) {
mem = (char *)ptr;
unassert(isheap(mem));
base = mem - heap.memory;
*(unsigned *)mem = heap.free;
heap.free = base;
}
}
size_t malloc_usable_size(void *ptr) {
char *mem = (char *)ptr;
unassert(isheap(mem));
return ((unsigned *)mem)[-1];
}
void *memalign(size_t align, size_t need) {
char *res;
unsigned next, next2, base, toto, *link, *link2;
// normalize arguments
while (align & (align - 1))
++align;
if (need < sizeof(unsigned))
need = sizeof(unsigned);
if (align < sizeof(unsigned))
align = sizeof(unsigned);
if (align > 65536)
goto InvalidArgument;
if (ckd_add(&need, need, sizeof(unsigned) - 1))
goto OutOfMemory;
need &= -sizeof(unsigned);
// allocate from free list
next = heap.free;
link = &heap.free;
while (next) {
next2 = *(unsigned *)(heap.memory + next);
link2 = (unsigned *)(heap.memory + next);
if (need <= ((unsigned *)(heap.memory + next))[-1]) {
*link = next2;
return (void *)(heap.memory + next);
}
next = next2;
link = link2;
}
// allocate new static memory
base = heap.used;
base += sizeof(unsigned);
base += align - 1;
base &= -align;
if (ckd_add(&toto, base, need))
goto OutOfMemory;
if (toto > sizeof(heap.memory))
goto OutOfMemory;
res = heap.memory + base;
((unsigned *)res)[-1] = need;
heap.used = toto;
heap.last = base;
return res;
// we require more vespene gas
OutOfMemory:
errno = ENOMEM;
return 0;
InvalidArgument:
errno = EINVAL;
return 0;
}
void *malloc(size_t need) {
return memalign(sizeof(max_align_t), need);
}
void *calloc(size_t count, size_t size) {
char *res;
unsigned need, used;
if (ckd_mul(&need, count, size))
need = -1;
used = heap.used;
if ((res = (char *)malloc(need)))
if (res - heap.memory < used)
bzero(res, need);
return res;
}
void *realloc(void *ptr, size_t need) {
char *res, *mem;
unsigned base, have, toto;
if (!ptr) {
res = (char *)malloc(need);
} else {
mem = (char *)ptr;
unassert(isheap(mem));
have = ((unsigned *)mem)[-1];
base = mem - heap.memory;
if (need < have) {
res = mem;
} else if (base == heap.last) {
if (need < sizeof(unsigned))
need = sizeof(unsigned);
if (ckd_add(&need, need, sizeof(unsigned) - 1))
goto OutOfMemory;
need &= -sizeof(unsigned);
if (ckd_add(&toto, base, need))
goto OutOfMemory;
if (toto > sizeof(heap.memory))
goto OutOfMemory;
((unsigned *)mem)[-1] = need;
heap.used = toto;
res = mem;
} else if ((res = (char *)malloc(need))) {
if (have > need)
have = need;
memcpy(res, mem, have);
free(mem);
}
}
return res;
OutOfMemory:
errno = ENOMEM;
return 0;
}
#endif /* MODE_DBG */

View File

@ -259,6 +259,8 @@ static Elf64_Xword notesize;
static char *r_off32_e_lfanew;
#include "libc/mem/tinymalloc.inc"
static wontreturn void Die(const char *thing, const char *reason) {
tinyprint(2, thing, ": ", reason, "\n", NULL);
exit(1);

View File

@ -67,6 +67,8 @@
#define FORMAT_MACHO 2
#define FORMAT_PE 3
#include "libc/mem/tinymalloc.inc"
static int g_arch;
static int g_format;
static bool g_force;

View File

@ -226,6 +226,8 @@ const char *const kSafeEnv[] = {
"SYSTEMROOT", // needed by socket()
};
#include "libc/mem/tinymalloc.inc"
void OnAlrm(int sig) {
++gotalrm;
}

View File

@ -69,6 +69,8 @@ char linkbuf[PATH_MAX];
void Cp(char *, char *);
#include "libc/mem/tinymalloc.inc"
bool IsDirectory(const char *path) {
int e;
bool res;

View File

@ -158,6 +158,8 @@ static const char *stubpath;
static long FLAG_SizeOfStackCommit = 64 * 1024;
static long FLAG_SizeOfStackReserve = 8 * 1024 * 1024;
#include "libc/mem/tinymalloc.inc"
static wontreturn void Die(const char *thing, const char *reason) {
tinyprint(2, thing, ": ", reason, "\n", NULL);
exit(1);

View File

@ -67,6 +67,8 @@ static Elf64_Ehdr *elf;
static const char *epath;
static Elf64_Xword symcount;
#include "libc/mem/tinymalloc.inc"
static wontreturn void Die(const char *reason) {
tinyprint(2, epath, ": ", reason, "\n", NULL);
exit(1);

View File

@ -71,6 +71,8 @@ const char *prog;
char databuf[32768];
char pathbuf[PATH_MAX];
#include "libc/mem/tinymalloc.inc"
wontreturn void PrintUsage(int rc, FILE *f) {
fputs("usage: ", f);
fputs(prog, f);

View File

@ -50,6 +50,8 @@ static const char *prog;
static char16_t **filters;
static uint32_t pids[10000];
#include "libc/mem/tinymalloc.inc"
static wontreturn void PrintUsage(int rc, FILE *f) {
fprintf(f,
"Usage: %s [-nshv] NAME...\n"

View File

@ -146,6 +146,8 @@ static const char *buildroot;
static const char *genroot;
static const char *outpath;
#include "libc/mem/tinymalloc.inc"
static inline bool IsBlank(int c) {
return c == ' ' || c == '\t';
}

View File

@ -62,6 +62,8 @@ char linkbuf[PATH_MAX];
void Mv(char *, char *);
#include "libc/mem/tinymalloc.inc"
wontreturn void Die(const char *path, const char *reason) {
tinyprint(2, path, ": ", reason, "\n", NULL);
exit(1);

View File

@ -43,8 +43,6 @@
#include "third_party/xed/x86.h"
#include "tool/build/lib/getargs.h"
__static_yoink("realloc");
/**
* @fileoverview Build Package Script.
*
@ -153,6 +151,8 @@ struct Relas {
} *p;
} prtu;
#include "libc/mem/tinymalloc.inc"
static wontreturn void Die(const char *path, const char *reason) {
tinyprint(2, path, ": ", reason, "\n", NULL);
exit(1);

View File

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/serialize.h"
#include "libc/limits.h"
#include "libc/nt/struct/imageimportbyname.internal.h"
#include "libc/nt/struct/imageimportdescriptor.internal.h"
@ -25,6 +24,7 @@
#include "libc/nt/struct/imageoptionalheader.internal.h"
#include "libc/nt/struct/imagesectionheader.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdckdint.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"

View File

@ -20,6 +20,7 @@
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdio/sysparam.h"
@ -32,6 +33,8 @@ const char *FLAG_prefix;
const char *FLAG_suffix;
const char *path;
#include "libc/mem/tinymalloc.inc"
wontreturn void PrintUsage(int fd, int exitcode) {
tinyprint(fd, "\n\
NAME\n\
@ -74,42 +77,17 @@ wontreturn void DieOom(void) {
Die("out of memory");
}
struct {
char *last;
size_t used;
union {
char memory[1024 * 1024 * 1024];
size_t align;
};
} heap;
void *Malloc(size_t need) {
if (need <= sizeof(heap.memory)) {
int align = sizeof(size_t);
size_t base = heap.used;
base += align - 1;
base &= -align;
size_t toto = base + sizeof(size_t) + need;
if (toto >= heap.used && toto <= sizeof(heap.memory)) {
char *res = heap.memory + base;
*(size_t *)res = need;
heap.used = toto;
return res + sizeof(size_t);
}
}
DieOom();
static void *Malloc(size_t n) {
void *p;
if (!(p = malloc(n)))
DieOom();
return p;
}
void *Realloc(void *ptr, size_t need) {
if (ptr == heap.last) {
heap.used = (char *)ptr - heap.memory;
return Malloc(need);
} else {
void *res = Malloc(need);
size_t size = *(size_t *)((char *)ptr - sizeof(size_t));
memcpy(res, ptr, MIN(need, size));
return res;
}
static void *Realloc(void *p, size_t n) {
if (!(p = realloc(p, n)))
DieOom();
return p;
}
void ProcessFile(void) {

View File

@ -48,6 +48,8 @@ static bool recursive;
static bool doemptydirs;
static const char *prog;
#include "libc/mem/tinymalloc.inc"
static wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "USAGE\n\n ", prog, USAGE, NULL);
exit(rc);

View File

@ -30,6 +30,8 @@
* @fileoverview elf to symbol table file dump tool
*/
#include "libc/mem/tinymalloc.inc"
void PrintUsage(FILE *f) {
fprintf(f, "%s%s%s\n", "usage: ", program_invocation_name,
" [-?h] -o PATH COMDBG");