script engine split local and global variables into separate arrays

This commit is contained in:
nakst 2022-01-31 20:19:18 +00:00
parent 77b6097881
commit 7b7b286396
1 changed files with 86 additions and 68 deletions

View File

@ -259,21 +259,28 @@ typedef struct HeapEntry {
} HeapEntry; } HeapEntry;
typedef struct ExecutionContext { typedef struct ExecutionContext {
Value *variables; Value *globalVariables;
bool *variableIsManaged; bool *globalVariableIsManaged;
size_t variableCount; size_t globalVariableCount;
size_t variablesAllocated;
Value stack[50]; // TODO Merge with variables? Value stack[50]; // TODO Merge with variables?
bool stackIsManaged[50]; bool stackIsManaged[50];
uintptr_t stackPointer; uintptr_t stackPointer;
size_t stackEntriesAllocated; size_t stackEntriesAllocated;
HeapEntry *heap; HeapEntry *heap;
uintptr_t heapFirstUnusedEntry; uintptr_t heapFirstUnusedEntry;
size_t heapEntriesAllocated; size_t heapEntriesAllocated;
FunctionBuilder *functionData; // Cleanup the relations between ExecutionContext, FunctionBuilder, Tokenizer and ImportData. FunctionBuilder *functionData; // Cleanup the relations between ExecutionContext, FunctionBuilder, Tokenizer and ImportData.
Node *rootNode; // Only valid during script loading. Node *rootNode; // Only valid during script loading.
char *scriptPersistFile; char *scriptPersistFile;
struct ImportData *mainModule; struct ImportData *mainModule;
Value *localVariables;
bool *localVariableIsManaged;
size_t localVariableCount;
size_t localVariablesAllocated;
BackTraceItem backTrace[300]; BackTraceItem backTrace[300];
uintptr_t backTracePointer; uintptr_t backTracePointer;
} ExecutionContext; } ExecutionContext;
@ -2820,15 +2827,14 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
bool ASTGenerate(Tokenizer *tokenizer, Node *root, ExecutionContext *context) { bool ASTGenerate(Tokenizer *tokenizer, Node *root, ExecutionContext *context) {
Node *child = root->firstChild; Node *child = root->firstChild;
context->functionData->globalVariableOffset = context->variableCount; context->functionData->globalVariableOffset = context->globalVariableCount;
context->variableCount += root->scope->variableEntryCount; context->globalVariableCount += root->scope->variableEntryCount;
context->variablesAllocated += root->scope->variableEntryCount; context->globalVariables = AllocateResize(context->globalVariables, sizeof(Value) * context->globalVariableCount);
context->variables = AllocateResize(context->variables, sizeof(Value) * context->variablesAllocated); context->globalVariableIsManaged = AllocateResize(context->globalVariableIsManaged, sizeof(Value) * context->globalVariableCount);
context->variableIsManaged = AllocateResize(context->variableIsManaged, sizeof(Value) * context->variablesAllocated);
for (uintptr_t i = 0; i < root->scope->variableEntryCount; i++) { for (uintptr_t i = 0; i < root->scope->variableEntryCount; i++) {
context->variables[context->functionData->globalVariableOffset + i].i = 0; context->globalVariables[context->functionData->globalVariableOffset + i].i = 0;
context->variableIsManaged[context->functionData->globalVariableOffset + i] = false; context->globalVariableIsManaged[context->functionData->globalVariableOffset + i] = false;
} }
uint8_t zero = 0; // Make sure no function can start at 0. uint8_t zero = 0; // Make sure no function can start at 0.
@ -2838,10 +2844,10 @@ bool ASTGenerate(Tokenizer *tokenizer, Node *root, ExecutionContext *context) {
if (child->type == T_FUNCTION) { if (child->type == T_FUNCTION) {
uintptr_t variableIndex = context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false); uintptr_t variableIndex = context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false);
uintptr_t heapIndex = HeapAllocate(context); uintptr_t heapIndex = HeapAllocate(context);
context->variableIsManaged[variableIndex] = true; context->globalVariableIsManaged[variableIndex] = true;
context->heap[heapIndex].type = T_FUNCPTR; context->heap[heapIndex].type = T_FUNCPTR;
context->heap[heapIndex].lambdaID = context->functionData->dataBytes; context->heap[heapIndex].lambdaID = context->functionData->dataBytes;
context->variables[variableIndex].i = heapIndex; context->globalVariables[variableIndex].i = heapIndex;
if (child->isExternalCall) { if (child->isExternalCall) {
uint8_t b = T_EXTCALL; uint8_t b = T_EXTCALL;
@ -2880,8 +2886,8 @@ bool ASTGenerate(Tokenizer *tokenizer, Node *root, ExecutionContext *context) {
return false; return false;
} }
context->variables[context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false)].i = 0; context->globalVariables[context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false)].i = 0;
context->variableIsManaged[context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false)] = ASTIsManagedType(child->expressionType); context->globalVariableIsManaged[context->functionData->globalVariableOffset + ScopeLookupIndex(child, root->scope, false, false)] = ASTIsManagedType(child->expressionType);
} }
child = child->sibling; child = child->sibling;
@ -2948,9 +2954,15 @@ uintptr_t HeapAllocate(ExecutionContext *context) {
context->heap[i].gcMark = false; context->heap[i].gcMark = false;
} }
for (uintptr_t i = 0; i < context->variableCount; i++) { for (uintptr_t i = 0; i < context->globalVariableCount; i++) {
if (context->variableIsManaged[i]) { if (context->globalVariableIsManaged[i]) {
HeapGarbageCollectMark(context, context->variables[i].i); HeapGarbageCollectMark(context, context->globalVariables[i].i);
}
}
for (uintptr_t i = 0; i < context->localVariableCount; i++) {
if (context->localVariableIsManaged[i]) {
HeapGarbageCollectMark(context, context->localVariables[i].i);
} }
} }
@ -3021,7 +3033,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
// Checking that this is actually a valid function body pointer. // Checking that this is actually a valid function body pointer.
// Checking various integer overflows. // Checking various integer overflows.
uintptr_t variableBase = context->variableCount - 1; uintptr_t variableBase = context->localVariableCount - 1;
uint8_t *functionData = context->functionData->data; uint8_t *functionData = context->functionData->data;
while (true) { while (true) {
@ -3032,32 +3044,32 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
uint16_t newVariableCount = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8); uint16_t newVariableCount = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8);
instructionPointer += 2; instructionPointer += 2;
if (context->variableCount + newVariableCount > context->variablesAllocated) { if (context->localVariableCount + newVariableCount > context->localVariablesAllocated) {
// TODO Handling memory errors here. // TODO Handling memory errors here.
context->variablesAllocated = context->variableCount + newVariableCount; context->localVariablesAllocated = context->localVariableCount + newVariableCount;
context->variables = AllocateResize(context->variables, context->variablesAllocated * sizeof(Value)); context->localVariables = AllocateResize(context->localVariables, context->localVariablesAllocated * sizeof(Value));
context->variableIsManaged = AllocateResize(context->variableIsManaged, context->variablesAllocated * sizeof(bool)); context->localVariableIsManaged = AllocateResize(context->localVariableIsManaged, context->localVariablesAllocated * sizeof(bool));
} }
MemoryCopy(context->variableIsManaged + context->variableCount, functionData + instructionPointer, newVariableCount); MemoryCopy(context->localVariableIsManaged + context->localVariableCount, functionData + instructionPointer, newVariableCount);
instructionPointer += newVariableCount; instructionPointer += newVariableCount;
for (uintptr_t i = context->variableCount; i < context->variableCount + newVariableCount; i++) { for (uintptr_t i = context->localVariableCount; i < context->localVariableCount + newVariableCount; i++) {
if (command == T_FUNCBODY) { if (command == T_FUNCBODY) {
if (context->stackPointer < 1) return -1; if (context->stackPointer < 1) return -1;
context->variables[i] = context->stack[--context->stackPointer]; context->localVariables[i] = context->stack[--context->stackPointer];
} else { } else {
Value zero = { 0 }; Value zero = { 0 };
context->variables[i] = zero; context->localVariables[i] = zero;
} }
} }
context->variableCount += newVariableCount; context->localVariableCount += newVariableCount;
} else if (command == T_EXIT_SCOPE) { } else if (command == T_EXIT_SCOPE) {
uint16_t count = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8); uint16_t count = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8);
instructionPointer += 2; instructionPointer += 2;
if (context->variableCount < count) return -1; if (context->localVariableCount < count) return -1;
context->variableCount -= count; context->localVariableCount -= count;
} else if (command == T_NUMERIC_LITERAL) { } else if (command == T_NUMERIC_LITERAL) {
if (context->stackPointer == context->stackEntriesAllocated) { if (context->stackPointer == context->stackEntriesAllocated) {
PrintError4(context, instructionPointer - 1, "Stack overflow.\n"); PrintError4(context, instructionPointer - 1, "Stack overflow.\n");
@ -3188,30 +3200,34 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
int32_t scopeIndex; int32_t scopeIndex;
MemoryCopy(&scopeIndex, &functionData[instructionPointer], sizeof(scopeIndex)); MemoryCopy(&scopeIndex, &functionData[instructionPointer], sizeof(scopeIndex));
if (scopeIndex < 0) scopeIndex = variableBase - scopeIndex;
if ((uintptr_t) scopeIndex >= context->variableCount) {
return -1;
}
instructionPointer += sizeof(scopeIndex); instructionPointer += sizeof(scopeIndex);
context->stackIsManaged[context->stackPointer] = context->variableIsManaged[scopeIndex];
context->stack[context->stackPointer++] = context->variables[scopeIndex]; if (scopeIndex >= 0) {
if ((uintptr_t) scopeIndex >= context->globalVariableCount) return -1;
context->stackIsManaged[context->stackPointer] = context->globalVariableIsManaged[scopeIndex];
context->stack[context->stackPointer++] = context->globalVariables[scopeIndex];
} else {
scopeIndex = variableBase - scopeIndex;
if ((uintptr_t) scopeIndex >= context->localVariableCount) return -1;
context->stackIsManaged[context->stackPointer] = context->localVariableIsManaged[scopeIndex];
context->stack[context->stackPointer++] = context->localVariables[scopeIndex];
}
} else if (command == T_EQUALS) { } else if (command == T_EQUALS) {
if (!context->stackPointer) return -1;
int32_t scopeIndex; int32_t scopeIndex;
MemoryCopy(&scopeIndex, &functionData[instructionPointer], sizeof(scopeIndex)); MemoryCopy(&scopeIndex, &functionData[instructionPointer], sizeof(scopeIndex));
instructionPointer += sizeof(scopeIndex); instructionPointer += sizeof(scopeIndex);
if (scopeIndex < 0) scopeIndex = variableBase - scopeIndex;
if ((uintptr_t) scopeIndex >= context->variableCount || !context->stackPointer) { if (scopeIndex >= 0) {
return -1; if ((uintptr_t) scopeIndex >= context->globalVariableCount) return -1;
if (context->globalVariableIsManaged[scopeIndex] != context->stackIsManaged[context->stackPointer - 1]) return -1;
context->globalVariables[scopeIndex] = context->stack[--context->stackPointer];
} else {
scopeIndex = variableBase - scopeIndex;
if ((uintptr_t) scopeIndex >= context->localVariableCount) return -1;
if (context->localVariableIsManaged[scopeIndex] != context->stackIsManaged[context->stackPointer - 1]) return -1;
context->localVariables[scopeIndex] = context->stack[--context->stackPointer];
} }
if (context->variableIsManaged[scopeIndex] != context->stackIsManaged[context->stackPointer - 1]) {
return -1;
}
context->variables[scopeIndex] = context->stack[--context->stackPointer];
} else if (command == T_EQUALS_DOT) { } else if (command == T_EQUALS_DOT) {
if (context->stackPointer < 2) return -1; if (context->stackPointer < 2) return -1;
if (!context->stackIsManaged[context->stackPointer - 1]) return -1; if (!context->stackIsManaged[context->stackPointer - 1]) return -1;
@ -3545,7 +3561,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
link->popResult = popResult; link->popResult = popResult;
link->assertResult = assertResult; link->assertResult = assertResult;
instructionPointer = newBody.i; instructionPointer = newBody.i;
variableBase = context->variableCount - 1; variableBase = context->localVariableCount - 1;
} else if (command == T_IF) { } else if (command == T_IF) {
if (context->stackPointer < 1) return -1; if (context->stackPointer < 1) return -1;
Value condition = context->stack[--context->stackPointer]; Value condition = context->stack[--context->stackPointer];
@ -3723,7 +3739,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
} }
} }
context->variableCount = variableBase + 1; context->localVariableCount = variableBase + 1;
if (context->backTracePointer) { if (context->backTracePointer) {
BackTraceItem *item = &context->backTrace[context->backTracePointer - 1]; BackTraceItem *item = &context->backTrace[context->backTracePointer - 1];
@ -3812,7 +3828,7 @@ bool ScriptParseOptions(ExecutionContext *context) {
context->heap[heapIndex].type = T_STR; context->heap[heapIndex].type = T_STR;
context->heap[heapIndex].bytes = optionLength - equalsPosition - 1; context->heap[heapIndex].bytes = optionLength - equalsPosition - 1;
context->heap[heapIndex].text = AllocateResize(NULL, context->heap[heapIndex].bytes); context->heap[heapIndex].text = AllocateResize(NULL, context->heap[heapIndex].bytes);
context->variables[index].i = heapIndex; context->globalVariables[index].i = heapIndex;
MemoryCopy(context->heap[heapIndex].text, options[i] + equalsPosition + 1, context->heap[heapIndex].bytes); MemoryCopy(context->heap[heapIndex].text, options[i] + equalsPosition + 1, context->heap[heapIndex].bytes);
} else if (node->expressionType->type == T_INT) { } else if (node->expressionType->type == T_INT) {
// TODO Overflow checking. // TODO Overflow checking.
@ -3832,7 +3848,7 @@ bool ScriptParseOptions(ExecutionContext *context) {
} }
} }
context->variables[index] = v; context->globalVariables[index] = v;
} else if (node->expressionType->type == T_BOOL) { } else if (node->expressionType->type == T_BOOL) {
char c = options[i][equalsPosition + 1]; char c = options[i][equalsPosition + 1];
bool truthy = c == 't' || c == 'y' || c == '1'; bool truthy = c == 't' || c == 'y' || c == '1';
@ -3843,7 +3859,7 @@ bool ScriptParseOptions(ExecutionContext *context) {
return false; return false;
} }
context->variables[index].i = truthy ? 1 : 0; context->globalVariables[index].i = truthy ? 1 : 0;
} else { } else {
PrintError3("#option variable '%.*s' is not of string, boolean or integer type.\n", node->token.textBytes, node->token.text); PrintError3("#option variable '%.*s' is not of string, boolean or integer type.\n", node->token.textBytes, node->token.text);
return false; return false;
@ -3919,7 +3935,7 @@ int ScriptExecute(ExecutionContext *context, ImportData *mainModule) {
intptr_t index = ScopeLookupIndex(&n, module->rootNode->scope, true, false); intptr_t index = ScopeLookupIndex(&n, module->rootNode->scope, true, false);
if (index != -1) { if (index != -1) {
int result = ScriptExecuteFunction(context->heap[context->variables[index + module->globalVariableOffset].i].lambdaID, context); int result = ScriptExecuteFunction(context->heap[context->globalVariables[index + module->globalVariableOffset].i].lambdaID, context);
if (result == 0) { if (result == 0) {
// A runtime error occurred. // A runtime error occurred.
@ -3933,7 +3949,7 @@ int ScriptExecute(ExecutionContext *context, ImportData *mainModule) {
module = module->nextImport; module = module->nextImport;
} }
int result = ScriptExecuteFunction(context->heap[context->variables[context->functionData->globalVariableOffset + startIndex].i].lambdaID, context); int result = ScriptExecuteFunction(context->heap[context->globalVariables[context->functionData->globalVariableOffset + startIndex].i].lambdaID, context);
if (result == 0) { if (result == 0) {
// A runtime error occurred. // A runtime error occurred.
@ -3965,8 +3981,10 @@ void ScriptFree(ExecutionContext *context) {
} }
AllocateResize(context->heap, 0); AllocateResize(context->heap, 0);
AllocateResize(context->variables, 0); AllocateResize(context->globalVariables, 0);
AllocateResize(context->variableIsManaged, 0); AllocateResize(context->globalVariableIsManaged, 0);
AllocateResize(context->localVariables, 0);
AllocateResize(context->localVariableIsManaged, 0);
AllocateResize(context->functionData->lineNumbers, 0); AllocateResize(context->functionData->lineNumbers, 0);
AllocateResize(context->functionData->data, 0); AllocateResize(context->functionData->data, 0);
AllocateResize(context->scriptPersistFile, 0); AllocateResize(context->scriptPersistFile, 0);
@ -4630,17 +4648,17 @@ int ExternalPersistRead(ExecutionContext *context, Value *returnValue) {
&& scope->entries[j]->isPersistentVariable) { && scope->entries[j]->isPersistentVariable) {
if (scope->entries[j]->expressionType->type == T_STR) { if (scope->entries[j]->expressionType->type == T_STR) {
// TODO Handling allocation failures. // TODO Handling allocation failures.
context->variables[k].i = HeapAllocate(context); context->globalVariables[k].i = HeapAllocate(context);
context->heap[context->variables[k].i].type = T_STR; context->heap[context->globalVariables[k].i].type = T_STR;
context->heap[context->variables[k].i].bytes = variableDataLength; context->heap[context->globalVariables[k].i].bytes = variableDataLength;
context->heap[context->variables[k].i].text = AllocateResize(NULL, variableDataLength); context->heap[context->globalVariables[k].i].text = AllocateResize(NULL, variableDataLength);
memcpy(context->heap[context->variables[k].i].text, &data[i], variableDataLength); memcpy(context->heap[context->globalVariables[k].i].text, &data[i], variableDataLength);
} else if (scope->entries[j]->expressionType->type == T_INT) { } else if (scope->entries[j]->expressionType->type == T_INT) {
if (variableDataLength == sizeof(int64_t)) memcpy(&context->variables[k].i, &data[i], sizeof(int64_t)); if (variableDataLength == sizeof(int64_t)) memcpy(&context->globalVariables[k].i, &data[i], sizeof(int64_t));
} else if (scope->entries[j]->expressionType->type == T_FLOAT) { } else if (scope->entries[j]->expressionType->type == T_FLOAT) {
if (variableDataLength == sizeof(double)) memcpy(&context->variables[k].f, &data[i], sizeof(double)); if (variableDataLength == sizeof(double)) memcpy(&context->globalVariables[k].f, &data[i], sizeof(double));
} else if (scope->entries[j]->expressionType->type == T_BOOL) { } else if (scope->entries[j]->expressionType->type == T_BOOL) {
if (variableDataLength == 1) context->variables[k].i = data[i] == 1; if (variableDataLength == 1) context->globalVariables[k].i = data[i] == 1;
} else { } else {
// TODO What should happen here? // TODO What should happen here?
} }
@ -4685,7 +4703,7 @@ int ExternalPersistWrite(ExecutionContext *context, Value *returnValue) {
fwrite(&variableNameLength, 1, sizeof(uint32_t), f); fwrite(&variableNameLength, 1, sizeof(uint32_t), f);
if (scope->entries[j]->expressionType->type == T_STR) { if (scope->entries[j]->expressionType->type == T_STR) {
HeapEntry *entry = &context->heap[context->variables[k].i]; HeapEntry *entry = &context->heap[context->globalVariables[k].i];
uint32_t variableDataLength = entry->type == T_STR ? entry->bytes : 0; uint32_t variableDataLength = entry->type == T_STR ? entry->bytes : 0;
fwrite(&variableDataLength, 1, sizeof(uint32_t), f); fwrite(&variableDataLength, 1, sizeof(uint32_t), f);
fwrite(scope->entries[j]->token.text, 1, variableNameLength, f); fwrite(scope->entries[j]->token.text, 1, variableNameLength, f);
@ -4694,17 +4712,17 @@ int ExternalPersistWrite(ExecutionContext *context, Value *returnValue) {
uint32_t variableDataLength = sizeof(int64_t); uint32_t variableDataLength = sizeof(int64_t);
fwrite(&variableDataLength, 1, sizeof(uint32_t), f); fwrite(&variableDataLength, 1, sizeof(uint32_t), f);
fwrite(scope->entries[j]->token.text, 1, variableNameLength, f); fwrite(scope->entries[j]->token.text, 1, variableNameLength, f);
fwrite(&context->variables[k].i, 1, sizeof(int64_t), f); fwrite(&context->globalVariables[k].i, 1, sizeof(int64_t), f);
} else if (scope->entries[j]->expressionType->type == T_FLOAT) { } else if (scope->entries[j]->expressionType->type == T_FLOAT) {
uint32_t variableDataLength = sizeof(double); uint32_t variableDataLength = sizeof(double);
fwrite(&variableDataLength, 1, sizeof(uint32_t), f); fwrite(&variableDataLength, 1, sizeof(uint32_t), f);
fwrite(scope->entries[j]->token.text, 1, variableNameLength, f); fwrite(scope->entries[j]->token.text, 1, variableNameLength, f);
fwrite(&context->variables[k].f, 1, sizeof(double), f); fwrite(&context->globalVariables[k].f, 1, sizeof(double), f);
} else if (scope->entries[j]->expressionType->type == T_BOOL) { } else if (scope->entries[j]->expressionType->type == T_BOOL) {
uint32_t variableDataLength = 1; uint32_t variableDataLength = 1;
fwrite(&variableDataLength, 1, sizeof(uint32_t), f); fwrite(&variableDataLength, 1, sizeof(uint32_t), f);
fwrite(scope->entries[j]->token.text, 1, variableNameLength, f); fwrite(scope->entries[j]->token.text, 1, variableNameLength, f);
uint8_t b = context->variables[k].i == 1; uint8_t b = context->globalVariables[k].i == 1;
fwrite(&b, 1, sizeof(uint8_t), f); fwrite(&b, 1, sizeof(uint8_t), f);
} else { } else {
PrintDebug("\033[0;32mWarning: The persistent variable %.*s could not be written, because it had an unsupported type.\033[0m\n", PrintDebug("\033[0;32mWarning: The persistent variable %.*s could not be written, because it had an unsupported type.\033[0m\n",