Rewrite Cosmopolitan Ar

The build/bootstrap/ar.com program is now tinier. This change reduces
its size from 140kb to 53kb. Nothing was traded away. Cosmopolitan Ar
performance is now 2x better than llvm-ar largely thanks to using the
copy_file_range() system call. This change homebrews a new allocation
API that addresses the shortcomings of the C standard library design.
Using these new balloc() and reballoc() functions I managed to reduce
memory consumption so much that Cosmpolitan Ar should now use roughly
100x fewer bytes of peak resident memory compared to llvm-ar. Correct
behavior with better compatibility has been assured. Binary output is
now pretty much bit-identical to llvm-ar, as of this change. This can
and should be the living proof we need to show that a better world is
possible for software.
This commit is contained in:
Justine Tunney 2023-07-02 10:19:16 -07:00
parent 197aa0d465
commit 0c630d95b5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
27 changed files with 916 additions and 341 deletions

View file

@ -16,17 +16,20 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "tool/build/lib/getargs.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#include "tool/build/lib/getargs.h"
/**
* @fileoverview Fast Command Line Argument Ingestion.
@ -72,6 +75,13 @@
#define IsSpace(c) ((255 & (c)) <= ' ')
static wontreturn void getargs_fail(const char *path, const char *reason) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "Unknown error";
tinyprint(2, path, ": ", reason, ": ", errstr, "\n", NULL);
exit(1);
}
/**
* Zeroes GetArgs object and sets its fields.
* @param args is borrowed for the lifetime of the GetArgs object
@ -86,7 +96,9 @@ void getargs_init(struct GetArgs *ga, char **args) {
* Releases memory associated with GetArgs object and zeroes it.
*/
void getargs_destroy(struct GetArgs *ga) {
if (ga->map) munmap(ga->map, ga->mapsize);
if (ga->map) {
if (munmap(ga->map, ga->mapsize)) notpossible;
}
bzero(ga, sizeof(*ga));
}
@ -106,8 +118,8 @@ const char *getargs_next(struct GetArgs *ga) {
char *p;
size_t k;
unsigned m;
struct stat st;
do {
ssize_t size;
for (;;) {
if (ga->map) {
for (; ga->j < ga->mapsize; ++ga->j) {
if (!IsSpace(ga->map[ga->j])) {
@ -134,36 +146,39 @@ const char *getargs_next(struct GetArgs *ga) {
break;
}
}
if (k) {
if (ga->j + k < ga->mapsize) {
ga->map[ga->j + k] = 0;
p = ga->map + ga->j;
ga->j += ++k;
return p;
} else {
eio();
break;
}
if (k && ga->j + k < ga->mapsize) {
ga->map[ga->j + k] = 0;
p = ga->map + ga->j;
ga->j += ++k;
return p;
}
if (munmap(ga->map, ga->mapsize) == -1) break;
if (munmap(ga->map, ga->mapsize)) notpossible;
ga->map = 0;
ga->mapsize = 0;
ga->j = 0;
}
if (!(p = ga->args[ga->i])) return 0;
++ga->i;
if (*p != '@') return p;
++p;
if ((fd = open((ga->path = p), O_RDONLY)) != -1) {
fstat(fd, &st);
if ((p = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd,
0)) != MAP_FAILED) {
ga->map = p;
ga->mapsize = st.st_size;
}
close(fd);
if (!(p = ga->args[ga->i])) {
return 0;
}
} while (ga->map);
perror(ga->path);
exit(1);
++ga->i;
if (*p != '@') {
return p;
}
++p;
if ((fd = open((ga->path = p), O_RDONLY)) == -1) {
getargs_fail(ga->path, "open");
}
if ((size = lseek(fd, 0, SEEK_END)) == -1) {
getargs_fail(ga->path, "lseek");
}
if (size) {
p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED) {
getargs_fail(ga->path, "mmap");
}
ga->map = p;
ga->mapsize = ROUNDUP(size, 4096);
}
close(fd);
}
}