Initial check-in.
This commit is contained in:
		
						commit
						e0a2599d8d
					
				| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
*#
 | 
			
		||||
.#*
 | 
			
		||||
*~
 | 
			
		||||
*.orig
 | 
			
		||||
npm-debug.log
 | 
			
		||||
package.yml
 | 
			
		||||
node_modules/*
 | 
			
		||||
tmp/
 | 
			
		||||
bin/_mocha
 | 
			
		||||
bin/mocha
 | 
			
		||||
bin/escodegen
 | 
			
		||||
bin/esgenerate
 | 
			
		||||
test-reports.xml
 | 
			
		||||
LisperatorLanguage
 | 
			
		||||
src/test.js
 | 
			
		||||
src/test.coffee
 | 
			
		||||
notes/
 | 
			
		||||
build/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
project("Collector")
 | 
			
		||||
 | 
			
		||||
list(APPEND CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS} -g -ftest-coverage -fprofile-arcs")
 | 
			
		||||
 | 
			
		||||
add_executable(collector
 | 
			
		||||
    src/collector.c)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,238 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_STACK 256
 | 
			
		||||
#define MAX_BARRIER 8
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  OBJ_INT,
 | 
			
		||||
  OBJ_PAIR
 | 
			
		||||
} ObjectType;
 | 
			
		||||
 | 
			
		||||
typedef struct sObject {
 | 
			
		||||
  unsigned char marked;
 | 
			
		||||
  struct sObject* next;
 | 
			
		||||
  ObjectType type;
 | 
			
		||||
  union {
 | 
			
		||||
    int value;
 | 
			
		||||
    struct {
 | 
			
		||||
      struct sObject* head;
 | 
			
		||||
      struct sObject* tail;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
} Object;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  Object* stack[MAX_STACK];
 | 
			
		||||
  Object* root;
 | 
			
		||||
  int stackSize;
 | 
			
		||||
  int numObjects;
 | 
			
		||||
  int maxObjects;
 | 
			
		||||
} VM;
 | 
			
		||||
 | 
			
		||||
void assert(int condition, const char* message) {
 | 
			
		||||
  if (!condition) {
 | 
			
		||||
    printf("%s\n", message);
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VM* newVM() {
 | 
			
		||||
  VM* vm = malloc(sizeof(VM));
 | 
			
		||||
  vm->stackSize = 0;
 | 
			
		||||
  vm->numObjects = 0;
 | 
			
		||||
  vm->maxObjects = MAX_BARRIER;
 | 
			
		||||
  return vm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void push(VM* vm, Object* value) {
 | 
			
		||||
  assert(vm->stackSize < MAX_STACK, "Stack overflow!");
 | 
			
		||||
  vm->stack[vm->stackSize++] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object* pop(VM* vm) {
 | 
			
		||||
  assert(vm->stackSize > 0, "Stack underflow!");
 | 
			
		||||
  return vm->stack[--(vm->stackSize)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mark(Object* object) {
 | 
			
		||||
  if (object->marked) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  object->marked = 1;
 | 
			
		||||
  if (object->type == OBJ_PAIR) {
 | 
			
		||||
    mark(object->head);
 | 
			
		||||
    mark(object->tail);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void markAll(VM* vm) {
 | 
			
		||||
  for(int i = 0; i < vm->stackSize; i++) {
 | 
			
		||||
    mark(vm->stack[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sweep(VM* vm) {
 | 
			
		||||
  Object** object = &vm->root;
 | 
			
		||||
  while (*object) {
 | 
			
		||||
    if (!(*object)->marked) {
 | 
			
		||||
      Object* unreached = *object;
 | 
			
		||||
      *object = unreached->next;
 | 
			
		||||
      vm->numObjects--;
 | 
			
		||||
      free(unreached);
 | 
			
		||||
    } else {
 | 
			
		||||
      (*object)->marked = 0;
 | 
			
		||||
      object = &(*object)->next;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gc(VM* vm) {
 | 
			
		||||
  int numObjects = vm->numObjects;
 | 
			
		||||
  markAll(vm);
 | 
			
		||||
  sweep(vm);
 | 
			
		||||
  vm->maxObjects = vm->numObjects * 2;
 | 
			
		||||
  printf("Collected %d objects, %d remaining.\n", numObjects - vm->numObjects,
 | 
			
		||||
         vm->numObjects);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object *newObject(VM* vm, ObjectType type) {
 | 
			
		||||
  if (vm->numObjects == vm->maxObjects) {
 | 
			
		||||
    gc(vm);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Object* object = malloc(sizeof(Object));
 | 
			
		||||
  object->marked = 0;
 | 
			
		||||
  object->type = type;
 | 
			
		||||
  object->next = vm->root;
 | 
			
		||||
  vm->root = object;
 | 
			
		||||
  vm->numObjects++;
 | 
			
		||||
  return object;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object* pushInt(VM* vm, int value) {
 | 
			
		||||
  Object* object = newObject(vm, OBJ_INT);
 | 
			
		||||
  object->value = value;
 | 
			
		||||
  push(vm, object);
 | 
			
		||||
  return object;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object* pushPair(VM* vm) {
 | 
			
		||||
  Object* object = newObject(vm, OBJ_PAIR);
 | 
			
		||||
  object->head = pop(vm);
 | 
			
		||||
  object->tail = pop(vm);
 | 
			
		||||
  push(vm, object);
 | 
			
		||||
  return object;
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
void freeVM(VM *vm) {
 | 
			
		||||
  vm->stackSize = 0;
 | 
			
		||||
  gc(vm);
 | 
			
		||||
  free(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void objectPrint(Object* object) {
 | 
			
		||||
  switch(object->type) {
 | 
			
		||||
  case OBJ_INT:
 | 
			
		||||
    printf("%d\n", object->value);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case OBJ_PAIR:
 | 
			
		||||
    printf("(");
 | 
			
		||||
    objectPrint(object->head);
 | 
			
		||||
    printf(", ");
 | 
			
		||||
    objectPrint(object->tail);
 | 
			
		||||
    printf(")");
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test1() {
 | 
			
		||||
  printf("Test 1: Objects on stack are preserved.\n");
 | 
			
		||||
  VM* vm = newVM();
 | 
			
		||||
  pushInt(vm, 1);
 | 
			
		||||
  pushInt(vm, 2);
 | 
			
		||||
 | 
			
		||||
  gc(vm);
 | 
			
		||||
  assert(vm->numObjects == 2, "Should have preserved objects.");
 | 
			
		||||
  freeVM(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test2() {
 | 
			
		||||
  printf("Test 2: Unreached objects are collected.\n");
 | 
			
		||||
  VM* vm = newVM();
 | 
			
		||||
  pushInt(vm, 1);
 | 
			
		||||
  pushInt(vm, 2);
 | 
			
		||||
  pop(vm);
 | 
			
		||||
  pop(vm);
 | 
			
		||||
 | 
			
		||||
  gc(vm);
 | 
			
		||||
  assert(vm->numObjects == 0, "Should have collected objects.");
 | 
			
		||||
  freeVM(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test3() {
 | 
			
		||||
  printf("Test 3: Reach nested objects.\n");
 | 
			
		||||
  VM* vm = newVM();
 | 
			
		||||
  pushInt(vm, 1);
 | 
			
		||||
  pushInt(vm, 2);
 | 
			
		||||
  pushPair(vm);
 | 
			
		||||
  pushInt(vm, 3);
 | 
			
		||||
  pushInt(vm, 4);
 | 
			
		||||
  pushPair(vm);
 | 
			
		||||
  pushPair(vm);
 | 
			
		||||
 | 
			
		||||
  gc(vm);
 | 
			
		||||
  assert(vm->numObjects == 7, "Should have reached objects.");
 | 
			
		||||
  freeVM(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test4() {
 | 
			
		||||
  printf("Test 4: Handle cycles.\n");
 | 
			
		||||
  VM* vm = newVM();
 | 
			
		||||
  pushInt(vm, 1);
 | 
			
		||||
  pushInt(vm, 2);
 | 
			
		||||
  Object* a = pushPair(vm);
 | 
			
		||||
  pushInt(vm, 3);
 | 
			
		||||
  pushInt(vm, 4);
 | 
			
		||||
  Object* b = pushPair(vm);
 | 
			
		||||
 | 
			
		||||
  /* Set up a cycle, and also make 2 and 4 unreachable and collectible. */
 | 
			
		||||
  a->tail = b;
 | 
			
		||||
  b->tail = a;
 | 
			
		||||
 | 
			
		||||
  gc(vm);
 | 
			
		||||
  assert(vm->numObjects == 4, "Should have collected objects.");
 | 
			
		||||
  freeVM(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perfTest() {
 | 
			
		||||
  printf("Performance Test.\n");
 | 
			
		||||
  VM* vm = newVM();
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < 1000; i++) {
 | 
			
		||||
    for (int j = 0; j < 20; j++) {
 | 
			
		||||
      pushInt(vm, i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int k = 0; k < 20; k++) {
 | 
			
		||||
      pop(vm);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  freeVM(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, const char * argv[]) {
 | 
			
		||||
  test1();
 | 
			
		||||
  test2();
 | 
			
		||||
  test3();
 | 
			
		||||
  test4();
 | 
			
		||||
  perfTest();
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
		Loading…
	
		Reference in New Issue