Added freeMemory callback to EngineNode, adjusted how nodes are freed

This commit is contained in:
2022-10-08 17:17:41 +01:00
parent 6b5cd7f580
commit 0b4a6097be
11 changed files with 146 additions and 55 deletions

View File

@@ -1,2 +1,10 @@
#include "common.h"
STATIC_ASSERT(sizeof(char) == 1);
STATIC_ASSERT(sizeof(short) == 2);
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(float) == 4);
STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4);

View File

@@ -11,3 +11,7 @@
#define CORE_API
#endif
#include <assert.h>
//test variable sizes based on platform
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")

View File

@@ -61,7 +61,6 @@ void freeEngine() {
callEngineNode(engine.rootNode, &engine.interpreter, "onFree");
freeEngineNode(engine.rootNode);
FREE(EngineNode, engine.rootNode);
engine.rootNode = NULL;
}

View File

@@ -2,12 +2,25 @@
#include "memory.h"
STATIC_ASSERT(sizeof(EngineNode) == 32);
STATIC_ASSERT(sizeof(EngineNodeCallback) == 8);
STATIC_ASSERT(sizeof(LiteralDictionary*) == 8);
STATIC_ASSERT(sizeof(EngineNode*) == 8);
STATIC_ASSERT(sizeof(int) == 4);
static void freeMemory(void* ptr) {
//free this node type's memory
FREE(EngineNode, ptr);
}
void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size) {
//init
node->freeMemory = freeMemory;
node->functions = ALLOCATE(LiteralDictionary, 1);
node->children = NULL;
node->capacity = 0;
node->count = 0;
node->functions = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(node->functions);
//run bytecode
@@ -37,7 +50,7 @@ void pushEngineNode(EngineNode* node, EngineNode* child) {
int oldCapacity = node->capacity;
node->capacity = GROW_CAPACITY(oldCapacity);
node->children = GROW_ARRAY(EngineNode, node->children, oldCapacity, node->capacity);
node->children = GROW_ARRAY(EngineNode*, node->children, oldCapacity, node->capacity);
}
//prune tombstones (experimental)
@@ -49,41 +62,35 @@ void pushEngineNode(EngineNode* node, EngineNode* child) {
}
//move down
if (node->children[i].functions != NULL) {
if (node->children[i] != NULL) {
node->children[counter++] = node->children[i];
}
}
//zero the rest
while (counter < node->capacity) {
node->children[counter].children = NULL;
node->children[counter].capacity = 0;
node->children[counter].count = 0;
node->children[counter].functions = NULL;
counter++;
}
//assign
node->children[node->count++] = *child;
node->children[node->count++] = child;
}
void freeEngineNode(EngineNode* node) {
//free and tombstone this node
for (int i = 0; i < node->capacity; i++) {
freeEngineNode(&node->children[i]);
if (node == NULL) {
return; //NO-OP
}
FREE_ARRAY(EngineNode, node->children, node->capacity);
//free and tombstone this node
for (int i = 0; i < node->count; i++) {
freeEngineNode(node->children[i]);
}
//free the pointer array to the children
FREE_ARRAY(EngineNode*, node->children, node->capacity);
if (node->functions != NULL) {
freeLiteralDictionary(node->functions);
FREE(LiteralDictionary, node->functions);
}
node->children = NULL;
node->capacity = -1;
node->count = -1;
node->functions = NULL;
//free this node's memory
node->freeMemory(node);
}
static void callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key) {
@@ -110,8 +117,8 @@ static void callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Li
//recurse to the (non-tombstone) children
for (int i = 0; i < node->count; i++) {
if (node->children[i].functions != NULL) {
callEngineNodeLiteral(&node->children[i], interpreter, key);
if (node->children[i] != NULL) {
callEngineNodeLiteral(node->children[i], interpreter, key);
}
}
}

View File

@@ -8,16 +8,20 @@
//forward declare
typedef struct _engineNode EngineNode;
typedef void (*EngineNodeCallback)(void*);
//the node object, which forms a tree
typedef struct _engineNode {
//use Toy's memory model
EngineNode* children;
int capacity;
int count; //includes tombstones
//TODO: add "liveCount"
//function for releasing memory
EngineNodeCallback freeMemory;
//toy functions, stored in a dict for flexibility
LiteralDictionary* functions;
//use Toy's memory model
EngineNode** children;
int capacity;
int count; //includes tombstones
} EngineNode;
CORE_API void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size); //run bytecode, then grab all top-level function literals

View File

@@ -231,6 +231,13 @@ static int nativeInitNode(Interpreter* interpreter, LiteralArray* arguments) {
freeLiteral(nodeIdn);
//check argument types
if (!IS_OPAQUE(node)) {
interpreter->errorOutput("Incorrect argument type passed to initNode\n");
freeLiteral(node);
return -1;
}
EngineNode* engineNode = AS_OPAQUE(node);
//init the new node
@@ -259,6 +266,13 @@ static int nativeFreeNode(Interpreter* interpreter, LiteralArray* arguments) {
freeLiteral(nodeIdn);
//check argument types
if (!IS_OPAQUE(node)) {
interpreter->errorOutput("Incorrect argument type passed to freeNode\n");
freeLiteral(node);
return -1;
}
EngineNode* engineNode = AS_OPAQUE(node);
//free the node
@@ -271,6 +285,60 @@ static int nativeFreeNode(Interpreter* interpreter, LiteralArray* arguments) {
return 0;
}
static int nativeFreeChildNode(Interpreter* interpreter, LiteralArray* arguments) {
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to freeChildNode\n");
return -1;
}
Literal index = popLiteralArray(arguments);
Literal node = popLiteralArray(arguments);
Literal nodeIdn = node; //annoying
if (!parseIdentifierToValue(interpreter, &node)) {
interpreter->errorOutput("Failed to parse parent node identifier to value\n");
freeLiteral(node);
return -1;
}
freeLiteral(nodeIdn);
//check argument types
if (!IS_OPAQUE(node) || !IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to freeChildNode\n");
freeLiteral(node);
return -1;
}
EngineNode* parentNode = AS_OPAQUE(node);
int idx = AS_INTEGER(index);
//check bounds
if (idx < 0 || idx >= parentNode->count) {
interpreter->errorOutput("Node index out of bounds in freeChildNode\n");
freeLiteral(node);
freeLiteral(index);
return -1;
}
//get the child node
EngineNode* childNode = parentNode->children[idx];
//free the node
if (childNode != NULL) {
callEngineNode(childNode, &engine.interpreter, "onFree");
freeEngineNode(childNode);
}
parentNode->children[idx] = NULL;
//cleanup
freeLiteral(node);
freeLiteral(index);
return 0;
}
static int nativePushNode(Interpreter* interpreter, LiteralArray* arguments) {
//checks
if (arguments->count != 2) {
@@ -360,7 +428,7 @@ static int nativeGetNode(Interpreter* interpreter, LiteralArray* arguments) {
return -1;
}
EngineNode* childNode = &parentNode->children[intIndex];
EngineNode* childNode = parentNode->children[intIndex];
Literal child = TO_OPAQUE_LITERAL(childNode, -1);
pushLiteralArray(&interpreter->stack, child);
@@ -386,7 +454,8 @@ int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
{"loadRootNode", nativeLoadRootNode},
{"loadNode", nativeLoadNode},
{"initNode", nativeInitNode},
{"freeNode", nativeFreeNode},
// {"freeNode", nativeFreeNode},
{"freeChildNode", nativeFreeChildNode},
{"pushNode", nativePushNode},
{"getNode", nativeGetNode},
{NULL, NULL}