mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
WIP functions working, untested, memory issues, read more
I've ripped out the deep copying, and flattened the bucket usage, but
this results in no memory being freed or reused for the lifetime of the
program.
This is shown most clearly with this script:
```toy
fn makeCounter() {
var counter: int = 0;
fn increment() {
return ++counter;
}
return increment;
}
var tally = makeCounter();
while (true) {
var result = tally();
if (result >= 10_000_000) {
break;
}
}
```
The number of calls vs amount of memory consumed is:
```
function calls -> memory used in megabytes
1_000 -> 0.138128
10_000 -> 2.235536
100_000 -> 21.7021
1_000_000 -> 216.1712
10_000_000 -> 1520.823
```
Obviously this needs to be fixed, as ballooning to gigabytes of memory
in only a moment isn't practical. That will be the next task - to find
some way to free memory that isn't needed anymore.
See #163, #160
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
//TODO: Not yet functional
|
//TODO: functions are untested
|
||||||
fn makeCounter() {
|
fn makeCounter() {
|
||||||
var counter: int = 0;
|
var counter: int = 0;
|
||||||
|
|
||||||
fn increment() {
|
fn increment() {
|
||||||
return counter++;
|
return ++counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
return increment;
|
return increment;
|
||||||
@@ -11,6 +11,10 @@ fn makeCounter() {
|
|||||||
|
|
||||||
var tally = makeCounter();
|
var tally = makeCounter();
|
||||||
|
|
||||||
print tally();
|
while (true) {
|
||||||
print tally();
|
var result = tally();
|
||||||
print tally();
|
|
||||||
|
if (result >= 10_000_000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,28 +94,6 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
|
|||||||
return scope->next;
|
return scope->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Scope* Toy_private_deepCopyScope(Toy_Bucket** scopeBucketHandle, Toy_Bucket** literalBucketHandle, Toy_Scope* scope) {
|
|
||||||
//copy/pasted from pushScope, so I can allocate the table manually
|
|
||||||
Toy_Scope* newScope = (Toy_Scope*)Toy_partitionBucket(scopeBucketHandle, sizeof(Toy_Scope));
|
|
||||||
|
|
||||||
newScope->next = scope->next;
|
|
||||||
newScope->table = scope->table != NULL ? Toy_private_adjustTableCapacity(NULL, scope->table->capacity) : NULL;
|
|
||||||
newScope->refCount = 0;
|
|
||||||
|
|
||||||
incrementRefCount(newScope);
|
|
||||||
|
|
||||||
if (newScope->table != NULL) {
|
|
||||||
//forcibly copy the contents
|
|
||||||
for (unsigned int i = 0; i < scope->table->capacity; i++) {
|
|
||||||
if (!TOY_VALUE_IS_NULL(scope->table->data[i].key)) {
|
|
||||||
Toy_insertTable(&newScope->table, Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, scope->table->data[i].key), Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, scope->table->data[i].value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
||||||
if (key->info.type != TOY_STRING_NAME) {
|
if (key->info.type != TOY_STRING_NAME) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ TOY_API Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope);
|
|||||||
TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
|
TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
|
||||||
TOY_API Toy_Scope* Toy_private_pushDummyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); //doesn't delcare a table for storage
|
TOY_API Toy_Scope* Toy_private_pushDummyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); //doesn't delcare a table for storage
|
||||||
|
|
||||||
TOY_API Toy_Scope* Toy_private_deepCopyScope(Toy_Bucket** scopeBucketHandle, Toy_Bucket** literalBucketHandle, Toy_Scope* scope);
|
|
||||||
|
|
||||||
//manage the contents
|
//manage the contents
|
||||||
TOY_API void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
TOY_API void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
||||||
TOY_API void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
TOY_API void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
||||||
|
|||||||
@@ -104,43 +104,13 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
|||||||
return TOY_VALUE_FROM_STRING(Toy_copyString(value.as.string));
|
return TOY_VALUE_FROM_STRING(Toy_copyString(value.as.string));
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY:
|
|
||||||
case TOY_VALUE_TABLE:
|
|
||||||
case TOY_VALUE_FUNCTION:
|
|
||||||
case TOY_VALUE_OPAQUE:
|
|
||||||
case TOY_VALUE_ANY:
|
|
||||||
case TOY_VALUE_REFERENCE:
|
|
||||||
case TOY_VALUE_UNKNOWN:
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy an unknown value type, exiting\n" TOY_CC_RESET);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//dummy return
|
|
||||||
return TOY_VALUE_FROM_NULL();
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Value Toy_private_deepCopyValue(Toy_Bucket** scopeBucketHandle, Toy_Bucket** literalBucketHandle, Toy_Value value) {
|
|
||||||
//this should be the same as Toy_copyValue(), but it forces a deep copy for the strings
|
|
||||||
MAYBE_UNWRAP(value);
|
|
||||||
|
|
||||||
switch(value.type) {
|
|
||||||
case TOY_VALUE_NULL:
|
|
||||||
case TOY_VALUE_BOOLEAN:
|
|
||||||
case TOY_VALUE_INTEGER:
|
|
||||||
case TOY_VALUE_FLOAT:
|
|
||||||
return value;
|
|
||||||
|
|
||||||
case TOY_VALUE_STRING: {
|
|
||||||
return TOY_VALUE_FROM_STRING(Toy_deepCopyString(literalBucketHandle, value.as.string));
|
|
||||||
}
|
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
//arrays probably won't get copied much
|
//arrays probably won't get copied much
|
||||||
Toy_Array* ptr = value.as.array;
|
Toy_Array* ptr = value.as.array;
|
||||||
Toy_Array* result = Toy_resizeArray(NULL, ptr->capacity);
|
Toy_Array* result = Toy_resizeArray(NULL, ptr->capacity);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ptr->count; i++) {
|
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||||
result->data[i] = Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, ptr->data[i]);
|
result->data[i] = Toy_copyValue(ptr->data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result->capacity = ptr->capacity;
|
result->capacity = ptr->capacity;
|
||||||
@@ -156,8 +126,8 @@ Toy_Value Toy_private_deepCopyValue(Toy_Bucket** scopeBucketHandle, Toy_Bucket**
|
|||||||
|
|
||||||
for (unsigned int i = 0; i < ptr->capacity; i++) {
|
for (unsigned int i = 0; i < ptr->capacity; i++) {
|
||||||
if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) {
|
if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) {
|
||||||
result->data[i].key = Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, ptr->data[i].key);
|
result->data[i].key = Toy_copyValue(ptr->data[i].key);
|
||||||
result->data[i].value = Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, ptr->data[i].value);
|
result->data[i].value = Toy_copyValue(ptr->data[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,35 +136,15 @@ Toy_Value Toy_private_deepCopyValue(Toy_Bucket** scopeBucketHandle, Toy_Bucket**
|
|||||||
|
|
||||||
return TOY_VALUE_FROM_TABLE(result);
|
return TOY_VALUE_FROM_TABLE(result);
|
||||||
}
|
}
|
||||||
case TOY_VALUE_FUNCTION: {
|
|
||||||
if (TOY_VALUE_AS_FUNCTION(value)->type == TOY_FUNCTION_MODULE) {
|
|
||||||
Toy_Function* fn = Toy_createModuleFunction(literalBucketHandle, TOY_VALUE_AS_FUNCTION(value)->module.module);
|
|
||||||
|
|
||||||
//BUGFIX: rewire any and all strings within the function's ancestors
|
case TOY_VALUE_FUNCTION:
|
||||||
if (fn->module.module.parentScope != NULL && fn->module.module.parentScope->next != NULL) {
|
return value; //URGENT: concerning
|
||||||
|
|
||||||
//break the loop to prevent infinite loops...???
|
|
||||||
//URGENT: fuck
|
|
||||||
Toy_Scope* tmp = fn->module.module.parentScope;
|
|
||||||
fn->module.module.parentScope = NULL;
|
|
||||||
|
|
||||||
Toy_Scope* duplicate = Toy_private_deepCopyScope(scopeBucketHandle, literalBucketHandle, tmp->next);
|
|
||||||
fn->module.module.parentScope = Toy_private_pushDummyScope(scopeBucketHandle, duplicate); //insert a new dummy
|
|
||||||
}
|
|
||||||
|
|
||||||
return TOY_VALUE_FROM_FUNCTION(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep-copy an unknown function type value, exiting\n" TOY_CC_RESET);
|
|
||||||
exit(-1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
case TOY_VALUE_REFERENCE:
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep-copy an unknown value type, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy an unknown value type, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ TOY_API Toy_Value Toy_unwrapValue(Toy_Value value);
|
|||||||
TOY_API unsigned int Toy_hashValue(Toy_Value value);
|
TOY_API unsigned int Toy_hashValue(Toy_Value value);
|
||||||
|
|
||||||
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_private_deepCopyValue(struct Toy_Bucket** scopeBucketHandle, struct Toy_Bucket** literalBucketHandle, Toy_Value value); //don't use refcounting
|
|
||||||
TOY_API void Toy_freeValue(Toy_Value value);
|
TOY_API void Toy_freeValue(Toy_Value value);
|
||||||
|
|
||||||
TOY_API bool Toy_checkValueIsTruthy(Toy_Value value);
|
TOY_API bool Toy_checkValueIsTruthy(Toy_Value value);
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ static void processRead(Toy_VM* vm) {
|
|||||||
|
|
||||||
//build a string from the data section
|
//build a string from the data section
|
||||||
if (stringType == TOY_STRING_LEAF) {
|
if (stringType == TOY_STRING_LEAF) {
|
||||||
value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->literalBucket, cstring));
|
value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->memoryBucket, cstring));
|
||||||
}
|
}
|
||||||
else if (stringType == TOY_STRING_NAME) {
|
else if (stringType == TOY_STRING_NAME) {
|
||||||
Toy_ValueType valueType = TOY_VALUE_UNKNOWN;
|
Toy_ValueType valueType = TOY_VALUE_UNKNOWN;
|
||||||
|
|
||||||
value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->literalBucket, cstring, len, valueType, false));
|
value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->memoryBucket, cstring, len, valueType, false));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_error("Invalid string type found in opcode read");
|
Toy_error("Invalid string type found in opcode read");
|
||||||
@@ -162,10 +162,10 @@ static void processRead(Toy_VM* vm) {
|
|||||||
unsigned int addr = (unsigned int)READ_INT(vm);
|
unsigned int addr = (unsigned int)READ_INT(vm);
|
||||||
|
|
||||||
Toy_Module module = Toy_parseModule(vm->code + vm->subsAddr + addr);
|
Toy_Module module = Toy_parseModule(vm->code + vm->subsAddr + addr);
|
||||||
module.parentScope = Toy_private_pushDummyScope(&vm->scopeBucket, vm->scope);
|
module.parentScope = Toy_private_pushDummyScope(&vm->memoryBucket, vm->scope);
|
||||||
|
|
||||||
//create and push the function value
|
//create and push the function value
|
||||||
Toy_Function* function = Toy_createModuleFunction(&vm->literalBucket, module);
|
Toy_Function* function = Toy_createModuleFunction(&vm->memoryBucket, module);
|
||||||
value = TOY_VALUE_FROM_FUNCTION(function);
|
value = TOY_VALUE_FROM_FUNCTION(function);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -210,7 +210,7 @@ static void processDeclare(Toy_VM* vm) {
|
|||||||
char* cstring = (char*)(vm->code + vm->dataAddr + jump);
|
char* cstring = (char*)(vm->code + vm->dataAddr + jump);
|
||||||
|
|
||||||
//build the name string
|
//build the name string
|
||||||
Toy_String* name = Toy_createNameStringLength(&vm->literalBucket, cstring, len, type, constant);
|
Toy_String* name = Toy_createNameStringLength(&vm->memoryBucket, cstring, len, type, constant);
|
||||||
|
|
||||||
//get the value
|
//get the value
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
@@ -430,7 +430,7 @@ static void processInvoke(Toy_VM* vm) {
|
|||||||
const char* cstr = ((char*)(module.code + module.dataAddr)) + paramAddr;
|
const char* cstr = ((char*)(module.code + module.dataAddr)) + paramAddr;
|
||||||
|
|
||||||
//as a name string
|
//as a name string
|
||||||
Toy_String* name = Toy_createNameStringLength(&subVM.literalBucket, cstr, strlen(cstr), paramType, true);
|
Toy_String* name = Toy_createNameStringLength(&subVM.memoryBucket, cstr, strlen(cstr), paramType, true);
|
||||||
|
|
||||||
Toy_declareScope(subVM.scope, name, argValue);
|
Toy_declareScope(subVM.scope, name, argValue);
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ static void processInvoke(Toy_VM* vm) {
|
|||||||
|
|
||||||
//extract and store any results
|
//extract and store any results
|
||||||
if (resultCount > 0) {
|
if (resultCount > 0) {
|
||||||
Toy_Array* results = Toy_extractResultsFromVM(&vm->scopeBucket, &vm->literalBucket, &subVM, resultCount);
|
Toy_Array* results = Toy_extractResultsFromVM(&subVM, resultCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < results->count; i++) {
|
for (unsigned int i = 0; i < results->count; i++) {
|
||||||
//NOTE: since the results array is being immediately freed, just push each element without a call to copy
|
//NOTE: since the results array is being immediately freed, just push each element without a call to copy
|
||||||
@@ -723,7 +723,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
|
|
||||||
//determine the args
|
//determine the args
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->literalBucket, "assertion failed")); //TODO: needs a better default message
|
message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->memoryBucket, "assertion failed")); //TODO: needs a better default message
|
||||||
value = Toy_popStack(&vm->stack);
|
value = Toy_popStack(&vm->stack);
|
||||||
}
|
}
|
||||||
else if (count == 2) {
|
else if (count == 2) {
|
||||||
@@ -738,7 +738,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
//do the check
|
//do the check
|
||||||
if (TOY_VALUE_IS_NULL(value) || Toy_checkValueIsTruthy(value) != true) {
|
if (TOY_VALUE_IS_NULL(value) || Toy_checkValueIsTruthy(value) != true) {
|
||||||
//on a failure, print the message
|
//on a failure, print the message
|
||||||
Toy_String* string = Toy_stringifyValue(&vm->literalBucket, message);
|
Toy_String* string = Toy_stringifyValue(&vm->memoryBucket, message);
|
||||||
char* buffer = Toy_getStringRawBuffer(string);
|
char* buffer = Toy_getStringRawBuffer(string);
|
||||||
|
|
||||||
Toy_assertFailure(buffer);
|
Toy_assertFailure(buffer);
|
||||||
@@ -756,7 +756,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
static void processPrint(Toy_VM* vm) {
|
static void processPrint(Toy_VM* vm) {
|
||||||
//print the value on top of the stack, popping it
|
//print the value on top of the stack, popping it
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
Toy_String* string = Toy_stringifyValue(&vm->literalBucket, value);
|
Toy_String* string = Toy_stringifyValue(&vm->memoryBucket, value);
|
||||||
char* buffer = Toy_getStringRawBuffer(string); //TODO: check string type to skip this call
|
char* buffer = Toy_getStringRawBuffer(string); //TODO: check string type to skip this call
|
||||||
|
|
||||||
Toy_print(buffer);
|
Toy_print(buffer);
|
||||||
@@ -779,7 +779,7 @@ static void processConcat(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//all good
|
//all good
|
||||||
Toy_String* result = Toy_concatStrings(&vm->literalBucket, TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right));
|
Toy_String* result = Toy_concatStrings(&vm->memoryBucket, TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right));
|
||||||
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result));
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -847,11 +847,11 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
//extract cstring, based on type
|
//extract cstring, based on type
|
||||||
if (str->info.type == TOY_STRING_LEAF) {
|
if (str->info.type == TOY_STRING_LEAF) {
|
||||||
const char* cstr = str->leaf.data;
|
const char* cstr = str->leaf.data;
|
||||||
result = Toy_createStringLength(&vm->literalBucket, cstr + i, l);
|
result = Toy_createStringLength(&vm->memoryBucket, cstr + i, l);
|
||||||
}
|
}
|
||||||
else if (str->info.type == TOY_STRING_NODE) {
|
else if (str->info.type == TOY_STRING_NODE) {
|
||||||
char* cstr = Toy_getStringRawBuffer(str);
|
char* cstr = Toy_getStringRawBuffer(str);
|
||||||
result = Toy_createStringLength(&vm->literalBucket, cstr + i, l);
|
result = Toy_createStringLength(&vm->memoryBucket, cstr + i, l);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1031,7 +1031,7 @@ static unsigned int process(Toy_VM* vm) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_OPCODE_SCOPE_PUSH:
|
case TOY_OPCODE_SCOPE_PUSH:
|
||||||
vm->scope = Toy_pushScope(&vm->scopeBucket, vm->scope);
|
vm->scope = Toy_pushScope(&vm->memoryBucket, vm->scope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_OPCODE_SCOPE_POP:
|
case TOY_OPCODE_SCOPE_POP:
|
||||||
@@ -1095,10 +1095,9 @@ void Toy_initVM(Toy_VM* vm) {
|
|||||||
//create persistent memory
|
//create persistent memory
|
||||||
vm->scope = NULL;
|
vm->scope = NULL;
|
||||||
vm->stack = Toy_allocateStack();
|
vm->stack = Toy_allocateStack();
|
||||||
vm->literalBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
vm->memoryBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
vm->scopeBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
|
||||||
|
|
||||||
vm->scopeBucketHandle = NULL; //not used
|
vm->parentBucketHandle = NULL;
|
||||||
|
|
||||||
Toy_resetVM(vm, true);
|
Toy_resetVM(vm, true);
|
||||||
}
|
}
|
||||||
@@ -1107,10 +1106,9 @@ void Toy_inheritVM(Toy_VM* vm, Toy_VM* parent) {
|
|||||||
//inherent persistent memory
|
//inherent persistent memory
|
||||||
vm->scope = NULL;
|
vm->scope = NULL;
|
||||||
vm->stack = Toy_allocateStack();
|
vm->stack = Toy_allocateStack();
|
||||||
vm->literalBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
vm->memoryBucket = parent->memoryBucket;
|
||||||
vm->scopeBucket = parent->scopeBucket;
|
|
||||||
|
|
||||||
vm->scopeBucketHandle = &parent->scopeBucket; //track this to update it later
|
vm->parentBucketHandle = &parent->memoryBucket; //track this to update it later
|
||||||
|
|
||||||
Toy_resetVM(vm, true);
|
Toy_resetVM(vm, true);
|
||||||
}
|
}
|
||||||
@@ -1130,7 +1128,7 @@ void Toy_bindVM(Toy_VM* vm, Toy_Module* module, bool preserveScope) {
|
|||||||
vm->subsAddr = module->subsAddr;
|
vm->subsAddr = module->subsAddr;
|
||||||
|
|
||||||
if (preserveScope == false) {
|
if (preserveScope == false) {
|
||||||
vm->scope = Toy_pushScope(&vm->scopeBucket, module->parentScope);
|
vm->scope = Toy_pushScope(&vm->memoryBucket, module->parentScope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,17 +1150,16 @@ void Toy_freeVM(Toy_VM* vm) {
|
|||||||
|
|
||||||
//clear the persistent memory
|
//clear the persistent memory
|
||||||
Toy_freeStack(vm->stack);
|
Toy_freeStack(vm->stack);
|
||||||
Toy_freeBucket(&vm->literalBucket);
|
|
||||||
|
|
||||||
if (vm->scopeBucketHandle != NULL) {
|
if (vm->parentBucketHandle != NULL) {
|
||||||
*(vm->scopeBucketHandle) = vm->scopeBucket; //re-adjust the parent's scopeBucket pointer, in case it was expanded
|
*(vm->parentBucketHandle) = vm->memoryBucket; //update the outter VM, if there is one
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_freeBucket(&vm->scopeBucket);
|
Toy_freeBucket(&vm->memoryBucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Array* Toy_extractResultsFromVM(Toy_Bucket** scopeBucketHandle, Toy_Bucket** literalBucketHandle, Toy_VM* subVM, unsigned int resultCount) {
|
Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount) {
|
||||||
if (subVM->stack->count < resultCount) {
|
if (subVM->stack->count < resultCount) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Too many results requested from VM, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Too many results requested from VM, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -1173,7 +1170,7 @@ Toy_Array* Toy_extractResultsFromVM(Toy_Bucket** scopeBucketHandle, Toy_Bucket**
|
|||||||
const unsigned int offset = subVM->stack->count - resultCount; //first element to extract
|
const unsigned int offset = subVM->stack->count - resultCount; //first element to extract
|
||||||
|
|
||||||
for (/* EMPTY */; results->count < resultCount; results->count++) {
|
for (/* EMPTY */; results->count < resultCount; results->count++) {
|
||||||
results->data[results->count] = Toy_private_deepCopyValue(scopeBucketHandle, literalBucketHandle, subVM->stack->data[offset + results->count]);
|
results->data[results->count] = Toy_copyValue(subVM->stack->data[offset + results->count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -39,9 +39,8 @@ typedef struct Toy_VM {
|
|||||||
Toy_Stack* stack;
|
Toy_Stack* stack;
|
||||||
|
|
||||||
//easy access to memory
|
//easy access to memory
|
||||||
Toy_Bucket* literalBucket; //stores the value literals (strings, functions, etc.)
|
Toy_Bucket* memoryBucket;
|
||||||
Toy_Bucket* scopeBucket; //stores the scope instances
|
Toy_Bucket** parentBucketHandle;
|
||||||
Toy_Bucket** scopeBucketHandle; //for reusing the scope bucket to save on alloc/free
|
|
||||||
} Toy_VM;
|
} Toy_VM;
|
||||||
|
|
||||||
TOY_API void Toy_resetVM(Toy_VM* vm, bool preserveScope);
|
TOY_API void Toy_resetVM(Toy_VM* vm, bool preserveScope);
|
||||||
@@ -53,6 +52,6 @@ TOY_API void Toy_bindVM(Toy_VM* vm, Toy_Module* module, bool preserveScope);
|
|||||||
TOY_API unsigned int Toy_runVM(Toy_VM* vm);
|
TOY_API unsigned int Toy_runVM(Toy_VM* vm);
|
||||||
TOY_API void Toy_freeVM(Toy_VM* vm);
|
TOY_API void Toy_freeVM(Toy_VM* vm);
|
||||||
|
|
||||||
TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_Bucket** scopeBucketHandle, Toy_Bucket** literalBucketHandle, Toy_VM* subVM, unsigned int resultCount);
|
TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount);
|
||||||
|
|
||||||
//TODO: inject extra data (hook system for external libraries)
|
//TODO: inject extra data (hook system for external libraries)
|
||||||
|
|||||||
@@ -244,56 +244,6 @@ int test_scope_allocation(void) {
|
|||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
//deep copy
|
|
||||||
{
|
|
||||||
//setup
|
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
|
||||||
|
|
||||||
//run
|
|
||||||
Toy_Scope* scopeA = Toy_pushScope(&bucket, NULL);
|
|
||||||
Toy_Scope* scopeB = Toy_pushScope(&bucket, scopeA);
|
|
||||||
Toy_Scope* scopeCopy = Toy_deepCopyScope(&bucket, scopeB);
|
|
||||||
|
|
||||||
//check
|
|
||||||
if (
|
|
||||||
scopeA == NULL ||
|
|
||||||
scopeA->next != NULL ||
|
|
||||||
scopeA->table == NULL ||
|
|
||||||
scopeA->table->capacity != 8 ||
|
|
||||||
scopeA->refCount != 3 ||
|
|
||||||
|
|
||||||
scopeB == NULL ||
|
|
||||||
scopeB->next != scopeA ||
|
|
||||||
scopeB->table == NULL ||
|
|
||||||
scopeB->table->capacity != 8 ||
|
|
||||||
scopeB->refCount != 1 ||
|
|
||||||
|
|
||||||
scopeB == NULL ||
|
|
||||||
scopeB->next != scopeA ||
|
|
||||||
scopeB->table == NULL ||
|
|
||||||
scopeB->table->capacity != 8 ||
|
|
||||||
scopeB->refCount != 1 ||
|
|
||||||
|
|
||||||
scopeB == scopeCopy ||
|
|
||||||
|
|
||||||
false)
|
|
||||||
{
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to deep copy a scope\n" TOY_CC_RESET);
|
|
||||||
Toy_popScope(scopeCopy);
|
|
||||||
Toy_popScope(scopeB);
|
|
||||||
Toy_popScope(scopeA);
|
|
||||||
Toy_freeBucket(&bucket);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
Toy_popScope(scopeCopy);
|
|
||||||
Toy_popScope(scopeB);
|
|
||||||
Toy_popScope(scopeA);
|
|
||||||
|
|
||||||
Toy_freeBucket(&bucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user