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
This commit is contained in:
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 = o/$(MODE)/libc/mem/mem.a
LIBC_MEM_A_FILES := $(wildcard libc/mem/*) LIBC_MEM_A_FILES := $(wildcard libc/mem/*)
LIBC_MEM_A_HDRS = $(filter %.h,$(LIBC_MEM_A_FILES)) 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_SRCS = $(filter %.c,$(LIBC_MEM_A_FILES))
LIBC_MEM_A_OBJS = $(LIBC_MEM_A_SRCS:%.c=o/$(MODE)/%.o) 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_LIBS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)))
LIBC_MEM_SRCS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_SRCS)) LIBC_MEM_SRCS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_SRCS))
LIBC_MEM_HDRS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_HDRS)) 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_BINS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_BINS))
LIBC_MEM_CHECKS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_CHECKS)) LIBC_MEM_CHECKS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_CHECKS))
LIBC_MEM_OBJS = $(foreach x,$(LIBC_MEM_ARTIFACTS),$($(x)_OBJS)) 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; static char *r_off32_e_lfanew;
#include "libc/mem/tinymalloc.inc"
static wontreturn void Die(const char *thing, const char *reason) { static wontreturn void Die(const char *thing, const char *reason) {
tinyprint(2, thing, ": ", reason, "\n", NULL); tinyprint(2, thing, ": ", reason, "\n", NULL);
exit(1); exit(1);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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