diff options
Diffstat (limited to 'src/platform')
-rw-r--r-- | src/platform/3ds.c | 58 | ||||
-rw-r--r-- | src/platform/3ds.mk | 2 | ||||
-rw-r--r-- | src/platform/linux.c | 158 |
3 files changed, 216 insertions, 2 deletions
diff --git a/src/platform/3ds.c b/src/platform/3ds.c index 5683422..5566121 100644 --- a/src/platform/3ds.c +++ b/src/platform/3ds.c @@ -6,6 +6,7 @@ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> /** * These cache-size details are from @@ -16,6 +17,16 @@ size_t get_l1d_size(void) { return 16 * 1024; } size_t get_l3_size(void) { return 2 * 1024 * 1024; } +uintptr_t alloc_gc_region(size_t size) { + void *ptr = malloc(size); + assume(ptr != NULL); + return (uintptr_t)ptr; +} + +void clear_gc_region(uintptr_t addr, size_t size) { + memset((void *)addr, 0, size); +} + void panic_begin(void) { consoleInit(GFX_TOP, NULL); } noreturn void panic_end(void) { @@ -35,6 +46,51 @@ noreturn void panic_end(void) { exit(1); } +static void gc_test(void) { + gc_debug(); + + const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM}; + + struct object *values = gc_alloc(64, 0); + struct object *value_slot_counts = gc_alloc(64, 0); + gc_root_push(&values); + gc_root_push(&value_slot_counts); + + for (size_t i = 0; i < 10000000; i++) { + if ((rand() & 0b11) == 0) { + size_t value_slot_count = rand() & 63; + if (!value_slot_count) + value_slot_count = 1; + size_t untraced_slot_count = rand() & 63; + struct value value = + alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count); + size_t i = rand() % 63; + gc_write_value_slot(values, i, value); + gc_write_value_slot(value_slot_counts, i, + integer_of_int(value_slot_count)); + } else { + size_t i = rand() & 63; + struct value value = gc_read_value_slot(values, i); + struct value value_slot_count_value = + gc_read_value_slot(value_slot_counts, i); + if (!value.bits) + continue; + assume(get_tag(value) == TAG_BUILTIN_OBJECT); + assume(get_tag(value_slot_count_value) == TAG_FIXNUM); + struct object *obj = untag_ptr(value); + intptr_t value_slot_count = untag_fixnum(value_slot_count_value); + size_t j = rand() % value_slot_count; + size_t k = rand() % 63; + gc_write_value_slot(obj, j, gc_read_value_slot(values, k)); + } + } + + gc_root_pop(); + gc_root_pop(); + + gc_debug(); +} + int main(int argc, char **argv) { gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false); @@ -66,7 +122,7 @@ int main(int argc, char **argv) { if (kDown & KEY_START) break; // break in order to return to hbmenu if (kDown & KEY_A) - todo("GM"); + gc_test(); circlePosition pos; hidCircleRead(&pos); diff --git a/src/platform/3ds.mk b/src/platform/3ds.mk index cbe7e0b..0b0d2f2 100644 --- a/src/platform/3ds.mk +++ b/src/platform/3ds.mk @@ -15,4 +15,4 @@ all: imb3.3dsx .PHONY: 3dslink imb3.3dsx: imb3.elf - 3dsxtool $< $@ + $(DEVKITPRO)/../../bin/3dsxtool $< $@ diff --git a/src/platform/linux.c b/src/platform/linux.c index e69de29..3305869 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -0,0 +1,158 @@ +#define _GNU_SOURCE +#include "../gc.h" +#include "../platform.h" +#include "../util.h" +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +int main(int argc, char **argv) { + // As a test of the garbage collector, we're doing a bunch of random + // mutations. + gc_init(); + srand(0); + gc_debug(); + + const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM}; + + struct object *values = gc_alloc(64, 0); + struct object *value_slot_counts = gc_alloc(64, 0); + gc_root_push(&values); + gc_root_push(&value_slot_counts); + + for (size_t i = 0; i < 1000000; i++) { + if ((rand() & 0b11) == 0) { + size_t value_slot_count = 3; + if (!value_slot_count) + value_slot_count = 1; + size_t untraced_slot_count = rand() & 255; + struct value value = + alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count); + size_t i = rand() % 63; + gc_write_value_slot(values, i, value); + gc_write_value_slot(value_slot_counts, i, + integer_of_int(value_slot_count)); + } else { + size_t i = rand() & 63; + struct value value = gc_read_value_slot(values, i); + struct value value_slot_count_value = + gc_read_value_slot(value_slot_counts, i); + if (!value.bits) + continue; + assume(get_tag(value) == TAG_BUILTIN_OBJECT); + assume(get_tag(value_slot_count_value) == TAG_FIXNUM); + struct object *obj = untag_ptr(value); + intptr_t value_slot_count = untag_fixnum(value_slot_count_value); + size_t j = rand() % value_slot_count; + size_t k = rand() % 63; + gc_write_value_slot(obj, j, gc_read_value_slot(values, k)); + } + } + + gc_debug(); + return 0; +} + +void panic_begin(void) {} +noreturn void panic_end(void) { abort(); } + +static size_t read_cache_size(const char *path) { + int fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd == -1) + fprintf(stderr, "open %s: %s\n", path, strerror(errno)), abort(); + + char buf[4096]; + size_t len = 0; + for (;;) { + ssize_t ret = read(fd, &buf[len], sizeof(buf) - len); + if (ret == 0) + break; + else if (ret < 0 && errno == EINTR) + continue; + else if (ret < 0) + fprintf(stderr, "read %s: %s\n", path, strerror(errno)), abort(); + else + len += ret; + } + + if (close(fd)) + fprintf(stderr, "close %s: %s\n", path, strerror(errno)), abort(); + + size_t i = 0, out = 0; + while (i < len) { + char ch = buf[i]; + if ('0' <= ch && ch <= '9') { + out = 10 * out + (ch - '0'); + i++; + } else { + break; + } + } + if (i < len) { + char ch = buf[i]; + if (ch == 'K') { + out *= 1024; + i++; + } else if (ch == 'M') { + out *= 1024 * 1024; + i++; + } + } + if (i < len && buf[i] == '\n') + i++; + if (i != len) { + fprintf(stderr, "invalid cache size in %s: [", path); + for (size_t j = 0; j < len; j++) { + fprintf(stderr, "%s", i == j ? "|" : j ? " " : ""); + char ch = buf[j]; + if (' ' <= ch && ch <= '~' && ch != '\'' && ch != '\\') + fprintf(stderr, "'%c'", ch); + else if (ch == '\n') + fprintf(stderr, "'\\n'"); + else if (ch == '\'') + fprintf(stderr, "\"'\""); + else if (ch == '\\') + fprintf(stderr, "'\\\\'"); + else + fprintf(stderr, "%02hhx", buf[j]); + } + fprintf(stderr, "]\n"); + abort(); + } + + return out; +} + +size_t get_l1d_size(void) { + return read_cache_size("/sys/devices/system/cpu/cpu0/cache/index0/size"); +} + +size_t get_l3_size(void) { + return read_cache_size("/sys/devices/system/cpu/cpu0/cache/index2/size"); +} + +uintptr_t alloc_gc_region(size_t size) { + static uintptr_t base_ptr = 0x10000; + static size_t page_size = 0; + if (!page_size) + page_size = sysconf(_SC_PAGE_SIZE); + + void *ptr = mmap((void *)base_ptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + perror("alloc_gc_region"), exit(111); + base_ptr = + (((uintptr_t)ptr + size + page_size - 1) & ~(page_size - 1)) + page_size; + return (uintptr_t)ptr; +} + +void clear_gc_region(uintptr_t addr, size_t size) { + void *new_ptr = mmap((void *)addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (new_ptr == MAP_FAILED) + perror("clear_gc_region"), exit(111); +} |