Replacing Toy_Literal function bytecode with Toy_RefFunction, addressing #77

This seems to have worked way too easily.
This commit is contained in:
2023-06-06 23:35:59 +10:00
parent 0949fd6ff9
commit 07f4a98b95
6 changed files with 110 additions and 40 deletions

View File

@@ -518,8 +518,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
} }
//create the function in the literal cache (by storing the compiler object) //create the function in the literal cache (by storing the compiler object)
Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0); Toy_Literal fnLiteral = ((Toy_Literal){ .as = { .generic = fnCompiler }, .type = TOY_LITERAL_FUNCTION_INTERMEDIATE});
fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type
//push the name //push the name
int identifierIndex = Toy_findLiteralIndex(&compiler->literalCache, node->fnDecl.identifier); int identifierIndex = Toy_findLiteralIndex(&compiler->literalCache, node->fnDecl.identifier);
@@ -1210,7 +1209,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, size_t* s
case TOY_LITERAL_FUNCTION_INTERMEDIATE: { case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
//extract the compiler //extract the compiler
Toy_Literal fn = compiler->literalCache.literals[i]; Toy_Literal fn = compiler->literalCache.literals[i];
void* fnCompiler = TOY_AS_FUNCTION(fn).inner.bytecode; //store the compiler here for now void* fnCompiler = fn.as.generic; //store the compiler here for now
//collate the function into bytecode (without header) //collate the function into bytecode (without header)
size_t size = 0; size_t size = 0;

View File

@@ -1323,8 +1323,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
//init the inner interpreter manually //init the inner interpreter manually
Toy_initLiteralArray(&inner.literalCache); Toy_initLiteralArray(&inner.literalCache);
inner.scope = Toy_pushScope(func.as.function.scope); inner.scope = Toy_pushScope(func.as.function.scope);
inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode; inner.bytecode = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->data;
inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func); inner.length = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->length;
inner.count = 0; inner.count = 0;
inner.codeStart = -1; inner.codeStart = -1;
inner.depth = interpreter->depth + 1; inner.depth = interpreter->depth + 1;
@@ -2428,20 +2428,16 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
//get the size of the function //get the size of the function
size_t size = (size_t)readShort(interpreter->bytecode, &interpreter->count); size_t size = (size_t)readShort(interpreter->bytecode, &interpreter->count);
//read the function code (literal cache and all)
unsigned char* bytes = TOY_ALLOCATE(unsigned char, size);
memcpy(bytes, interpreter->bytecode + interpreter->count, size); //TODO: -1 for the ending mark
interpreter->count += size;
//assert that the last memory slot is function end //assert that the last memory slot is function end
if (bytes[size - 1] != TOY_OP_FN_END) { if (interpreter->bytecode[interpreter->count + size - 1] != TOY_OP_FN_END) {
interpreter->errorOutput("[internal] Failed to find function end"); interpreter->errorOutput("[internal] Failed to find function end");
TOY_FREE_ARRAY(unsigned char, bytes, size);
return; return;
} }
//change the type to normal //copies internally, since functions can exist independant of literalCache
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size); interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(Toy_createRefFunction(interpreter->bytecode + interpreter->count, size));
interpreter->count += size;
} }
} }

View File

@@ -59,7 +59,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
if (TOY_IS_FUNCTION(literal)) { if (TOY_IS_FUNCTION(literal)) {
Toy_popScope(TOY_AS_FUNCTION(literal).scope); Toy_popScope(TOY_AS_FUNCTION(literal).scope);
TOY_AS_FUNCTION(literal).scope = NULL; TOY_AS_FUNCTION(literal).scope = NULL;
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal)); Toy_deleteRefFunction((Toy_RefFunction*)(TOY_AS_FUNCTION(literal).inner.ptr));
} }
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) { if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
@@ -84,12 +84,8 @@ bool Toy_private_isTruthy(Toy_Literal x) {
return true; return true;
} }
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){{ .string = { .ptr = ptr }},TOY_LITERAL_STRING, 0});
}
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) { Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER, 0}); return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER});
} }
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) { Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
@@ -146,10 +142,8 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
} }
case TOY_LITERAL_FUNCTION: { case TOY_LITERAL_FUNCTION: {
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original)); Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(Toy_copyRefFunction( TOY_AS_FUNCTION(original).inner.ptr ));
memcpy(buffer, TOY_AS_FUNCTION(original).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope); TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
return literal; return literal;

View File

@@ -3,6 +3,7 @@
#include "toy_common.h" #include "toy_common.h"
#include "toy_refstring.h" #include "toy_refstring.h"
#include "toy_reffunction.h"
//forward delcare stuff //forward delcare stuff
struct Toy_Literal; struct Toy_Literal;
@@ -55,7 +56,7 @@ typedef struct Toy_Literal {
struct { struct {
union { union {
void* bytecode; //8 Toy_RefFunction* ptr; //8
Toy_NativeFn native; //8 Toy_NativeFn native; //8
Toy_HookFn hook; //8 Toy_HookFn hook; //8
} inner; //8 } inner; //8
@@ -79,10 +80,13 @@ typedef struct Toy_Literal {
void* ptr; //8 void* ptr; //8
int tag; //4 int tag; //4
} opaque; //16 } opaque; //16
void* generic; //8
} as; //16 } as; //16
Toy_LiteralType type; //4 Toy_LiteralType type; //4
int bytecodeLength; //4 - shenanigans with byte alignment reduces the size of Toy_Literal //4 - unused
//shenanigans with byte alignment reduces the size of Toy_Literal
} Toy_Literal; } Toy_Literal;
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL) #define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
@@ -112,29 +116,29 @@ typedef struct Toy_Literal {
#define TOY_AS_TYPE(value) ((value).as.type) #define TOY_AS_TYPE(value) ((value).as.type)
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr) #define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0}) #define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0}) #define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0}) #define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT, 0}) #define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT})
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value) #define TOY_TO_STRING_LITERAL(value) ((Toy_Literal){{ .string = { .ptr = value }},TOY_LITERAL_STRING})
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0}) #define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0}) #define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY})
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, l}) #define TOY_TO_FUNCTION_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .ptr = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION})
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE, 0}) #define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE})
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK, 0}) #define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK})
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value) #define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE, 0}) #define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 0}) #define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE})
//BUGFIX: For blank indexing //BUGFIX: For blank indexing
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK) #define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK, 0}) #define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK})
TOY_API void Toy_freeLiteral(Toy_Literal literal); TOY_API void Toy_freeLiteral(Toy_Literal literal);
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x) #define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) ((lit).bytecodeLength) #define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) (Toy_lengthRefFunction((lit).inner.ptr))
#define TOY_MAX_STRING_LENGTH 4096 #define TOY_MAX_STRING_LENGTH 4096
#define TOY_HASH_I(lit) ((lit).as.identifier.hash) #define TOY_HASH_I(lit) ((lit).as.identifier.hash)
@@ -143,7 +147,6 @@ TOY_API void Toy_freeLiteral(Toy_Literal literal);
//BUGFIX: macros are not functions //BUGFIX: macros are not functions
TOY_API bool Toy_private_isTruthy(Toy_Literal x); TOY_API bool Toy_private_isTruthy(Toy_Literal x);
TOY_API Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr);
TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr); TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr);
TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype); TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype);

55
source/toy_reffunction.c Normal file
View File

@@ -0,0 +1,55 @@
#include "toy_reffunction.h"
#include <string.h>
//memory allocation
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefFunctionAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn allocator) {
allocate = allocator;
}
//API
Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length) {
//allocate the memory area (including metadata space)
Toy_RefFunction* refFunction = allocate(NULL, 0, sizeof(size_t) + sizeof(int) + sizeof(char) * length);
if (refFunction == NULL) {
return NULL;
}
//set the data
refFunction->refCount = 1;
refFunction->length = length;
memcpy(refFunction->data, data, refFunction->length);
return refFunction;
}
void Toy_deleteRefFunction(Toy_RefFunction* refFunction) {
//decrement, then check
refFunction->refCount--;
if (refFunction->refCount <= 0) {
allocate(refFunction, sizeof(size_t) + sizeof(int) + sizeof(char) * (refFunction->length + 1), 0);
}
}
int Toy_countRefFunction(Toy_RefFunction* refFunction) {
return refFunction->refCount;
}
size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction) {
return refFunction->length;
}
Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction) {
//Cheaty McCheater Face
refFunction->refCount++;
return refFunction;
}
Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction) {
//create a new function, with a new refCount
return Toy_createRefFunction(refFunction->data, refFunction->length);
}

23
source/toy_reffunction.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
#include "toy_common.h"
//memory allocation hook
typedef void* (*Toy_RefFunctionAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
TOY_API void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn);
//the RefFunction structure
typedef struct Toy_RefFunction {
size_t length;
int refCount;
unsigned char data[];
} Toy_RefFunction;
//API
TOY_API Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length);
TOY_API void Toy_deleteRefFunction(Toy_RefFunction* refFunction);
TOY_API int Toy_countRefFunction(Toy_RefFunction* refFunction);
TOY_API size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction);
TOY_API Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction);
TOY_API Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction);