summaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/3ds.c58
-rw-r--r--src/platform/3ds.mk2
-rw-r--r--src/platform/linux.c158
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);
+}