summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-11-18 00:34:23 -0600
committerNathan Ringo <nathan@remexre.com>2024-11-18 00:34:23 -0600
commit943a6597b2bcd1b3ed208458a5cba61ad5b4051c (patch)
treed0acf34996941417aca241f5f01e399aaa90af39 /src
parent57331ba9756df043b5c665aa4952a0a7b38799e5 (diff)
...
Diffstat (limited to 'src')
-rw-r--r--src/Makefile6
-rw-r--r--src/gc.h14
-rw-r--r--src/gc/gc-debug.c0
-rw-r--r--src/gc/gc.c99
-rw-r--r--src/main.c5
-rw-r--r--src/platform.h13
-rw-r--r--src/platform/3ds.c33
-rw-r--r--src/util.c37
-rw-r--r--src/value.c111
-rw-r--r--src/value.h12
10 files changed, 263 insertions, 67 deletions
diff --git a/src/Makefile b/src/Makefile
index 432b331..07f1cb5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -12,7 +12,7 @@ LDFLAGS =
CC = $(DEVKITPRO)/devkitARM/bin/arm-none-eabi-gcc
-CFLAGS_AUTO = -D__3DS__ -ffunction-sections -flto -g -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -mword-relocations -Og -std=c11 -Wall -Werror=implicit-function-declaration
+CFLAGS_AUTO = -D__3DS__ -ffunction-sections -flto -g -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -mword-relocations -O3 -std=c11 -Wall -Werror=implicit-function-declaration
LDFLAGS_AUTO = -L$(DEVKITPRO)/libctru/lib -specs=3dsx.specs
LDLIBS_AUTO = -lctru -lm
@@ -38,9 +38,7 @@ all: imb3.3dsx
imb3.3dsx: imb3.elf
3dsxtool $< $@
-imb3.elf: $(OBJS) obj/gc/gc.o
- $(CC) $(CFLAGS_ALL) $(LDFLAGS_ALL) -o $@ $^ $(LDLIBS_ALL)
-imb3-debug.elf: $(OBJS) obj/gc/gc-debug.o
+imb3.elf: $(OBJS) obj/gc/gc.o obj/platform/3ds.o
$(CC) $(CFLAGS_ALL) $(LDFLAGS_ALL) -o $@ $^ $(LDLIBS_ALL)
obj/%.o: $(srcdir)/%.c
diff --git a/src/gc.h b/src/gc.h
index dff3b79..d7ce8b0 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -2,15 +2,21 @@
#define IMB3_GC_H
#include "value.h"
-#include <stddef.h>
void gc_init(void);
void gc_collect(void);
struct object;
-struct value gc_read_value_slot(struct object *, size_t);
-uintptr_t gc_read_untraced_slot(struct object *, size_t);
-uint8_t gc_read_untraced_byte(struct object *, size_t);
+
+struct object *gc_alloc(size_t value_slot_count, size_t untraced_slot_count);
+struct object *gc_alloc_compiled_function(size_t value_slot_count,
+ size_t untraced_slot_count);
+struct object *gc_alloc_hashtable_eq(size_t value_slot_count,
+ size_t untraced_slot_count);
+
+struct value gc_read_value_slot(const struct object *, size_t);
+uintptr_t gc_read_untraced_slot(const struct object *, size_t);
+uint8_t gc_read_untraced_byte(const struct object *, size_t);
void gc_write_value_slot(struct object *, size_t, struct value);
void gc_write_untraced_slot(struct object *, size_t, uintptr_t);
void gc_write_untraced_byte(struct object *, size_t, uint8_t);
diff --git a/src/gc/gc-debug.c b/src/gc/gc-debug.c
deleted file mode 100644
index e69de29..0000000
--- a/src/gc/gc-debug.c
+++ /dev/null
diff --git a/src/gc/gc.c b/src/gc/gc.c
index f53fd79..1c0daec 100644
--- a/src/gc/gc.c
+++ b/src/gc/gc.c
@@ -1,18 +1,12 @@
+#include "../gc.h"
+#include "../platform.h"
#include "../util.h"
#include <stdbool.h>
#include <stddef.h>
-#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
/**
- * These cache-size details are from
- * https://www.copetti.org/writings/consoles/nintendo-3ds/. We call the second
- * level of cache (only available on N3DS) L3, since this GC design only cares
- * about L1D and L3.
- */
-static const size_t L1D_SIZE = 16 * 1024, L3_SIZE = 2 * 1024 * 1024;
-
-/**
* Constants that should probably be learned.
*/
static const size_t NURSERY_L1D_SIZE_FACTOR = 1;
@@ -43,19 +37,19 @@ enum object_kind {
OBJECT_UNTRACED,
/**
+ * A wrapper for a pointer to a code address. When this object gets collected,
+ * calls `free_code` on its first untraced slot.
+ */
+ OBJECT_COMPILED_FUNCTION,
+
+ /**
* A hashtable keyed by the addresses. This behaves like a normal object, but
* the first untraced slot gets set to the `uintptr_t` 1 whenever a collection
* traces the hashtable.
*
* The hashtable uses this information to rehash after each collection.
*/
- OBJECT_EQ_HASHTABLE,
-
- /**
- * A wrapper for a pointer to a code address. When this object gets collected,
- * calls `free_code` on its first untraced slot.
- */
- OBJECT_COMPILED_FUNCTION,
+ OBJECT_HASHTABLE_EQ,
};
/**
@@ -72,11 +66,11 @@ struct object_size {
/**
* Returns the number of slots for values the object has.
*/
-static size_t object_value_slots(struct object_size size) {
+static size_t object_size_value_slots(struct object_size size) {
switch (size.kind) {
case OBJECT_NORMAL:
- case OBJECT_EQ_HASHTABLE:
case OBJECT_COMPILED_FUNCTION:
+ case OBJECT_HASHTABLE_EQ:
return size.bits >> ((4 * sizeof(size_t)) - 3);
case OBJECT_UNTRACED:
return 0;
@@ -86,11 +80,11 @@ static size_t object_value_slots(struct object_size size) {
/**
* Returns the number of untraced slots the object has.
*/
-static size_t object_untraced_slots(struct object_size size) {
+static size_t object_size_untraced_slots(struct object_size size) {
switch (size.kind) {
case OBJECT_NORMAL:
- case OBJECT_EQ_HASHTABLE:
case OBJECT_COMPILED_FUNCTION:
+ case OBJECT_HASHTABLE_EQ:
return size.bits & ((1 << ((4 * sizeof(size_t)) - 3)) - 1);
case OBJECT_UNTRACED:
return size.bits;
@@ -106,6 +100,20 @@ struct object {
};
/**
+ * Returns the number of slots for values the object has.
+ */
+static size_t object_value_slots(const struct object *obj) {
+ return object_size_value_slots(((struct object_size *)obj)[-1]);
+}
+
+/**
+ * Returns the number of untraced slots the object has.
+ */
+static size_t object_untraced_slots(const struct object *obj) {
+ return object_size_untraced_slots(((struct object_size *)obj)[-1]);
+}
+
+/**
* This is the layout of an object in the nursery.
*/
struct nursery_object {
@@ -120,8 +128,8 @@ struct nursery_object {
* with one.
*/
struct young_heap_object {
- struct object_size size;
size_t fwd;
+ struct object_size size;
uintptr_t slots[];
};
@@ -199,10 +207,10 @@ static struct old_heap_block old_heap_sentinels[SIZE_CLASS_COUNT];
void gc_init(void) {
// Allocate the nursery and young-heap.
nursery_bottom = nursery_next =
- (uintptr_t)malloc(L1D_SIZE * NURSERY_L1D_SIZE_FACTOR);
+ (uintptr_t)malloc(get_l1d_size() * NURSERY_L1D_SIZE_FACTOR);
assume(nursery_bottom);
young_heap_bottom = young_heap_next =
- (uintptr_t)malloc(L3_SIZE * YOUNG_HEAP_L3_SIZE_FACTOR);
+ (uintptr_t)malloc(get_l3_size() * YOUNG_HEAP_L3_SIZE_FACTOR);
assume(young_heap_bottom);
// Self-link the old-heap.
@@ -211,3 +219,48 @@ void gc_init(void) {
&old_heap_sentinels[i];
}
}
+
+struct object *gc_alloc(size_t value_slot_count, size_t untraced_slot_count) {
+ todo("gc_alloc");
+}
+
+struct object *gc_alloc_compiled_function(size_t value_slot_count,
+ size_t untraced_slot_count) {
+ todo("gc_alloc_compiled_function");
+}
+
+struct object *gc_alloc_hashtable_eq(size_t value_slot_count,
+ size_t untraced_slot_count) {
+ todo("gc_alloc_hashtable_eq");
+}
+
+struct value gc_read_value_slot(const struct object *obj, size_t slot_index) {
+ assume(slot_index < object_value_slots(obj));
+ todo("gc_read_value_slot");
+}
+
+uintptr_t gc_read_untraced_slot(const struct object *obj, size_t slot_index) {
+ assume(slot_index < object_untraced_slots(obj));
+ todo("gc_read_untraced_slot");
+}
+
+uint8_t gc_read_untraced_byte(const struct object *obj, size_t byte_index) {
+ todo("gc_read_untraced_byte");
+}
+
+void gc_write_value_slot(struct object *obj, size_t slot_index,
+ struct value value) {
+ assume(slot_index < object_value_slots(obj));
+ todo("gc_write_value_slot");
+}
+
+void gc_write_untraced_slot(struct object *obj, size_t slot_index,
+ uintptr_t value) {
+ assume(slot_index < object_untraced_slots(obj));
+ todo("gc_write_untraced_slot");
+}
+
+void gc_write_untraced_byte(struct object *obj, size_t byte_index,
+ uint8_t byte) {
+ todo("gc_write_untraced_byte");
+}
diff --git a/src/main.c b/src/main.c
index c8a1115..7be1fa7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,6 +7,9 @@
int main(int argc, char **argv) {
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
+ gc_init();
+ bootstrap();
+
// Initialize console on top screen. Using NULL as the second argument tells
// the console library to use the internal console structure as current one
consoleInit(GFX_TOP, NULL);
@@ -20,8 +23,6 @@ int main(int argc, char **argv) {
printf("\x1b[29;16HPress Start to exit.\n");
- gc_init();
-
// Main loop
while (aptMainLoop()) {
// Scan all the inputs. This should be done once for each frame
diff --git a/src/platform.h b/src/platform.h
new file mode 100644
index 0000000..2dbfd26
--- /dev/null
+++ b/src/platform.h
@@ -0,0 +1,13 @@
+#ifndef IMB3_PLATFORM_H
+#define IMB3_PLATFORM_H
+
+#include <stddef.h>
+#include <stdnoreturn.h>
+
+size_t get_l1d_size(void);
+size_t get_l3_size(void);
+
+void panic_begin(void);
+noreturn void panic_end(void);
+
+#endif // IMB3_PLATFORM_H
diff --git a/src/platform/3ds.c b/src/platform/3ds.c
new file mode 100644
index 0000000..888baf7
--- /dev/null
+++ b/src/platform/3ds.c
@@ -0,0 +1,33 @@
+#include <3ds.h>
+
+#include "../platform.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * These cache-size details are from
+ * https://www.copetti.org/writings/consoles/nintendo-3ds/. We call the second
+ * level of cache (only available on N3DS) L3, since the GC design only cares
+ * about L1D and L3.
+ */
+size_t get_l1d_size(void) { return 16 * 1024; }
+size_t get_l3_size(void) { return 2 * 1024 * 1024; }
+
+void panic_begin(void) { consoleInit(GFX_TOP, NULL); }
+
+noreturn void panic_end(void) {
+ printf("\nPress Start to exit.\n");
+
+ while (aptMainLoop()) {
+ hidScanInput();
+ u32 keys = hidKeysDown();
+ if (keys & KEY_START)
+ break;
+ gfxFlushBuffers();
+ gfxSwapBuffers();
+ gspWaitForVBlank();
+ }
+
+ gfxExit();
+ exit(1);
+}
diff --git a/src/util.c b/src/util.c
index c219831..14a213a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,43 +1,12 @@
#include "util.h"
+#include "platform.h"
#include <stdarg.h>
#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef __3DS__
-
-#include <3ds.h>
-
-static void panic_begin(void) { consoleInit(GFX_TOP, NULL); }
-
-static noreturn void panic(void) {
- printf("\nPress Start to exit.\n");
-
- while (aptMainLoop()) {
- hidScanInput();
- u32 keys = hidKeysDown();
- if (keys & KEY_START)
- break;
- gfxFlushBuffers();
- gfxSwapBuffers();
- gspWaitForVBlank();
- }
-
- gfxExit();
- exit(1);
-}
-
-#else
-
-static void panic_begin(void) {}
-
-static noreturn void panic(void) { abort(); }
-
-#endif
noreturn void assume__failed(const char *file, int line, const char *expr) {
panic_begin();
fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, expr);
- panic();
+ panic_end();
}
noreturn void todo__impl(const char *file, int line, const char *fmt, ...) {
@@ -47,5 +16,5 @@ noreturn void todo__impl(const char *file, int line, const char *fmt, ...) {
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
- panic();
+ panic_end();
}
diff --git a/src/value.c b/src/value.c
index 66d388c..07af689 100644
--- a/src/value.c
+++ b/src/value.c
@@ -1 +1,112 @@
#include "value.h"
+#include "gc.h"
+
+enum builtin {
+ BUILTIN_BUILTIN_CLASS_BIGNUM,
+ BUILTIN_BUILTIN_CLASS_BUILTIN_CLASS,
+ BUILTIN_BUILTIN_CLASS_BUILTIN_FUNCTION,
+ BUILTIN_BUILTIN_CLASS_BUILTIN_OBJECT,
+ BUILTIN_BUILTIN_CLASS_CHARACTER,
+ BUILTIN_BUILTIN_CLASS_COMPILED_FUNCTION,
+ BUILTIN_BUILTIN_CLASS_CONS,
+ BUILTIN_BUILTIN_CLASS_DIRECT_SLOT_DEFINITION,
+ BUILTIN_BUILTIN_CLASS_EFFECTIVE_SLOT_DEFINITION,
+ BUILTIN_BUILTIN_CLASS_FIXNUM,
+ BUILTIN_BUILTIN_CLASS_GENERIC_FUNCTION,
+ BUILTIN_BUILTIN_CLASS_HASHTABLE_EQ,
+ BUILTIN_BUILTIN_CLASS_HASHTABLE_EQUAL,
+ BUILTIN_BUILTIN_CLASS_METHOD,
+ BUILTIN_BUILTIN_CLASS_NULL,
+ BUILTIN_BUILTIN_CLASS_PACKAGE,
+ BUILTIN_BUILTIN_CLASS_STANDARD_CLASS,
+ BUILTIN_BUILTIN_CLASS_STANDARD_OBJECT,
+ BUILTIN_BUILTIN_CLASS_STRING,
+ BUILTIN_BUILTIN_CLASS_SYMBOL,
+ BUILTIN_BUILTIN_CLASS_THREADED_FUNCTION,
+ BUILTIN_BUILTIN_CLASS_VECTOR_VALUE_ADJ_FILL,
+ BUILTIN_BUILTIN_CLASS_VECTOR_VALUE_NOADJ_FILL,
+ BUILTIN_BUILTIN_CLASS_VECTOR_VALUE_NOADJ_NOFILL,
+
+ BUILTIN_FUNCTION_CLASS_DIRECT_SLOTS,
+ BUILTIN_FUNCTION_CLASS_DIRECT_SUBCLASSES,
+ BUILTIN_FUNCTION_CLASS_DIRECT_SUPERCLASSES,
+ BUILTIN_FUNCTION_CLASS_NAME,
+ BUILTIN_FUNCTION_CLASS_PRECEDENCE_LIST,
+ BUILTIN_FUNCTION_CLASS_SLOTS,
+ BUILTIN_FUNCTION_EQ,
+ BUILTIN_FUNCTION_EQUAL,
+ BUILTIN_FUNCTION_GETHASH,
+ BUILTIN_FUNCTION_GETSLOT,
+ BUILTIN_FUNCTION_SETHASH,
+ BUILTIN_FUNCTION_SETSLOT,
+ BUILTIN_FUNCTION_SLOT_LOCATION,
+ BUILTIN_FUNCTION_SLOT_NAME,
+ BUILTIN_FUNCTION_SLOT_TYPE,
+ BUILTIN_FUNCTION_VECTOR_GET,
+ BUILTIN_FUNCTION_VECTOR_PUSH,
+ BUILTIN_FUNCTION_VECTOR_PUSH_EXTEND,
+ BUILTIN_FUNCTION_VECTOR_SET,
+
+ BUILTIN_VARIABLE_DSTACK,
+ BUILTIN_VARIABLE_RSTACK,
+
+ BUILTINS_COUNT,
+};
+
+static struct value builtins[BUILTINS_COUNT];
+
+enum builtin_class_slot_index {
+ BUILTIN_CLASS__NAME,
+ BUILTIN_CLASS__FINALIZED,
+ BUILTIN_CLASS__DIRECT_SUPERCLASSES,
+ BUILTIN_CLASS__DIRECT_SUBCLASSES,
+ BUILTIN_CLASS__PRECEDENCE_LIST,
+
+ BUILTIN_CLASS_SLOT_COUNT,
+};
+
+enum standard_class_slot_index {
+ STANDARD_CLASS__NAME,
+ STANDARD_CLASS__FINALIZED,
+ STANDARD_CLASS__DIRECT_SUPERCLASSES,
+ STANDARD_CLASS__DIRECT_SUBCLASSES,
+ STANDARD_CLASS__PRECEDENCE_LIST,
+ STANDARD_CLASS__DIRECT_SLOTS,
+ STANDARD_CLASS__SLOTS,
+
+ STANDARD_CLASS_SLOT_COUNT,
+};
+
+static void push(struct value value) {}
+
+static struct value pop(void) { return (struct value){.bits = 0}; }
+
+struct value alloc_builtin_object(struct value class, size_t value_slot_count,
+ size_t untraced_slot_count) {
+ struct object *obj;
+ if (class.bits == builtins[BUILTIN_BUILTIN_CLASS_COMPILED_FUNCTION].bits)
+ obj = gc_alloc_compiled_function(value_slot_count, untraced_slot_count);
+ else if (class.bits == builtins[BUILTIN_BUILTIN_CLASS_HASHTABLE_EQ].bits)
+ obj = gc_alloc_hashtable_eq(value_slot_count, untraced_slot_count);
+ else
+ obj = gc_alloc(value_slot_count, untraced_slot_count);
+ gc_write_value_slot(obj, 0, class);
+ return (struct value){
+ .bits = (uintptr_t)obj | TAG_BUILTIN_OBJECT,
+ };
+}
+
+void bootstrap(void) {
+ // Since it is its own class, standard-class needs to be constructed
+ // manually.
+ {
+ struct object *obj = gc_alloc(STANDARD_CLASS_SLOT_COUNT + 1, 0);
+ builtins[BUILTIN_BUILTIN_CLASS_STANDARD_CLASS] = (struct value){
+ .bits = (uintptr_t)obj | TAG_BUILTIN_OBJECT,
+ };
+ gc_write_value_slot(obj, 0, builtins[BUILTIN_BUILTIN_CLASS_STANDARD_CLASS]);
+ // TODO
+ }
+
+ //
+}
diff --git a/src/value.h b/src/value.h
index a932514..3795486 100644
--- a/src/value.h
+++ b/src/value.h
@@ -1,6 +1,7 @@
#ifndef IMB3_VALUE_H
#define IMB3_VALUE_H
+#include <stddef.h>
#include <stdint.h>
struct value {
@@ -35,4 +36,15 @@ enum value_tag {
TAG_STANDARD_OBJECT = 0b110,
};
+/**
+ * Allocates a builtin-object with the given class and slot count.
+ */
+struct value make_builtin_object(struct value class, size_t value_slot_count,
+ size_t untraced_slot_count);
+
+/**
+ * Bootstraps the class heirarchy. This should only be called once.
+ */
+void bootstrap(void);
+
#endif // IMB3_VALUE_H