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

2
Toy

Submodule Toy updated: 8b04939430...168369d897

View File

@@ -21,8 +21,7 @@ fn onInit(node: opaque) {
makeChild(node, "assets/scripts/child.toy", false);
//actually, grab that first node and free it
var o: opaque = getNode(node, 0);
freeNode(o);
freeChildNode(node, 0); //must be done from the parent node, so it's pointer can be nullified
}
fn onStep(node: opaque) {

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}

View File

@@ -1,14 +1,14 @@
var tally: int = 0;
fn onInit() {
fn onInit(node) {
print "child init called";
}
fn onStep() {
fn onStep(node) {
print "child step called";
print ++tally;
}
fn onFree() {
fn onFree(node) {
print "child free called";
}

View File

@@ -1,11 +1,11 @@
fn onInit() {
fn onInit(node) {
print "init called";
}
fn onStep() {
fn onStep(node) {
print "step called";
}
fn onFree() {
fn onFree(node) {
print "free called";
}

View File

@@ -6,6 +6,7 @@
#include "interpreter.h"
#include "repl_tools.h"
#include "console_colors.h"
#include "memory.h"
#include <stdio.h>
#include <stdlib.h>
@@ -29,15 +30,15 @@ int main() {
unsigned char* tb = compileString(source, &size);
//create and test the engine node
EngineNode node;
EngineNode* node = ALLOCATE(EngineNode, 1);
initEngineNode(&node, &interpreter, tb, size);
initEngineNode(node, &interpreter, tb, size);
callEngineNode(&node, &interpreter, "onInit");
callEngineNode(&node, &interpreter, "onStep");
callEngineNode(&node, &interpreter, "onFree");
callEngineNode(node, &interpreter, "onInit");
callEngineNode(node, &interpreter, "onStep");
callEngineNode(node, &interpreter, "onFree");
freeEngineNode(&node);
freeEngineNode(node);
//free
free((void*)source);
@@ -56,35 +57,35 @@ int main() {
unsigned char* tb = compileString(source, &size);
//create and test the engine node
EngineNode node;
EngineNode* node = ALLOCATE(EngineNode, 1);
initEngineNode(&node, &interpreter, tb, size);
initEngineNode(node, &interpreter, tb, size);
resetInterpreter(&interpreter);
for (int i = 0; i < 10; i++) {
char* source = readFile("./scripts/child_engine_node.toy", &size);
unsigned char* tb = compileString(source, &size);
EngineNode child;
initEngineNode(&child, &interpreter, tb, size);
EngineNode* child = ALLOCATE(EngineNode, 1);
initEngineNode(child, &interpreter, tb, size);
resetInterpreter(&interpreter);
pushEngineNode(&node, &child);
pushEngineNode(node, child);
free((void*)source);
}
//test the calls
callEngineNode(&node, &interpreter, "onInit");
callEngineNode(node, &interpreter, "onInit");
for (int i = 0; i < 10; i++) {
callEngineNode(&node, &interpreter, "onStep");
callEngineNode(node, &interpreter, "onStep");
}
callEngineNode(&node, &interpreter, "onFree");
callEngineNode(node, &interpreter, "onFree");
//free
freeEngineNode(&node);
freeEngineNode(node);
free((void*)source);
freeInterpreter(&interpreter);
}