-capfuck: capfuck.c sane-ctype.c class.c
+capfuck: capfuck.c sane-ctype.c class.c object.c
gcc -Wall -o $@ -g -std=c99 $^
@@ -271,8 +271,7 @@ static unsigned prepare_context(struct context* ctx)
/* Find suitable message. */
ctx->c_message = ctx->c_vat->v_msgq_head;
- while(ctx->c_message && ctx->c_message->m_target->o_flags ==
- OF_EXECUTING)
+ while(ctx->c_message && object_is_executing(ctx->c_message->m_target))
ctx->c_message = ctx->c_message->m_next;
if(!ctx->c_message)
return 0;
@@ -290,7 +289,7 @@ static unsigned prepare_context(struct context* ctx)
ctx->c_message->m_next = NULL;
/* Mark object as being executed. */
- ctx->c_message->m_target->o_flags |= OF_EXECUTING;
+ object_set_executing(ctx->c_message->m_target);
/* Set fields. */
ctx->c_stacktop = NULL;
@@ -312,7 +311,7 @@ static void unprepare_context(struct context* ctx)
mutex_lock(&ctx->c_vat->v_msgq_lock);
mutex_lock(&ctx->c_lock);
- ctx->c_message->m_target->o_flags &= ~OF_EXECUTING;
+ object_clear_executing(ctx->c_message->m_target);
/* Kill the message. It is now handled. */
free(ctx->c_message);
@@ -337,9 +336,7 @@ static void singlestep_context(struct context* ctx, struct message* msg,
struct object* tmp2;
struct stack* tmp3;
struct message* tmp4;
- struct class* tmp5;
size_t parameters;
- size_t fields;
/* Grab context lock. */
mutex_lock(&ctx->c_lock);
@@ -377,16 +374,10 @@ static void singlestep_context(struct context* ctx, struct message* msg,
ctx->c_alt_flag = 1;
break;
case 'f':
- tmp1 = pop_stack(ctx);
- if(ctx->c_numreg < class_field_count(tc))
- t->o_fields[ctx->c_numreg] = tmp1;
+ object_write_field(t, ctx->c_numreg, pop_stack(ctx));
break;
case 'F':
- if(ctx->c_numreg < class_field_count(tc))
- tmp1 = t->o_fields[ctx->c_numreg];
- else
- tmp1 = NULL;
- push_stack(ctx, tmp1);
+ push_stack(ctx, object_read_field(t, ctx->c_numreg));
break;
case 'l':
tmp1 = pop_stack(ctx);
@@ -441,25 +432,8 @@ static void singlestep_context(struct context* ctx, struct message* msg,
push_stack(ctx, t);
break;
case 'N':
- fields = 0;
- tmp5 = class_search(ctx->c_numreg);
- if(tmp5)
- fields = class_field_count(tmp5);
- tmp1 = malloc(sizeof(struct object) + fields *
- sizeof(struct object*));
- if(!tmp1) {
- fprintf(stderr, "Out of memory!\n");
- exit(1);
- }
- tmp1->o_flags = 0;
- tmp1->o_class = tmp5;
- tmp1->o_special = NULL;
- tmp1->o_prev = NULL;
- tmp1->o_next = ctx->c_vat->v_object_list;
- ctx->c_vat->v_object_list->o_prev = tmp1;
- ctx->c_vat->v_object_list = tmp1;
- for(size_t i = 0; i < fields; i++)
- tmp1->o_fields[i] = NULL;
+ tmp1 = object_create_ordinary(class_search(ctx->c_numreg));
+ objectlist_add(ctx->c_vat->v_objectlist, tmp1);
push_stack(ctx, tmp1);
break;
default:
@@ -479,10 +453,9 @@ static unsigned execute_msghandler(struct context* ctx)
struct message* m = ctx->c_message;
struct object* t = m->m_target;
- struct class* tc = t->o_class;
+ struct class* tc = object_class(t);
- if(t->o_special) {
- t->o_special(ctx, m);
+ if(object_exec_special(t, ctx, m)) {
unprepare_context(ctx);
return 1;
} else if(!tc) {
@@ -536,20 +509,18 @@ static void queue_message(struct vat* vat, struct message* message)
/*****************************************************************************/
static void recursive_mark_live(struct object* object)
{
+ size_t fields;
+ struct class* class = object_class(object);
+
/* Don't recurse twice to same object. */
- if(!object || !(object->o_flags & OF_MARKED_FOR_GC))
+ if(!object || !object_is_gcmark(object))
return;
+ object_clear_gcmark(object);
- /* Clear the gc flag. */
- object->o_flags &= ~OF_MARKED_FOR_GC;
- /* These are pretty special. */
- if(!object->o_class)
- return;
-
- /* Recurse. */
- for(size_t i = 0; i < class_field_count(object->o_class); i++)
- recursive_mark_live(object->o_fields[i]);
+ fields = class ? class_field_count(class) : 0;
+ for(size_t i = 0; i < fields; i++)
+ recursive_mark_live(object_read_field(object, i));
}
/*****************************************************************************/
@@ -566,48 +537,12 @@ static void mark_messages_live(struct message* queue)
/*****************************************************************************/
static unsigned perform_gc(struct vat* vat)
{
- struct object* object = vat->v_object_list;
- struct object* tmp;
-
- while(object) {
- object->o_flags |= OF_MARKED_FOR_GC;
- object = object->o_next;
- }
+ objectlist_set_gcmark_all(vat->v_objectlist);
mark_messages_live(vat->v_msgq_head);
-
- object = vat->v_object_list;
- while(object) {
- if((object->o_flags & OF_MARKED_FOR_GC) == 0) {
- object = object->o_next;
- break;
- }
-
- tmp = object;
- object = object->o_next;
- if(tmp->o_prev)
- tmp->o_prev->o_next = tmp->o_next;
- if(tmp->o_next)
- tmp->o_next->o_prev = tmp->o_prev;
- if(vat->v_object_list == tmp)
- vat->v_object_list = tmp->o_next;
- free(tmp);
- }
-
- return (vat->v_object_list != NULL);
-
+ return objectlist_kill_marked(vat->v_objectlist);
}
/*****************************************************************************/
-struct object capfuck_dummy = {
- 0, /* No flags. */
- NULL, /* No class. */
- NULL, /* Handler. */
- NULL, /* Prev. */
- NULL, /* Next. */
- {}
-};
-
-/*****************************************************************************/
void capfuck_stdin_h(struct context* ctx, struct message* msg)
{
if(msg->m_parameter_count == 0 || !msg->m_parameters[0])
@@ -624,10 +559,11 @@ void capfuck_stdin_h(struct context* ctx, struct message* msg)
for(unsigned i = 0; i < 9; i++)
message->m_parameters[i] = NULL;
} else {
- message->m_parameters[0] = &capfuck_dummy;
+ struct object* dummy = object_read_field(msg->m_target, 0);
+ message->m_parameters[0] = dummy;
for(unsigned i = 0; i < 8; i++)
message->m_parameters[i + 1] = ((c >> (7 - i)) & 1) ?
- &capfuck_dummy : NULL;
+ dummy : NULL;
}
queue_message(ctx->c_vat, message);
}
@@ -695,53 +631,47 @@ int main(int argc, char** argv)
fprintf(stderr, "No classes defined.\n");
exit(1);
}
- struct object* object = malloc(sizeof(struct object) +
- class_field_count(class) * sizeof(struct object*));
+
+ struct object* object;
+ struct object* capfuck_stdin;
+ struct object* capfuck_stdout;
+ struct object* capfuck_stderr;
+ struct object* capfuck_dummy;
+
struct message* message = malloc(sizeof(struct message) +
3 * sizeof(struct object*));
struct vat* vat = malloc(sizeof(struct vat));
struct context* context = malloc(sizeof(struct context) +
parser.p_maxlocals * sizeof(struct object*));
- struct object* capfuck_stdin = malloc(sizeof(struct object));
- struct object* capfuck_stdout = malloc(sizeof(struct object));
- struct object* capfuck_stderr = malloc(sizeof(struct object));
- if(!object || !message || !vat || !context || !capfuck_stdin ||
- !capfuck_stdout || !capfuck_stderr) {
+ if(!message || !vat || !context) {
fprintf(stderr, "Out of memory.\n");
return 1;
}
+ /* Create initial object complement. */
+ object = object_create_ordinary(class);
+ capfuck_dummy = object_create_special(NULL, 0);
+ capfuck_stdin = object_create_special(capfuck_stdin_h, 2);
+ capfuck_stdout = object_create_special(capfuck_stdout_h, 0);
+ capfuck_stderr = object_create_special(capfuck_stderr_h, 0);
+
+ /* Capfuck_stdin uses capfuck_dummy. Keep it from being GCd. */
+ object_write_field(capfuck_stdin, 0, capfuck_dummy);
+
/* Initialize fields. */
- object->o_flags = 0;
- object->o_class = class;
- object->o_special = NULL;
- object->o_prev = NULL;
- object->o_next = capfuck_stdin;
- for(size_t i = 0; i < class_field_count(class); i++)
- object->o_fields[i] = NULL;
- capfuck_stdin->o_flags = 0;
- capfuck_stdin->o_class = NULL;
- capfuck_stdin->o_special = capfuck_stdin_h;
- capfuck_stdin->o_prev = object;
- capfuck_stdin->o_next = capfuck_stdout;
- capfuck_stdout->o_flags = 0;
- capfuck_stdout->o_class = NULL;
- capfuck_stdout->o_special = capfuck_stdout_h;
- capfuck_stdout->o_prev = capfuck_stdin;
- capfuck_stdout->o_next = capfuck_stderr;
- capfuck_stderr->o_flags = 0;
- capfuck_stderr->o_class = NULL;
- capfuck_stderr->o_special = capfuck_stderr_h;
- capfuck_stderr->o_prev = capfuck_stdout;
- capfuck_stderr->o_next = NULL;
message->m_target = object;
message->m_next = NULL;
message->m_parameter_count = 3;
message->m_parameters[0] = capfuck_stdin;
message->m_parameters[1] = capfuck_stdout;
message->m_parameters[2] = capfuck_stderr;
- vat->v_object_list = object;
+ vat->v_objectlist = objectlist_create();
+ objectlist_add(vat->v_objectlist, capfuck_stdin);
+ objectlist_add(vat->v_objectlist, capfuck_stdout);
+ objectlist_add(vat->v_objectlist, capfuck_stderr);
+ objectlist_add(vat->v_objectlist, capfuck_dummy);
+ objectlist_add(vat->v_objectlist, object);
vat->v_msgq_head = NULL;
vat->v_msgq_tail = NULL;
vat->v_max_locals = parser.p_maxlocals;
@@ -764,6 +694,7 @@ int main(int argc, char** argv)
}
mutex_unlock(&context->c_lock);
+ objectlist_destroy(vat->v_objectlist);
free(vat);
free(context);
@@ -80,6 +80,7 @@ struct class* class_make(size_t fields, size_t locals,
class->c_locals = locals;
class->c_body = instructions;
class->c_body_length = ins_len;
+ class->c_next = NULL;
return class;
}
--- /dev/null
+#include "object.h"
+#include <stdio.h>
+
+/* Object. */
+struct object
+{
+ /* Flags. */
+ unsigned o_flags;
+ /* Class of object. */
+ struct class* o_class;
+ /* Special receiver. */
+ void (*o_special)(struct context* ctx, struct message* msg);
+ /* Fields. */
+ struct object* o_fields[0];
+};
+
+
+/* Object list node. */
+struct objectlist_node
+{
+ /* Object pointed. */
+ struct object* oln_object;
+ /* Next node. */
+ struct objectlist_node* oln_next;
+};
+
+
+/* Object list. */
+struct objectlist
+{
+ /* Root of list. */
+ struct objectlist_node* ol_first;
+};
+
+
+/*****************************************************************************/
+struct object* object_read_field(struct object* object, size_t slot)
+{
+ if(slot < class_field_count(object->o_class))
+ return object->o_fields[slot];
+ else
+ return NULL;
+}
+
+/*****************************************************************************/
+void object_write_field(struct object* object, size_t slot,
+ struct object* towrite)
+{
+ if(slot < class_field_count(object->o_class))
+ object->o_fields[slot] = towrite;
+}
+
+/*****************************************************************************/
+unsigned object_is_executing(struct object* object)
+{
+ return ((object->o_flags & OF_EXECUTING) ? 1 : 0);
+}
+
+/*****************************************************************************/
+void object_set_executing(struct object* object)
+{
+ object->o_flags |= OF_EXECUTING;
+}
+
+/*****************************************************************************/
+void object_clear_executing(struct object* object)
+{
+ object->o_flags &= ~OF_EXECUTING;
+}
+
+/*****************************************************************************/
+void object_set_gcmark(struct object* object)
+{
+ object->o_flags |= OF_MARKED_FOR_GC;
+}
+
+/*****************************************************************************/
+void object_clear_gcmark(struct object* object)
+{
+ object->o_flags &= ~OF_MARKED_FOR_GC;
+}
+
+/*****************************************************************************/
+unsigned object_is_gcmark(struct object* object)
+{
+ return ((object->o_flags & OF_MARKED_FOR_GC) ? 1 : 0);
+}
+
+
+
+/*****************************************************************************/
+struct objectlist* objectlist_create()
+{
+ struct objectlist* objectlist;
+ objectlist = malloc(sizeof(struct objectlist*));
+ if(!objectlist) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ objectlist->ol_first = NULL;
+ return objectlist;
+}
+
+/*****************************************************************************/
+void objectlist_destroy(struct objectlist* objectlist)
+{
+ while(objectlist->ol_first) {
+ struct objectlist_node* tmp = objectlist->ol_first;
+ objectlist->ol_first = tmp->oln_next;
+ free(tmp->oln_object);
+ free(tmp);
+ }
+ free(objectlist);
+}
+
+/*****************************************************************************/
+void objectlist_add(struct objectlist* objectlist, struct object* object)
+{
+ struct objectlist_node* node;
+ node = malloc(sizeof(struct objectlist_node));
+ if(!node) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ node->oln_object = object;
+ node->oln_next = objectlist->ol_first;
+ objectlist->ol_first = node;
+}
+
+/*****************************************************************************/
+unsigned objectlist_kill_marked(struct objectlist* objectlist)
+{
+ struct objectlist_node* tmp = objectlist->ol_first;
+ struct objectlist_node* tmp2;
+ while(tmp && tmp->oln_object->o_flags & OF_MARKED_FOR_GC)
+ {
+ objectlist->ol_first = tmp->oln_next;
+ free(tmp->oln_object);
+ free(tmp);
+ tmp = objectlist->ol_first;
+ }
+ if(!objectlist->ol_first)
+ return 0;
+
+ tmp = objectlist->ol_first;
+ while(tmp->oln_next) {
+ if(tmp->oln_next->oln_object->o_flags & OF_MARKED_FOR_GC) {
+ tmp2 = tmp->oln_next;
+ tmp->oln_next = tmp2->oln_next;
+ free(tmp2->oln_object);
+ free(tmp2);
+ }
+ tmp = tmp->oln_next;
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+void objectlist_set_gcmark_all(struct objectlist* objectlist)
+{
+ struct objectlist_node* tmp = objectlist->ol_first;
+ while(tmp) {
+ object_set_gcmark(tmp->oln_object);
+ tmp = tmp->oln_next;
+ }
+}
+
+/*****************************************************************************/
+struct object* object_create_ordinary(struct class* class)
+{
+ size_t fields;
+ struct object* object;
+
+ fields = class ? class_field_count(class) : 0;
+ object = malloc(sizeof(struct object) + fields *
+ sizeof(struct object*));
+ if(!object) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ object->o_flags = 0;
+ object->o_class = class;
+ object->o_special = NULL;
+ for(size_t i = 0; i < fields; i++)
+ object->o_fields[i] = NULL;
+ return object;
+}
+
+/*****************************************************************************/
+struct object* object_create_special(void (*handler)(struct context* ctx,
+ struct message* msg), size_t fields)
+{
+ struct object* object;
+ struct class* class;
+
+ object = malloc(sizeof(struct object) + fields *
+ sizeof(struct object*));
+ if(!object) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ object->o_flags = 0;
+ object->o_class = NULL;
+ object->o_special = handler;
+
+ if(fields > 0) {
+ class = class_make(fields, 0, NULL, 0);
+ class_register(class);
+ object->o_class = class;
+ }
+
+ return object;
+}
+
+/*****************************************************************************/
+struct class* object_class(struct object* object)
+{
+ return object->o_class;
+}
+
+/*****************************************************************************/
+unsigned object_exec_special(struct object* object, struct context* ctx,
+ struct message* msg)
+{
+ if(object->o_special) {
+ object->o_special(ctx, msg);
+ return 1;
+ } else
+ return 0;
+
+}
--- /dev/null
+#ifndef _object__h__included__
+#define _object__h__included__
+
+#include "class.h"
+
+struct context;
+struct message;
+
+/* Object marked for garbage collection. */
+#define OF_MARKED_FOR_GC 1
+/* Already execuing message handler. */
+#define OF_EXECUTING 2
+
+/* Object. */
+struct object;
+
+/* Object list. */
+struct objectlist;
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Read object field.
+ *
+ * PARAMETERS:
+ * object The object to read.
+ * slot Field slot number.
+ *
+ * RETURN VALUE:
+ * Read value, or NULL if slot is invalid.
+ *
+ *****************************************************************************/
+struct object* object_read_field(struct object* object, size_t slot);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Write object field. Writes to nonexistent slots are discarded.
+ *
+ * PARAMETERS:
+ * object The object to write.
+ * slot Field slot number.
+ * towrite Refrence to write.
+ *
+ *****************************************************************************/
+void object_write_field(struct object* object, size_t slot,
+ struct object* towrite);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Get class of object.
+ *
+ * PARAMETERS:
+ * object The object to interrogate.
+ *
+ * RETURN VALUE:
+ * Class of object.
+ *
+ *****************************************************************************/
+struct class* object_class(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Check object EXECUTING flag.
+ *
+ * PARAMETERS:
+ * object The object to interrogate.
+ *
+ * RETURN VALUE:
+ * 1 if object is executing, 0 otherwise.
+ *
+ *****************************************************************************/
+unsigned object_is_executing(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Set object EXECUTING flag.
+ *
+ * PARAMETERS:
+ * object The object to manipulate.
+ *
+ *****************************************************************************/
+void object_set_executing(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Clear object EXECUTING flag.
+ *
+ * PARAMETERS:
+ * object The object to manipulate.
+ *
+ *****************************************************************************/
+void object_clear_executing(struct object* object);
+
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Check object MARKED_FOR_GC flag.
+ *
+ * PARAMETERS:
+ * object The object to interrogate.
+ *
+ * RETURN VALUE:
+ * 1 if object is marked for GC, 0 otherwise.
+ *
+ *****************************************************************************/
+unsigned object_is_gcmark(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Set object MARKED_FOR_GC flag.
+ *
+ * PARAMETERS:
+ * object The object to manipulate.
+ *
+ *****************************************************************************/
+void object_set_gcmark(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Clear object MARKED_FOR_GC flag.
+ *
+ * PARAMETERS:
+ * object The object to manipulate.
+ *
+ *****************************************************************************/
+void object_clear_gcmark(struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Create object of specified class.
+ *
+ * PARAMETERS:
+ * class The class of new object.
+ *
+ * RETURN VALUE:
+ * The newly created object.
+ *
+ *****************************************************************************/
+struct object* object_create_ordinary(struct class* class);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Create special object.
+ *
+ * PARAMETERS:
+ * handler Handler object.
+ * fields Fields for local object. Note that if this
+ * is nonzero, new class is created and
+ * registered.
+ *
+ * RETURN VALUE:
+ * The newly created object.
+ *
+ *****************************************************************************/
+struct object* object_create_special(void (*handler)(struct context* ctx,
+ struct message* msg), size_t fields);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Create object list.
+ *
+ * RETURN VALUE:
+ * The newly created object list.
+ *
+ *****************************************************************************/
+struct objectlist* objectlist_create();
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Destroy object list and all objects in it.
+ *
+ * PARAMETERS:
+ * objectlist Object list to destroy.
+ *
+ *****************************************************************************/
+void objectlist_destroy(struct objectlist* objectlist);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Add object to object list.
+ *
+ * PARAMETERS:
+ * objectlist Object list to add object to.
+ * object Object to add.
+ *
+ *****************************************************************************/
+void objectlist_add(struct objectlist* objectlist, struct object* object);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Kill all marked objects from list.
+ *
+ * PARAMETERS:
+ * objectlist Object list to manipulate.
+ *
+ * RETURN VALUE:
+ * 1 if more remain, 0 if all are gone.
+ *
+ *****************************************************************************/
+unsigned objectlist_kill_marked(struct objectlist* objectlist);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Set object MARKED_FOR_GC flag for all objects in list.
+ *
+ * PARAMETERS:
+ * objectlist The object list to manipulate.
+ *
+ *****************************************************************************/
+void objectlist_set_gcmark_all(struct objectlist* objectlist);
+
+/******************************************************************************
+ *
+ * DESCRIPTION:
+ * Execute special action, if any.
+ *
+ * PARAMETERS:
+ * object The object.
+ * ctx Context to pass in.
+ * msg Message to pass in.
+ *
+ * RETURN VALUE:
+ * 1 if special action was executed, 0 if there is none.
+ *
+ *****************************************************************************/
+unsigned object_exec_special(struct object* object, struct context* ctx,
+ struct message* msg);
+
+
+#endif
#define _types__h__included__
#include "class.h"
-
-struct context;
+#include "object.h"
struct message;
-/* Object marked for garbage collection. */
-#define OF_MARKED_FOR_GC 1
-/* Already execuing message handler. */
-#define OF_EXECUTING 2
/* on line, no non-whitespace yet. */
#define PS_INITIAL 0
/* Last was non-whitespace. */
@@ -32,23 +27,6 @@ struct lock
{
};
-/* Object. */
-struct object
-{
- /* Flags. */
- unsigned o_flags;
- /* Class of object. */
- struct class* o_class;
- /* Special receiver. */
- void (*o_special)(struct context* ctx, struct message* msg);
- /* Previous object. */
- struct object* o_prev;
- /* Next object. */
- struct object* o_next;
- /* Fields. */
- struct object* o_fields[0];
-};
-
/* Message. */
struct message
{
@@ -76,6 +54,8 @@ struct stack
/* Vat. */
struct vat
{
+ /* Object list. */
+ struct objectlist* v_objectlist;
/* Object list head. */
struct object* v_object_list;
/* Message queue head. */