summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.txt34
-rw-r--r--src/gc/sms.c6
-rw-r--r--src/platform/linux.c44
-rw-r--r--src/value.c14
-rw-r--r--src/value.h7
5 files changed, 59 insertions, 46 deletions
diff --git a/README.txt b/README.txt
index 0221931..81933f3 100644
--- a/README.txt
+++ b/README.txt
@@ -216,3 +216,37 @@
│ │
│ iv. Does interleaving all three passes improve performance? │
╰──────────────────────────────────────────────────────────────────────────────╯
+
+╭──────────────────────────────────────────────────────────────────────────────╮
+│ The Meta-Object Protocol (i.e., the scary parts of the object system) │
+╞══════════════════════════════════════════════════════════════════════════════╡
+│ The object system supports a meta-object protocol inspired by the original │
+│ MOP as implemented in most Common Lisp implementations, but with a few parts │
+│ cleaned up and simplified. │
+│ │
+│ The pre-defined classes are either BUILTIN-CLASSes or STANDARD-CLASSes. The │
+│ main difference between the two is that only STANDARD-CLASSes have a slots │
+│ array. STANDARD-CLASS may be subclassed, allowing user-defined metaclasses │
+│ to be defined. BUILTIN-CLASS may not be subclassed. │
+│ │
+│ The class hierarchy for pre-defined classes is as follows: │
+│ │
+│ t │
+│ ┌───────────────────┴────────────────┐ │
+│ builtin-object │ │
+│ ┌────┬───┬─────────┬──────┬─────┼───────────────┐ │ │
+│ integer │ symbol sequence │ character hashtable │ │
+│ ┌──┴──┐ └──┐│ ┌──┴──┐ │ ┌───────┴───────┐ │ │
+│ bignum fixnum ││ list vector └─────┐ hashtable-eq hashtable-equal │ │
+│ ┌───────┬───┘└──┐┌─┴──┐ └┬───… │ │ │
+│ method package null cons string function │ │
+│ ┌─────────────────┬────────┴───────┬─────────────────┐ │ │
+│ builtin-function compiled-function generic-function threaded-function │ │
+│ │ │
+│ ┌─────────────────────────────────────┘ │
+│ standard-object │
+│ ┌─────────────────────┬─┴────────────────────┐ │
+│ class direct-slot-definition effective-slot-definition │
+│ ┌──────┴──────┐ │
+│ builtin-class standard-class │
+╰──────────────────────────────────────────────────────────────────────────────╯
diff --git a/src/gc/sms.c b/src/gc/sms.c
index eb76dab..427edc5 100644
--- a/src/gc/sms.c
+++ b/src/gc/sms.c
@@ -53,7 +53,11 @@ static const struct object_header *hdrc(const void *ptr) {
static size_t collect_amount[5] = {0};
static size_t collect_amount_i = 0;
-void gc_init(void) {}
+void gc_init(void) {
+ for (size_t i = 0; i < sizeof(collect_amount) / sizeof(collect_amount[0]);
+ i++)
+ collect_amount[i] = (size_t)-1;
+}
static void gc_mark(const struct value initial_value) {
// If the initial value wasn't a pointer to an unmarked object, we can bail
diff --git a/src/platform/linux.c b/src/platform/linux.c
index 3305869..052c00c 100644
--- a/src/platform/linux.c
+++ b/src/platform/linux.c
@@ -11,49 +11,13 @@
#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));
- }
- }
+ bootstrap();
gc_debug();
+ gc_collect(GC_COLLECT_MANUAL);
+ gc_debug();
+
return 0;
}
diff --git a/src/value.c b/src/value.c
index eacc21c..e240646 100644
--- a/src/value.c
+++ b/src/value.c
@@ -152,14 +152,18 @@ struct object *untag_ptr(struct value value) {
}
void bootstrap(void) {
+ // Register every builtin slot as a root.
+ for (size_t i = 0; i < BUILTINS_COUNT; i++)
+ gc_root_push(&builtins[i]);
+
// 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]);
+ builtins[BUILTIN_BUILTIN_CLASS_STANDARD_CLASS] =
+ tag_ptr(gc_alloc(STANDARD_CLASS_SLOT_COUNT + 1, 0), TAG_BUILTIN_OBJECT);
+ builtin_object_write_value_slot(
+ builtins[BUILTIN_BUILTIN_CLASS_STANDARD_CLASS], 0,
+ builtins[BUILTIN_BUILTIN_CLASS_STANDARD_CLASS]);
// TODO
}
diff --git a/src/value.h b/src/value.h
index 1331d9d..50c50f9 100644
--- a/src/value.h
+++ b/src/value.h
@@ -89,6 +89,13 @@ intptr_t untag_fixnum(struct value);
*/
struct object *untag_ptr(struct value);
+struct value builtin_object_read_value_slot(const struct value, size_t);
+uintptr_t builtin_object_read_untraced_slot(const struct value, size_t);
+uint8_t builtin_object_read_untraced_byte(const struct value, size_t);
+void builtin_object_write_value_slot(struct value, size_t, struct value);
+void builtin_object_write_untraced_slot(struct value, size_t, uintptr_t);
+void builtin_object_write_untraced_byte(struct value, size_t, uint8_t);
+
/**
* Bootstraps the class heirarchy. This should only be called once.
*/