add gc
This commit is contained in:
parent
3c3d2716a5
commit
c3629d7150
@ -5,7 +5,8 @@ set(CMAKE_C_STANDARD 99)
|
|||||||
|
|
||||||
add_compile_options(-g -Wall -pedantic)
|
add_compile_options(-g -Wall -pedantic)
|
||||||
|
|
||||||
add_executable(njvm njvm.c)
|
add_executable(njvm njvm.c
|
||||||
|
njvm.h)
|
||||||
|
|
||||||
# Include directories for njvm executable
|
# Include directories for njvm executable
|
||||||
target_include_directories(njvm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bigint/build/include)
|
target_include_directories(njvm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bigint/build/include)
|
||||||
|
|||||||
104
GC.c
104
GC.c
@ -1,6 +1,6 @@
|
|||||||
#ifndef GC
|
#ifndef GC
|
||||||
#define GC
|
#define GC
|
||||||
#define HAS_BROKENHEART_FLAG(objRef) (((objRef)->size & 1 << (7 * sizeof(unsigned int) -1)) == 0)
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -8,107 +8,7 @@
|
|||||||
#include "objref.c"
|
#include "objref.c"
|
||||||
#include "instruktion.c"
|
#include "instruktion.c"
|
||||||
#include "support.c"
|
#include "support.c"
|
||||||
|
#include "bigint.h"
|
||||||
|
|
||||||
ObjRef heap;
|
|
||||||
ObjRef freePointer;
|
|
||||||
ObjRef middle;
|
|
||||||
ObjRef start;
|
|
||||||
ObjRef end;
|
|
||||||
ObjRef finalEnd;
|
|
||||||
ObjRef scanPtr;
|
|
||||||
ObjRef tmpEnd;
|
|
||||||
|
|
||||||
unsigned int defaultHeap = 8192 * 1024;
|
|
||||||
|
|
||||||
void heapAlloc(unsigned int size){
|
|
||||||
heap = malloc(size);
|
|
||||||
if(heap == NULL){
|
|
||||||
fatalError("Not enough memory on Heap\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
start = heap;
|
|
||||||
freePointer = start;
|
|
||||||
middle = (heap + (defaultHeap/2));
|
|
||||||
end = middle;
|
|
||||||
finalEnd = (middle + (defaultHeap/2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void flip(void){
|
|
||||||
freePointer = end;
|
|
||||||
tmpEnd = finalEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjRef copyObjToFreeMem(ObjRef obj){
|
|
||||||
ObjRef tmp = freePointer;
|
|
||||||
memcpy(tmp, obj, obj->size);
|
|
||||||
if(IS_PRIMITIVE(tmp)){
|
|
||||||
freePointer += sizeof(tmp) + tmp->size;
|
|
||||||
}else{
|
|
||||||
freePointer += sizeof(tmp) + tmp->size * sizeof(void*);
|
|
||||||
}
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjRef rellocate(ObjRef orig){
|
|
||||||
ObjRef copy;
|
|
||||||
if (orig == NULL){
|
|
||||||
|
|
||||||
copy = NULL;
|
|
||||||
} else {
|
|
||||||
unsigned int tmp = HAS_BROKENHEART_FLAG(orig);
|
|
||||||
if (tmp){
|
|
||||||
copy = orig->forward_pointer;
|
|
||||||
} else {
|
|
||||||
copy = copyObjToFreeMem(orig);
|
|
||||||
orig->size = (1 | (1 << (7 * sizeof(unsigned int) -1)));
|
|
||||||
//SET_BROKENHEART_FLAG(orig);
|
|
||||||
orig->forward_pointer = copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void garbageColl(void){
|
|
||||||
flip();
|
|
||||||
for(int i = 0; i < program_size; i++){
|
|
||||||
static_data_area[i] = rellocate(static_data_area[i]); // alte Objekte werden in neue akktive Halbspeicher geleitet bei relocate!
|
|
||||||
}
|
|
||||||
bip.op1 = rellocate(bip.op1);
|
|
||||||
bip.op2 = rellocate(bip.op2);
|
|
||||||
bip.res = rellocate(bip.res);
|
|
||||||
bip.rem = rellocate(bip.rem);
|
|
||||||
returnValueReg = rellocate(returnValueReg);
|
|
||||||
|
|
||||||
scan();
|
|
||||||
end = finalEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjRef garbageCollectorMalloc(unsigned int size){
|
|
||||||
if((freePointer + size) > end){
|
|
||||||
garbageColl();
|
|
||||||
} else if((freePointer > finalEnd)){
|
|
||||||
fatalError("Not enough memory on Heap\n");
|
|
||||||
}
|
|
||||||
ObjRef obj = freePointer;
|
|
||||||
if(obj == NULL){
|
|
||||||
fatalError("Object is Null\n");
|
|
||||||
}
|
|
||||||
freePointer += size;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void scan(void){
|
|
||||||
scanPtr = start; //Zielspeicherzeiger;
|
|
||||||
while (scanPtr < freePointer){
|
|
||||||
|
|
||||||
if (!IS_PRIMITIVE(scanPtr)){
|
|
||||||
|
|
||||||
for (int i = 0; i < GET_ELEMENT_COUNT(scanPtr); i++){
|
|
||||||
GET_REFS_PTR(scanPtr)[i] = rellocate(GET_REFS_PTR(scanPtr)[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
191
njvm.c
191
njvm.c
@ -8,12 +8,17 @@
|
|||||||
#include "debugMenu.c"
|
#include "debugMenu.c"
|
||||||
#include "bigint.h"
|
#include "bigint.h"
|
||||||
#include "record.c"
|
#include "record.c"
|
||||||
#include "GC.c"
|
|
||||||
#include "SDA.c"
|
#include "SDA.c"
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
|
|
||||||
|
// Purge Flag
|
||||||
|
int purgeFlag = false;
|
||||||
|
|
||||||
|
// Heap Size
|
||||||
|
int argVheapSizeKiB = 8192;
|
||||||
|
|
||||||
// Program
|
// Program
|
||||||
struct program program;
|
struct program program;
|
||||||
|
|
||||||
@ -22,7 +27,7 @@ struct sda sda;
|
|||||||
|
|
||||||
// Stack
|
// Stack
|
||||||
struct stack stack;
|
struct stack stack;
|
||||||
#define SIZE 64
|
#define SIZE 10000
|
||||||
|
|
||||||
//Register
|
//Register
|
||||||
struct stack reg;
|
struct stack reg;
|
||||||
@ -46,7 +51,7 @@ void execute(struct program program) {
|
|||||||
ObjRef tempObj2;
|
ObjRef tempObj2;
|
||||||
int tempInt;
|
int tempInt;
|
||||||
for (i = 0; i < *program.size; ++i) {
|
for (i = 0; i < *program.size; ++i) {
|
||||||
if (debug == 1 || bp == i) debugMenu(fp, stack, &debug, i, &bp);
|
//if (debug == 1 || bp == i) debugMenu(fp, stack, &debug, i, &bp);
|
||||||
if(debug == 1) printf("(%i)",i);
|
if(debug == 1) printf("(%i)",i);
|
||||||
switch (program.program[i] >> 24) {
|
switch (program.program[i] >> 24) {
|
||||||
case HALT:
|
case HALT:
|
||||||
@ -315,9 +320,184 @@ void execute(struct program program) {
|
|||||||
void tests(void) {
|
void tests(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Garbage Collection
|
||||||
|
*/
|
||||||
|
|
||||||
|
ObjRef *heap;
|
||||||
|
int heapSizeKiB;
|
||||||
|
char *memTargetPtr; //zielspeicherzeiger
|
||||||
|
char *freeHeapPtr; //freizeiger
|
||||||
|
char *halfHeapPtr; //halbspeicherende
|
||||||
|
int gcCount = 0;
|
||||||
|
|
||||||
|
#define MSB (1 << (8 * sizeof(unsigned int) - 1))
|
||||||
|
#define IS_PRIMITIVE(objRef) (((objRef)->size & MSB) == 0)
|
||||||
|
#define GET_SIZE(objRef)((objRef)->size& ~MSB) //Gets the size of an ObjRef
|
||||||
|
#define GET_REFS(objRef)((ObjRef *)((objRef)->data)) //Pointer on first ObjRef in Object
|
||||||
|
|
||||||
|
ObjRef copyObjectToFreeMem(ObjRef orig) {
|
||||||
|
//printf("%s%d\n", "Size in CpyObj: ", GET_SIZE(orig) );
|
||||||
|
int size;
|
||||||
|
if (IS_PRIMITIVE(orig)) {
|
||||||
|
size = GET_SIZE(orig);
|
||||||
|
} else {
|
||||||
|
size = sizeof(void *) + sizeof(unsigned int) + sizeof(bool) + GET_SIZE(orig) * sizeof(ObjRef *);
|
||||||
|
}
|
||||||
|
memcpy(freeHeapPtr, orig, size);
|
||||||
|
ObjRef oldPtr = (ObjRef) freeHeapPtr;
|
||||||
|
//printf("%s%d\n","size after memcpy ", GET_SIZE(oldPtr));
|
||||||
|
//printf("%s%d\n","actual Size: ", size);
|
||||||
|
//oldPtr->size = size;
|
||||||
|
freeHeapPtr += size;
|
||||||
|
return oldPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjRef relocate(ObjRef orig) {
|
||||||
|
/* if (orig == NULL) {
|
||||||
|
printf("%s\n", "null");
|
||||||
|
} else {
|
||||||
|
printf("%s%d\n","Size in relocate ", GET_SIZE(orig));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ObjRef copy;
|
||||||
|
if (orig == NULL) {
|
||||||
|
/* relocate(nil) = nil */
|
||||||
|
copy = NULL;
|
||||||
|
} else {
|
||||||
|
if (orig->brokenHeart == 1) {
|
||||||
|
/* Objekt ist bereits kopiert */
|
||||||
|
copy = orig->forwardPointer;
|
||||||
|
//copy->size =orig->size;
|
||||||
|
//printf("%s\n", "already copied");
|
||||||
|
} else {
|
||||||
|
/* Objekt muss noch kopiert werden*/
|
||||||
|
copy = copyObjectToFreeMem(orig);
|
||||||
|
orig->brokenHeart = true;
|
||||||
|
orig->forwardPointer = copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void scan(void) {
|
||||||
|
char *scanPtr = memTargetPtr;
|
||||||
|
while (scanPtr < freeHeapPtr) {
|
||||||
|
/* es gibt noch Objekte, die
|
||||||
|
* gescannt werden müssen.
|
||||||
|
*/ ObjRef scanOr = (ObjRef) scanPtr;
|
||||||
|
// printf("%d\n", GET_SIZE(scanOr));
|
||||||
|
if (!IS_PRIMITIVE(scanOr)) {
|
||||||
|
/* Ist ein Verbundobjekt */
|
||||||
|
for (int i = 0; i < GET_SIZE(scanOr); i++) {
|
||||||
|
GET_REFS(scanOr)[i] = relocate(GET_REFS(scanOr)[i]);
|
||||||
|
}
|
||||||
|
scanPtr += sizeof(bool) + (GET_SIZE(scanOr) * sizeof(ObjRef *)) + sizeof(unsigned int) + sizeof(void *);
|
||||||
|
} else {
|
||||||
|
//printf("%s %d\n", "is primitive, size: ", GET_SIZE(scanOr));
|
||||||
|
scanPtr += GET_SIZE(scanOr);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap() {
|
||||||
|
if (memTargetPtr == (char *) heap) {
|
||||||
|
//printf("%s\n", "swapped to second half");
|
||||||
|
freeHeapPtr = halfHeapPtr;
|
||||||
|
memTargetPtr = halfHeapPtr;
|
||||||
|
halfHeapPtr = ((char *) heap) + (heapSizeKiB * 1024);
|
||||||
|
} else {
|
||||||
|
//printf("%s\n", "swapped to first half");
|
||||||
|
freeHeapPtr = ((char *) heap);
|
||||||
|
memTargetPtr = ((char *) heap);
|
||||||
|
halfHeapPtr = ((char *) heap) + ((heapSizeKiB * 1024) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void garbageCollector() {
|
||||||
|
char *memToPurgePtr = halfHeapPtr - ((heapSizeKiB * 1024) / 2);
|
||||||
|
swap();
|
||||||
|
//printf("%s\n", "stack");
|
||||||
|
for (int i = 0; i < stack.current; i++) {
|
||||||
|
if (stack.stack[i].isObjRef) {
|
||||||
|
stack.stack[i].u.objRef = relocate(stack.stack[i].u.objRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("%s\n", "globals");
|
||||||
|
for (int i = 0; i < sda.size; i++) {
|
||||||
|
sda.sda[i] = relocate(sda.sda[i]);
|
||||||
|
}
|
||||||
|
//printf("%s\n", "retVal");
|
||||||
|
//returnValue = relocate(returnValue);
|
||||||
|
|
||||||
|
//printf("%s\n", "op1");
|
||||||
|
bip.op1 = relocate(bip.op1);
|
||||||
|
ObjRef b = bip.op1;
|
||||||
|
if(b!= NULL)
|
||||||
|
//printf("%d\n", GET_SIZE(b));
|
||||||
|
|
||||||
|
//printf("%s\n", "op2");
|
||||||
|
bip.op2 = relocate(bip.op2);
|
||||||
|
b = bip.op2;
|
||||||
|
if(b!= NULL)
|
||||||
|
//printf("%d\n", GET_SIZE(b));
|
||||||
|
|
||||||
|
//printf("%s\n", "res");
|
||||||
|
bip.res = relocate(bip.res);
|
||||||
|
b = bip.res;
|
||||||
|
if(b!= NULL)
|
||||||
|
//printf("%d\n", GET_SIZE(b));
|
||||||
|
|
||||||
|
//printf("%s\n", "rem");
|
||||||
|
bip.rem = relocate(bip.rem);
|
||||||
|
b = bip.rem;
|
||||||
|
if(b!= NULL)
|
||||||
|
//printf("%d\n", GET_SIZE(b));
|
||||||
|
|
||||||
|
|
||||||
|
scan();
|
||||||
|
if (purgeFlag) {
|
||||||
|
memset(memToPurgePtr, 0, heapSizeKiB * 1024 / 2);
|
||||||
|
}
|
||||||
|
gcCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjRef alloc(unsigned int size) {
|
||||||
|
if (freeHeapPtr + size > halfHeapPtr) {
|
||||||
|
garbageCollector();
|
||||||
|
if (freeHeapPtr + size > halfHeapPtr) {
|
||||||
|
fprintf(stderr, "Heap is full\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ObjRef or;
|
||||||
|
or = (ObjRef) freeHeapPtr;
|
||||||
|
freeHeapPtr = freeHeapPtr + size;
|
||||||
|
return or;
|
||||||
|
}
|
||||||
|
|
||||||
|
void heapAllocator(int n) {
|
||||||
|
heapSizeKiB = n;
|
||||||
|
if ((heap = malloc(n * 1024)) == NULL) {
|
||||||
|
perror("malloc");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memTargetPtr = (char *) heap;
|
||||||
|
freeHeapPtr = memTargetPtr;
|
||||||
|
halfHeapPtr = (memTargetPtr + (n * 1024) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main
|
||||||
|
*/
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Init the Heap
|
// Init the Heap
|
||||||
initHeap(1000);
|
//initHeap(1000);
|
||||||
|
|
||||||
// Initialize the Stack
|
// Initialize the Stack
|
||||||
int size = SIZE;
|
int size = SIZE;
|
||||||
@ -372,6 +552,7 @@ int main(int argc, char *argv[]) {
|
|||||||
run = 1;
|
run = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
heapAllocator(argVheapSizeKiB);
|
||||||
// Init the sda
|
// Init the sda
|
||||||
ObjRef s[sizeSDA];
|
ObjRef s[sizeSDA];
|
||||||
sda.size = &sizeSDA;
|
sda.size = &sizeSDA;
|
||||||
@ -394,4 +575,4 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Error: no code file specified\n");
|
printf("Error: no code file specified\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
11
njvm.h
Normal file
11
njvm.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Created by Elias Bennour on 28.01.24.
|
||||||
|
//
|
||||||
|
#include "objref.c"
|
||||||
|
|
||||||
|
#ifndef NINJA_NJVM_H
|
||||||
|
#define NINJA_NJVM_H
|
||||||
|
|
||||||
|
ObjRef alloc(unsigned int size);
|
||||||
|
|
||||||
|
#endif //NINJA_NJVM_H
|
||||||
2
objref.c
2
objref.c
@ -5,7 +5,7 @@
|
|||||||
typedef struct ObjRef{
|
typedef struct ObjRef{
|
||||||
// if brkokenHeart and forward_pointer added at this point bip throws errors
|
// if brkokenHeart and forward_pointer added at this point bip throws errors
|
||||||
bool brokenHeart;
|
bool brokenHeart;
|
||||||
struct ObjRef *forward_pointer;
|
struct ObjRef *forwardPointer;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
unsigned char data[1];
|
unsigned char data[1];
|
||||||
} *ObjRef;
|
} *ObjRef;
|
||||||
|
|||||||
5
record.c
5
record.c
@ -5,12 +5,13 @@
|
|||||||
#define RECORD
|
#define RECORD
|
||||||
#include "stackslot.c"
|
#include "stackslot.c"
|
||||||
#include "instruktion.c"
|
#include "instruktion.c"
|
||||||
#include "GC.c"
|
#include "njvm.h"
|
||||||
|
|
||||||
ObjRef newRecord(int size){
|
ObjRef newRecord(int size){
|
||||||
ObjRef record;
|
ObjRef record;
|
||||||
unsigned int objSize;
|
unsigned int objSize;
|
||||||
objSize = sizeof(*record) + (size * sizeof(void *));
|
objSize = sizeof(*record) + (size * sizeof(void *));
|
||||||
if((record = malloc(objSize)) == NULL){
|
if((record = alloc(objSize)) == NULL){
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
}
|
}
|
||||||
record->size = MSB;
|
record->size = MSB;
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
|
#ifndef SUPPORT_C
|
||||||
|
#define SUPPORT_C
|
||||||
|
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "objref.c"
|
#include "objref.c"
|
||||||
#include "GC.c"
|
#include "njvm.h"
|
||||||
|
|
||||||
void fatalError(char *msg){
|
void fatalError(char *msg){
|
||||||
printf("Fatal error: %s\n", msg);
|
printf("Fatal error: %s\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -13,7 +16,7 @@ void fatalError(char *msg){
|
|||||||
void * newPrimObject(int dataSize) {
|
void * newPrimObject(int dataSize) {
|
||||||
ObjRef bigObjRef;
|
ObjRef bigObjRef;
|
||||||
|
|
||||||
bigObjRef = malloc(sizeof(unsigned int) +
|
bigObjRef = alloc(sizeof(unsigned int) +
|
||||||
dataSize * sizeof(unsigned char));
|
dataSize * sizeof(unsigned char));
|
||||||
if (bigObjRef == NULL) {
|
if (bigObjRef == NULL) {
|
||||||
fatalError("newPrimObject() got no memory");
|
fatalError("newPrimObject() got no memory");
|
||||||
@ -26,3 +29,5 @@ void * getPrimObjectDataPointer(void * obj){
|
|||||||
ObjRef oo = ((ObjRef) (obj));
|
ObjRef oo = ((ObjRef) (obj));
|
||||||
return oo->data;
|
return oo->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user